Beispiel #1
0
 def testFEN(self):
     """Testing board-FEN conversion with several positions"""
     for i, fenstr in enumerate(self.positions[1:]):
         board = LBoard()
         board.applyFen(fenstr)
         fenstr2 = board.asFen()
         self.assertEqual(fenstr, fenstr2)
Beispiel #2
0
    def test_pdb_database_get_bitboards(self):
        """Testing .pdb database get_bitboards"""

        db = self.load_test_pgn()

        board = LBoard()
        board.applyFen(FEN_START)

        for ply in range(4):
            bb_candidates = {}
            for lmove in genAllMoves(board):
                board.applyMove(lmove)
                if board.opIsChecked():
                    board.popMove()
                    continue
                bb_candidates[board.friends[0] | board.friends[1]] = lmove
                board.popMove()

            bitboards = db.get_bitboards(ply, bb_candidates)
            print("==========")
            for row in bitboards:
                print(row)
            print("----------")
            self.assertEqual(len(bitboards), BITBOARD_COUNT[ply])
            self.assertEqual(sum([row[1] for row in bitboards]), GAME_COUNT)
Beispiel #3
0
    def run(cls, fenstr, variant):
        cls._ensureReady()
        if cls.widgets["newgamedialog"].props.visible:
            cls.widgets["newgamedialog"].present()
            return

        cls._hideOthers()
        for button in ("copy_button", "clear_button", "paste_button", "initial_button"):
            cls.widgets[button].show()
        cls.widgets["newgamedialog"].set_title(_("Setup Position"))
        cls.widgets["setupPositionSidePanel"].show()

        cls.setupmodel = SetupModel()
        cls.board_control = BoardControl(cls.setupmodel,
                                         {},
                                         setup_position=True)
        cls.setupmodel.curplayer = SetupPlayer(cls.board_control)
        cls.setupmodel.connect("game_changed", cls.game_changed)

        child = cls.widgets["setupBoardDock"].get_child()
        if child is not None:
            cls.widgets["setupBoardDock"].remove(child)
        cls.widgets["setupBoardDock"].add(cls.board_control)
        cls.board_control.show_all()
        if fenstr is not None:
            lboard = LBoard(variant)
            lboard.applyFen(fenstr)
            cls.setupmodel.boards = [cls.setupmodel.variant(setup=fenstr, lboard=lboard)]
            cls.setupmodel.variations = [cls.setupmodel.boards]
            cls.ini_widgets(fenstr, lboard)
        else:
            fenstr = cls.get_fen()
            cls.ini_widgets(True)
        cls.widgets["fen_entry"].set_text(fenstr)

        cls.setupmodel.start()
        cls.board_control.emit("action", "SETUP", None, fenstr)

        def _validate(gamemodel):
            try:
                fenstr = cls.get_fen()
                cls.setupmodel.variant(setup=fenstr)
                return True
            except (AssertionError, LoadingError, SyntaxError) as e:
                d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING,
                                      buttons=Gtk.ButtonsType.OK,
                                      message_format=e.args[0])
                if len(e.args) > 1:
                    d.format_secondary_text(e.args[1])
                d.connect("response", lambda d, a: d.hide())
                d.show()
                return False

        def _callback(gamemodel, p0, p1):
            text = cls.get_fen()
            perspective = perspective_manager.get_perspective("games")
            create_task(perspective.generalStart(
                gamemodel, p0, p1, (StringIO(text), fen, 0, -1)))

        cls._generalRun(_callback, _validate)
Beispiel #4
0
    def test_gating_king_move(self):
        board = LBoard(SCHESS)
        board.applyFen(SCHESSSTART)

        for move in "e2e3 e7e5 d1h5 d8e7 h5g4 b8c6 g1f3 d7d5 g4h4 e7c5 h4a4 e5e4 d2d4 c5e7 f3d2 e7b4 a4b4 c6b4".split():
            board.applyMove(parseAN(board, move))
        print("--------")
        print(board)

        moves = set()
        for move in genAllMoves(board):
            moves.add(toAN(board, move))

        self.assertIn("e1d1e", moves)
        self.assertIn("e1d1h", moves)

        fen = board.asFen()
        move = parseAN(board, "e1d1e")
        board.applyMove(move)
        print("e1d1e")
        print(board)

        self.assertEqual(placement(board.asFen()), "r1b1kbnr/ppp2ppp/8/3p4/1n1Pp3/4P3/PPPN1PPP/RNBKEB1R[heH]")

        board.popMove()
        self.assertEqual(placement(board.asFen()), placement(fen))
Beispiel #5
0
    def feed_book(self, records, positions):
        BOOK_DEPTH_MAX = conf.get("book_depth_max")

        for rec in records:
            model = GameModel()

            if rec["Result"] == DRAW:
                score = (1, 1)
            elif rec["Result"] == WHITEWON:
                score = (2, 0)
            elif rec["Result"] == BLACKWON:
                score = (0, 2)
            else:
                score = (0, 0)

            fenstr = rec["FEN"]
            variant = self.chessfile.get_variant(rec)

            if variant:
                model.variant = name2variant[variant]
                board = LBoard(model.variant.variant)
            else:
                model.variant = NormalBoard
                board = LBoard()

            if fenstr:
                try:
                    board.applyFen(fenstr)
                except SyntaxError:
                    continue
            else:
                board.applyFen(FEN_START)

            boards = [board]

            movetext = self.chessfile.get_movetext(rec)
            boards = self.chessfile.parse_movetext(movetext, boards[0], -1)

            for board in boards:
                if board.plyCount > BOOK_DEPTH_MAX:
                    break
                move = board.lastMove
                if move is not None:
                    poly_move = toPolyglot(board.prev, move)
                    # move_str = "%s%s" % (reprCord[FCORD(move)], reprCord[TCORD(move)])
                    # print("%0.16x" % board.prev.hash, poly_move, board.prev.asFen(), move_str)
                    if board.prev.hash in positions:
                        if poly_move in positions[board.prev.hash]:
                            positions[board.prev.hash][poly_move] += score[
                                board.prev.color
                            ]
                        else:
                            positions[board.prev.hash][poly_move] = score[
                                board.prev.color
                            ]
                    else:
                        # board.prev.asFen(), move_str,
                        positions[board.prev.hash] = {
                            poly_move: score[board.prev.color]
                        }
Beispiel #6
0
def benchmark(maxdepth=6):
    """ Times a search of a static list of positions. """

    suite_time = time()
    suite_nodes = lsearch.nodes
    lsearch.endtime = sys.maxsize
    lsearch.searching = True
    for i, fen in enumerate(benchmarkPositions):
        lsearch.table.clear()
        clearPawnTable()
        board = LBoard(NORMALCHESS)
        board.applyFen(fen)
        pos_start_time = time()
        pos_start_nodes = lsearch.nodes
        for depth in range(1, maxdepth):
            mvs, scr = lsearch.alphaBeta(board, depth)
            pos_time = time() - pos_start_time
            pos_nodes = lsearch.nodes - pos_start_nodes
            pv = " ".join(listToSan(board, mvs))
            time_cs = int(100 * pos_time)
            print(depth, scr, time_cs, pos_nodes, pv)
        print("Searched position", i, "at",
              int(pos_nodes / pos_time) if pos_time > 0 else pos_nodes, "n/s")
    suite_time = time() - suite_time
    suite_nodes = lsearch.nodes - suite_nodes
    print("Total:", suite_nodes, "nodes in", suite_time, "s: ",
          suite_nodes / suite_time, "n/s")
    lsearch.nodes = 0
Beispiel #7
0
def benchmark(maxdepth=6):
    """ Times a search of a static list of positions. """

    suite_time = time()
    suite_nodes = lsearch.nodes
    lsearch.endtime = sys.maxsize
    lsearch.searching = True
    for i, fen in enumerate(benchmarkPositions):
        lsearch.table.clear()
        clearPawnTable()
        board = LBoard(NORMALCHESS)
        board.applyFen(fen)
        pos_start_time = time()
        pos_start_nodes = lsearch.nodes
        for depth in range(1, maxdepth):
            mvs, scr = lsearch.alphaBeta(board, depth)
            pos_time = time() - pos_start_time
            pos_nodes = lsearch.nodes - pos_start_nodes
            pv = " ".join(listToSan(board, mvs))
            time_cs = int(100 * pos_time)
            print(depth, scr, time_cs, pos_nodes, pv)
        print("Searched position", i, "at", int(pos_nodes / pos_time) if pos_time > 0 else pos_nodes, "n/s")
    suite_time = time() - suite_time
    suite_nodes = lsearch.nodes - suite_nodes
    print("Total:", suite_nodes, "nodes in", suite_time, "s: ", suite_nodes /
          suite_time, "n/s")
    lsearch.nodes = 0
Beispiel #8
0
    def test_default_gating_avail(self):
        board = LBoard(SCHESS)
        board.applyFen(SCHESSSTART)

        print(board)
        print(toString(board.virgin[0]))
        print(toString(board.virgin[1]))

        self.assertEqual(board.virgin[0], brank8[1])
        self.assertEqual(board.virgin[1], brank8[0])

        board = LBoard(SCHESS)
        FEN = "r1hqerk1/pp1nbppp/2pp1nb1/4p3/2PPP3/2N1B1PP/PP2NPB1/RH1QK2R/E w KQHEDA - 2 10"
        board.applyFen(FEN)
        print("-----------")
        print(board)

        move = parseSAN(board, "O-O")
        board.applyMove(move)
        castl = board.asFen().split()[2]

        self.assertNotIn("Q", castl)
        self.assertNotIn("K", castl)
        self.assertNotIn("E", castl)
        self.assertNotIn("H", castl)
    def as_fen(self, variant):
        fenstr = []
        for r, row in enumerate(reversed(self.data)):
            empty = 0
            for i in range(0, 8):
                piece = row.get(i)
                if piece is not None:
                    if empty > 0:
                        fenstr.append(str(empty))
                        empty = 0
                    sign = reprSign[piece.piece]
                    if piece.color == BLACK:
                        sign = sign.lower()
                    else:
                        sign = sign.upper()
                    fenstr.append(sign)
                else:
                    empty += 1
            if empty > 0:
                fenstr.append(str(empty))
            if r != 7:
                fenstr.append("/")

        board = LBoard(variant)
        board.applyFen("".join(fenstr) + " w")
        return board.asFen().split()[0]
Beispiel #10
0
    def test_gating_castle_at_rook_bOO(self):
        board = LBoard(SCHESS)
        board.applyFen(SCHESSSTART)

        for move in "e2e3 e7e6 g1f3 c7c6 c2c3 d7d5 d2d4 g8f6 h2h3 f6e4 d1c2 b8d7 f1d3 f7f5 e1g1e d8c7 e1e2 f8e7 c2d1".split():
            board.applyMove(parseAN(board, move))

        moves = set()
        for move in genAllMoves(board):
            moves.add(toAN(board, move))
        print("--------")
        print(board)

        self.assertIn("h8e8h", moves)
        self.assertIn("h8e8e", moves)

        fen = board.asFen()
        move = parseAN(board, "h8e8h")
        board.applyMove(move)
        print("h8e8e")
        print(board)

        self.assertEqual(placement(board.asFen()), "r1b2rkh/ppqnb1pp/2p1p3/3p1p2/3Pn3/2PBPN1P/PP2EPP1/RNBQ1RK1[eH]")

        board.popMove()
        self.assertEqual(placement(board.asFen()), placement(fen))
Beispiel #11
0
    def test_gating_castle_at_rook_wOO(self):
        FEN = "r2qk2r/pppbbppp/4pn2/1N1p4/1n1P4/4PN2/PPPBBPPP/R2QK2R[heHE] w KQkq - 10 8"
        board = LBoard(SCHESS)
        board.applyFen(FEN)

        moves = set()
        for move in genAllMoves(board):
            moves.add(toAN(board, move))
        print("--------")
        print(board)

        self.assertIn("h1e1h", moves)
        self.assertIn("h1e1e", moves)

        self.assertEqual(repr(Move.Move(parseSAN(board, 'O-O/Hh1'))), 'h1e1h')
        self.assertEqual(repr(Move.Move(parseSAN(board, 'O-O/Eh1'))), 'h1e1e')

        self.assertEqual(toSAN(board, newMove(H1, E1, HAWK_GATE_AT_ROOK)), "O-O/Hh1")
        self.assertEqual(toSAN(board, newMove(H1, E1, ELEPHANT_GATE_AT_ROOK)), "O-O/Eh1")

        fen = board.asFen()
        move = parseAN(board, "h1e1e")
        board.applyMove(move)
        print("h1e1e")
        print(board)

        self.assertEqual(placement(board.asFen()), "r2qk2r/pppbbppp/4pn2/1N1p4/1n1P4/4PN2/PPPBBPPP/R2Q1RKE[heH]")

        board.popMove()
        self.assertEqual(placement(board.asFen()), placement(fen))
Beispiel #12
0
    def test_gating_castle_at_rook_wOOO(self):
        board = LBoard(SCHESS)
        board.applyFen(SCHESSSTART)

        for move in "e2e4 d7d6 d1e2 c8d7 g1f3 g8f6 e4e5 f6d5 e2e4 d5b6 d2d3 d7c6 e4f5 c6d7 f5g5 g7g6 f3d4 h7h5 g5f4 d6e5 f4h4 f8g7 d4f3 d7g4 b1c3 f7f6 c3e4 d8d5 e4c3 d5c5 c1e3 c5d6 h2h3 g4f3 g2f3 e8g8h".split():
            board.applyMove(parseAN(board, move))

        moves = set()
        for move in genAllMoves(board):
            moves.add(toAN(board, move))
        print("--------")
        print(board)

        self.assertIn("a1e1h", moves)
        self.assertIn("a1e1e", moves)

        fen = board.asFen()
        parseAN(board, "a1e1e")
        board.applyMove(move)
        print("a1e1e")
        print(board)

        self.assertEqual(placement(board.asFen()), "rn2hrk1/ppp1p1b1/1n1q1pp1/4p2p/7Q/2NPBP1P/PPP2P2/E1KR1B1R[eH]")

        board.popMove()
        self.assertEqual(placement(board.asFen()), placement(fen))
Beispiel #13
0
 def testFEN(self):
     """Testing board-FEN conversion with several positions"""
     for i, fenstr in enumerate(self.positions[1:]):
         board = LBoard()
         board.applyFen(fenstr)
         fenstr2 = board.asFen()
         self.assertEqual(fenstr, fenstr2)
Beispiel #14
0
    def testPolyglot_1(self):
        """Testing hash keys agree with Polyglot's"""

        for testcase in testcases:
            board = LBoard(Board)
            board.applyFen(testcase[0])
            self.assertEqual(board.hash, testcase[1])
Beispiel #15
0
    def test_paresSAN1(self):
        """Testing parseSAN with unambiguous notations variants"""
        
        board = LBoard()
        board.applyFen("4k2B/8/8/8/8/8/8/B3K3 w - - 0 1")        

        self.assertEqual(repr(Move(parseSAN(board, 'Ba1b2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'Bh8b2'))), 'h8b2')

        self.assertEqual(repr(Move(parseSAN(board, 'Bab2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'Bhb2'))), 'h8b2')

        self.assertEqual(repr(Move(parseSAN(board, 'B1b2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'B8b2'))), 'h8b2')


        board = LBoard()
        board.applyFen("4k2B/8/8/8/8/8/1b6/B3K3 w - - 0 1")        

        self.assertEqual(repr(Move(parseSAN(board, 'Ba1xb2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'Bh8xb2'))), 'h8b2')

        self.assertEqual(repr(Move(parseSAN(board, 'Baxb2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'Bhxb2'))), 'h8b2')

        self.assertEqual(repr(Move(parseSAN(board, 'B1xb2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'B8xb2'))), 'h8b2')
Beispiel #16
0
    def test_paresSAN1(self):
        """Testing parseSAN with unambiguous notations variants"""

        board = LBoard()
        board.applyFen("4k2B/8/8/8/8/8/8/B3K3 w - - 0 1")

        self.assertEqual(repr(Move(parseSAN(board, 'Ba1b2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'Bh8b2'))), 'h8b2')

        self.assertEqual(repr(Move(parseSAN(board, 'Bab2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'Bhb2'))), 'h8b2')

        self.assertEqual(repr(Move(parseSAN(board, 'B1b2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'B8b2'))), 'h8b2')

        board = LBoard()
        board.applyFen("4k2B/8/8/8/8/8/1b6/B3K3 w - - 0 1")

        self.assertEqual(repr(Move(parseSAN(board, 'Ba1xb2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'Bh8xb2'))), 'h8b2')

        self.assertEqual(repr(Move(parseSAN(board, 'Baxb2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'Bhxb2'))), 'h8b2')

        self.assertEqual(repr(Move(parseSAN(board, 'B1xb2'))), 'a1b2')
        self.assertEqual(repr(Move(parseSAN(board, 'B8xb2'))), 'h8b2')
Beispiel #17
0
    def testPolyglot_1(self):
        """Testing hash keys agree with Polyglot's"""

        for testcase in testcases:
            board = LBoard(Board)
            board.applyFen(testcase[0])
            self.assertEqual(board.hash, testcase[1])
    def create_fen(self, pieces):
        """ Create a random FEN position using given pieces """

        pos = pieces.rfind("k")
        pieces = pieces[:pos], pieces[pos:]

        ok = False
        while not ok:
            lboard = LBoard()
            lboard.applyFen("8/8/8/8/8/8/8/8 w - - 0 1")

            cords = list(range(0, 64))
            pawn_cords = list(range(0 + 8, 64 - 8))
            for color in (BLACK, WHITE):
                for char in pieces[color]:
                    piece = chrU2Sign[char.upper()]
                    cord = random.choice(pawn_cords if char == "p" else cords)
                    lboard._addPiece(cord, piece, color)
                    cords.remove(cord)
                    if cord in pawn_cords:
                        pawn_cords.remove(cord)
            # TODO: 2 same color bishop is not ok
            ok = (not lboard.isChecked()) and (not lboard.opIsChecked())

        fen = lboard.asFen()
        return fen
Beispiel #19
0
    def run(cls, fenstr, variant):
        cls._ensureReady()
        if cls.widgets["newgamedialog"].props.visible:
            cls.widgets["newgamedialog"].present()
            return

        cls._hideOthers()
        for button in ("copy_button", "clear_button", "paste_button", "initial_button"):
            cls.widgets[button].show()
        cls.widgets["newgamedialog"].set_title(_("Setup Position"))
        cls.widgets["setupPositionSidePanel"].show()

        cls.setupmodel = SetupModel()
        cls.board_control = BoardControl(cls.setupmodel,
                                         {},
                                         setup_position=True)
        cls.setupmodel.curplayer = SetupPlayer(cls.board_control)
        cls.setupmodel.connect("game_changed", cls.game_changed)

        child = cls.widgets["setupBoardDock"].get_child()
        if child is not None:
            cls.widgets["setupBoardDock"].remove(child)
        cls.widgets["setupBoardDock"].add(cls.board_control)
        cls.board_control.show_all()
        if fenstr is not None:
            lboard = LBoard(variant)
            lboard.applyFen(fenstr)
            cls.setupmodel.boards = [cls.setupmodel.variant(setup=fenstr, lboard=lboard)]
            cls.setupmodel.variations = [cls.setupmodel.boards]
            cls.ini_widgets(fenstr, lboard)
        else:
            fenstr = cls.get_fen()
            cls.ini_widgets(True)
        cls.widgets["fen_entry"].set_text(fenstr)

        cls.setupmodel.start()

        def _validate(gamemodel):
            try:
                fenstr = cls.get_fen()
                cls.setupmodel.variant(setup=fenstr)
                return True
            except (AssertionError, LoadingError, SyntaxError) as e:
                d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING,
                                      buttons=Gtk.ButtonsType.OK,
                                      message_format=e.args[0])
                if len(e.args) > 1:
                    d.format_secondary_text(e.args[1])
                d.connect("response", lambda d, a: d.hide())
                d.show()
                return False

        def _callback(gamemodel, p0, p1):
            text = cls.get_fen()
            perspective = perspective_manager.get_perspective("games")
            create_task(perspective.generalStart(
                gamemodel, p0, p1, (StringIO(text), fen, 0, -1)))

        cls._generalRun(_callback, _validate)
Beispiel #20
0
    def test_toSAN(self):
        """ Testing toSAN() with giveaway king move """

        board = LBoard(GIVEAWAYCHESS)
        board.applyFen("4R3/8/7B/2P5/8/8/PP5k/6k1 b - - 0 28")

        self.assertEqual(toSAN(board, newMove(G1, G2)), "Kgg2")
        self.assertEqual(toSAN(board, newMove(H2, G2)), "Khg2")
Beispiel #21
0
    def test_apply_pop(self):
        """Testing Atomic applyMove popMove"""

        board = LBoard(variant=ATOMICCHESS)
        board.applyFen(FEN)
        print(board)
        hist_exploding_around0 = [a[:] for a in board.hist_exploding_around]
        print_apply_pop = False

        for lmove1 in genAllMoves(board):
            board.applyMove(lmove1)
            if board.opIsChecked():
                if print_apply_pop: print("popMove1 (invalid)", Move(lmove1))
                board.popMove()
                continue

            hist_exploding_around1 = [
                a[:] for a in board.hist_exploding_around
            ]
            for lmove2 in genAllMoves(board):
                board.applyMove(lmove2)
                if print_apply_pop: print("   applyMove2", Move(lmove2))
                if board.opIsChecked():
                    if print_apply_pop:
                        print("   popMove2 (invalid)", Move(lmove2))
                    board.popMove()
                    continue

                hist_exploding_around2 = [
                    a[:] for a in board.hist_exploding_around
                ]
                for lmove3 in genAllMoves(board):
                    board.applyMove(lmove3)
                    if print_apply_pop: print("      applyMove3", Move(lmove3))
                    if board.opIsChecked():
                        if print_apply_pop:
                            print("      popMove3 (invalid)", Move(lmove3))
                        board.popMove()
                        continue

                    board.popMove()
                    if print_apply_pop: print("      popMove3", Move(lmove3))

                    self.assertEqual(hist_exploding_around2,
                                     board.hist_exploding_around)

                board.popMove()
                if print_apply_pop: print("   popMove2", Move(lmove2))

                self.assertEqual(hist_exploding_around1,
                                 board.hist_exploding_around)

            board.popMove()
            if print_apply_pop: print("popMove1", Move(lmove1))

            self.assertEqual(hist_exploding_around0,
                             board.hist_exploding_around)
Beispiel #22
0
    def test_gating_san_move(self):
        board = LBoard(SCHESS)
        board.applyFen(SCHESSSTART)

        self.assertEqual(repr(Move.Move(parseSAN(board, 'Nf3/H'))), 'g1f3h')
        self.assertEqual(repr(Move.Move(parseSAN(board, 'Nf3/E'))), 'g1f3e')

        self.assertEqual(toSAN(board, newMove(G1, F3, HAWK_GATE)), "Nf3/H")
        self.assertEqual(toSAN(board, newMove(G1, F3, ELEPHANT_GATE)), "Nf3/E")
Beispiel #23
0
 def testFEN(self):
     """Testing board-FEN conversion with several positions"""
     print
     board = LBoard(Board)
     for i, fenstr in enumerate(self.positions[1:]):
         sys.stdout.write("#")
         board.applyFen(fenstr)
         fenstr2 = board.asFen()
         self.assertEqual(fenstr, fenstr2)
     print
Beispiel #24
0
 def testFEN(self):
     """Testing board-FEN conversion with several positions"""
     print
     board = LBoard(Board)
     for i, fenstr in enumerate(self.positions[1:]):
         sys.stdout.write("#")
         board.applyFen(fenstr)
         fenstr2 = board.asFen()
         self.assertEqual(fenstr, fenstr2)
     print
Beispiel #25
0
    def test_paresSAN2(self):
        """Testing parseAN and parseSAN with bad promotions moves"""

        board = LBoard()
        board.applyFen("4k3/P7/8/8/8/8/8/4K3 w - - 0 1")

        self.assertRaises(ParsingError, parseAN, board, 'a7a8K')
        self.assertRaises(ParsingError, parseAN, board, 'a7a8')

        self.assertRaises(ParsingError, parseSAN, board, 'a8K')
        self.assertRaises(ParsingError, parseSAN, board, 'a8')
Beispiel #26
0
    def testFRCCastlingUCI(self):
        """Testing UCI engine FRC castling move"""
        print()

        fen = "rbq1krb1/pp1pp1pp/2p1n3/5p2/2PP1P1n/4B1N1/PP2P1PP/RBQNKR2 w FAfa - 2 6"
        print(fen)
        board = LBoard(FISCHERRANDOMCHESS)
        board.applyFen(fen)
        # print board
        moves = [move for move in genCastles(board)]
        self.assertTrue(parseAN(board, "e1g1") in moves)
Beispiel #27
0
    def test_paresSAN2(self):
        """Testing parseAN and parseSAN with bad promotions moves"""

        board = LBoard()
        board.applyFen("4k3/P7/8/8/8/8/8/4K3 w - - 0 1")

        self.assertRaises(ParsingError, parseAN, board, 'a7a8K')
        # If promotion piece is missing pychess assumes queen promotion from 0.99.2
        # self.assertRaises(ParsingError, parseAN, board, 'a7a8')

        self.assertRaises(ParsingError, parseSAN, board, 'a8K')
Beispiel #28
0
    def testFRCCastlingUCI(self):
        """Testing UCI engine FRC castling move"""
        print()

        fen = "rbq1krb1/pp1pp1pp/2p1n3/5p2/2PP1P1n/4B1N1/PP2P1PP/RBQNKR2 w FAfa - 2 6"
        print(fen)
        board = LBoard(FISCHERRANDOMCHESS)
        board.applyFen(fen)
        # print board
        moves = [move for move in genCastles(board)]
        self.assertTrue(parseAN(board, "e1g1") in moves)
Beispiel #29
0
    def test_paresSAN2(self):
        """Testing parseAN and parseSAN with bad promotions moves"""
        
        board = LBoard()
        board.applyFen("4k3/P7/8/8/8/8/8/4K3 w - - 0 1")        

        self.assertRaises(ParsingError, parseAN, board, 'a7a8K')
        self.assertRaises(ParsingError, parseAN, board, 'a7a8')

        self.assertRaises(ParsingError, parseSAN, board, 'a8K')
        self.assertRaises(ParsingError, parseSAN, board, 'a8')
Beispiel #30
0
    def test_gating_castle_at_rook_wOOO_SAN(self):
        FEN = "r2ek2r/5pp1/1pp1pnp1/2pp1h2/3P4/2P1PP2/PP1N2PP/R3K1HR/E w KQHEAkq - 2 16"
        board = LBoard(SCHESS)
        board.applyFen(FEN)

        self.assertEqual(repr(Move.Move(parseSAN(board, 'O-O-O'))), 'e1c1')
        self.assertEqual(repr(Move.Move(parseSAN(board, 'O-O-O/Ea1'))), 'a1e1e')
        self.assertEqual(repr(Move.Move(parseSAN(board, 'O-O-O/Ee1'))), 'e1c1e')

        self.assertEqual(toSAN(board, newMove(E1, C1, QUEEN_CASTLE)), "O-O-O")
        self.assertEqual(toSAN(board, newMove(A1, E1, ELEPHANT_GATE_AT_ROOK)), "O-O-O/Ea1")
        self.assertEqual(toSAN(board, newMove(E1, C1, ELEPHANT_GATE)), "O-O-O/Ee1")
Beispiel #31
0
    def feed_book(self, records, positions):
        for rec in records:
            model = GameModel()

            if rec["Result"] == DRAW:
                score = (1, 1)
            elif rec["Result"] == WHITEWON:
                score = (2, 0)
            elif rec["Result"] == BLACKWON:
                score = (0, 2)
            else:
                score = (0, 0)

            fenstr = rec["FEN"]
            variant = self.chessfile.get_variant(rec)

            if variant:
                model.variant = name2variant[variant]
                board = LBoard(model.variant.variant)
            else:
                model.variant = NormalBoard
                board = LBoard()

            if fenstr:
                try:
                    board.applyFen(fenstr)
                except SyntaxError as err:
                    continue
            else:
                board.applyFen(FEN_START)

            boards = [board]

            movetext = self.chessfile.get_movetext(rec)
            boards = self.chessfile.parse_movetext(movetext, boards[0], -1)

            for board in boards:
                if board.plyCount > BOOK_DEPTH:
                    break
                move = board.lastMove
                if move is not None:
                    poly_move = toPolyglot(board.prev, move)
                    # move_str = "%s%s" % (reprCord[FCORD(move)], reprCord[TCORD(move)])
                    # print("%0.16x" % board.prev.hash, poly_move, board.prev.asFen(), move_str)
                    if board.prev.hash in positions:
                        if poly_move in positions[board.prev.hash]:
                            positions[board.prev.hash][poly_move] += score[board.prev.color]
                        else:
                            positions[board.prev.hash][poly_move] = score[board.prev.color]
                    else:
                        # board.prev.asFen(), move_str,
                        positions[board.prev.hash] = {poly_move: score[board.prev.color]}
Beispiel #32
0
    def test_promotion(self):
        # promotion moves
        FEN = "r4knr/1bpp1Pp1/pp3b2/q2pep1p/3N4/P1N5/1PPQBPPP/R1B1K2R[hHE] w KQ - 1 17"
        board = LBoard(SCHESS)
        board.applyFen(FEN)
        print("--------")
        print(board)

        moves = set()
        for move in genAllMoves(board):
            moves.add(toAN(board, move))

        self.assertIn("f7g8=H", moves)
        self.assertIn("f7g8=E", moves)
Beispiel #33
0
    def testFEN(self):
        """Testing board-FEN conversion with several positions"""

        positions = []
        with open('gamefiles/perftsuite.epd') as f:
            for line in f:
                semi = line.find(" ;")
                positions.append(line[:semi])

        for i, fenstr in enumerate(positions[1:]):
            board = LBoard()
            board.applyFen(fenstr)
            fenstr2 = board.asFen()
            self.assertEqual(fenstr, fenstr2)
Beispiel #34
0
    def testFRCCastling(self):
        """Testing FRC castling movegen"""
        print()

        for fen, castles in data:
            print(fen)
            board = LBoard(FISCHERRANDOMCHESS)
            board.applyFen(fen)
            # print board
            moves = [move for move in genCastles(board)]
            self.assertEqual(len(moves), len(castles))
            for i, castle in enumerate(castles):
                kfrom, kto, flag = castle
                self.assertEqual(moves[i], newMove(kfrom, kto, flag))
Beispiel #35
0
    def testFRCCastling(self):
        """Testing FRC castling movegen"""
        print()

        for fen, castles in data:
            print(fen)
            board = LBoard(FISCHERRANDOMCHESS)
            board.applyFen(fen)
            # print board
            moves = [move for move in genCastles(board)]
            self.assertEqual(len(moves), len(castles))
            for i, castle in enumerate(castles):
                kfrom, kto, flag = castle
                self.assertEqual(moves[i], newMove(kfrom, kto, flag))
Beispiel #36
0
class EvalTestCase(unittest.TestCase):
    
    def setUp (self):
        self.board = LBoard(NORMALCHESS)
        self.board.applyFen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1")
    
    def test1(self):
        """Testing eval symmetry with startboard (WHITE)"""
        score = evaluateComplete(self.board, color=WHITE)
        self.assertEqual(score, 0)
    
    def test2(self):
        """Testing eval symmetry with startboard (BLACK)"""
        score = evaluateComplete(self.board, color=BLACK)
        self.assertEqual(score, 0)
    
    def test3(self):
        """Testing eval symmetry of each function"""
        funcs = (f for f in dir(leval) if f.startswith("eval"))
        funcs = (getattr(leval,f) for f in funcs)
        funcs = (f for f in funcs if callable(f) \
                                    and f != leval.evaluateComplete\
                                    and f != leval.evalMaterial\
                                    and f != leval.evalPawnStructure\
                                    and f != leval.evalTrappedBishops)
        
        sw, phasew = leval.evalMaterial (self.board, WHITE)
        sb, phaseb = leval.evalMaterial (self.board, BLACK)

        self.assertEqual(phasew, phaseb)
        
        pawnScore, passed, weaked = leval.cacheablePawnInfo (self.board, phasew)
        sw = leval.evalPawnStructure (self.board, WHITE, phasew, passed, weaked)

        pawnScore, passed, weaked = leval.cacheablePawnInfo (self.board, phaseb)
        sb = leval.evalPawnStructure (self.board, BLACK, phaseb, passed, weaked)

        self.assertEqual(sw, sb)

        sw = leval.evalTrappedBishops (self.board, WHITE)
        sb = leval.evalTrappedBishops (self.board, BLACK)

        self.assertEqual(sw, sb)

        for func in funcs:
            sw = func(self.board, WHITE, phasew)
            sb = func(self.board, BLACK, phaseb)
            #print func, sw, sb
            self.assertEqual(sw, sb)
Beispiel #37
0
    def movegen(self, positions, variant):
        for i, (fen, depths) in enumerate(positions):
            print(i + 1, "/", len(positions), "-", fen)
            board = LBoard(variant)
            board.applyFen(fen)
            hash = board.hash

            for depth, suposedMoveCount in depths:
                if depth > self.MAXDEPTH:
                    break
                self.count = 0
                print("searching depth %d for %d moves" % (depth, suposedMoveCount))
                self.perft(board, depth, [])
                self.assertEqual(board.hash, hash)
                self.assertEqual(self.count, suposedMoveCount)
Beispiel #38
0
    def movegen(self, positions, variant):
        for i, (fen, depths) in enumerate(positions):
            print(i + 1, "/", len(positions), "-", fen)
            board = LBoard(variant)
            board.applyFen(fen)
            hash = board.hash

            for depth, suposedMoveCount in depths:
                if depth > self.MAXDEPTH:
                    break
                self.count = 0
                print("searching depth %d for %d moves" % (depth, suposedMoveCount))
                self.perft(board, depth, [])
                self.assertEqual(board.hash, hash)
                self.assertEqual(self.count, suposedMoveCount)
Beispiel #39
0
    def test_apply_pop(self):
        """Testing Atomic applyMove popMove"""

        board = LBoard(variant=ATOMICCHESS)
        board.applyFen(FEN1)
        print(board)
        hist_exploding_around0 = [a[:] for a in board.hist_exploding_around]
        print_apply_pop = False

        for lmove1 in genAllMoves(board):
            board.applyMove(lmove1)
            if board.opIsChecked():
                if print_apply_pop: print("popMove1 (invalid)", Move(lmove1))
                board.popMove()
                continue
                
            hist_exploding_around1 = [a[:] for a in board.hist_exploding_around]
            for lmove2 in genAllMoves(board):
                board.applyMove(lmove2)
                if print_apply_pop: print("   applyMove2", Move(lmove2))
                if board.opIsChecked():
                    if print_apply_pop: print("   popMove2 (invalid)", Move(lmove2))
                    board.popMove()
                    continue

                hist_exploding_around2 = [a[:] for a in board.hist_exploding_around]
                for lmove3 in genAllMoves(board):
                    board.applyMove(lmove3)
                    if print_apply_pop: print("      applyMove3", Move(lmove3))
                    if board.opIsChecked():
                        if print_apply_pop: print("      popMove3 (invalid)", Move(lmove3))
                        board.popMove()
                        continue

                    board.popMove()
                    if print_apply_pop: print("      popMove3", Move(lmove3))

                    self.assertEqual(hist_exploding_around2, board.hist_exploding_around)

                board.popMove()
                if print_apply_pop: print("   popMove2", Move(lmove2))

                self.assertEqual(hist_exploding_around1, board.hist_exploding_around)
                
            board.popMove()
            if print_apply_pop: print("popMove1", Move(lmove1))

            self.assertEqual(hist_exploding_around0, board.hist_exploding_around)
Beispiel #40
0
def create_fen(pieces):
    """ Create a random FEN position using given pieces """

    pos = pieces.rfind("k")
    pieces = pieces[:pos], pieces[pos:]

    ok = False
    while not ok:
        lboard = LBoard()
        lboard.applyFen("8/8/8/8/8/8/8/8 w - - 0 1")
        bishop_cords = [[], []]
        bishop_colors_ok = True

        cords = list(range(0, 64))
        pawn_cords = list(range(0 + 8, 64 - 8))

        # Order of color is important here to prevent offering
        # positions with trivial captures in first move
        for color in (WHITE, BLACK):
            for char in pieces[color]:
                piece = chrU2Sign[char.upper()]
                attacked = True
                limit = 100
                while attacked and limit > 0:
                    cord = random.choice(pawn_cords if char == "p" else cords)
                    attacked = isAttacked(lboard, cord, 1 - color)
                    limit -= 1
                lboard._addPiece(cord, piece, color)
                cords.remove(cord)
                if cord in pawn_cords:
                    pawn_cords.remove(cord)
                if char == "b":
                    bishop_cords[color].append(cord)

            # 2 same color bishop is not ok
            if len(bishop_cords[color]) == 2 and bishop_colors_ok:
                b0, b1 = bishop_cords[color]
                b0_color = BLACK if RANK(b0) % 2 == FILE(b0) % 2 else WHITE
                b1_color = BLACK if RANK(b1) % 2 == FILE(b1) % 2 else WHITE
                if b0_color == b1_color:
                    bishop_colors_ok = False
                    break

        ok = (not lboard.isChecked()) and (
            not lboard.opIsChecked()) and bishop_colors_ok

    fen = lboard.asFen()
    return fen
Beispiel #41
0
    def test_parseFAN(self):
        """Testing parseFAN"""

        board = LBoard()
        board.applyFen("rnbqkbnr/8/8/8/8/8/8/RNBQKBNR w KQkq - 0 1")

        for lmove in genAllMoves(board):
            board.applyMove(lmove)
            if board.opIsChecked():
                board.popMove()
                continue

            board.popMove()

            fan = toFAN(board, lmove)
            self.assertEqual(parseFAN(board, fan), lmove)
Beispiel #42
0
    def test_parseFAN(self):
        """Testing parseFAN"""

        board = LBoard()
        board.applyFen("rnbqkbnr/8/8/8/8/8/8/RNBQKBNR w KQkq - 0 1")        

        for lmove in genAllMoves(board):
            board.applyMove(lmove)
            if board.opIsChecked():
                board.popMove()
                continue

            board.popMove()

            fan = toFAN(board, lmove)
            self.assertEqual(parseFAN(board, fan), lmove)
Beispiel #43
0
def create_fen(pieces):
    """ Create a random FEN position using given pieces """

    pos = pieces.rfind("k")
    pieces = pieces[:pos], pieces[pos:]

    ok = False
    while not ok:
        lboard = LBoard()
        lboard.applyFen("8/8/8/8/8/8/8/8 w - - 0 1")
        bishop_cords = [[], []]
        bishop_colors_ok = True

        cords = list(range(0, 64))
        pawn_cords = list(range(0 + 8, 64 - 8))

        # Order of color is important here to prevent offering
        # positions with trivial captures in first move
        for color in (WHITE, BLACK):
            for char in pieces[color]:
                piece = chrU2Sign[char.upper()]
                attacked = True
                limit = 100
                while attacked and limit > 0:
                    cord = random.choice(pawn_cords if char == "p" else cords)
                    attacked = isAttacked(lboard, cord, 1 - color)
                    limit -= 1
                lboard._addPiece(cord, piece, color)
                cords.remove(cord)
                if cord in pawn_cords:
                    pawn_cords.remove(cord)
                if char == "b":
                    bishop_cords[color].append(cord)

            # 2 same color bishop is not ok
            if len(bishop_cords[color]) == 2 and bishop_colors_ok:
                b0, b1 = bishop_cords[color]
                b0_color = BLACK if RANK(b0) % 2 == FILE(b0) % 2 else WHITE
                b1_color = BLACK if RANK(b1) % 2 == FILE(b1) % 2 else WHITE
                if b0_color == b1_color:
                    bishop_colors_ok = False
                    break

        ok = (not lboard.isChecked()) and (not lboard.opIsChecked()) and bishop_colors_ok

    fen = lboard.asFen()
    return fen
Beispiel #44
0
    def test_black_promotion(self):
        FEN = "k7/8/8/8/8/8/p7/7K b - - 0 1"
        board = LBoard(LIGHTBRIGADECHESS)
        board.applyFen(FEN)
        print("--------")
        print(board)

        moves = set()
        for move in genAllMoves(board):
            moves.add(toAN(board, move))

        self.assertIn("a2a1=N", moves)
        self.assertNotIn("a2a1", moves)
        self.assertNotIn("a2a1=R", moves)
        self.assertNotIn("a2a1=B", moves)
        self.assertNotIn("a2a1=Q", moves)
        self.assertNotIn("a2a1=K", moves)
Beispiel #45
0
            def on_book_created(persp, event):
                self.assertTrue(os.path.isfile(BIN))

                book.path = BIN
                book.bookfile = True

                testcase = testcases[0]
                board = LBoard(Board)
                board.applyFen(testcase[0])
                openings = book.getOpenings(board)
                self.assertEqual(sorted(openings), sorted([(newMove(E2, E4), 2, 0), (newMove(A2, A4), 0, 0)]))

                testcase = testcases[-1]
                board = LBoard(Board)
                board.applyFen(testcase[0])
                openings = book.getOpenings(board)
                self.assertEqual(openings, [])

                event.set()
Beispiel #46
0
    def movegen(self, positions):
        for i, (fen, depths) in enumerate(positions):
            board = LBoard(FISCHERRANDOMCHESS)
            fen = fen.split()
            castl = fen[2]
            castl = castl.replace("K", "H")
            castl = castl.replace("Q", "A")
            castl = castl.replace("k", "h")
            castl = castl.replace("q", "a")
            fen[2] = castl
            fen = ' '.join(fen)

            print(i+1, "/", len(positions), "-", fen)
            board.applyFen(fen)
            
            for depth, suposedMoveCount in enumerate(depths):
                if depth+1 > self.MAXDEPTH: break
                self.count = 0
                print("searching depth %d for %d moves" % \
                        (depth+1, suposedMoveCount))
                self.perft (board, depth+1, [])
                self.assertEqual(self.count, suposedMoveCount)
Beispiel #47
0
class EvalTestCase(unittest.TestCase):
    
    def setUp (self):
        self.board = LBoard(NORMALCHESS)
        self.board.applyFen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1")
    
    def test1(self):
        """Testing eval symmetry with startboard (WHITE)"""
        score = evaluateComplete(self.board, color=WHITE, balanced=True)
        self.assertEqual(score, 0)
    
    def test2(self):
        """Testing eval symmetry with startboard (BLACK)"""
        score = evaluateComplete(self.board, color=BLACK, balanced=True)
        self.assertEqual(score, 0)
    
    def test3(self):
        """Testing eval symmetry between colors with balanced=False"""
        scorew = evaluateComplete(self.board, color=WHITE)
        scoreb = evaluateComplete(self.board, color=BLACK)
        self.assertEqual(scorew, scoreb)
    
    def test4(self):
        """Testing eval symmetry of each function"""
        funcs = (f for f in dir(leval) if f.startswith("eval"))
        funcs = (getattr(leval,f) for f in funcs)
        funcs = (f for f in funcs if callable(f) and f != leval.evalMaterial)
        
        sw, phasew = leval.evalMaterial (self.board, WHITE)
        sb, phaseb = leval.evalMaterial (self.board, BLACK)
        self.assertEqual(phasew, phaseb)
        
        for func in funcs:
            sw = func(self.board, WHITE, phasew)
            sb = func(self.board, BLACK, phaseb)
            #print func, sw, sb
            self.assertEqual(sw, sb)
Beispiel #48
0
    def loadToModel (self, gameno, position=-1, model=None):
        if not model:
            model = GameModel()

        # the seven mandatory PGN headers
        model.tags['Event'] = self._getTag(gameno, 'Event')
        model.tags['Site'] = self._getTag(gameno, 'Site')
        model.tags['Date'] = self._getTag(gameno, 'Date')
        model.tags['Round'] = self.get_round(gameno)
        model.tags['White'], model.tags['Black'] = self.get_player_names(gameno)
        model.tags['Result'] = reprResult[self.get_result(gameno)]
        
        pgnHasYearMonthDay = True
        for tag in ('Year', 'Month', 'Day'):
            if not self._getTag(gameno, tag):
                pgnHasYearMonthDay = False
                break
        if model.tags['Date'] and not pgnHasYearMonthDay:
            date_match = re.match(".*(\d{4}).(\d{2}).(\d{2}).*", model.tags['Date'])
            if date_match:
                year, month, day = date_match.groups()
                model.tags['Year'] = year
                model.tags['Month'] = month
                model.tags['Day'] = day
                
        # non-mandatory headers
        for tag in ('Annotator', 'ECO', 'EventDate', 'Time', 'WhiteElo', 'BlackElo', 'TimeControl'):
            if self._getTag(gameno, tag):
                model.tags[tag] = self._getTag(gameno, tag)
            else:
                model.tags[tag] = ""

        # TODO: enable this when NewGameDialog is altered to give user option of
        # whether to use PGN's clock time, or their own custom time. Also,
        # dialog should set+insensitize variant based on the variant of the
        # game selected in the dialog
        if model.tags['TimeControl']:
            secs, gain = parseTimeControlTag(model.tags['TimeControl'])
            model.timed = True
            model.timemodel.secs = secs
            model.timemodel.gain = gain
            model.timemodel.minutes = secs / 60

            for tag, color in (('WhiteClock', WHITE), ('BlackClock', BLACK)):
                if self._getTag(gameno, tag):
                    try:
                        ms = parseClockTimeTag(self._getTag(gameno, tag))
                        model.timemodel.intervals[color][0] = ms / 1000
                    except ValueError: 
                        raise LoadingError( \
                            "Error parsing '%s' Header for gameno %s" % (tag, gameno))
        
        fenstr = self._getTag(gameno, "FEN")
        variant = self.get_variant(gameno)
        
        if variant:
            model.tags["Variant"] = variant
            # Fixes for some non statndard Chess960 .pgn
            if (fenstr is not None) and variant == "Fischerandom":
                parts = fenstr.split()
                parts[0] = parts[0].replace(".", "/").replace("0", "")
                if len(parts) == 1:
                    parts.append("w")
                    parts.append("-")
                    parts.append("-")
                fenstr = " ".join(parts)

            model.variant = name2variant[variant]
            board = LBoard(model.variant.variant)
        else:
            model.variant = NormalBoard
            board = LBoard()

        if fenstr:
            try:
                board.applyFen(fenstr)
            except SyntaxError as e:
                board.applyFen(FEN_EMPTY)
                raise LoadingError(_("The game can't be loaded, because of an error parsing FEN"), e.args[0])
        else:
            board.applyFen(FEN_START)
        
        boards = [board]

        del model.moves[:]
        del model.variations[:]
        
        self.error = None
        movetext = self.get_movetext(gameno)
        
        boards = self.parse_string(movetext, boards[0], position)

        # The parser built a tree of lboard objects, now we have to
        # create the high level Board and Move lists...
        
        for board in boards:
            if board.lastMove is not None:
                model.moves.append(Move(board.lastMove))
        
        self.has_emt = False
        self.has_eval = False
        
        def walk(node, path):
            if node.prev is None:
                # initial game board
                board = model.variant(setup=node.asFen(), lboard=node)
            else:
                move = Move(node.lastMove)
                try:
                    board = node.prev.pieceBoard.move(move, lboard=node)
                except:
                    raise LoadingError(_("Invalid move."), "%s%s" % (move_count(node, black_periods=True), move))

            if node.next is None:
                model.variations.append(path+[board])
            else:
                walk(node.next, path+[board])

            for child in node.children:
                if isinstance(child, list):
                    if len(child) > 1:
                        # non empty variation, go walk
                        walk(child[1], list(path))
                else:
                    if not self.has_emt:
                        self.has_emt = child.find("%emt") >= 0
                    if not self.has_eval:
                        self.has_eval = child.find("%eval") >= 0
        
        # Collect all variation paths into a list of board lists
        # where the first one will be the boards of mainline game.
        # model.boards will allways point to the current shown variation
        # which will be model.variations[0] when we are in the mainline.
        walk(boards[0], [])
        model.boards = model.variations[0]
        
        self.has_emt = self.has_emt and "TimeControl" in model.tags
        if self.has_emt or self.has_eval:
            if self.has_emt:
                blacks = len(model.moves)//2
                whites = len(model.moves)-blacks

                model.timemodel.intervals = [
                    [model.timemodel.intervals[0][0]]*(whites+1),
                    [model.timemodel.intervals[1][0]]*(blacks+1),
                ]
                secs, gain = parseTimeControlTag(model.tags['TimeControl'])
                model.timemodel.intervals[0][0] = secs
                model.timemodel.intervals[1][0] = secs
            
            for ply, board in enumerate(boards):
                for child in board.children:
                    if isinstance(child, basestring):
                        if self.has_emt:
                            match = movetime.search(child)
                            if match:
                                movecount, color = divmod(ply+1, 2)
                                hour, minute, sec, msec = match.groups()
                                prev = model.timemodel.intervals[color][movecount-1]
                                msec = 0 if msec is None else int(msec)
                                msec += int(sec)*1000 + int(minute)*60*1000 + int(hour)*60*60*1000
                                model.timemodel.intervals[color][movecount] = prev - msec/1000
                        
                        if self.has_eval:
                            match = moveeval.search(child)
                            if match:
                                sign, num, fraction, depth = match.groups()
                                sign = 1 if sign is None or sign == "+" else -1
                                num = int(num) if int(num) == MATE_VALUE else int(num)
                                fraction = 0 if fraction is None else float(fraction)/100
                                value = sign * (num + fraction)
                                depth = "" if depth is None else depth
                                model.scores[ply] = ("", value, depth)

            log.debug("pgn.loadToModel: intervals %s" % model.timemodel.intervals)

        # Find the physical status of the game
        model.status, model.reason = getStatus(model.boards[-1])
        
        # Apply result from .pgn if the last position was loaded
        if position == -1 or len(model.moves) == position - model.lowply:
            status = self.get_result(gameno)
            if status in (WHITEWON, BLACKWON) and status != model.status:
                model.status = status
                model.reason = WON_RESIGN
            elif status == DRAW and status != model.status:
                model.status = DRAW
                model.reason = DRAW_AGREE
        
        # If parsing gave an error we throw it now, to enlarge our possibility
        # of being able to continue the game from where it failed.
        if self.error:
            raise self.error

        return model
Beispiel #49
0
class PyChessCECP(PyChess):
    def __init__(self):
        PyChess.__init__(self)
        self.board = LBoard(NORMALCHESS)
        self.board.applyFen(FEN_START)

        self.forced = False
        self.analyzing = False
        self.thread = None

        self.basetime = 0

        self.features = {
            "ping": 1,
            "setboard": 1,
            "playother": 1,
            "san": 1,
            "usermove": 1,
            "time": 1,
            "draw": 1,
            "sigint": 0,
            "sigterm": 0,
            "reuse": 1,
            "analyze": 1,
            "myname": "PyChess %s" % pychess.VERSION,
            "variants": "normal,wildcastle,nocastle,fischerandom,crazyhouse," +
                        "losers,suicide,giveaway,horde,atomic," +
                        "kingofthehill,3check,asean,cambodian,makruk,sittuyin",
            "colors": 0,
            "ics": 0,
            "name": 0,
            "pause": 0,  # Unimplemented
            "nps": 0,  # Unimplemented
            "debug": 1,
            "memory": 0,  # Unimplemented
            "smp": 0,  # Unimplemented
            "egt": "gaviota",
            "option": "skipPruneChance -slider 0 0 100"
        }
        python = sys.executable.split("/")[-1]
        python_version = "%s.%s.%s" % sys.version_info[0:3]
        self.print("# %s [%s %s]" %
                   (self.features["myname"], python, python_version))

    def handle_sigterm(self, *args):
        self.__stopSearching()
        sys.exit(0)

    def makeReady(self):
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        signal.signal(signal.SIGTERM, self.handle_sigterm)

    def run(self):
        while True:
            try:
                line = get_input()
            except EOFError:
                line = "quit"
            lines = line.split()

            try:
                if not lines:
                    continue

                log.debug(line, extra={"task": "xboard"})

                # CECP commands
                # See http://home.hccnet.nl/h.g.muller/engine-intf.html

                if lines[0] == "xboard":
                    pass

                elif lines[0] == "protover":
                    stringPairs = ["=".join([k, '"%s"' % v if isinstance(
                        v, str) else str(v)]) for k, v in self.features.items()]
                    self.print("feature %s" % " ".join(stringPairs))
                    self.print("feature done=1")

                elif lines[0] in ("accepted", "rejected"):
                    # We only really care about one case:
                    if tuple(lines) == ("rejected", "debug"):
                        self.debug = False

                elif lines[0] == "new":
                    self.__stopSearching()
                    self.board = LBoard(NORMALCHESS)
                    self.board.applyFen(FEN_START)
                    self.outOfBook = False
                    self.forced = False
                    self.playingAs = BLACK
                    self.clock[:] = self.basetime, self.basetime
                    self.searchtime = 0
                    self.sd = MAXPLY
                    if self.analyzing:
                        self.__analyze()

                elif lines[0] == "variant":
                    if len(lines) > 1:
                        if lines[1] == "fischerandom":
                            self.board.variant = FISCHERRANDOMCHESS
                        elif lines[1] == "crazyhouse":
                            self.board.variant = CRAZYHOUSECHESS
                            self.board.iniHouse()
                        elif lines[1] == "wildcastle":
                            self.board.variant = WILDCASTLESHUFFLECHESS
                        elif lines[1] == "losers":
                            self.board.variant = LOSERSCHESS
                        elif lines[1] == "suicide":
                            self.board.variant = SUICIDECHESS
                        elif lines[1] == "giveaway":
                            self.board.variant = GIVEAWAYCHESS
                        elif lines[1] == "atomic":
                            self.board.variant = ATOMICCHESS
                            self.board.iniAtomic()
                        elif lines[1] == "3check":
                            self.board.variant = THREECHECKCHESS
                        elif lines[1] == "kingofthehill":
                            self.board.variant = KINGOFTHEHILLCHESS
                            self.print("setup (PNBRQKpnbrqk) 8x8+0_fairy %s" %
                                       FEN_START)
                        elif lines[1] == "horde":
                            self.board = LBoard(HORDECHESS)
                            self.board.applyFen(HORDESTART)
                        elif lines[1] == "asean":
                            self.board = LBoard(ASEANCHESS)
                            self.board.applyFen(ASEANSTART)
                        elif lines[1] == "makruk":
                            self.board = LBoard(MAKRUKCHESS)
                            self.board.applyFen(MAKRUKSTART)
                        elif lines[1] == "cambodian":
                            self.board = LBoard(CAMBODIANCHESS)
                            self.board.applyFen(KAMBODIANSTART)
                            self.print(
                                "setup (PN.R.M....SKpn.r.m....sk) 8x8+0_makruk %s"
                                % KAMBODIANSTART)
                            self.print("piece K& KiN")
                            self.print("piece M& FifD")
                        elif lines[1] == "sittuyin":
                            self.board = LBoard(SITTUYINCHESS)
                            self.board.applyFen(SITTUYINSTART)
                            self.print(
                                "setup (PN.R.F....SKpn.r.f....sk) 8x8+6_bughouse %s"
                                % SITTUYINSTART)
                            self.print("piece N& Nj@3")
                            self.print("piece S& FfWj@3")
                            self.print("piece F& Fjb@3")
                            self.print("piece R& R@1")
                            self.print("piece K& Kj@3")
                            self.print("piece P& fmWfcFj@3")

                elif lines[0] == "quit":
                    self.forced = True
                    self.__stopSearching()
                    sys.exit(0)

                elif lines[0] == "random":
                    leval.random = True

                elif lines[0] == "force":
                    if not self.forced and not self.analyzing:
                        self.forced = True
                        self.__stopSearching()

                elif lines[0] == "go":
                    self.playingAs = self.board.color
                    self.forced = False
                    self.__go()

                elif lines[0] == "playother":
                    self.playingAs = 1 - self.board.color
                    self.forced = False
                    # TODO: start pondering, if possible

                elif lines[0] in ("black", "white"):
                    newColor = lines[0] == "black" and BLACK or WHITE
                    self.__stopSearching()
                    self.playingAs = 1 - newColor
                    if self.board.color != newColor:
                        self.board.setColor(newColor)
                        self.board.setEnpassant(None)
                    if self.analyzing:
                        self.__analyze()

                elif lines[0] == "level":
                    self.movestogo = int(lines[1])
                    inc = int(lines[3])
                    minutes = lines[2].split(":")
                    # Per protocol spec, strip off any non-numeric suffixes.
                    for i in range(len(minutes)):
                        minutes[i] = re.match(r'\d*', minutes[i]).group()
                    self.basetime = int(minutes[0]) * 60
                    if len(minutes) > 1 and minutes[1]:
                        self.basetime += int(minutes[1])
                    self.clock[:] = self.basetime, self.basetime
                    self.increment = inc, inc

                elif lines[0] == "st":
                    self.searchtime = float(lines[1])

                elif lines[0] == "sd":
                    self.sd = int(lines[1])

                # Unimplemented: nps

                elif lines[0] == "time":
                    self.clock[self.playingAs] = float(lines[1]) / 100.

                elif lines[0] == "otim":
                    self.clock[1 - self.playingAs] = float(lines[1]) / 100.

                elif lines[0] == "usermove":
                    self.__stopSearching()
                    try:
                        move = parseAny(self.board, lines[1])
                    except ParsingError as err:
                        self.print("Error (unknown command): %s" % lines[1])
                        self.print(self.board.prepr(ascii=ASCII))
                        continue
                    if not validateMove(self.board, move):
                        self.print("Illegal move: %s" % lines[1])
                        self.print(self.board.prepr(ascii=ASCII))
                        continue
                    self.board.applyMove(move)
                    self.playingAs = self.board.color
                    if not self.forced and not self.analyzing:
                        self.__go()
                    if self.analyzing:
                        self.__analyze()

                elif lines[0] == "?":
                    if not self.forced and not self.analyzing:
                        self.__stopSearching()

                elif lines[0] == "ping":
                    self.print("pong %s" % lines[1])

                elif lines[0] == "draw":
                    if self.__willingToDraw():
                        self.print("offer draw")

                elif lines[0] == "result":
                    # We don't really care what the result is at the moment.
                    pass

                elif lines[0] == "setboard":
                    self.__stopSearching()
                    try:
                        self.board = LBoard(self.board.variant)
                        fen = " ".join(lines[1:])
                        self.board.applyFen(fen.replace("[", "/").replace("]",
                                                                          ""))
                    except SyntaxError as err:
                        self.print("tellusererror Illegal position: %s" %
                                   str(err))

                # "edit" is unimplemented. See docs. Exiting edit mode returns to analyze mode.

                elif lines[0] == "hint":
                    pass  # TODO: Respond "Hint: MOVE" if we have an expected reply

                elif lines[0] == "bk":
                    entries = getOpenings(self.board)
                    if entries:
                        totalWeight = sum(entry[1] for entry in entries)
                        for entry in entries:
                            self.print("\t%s\t%02.2f%%" %
                                       (toSAN(self.board, entry[0]), entry[1] *
                                        100.0 / totalWeight))

                elif lines[0] == "undo":
                    self.__stopSearching()
                    self.board.popMove()
                    if self.analyzing:
                        self.__analyze()

                elif lines[0] == "remove":
                    self.__stopSearching()
                    self.board.popMove()
                    self.board.popMove()
                    if self.analyzing:
                        self.__analyze()

                elif lines[0] in ("hard", "easy"):
                    self.ponder = (lines[0] == "hard")

                elif lines[0] in ("post", "nopost"):
                    self.post = (lines[0] == "post")

                elif lines[0] == "analyze":
                    self.analyzing = True
                    self.__analyze()

                elif lines[0] in ("name", "rating", "ics", "computer"):
                    pass  # We don't care.

                # Unimplemented: pause, resume

                elif lines[0] == "memory":
                    # FIXME: this is supposed to control the *total* memory use.
                    if lsearch.searching:
                        self.print("Error (already searching):", line)
                    else:
                        limit = int(lines[1])
                        if limit < 1:
                            self.print("Error (limit too low):", line)
                        else:
                            pass
                            # TODO implement
                            # lsearch.setHashSize(limit)

                elif lines[0] == "cores":
                    pass  # We aren't SMP-capable.

                elif lines[0] == "egtpath":
                    if len(lines) >= 3 and lines[1] == "gaviota":
                        conf.set("egtb_path", conf.get("egtb_path", lines[2]))
                        from pychess.Utils.lutils.lsearch import enableEGTB
                        enableEGTB()

                elif lines[0] == "option" and len(lines) > 1:
                    name, eq, value = lines[1].partition("=")
                    if value:
                        value = int(
                            value
                        )  # CECP spec says option values are *always* numeric
                    if name == "skipPruneChance":
                        if 0 <= value <= 100:
                            self.skipPruneChance = value / 100.0
                        else:
                            self.print(
                                "Error (argument must be an integer 0..100): %s"
                                % line)

                # CECP analyze mode commands
                # See http://www.gnu.org/software/xboard/engine-intf.html#11

                elif lines[0] == "exit":
                    if self.analyzing:
                        self.__stopSearching()
                        self.analyzing = False

                # Periodic updates (".") are not implemented.

                # Custom commands

                elif lines[0] == "moves":
                    self.print(self.board.prepr(ascii=ASCII))
                    self.print([toSAN(self.board, move)
                                for move in genAllMoves(self.board)])

                elif lines[0] == "captures":
                    self.print(self.board.prepr(ascii=ASCII))
                    self.print([toSAN(self.board, move)
                                for move in genCaptures(self.board)])

                elif lines[0] == "evasions":
                    self.print(self.board.prepr(ascii=ASCII))
                    self.print([toSAN(self.board, move)
                                for move in genCheckEvasions(self.board)])

                elif lines[0] == "benchmark":
                    if len(lines) > 1:
                        benchmark(int(lines[1]))
                    else:
                        benchmark()

                elif lines[0] == "profile":
                    if len(lines) > 1:
                        import cProfile
                        cProfile.runctx("benchmark()", locals(), globals(),
                                        lines[1])
                    else:
                        self.print("Usage: profile outputfilename")

                elif lines[0] == "perft":
                    root = "0" if len(lines) < 3 else lines[2]
                    depth = "1" if len(lines) == 1 else lines[1]
                    if root.isdigit() and depth.isdigit():
                        perft(self.board, int(depth), int(root))
                    else:
                        self.print("Error (arguments must be integer")

                elif lines[0] == "stop_unittest":
                    break

                elif len(lines) == 1:
                    # A GUI without usermove support might try to send a move.
                    try:
                        move = parseAny(self.board, line)
                    except ParsingError:
                        self.print("Error (unknown command): %s" % line)
                        continue
                    if not validateMove(self.board, move):
                        self.print("Illegal move: %s" % lines[0])
                        self.print(self.board.prepr(ascii=ASCII))
                        continue
                    self.__stopSearching()
                    self.board.applyMove(move)
                    self.playingAs = self.board.color
                    if not self.forced and not self.analyzing:
                        self.__go()
                    if self.analyzing:
                        self.__analyze()

                else:
                    self.print("Error (unknown command): %s" % line)
            except IndexError:
                self.print("Error (missing argument): %s" % line)

    def __stopSearching(self):
        lsearch.searching = False
        if self.thread:
            self.thread.join()

    def __go(self):
        def ondone(result):
            if not self.forced:
                self.board.applyMove(parseSAN(self.board, result))
                self.print("move %s" % result)
            # TODO: start pondering, if enabled

        self.thread = Thread(target=PyChess._PyChess__go,
                             name=fident(PyChess._PyChess__go),
                             args=(self, ondone))
        self.thread.daemon = True
        self.thread.start()

    def __analyze(self):
        self.thread = Thread(target=PyChess._PyChess__analyze,
                             name=fident(PyChess._PyChess__analyze),
                             args=(self, ))
        self.thread.daemon = True
        self.thread.start()

    def __willingToDraw(self):
        return self.scr <= 0  # FIXME: this misbehaves in all but the simplest use cases
Beispiel #50
0
class PyChessFICS(PyChess):
    def __init__ (self, password, from_address, to_address):
        PyChess.__init__(self)
        
        self.ports = (23, 5000)
        if not password:
            self.username = "******"
        else: self.username = "******"
        self.owner = "Lobais"
        self.password = password
        self.from_address = "The PyChess Bot <%s>" % from_address
        self.to_address = "Thomas Dybdahl Ahle <%s>" % to_address
        
        # Possible start times
        self.minutes = (1,2,3,4,5,6,7,8,9,10)
        self.gains = (0,5,10,15,20)
        # Possible colors. None == random
        self.colors = (WHITE, BLACK, None) 
        # The amount of random challenges, that PyChess sends with each seek
        self.challenges = 10
        enableEGTB()
        
        self.sudos = set()
        self.ownerOnline = False
        self.waitingForPassword = None
        self.log = []
        self.acceptedTimesettings = []
        
        self.worker = None
        
        repeat_sleep(self.sendChallenges, 60*1)
    
    def __triangular(self, low, high, mode):
        """Triangular distribution.
        Continuous distribution bounded by given lower and upper limits,
        and having a given mode value in-between.
        http://en.wikipedia.org/wiki/Triangular_distribution
        """
        u = random.random()
        c = (mode - low) / (high - low)
        if u > c:
            u = 1 - u
            c = 1 - c
            low, high = high, low
        tri = low + (high - low) * (u * c) ** 0.5
        if tri < mode:
            return int(tri)
        elif tri > mode:
            return int(math.ceil(tri))
        return int(round(tri))
    
    def sendChallenges(self):
        if self.connection.bm.isPlaying():
            return True
        
        statsbased = ((0.39197722779282, 3, 0),
                      (0.59341408108783, 5, 0),
                      (0.77320877377846, 1, 0),
                      (0.8246379941394, 10, 0),
                      (0.87388717406441, 2, 12),
                      (0.91443760169489, 15, 0),
                      (0.9286423058163, 4, 0),
                      (0.93891977227793, 2, 0),
                      (0.94674539138335, 20, 0),
                      (0.95321476842423, 2, 2),
                      (0.9594588808257, 5, 2),
                      (0.96564528079889, 3, 2),
                      (0.97173859621034, 7, 0),
                      (0.97774906636184, 3, 1),
                      (0.98357243654425, 5, 12),
                      (0.98881309737017, 5, 5),
                      (0.99319644938247, 6, 0),
                      (0.99675879556023, 3, 12),
                      (1, 5, 3))
        
        #n = random.random()
        #for culminativeChance, minute, gain in statsbased:
        #    if n < culminativeChance:
        #        break
        
        culminativeChance, minute, gain = random.choice(statsbased)
        
        #type = random.choice((TYPE_LIGHTNING, TYPE_BLITZ, TYPE_STANDARD))
        #if type == TYPE_LIGHTNING:
        #    minute = self.__triangular(0,2+1,1)
        #    mingain = not minute and 1 or 0
        #    maxgain = int((3-minute)*3/2)
        #    gain = random.randint(mingain, maxgain)
        #elif type == TYPE_BLITZ:
        #    minute = self.__triangular(0,14+1,5)
        #    mingain = max(int((3-minute)*3/2+1), 0)
        #    maxgain = int((15-minute)*3/2)
        #    gain = random.randint(mingain, maxgain)
        #elif type == TYPE_STANDARD:
        #    minute = self.__triangular(0,20+1,12)
        #    mingain = max(int((15-minute)*3/2+1), 0)
        #    maxgain = int((20-minute)*3/2)
        #    gain = self.__triangular(mingain, maxgain, mingain)
        
        #color = random.choice(self.colors)
        self.extendlog(["Seeking %d %d" % (minute, gain)])
        self.connection.glm.seek(minute, gain, True)
        opps = random.sample(self.connection.players.get_online_playernames(),
                             self.challenges)
        self.extendlog("Challenging %s" % op for op in opps)
        for player in opps:
            self.connection.om.challenge(player, minute, gain, True)
        
        return True
    
    def makeReady(self):
        signal.signal(signal.SIGINT, Gtk.main_quit)
        
        PyChess.makeReady(self)
        
        self.connection = FICSMainConnection("freechess.org", self.ports,
                                             self.username, self.password)
        self.connection.connect("connectingMsg", self.__showConnectLog)
        self.connection._connect()
        
        self.connection.glm.connect("addPlayer", self.__onAddPlayer)
        self.connection.glm.connect("removePlayer", self.__onRemovePlayer)
        self.connection.cm.connect("privateMessage", self.__onTell)
        self.connection.alm.connect("logOut", self.__onLogOut)
        self.connection.bm.connect("playGameCreated", self.__onGameCreated)
        self.connection.bm.connect("curGameEnded", self.__onGameEnded)
        self.connection.bm.connect("boardUpdate", self.__onBoardUpdate)
        self.connection.om.connect("onChallengeAdd", self.__onChallengeAdd)
        self.connection.om.connect("onOfferAdd", self.__onOfferAdd)
        self.connection.adm.connect("onAdjournmentsList", self.__onAdjournmentsList)
        self.connection.em.connect("onAmbiguousMove", self.__onAmbiguousMove)
        self.connection.em.connect("onIllegalMove", self.__onAmbiguousMove)
        
        self.connection.adm.queryAdjournments()
        self.connection.lvm.setVariable("autoflag", 1)
        
        self.connection.fm.setFingerNote(1,
            "PyChess is the chess engine bundled with the PyChess %s " % pychess.VERSION +
            "chess client. This instance is owned by %s, but acts " % self.owner +
            "quite autonomously.")
        
        self.connection.fm.setFingerNote(2,
            "PyChess is 100% Python code and is released under the terms of " +
            "the GPL. The evalution function is largely equal to the one of" +
            "GnuChess, but it plays quite differently.")
        
        self.connection.fm.setFingerNote(3,
            "PyChess runs on an elderly AMD Sempron(tm) Processor 3200+, 512 " +
            "MB DDR2 Ram, but is built to take use of 64bit calculating when " +
            "accessible, through the gpm library.")
        
        self.connection.fm.setFingerNote(4,
            "PyChess uses a small 500 KB openingbook based solely on Kasparov " +
            "games. The engine doesn't have much endgame knowledge, but might " +
            "in some cases access an online endgamedatabase.")
        
        self.connection.fm.setFingerNote(5,
            "PyChess will allow any pause/resume and adjourn wishes, but will " +
            "deny takebacks. Draw, abort and switch offers are accepted, " +
            "if they are found to be an advance. Flag is auto called, but " +
            "PyChess never resigns. We don't want you to forget your basic " +
            "mating skills.")
    
    def main(self):
        self.connection.run()
        self.extendlog([str(self.acceptedTimesettings)])
        self.phoneHome("Session ended\n"+"\n".join(self.log))
        print("Session ended")
    
    def run(self):
        t = Thread(target=self.main, name=fident(self.main))
        t.daemon = True
        t.start()
        Gdk.threads_init()
        Gtk.main()
    
    #===========================================================================
    # General
    #===========================================================================
    
    def __showConnectLog (self, connection, message):
        print(message)
    
    def __onLogOut (self, autoLogoutManager):
        self.connection.close()
        #sys.exit()
    
    def __onAddPlayer (self, gameListManager, player):
        if player["name"] in self.sudos:
            self.sudos.remove(player["name"])
        if player["name"] == self.owner:
            self.connection.cm.tellPlayer(self.owner, "Greetings")
            self.ownerOnline = True
    
    def __onRemovePlayer (self, gameListManager, playername):
        if playername == self.owner:
            self.ownerOnline = False
    
    def __onAdjournmentsList (self, adjournManager, adjournments):
        for adjournment in adjournments:
            if adjournment["online"]:
                adjournManager.challenge(adjournment["opponent"])
    
    def __usage (self):
        return "|| PyChess bot help file || " +\
               "# help 'Displays this help file' " +\
               "# sudo <password> <command> 'Lets PyChess execute the given command' "+\
               "# sendlog 'Makes PyChess send you its current log'"
    
    def __onTell (self, chatManager, name, title, isadmin, text):
        
        if self.waitingForPassword:
            if text.strip() == self.password or (not self.password and text == "none"):
                self.sudos.add(name)
                self.tellHome("%s gained sudo access" % name)
                self.connection.client.run_command(self.waitingForPassword)
            else:
                chatManager.tellPlayer(name, "Wrong password")
                self.tellHome("%s failed sudo access" % name)
            self.waitingForPassword = None
            return
        
        args = text.split()
        
        #if args == ["help"]:
        #    chatManager.tellPlayer(name, self.__usage())
        
        if args[0] == "sudo":
            command = " ".join(args[1:])
            if name in self.sudos or name == self.owner:
                # Notice: This can be used to make nasty loops
                print(command, file=self.connection.client)
            else:
                print(repr(name), self.sudos)
                chatManager.tellPlayer(name, "Please send me the password")
                self.waitingForPassword = command
        
        elif args == ["sendlog"]:
            if self.log:
                # TODO: Consider email
                chatManager.tellPlayer(name, "\\n".join(self.log))
            else:
                chatManager.tellPlayer(name, "The log is currently empty")
        
        else:
            if self.ownerOnline:
                self.tellHome("%s told me '%s'" % (name, text))
            else:
                def onlineanswer (message):
                    data = urlopen("http://www.pandorabots.com/pandora/talk?botid=8d034368fe360895",
                                   urlencode({"message":message, "botcust2":"x"}).encode("utf-8")).read().decode('utf-8')
                    ss = "<b>DMPGirl:</b>"
                    es = "<br>"
                    answer = data[data.find(ss)+len(ss) : data.find(es,data.find(ss))]
                    chatManager.tellPlayer(name, answer)
                t = Thread(target=onlineanswer,
                           name=fident(onlineanswer),
                           args=(text,))
                t.daemon = True
                t.start()
            #chatManager.tellPlayer(name, "Sorry, your request was nonsense.\n"+\
            #                           "Please read my help file for more info")
    
    #===========================================================================
    # Challenges and other offers
    #===========================================================================
    
    def __onChallengeAdd (self, offerManager, index, match):
        #match = {"tp": type, "w": fname, "rt": rating, "color": color,
        #         "r": rated, "t": mins, "i": incr}
        offerManager.acceptIndex(index)
    
    def __onOfferAdd (self, offerManager, offer):
        if offer.type in (PAUSE_OFFER, RESUME_OFFER, ADJOURN_OFFER):
            offerManager.accept(offer)
        elif offer.type in (TAKEBACK_OFFER,):
            offerManager.decline(offer)
        elif offer.type in (DRAW_OFFER, ABORT_OFFER, SWITCH_OFFER):
            if self.__willingToDraw():
                offerManager.accept(offer)
            else: offerManager.decline(offer)
    
    #===========================================================================
    # Playing
    #===========================================================================
    
    def __onGameCreated (self, boardManager, ficsgame):
        
        base = int(ficsgame.minutes)*60
        inc = int(ficsgame.inc)
        self.clock[:] = base, base
        self.increment[:] = inc, inc
        self.gameno = ficsgame.gameno
        self.lastPly = -1
        
        self.acceptedTimesettings.append((base, inc))
        
        self.tellHome("Starting a game (%s, %s) gameno: %s" %
                (ficsgame.wplayer.name, ficsgame.bplayer.name, ficsgame.gameno))
        
        if ficsgame.bplayer.name.lower() == self.connection.getUsername().lower():
            self.playingAs = BLACK
        else:
            self.playingAs = WHITE
        
        self.board = LBoard(NORMALCHESS)
        # Now we wait until we recieve the board.
    
    def __go (self):
        if self.worker:
            self.worker.cancel()
        self.worker = GtkWorker(lambda worker: PyChess._PyChess__go(self, worker))
        self.worker.connect("published", lambda w, msg: self.extendlog(msg))
        self.worker.connect("done", self.__onMoveCalculated)
        self.worker.execute()

    def __willingToDraw (self):
        return self.scr <= 0 # FIXME: this misbehaves in all but the simplest use cases
    
    def __onGameEnded (self, boardManager, ficsgame):
        self.tellHome(reprResult_long[ficsgame.result] + " " + reprReason_long[ficsgame.reason])
        lsearch.searching = False
        if self.worker:
            self.worker.cancel()
            self.worker = None
    
    def __onMoveCalculated (self, worker, sanmove):
        if worker.isCancelled() or not sanmove:
            return
        self.board.applyMove(parseSAN(self.board,sanmove))
        self.connection.bm.sendMove(sanmove)
        self.extendlog(["Move sent %s" % sanmove])
    
    def __onBoardUpdate (self, boardManager, gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms):
        self.extendlog(["","I got move %d %s for gameno %s" % (ply, lastmove, gameno)])
        
        if self.gameno != gameno:
            return
        
        self.board.applyFen(fen)
        
        self.clock[:] = wms/1000., bms/1000.
        
        if curcol == self.playingAs:
            self.__go()
    
    def __onAmbiguousMove (self, errorManager, move):
        # This is really a fix for fics, but sometimes it is necessary
        if determineAlgebraicNotation(move) == SAN:
            self.board.popMove()
            move_ = parseSAN(self.board, move)
            lanmove = toLAN(self.board, move_)
            self.board.applyMove(move_)
            self.connection.bm.sendMove(lanmove)
        else:
            self.connection.cm.tellOpponent(
                    "I'm sorry, I wanted to move %s, but FICS called " % move +
                    "it 'Ambigious'. I can't find another way to express it, " +
                    "so you can win")
            self.connection.bm.resign()
    
    #===========================================================================
    # Utils
    #===========================================================================
    
    def extendlog(self, messages):
        [log.info(m+"\n") for m in messages]
        self.log.extend(messages)
        del self.log[:-10]
    
    def tellHome(self, message):
        print(message)
        if self.ownerOnline:
            self.connection.cm.tellPlayer(self.owner, message)
    
    def phoneHome(self, message):
        
        SENDMAIL = '/usr/sbin/sendmail'
        SUBJECT = "Besked fra botten"
        
        p = subprocess.Popen([SENDMAIL, '-f',
                              email.Utils.parseaddr(self.from_address)[1],
                              email.Utils.parseaddr(self.to_address)[1]],
                              stdin=subprocess.PIPE)
        
        print("MIME-Version: 1.0", file=p.stdin)
        print("Content-Type: text/plain; charset=UTF-8", file=p.stdin)
        print("Content-Disposition: inline", file=p.stdin)
        print("From: %s" % self.from_address, file=p.stdin)
        print("To: %s" % self.to_address, file=p.stdin)
        print("Subject: %s" % SUBJECT, file=p.stdin)
        print(file=p.stdin)
        print(message, file=p.stdin)
        print("Cheers", file=p.stdin)
        
        p.stdin.close()
        p.wait()
Beispiel #51
0
    def do_import(self, filename):
        print(filename)
        # collect new names not in they dict yet
        self.collection_data = []
        self.event_data = []
        self.site_data = []
        self.player_data = []
        self.annotator_data = []
        
        # collect new games and commit them in big chunks for speed
        self.game_data = []

        if filename.lower().endswith(".zip") and zipfile.is_zipfile(filename):
            zf = zipfile.ZipFile(filename, "r")
            files = [f for f in zf.namelist() if f.lower().endswith(".pgn")]
        else:
            zf = None
            files = [filename]
        
        for pgnfile in files:
            if zf is None:
                cf = pgn_load(open(pgnfile, "rU"))
            else:
                cf = pgn_load(zf.open(pgnfile, "rU"))
             
            # use transaction to avoid autocommit slowness
            trans = self.conn.begin()
            try:
                for i, game in enumerate(cf.games):
                    #print i+1#, cf.get_player_names(i)
                    movelist = array("H")
                    comments = []
                    cf.error = None

                    fenstr = cf._getTag(i, "FEN")
                    variant = cf.get_variant(i)

                    # Fixes for some non statndard Chess960 .pgn
                    if variant==0 and (fenstr is not None) and "Chess960" in cf._getTag(i,"Event"):
                        cf.tagcache[i]["Variant"] = "Fischerandom"
                        variant = 1
                        parts = fenstr.split()
                        parts[0] = parts[0].replace(".", "/").replace("0", "")
                        if len(parts) == 1:
                            parts.append("w")
                            parts.append("-")
                            parts.append("-")
                        fenstr = " ".join(parts)
                    
                    if variant:
                        board = LBoard(FISCHERRANDOMCHESS)
                    else:
                        board = LBoard()

                    if fenstr:
                        try:
                            board.applyFen(fenstr)
                        except SyntaxError as e:
                            print(_("The game #%s can't be loaded, because of an error parsing FEN") % (i+1), e.args[0])
                            continue
                    else:
                        board = LBoard_FEN_START.clone()

                    boards = [board]
                    movetext = cf.get_movetext(i)
                    boards = cf.parse_string(movetext, boards[0], -1)

                    if cf.error is not None:
                        print("ERROR in game #%s" % (i+1), cf.error.args[0])
                        continue

                    walk(boards[0], movelist, comments)
                    
                    if not movelist:
                        if (not comments) and (cf._getTag(i, 'White') is None) and (cf._getTag(i, 'Black') is None):
                            print("empty game")
                            continue
                    
                    event_id = self.get_id(cf._getTag(i, 'Event'), event, EVENT)

                    site_id = self.get_id(cf._getTag(i, 'Site'), site, SITE)

                    game_date = cf._getTag(i, 'Date')
                    if game_date and not '?' in game_date:
                        ymd = game_date.split('.')
                        if len(ymd) == 3:
                            game_year, game_month, game_day = map(int, ymd)
                        else:
                            game_year, game_month, game_day = int(game_date[:4]), None, None
                    elif game_date and not '?' in game_date[:4]:
                        game_year, game_month, game_day = int(game_date[:4]), None, None
                    else:
                        game_year, game_month, game_day = None, None, None

                    game_round = cf._getTag(i, 'Round')

                    white, black = cf.get_player_names(i)
                    white_id = self.get_id(white, player, PLAYER)
                    black_id = self.get_id(black, player, PLAYER)

                    result = cf.get_result(i)
     
                    white_elo = cf._getTag(i, 'WhiteElo')
                    white_elo = int(white_elo) if white_elo and white_elo.isdigit() else None
                    
                    black_elo = cf._getTag(i, 'BlackElo')
                    black_elo = int(black_elo) if black_elo and black_elo.isdigit() else None
     
                    ply_count = cf._getTag(i, "PlyCount")
     
                    event_date = cf._getTag(i, 'EventDate')
     
                    eco = cf._getTag(i, "ECO")
                    eco = eco[:3] if eco else None

                    fen = cf._getTag(i, "FEN")
     
                    variant = cf.get_variant(i)
                    
                    board = cf._getTag(i, "Board")
                    
                    annotator = cf._getTag(i, "Annotator")
                    annotator_id = self.get_id(annotator, annotator, ANNOTATOR)

                    collection_id = self.get_id(unicode(pgnfile), collection, COLLECTION)

                    self.game_data.append({
                        'event_id': event_id,
                        'site_id': site_id,
                        'date_year': game_year,
                        'date_month': game_month,
                        'date_day': game_day,
                        'round': game_round,
                        'white_id': white_id,
                        'black_id': black_id,
                        'result': result,
                        'white_elo': white_elo,
                        'black_elo': black_elo,
                        'ply_count': ply_count,
                        'eco': eco,
                        'fen': fen,
                        'variant': variant,
                        'board': board,
                        'annotator_id': annotator_id,
                        'collection_id': collection_id,
                        'movelist': movelist.tostring(),
                        'comments': unicode("|".join(comments)),
                        })

                    if len(self.game_data) >= CHUNK:
                        if self.collection_data:
                            self.conn.execute(self.ins_collection, self.collection_data)
                            self.collection_data = []

                        if self.event_data:
                            self.conn.execute(self.ins_event, self.event_data)
                            self.event_data = []

                        if self.site_data:
                            self.conn.execute(self.ins_site, self.site_data)
                            self.site_data = []

                        if self.player_data:
                            self.conn.execute(self.ins_player, self.player_data)
                            self.player_data = []

                        if self.annotator_data:
                            self.conn.execute(self.ins_annotator, self.annotator_data)
                            self.annotator_data = []

                        self.conn.execute(self.ins_game, self.game_data)
                        self.game_data = []
                        print(pgnfile, i+1)
                    
                if self.collection_data:
                    self.conn.execute(self.ins_collection, self.collection_data)
                    self.collection_data = []

                if self.event_data:
                    self.conn.execute(self.ins_event, self.event_data)
                    self.event_data = []

                if self.site_data:
                    self.conn.execute(self.ins_site, self.site_data)
                    self.site_data = []

                if self.player_data:
                    self.conn.execute(self.ins_player, self.player_data)
                    self.player_data = []

                if self.annotator_data:
                    self.conn.execute(self.ins_annotator, self.annotator_data)
                    self.annotator_data = []

                if self.game_data:
                    self.conn.execute(self.ins_game, self.game_data)
                    self.game_data = []

                print(pgnfile, i+1)
                trans.commit()

            except ProgrammingError as e:
                trans.rollback()
                print("Importing %s failed! %s" % (file, e))
Beispiel #52
0
    def loadToModel(self, rec, position=-1, model=None):
        """ Parse game text and load game record header tags to a GameModel object """

        if not model:
            model = GameModel()

        if self.pgn_is_string:
            rec = self.games[0]
            game_date = rec["Date"]
            result = rec["Result"]
            variant = rec["Variant"]
        else:
            game_date = self.get_date(rec)
            result = reprResult[rec["Result"]]
            variant = self.get_variant(rec)

        # the seven mandatory PGN headers
        model.tags['Event'] = rec["Event"]
        model.tags['Site'] = rec["Site"]
        model.tags['Date'] = game_date
        model.tags['Round'] = rec["Round"]
        model.tags['White'] = rec["White"]
        model.tags['Black'] = rec["Black"]
        model.tags['Result'] = result

        if model.tags['Date']:
            date_match = re.match(".*(\d{4}).(\d{2}).(\d{2}).*",
                                  model.tags['Date'])
            if date_match:
                year, month, day = date_match.groups()
                model.tags['Year'] = year
                model.tags['Month'] = month
                model.tags['Day'] = day

        # non-mandatory tags
        for tag in ('Annotator', 'ECO', 'WhiteElo', 'BlackElo', 'TimeControl'):
            value = rec[tag]
            if value:
                model.tags[tag] = value
            else:
                model.tags[tag] = ""

        if not self.pgn_is_string:
            model.info = self.tag_database.get_info(rec)

        if model.tags['TimeControl']:
            secs, gain = parseTimeControlTag(model.tags['TimeControl'])
            model.timed = True
            model.timemodel.secs = secs
            model.timemodel.gain = gain
            model.timemodel.minutes = secs / 60
            for tag, color in (('WhiteClock', WHITE), ('BlackClock', BLACK)):
                if hasattr(rec, tag):
                    try:
                        millisec = parseClockTimeTag(rec[tag])
                        # We need to fix when FICS reports negative clock time like this
                        # [TimeControl "180+0"]
                        # [WhiteClock "0:00:15.867"]
                        # [BlackClock "23:59:58.820"]
                        start_sec = (
                            millisec - 24 * 60 * 60 * 1000
                        ) / 1000. if millisec > 23 * 60 * 60 * 1000 else millisec / 1000.
                        model.timemodel.intervals[color][0] = start_sec
                    except ValueError:
                        raise LoadingError(
                            "Error parsing '%s'" % tag)

        fenstr = rec["FEN"]

        if variant:
            if variant not in name2variant:
                raise LoadingError("Unknown variant %s" % variant)

            model.tags["Variant"] = variant
            # Fixes for some non statndard Chess960 .pgn
            if (fenstr is not None) and variant == "Fischerandom":
                parts = fenstr.split()
                parts[0] = parts[0].replace(".", "/").replace("0", "")
                if len(parts) == 1:
                    parts.append("w")
                    parts.append("-")
                    parts.append("-")
                fenstr = " ".join(parts)

            model.variant = name2variant[variant]
            board = LBoard(model.variant.variant)
        else:
            model.variant = NormalBoard
            board = LBoard()

        if fenstr:
            try:
                board.applyFen(fenstr)
            except SyntaxError as err:
                board.applyFen(FEN_EMPTY)
                raise LoadingError(
                    _("The game can't be loaded, because of an error parsing FEN"),
                    err.args[0])
        else:
            board.applyFen(FEN_START)

        boards = [board]

        del model.moves[:]
        del model.variations[:]

        self.error = None
        movetext = self.get_movetext(rec)

        boards = self.parse_movetext(movetext, boards[0], position)

        # The parser built a tree of lboard objects, now we have to
        # create the high level Board and Move lists...

        for board in boards:
            if board.lastMove is not None:
                model.moves.append(Move(board.lastMove))

        self.has_emt = False
        self.has_eval = False

        def walk(model, node, path):
            if node.prev is None:
                # initial game board
                board = model.variant(setup=node.asFen(), lboard=node)
            else:
                move = Move(node.lastMove)
                try:
                    board = node.prev.pieceBoard.move(move, lboard=node)
                except:
                    raise LoadingError(
                        _("Invalid move."),
                        "%s%s" % (move_count(node, black_periods=True), move))

            if node.next is None:
                model.variations.append(path + [board])
            else:
                walk(model, node.next, path + [board])

            for child in node.children:
                if isinstance(child, list):
                    if len(child) > 1:
                        # non empty variation, go walk
                        walk(model, child[1], list(path))
                else:
                    if not self.has_emt:
                        self.has_emt = child.find("%emt") >= 0
                    if not self.has_eval:
                        self.has_eval = child.find("%eval") >= 0

        # Collect all variation paths into a list of board lists
        # where the first one will be the boards of mainline game.
        # model.boards will allways point to the current shown variation
        # which will be model.variations[0] when we are in the mainline.
        walk(model, boards[0], [])
        model.boards = model.variations[0]
        self.has_emt = self.has_emt and "TimeControl" in model.tags
        if self.has_emt or self.has_eval:
            if self.has_emt:
                blacks = len(model.moves) // 2
                whites = len(model.moves) - blacks

                model.timemodel.intervals = [
                    [model.timemodel.intervals[0][0]] * (whites + 1),
                    [model.timemodel.intervals[1][0]] * (blacks + 1),
                ]
                secs, gain = parseTimeControlTag(model.tags['TimeControl'])
                model.timemodel.intervals[0][0] = secs
                model.timemodel.intervals[1][0] = secs
            for ply, board in enumerate(boards):
                for child in board.children:
                    if isinstance(child, str):
                        if self.has_emt:
                            match = movetime.search(child)
                            if match:
                                movecount, color = divmod(ply + 1, 2)
                                hour, minute, sec, msec = match.groups()
                                prev = model.timemodel.intervals[color][
                                    movecount - 1]
                                hour = 0 if hour is None else int(hour[:-1])
                                minute = 0 if minute is None else int(minute[:-1])
                                msec = 0 if msec is None else int(msec)
                                msec += int(sec) * 1000 + int(
                                    minute) * 60 * 1000 + int(
                                        hour) * 60 * 60 * 1000
                                model.timemodel.intervals[color][
                                    movecount] = prev - msec / 1000. + gain

                        if self.has_eval:
                            match = moveeval.search(child)
                            if match:
                                sign, num, fraction, depth = match.groups()
                                sign = 1 if sign is None or sign == "+" else -1
                                num = int(num) if int(
                                    num) == MATE_VALUE else int(num)
                                fraction = 0 if fraction is None else int(
                                    fraction)
                                value = sign * (num * 100 + fraction)
                                depth = "" if depth is None else depth
                                if board.color == BLACK:
                                    value = -value
                                model.scores[ply] = ("", value, depth)
            log.debug("pgn.loadToModel: intervals %s" %
                      model.timemodel.intervals)

        # Find the physical status of the game
        model.status, model.reason = getStatus(model.boards[-1])

        # Apply result from .pgn if the last position was loaded
        if position == -1 or len(model.moves) == position - model.lowply:
            status = rec["Result"]
            if status in (WHITEWON, BLACKWON) and status != model.status:
                model.status = status
                model.reason = WON_RESIGN
            elif status == DRAW and status != model.status:
                model.status = DRAW
                model.reason = DRAW_AGREE

        # If parsing gave an error we throw it now, to enlarge our possibility
        # of being able to continue the game from where it failed.
        if self.error:
            raise self.error

        return model
Beispiel #53
0
class ZobristTestCase(unittest.TestCase):
    def make_move(self, an_move):
        self.board.applyMove(parseAN(self.board, an_move))

    def setUp(self):
        self.board = LBoard(Board)
        self.board.applyFen(FEN)

    def testZobrist_1(self):
        """Testing zobrist hashing with simple move and take back"""

        hash = self.board.hash
        self.make_move("c3b5")
        self.board.color = 1 - self.board.color
        self.make_move("b5c3")

        self.assertEqual(hash, self.board.hash)

    def testZobrist_2(self):
        """Testing zobrist hashing with W00,B00,a1b1 vs. a1b1,B00,W00"""

        self.make_move("e1g1")
        self.make_move("e8g8")
        self.make_move("a1b1")
        hash1 = self.board.hash

        self.board.popMove()
        self.board.popMove()
        self.board.popMove()

        self.make_move("a1b1")
        self.make_move("e8g8")
        self.make_move("e1g1")
        hash2 = self.board.hash

        self.assertEqual(hash1, hash2)

    def testZobrist_3(self):
        """Testing zobrist hashing with W000,B000,h1g1 vs. h1g1,B000,W000"""

        self.make_move("e1c1")
        self.make_move("e8c8")
        self.make_move("h1g1")
        hash1 = self.board.hash

        self.board.popMove()
        self.board.popMove()
        self.board.popMove()

        self.make_move("h1g1")
        self.make_move("e8c8")
        self.make_move("e1c1")
        hash2 = self.board.hash

        self.assertEqual(hash1, hash2)

    def testZobrist_4(self):
        """Testing zobrist hashing with en-passant"""

        self.make_move("a2a4")
        self.make_move("b4a3")
        self.make_move("e1c1")
        self.make_move("c7c5")
        self.make_move("d5c6")
        self.make_move("e8c8")
        hash1 = self.board.hash

        self.board.popMove()
        self.board.popMove()
        self.board.popMove()
        self.board.popMove()
        self.board.popMove()
        self.board.popMove()

        self.make_move("e1c1")
        self.make_move("c7c5")
        self.make_move("d5c6")
        self.make_move("e8c8")
        self.make_move("a2a4")
        self.make_move("b4a3")
        hash2 = self.board.hash

        self.assertEqual(hash1, hash2)
Beispiel #54
0
                            site, player, game, annotator, ini_collection

CHUNK = 1000

EVENT, SITE, PLAYER, ANNOTATOR, COLLECTION = range(5)

removeDic = {
    ord(unicode("'")): None,
    ord(unicode(",")): None,
    ord(unicode(".")): None,
    ord(unicode("-")): None,
    ord(unicode(" ")): None,
}

LBoard_FEN_START = LBoard()
LBoard_FEN_START.applyFen(FEN_START)

class PgnImport():
    def __init__(self):
        self.conn = engine.connect()
        
        self.ins_collection = collection.insert()
        self.ins_event = event.insert()
        self.ins_site = site.insert()
        self.ins_player = player.insert()
        self.ins_annotator = annotator.insert()
        self.ins_game = game.insert()
        
        self.collection_dict = {}
        self.event_dict = {}
        self.site_dict = {}
Beispiel #55
0
class PyChessCECP(PyChess):
    
    def __init__ (self):
        PyChess.__init__(self)
        self.board = LBoard(NORMALCHESS)
        self.board.applyFen(FEN_START)
        
        self.forced = False
        self.analyzing = False
        self.thread = None

        self.basetime = 0
        
        self.features = {
            "ping": 1,
            "setboard": 1,
            "playother": 1,
            "san": 1,
            "usermove": 1,
            "time": 1,
            "draw": 1,
            "sigint": 0,
            "sigterm": 0,
            "reuse": 1,
            "analyze": 1,
            "myname": "PyChess %s" % pychess.VERSION,
            "variants": "normal,wildcastle,nocastle,fischerandom,crazyhouse,losers,suicide,atomic",
            "colors": 0,
            "ics": 0,
            "name": 0,
            "pause": 0, # Unimplemented
            "nps": 0, # Unimplemented
            "debug": 1,
            "memory": 1,
            "smp": 0, # Unimplemented
            # "egt": "gaviota", # TODO: re-enable
            "option": "skipPruneChance -slider 0 0 100"
        }
    
    def handle_sigterm(self, *args):
        self.__stopSearching()
        sys.exit(0)
    
    def makeReady(self):
        PyChess.makeReady(self)
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        signal.signal(signal.SIGTERM, self.handle_sigterm)
    
    def run (self):
        while True:
            try:
                line = raw_input()
            except EOFError:
                line = "quit"
            lines = line.split()
            if 1:
            #try:
                if not lines:
                    continue
     
                ########## CECP commands ##########
                # See http://www.gnu.org/software/xboard/engine-intf.html#8
                
                elif lines[0] == "xboard":
                    pass
     
                elif lines[0] == "protover":
                    stringPairs = ["=".join([k, '"%s"' % v if type(v) is str else str(v)]) for k,v in self.features.iteritems()]
                    print "feature %s" % " ".join(stringPairs)
                    print "feature done=1"
                
                elif lines[0] in ("accepted", "rejected"):
                    # We only really care about one case:
                    if tuple(lines) == ("rejected", "debug"):
                        self.debug = False
     
                elif lines[0] == "new":
                    self.__stopSearching()
                    self.board = LBoard(NORMALCHESS)
                    self.board.applyFen(FEN_START)
                    self.forced = False
                    self.playingAs = BLACK
                    self.clock[:] = self.basetime, self.basetime
                    self.searchtime = 0
                    self.sd = MAXPLY
                    if self.analyzing:
                        self.__analyze()
                
                elif lines[0] == "variant":
                    if len(lines) > 1:
                        if lines[1] == "fischerandom":
                            self.board.variant = FISCHERRANDOMCHESS
                        elif lines[1] == "crazyhouse":
                            self.board.variant = CRAZYHOUSECHESS
                            self.board.iniHouse()
                        elif lines[1] == "wildcastle":
                            self.board.variant = WILDCASTLESHUFFLECHESS
                        elif lines[1] == "losers":
                            self.board.variant = LOSERSCHESS
                        elif lines[1] == "suicide":
                            self.board.variant = SUICIDECHESS
                        elif lines[1] == "atomic":
                            self.board.variant = ATOMICCHESS
                            self.board.iniAtomic()
                
                elif lines[0] == "quit":
                    self.forced = True
                    self.__stopSearching()
                    sys.exit(0)
                    
                elif lines[0] == "random":
                    leval.random = True
     
                elif lines[0] == "force":
                    if not self.forced and not self.analyzing:
                        self.forced = True
                        self.__stopSearching()
                
                elif lines[0] == "go":
                    self.playingAs = self.board.color
                    self.forced = False
                    self.__go()
                
                elif lines[0] == "playother":
                    self.playingAs = 1-self.board.color
                    self.forced = False
                    # TODO: start pondering, if possible
                
                elif lines[0] in ("black", "white"):
                    newColor = lines[0] == "black" and BLACK or WHITE
                    self.__stopSearching()
                    self.playingAs = 1-newColor
                    if self.board.color != newColor:
                        self.board.setColor(newColor)
                        self.board.setEnpassant(None)
                    if self.analyzing:
                        self.__analyze()
                
                elif lines[0] == "level":
                    self.movestogo = int(lines[1])
                    inc = int(lines[3])
                    minutes = lines[2].split(":")
                    # Per protocol spec, strip off any non-numeric suffixes.
                    for i in xrange(len(minutes)):
                        minutes[i] = re.match(r'\d*', minutes[i]).group()
                    self.basetime = int(minutes[0])*60
                    if len(minutes) > 1 and minutes[1]:
                        self.basetime += int(minutes[1])
                    self.clock[:] = self.basetime, self.basetime
                    self.increment = inc, inc
                
                elif lines[0] == "st":
                    self.searchtime = float(lines[1])
     
                elif lines[0] == "sd":
                    self.sd = int(lines[1])
                
                # Unimplemented: nps
                
                elif lines[0] == "time":
                    self.clock[self.playingAs] = float(lines[1])/100.
                
                elif lines[0] == "otim":
                    self.clock[1-self.playingAs] = float(lines[1])/100.
                
                elif lines[0] == "usermove":
                    self.__stopSearching()
                    try:
                        move = parseAny (self.board, lines[1])
                    except ParsingError, e:
                        print "Error (unknown command):", lines[1]
                        print self.board
                        continue
                    if not validateMove(self.board, move):
                        print "Illegal move", lines[1]
                        print self.board
                        continue
                    self.board.applyMove(move)
                    self.playingAs = self.board.color
                    if not self.forced and not self.analyzing:
                        self.__go()
                    if self.analyzing:
                        self.__analyze()
                
                elif lines[0] == "?":
                    if not self.forced and not self.analyzing:
                        self.__stopSearching()
                
                elif lines[0] == "ping":
                    print "pong", lines[1]
                    
                elif lines[0] == "draw":
                    if self.__willingToDraw():
                        print "offer draw"
                
                elif lines[0] == "result":
                    # We don't really care what the result is at the moment.
                    pass
                    
                elif lines[0] == "setboard":
                    self.__stopSearching()
                    try:
                        self.board = LBoard(self.board.variant)
                        fen = " ".join(lines[1:])
                        self.board.applyFen(fen.replace("[", "/").replace("]", ""))
                    except SyntaxError as e:
                        print "tellusererror Illegal position:", str(e)
                    if self.analyzing:
                        self.__analyze()
                
                # "edit" is unimplemented. See docs. Exiting edit mode returns to analyze mode.
     
                elif lines[0] == "hint":
                    pass # TODO: Respond "Hint: MOVE" if we have an expected reply
                
                elif lines[0] == "bk":
                    entries = getOpenings(self.board)
                    if entries:
                        totalWeight = sum(entry[1] for entry in entries)
                        for entry in entries:
                            print "\t%s\t%02.2f%%" % (toSAN(self.board, entry[0]), entry[1] * 100.0 / totalWeight)
                
                elif lines[0] == "undo":
                    self.__stopSearching()
                    self.board.popMove()
                    if self.analyzing:
                        self.__analyze()
     
                elif lines[0] == "remove":
                    self.__stopSearching()
                    self.board.popMove()
                    self.board.popMove()
                    if self.analyzing:
                        self.__analyze()
                
                elif lines[0] in ("hard", "easy"):
                    self.ponder = (lines[0] == "hard")
                
                elif lines[0] in ("post", "nopost"):
                    self.post = (lines[0] == "post")
                
                elif lines[0] == "analyze":
                    self.analyzing = True
                    self.__analyze()
     
                elif lines[0] in ("name", "rating", "ics", "computer"):
                    pass # We don't care.
     
                # Unimplemented: pause, resume
     
                elif lines[0] == "memory":
                    # FIXME: this is supposed to control the *total* memory use.
                    if lsearch.searching:
                        print "Error (already searching):", line
                    else:
                        limit = int(lines[1])
                        if limit < 1:
                            print "Error (limit too low):", line
                        else:
                            pass
                            # TODO implement
                            #lsearch.setHashSize(limit)
     
                elif lines[0] == "cores":
                    pass # We aren't SMP-capable.
     
                elif lines[0] == "egtpath":
                    # TODO: Accept "egtpath TYPE PATH" commands, at least for Gaviota EGTBs
                    pass
     
                elif lines[0] == "option" and len(lines) > 1:
                    name, eq, value = lines[1].partition("=")
                    if value: value = int(value) # CECP spec says option values are *always* numeric
                    if name == "skipPruneChance":
                        if 0 <= value <= 100:
                            self.skipPruneChance = value / 100.0
                        else:
                            print "Error (argument must be an integer 0..100):", line
     
                ########## CECP analyze mode commands ##########
                # See http://www.gnu.org/software/xboard/engine-intf.html#11
     
                elif lines[0] == "exit":
                    if self.analyzing:
                        self.__stopSearching()
                        self.analyzing = False
     
                # Periodic updates (".") are not implemented.
     
                ########## Custom commands ##########
     
                elif lines[0] == "egtb":
                    enableEGTB()
                
                elif lines[0] == "benchmark":
                    benchmark()
                
                elif lines[0] == "profile":
                    if len(lines) > 1:
                        import cProfile
                        cProfile.runctx("benchmark()", locals(), globals(), lines[1])
                    else:
                        print "Usage: profile outputfilename"
                
                elif len(lines) == 1:
                    # A GUI without usermove support might try to send a move.
                    try:
                        move = parseAny (self.board, line)
                    except:
                        print "Error (unknown command):", line
                        continue
                    if not validateMove(self.board, move):
                        print "Illegal move", lines[0]
                        print self.board
                        continue
                    self.__stopSearching()
                    self.board.applyMove(move)
                    self.playingAs = self.board.color
                    if not self.forced and not self.analyzing:
                        self.__go()
                    if self.analyzing:
                        self.__analyze()

                else:
                    print "Error (unknown command):", line
Beispiel #56
0
                log.warning("Couldn't parse %s data for position %s.\nData was: %s" %
                         (reprColor[color], fen, repr(data)))
                self.table[(fen, color)] = [] # Don't try again.
        
        if (fen,board.color) in self.table:
            return self.table[(fen,board.color)]
        return []
    
    def scoreGame(self, board, omitDepth, probeSoft):
        scores = self.scoreAllMoves(board, probeSoft)
        if scores:
            return scores[0][1], scores[0][2]
        return None, None

if __name__ == "__main__":
    from pychess.Utils.lutils.LBoard import LBoard
    from pychess.Utils.lutils.lmove import listToSan
    board = LBoard(NORMALCHESS)
    
    board.applyFen("8/k2P4/8/8/8/8/8/4K2R w - - 0 1")
    moves = probeEndGameTable(board)
    assert len(moves) == 18, listToSan(board, (move[0] for move in moves))
    
    board.applyFen("8/p7/6kp/3K4/6PP/8/8/8 b - - 0 1")
    moves = probeEndGameTable(board)
    assert len(moves) == 7, listToSan(board, (move[0] for move in moves))
    
    board.applyFen("8/p6k/2K5/7R/6PP/8/8/8 b - - 0 66")
    moves = probeEndGameTable(board)
    assert len(moves) == 3, listToSan(board, (move[0] for move in moves))
Beispiel #57
0
from pychess.System.prefix import addDataPrefix
from pychess.Utils.lutils.LBoard import LBoard
from pychess.Utils.lutils.lmove import toSAN, toFAN
from pychess.Savers.pgn import move_count
from pychess.Savers.pgnbase import nag2symbol
from pychess.widgets.Background import set_textview_color
from pychess.widgets.ChessClock import formatTime
from pychess.Utils.TimeModel import TimeModel

__title__ = _("Annotation")
__active__ = True
__icon__ = addDataPrefix("glade/panel_annotation.svg")
__desc__ = _("Annotated game")

EMPTY_BOARD = LBoard()
EMPTY_BOARD.applyFen(FEN_EMPTY)

"""
We are maintaining a list of nodes to help manipulate the textbuffer.
Node can represent a move, comment or variation (start/end) marker.
Nodes are dicts with keys like:
board  = in move node it's the lboard of move
         in comment node it's the lboard where the comment belongs to
         in end variation marker node it's the first lboard of the variation
         in start variation marker is's None
start  = the beginning offest of the node in the textbuffer
end    = the ending offest of the node in the textbuffer
parent = the parent lboard if the node is a move in a variation, otherwise None
vari   = in end variation node it's the start variation marker node
         in start variation node it's None
level  = depth in variation tree (0 for mainline nodes, 1 for first level variation moves, etc.)
Beispiel #58
0
class OLVFile(ChessFile):
    def __init__(self, handle):
        ChessFile.__init__(self, handle)

        self.games = self.read_games(handle)
        self.count = len(self.games)

    def read_games(self, handle):
        """ We don't return games if stipulation is not 'mate in #' """
        games = []
        rec = None
        rec_id = 1
        contains_fairy_pieces = False

        # authors is a more line list (each line starts with "-")
        in_authors = False

        # piece list are usually in one line list inside []
        # but sometimes given in more line lists
        in_white = False
        in_black = False

        for line in handle:
            line = line.rstrip()

            if in_authors and ":" in line:
                in_authors = False

            elif in_white and ":" in line:
                in_white = False

            elif in_black and ":" in line:
                in_black = False
                rec["FEN"] = self.lboard.asFen()

            # New record start
            if line == "---":
                if rec is not None and rec["Black"].startswith("Mate in ") and not contains_fairy_pieces:
                    games.append(rec)
                    rec_id += 1

                contains_fairy_pieces = False

                self.lboard = LBoard()
                self.lboard.applyFen("8/8/8/8/8/8/8/8 w - - 0 1")

                rec = collections.defaultdict(str)
                rec["Id"] = rec_id
                rec["Offset"] = 0

            elif line.startswith("authors:"):
                in_authors = True

            elif line.startswith("source:"):
                rec["Event"] = line[8:]

            elif line.startswith("source-id:"):
                rec["Event"] = "%s (%s)" % (rec["Event"], line[12:])

            elif line.startswith("date:"):
                parts = line[6:].split("-")
                parts_len = len(parts)
                if parts_len >= 3:
                    rec["Day"] = parts[2]
                if parts_len >= 2:
                    rec["Month"] = parts[1]
                if parts_len >= 1:
                    rec["Year"] = parts[0]

            elif line.startswith("distinction:"):
                rec["Site"] = line[12:]

            elif line.startswith("algebraic:"):
                pass

            elif line.startswith("  white:"):
                parts = line.split("[")
                if len(parts) > 1:
                    pieces = parts[1][:-1]
                    for piece in pieces.split(", "):
                        if piece.startswith("Royal") or piece[0] not in chr2piece:
                            contains_fairy_pieces = True
                        else:
                            cord = Cord(piece[1:3]).cord
                            piece = chr2piece[piece[0]]
                            self.lboard._addPiece(cord, piece, WHITE)
                else:
                    in_white = True

            elif line.startswith("  black:"):
                parts = line.split("[")
                if len(parts) > 1:
                    pieces = parts[1][:-1]
                    for piece in pieces.split(", "):
                        if piece.startswith("Royal") or piece[0] not in chr2piece:
                            contains_fairy_pieces = True
                        else:
                            cord = Cord(piece[1:3]).cord
                            piece = chr2piece[piece[0]]
                            self.lboard._addPiece(cord, piece, BLACK)

                    rec["FEN"] = self.lboard.asFen()
                else:
                    in_black = True

            elif line.startswith("stipulation:"):
                if line.endswith("Black to move"):
                    line = line[:-14]
                    rec["FEN"] = rec["FEN"].replace("w", "b")

                line = line.split(": ")[1]
                if "+" in line:
                    rec["Result"] = WHITEWON
                    rec["Black"] = "Win"
                elif "-" in line:
                    rec["Result"] = BLACKWON
                    rec["Black"] = "Win"
                elif "=" in line:
                    rec["Result"] = DRAW
                    rec["Black"] = "Draw"
                elif line.startswith('"#'):
                    rec["Result"] = WHITEWON
                    rec["Black"] = "Mate in %s" % line[2:-1]
                    rec["Termination"] = "mate in %s" % line[2:-1]

            elif line.startswith("solution:"):
                # TODO: solutions can be in several (sometimes rather unusual) form
                pass

            else:
                if in_authors:
                    author = line[line.find("-") + 1:].lstrip()
                    if rec["White"]:
                        rec["White"] = "%s - %s" % (rec["White"], author)
                    else:
                        rec["White"] = author

                elif in_white:
                    piece = line[line.find("-") + 1:].lstrip()
                    cord = Cord(piece[1:3]).cord
                    piece = chr2piece[piece[0]]
                    self.lboard._addPiece(cord, piece, WHITE)

                elif in_black:
                    piece = line[line.find("-") + 1:].lstrip()
                    cord = Cord(piece[1:3]).cord
                    piece = chr2piece[piece[0]]
                    self.lboard._addPiece(cord, piece, BLACK)

        # Append the latest record
        if rec is not None and rec["Black"].startswith("Mate in ") and not contains_fairy_pieces:
            games.append(rec)

        return games

    def loadToModel(self, rec, position, model=None):
        if not model:
            model = GameModel()

        model.tags['Event'] = rec["Event"]
        model.tags['Site'] = rec["Site"]
        model.tags['Date'] = self.get_date(rec)
        model.tags['Round'] = ""
        model.tags['White'] = "?"
        model.tags['Black'] = "?"
        model.tags['Termination'] = rec["Termination"]

        fen = rec["FEN"]

        model.boards = [model.variant(setup=fen)]
        model.variations = [model.boards]
        model.status = WAITING_TO_START

        return model

    def get_date(self, rec):
        year = rec['Year']
        month = rec['Month']
        day = rec['Day']
        if year and month and day:
            tag_date = "%s.%02d.%02d" % (year, int(month), int(day))
        elif year and month:
            tag_date = "%s.%02d" % (year, int(month))
        elif year:
            tag_date = "%s" % year
        else:
            tag_date = ""
        return tag_date
Beispiel #59
0
    def test_apply_pop(self):
        """Testing Crazyhouse applyMove popMove"""

        board = LBoard(variant=CRAZYHOUSECHESS)
        board.applyFen(FEN1)
        
        holding0 = (board.holding[0].copy(), board.holding[1].copy())
        promoted0 = board.promoted[:]
        capture_promoting0 = board.capture_promoting
        hist_capture_promoting0 = board.hist_capture_promoting[:]

        print_board_promoted = False
        print_apply_pop = False

        for lmove1 in genAllMoves(board):
            #if lmove1 != parseAN(board, "c7b8=Q"):
            #    continue
            board.applyMove(lmove1)
            if print_apply_pop: print("applyMove1", Move(lmove1), board.holding, board.capture_promoting)
            if print_board_promoted: print(board.promoted)
            if board.opIsChecked():
                if print_apply_pop: print("popMove1 (invalid)", Move(lmove1))
                board.popMove()
                continue
                
            holding1 = (board.holding[0].copy(), board.holding[1].copy())
            promoted1 = board.promoted[:]
            capture_promoting1 = board.capture_promoting
            hist_capture_promoting1 = board.hist_capture_promoting[:]
            for lmove2 in genAllMoves(board):
                #if lmove2 != parseAN(board, "e8f7"):
                #   continue
                board.applyMove(lmove2)
                if print_apply_pop: print("   applyMove2", Move(lmove2), board.holding, board.capture_promoting)
                if print_board_promoted: print(board.promoted)
                if board.opIsChecked():
                    if print_apply_pop: print("   popMove2 (invalid)", Move(lmove2))
                    board.popMove()
                    continue

                holding2 = (board.holding[0].copy(), board.holding[1].copy())
                promoted2 = board.promoted[:]
                capture_promoting2 = board.capture_promoting
                hist_capture_promoting2 = board.hist_capture_promoting[:]
                for lmove3 in genAllMoves(board):
                    #if lmove3 != parseAN(board, "b8c8"):
                    #   continue
                    board.applyMove(lmove3)
                    if print_apply_pop: print("      applyMove3", Move(lmove3), board.holding, board.capture_promoting)
                    if print_board_promoted: print(board.promoted)
                    if board.opIsChecked():
                        if print_apply_pop: print("      popMove3 (invalid)", Move(lmove3))
                        board.popMove()
                        continue

                    board.popMove()
                    if print_apply_pop: print("      popMove3", Move(lmove3), board.holding, board.capture_promoting)
                    if print_board_promoted: print(board.promoted)

                    self.assertEqual(holding2, board.holding)
                    self.assertEqual(promoted2, board.promoted)
                    self.assertEqual(capture_promoting2, board.capture_promoting)
                    self.assertEqual(hist_capture_promoting2, board.hist_capture_promoting)

                board.popMove()
                if print_apply_pop: print("   popMove2", Move(lmove2), board.holding, board.capture_promoting)
                if print_board_promoted: print(board.promoted)

                self.assertEqual(holding1, board.holding)
                self.assertEqual(promoted1, board.promoted)
                self.assertEqual(capture_promoting1, board.capture_promoting)
                self.assertEqual(hist_capture_promoting1, board.hist_capture_promoting)
                
            board.popMove()
            if print_apply_pop: print("popMove1", Move(lmove1), board.holding, board.capture_promoting)
            if print_board_promoted: print(board.promoted)

            self.assertEqual(holding0, board.holding)
            self.assertEqual(promoted0, board.promoted)
            self.assertEqual(capture_promoting0, board.capture_promoting)
            self.assertEqual(hist_capture_promoting0, board.hist_capture_promoting)