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 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 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 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 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)
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_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 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 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 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_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 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_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 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 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_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 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 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))
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)
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 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)
def test_white_promotion(self): FEN = "k7/7P/8/8/8/8/8/7K w - - 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("h7h8=Q", moves) self.assertNotIn("h7h8", moves) self.assertNotIn("h7h8=R", moves) self.assertNotIn("h7h8=B", moves) self.assertNotIn("h7h8=N", moves) self.assertNotIn("h7h8=K", moves)
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)
def __onPlayBoardCreated (self, boardManager, board): self.mytime = int(board["mins"])*60 self.increment = int(board["incr"]) self.gameno = board["gameno"] self.lastPly = -1 self.acceptedTimesettings.append((self.mytime, self.increment)) self.tellHome("Starting a game (%s, %s) gameno: %s" % (board["wname"], board["bname"], board["gameno"])) if board["bname"].lower() == self.connection.getUsername().lower(): self.playingAs = BLACK else: self.playingAs = WHITE self.board = LBoard(NORMALCHESS)
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 add_variation(self, board, moves, comment="", score=""): board0 = board board = board0.clone() board.board.prev = None 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 null_board.plyCount = board0.board.plyCount + 1 board0.board.next = null_board board0.board.next.children.append([board.board for board in variation]) 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 self.emit("variation_added", board0.board.next.children[-1], board0.board.next, comment, score) return self.variations[-1]
def add_variation(self, board, moves, comment="", score=""): board0 = board board = board0.clone() board.board.prev = None 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 null_board.plyCount = board0.board.plyCount + 1 board0.board.next = null_board board0.board.next.children.append([board.board for board in variation]) 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 self.emit("variation_added", board0.board.next.children[-1], board0.board.next, comment, score) return self.variations[-1]
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," + \ "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 __init__ (self): PyChess.__init__(self) self.board = LBoard(NORMALCHESS) self.board.applyFen(FEN_START) self.forced = False self.analyzing = False self.worker = None self.features = { "setboard": 1, "analyze": 1, "san": 1, "usermove": 1, "reuse": 0, "draw": 1, "sigterm": 1, "colors": 1, "variants": "normal,nocastle,fischerandom", "myname": "PyChess %s" % pychess.VERSION }
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)
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)
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)
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)
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 add_variation(self, board, moves): board0 = board board = board0.clone() board.board.prev = None 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: 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([board.board for board in variation]) 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 #self.emit("variations_changed") return self.variations[-1]
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]}
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 __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)
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 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()
from pychess.System.Log import log 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
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
from pychess.Database.model import engine, metadata, collection, event,\ 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 = {}
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
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))