<commit_before>import logging
import random

from pyswip import Prolog, Functor, Atom

from pygdl.kif import (kif_to_prolog,
                       kif_s_expr_to_prolog,
                       single_kif_term_to_prolog)
from pygdl.sexpr import (parse_s_expressions,
                         prefix_functional_to_s_expressions,
                         to_s_expression_string)

logger = logging.getLogger(__name__)


class QueryEvaluatesFalseError(Exception):
    def __init__(self, query):
        self.query = query

    def __str__(self):
        return "Query: " + self.query


class PrologTerm(object):
    """Representation of a Prolog term."""
    def __init__(self, obj):
        super().__init__()
        self.obj = obj

    def __repr__(self):
        return "{}({!r})".format(PrologTerm.__name__, self.obj)

    def __str__(self):
        """Return the term as a Prolog string."""
        if isinstance(self.obj, Functor):
            # Default str(Functor()) does not give a Prolog string
            return "{!s}({!s})".format(
                self.obj.name,
                ", ".join(str(PrologTerm(arg))
                          for arg in self.obj.args))
        else:
            return str(self.obj)


class PrologGameState(object):
    """Manage a game state with Prolog."""
    def __init__(self):
        super().__init__()
        self.prolog = Prolog()
        self.is_game_specified = False

        # Prolog() is a singleton class so make sure that this is the only
        # GameState using it.
        id_ = random.randint(0, 10**10)
        self.prolog.assertz('pygdl_game_state_id({!s})'.format(id_))
        assert sum(1 for _ in self.query('pygdl_game_state_id(X)')) == 1, \
            "Cannot create more than one instance of GameState"

        # Procedures defined by the game description language.
        self.prolog.assertz('distinct(X, Y) :- dif(X, Y)')
        self.prolog.assertz('or(A, B) :- A')
        self.prolog.assertz('or(A, B) :- B')

        # Rules used for evaluating game states
        self.prolog.dynamic('turn/1')
        self.prolog.dynamic('does/2')
        self.prolog.dynamic('true/1')
        self.prolog.dynamic('nexttrue/1')
        self.prolog.dynamic('wastrue/2')
        self.prolog.assertz(
            """update :-
                forall(role(Role),
                       (findall(Move, does(Role, Move), MoveList),
                        length(MoveList, L),
                        L == 1,
                        does(Role, Move),
                        legal(Role, Move))),
                turn(Turn),
                retractall(wastrue(_, Turn)),
                forall(true(Fact), assert(wastrue(Fact, Turn))),
                forall(base(Fact), (not(next(Fact)); assert(nexttrue(Fact)))),
                retractall(true(_)),
                forall(nexttrue(Fact), assert(true(Fact))),
                retractall(nexttrue(_)),
                succ(Turn, NewTurn),
                assert(turn(NewTurn)),
                retract(turn(Turn))
            """)
        self.prolog.assertz(
            """resetturn(Turn) :-
                wastrue(_, Turn), !,
                retractall(true(_)),
                retractall(turn(_)),
                forall(wastrue(Fact, Turn), assert(true(Fact))),
                assert(turn(Turn))
            """)
        self.prolog.assertz(
            """setmove(Role, Move) :-
                role(Role),
                legal(Role, Move),
                retractall(does(Role, _)),
                assert(does(Role, Move))
            """)

    def load_game_from_facts(self, facts):
        """Load game from a list of prolog fact strings."""
        for fact in facts:
            self.prolog.assertz(fact)
<commit_msg>Game state restores move assignments on resetturn<commit_after>import logging
import random

from pyswip import Prolog, Functor, Atom

from pygdl.kif import (kif_to_prolog,
                       kif_s_expr_to_prolog,
                       single_kif_term_to_prolog)
from pygdl.sexpr import (parse_s_expressions,
                         prefix_functional_to_s_expressions,
                         to_s_expression_string)

logger = logging.getLogger(__name__)


class QueryEvaluatesFalseError(Exception):
    def __init__(self, query):
        self.query = query

    def __str__(self):
        return "Query: " + self.query


class PrologTerm(object):
    """Representation of a Prolog term."""
    def __init__(self, obj):
        super().__init__()
        self.obj = obj

    def __repr__(self):
        return "{}({!r})".format(PrologTerm.__name__, self.obj)

    def __str__(self):
        """Return the term as a Prolog string."""
        if isinstance(self.obj, Functor):
            # Default str(Functor()) does not give a Prolog string
            return "{!s}({!s})".format(
                self.obj.name,
                ", ".join(str(PrologTerm(arg))
                          for arg in self.obj.args))
        else:
            return str(self.obj)


class PrologGameState(object):
    """Manage a game state with Prolog."""
    def __init__(self):
        super().__init__()
        self.prolog = Prolog()
        self.is_game_specified = False

        # Prolog() is a singleton class so make sure that this is the only
        # GameState using it.
        id_ = random.randint(0, 10**10)
        self.prolog.assertz('pygdl_game_state_id({!s})'.format(id_))
        assert sum(1 for _ in self.query('pygdl_game_state_id(X)')) == 1, \
            "Cannot create more than one instance of GameState"

        # Procedures defined by the game description language.
        self.prolog.assertz('distinct(X, Y) :- dif(X, Y)')
        self.prolog.assertz('or(A, B) :- A')
        self.prolog.assertz('or(A, B) :- B')

        # Rules used for evaluating game states
        self.prolog.dynamic('turn/1')
        self.prolog.dynamic('does/2')
        self.prolog.dynamic('true/1')
        self.prolog.dynamic('nexttrue/1')
        self.prolog.dynamic('wastrue/2')
        self.prolog.dynamic('wasdoes/3')
        self.prolog.assertz(
            """update :-
                forall(role(Role),
                       (findall(Move, does(Role, Move), MoveList),
                        length(MoveList, L),
                        L == 1,
                        does(Role, Move),
                        legal(Role, Move))),
                turn(Turn),
                retractall(wastrue(_, Turn)),
                retractall(wasdoes(_, _, Turn)),
                forall(true(Fact), assert(wastrue(Fact, Turn))),
                forall(does(Role, Move), assert(wasdoes(Role, Move, Turn))),
                forall(base(Fact), (not(next(Fact)); assert(nexttrue(Fact)))),
                retractall(true(_)),
                forall(nexttrue(Fact), assert(true(Fact))),
                retractall(nexttrue(_)),
                succ(Turn, NewTurn),
                assert(turn(NewTurn)),
                retract(turn(Turn))
            """)
        self.prolog.assertz(
            """resetturn(Turn) :-
                wastrue(_, Turn), !,
                retractall(turn(_)),
                retractall(true(_)),
                retractall(does(_, _)),
                forall(wastrue(Fact, Turn), assert(true(Fact))),
                forall(wasdoes(Role, Move, Turn), assert(does(Role, Move))),
                assert(turn(Turn))
            """)
        self.prolog.assertz(
            """setmove(Role, Move) :-
                role(Role),
                legal(Role, Move),
                retractall(does(Role, _)),
                assert(does(Role, Move))
            """)

    def load_game_from_facts(self, facts):
        """Load game from a list of prolog fact strings."""
        for fact in facts:
            self.prolog.assertz(fact)

{'fraction_non_alphanumeric': 0.12698819907644945, 'fraction_numerical': 0.0034633145202668035, 'mean_word_length': 1.7826552462526766, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '612435', 'n_tokens_mistral': 2359, 'n_tokens_neox': 2231, 'n_words': 482}