def checkStatus(self): """ Updates self.status so it fits with what getStatus(boards[-1]) would return. That is, if the game is e.g. check mated this will call mode.end(), or if moves have been undone from an otherwise ended position, this will call __resume and emit game_unended. """ log.debug("GameModel.checkStatus:") # call flag by engine if self.isEngine2EngineGame() and self.status in UNDOABLE_STATES: return status, reason = getStatus(self.boards[-1]) if self.endstatus is not None: self.end(self.endstatus, reason) return if status != RUNNING and self.status in (WAITING_TO_START, PAUSED, RUNNING): if status == DRAW and reason in (DRAW_REPITITION, DRAW_50MOVES): if self.isEngine2EngineGame(): self.end(status, reason) return else: self.end(status, reason) return if status != self.status and self.status in UNDOABLE_STATES \ and self.reason in UNDOABLE_REASONS: self.__resume() self.status = status self.reason = UNKNOWN_REASON self.emit("game_unended")
def status_changed(self, player, prop): log.debug( "%s" % player, extra={"task": (self.connection.username, "PTS.status_changed")}) if player not in self.players: return try: self.store.set(self.players[player]["ti"], 6, player.display_status) self.store.set(self.players[player]["ti"], 7, get_player_tooltip_text(player)) except KeyError: pass if player.status == IC_STATUS_PLAYING and player.game and \ "private" not in self.players[player]: self.players[player]["private"] = player.game.connect( "notify::private", self.private_changed, player) elif player.status != IC_STATUS_PLAYING and \ "private" in self.players[player]: game = player.game if game and game.handler_is_connected(self.players[player][ "private"]): game.disconnect(self.players[player]["private"]) del self.players[player]["private"] if player == self.getSelectedPlayer(): self.onSelectionChanged(None) return False
def init_chess_db(self): """ Create/open polyglot .bin file with extra win/loss/draw stats using chess_db parser from https://github.com/mcostalba/chess_db """ if chess_db_path is not None and self.path and self.size > 0: try: if self.progressbar is not None: self.progressbar.set_text("Creating .bin index file...") self.chess_db = Parser(engine=(chess_db_path, )) self.chess_db.open(self.path) bin_path = os.path.splitext(self.path)[0] + '.bin' if not os.path.isfile(bin_path): log.debug("No valid games found in %s" % self.path) self.chess_db = None elif getmtime(self.path) > getmtime(bin_path): self.chess_db.make() except OSError as err: self.chess_db = None log.warning("Failed to sart chess_db parser. OSError %s %s" % (err.errno, err.strerror)) except pexpect.TIMEOUT: self.chess_db = None log.warning("chess_db parser failed (pexpect.TIMEOUT)") except pexpect.EOF: self.chess_db = None log.warning("chess_db parser failed (pexpect.EOF)")
def private_changed(self, game, prop, player): log.debug( "%s" % player, extra={"task": (self.connection.username, "PTS.private_changed")}) self.status_changed(player, prop) self.onSelectionChanged(self.tv.get_selection()) return False
def decline(self, offer): log.debug("OfferManager.decline: %s" % offer) if offer.index is not None: self.declineIndex(offer.index) else: self.connection.client.run_command("decline t %s" % offerTypeToStr[offer.type])
def playerUndoMoves(self, movecount, gamemodel): log.debug("ICPlayer.playerUndoMoves: id(self)=%d self=%s, undoing movecount=%d" % \ (id(self), self, movecount)) # If current player has changed so that it is no longer us to move, # We raise TurnInterruprt in order to let GameModel continue the game if movecount % 2 == 1 and gamemodel.curplayer != self: self.queue.put("int")
def setBoard (self, board): log.debug("setBoardAtPly: board=%s" % board, extra={"task":self.defname}) self._recordMove(board, None, None) if not self.readyMoves: return self._searchNow()
def __obsGameCreated (self, bm, ficsgame): if self.gamemodel.ficsplayers[0] == ficsgame.wplayer and \ self.gamemodel.ficsplayers[1] == ficsgame.bplayer and \ self.gameno == ficsgame.gameno: log.debug("ICPlayer.__obsGameCreated: gameno reappeared: gameno=%s white=%s black=%s" % \ (ficsgame.gameno, ficsgame.wplayer.name, ficsgame.bplayer.name)) self.current = False
def offer (self, offer, curply): log.debug("OfferManager.offer: curply=%s %s\n" % (curply, offer)) self.lastPly = curply s = offerTypeToStr[offer.type] if offer.type == TAKEBACK_OFFER: s += " " + str(curply - offer.param) print >> self.connection.client, s
def cook_some(self): recv = self.sock.recv(self.BUFFER_SIZE) if len(recv) == 0: return if not self.connected: log.debug(recv, extra={"task": (self.name, "raw")}) self.buf += recv self.connected = True if b"FatICS" in self.buf: self.FatICS = True elif b"puertorico.com" in self.buf: self.USCN = True self.buf = self.buf.replace(IAC_WONT_ECHO, b"") elif b"Starting FICS session" in self.buf: self.buf = self.buf.replace(IAC_WONT_ECHO, b"") else: recv, g_count, self.stateinfo = self.decode(recv, self.stateinfo) recv = recv.replace(b"\r", b"") log.debug(recv, extra={"task": (self.name, "raw")}) for i in range(g_count): print(G_RESPONSE, file=self) self.buf += recv
def offerError(self, offer, error): log.debug("Human.offerError: self=%s error=%s %s" % (self, error, offer)) assert offer.type in ACTION_NAMES actionName = ACTION_NAMES[offer.type] if error == ACTION_ERROR_NONE_TO_ACCEPT: heading = _("Unable to accept %s") % actionName.lower() text = _("Probably because it has been withdrawn.") elif error == ACTION_ERROR_NONE_TO_DECLINE or \ error == ACTION_ERROR_NONE_TO_WITHDRAW: # If the offer was not there, it has probably already been either # declined or withdrawn. return else: heading = _("%s returns an error") % actionName text = ERROR_MESSAGES[error] content = InfoBar.get_message_content(heading, text, Gtk.STOCK_DIALOG_WARNING) def response_cb(infobar, response, message): message.dismiss() message = InfoBarMessage(Gtk.MessageType.WARNING, content, response_cb) message.add_button(InfoBarMessageButton(Gtk.STOCK_CLOSE, Gtk.ResponseType.CANCEL)) self.gmwidg.showMessage(message)
def _on_analyze(self, analyzer, analysis, analyzer_type): if self.board.view.animating: return if not self.menuitems[analyzer_type + "_mode"].active: return if len(analysis) >= 1 and analysis[0] is not None: movstrs, score, depth = analysis[0] board = analyzer.board try: moves = listToMoves(board, movstrs, validate=True) except ParsingError as e: # ParsingErrors may happen when parsing "old" lines from # analyzing engines, which haven't yet noticed their new tasks log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" % (' '.join(movstrs), e)) return except: return if moves and (self.gamemodel.curplayer.__type__ == LOCAL or [player.__type__ for player in self.gamemodel.players] == [REMOTE, REMOTE] or self.gamemodel.status not in UNFINISHED_STATES): if moves[0].flag == DROP: piece = lmove.FCORD(moves[0].move) color = board.color if analyzer_type == HINT else 1 - board.color cord0 = board.getHoldingCord(color, piece) self._set_arrow(analyzer_type, (cord0, moves[0].cord1)) else: self._set_arrow(analyzer_type, moves[0].cords) else: self._set_arrow(analyzer_type, None) return False
def cook_some(self, data): if not self.connected: log.debug(data, extra={"task": (self.name, "raw")}) self.connected = True if b"FatICS" in data: self.FatICS = True elif b"puertorico.com" in data: self.USCN = True data = data.replace(IAC_WONT_ECHO, b"") elif b"chessclub.com" in data: self.ICC = True data = data.replace(IAC_WONT_ECHO, b"") elif b"Starting FICS session" in data: data = data.replace(IAC_WONT_ECHO, b"") else: if self.timeseal: data, g_count, self.stateinfo = self.decode(data, self.stateinfo) data = data.replace(b"\r", b"").replace(b"\x07", b"") # enable this only for temporary debugging log.debug(data, extra={"task": (self.name, "raw")}) if self.timeseal: for i in range(g_count): self._stream_writer.write(self.encode(bytearray(G_RESPONSE, "utf-8")) + b"\n") return data
def on_analyze(self, engine, analysis): if self.boardview.animating: return if self.boardview.model.isPlayingICSGame(): return if not self.active: return is_FAN = conf.get("figuresInNotation", False) for i, line in enumerate(analysis): if line is None: self.store[self.path + (i, )] = self.textOnlyRow("") continue board0 = self.engine.board board = board0.clone() movstrs, score, depth = line try: pv = listToMoves(board, movstrs, validate=True) except ParsingError as e: # ParsingErrors may happen when parsing "old" lines from # analyzing engines, which haven't yet noticed their new tasks log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" % (' '.join(movstrs), e)) return except: return move = None if pv: move = pv[0] ply0 = board.ply if self.mode == HINT else board.ply + 1 counted_pv = [] for j, pvmove in enumerate(pv): ply = ply0 + j if ply % 2 == 0: mvcount = "%d." % (ply / 2 + 1) elif j == 0: mvcount = "%d..." % (ply / 2 + 1) else: mvcount = "" counted_pv.append("%s%s" % (mvcount, toFAN(board, pvmove) if is_FAN else toSAN(board, pvmove, True))) board = board.move(pvmove) goodness = (min(max(score, -250), 250) + 250) / 500.0 if self.engine.board.color == BLACK: score = -score self.store[self.path + (i, )] = [ (board0, move, pv), (prettyPrintScore(score, depth), 1, goodness), 0, False, " ".join(counted_pv), False, False ]
def generalStart (gamemodel, player0tup, player1tup, loaddata=None): """ The player tuples are: (The type af player in a System.const value, A callable creating the player, A list of arguments for the callable, A preliminary name for the player) If loaddata is specified, it should be a tuple of: (A text uri or fileobj, A Savers.something module with a load function capable of loading it, An int of the game in file you want to load, The position from where to start the game) """ log.debug("ionest.generalStart: %s\n %s\n %s\n" % (gamemodel, player0tup, player1tup)) worker = GtkWorker (lambda w: workfunc(w, gamemodel, player0tup, player1tup, loaddata)) def onPublished (worker, vallist): for val in vallist: # The worker will start by publishing (gmwidg, game) if type(val) == tuple: gmwidg, game = val gamewidget.attachGameWidget(gmwidg) gamenanny.nurseGame(gmwidg, game) handler.emit("gmwidg_created", gmwidg, game) # Then the worker will publish functions setting up widget stuff elif callable(val): val() worker.connect("published", onPublished) def onDone (worker, (gmwidg, game)): gmwidg.connect("close_clicked", closeGame, game) worker.__del__()
def acceptReceived(self, player, offer): log.debug("GameModel.acceptReceived: accepter=%s %s" % ( repr(player), offer)) if player == self.players[WHITE]: opPlayer = self.players[BLACK] else: opPlayer = self.players[WHITE] if offer in self.offers and self.offers[offer] == opPlayer: if offer.type == DRAW_OFFER: self.end(DRAW, DRAW_AGREE) elif offer.type == TAKEBACK_OFFER: log.debug("GameModel.acceptReceived: undoMoves(%s)" % ( self.ply - offer.param)) self.undoMoves(self.ply - offer.param) elif offer.type == ADJOURN_OFFER: self.end(ADJOURNED, ADJOURNED_AGREEMENT) elif offer.type == ABORT_OFFER: self.end(ABORTED, ABORTED_AGREEMENT) elif offer.type == PAUSE_OFFER: self.pause() elif offer.type == RESUME_OFFER: self.resume() del self.offers[offer] else: player.offerError(offer, ACTION_ERROR_NONE_TO_ACCEPT)
def __onOfferDeclined(self, om, offer): for offer_ in list(self.gamemodel.offers.keys()): if offer.type == offer_.type: offer.param = offer_.param log.debug("ICPlayer.__onOfferDeclined: emitting decline for %s" % offer) self.emit("decline", offer)
def makeMove(self, board1, move, board2): log.debug("Human.makeMove: move=%s, board1=%s board2=%s" % ( move, board1, board2)) if self.board.view.premove_piece and self.board.view.premove0 and \ self.board.view.premove1 and \ self.color == self.board.view.premove_piece.color: if validate(board1, Move(self.board.view.premove0, self.board.view.premove1, board1, promotion=self.board.view.premove_promotion)): log.debug("Human.makeMove: Setting move to premove %s %s" % ( self.board.view.premove0, self.board.view.premove1)) self.board.emit_move_signal( self.board.view.premove0, self.board.view.premove1, promotion=self.board.view.premove_promotion) # reset premove self.board.view.setPremove(None, None, None, None) self.gmwidg.setLocked(False) item = yield from self.move_queue.get() self.gmwidg.setLocked(True) if item == "del": log.debug("Human.makeMove got: del") raise PlayerIsDead elif item == "int": log.debug("Human.makeMove got: int") raise TurnInterrupt elif item == "pass": log.debug("Human.makeMove got: pass") raise PassInterrupt return item
def offerDeclined (self, offer): log.debug("Human.offerDeclined: self=%s %s\n" % (self, offer)) if offer.type not in ACTION_NAMES: return title = _("%s was declined by your opponent") % ACTION_NAMES[offer.type] description = _("You can try to send the offer to your opponent later in the game again.") self._message(title, description, gtk.MESSAGE_INFO, gtk.BUTTONS_OK)
def analyse_moves(): should_black = conf.get("shouldBlack", True) should_white = conf.get("shouldWhite", True) from_current = conf.get("fromCurrent", True) start_ply = gmwidg.board.view.shown if from_current else 0 move_time = int(conf.get("max_analysis_spin", 3)) threshold = int(conf.get("variation_threshold_spin", 50)) for board in gamemodel.boards[start_ply:]: if stop_event.is_set(): break @idle_add def do(): gmwidg.board.view.setShownBoard(board) do() analyzer.setBoard(board) if threat_PV: inv_analyzer.setBoard(board) time.sleep(move_time + 0.1) ply = board.ply color = (ply - 1) % 2 if ply - 1 in gamemodel.scores and ply in gamemodel.scores and ( (color == BLACK and should_black) or (color == WHITE and should_white)): oldmoves, oldscore, olddepth = gamemodel.scores[ply - 1] oldscore = oldscore * -1 if color == BLACK else oldscore score_str = prettyPrintScore(oldscore, olddepth) moves, score, depth = gamemodel.scores[ply] score = score * -1 if color == WHITE else score diff = score - oldscore if (diff > threshold and color == BLACK) or (diff < -1 * threshold and color == WHITE): if threat_PV: try: if ply - 1 in gamemodel.spy_scores: oldmoves0, oldscore0, olddepth0 = gamemodel.spy_scores[ply - 1] score_str0 = prettyPrintScore(oldscore0, olddepth0) pv0 = listToMoves(gamemodel.boards[ply - 1], ["--"] + oldmoves0, validate=True) if len(pv0) > 2: gamemodel.add_variation(gamemodel.boards[ply - 1], pv0, comment="Treatening", score=score_str0) except ParsingError as e: # ParsingErrors may happen when parsing "old" lines from # analyzing engines, which haven't yet noticed their new tasks log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" % (' '.join(oldmoves), e)) try: pv = listToMoves(gamemodel.boards[ply - 1], oldmoves, validate=True) gamemodel.add_variation(gamemodel.boards[ply - 1], pv, comment="Better is", score=score_str) except ParsingError as e: # ParsingErrors may happen when parsing "old" lines from # analyzing engines, which haven't yet noticed their new tasks log.debug("__parseLine: Ignored (%s) from analyzer: ParsingError%s" % (' '.join(oldmoves), e)) widgets["analyze_game"].hide() widgets["analyze_ok_button"].set_sensitive(True) conf.set("analyzer_check", old_check_value) if threat_PV: conf.set("inv_analyzer_check", old_inv_check_value) message.dismiss()
def offerWithdrawn (self, offer): log.debug("Human.offerWithdrawn: self=%s %s\n" % (self, offer)) if offer.type not in ACTION_NAMES: return title = _("%s was withdrawn by your opponent") % ACTION_NAMES[offer.type] description = _("Your opponent seems to have changed his or her mind.") self._message(title, description, gtk.MESSAGE_INFO, gtk.BUTTONS_OK)
def acceptReceived(self, player, offer): log.debug("ICGameModel.acceptReceived: accepter=%s %s" % (repr(player), offer)) if player.__type__ == LOCAL: GameModel.acceptReceived(self, player, offer) log.debug("ICGameModel.acceptReceived: connection.om.accept(%s)" % offer) self.connection.om.accept(offer)
def __onOfferAdd(self, om, offer): if self.gamemodel.status in UNFINISHED_STATES and not self.gamemodel.isObservationGame( ): log.debug("ICPlayer.__onOfferAdd: emitting offer: self.gameno=%s self.name=%s %s" % \ (self.gameno, self.name, offer)) self.offers[offer.index] = offer self.emit("offer", offer)
def makeMove(self, board1, move, board2): log.debug("makeMove: move=%s self.pondermove=%s board1=%s board2=%s self.board=%s" % ( move, self.pondermove, board1, board2, self.board), extra={"task": self.defname}) assert self.readyMoves self._recordMove(board1, move, board2) self.waitingForMove = True ponderhit = False if board2 and self.pondermove and move == self.pondermove: ponderhit = True elif board2 and self.pondermove: self.ignoreNext = True print("stop", file=self.engine) self._searchNow(ponderhit=ponderhit) # Parse outputs try: return_queue = yield from self.queue.get() if return_queue == "invalid": raise InvalidMove if return_queue == "del": raise PlayerIsDead if return_queue == "int": self.pondermove = None self.ignoreNext = True self.needBestmove = True self.hurry() raise TurnInterrupt return return_queue finally: self.waitingForMove = False
def accept(self, offer): log.debug("OfferManager.accept: %s" % offer) if offer.index is not None: self.acceptIndex(offer.index) else: self.connection.client.run_command("accept t %s" % offerTypeToStr[offer.type])
def on_gmwidg_closed(gmwidg): log.debug("GladeHandlers.on_gmwidg_closed") del gameDic[gmwidg] if not gameDic: for widget in MENU_ITEMS: gamewidget.getWidgets()[widget].set_property('sensitive', False)
def offerReceived(self, player, offer): log.debug("ICGameModel.offerReceived: offerer=%s %s" % (repr(player), offer)) if player == self.players[WHITE]: opPlayer = self.players[BLACK] else: opPlayer = self.players[WHITE] if offer.type == CHAT_ACTION: opPlayer.putMessage(offer.param) elif offer.type in (RESIGNATION, FLAG_CALL): self.connection.om.offer(offer, self.ply) elif offer.type in OFFERS: if offer not in self.offers: log.debug("ICGameModel.offerReceived: %s.offer(%s)" % (repr(opPlayer), offer)) self.offers[offer] = player opPlayer.offer(offer) # If the offer was an update to an old one, like a new takebackvalue # we want to remove the old one from self.offers for offer_ in list(self.offers.keys()): if offer.type == offer_.type and offer != offer_: del self.offers[offer_]
def init_engine(analyzer_type, gamemodel, force=False): """ Initializes and starts the engine analyzer of analyzer_type the user has configured in the Engines tab of the preferencesDialog, for gamemodel. If no such engine is set in the preferences, or if the configured engine doesn't support the chess variant being played in gamemodel, then no analyzer is started and None is returned. """ if analyzer_type == HINT: combo_name = "ana_combobox" check_name = "analyzer_check" mode = ANALYZING else: combo_name = "inv_ana_combobox" check_name = "inv_analyzer_check" mode = INVERSE_ANALYZING analyzer = None if conf.get(check_name, True): anaengines = list(discoverer.getAnalyzers()) engine = discoverer.getEngineByMd5(conf.get(combo_name, 0)) if engine is None: engine = anaengines[0] if gamemodel.variant.variant in discoverer.getEngineVariants(engine): analyzer = discoverer.initAnalyzerEngine(engine, mode, gamemodel.variant) log.debug("%s analyzer: %s" % (analyzer_type, repr(analyzer))) return analyzer
def nurseGame (gmwidg, gamemodel): """ Call this function when gmwidget is just created """ log.debug("nurseGame: %s %s" % (gmwidg, gamemodel)) gmwidg.connect("infront", on_gmwidg_infront) gmwidg.connect("closed", on_gmwidg_closed) gmwidg.connect("title_changed", on_gmwidg_title_changed) # Because of the async loading of games, the game might already be started, # when nurseGame is called. # Thus we support both cases. if gamemodel.status == WAITING_TO_START: gamemodel.connect("game_started", on_game_started, gmwidg) gamemodel.connect("game_loaded", game_loaded, gmwidg) else: if gamemodel.uri: game_loaded(gamemodel, gamemodel.uri, gmwidg) on_game_started(gamemodel, gmwidg) gamemodel.connect("game_saved", game_saved, gmwidg) gamemodel.connect("game_ended", game_ended, gmwidg) gamemodel.connect("game_unended", game_unended, gmwidg) gamemodel.connect("game_resumed", game_unended, gmwidg) gamemodel.connect("game_changed", game_changed, gmwidg) gamemodel.connect("game_paused", game_paused, gmwidg) if isinstance(gamemodel, ICGameModel): gamemodel.connection.connect("disconnected", on_disconnected, gmwidg)
def offer(self, offer): log.debug("Human.offer: self=%s %s" % (self, offer)) assert offer.type in OFFER_MESSAGES if self.gamemodel.players[1 - self.color].__type__ is LOCAL: self.emit("accept", offer) return heading, text, takes_param = OFFER_MESSAGES[offer.type] if takes_param: param = offer.param if offer.type == TAKEBACK_OFFER and \ self.gamemodel.players[1 - self.color].__type__ != REMOTE: param = self.gamemodel.ply - offer.param heading = heading % param text = text % param def response_cb(infobar, response, message): if response == Gtk.ResponseType.ACCEPT: self.emit("accept", offer) elif response == Gtk.ResponseType.NO: self.emit("decline", offer) message.dismiss() content = InfoBar.get_message_content(heading, text, Gtk.STOCK_DIALOG_QUESTION) message = InfoBarMessage(Gtk.MessageType.QUESTION, content, response_cb) message.add_button(InfoBarMessageButton( _("Accept"), Gtk.ResponseType.ACCEPT)) message.add_button(InfoBarMessageButton( _("Decline"), Gtk.ResponseType.NO)) message.add_button(InfoBarMessageButton(Gtk.STOCK_CLOSE, Gtk.ResponseType.CANCEL)) self.gmwidg.showMessage(message)
def playerUndoMoves(self, movecount, gamemodel): log.debug("Human.playerUndoMoves: movecount=%s self=%s gamemodel.curplayer=%s" % (movecount, self, gamemodel.curplayer)) self.gmwidg.clearMessages() # If the movecount is odd, the player has changed, and we have to interupt if movecount % 2 == 1 and gamemodel.curplayer != self: # If it is no longer us to move, we raise TurnInterruprt in order to # let GameModel continue the game. log.debug("Human.playerUndoMoves: putting TurnInterrupt into self.move_queue %s" % self.name) self.move_queue.put_nowait("int") # If the movecount is even, we have to ensure the board is unlocked. # This is because it might have been locked by the game ending, but # perhaps we have now undone some moves, and it is no longer ended. elif movecount % 2 == 0 and gamemodel.curplayer == self: log.debug("Human.playerUndoMoves: self=%s: calling gmwidg.setLocked" % (self)) self.gmwidg.setLocked(False) log.debug("Human.playerUndoMoves: putting PassInterrupt into self.move_queue %s" % self.name) self.move_queue.put_nowait("pass")
def write_stdin(self, writer, line): try: log.debug(line, extra={"task": self.defname}) writer.write(line.encode()) yield from writer.drain() except BrokenPipeError: log.debug('SubProcess.write_stdin(): BrokenPipeError', extra={"task": self.defname}) self.emit("died") self.terminate() except ConnectionResetError: log.debug('SubProcess.write_stdin(): ConnectionResetError', extra={"task": self.defname}) self.emit("died") self.terminate() except GLib.GError: log.debug("SubProcess.write_stdin(): GLib.GError", extra={"task": self.defname}) self.emit("died") self.terminate()
def makeMove(self, board1, move, board2): log.debug("ICPlayer.makemove: id(self)=%d self=%s move=%s board1=%s board2=%s" % ( id(self), self, move, board1, board2)) if board2 and not self.gamemodel.isObservationGame(): # TODO: Will this work if we just always use CASTLE_SAN? castle_notation = CASTLE_KK if board2.variant == FISCHERRANDOMCHESS: castle_notation = CASTLE_SAN self.connection.bm.sendMove(toAN(board2, move, castleNotation=castle_notation)) # wait for fics to send back our move we made item = yield from self.move_queue.get() item = yield from self.move_queue.get() try: if item == "end": raise GameEnded elif item == "del": raise PlayerIsDead gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms = item self.gamemodel.onBoardUpdate(gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms) if self.turn_interrupt: self.turn_interrupt = False raise TurnInterrupt if ply < board1.ply: # This should only happen in an observed game board1 = self.gamemodel.getBoardAtPly(max(ply - 1, 0)) log.debug("ICPlayer.makemove: id(self)=%d self=%s from queue got: ply=%d sanmove=%s" % ( id(self), self, ply, lastmove)) try: move = parseSAN(board1, lastmove) log.debug("ICPlayer.makemove: id(self)=%d self=%s parsed move=%s" % ( id(self), self, move)) except ParsingError: raise return move finally: log.debug("ICPlayer.makemove: id(self)=%d self=%s returning move=%s" % (id(self), self, move))
def onBoardUpdate(self, bm, gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms): log.debug(("ICGameModel.onBoardUpdate: id=%s self.ply=%s self.players=%s gameno=%s " + \ "wname=%s bname=%s ply=%s curcol=%s lastmove=%s fen=%s wms=%s bms=%s") % \ (str(id(self)), str(self.ply), repr(self.players), str(gameno), str(wname), str(bname), \ str(ply), str(curcol), str(lastmove), str(fen), str(wms), str(bms))) if gameno != self.ficsgame.gameno or len(self.players) < 2 or wname != self.players[0].ichandle \ or bname != self.players[1].ichandle: return log.debug("ICGameModel.onBoardUpdate: id=%d, self.players=%s: updating time and/or ply" % \ (id(self), str(self.players))) if self.timed: log.debug("ICGameModel.onBoardUpdate: id=%d self.players=%s: updating timemodel" % \ (id(self), str(self.players))) # If game end coming from helper connection before last move made # we have to tap() ourselves if self.status in (DRAW, WHITEWON, BLACKWON): if self.timemodel.ply < ply: self.timemodel.paused = False self.timemodel.tap() self.timemodel.paused = True self.timemodel.updatePlayer(WHITE, wms / 1000.) self.timemodel.updatePlayer(BLACK, bms / 1000.) if ply < self.ply: log.debug("ICGameModel.onBoardUpdate: id=%d self.players=%s self.ply=%d ply=%d: TAKEBACK" % \ (id(self), str(self.players), self.ply, ply)) offers = self.offers.keys() for offer in offers: if offer.type == TAKEBACK_OFFER: # There can only be 1 outstanding takeback offer for both players on FICS, # (a counter-offer by the offeree for a takeback for a different number of # moves replaces the initial offer) so we can safely remove all of them del self.offers[offer] # In some cases (like lost on time) the last move is resent if self.reason != WON_CALLFLAG: self.undoMoves(self.ply - ply)
def makeMove(self, board1, move, board2): log.debug( "ICPlayer.makemove: id(self)=%d self=%s move=%s board1=%s board2=%s" % (id(self), self, move, board1, board2)) if board2 and not self.gamemodel.isObservationGame(): # TODO: Will this work if we just always use CASTLE_SAN? castle_notation = CASTLE_KK if board2.variant == FISCHERRANDOMCHESS: castle_notation = CASTLE_SAN self.connection.bm.sendMove( toAN(board2, move, castleNotation=castle_notation)) item = self.queue.get(block=True) try: if item == "del": raise PlayerIsDead if item == "int": raise TurnInterrupt ply, sanmove = item if ply < board1.ply: # This should only happen in an observed game board1 = self.gamemodel.getBoardAtPly(max(ply - 1, 0)) log.debug( "ICPlayer.makemove: id(self)=%d self=%s from queue got: ply=%d sanmove=%s" % (id(self), self, ply, sanmove)) try: move = parseSAN(board1, sanmove) log.debug( "ICPlayer.makemove: id(self)=%d self=%s parsed move=%s" % (id(self), self, move)) except ParsingError: raise return move finally: log.debug( "ICPlayer.makemove: id(self)=%d self=%s returning move=%s" % (id(self), self, move)) self.okqueue.put("ok")
def on_icc_my_game_result(self, data): log.debug("DG_MY_GAME_RESULT %s" % data) # gamenumber become-examined game_result_code score_string2 description-string ECO # 1242 1 Res 1-0 {Black resigns} {D89} parts = data.split(" ", 4) gameno, ex, result_code, result, rest = parts gameno = int(gameno) comment, rest = rest[2:].split("}", 1) try: game = self.connection.games.get_game_by_gameno(gameno) except KeyError: return wname = game.wplayer.name bname = game.bplayer.name result, reason = parse_reason(reprResult.index(result), comment, wname=wname) try: wplayer = self.connection.players.get(wname) wplayer.restore_previous_status() # no status update will be sent by # FICS if the player doesn't become available, so we restore # previous status first (not necessarily true, but the best guess) except KeyError: log.debug("%s not in self.connections.players - creating" % wname) wplayer = FICSPlayer(wname) try: bplayer = self.connection.players.get(bname) bplayer.restore_previous_status() except KeyError: log.debug("%s not in self.connections.players - creating" % bname) bplayer = FICSPlayer(bname) game = FICSGame(wplayer, bplayer, gameno=int(gameno), result=result, reason=reason) if wplayer.game is not None: game.rated = wplayer.game.rated game = self.connection.games.get(game, emit=False) self.connection.games.game_ended(game) # Do this last to give anybody connected to the game's signals a chance # to disconnect from them first wplayer.game = None bplayer.game = None
def parse(self): line = yield from self.lines.popleft() if not line.line: return # TODO: necessary? # print("line.line:", line.line) if self.lines.datagram_mode and line.code is not None: if line.code_type == DG: callback = self.replay_dg_dict[line.code] callback(line.line) log.debug( line.line, extra={"task": (self.telnet.name, callback.__name__)}) return elif line.code_type == CN and line.code in self.replay_cn_dict: callback = self.replay_cn_dict[line.code] callback(line.line) log.debug( line.line, extra={"task": (self.telnet.name, callback.__name__)}) return predictions = (self.reply_cmd_dict[line.code] if line.code is not None and line.code in self.reply_cmd_dict else self.predictions) for pred in list(predictions): answer = yield from self.test_prediction(pred, line) # print(answer, " parse_line: trying prediction %s for line '%s'" % (pred.name, line.line[:80])) if answer in (RETURN_MATCH, RETURN_MATCH_END): log.debug( "\n".join(pred.matches), extra={"task": (self.telnet.name, pred.name)}, ) break else: # print(" NOT MATCHED:", line.line[:80]) if line.code != BLKCMD_PASSWORD: log.debug(line.line, extra={"task": (self.telnet.name, "nonmatched")})
def terminate(self): log.debug("GameModel.terminate: %s" % self) if self.status != KILLED: for player in self.players: player.end(self.status, self.reason) for spectator in self.spectators.values(): spectator.end(self.status, self.reason) if self.timed: log.debug("GameModel.terminate: -> timemodel.end()") self.timemodel.end() log.debug("GameModel.terminate: <- timemodel.end() %s" % repr(self.timemodel)) self.emit("game_terminated")
def playerUndoMoves(self, movecount, gamemodel): log.debug("ICPlayer.playerUndoMoves: id(self)=%d self=%s, undoing movecount=%d" % ( id(self), self, movecount)) # If current player has changed so that it is no longer us to move, # We raise TurnInterrupt in order to let GameModel continue the game if movecount % 2 == 1 and gamemodel.curplayer != self: log.debug("ICPlayer.playerUndoMoves: set self.turn_interrupt = True %s" % self.name) if self.connection.ICC: self.move_queue.put_nowait("stm") else: self.turn_interrupt = True if movecount % 2 == 0 and gamemodel.curplayer == self: log.debug("ICPlayer.playerUndoMoves: set self.pass_interrupt = True %s" % self.name) if self.connection.ICC: self.move_queue.put_nowait("pass") else: self.pass_interrupt = True
def __boardUpdate(self, bm, gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms): log.debug("ICPlayer.__boardUpdate: id(self)=%d self=%s %s %s %s %d %d %s %s %d %d" % ( id(self), self, gameno, wname, bname, ply, curcol, lastmove, fen, wms, bms)) if gameno == self.gameno and len(self.gamemodel.players) >= 2 and self.current: # LectureBot allways uses gameno 1 for many games in one lecture # and wname == self.gamemodel.players[0].ichandle \ # and bname == self.gamemodel.players[1].ichandle \ log.debug("ICPlayer.__boardUpdate: id=%d self=%s gameno=%s: this is my move" % ( id(self), self, gameno)) # In some cases (like lost on time) the last move is resent if ply <= self.gamemodel.ply: return if 1 - curcol == self.color and ply == self.gamemodel.ply + 1 and lastmove is not None: log.debug("ICPlayer.__boardUpdate: id=%d self=%s ply=%d: \ putting move=%s in queue" % (id(self), self, ply, lastmove)) self.queue.put_nowait((ply, lastmove))
def makeMove (self, board1, move, board2): log.debug("Human.makeMove: move=%s, board1=%s board2=%s" % \ (move, board1, board2)) if self.board.view.premovePiece and self.board.view.premove0 and self.board.view.premove1 and \ self.color == self.board.view.premovePiece.color: if validate(board1, Move(self.board.view.premove0, self.board.view.premove1, board1, promotion=self.board.view.premovePromotion)): log.debug("Human.makeMove: Setting move to premove %s %s" % \ (self.board.view.premove0, self.board.view.premove1)) self.board.emit_move_signal(self.board.view.premove0, self.board.view.premove1, promotion=self.board.view.premovePromotion) # reset premove self.board.view.setPremove(None, None, None, None) self.gmwidg.setLocked(False) item = self.queue.get(block=True) self.gmwidg.setLocked(True) if item == "del": raise PlayerIsDead("Killed by foreign forces") if item == "int": log.debug("Human.makeMove: %s: raise TurnInterrupt" % self) raise TurnInterrupt return item
def __boardUpdate (self, bm, gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms): log.debug("ICPlayer.__boardUpdate: id(self)=%d self=%s %s %s %s %d %d %s %s %d %d\n" % \ (id(self), self, gameno, wname, bname, ply, curcol, lastmove, fen, wms, bms)) if gameno == self.gameno and len(self.gamemodel.players) >= 2 \ and wname == self.gamemodel.players[0].getICHandle() \ and bname == self.gamemodel.players[1].getICHandle(): log.debug("ICPlayer.__boardUpdate: id=%d self=%s gameno=%s: this is my move\n" % \ (id(self), self, gameno)) # In some cases (like lost on time) the last move is resent if ply <= self.gamemodel.ply: return if 1-curcol == self.color: log.debug("ICPlayer.__boardUpdate: id=%d self=%s ply=%d: putting move=%s in queue\n" % \ (id(self), self, ply, lastmove)) self.queue.put((ply, lastmove)) # Ensure the fics thread doesn't continue parsing, before the # game/player thread has recieved the move. # Specifically this ensures that we aren't killed due to end of # game before our last move is recieved self.okqueue.get(block=True)
traceback.print_exc(file=stringio) error = stringio.getvalue() log.error( "GameModel.run: A Player died: player=%s error=%s\n%s" % (curPlayer, error, e)) if curColor == WHITE: self.kill(WHITE_ENGINE_DIED) else: self.kill(BLACK_ENGINE_DIED) break except TurnInterrupt: log.debug("GameModel.run: id=%s, players=%s, self.ply=%s: TurnInterrupt\n" % \ (id(self), str(self.players), self.ply)) continue log.debug("GameModel.run: id=%s, players=%s, self.ply=%s: acquiring self.applyingMoveLock\n" % \ (id(self), str(self.players), self.ply)) self.applyingMoveLock.acquire() try: log.debug("GameModel.run: id=%s, players=%s, self.ply=%s: applying move=%s\n" % \ (id(self), str(self.players), self.ply, str(move))) self.needsSave = True newBoard = self.boards[-1].move(move) self.boards.append(newBoard) self.moves.append(move) if self.timemodel: self.timemodel.tap() self.checkStatus() self.emit("game_changed")
def onBoardUpdate(self, bm, gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms): log.debug(("ICGameModel.onBoardUpdate: id=%s self.ply=%s self.players=%s gameno=%s " + \ "wname=%s bname=%s ply=%s curcol=%s lastmove=%s fen=%s wms=%s bms=%s") % \ (str(id(self)), str(self.ply), repr(self.players), str(gameno), str(wname), str(bname), \ str(ply), str(curcol), str(lastmove), str(fen), str(wms), str(bms))) if gameno != self.ficsgame.gameno or len(self.players) < 2: # LectureBot allways uses gameno 1 for many games in one lecture # or wname != self.players[0].ichandle or bname != self.players[1].ichandle: return log.debug("ICGameModel.onBoardUpdate: id=%d, self.players=%s: updating time and/or ply" % \ (id(self), str(self.players))) if self.timed: log.debug("ICGameModel.onBoardUpdate: id=%d self.players=%s: updating timemodel" % \ (id(self), str(self.players))) # If game end coming from helper connection before last move made # we have to tap() ourselves if self.status in (DRAW, WHITEWON, BLACKWON): if self.timemodel.ply < ply: self.timemodel.paused = False self.timemodel.tap() self.timemodel.paused = True self.timemodel.updatePlayer(WHITE, wms / 1000.) self.timemodel.updatePlayer(BLACK, bms / 1000.) if lastmove is None: if bname != self.tags["Black"]: self.tags["Black"] = self.players[ BLACK].name = self.ficsplayers[BLACK].name = bname self.emit("players_changed") if wname != self.tags["White"]: self.tags["White"] = self.players[ WHITE].name = self.ficsplayers[WHITE].name = wname self.emit("players_changed") if self.boards[-1].asFen() != fen: self.status = RUNNING self.loadAndStart(StringIO(fen), fen_loader, 0, -1, first_time=False) self.emit("game_started") curPlayer = self.players[self.curColor] curPlayer.resetPosition() elif ply < self.ply: log.debug("ICGameModel.onBoardUpdate: id=%d self.players=%s \ self.ply=%d ply=%d: TAKEBACK" % \ (id(self), str(self.players), self.ply, ply)) for offer in list(self.offers.keys()): if offer.type == TAKEBACK_OFFER: # There can only be 1 outstanding takeback offer for both players on FICS, # (a counter-offer by the offeree for a takeback for a different number of # moves replaces the initial offer) so we can safely remove all of them del self.offers[offer] # In some cases (like lost on time) the last move is resent # or we just observing an examined game if self.reason != WON_CALLFLAG: if len(self.moves) >= self.ply - ply: self.undoMoves(self.ply - ply) else: self.status = RUNNING self.loadAndStart(StringIO(fen), fen_loader, 0, -1, first_time=False) self.emit("game_started") curPlayer = self.players[self.curColor] curPlayer.resetPosition() elif ply > self.ply + 1: self.status = RUNNING self.loadAndStart(StringIO(fen), fen_loader, 0, -1, first_time=False) self.emit("game_started") curPlayer = self.players[self.curColor] curPlayer.resetPosition()
def onGameEnded(self, bm, ficsgame): if ficsgame == self.ficsgame and len(self.players) >= 2: log.debug( "ICGameModel.onGameEnded: self.players=%s ficsgame=%s" % \ (repr(self.players), repr(ficsgame))) self.end(ficsgame.result, ficsgame.reason)
def game_unended(gamemodel, gmwidg): log.debug("gamenanny.game_unended: %s" % gamemodel.boards[-1]) gmwidg.clearMessages() _set_statusbar(gmwidg, "") return False
def on_game_close_clicked(self, button): log.debug("gamewidget.on_game_close_clicked %s" % button) self.emit("game_close_clicked")
def offerReceived(self, player, offer): log.debug("GameModel.offerReceived: offerer=%s %s" % (repr(player), offer)) if player == self.players[WHITE]: opPlayer = self.players[BLACK] elif player == self.players[BLACK]: opPlayer = self.players[WHITE] else: # Player comments echoed to opponent if the player started a conversation # with you prior to observing a game the player is in #1113 return if offer.type == HURRY_ACTION: opPlayer.hurry() elif offer.type == CHAT_ACTION: # print("GameModel.offerreceived(player, offer)", player.name, offer.param) opPlayer.putMessage(offer.param) elif offer.type == RESIGNATION: if player == self.players[WHITE]: self.end(BLACKWON, WON_RESIGN) else: self.end(WHITEWON, WON_RESIGN) elif offer.type == FLAG_CALL: assert self.timed if self.timemodel.getPlayerTime(1 - player.color) <= 0: if self.timemodel.getPlayerTime(player.color) <= 0: self.end(DRAW, DRAW_CALLFLAG) elif not playerHasMatingMaterial(self.boards[-1], player.color): if player.color == WHITE: self.end(DRAW, DRAW_WHITEINSUFFICIENTANDBLACKTIME) else: self.end(DRAW, DRAW_BLACKINSUFFICIENTANDWHITETIME) else: if player == self.players[WHITE]: self.end(WHITEWON, WON_CALLFLAG) else: self.end(BLACKWON, WON_CALLFLAG) else: player.offerError(offer, ACTION_ERROR_NOT_OUT_OF_TIME) elif offer.type == DRAW_OFFER and isClaimableDraw(self.boards[-1]): reason = getStatus(self.boards[-1])[1] self.end(DRAW, reason) elif offer.type == TAKEBACK_OFFER and offer.param < self.lowply: player.offerError(offer, ACTION_ERROR_TOO_LARGE_UNDO) elif offer.type in OFFERS: if offer not in self.offers: log.debug("GameModel.offerReceived: doing %s.offer(%s)" % (repr(opPlayer), offer)) self.offers[offer] = player opPlayer.offer(offer) # If we updated an older offer, we want to delete the old one keys = self.offers.keys() for offer_ in keys: if offer.type == offer_.type and offer != offer_: del self.offers[offer_]
def update_board(self, gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms): log.debug(( "ICGameModel.update_board: id=%s self.ply=%s self.players=%s gameno=%s " + "wname=%s bname=%s ply=%s curcol=%s lastmove=%s fen=%s wms=%s bms=%s" ) % (str(id(self)), str(self.ply), repr( self.players), str(gameno), str(wname), str(bname), str(ply), str(curcol), str(lastmove), str(fen), str(wms), str(bms))) if gameno != self.ficsgame.gameno or len( self.players) < 2 or self.disconnected: return if self.timed: log.debug( "ICGameModel.update_board: id=%d self.players=%s: updating timemodel" % (id(self), str(self.players))) # If game end coming from helper connection before last move made # we have to tap() ourselves if self.status in (DRAW, WHITEWON, BLACKWON): if self.timemodel.ply < ply: self.timemodel.paused = False self.timemodel.tap() self.timemodel.paused = True self.timemodel.updatePlayer(WHITE, wms / 1000.) self.timemodel.updatePlayer(BLACK, bms / 1000.) if ply < self.ply: log.debug("ICGameModel.update_board: id=%d self.players=%s \ self.ply=%d ply=%d: TAKEBACK" % (id(self), str(self.players), self.ply, ply)) for offer in list(self.offers.keys()): if offer.type == TAKEBACK_OFFER: # There can only be 1 outstanding takeback offer for both players on FICS, # (a counter-offer by the offeree for a takeback for a different number of # moves replaces the initial offer) so we can safely remove all of them del self.offers[offer] if len(self.moves) >= self.ply - ply: self.undoMoves(self.ply - ply) else: self.status = RUNNING self.loadAndStart(StringIO(fen), fen_loader, 0, -1, first_time=False) self.emit("game_started") curPlayer = self.players[self.curColor] curPlayer.resetPosition() elif ply > self.ply + 1: log.debug("ICGameModel.update_board: id=%d self.players=%s \ self.ply=%d ply=%d: FORWARD JUMP" % (id(self), str(self.players), self.ply, ply)) self.status = RUNNING self.loadAndStart(StringIO(fen), fen_loader, 0, -1, first_time=False) self.emit("game_started") curPlayer = self.players[self.curColor] curPlayer.resetPosition()
def init_layout(self): perspective_widget = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) perspective_manager.set_perspective_widget("fics", perspective_widget) perspective_manager.set_perspective_menuitems("fics", self.menuitems) self.infobar = InfoBarNotebook("fics_lounge_infobar") self.infobar.hide() perspective_widget.pack_start(self.infobar, False, False, 0) self.dock = PyDockTop("fics", self) align = Gtk.Alignment() align.show() align.add(self.dock) self.dock.show() perspective_widget.pack_start(align, True, True, 0) self.notebooks = {"ficshome": new_notebook()} self.main_notebook = self.notebooks["ficshome"] for panel in self.sidePanels: self.notebooks[panel.__name__] = new_notebook(panel.__name__) self.docks["ficshome"] = (Gtk.Label(label="ficshome"), self.notebooks["ficshome"], None) for panel in self.sidePanels: self.docks[panel.__name__][1] = self.notebooks[panel.__name__] self.load_from_xml() # Default layout of side panels if not os.path.isfile(self.dockLocation): leaf = self.dock.dock(self.docks["ficshome"][1], CENTER, self.docks["ficshome"][0], "ficshome") leaf.setDockable(False) console_leaf = leaf.dock(self.docks["ConsolePanel"][1], SOUTH, self.docks["ConsolePanel"][0], "ConsolePanel") console_leaf.dock(self.docks["NewsPanel"][1], CENTER, self.docks["NewsPanel"][0], "NewsPanel") seek_leaf = leaf.dock(self.docks["SeekListPanel"][1], WEST, self.docks["SeekListPanel"][0], "SeekListPanel") seek_leaf.dock(self.docks["SeekGraphPanel"][1], CENTER, self.docks["SeekGraphPanel"][0], "SeekGraphPanel") seek_leaf.dock(self.docks["PlayerListPanel"][1], CENTER, self.docks["PlayerListPanel"][0], "PlayerListPanel") seek_leaf.dock(self.docks["GameListPanel"][1], CENTER, self.docks["GameListPanel"][0], "GameListPanel") seek_leaf.dock(self.docks["ArchiveListPanel"][1], CENTER, self.docks["ArchiveListPanel"][0], "ArchiveListPanel") leaf = leaf.dock(self.docks["ChatPanel"][1], SOUTH, self.docks["ChatPanel"][0], "ChatPanel") # leaf.dock(self.docks["LecturesPanel"][1], CENTER, self.docks["LecturesPanel"][0], "LecturesPanel") def unrealize(dock): dock.saveToXML(self.dockLocation) dock._del() self.dock.connect("unrealize", unrealize) self.dock.show_all() perspective_widget.show_all() log.debug("FICS.__init__: finished")
def players_changed(self, model): log.debug("annotationPanel.players_changed: starting") self.update log.debug("annotationPanel.players_changed: returning")
def generalStart(self, gamemodel, player0tup, player1tup, loaddata=None): """ The player tuples are: (The type af player in a System.const value, A callable creating the player, A list of arguments for the callable, A preliminary name for the player) If loaddata is specified, it should be a tuple of: (A text uri or fileobj, A Savers.something module with a load function capable of loading it, An int of the game in file you want to load, The position from where to start the game) """ log.debug("Games.generalStart: %s\n %s\n %s" % (gamemodel, player0tup, player1tup)) gmwidg = gamewidget.GameWidget(gamemodel, self) self.gamewidgets.add(gmwidg) self.gmwidg_cids[gmwidg] = gmwidg.connect("game_close_clicked", self.closeGame) # worker.publish((gmwidg,gamemodel)) self.attachGameWidget(gmwidg) game_nanny.nurseGame(gmwidg, gamemodel) log.debug("Games.generalStart: -> emit gmwidg_created: %s" % (gmwidg)) self.emit("gmwidg_created", gmwidg) log.debug("Games.generalStart: <- emit gmwidg_created: %s" % (gmwidg)) # Initing players def set_name(none, player, key, alt): player.setName(conf.get(key, alt)) players = [] for i, playertup in enumerate((player0tup, player1tup)): type, func, args, prename = playertup if type != LOCAL: if type == ARTIFICIAL: player = yield from func(*args) else: player = func(*args) players.append(player) # if type == ARTIFICIAL: # def readyformoves (player, color): # gmwidg.setTabText(gmwidg.display_text)) # players[i].connect("readyForMoves", readyformoves, i) else: # Until PyChess has a proper profiles system, as discussed on the # issue tracker, we need to give human players special treatment player = func(gmwidg, *args) players.append(player) if player0tup[0] == ARTIFICIAL and player1tup[0] == ARTIFICIAL: def emit_action(board, action, param, gmwidg): if gmwidg.isInFront(): gamemodel.curplayer.emit("offer", Offer(action, param=param)) self.board_cids[gmwidg.board] = gmwidg.board.connect("action", emit_action, gmwidg) log.debug("Games.generalStart: -> gamemodel.setPlayers(): %s" % (gamemodel)) gamemodel.setPlayers(players) log.debug("Games.generalStart: <- gamemodel.setPlayers(): %s" % (gamemodel)) # Starting if loaddata: try: uri, loader, gameno, position = loaddata gamemodel.loadAndStart(uri, loader, gameno, position) if position != gamemodel.ply: gmwidg.board.view.shown = position except LoadingError as e: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.OK) d.set_markup(_("<big><b>Error loading game</big></b>")) d.format_secondary_text(", ".join(str(a) for a in e.args)) d.show() d.hide() else: if gamemodel.variant.need_initial_board: for player in gamemodel.players: player.setOptionInitialBoard(gamemodel) log.debug("Games..generalStart: -> gamemodel.start(): %s" % (gamemodel)) gamemodel.start() log.debug("Games.generalStart: <- gamemodel.start(): %s" % (gamemodel)) log.debug("Games.generalStart: returning gmwidg=%s\n gamemodel=%s" % (gmwidg, gamemodel))
def closeGame(self, gmwidg): log.debug("Games.closeGame") response = None if not gmwidg.gamemodel.isChanged(): response = Gtk.ResponseType.OK else: markup = "<b><big>" + _("Save the current game before you close it?") + "</big></b>" if conf.get("autoSave", False): x = self.saveGamePGN(gmwidg.gamemodel) if x: response = Gtk.ResponseType.OK else: markup = "<b><big>" + _("Unable to save to configured file. \ Save the current game before you close it?") + "</big></b>" if response is None: d = Gtk.MessageDialog(mainwindow(), type=Gtk.MessageType.WARNING) d.add_button(_("Close _without Saving"), Gtk.ResponseType.OK) d.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL) if gmwidg.gamemodel.uri: d.add_button(Gtk.STOCK_SAVE, Gtk.ResponseType.YES) else: d.add_button(Gtk.STOCK_SAVE_AS, Gtk.ResponseType.YES) gmwidg.bringToFront() d.set_markup(markup) d.format_secondary_text(_( "It is not possible later to continue the game,\nif you don't save it.")) response = d.run() d.destroy() if response == Gtk.ResponseType.YES: # Test if cancel was pressed in the save-file-dialog if self.saveGame(gmwidg.gamemodel) != Gtk.ResponseType.ACCEPT: response = Gtk.ResponseType.CANCEL if response not in (Gtk.ResponseType.DELETE_EVENT, Gtk.ResponseType.CANCEL): if gmwidg.gamemodel.status in UNFINISHED_STATES: gmwidg.gamemodel.end(ABORTED, ABORTED_AGREEMENT) gmwidg.disconnect(self.gmwidg_cids[gmwidg]) del self.gmwidg_cids[gmwidg] for cid in self.notify_cids[gmwidg]: conf.notify_remove(cid) del self.notify_cids[gmwidg] if gmwidg.board in self.board_cids: gmwidg.board.disconnect(self.board_cids[gmwidg.board]) del self.board_cids[gmwidg.board] self.delGameWidget(gmwidg) self.gamewidgets.remove(gmwidg) gmwidg.gamemodel.terminate() if len(self.gamewidgets) == 0: for widget in MENU_ITEMS: gamewidget.getWidgets()[widget].set_property('sensitive', False) return response
def closeAllGames(self, gamewidgets): log.debug("Games.closeAllGames") response = None changedPairs = [(gmwidg, gmwidg.gamemodel) for gmwidg in gamewidgets if gmwidg.gamemodel.isChanged()] if len(changedPairs) == 0: response = Gtk.ResponseType.OK elif len(changedPairs) == 1: response = self.closeGame(changedPairs[0][0]) else: markup = "<big><b>" + ngettext("There is %d game with unsaved moves.", "There are %d games with unsaved moves.", len(changedPairs)) % len(changedPairs) + " " + \ _("Save moves before closing?") + "</b></big>" for gmwidg, game in changedPairs: if not gmwidg.gamemodel.isChanged(): response = Gtk.ResponseType.OK else: if conf.get("autoSave", False): x = self.saveGamePGN(game) if x: response = Gtk.ResponseType.OK else: response = None markup = "<b><big>" + _("Unable to save to configured file. \ Save the games before closing?") + "</big></b>" break if response is None: widgets = GladeWidgets("saveGamesDialog.glade") dialog = widgets["saveGamesDialog"] heading = widgets["saveGamesDialogHeading"] saveLabel = widgets["saveGamesDialogSaveLabel"] treeview = widgets["saveGamesDialogTreeview"] heading.set_markup(markup) liststore = Gtk.ListStore(bool, str) treeview.set_model(liststore) renderer = Gtk.CellRendererToggle() renderer.props.activatable = True treeview.append_column(Gtk.TreeViewColumn("", renderer, active=0)) treeview.append_column(Gtk.TreeViewColumn("", Gtk.CellRendererText(), text=1)) for gmwidg, game in changedPairs: liststore.append((True, "%s %s %s" % (game.players[0], _("vs."), game.players[1]))) def callback(cell, path): if path: liststore[path][0] = not liststore[path][0] saves = len(tuple(row for row in liststore if row[0])) saveLabel.set_text(ngettext( "_Save %d document", "_Save %d documents", saves) % saves) saveLabel.set_use_underline(True) renderer.connect("toggled", callback) callback(None, None) while True: response = dialog.run() if response == Gtk.ResponseType.YES: for i in range(len(liststore) - 1, -1, -1): checked, name = liststore[i] if checked: cgmwidg, cgame = changedPairs[i] if self.saveGame(cgame) == Gtk.ResponseType.ACCEPT: liststore.remove(liststore.get_iter((i, ))) del changedPairs[i] if cgame.status in UNFINISHED_STATES: cgame.end(ABORTED, ABORTED_AGREEMENT) cgame.terminate() self.delGameWidget(cgmwidg) else: break else: break else: break dialog.destroy() if response not in (Gtk.ResponseType.DELETE_EVENT, Gtk.ResponseType.CANCEL): pairs = [(gmwidg, gmwidg.gamemodel) for gmwidg in gamewidgets] for gmwidg, game in pairs: if game.status in UNFINISHED_STATES: game.end(ABORTED, ABORTED_AGREEMENT) game.terminate() if gmwidg.notebookKey in self.key2gmwidg: self.delGameWidget(gmwidg) return response
def on_window_key_press(self, window, event): log.debug('on_window_key_press: %s %s' % (window.get_title(), event)) # debug leaking memory if Gdk.keyval_name(event.keyval) == "F12": from pychess.System.debug import print_obj_referrers, print_muppy_sumary if event.get_state() & Gdk.ModifierType.SHIFT_MASK: print_muppy_sumary() else: print_obj_referrers() # Tabbing related shortcuts persp = perspective_manager.get_perspective("games") if not persp.getheadbook(): pagecount = 0 else: pagecount = persp.getheadbook().get_n_pages() if pagecount > 1: if event.get_state() & Gdk.ModifierType.CONTROL_MASK: page_num = persp.getheadbook().get_current_page() # Move selected if event.get_state() & Gdk.ModifierType.SHIFT_MASK: child = persp.getheadbook().get_nth_page(page_num) if event.keyval == Gdk.KEY_Page_Up: persp.getheadbook().reorder_child( child, (page_num - 1) % pagecount) return True elif event.keyval == Gdk.KEY_Page_Down: persp.getheadbook().reorder_child( child, (page_num + 1) % pagecount) return True # Change selected else: if event.keyval == Gdk.KEY_Page_Up: persp.getheadbook().set_current_page( (page_num - 1) % pagecount) return True elif event.keyval == Gdk.KEY_Page_Down: persp.getheadbook().set_current_page( (page_num + 1) % pagecount) return True gmwidg = persp.cur_gmwidg() if gmwidg is not None: # Let default handler work if typing inside entry widgets current_focused_widget = gamewidget.getWidgets( )["main_window"].get_focus() if current_focused_widget is not None and isinstance( current_focused_widget, Gtk.Entry): return False # Prevent moving in game while lesson not finished if gmwidg.gamemodel.lesson_game: return # Navigate on boardview with arrow keys if event.keyval in leftkeys: if event.get_state() & Gdk.ModifierType.CONTROL_MASK: gmwidg.board.view.backToMainLine() return True else: gmwidg.board.view.showPrev() return True elif event.keyval in rightkeys: gmwidg.board.view.showNext() return True elif event.keyval in upkeys: gmwidg.board.view.showPrev(step=2) return True elif event.keyval in downkeys: gmwidg.board.view.showNext(step=2) return True elif event.keyval in homekeys: gmwidg.board.view.showFirst() return True elif event.keyval in endkeys: gmwidg.board.view.showLast() return True if (not event.get_state() & Gdk.ModifierType.CONTROL_MASK) and \ (not event.get_state() & Gdk.ModifierType.MOD1_MASK) and \ (event.keyval != Gdk.KEY_Escape) and \ (event.keyval not in functionkeys): # Enter moves with keyboard board_control = gmwidg.board keyname = Gdk.keyval_name(event.keyval) board_control.key_pressed(keyname) print(board_control.keybuffer) return True return False
def offerRecieved(self, player, offer): log.debug("GameModel.offerRecieved: offerer=%s %s\n" % (repr(player), offer)) if player == self.players[WHITE]: opPlayer = self.players[BLACK] else: opPlayer = self.players[WHITE] if self.status not in UNFINISHED_STATES and offer.type in INGAME_ACTIONS: player.offerError(offer, ACTION_ERROR_REQUIRES_UNFINISHED_GAME) elif offer.type == RESUME_OFFER and self.status in (DRAW, WHITEWON,BLACKWON) and \ self.reason in UNRESUMEABLE_REASONS: player.offerError(offer, ACTION_ERROR_UNRESUMEABLE_POSITION) elif offer.type == RESUME_OFFER and self.status != PAUSED: player.offerError(offer, ACTION_ERROR_RESUME_REQUIRES_PAUSED) elif offer.type == HURRY_ACTION: opPlayer.hurry() elif offer.type == CHAT_ACTION: opPlayer.putMessage(offer.param) elif offer.type == RESIGNATION: if player == self.players[WHITE]: self.end(BLACKWON, WON_RESIGN) else: self.end(WHITEWON, WON_RESIGN) elif offer.type == FLAG_CALL: if not self.timemodel: player.offerError(offer, ACTION_ERROR_NO_CLOCK) return if player == self.players[WHITE]: opcolor = BLACK else: opcolor = WHITE if self.timemodel.getPlayerTime(opcolor) <= 0: if self.timemodel.getPlayerTime(1 - opcolor) <= 0: self.end(DRAW, DRAW_CALLFLAG) elif not playerHasMatingMaterial(self.boards[-1], (1 - opcolor)): if opcolor == WHITE: self.end(DRAW, DRAW_BLACKINSUFFICIENTANDWHITETIME) else: self.end(DRAW, DRAW_WHITEINSUFFICIENTANDBLACKTIME) else: if player == self.players[WHITE]: self.end(WHITEWON, WON_CALLFLAG) else: self.end(BLACKWON, WON_CALLFLAG) else: player.offerError(offer, ACTION_ERROR_NOT_OUT_OF_TIME) elif offer.type == DRAW_OFFER and isClaimableDraw(self.boards[-1]): reason = getStatus(self.boards[-1])[1] self.end(DRAW, reason) elif offer.type == TAKEBACK_OFFER and offer.param < self.lowply: player.offerError(offer, ACTION_ERROR_TOO_LARGE_UNDO) elif offer.type == TAKEBACK_OFFER and self.status != RUNNING and \ (self.status not in UNDOABLE_STATES or self.reason not in UNDOABLE_REASONS): player.offerError(offer, ACTION_ERROR_GAME_ENDED) elif offer.type in OFFERS: if offer not in self.offers: log.debug("GameModel.offerRecieved: doing %s.offer(%s)\n" % \ (repr(opPlayer), offer)) self.offers[offer] = player opPlayer.offer(offer) # If we updated an older offer, we want to delete the old one for offer_ in self.offers.keys(): if offer.type == offer_.type and offer != offer_: del self.offers[offer_]
def __init__(self): log.debug("FICS.__init__: starting") GObject.GObject.__init__(self) Perspective.__init__(self, "fics", _("ICS")) self.dockLocation = addUserConfigPrefix("pydock-fics.xml") self.first_run = True
def run(self): log.debug("GameModel.run: Starting. self=%s" % self) # Avoid racecondition when self.start is called while we are in # self.end if self.status != WAITING_TO_START: return if not self.isLocalGame(): self.timemodel.handle_gain = False self.status = RUNNING for player in self.players + list(self.spectators.values()): player.start() log.debug("GameModel.run: emitting 'game_started' self=%s" % self) self.emit("game_started") # Let GameModel end() itself on games started with loadAndStart() self.checkStatus() self.curColor = self.boards[-1].color while self.status in (PAUSED, RUNNING, DRAW, WHITEWON, BLACKWON): curPlayer = self.players[self.curColor] if self.timed: log.debug("GameModel.run: id=%s, players=%s, self.ply=%s: updating %s's time" % ( id(self), str(self.players), str(self.ply), str(curPlayer))) curPlayer.updateTime( self.timemodel.getPlayerTime(self.curColor), self.timemodel.getPlayerTime(1 - self.curColor)) try: log.debug("GameModel.run: id=%s, players=%s, self.ply=%s: calling %s.makeMove()" % ( id(self), str(self.players), self.ply, str(curPlayer))) if self.ply > self.lowply: move = curPlayer.makeMove(self.boards[-1], self.moves[-1], self.boards[-2]) else: move = curPlayer.makeMove(self.boards[-1], None, None) log.debug("GameModel.run: id=%s, players=%s, self.ply=%s: got move=%s from %s" % ( id(self), str(self.players), self.ply, move, str(curPlayer))) except PlayerIsDead as e: if self.status in (WAITING_TO_START, PAUSED, RUNNING): stringio = StringIO() traceback.print_exc(file=stringio) error = stringio.getvalue() log.error( "GameModel.run: A Player died: player=%s error=%s\n%s" % (curPlayer, error, e)) if self.curColor == WHITE: self.kill(WHITE_ENGINE_DIED) else: self.kill(BLACK_ENGINE_DIED) break except InvalidMove as e: if self.curColor == WHITE: self.end(BLACKWON, WON_ADJUDICATION) else: self.end(WHITEWON, WON_ADJUDICATION) break except TurnInterrupt: log.debug("GameModel.run: id=%s, players=%s, self.ply=%s: TurnInterrupt" % ( id(self), str(self.players), self.ply)) self.curColor = self.boards[-1].color continue log.debug("GameModel.run: id=%s, players=%s, self.ply=%s: acquiring self.applyingMoveLock" % ( id(self), str(self.players), self.ply)) assert isinstance(move, Move), "%s" % repr(move) self.applyingMoveLock.acquire() try: log.debug("GameModel.run: id=%s, players=%s, self.ply=%s: applying move=%s" % ( id(self), str(self.players), self.ply, str(move))) self.needsSave = True newBoard = self.boards[-1].move(move) newBoard.board.prev = self.boards[-1].board # Variation on next move can exist from the hint panel... if self.boards[-1].board.next is not None: newBoard.board.children = self.boards[ -1].board.next.children self.boards = self.variations[0] self.boards[-1].board.next = newBoard.board self.boards.append(newBoard) self.moves.append(move) if self.timed: self.timemodel.tap() if not self.terminated: self.emit("game_changed", self.ply) for spectator in self.spectators.values(): if spectator.board == self.boards[-2]: spectator.putMove(self.boards[-1], self.moves[-1], self.boards[-2]) self.setOpening() self.checkStatus() self.curColor = 1 - self.curColor finally: log.debug("GameModel.run: releasing self.applyingMoveLock") self.applyingMoveLock.release()
def coro(): log.debug("GameModel.run: Starting. self=%s" % self) # Avoid racecondition when self.start is called while we are in # self.end if self.status != WAITING_TO_START: return if not self.isLocalGame(): self.timemodel.handle_gain = False self.status = RUNNING for player in self.players + list(self.spectators.values()): event = asyncio.Event() is_dead = set() player.start(event, is_dead) yield from event.wait() if is_dead: if player in self.players[WHITE]: self.kill(WHITE_ENGINE_DIED) break elif player in self.players[BLACK]: self.kill(BLACK_ENGINE_DIED) break log.debug("GameModel.run: emitting 'game_started' self=%s" % self) self.emit("game_started") # Let GameModel end() itself on games started with loadAndStart() if not self.lesson_game: self.checkStatus() if self.isEngine2EngineGame() and self.timed: self.timemodel.start() self.timemodel.started = True self.curColor = self.boards[-1].color book_depth_max = conf.get("book_depth_max") while self.status in (PAUSED, RUNNING, DRAW, WHITEWON, BLACKWON): curPlayer = self.players[self.curColor] if self.timed: log.debug( "GameModel.run: id=%s, players=%s, self.ply=%s: updating %s's time" % (id(self), str(self.players), str( self.ply), str(curPlayer))) curPlayer.updateTime( self.timemodel.getPlayerTime(self.curColor), self.timemodel.getPlayerTime(1 - self.curColor)) try: log.debug( "GameModel.run: id=%s, players=%s, self.ply=%s: calling %s.makeMove()" % (id(self), str( self.players), self.ply, str(curPlayer))) move = None # if the current player is a bot if curPlayer.__type__ == ARTIFICIAL and book_depth_max > 0 and self.ply <= book_depth_max: move = self.get_book_move() log.debug( "GameModel.run: id=%s, players=%s, self.ply=%s: got move=%s from book" % (id(self), str(self.players), self.ply, move)) if move is not None: curPlayer.set_board(self.boards[-1].move(move)) # if the current player is not a bot if move is None: if self.ply > self.lowply: move = yield from curPlayer.makeMove( self.boards[-1], self.moves[-1], self.boards[-2]) else: move = yield from curPlayer.makeMove( self.boards[-1], None, None) log.debug( "GameModel.run: id=%s, players=%s, self.ply=%s: got move=%s from %s" % (id(self), str( self.players), self.ply, move, str(curPlayer))) except PlayerIsDead as e: if self.status in (WAITING_TO_START, PAUSED, RUNNING): stringio = StringIO() traceback.print_exc(file=stringio) error = stringio.getvalue() log.error( "GameModel.run: A Player died: player=%s error=%s\n%s" % (curPlayer, error, e)) if self.curColor == WHITE: self.kill(WHITE_ENGINE_DIED) else: self.kill(BLACK_ENGINE_DIED) break except InvalidMove as e: stringio = StringIO() traceback.print_exc(file=stringio) error = stringio.getvalue() log.error( "GameModel.run: InvalidMove by player=%s error=%s\n%s" % (curPlayer, error, e)) if self.curColor == WHITE: self.end(BLACKWON, WON_ADJUDICATION) else: self.end(WHITEWON, WON_ADJUDICATION) break except PassInterrupt: log.debug( "GameModel.run: id=%s, players=%s, self.ply=%s: PassInterrupt" % (id(self), str(self.players), self.ply)) continue except TurnInterrupt: log.debug( "GameModel.run: id=%s, players=%s, self.ply=%s: TurnInterrupt" % (id(self), str(self.players), self.ply)) self.curColor = self.boards[-1].color continue except GameEnded: log.debug("GameModel.run: got GameEnded exception") break assert isinstance(move, Move), "%s" % repr(move) log.debug( "GameModel.run: id=%s, players=%s, self.ply=%s: applying move=%s" % (id(self), str(self.players), self.ply, str(move))) self.needsSave = True newBoard = self.boards[-1].move(move) newBoard.board.prev = self.boards[-1].board # newBoard.printPieces() # Variation on next move can exist from the hint panel... if self.boards[-1].board.next is not None: newBoard.board.children = self.boards[ -1].board.next.children self.boards = self.variations[0] self.boards[-1].board.next = newBoard.board self.boards.append(newBoard) self.moves.append(move) if self.timed: self.timemodel.tap() if not self.terminated: self.emit("game_changed", self.ply) for spectator in self.spectators.values(): if spectator.board == self.boards[-2]: spectator.putMove(self.boards[-1], self.moves[-1], self.boards[-2]) if self.puzzle_game and len(self.moves) % 2 == 1: status, reason = getStatus(self.boards[-1]) self.failed_playing_best = self.check_failed_playing_best( status) if self.failed_playing_best: # print("failed_playing_best() == True -> yield from asyncio.sleep(1.5) ") # It may happen that analysis had no time to fill hints with best moves # so we give him another chance with some additional time to think on it self.spectators[HINT].setBoard(self.boards[-2]) # TODO: wait for an event (analyzer PV reaching 18 ply) # instead of hard coded sleep time yield from asyncio.sleep(1.5) self.failed_playing_best = self.check_failed_playing_best( status) self.checkStatus() self.setOpening() self.curColor = 1 - self.curColor self.checkStatus()
def game_ended(gamemodel, reason, gmwidg): log.debug("gamenanny.game_ended: reason=%s gmwidg=%s\ngamemodel=%s" % (reason, gmwidg, gamemodel)) nameDic = { "white": gamemodel.players[WHITE], "black": gamemodel.players[BLACK], "mover": gamemodel.curplayer } if gamemodel.status == WHITEWON: nameDic["winner"] = gamemodel.players[WHITE] nameDic["loser"] = gamemodel.players[BLACK] elif gamemodel.status == BLACKWON: nameDic["winner"] = gamemodel.players[BLACK] nameDic["loser"] = gamemodel.players[WHITE] msg_one = reprResult_long[gamemodel.status] % nameDic msg_two = reprReason_long[reason] % nameDic if gamemodel.reason == WON_ADJUDICATION: color = BLACK if gamemodel.status == WHITEWON else WHITE invalid_move = gamemodel.players[color].invalid_move if invalid_move: msg_two += _(" invalid engine move: %s" % invalid_move) content = InfoBar.get_message_content(msg_one, msg_two, Gtk.STOCK_DIALOG_INFO) message = InfoBarMessage(Gtk.MessageType.INFO, content, None) callback = None if isinstance(gamemodel, ICGameModel): if gamemodel.hasLocalPlayer() and not gamemodel.examined: def status_changed(player, prop, message): make_sensitive_if_available(message.buttons[0], player) make_sensitive_if_playing(message.buttons[1], player) def callback(infobar, response, message): if response == 0: gamemodel.remote_player.offerRematch() elif response == 1: gamemodel.remote_player.observe() return False gmwidg.cids[gamemodel.remote_ficsplayer] = \ gamemodel.remote_ficsplayer.connect("notify::status", status_changed, message) message.add_button(InfoBarMessageButton(_("Offer Rematch"), 0)) message.add_button( InfoBarMessageButton( _("Observe %s" % gamemodel.remote_ficsplayer.name), 1)) status_changed(gamemodel.remote_ficsplayer, None, message) else: def status_changed(player, prop, button): make_sensitive_if_playing(button, player) def callback(infobar, response, message): if response in (0, 1): gamemodel.players[response].observe() return False for i, player in enumerate(gamemodel.ficsplayers): button = InfoBarMessageButton(_("Observe %s" % player.name), i) message.add_button(button) gmwidg.cids[player] = player.connect("notify::status", status_changed, button) status_changed(player, None, button) elif gamemodel.hasLocalPlayer(): def callback(infobar, response, message): if response == 1: # newGameDialog uses ionest uses gamenanny uses newGameDialog... from pychess.widgets.newGameDialog import createRematch createRematch(gamemodel) elif response == 2: if gamemodel.ply > 1: offer = Offer(TAKEBACK_OFFER, gamemodel.ply - 2) else: offer = Offer(TAKEBACK_OFFER, gamemodel.ply - 1) if gamemodel.players[0].__type__ == LOCAL: gamemodel.players[0].emit("offer", offer) else: gamemodel.players[1].emit("offer", offer) return False if not gamemodel.isLoadedGame(): message.add_button(InfoBarMessageButton(_("Play Rematch"), 1)) if gamemodel.status in UNDOABLE_STATES and gamemodel.reason in UNDOABLE_REASONS: if gamemodel.ply == 1: message.add_button(InfoBarMessageButton(_("Undo one move"), 2)) elif gamemodel.ply > 1: message.add_button(InfoBarMessageButton( _("Undo two moves"), 2)) message.callback = callback gmwidg.game_ended_message = message if len(key2gmwidg) > 0: gmwidg.replaceMessages(message) gmwidg.status("%s %s." % (msg_one, msg_two[0].lower() + msg_two[1:])) if reason == WHITE_ENGINE_DIED: engineDead(gamemodel.players[0], gmwidg) elif reason == BLACK_ENGINE_DIED: engineDead(gamemodel.players[1], gmwidg) if (isinstance(gamemodel, ICGameModel) and not gamemodel.isObservationGame()) or \ gamemodel.isEngine2EngineGame(): gamemodel.restart_analyzer(HINT) gamemodel.restart_analyzer(SPY) if not conf.get("hint_mode", False): gamemodel.pause_analyzer(HINT) if not conf.get("spy_mode", False): gamemodel.pause_analyzer(SPY) return False