def loadToModel(self, rec, position, model=None): if not model: model = GameModel() if "Variant" in rec: model.variant = FischerandomBoard fieldlist = rec["FEN"].split(" ") if len(fieldlist) == 4: fen = rec["FEN"] opcodestr = "" elif len(fieldlist) > 4: fen = " ".join(fieldlist[:4]) opcodestr = " ".join(fieldlist[4:]) else: raise LoadingError("EPD string can not have less than 4 field") opcodes = {} for opcode in map(str.strip, opcodestr.split(";")): space = opcode.find(" ") if space == -1: opcodes[opcode] = True else: opcodes[opcode[:space]] = opcode[space + 1:] if "hmvc" in opcodes: fen += " " + opcodes["hmvc"] else: fen += " 0" if "fmvn" in opcodes: fen += " " + opcodes["fmvn"] else: fen += " 1" model.boards = [model.variant(setup=fen)] model.variations = [model.boards] model.status = WAITING_TO_START # rc is kinda broken # if "rc" in opcodes: # model.boards[0].board.rc = int(opcodes["rc"]) if "resign" in opcodes: if fieldlist[1] == "w": model.status = BLACKWON else: model.status = WHITEWON model.reason = WON_RESIGN if model.status == WAITING_TO_START: status, reason = getStatus(model.boards[-1]) if status in (BLACKWON, WHITEWON, DRAW): model.status, model.reason = status, reason return model
def loadToModel(self, rec, position, model=None): if not model: model = GameModel() if "Variant" in rec: model.variant = FischerandomBoard fieldlist = rec["FEN"].split(" ") if len(fieldlist) == 4: fen = rec["FEN"] opcodestr = "" elif len(fieldlist) > 4: fen = " ".join(fieldlist[:4]) opcodestr = " ".join(fieldlist[4:]) else: raise LoadingError("EPD string can not have less than 4 field") opcodes = {} for opcode in map(str.strip, opcodestr.split(";")): space = opcode.find(" ") if space == -1: opcodes[opcode] = True else: opcodes[opcode[:space]] = opcode[space + 1:] if "hmvc" in opcodes: fen += " " + opcodes["hmvc"] else: fen += " 0" if "fmvn" in opcodes: fen += " " + opcodes["fmvn"] else: fen += " 1" model.boards = [model.variant(setup=fen)] model.variations = [model.boards] model.status = WAITING_TO_START # rc is kinda broken # if "rc" in opcodes: # model.boards[0].board.rc = int(opcodes["rc"]) if "resign" in opcodes: if fieldlist[1] == "w": model.status = BLACKWON else: model.status = WHITEWON model.reason = WON_RESIGN if model.status == WAITING_TO_START: status, reason = getStatus(model.boards[-1]) if status in (BLACKWON, WHITEWON, DRAW): model.status, model.reason = status, reason return model
def loadToModel(self, gameno, position=-1, model=None, quick_parse=True): if not model: model = GameModel() 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._getTag(gameno, 'Round') model.tags['White'], model.tags['Black'] = self.get_player_names( gameno) model.tags['WhiteElo'] = self._getTag(gameno, 'WhiteElo') model.tags['BlackElo'] = self._getTag(gameno, 'BlackElo') model.tags['Result'] = reprResult[self.get_result(gameno)] model.tags['ECO'] = self._getTag(gameno, "ECO") fenstr = self._getTag(gameno, "FEN") variant = self._getTag(gameno, "Variant") if variant and ("fischer" in variant.lower() or "960" in variant): from pychess.Variants.fischerandom import FRCBoard model.variant = FischerRandomChess model.boards = [FRCBoard(fenstr)] else: if fenstr: model.boards = [Board(fenstr)] else: model.boards = [Board(setup=True)] del model.moves[:] model.status = WAITING_TO_START model.reason = UNKNOWN_REASON error = None if quick_parse: movstrs = self._getMoves(gameno) for i, mstr in enumerate(movstrs): if position != -1 and model.ply >= position: break try: move = parseAny(model.boards[-1], mstr) except ParsingError, e: notation, reason, boardfen = e.args ply = model.boards[-1].ply if ply % 2 == 0: moveno = "%d." % (i / 2 + 1) else: moveno = "%d..." % (i / 2 + 1) errstr1 = _( "The game can't be read to end, because of an error parsing move %(moveno)s '%(notation)s'." ) % { 'moveno': moveno, 'notation': notation } errstr2 = _("The move failed because %s.") % reason error = LoadingError(errstr1, errstr2) break model.moves.append(move) model.boards.append(model.boards[-1].move(move))
def loadToModel (self, gameno, position=-1, model=None, quick_parse=True): if not model: model = GameModel() 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._getTag(gameno, 'Round') model.tags['White'], model.tags['Black'] = self.get_player_names(gameno) model.tags['WhiteElo'] = self._getTag(gameno, 'WhiteElo') model.tags['BlackElo'] = self._getTag(gameno, 'BlackElo') model.tags['Result'] = reprResult[self.get_result(gameno)] model.tags['ECO'] = self._getTag(gameno, "ECO") fenstr = self._getTag(gameno, "FEN") variant = self._getTag(gameno, "Variant") if variant and ("fischer" in variant.lower() or "960" in variant): from pychess.Variants.fischerandom import FRCBoard model.variant = FischerRandomChess model.boards = [FRCBoard(fenstr)] else: if fenstr: model.boards = [Board(fenstr)] else: model.boards = [Board(setup=True)] del model.moves[:] model.status = WAITING_TO_START model.reason = UNKNOWN_REASON error = None if quick_parse: movstrs = self._getMoves (gameno) for i, mstr in enumerate(movstrs): if position != -1 and model.ply >= position: break try: move = parseAny (model.boards[-1], mstr) except ParsingError, e: notation, reason, boardfen = e.args ply = model.boards[-1].ply if ply % 2 == 0: moveno = "%d." % (i/2+1) else: moveno = "%d..." % (i/2+1) errstr1 = _("The game can't be read to end, because of an error parsing move %(moveno)s '%(notation)s'.") % { 'moveno': moveno, 'notation': notation} errstr2 = _("The move failed because %s.") % reason error = LoadingError (errstr1, errstr2) break model.moves.append(move) model.boards.append(model.boards[-1].move(move))
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 loadToModel(self, rec, position=-1, model=None): """ Parse game text and load game record header tags to a GameModel object """ if model is None: model = GameModel() if self.pgn_is_string: rec = self.games[0] # Load mandatory tags for tag in mandatory_tags: model.tags[tag] = rec[tag] # Load other tags for tag in ('WhiteElo', 'BlackElo', 'ECO', 'TimeControl', 'Annotator'): model.tags[tag] = rec[tag] if self.pgn_is_string: for tag in rec: if isinstance(rec[tag], str) and rec[tag]: model.tags[tag] = rec[tag] else: model.info = self.tag_database.get_info(rec) extra_tags = self.tag_database.get_exta_tags(rec) for et in extra_tags: model.tags[et['tag_name']] = et['tag_value'] if self.pgn_is_string: variant = rec["Variant"].capitalize() else: variant = self.get_variant(rec) if model.tags['TimeControl']: tc = parseTimeControlTag(model.tags['TimeControl']) if tc is not None: secs, gain, moves = tc model.timed = True model.timemodel.secs = secs model.timemodel.gain = gain model.timemodel.minutes = secs / 60 model.timemodel.moves = moves for tag, color in (('WhiteClock', WHITE), ('BlackClock', BLACK)): if tag in model.tags: try: millisec = parseClockTimeTag(model.tags[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) model.tags["FEN"] = 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 _create_board(model, node): 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 Exception: raise LoadingError( _("Invalid move."), "%s%s" % (move_count(node, black_periods=True), move)) return board def walk(model, node, path): boards = path stack = [] current = node while current is not None: board = _create_board(model, current) boards.append(board) stack.append(current) current = current.next else: model.variations.append(list(boards)) while stack: current = stack.pop() boards.pop() for child in current.children: if isinstance(child, list): if len(child) > 1: # non empty variation, go walk walk(model, child[1], list(boards)) 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 model.timed 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), ] 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 = move_time_re.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 = move_eval_re.search(child) if match: sign, num, fraction, depth = match.groups() sign = 1 if sign is None or sign == "+" else -1 num = 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: if self.pgn_is_string: result = rec["Result"] if result in pgn2Const: status = pgn2Const[result] else: status = RUNNING else: 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 model.timed: model.timemodel.movingColor = model.boards[-1].color # 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 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)] 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 headers for tag in ('Annotator', 'ECO', 'WhiteElo', 'BlackElo', 'TimeControl'): if self._getTag(gameno, tag): model.tags[tag] = self._getTag(gameno, tag) else: model.tags[tag] = "" model.info = self.get_info(gameno) # 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: millisec = parseClockTimeTag(self._getTag(gameno, 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' Header for gameno %s" % (tag, gameno)) fenstr = self._getTag(gameno, "FEN") variant = self.get_variant(gameno) if variant: if variant not in name2variant: raise LoadingError("Unknown variant %s for gameno %s" % (variant, gameno)) 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(gameno) 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, 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] 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 = 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
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
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) # 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.timed: # 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)) # if model.tags['TimeControl']: # minutes, gain = parseTimeControlTag(model.tags['TimeControl']) # model.timemodel.minutes = minutes # model.timemodel.gain = gain fenstr = self._getTag(gameno, "FEN") variant = self.get_variant(gameno) if variant: # Fixes for some non statndard Chess960 .pgn if (fenstr is not None) and variant == "Fischerandom": model.tags["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) elif variant == "Atomic": model.tags["Variant"] = "Atomic" elif variant == "Crazyhouse": model.tags["Variant"] = "Crazyhouse" elif variant == "Wildcastle": model.tags["Variant"] = "Wildcastle" elif variant == "Suicide": model.tags["Variant"] = "Suicide" elif variant == "Losers": model.tags["Variant"] = "Losers" elif variant == "Kingofthehill": model.tags["Variant"] = "Kingofthehill" if variant == "Fischerandom": board = LBoard(FISCHERRANDOMCHESS) model.variant = FischerRandomChess elif variant == "Atomic": board = LBoard(ATOMICCHESS) model.variant = AtomicChess elif variant == "Crazyhouse": board = LBoard(CRAZYHOUSECHESS) model.variant = CrazyhouseChess elif variant == "Wildcastle": board = LBoard(WILDCASTLECHESS) model.variant = WildcastleChess elif variant == "Suicide": board = LBoard(SUICIDECHESS) model.variant = SuicideChess elif variant == "Losers": board = LBoard(LOSERSCHESS) model.variant = LosersChess elif variant == "Kingofthehill": board = LBoard(KINGOFTHEHILLCHESS) model.variant = KingOfTheHillChess else: 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 if variant == "Fischerandom": board = FRCBoard(setup=node.asFen(), lboard=node) elif variant == "Atomic": board = AtomicBoard(setup=node.asFen(), lboard=node) elif variant == "Crazyhouse": board = CrazyhouseBoard(setup=node.asFen(), lboard=node) elif variant == "Wildcastle": board = WildcastleBoard(setup=node.asFen(), lboard=node) elif variant == "Suicide": board = SuicideBoard(setup=node.asFen(), lboard=node) elif variant == "Losers": board = LosersBoard(setup=node.asFen(), lboard=node) elif variant == "Kingofthehill": board = KingOfTheHillBoard(setup=node.asFen(), lboard=node) else: board = Board(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