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] }
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 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')
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)
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)
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))
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
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 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))
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))
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))
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
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]
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)
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")
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)
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")
def on_book_created(persp, event): self.assertTrue(os.path.isfile(BIN)) 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()
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
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)
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')
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')
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")
def add_variation(self, board, moves, comment="", score="", emit=True): board0 = board board = board0.clone() board.board.prev = None # this prevents annotation panel node searches to find this instead of board0 board.board.hash = -1 if comment: board.board.children.append(comment) variation = [board] for move in moves: new = board.move(move) if len(variation) == 1: new.board.prev = board0.board variation[0].board.next = new.board else: new.board.prev = board.board board.board.next = new.board variation.append(new) board = new if board0.board.next is None: # If we are in the latest played board, and want to add a variation # we have to add a not played yet board first # which can hold the variation as his child from pychess.Utils.lutils.LBoard import LBoard null_board = LBoard() null_board.prev = board0.board board0.board.next = null_board board0.board.next.children.append( [vboard.board for vboard in variation]) if score: variation[-1].board.children.append(score) head = None for vari in self.variations: if board0 in vari: head = vari break variation[0] = board0 self.variations.append(head[:board0.ply - self.lowply] + variation) self.needsSave = True if emit: self.emit("variation_added", board0.board.next.children[-1], board0.board.next) return self.variations[-1]
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))
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)
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)
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)
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
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)