def test1(self): """ From gbtami (player accepting a challenge) point of view """ lines = [ "Challenge: ggbtami (----) gbtami (1708) unrated blitz 5 0.", 'You can "accept" or "decline", or propose different parameters.', "fics% ", "<pf> 7 w=ggbtami t=match p=ggbtami (----) gbtami (1708) unrated blitz 5 0", "fics% ", BLOCK_START + '52' + BLOCK_SEPARATOR + '11' + BLOCK_SEPARATOR, "You accept the match offer from ggbtami." "", "", "<pr> 7", "fics% ", "Creating: gbtami (1708) ggbtami (++++) unrated blitz 5 0", "{Game 107 (gbtami vs. ggbtami) Creating unrated blitz match.}" "", "", "<12> rnbqkbnr pppppppp -------- -------- -------- -------- PPPPPPPP RNBQKBNR W -1 1 1 1 1 0 107 gbtami ggbtami 1 5 0 39 39 300000 300000 1 none (0:00.000) none 0 0 0", "" "" "Game 107: A disconnection will be considered a forfeit.", BLOCK_END, "fics% '" ] me = self.connection.players.get('gbtami') me.ratings[TYPE_BLITZ] = 1708 opponent = self.connection.players.get('ggbtami') opponent.ratings[TYPE_BLITZ] = 0 game = FICSGame(me, opponent, gameno=107, rated=False, game_type=GAME_TYPES['blitz'], private=False, minutes=5, inc=0, board=FICSBoard(300000, 300000, fen=FEN_START)) me.game = game opponent.game = game self.runAndAssertEquals("playGameCreated", lines, (game, )) lines = [ BLOCK_START + '58' + BLOCK_SEPARATOR + '1' + BLOCK_SEPARATOR, "<12> rnbqkbnr pppppppp -------- -------- -------- -----P-- PPPPP-PP RNBQKBNR B -1 1 1 1 1 0 107 gbtami ggbtami -1 5 0 39 39 300000 300000 1 P/f2-f3 (0:00.000) f3 0 0 0", BLOCK_END, "fics% ", "<12> rnbqkbnr pppp-ppp -------- ----p--- -------- -----P-- PPPPP-PP RNBQKBNR W 4 1 1 1 1 0 107 gbtami ggbtami 1 5 0 39 39 300000 300000 2 P/e7-e5 (0:00.000) e5 0 1 0", "fics% ", BLOCK_START + '61' + BLOCK_SEPARATOR + '1' + BLOCK_SEPARATOR, "<12> rnbqkbnr pppp-ppp -------- ----p--- ------P- -----P-- PPPPP--P RNBQKBNR B 6 1 1 1 1 0 107 gbtami ggbtami -1 5 0 39 39 297338 300000 2 P/g2-g4 (0:02.662) g4 0 1 296", BLOCK_END, "fics% ", "<12> rnb-kbnr pppp-ppp -------- ----p--- ------Pq -----P-- PPPPP--P RNBQKBNR W -1 1 1 1 1 1 107 gbtami ggbtami 1 5 0 39 39 297338 295763 3 Q/d8-h4 (0:04.237) Qh4# 0 1 304", "fics% ", "{Game 107 (gbtami vs. ggbtami) gbtami checkmated} 0-1", "No ratings adjustment done.", "fics% " ] game = self.connection.games[game] def coro(): yield from self.connection.process_lines(lines) self.loop.run_until_complete(coro()) self.assertEqual(game.move_queue.qsize(), 4) self.assertEqual(game.reason, WON_MATE)
def on_icc_spgn(self, data): if self.connection.query_game is None: return game = self.connection.query_game game.board = FICSBoard(0, 0, pgn=data) game = self.connection.games.get(game) self.emit("archiveGamePreview", game)
def onPlayGameCreated(self, matchlist): log.debug( "'%s' '%s' '%s'" % (matchlist[0].string, matchlist[1].string, matchlist[-1].string), extra={"task": (self.connection.username, "BM.onPlayGameCreated")}) wname, wrating, bname, brating, rated, match_type, minutes, inc = matchlist[ 0].groups() item = 2 if self.connection.USCN else 1 gameno, wname, bname, rated, match_type = matchlist[item].groups() gameno = int(gameno) wrating = parseRating(wrating) brating = parseRating(brating) rated = rated == "rated" game_type = GAME_TYPES[match_type] wplayer = self.connection.players.get(wname) bplayer = self.connection.players.get(bname) for player, rating in ((wplayer, wrating), (bplayer, brating)): if game_type.rating_type in player.ratings and \ player.ratings[game_type.rating_type] != rating: player.ratings[game_type.rating_type] = rating player.emit("ratings_changed", game_type.rating_type, player) style12 = matchlist[-1].groups()[0] castleSigns = self.generateCastleSigns(style12, game_type) self.castleSigns[gameno] = castleSigns gameno, relation, curcol, ply, wname, bname, wms, bms, gain, lastmove, fen = \ self.parseStyle12(style12, castleSigns) game = FICSGame(wplayer, bplayer, gameno=gameno, rated=rated, game_type=game_type, minutes=int(minutes), inc=int(inc), board=FICSBoard(wms, bms, fen=fen)) game = self.connection.games.get(game) for player in (wplayer, bplayer): if player.status != IC_STATUS_PLAYING: player.status = IC_STATUS_PLAYING if player.game != game: player.game = game self.theGameImPlaying = game self.gamemodelStartedEvents[gameno] = threading.Event() self.connection.client.run_command("follow") self.emit("playGameCreated", game)
def test3(self): """ Accepting a seek """ loop = asyncio.get_event_loop() loop.set_debug(enabled=True) widgets = uistuff.GladeWidgets("PyChess.glade") gamewidget.setWidgets(widgets) perspective_manager.set_widgets(widgets) self.welcome_persp = Welcome() perspective_manager.add_perspective(self.welcome_persp) self.games_persp = Games() perspective_manager.add_perspective(self.games_persp) self.fics_persp = FICS() perspective_manager.add_perspective(self.fics_persp) self.fics_persp.create_toolbuttons() self.lounge = perspective_manager.get_perspective("fics") self.lounge.open_lounge(self.connection, self.connection, "freechess.org") lines = [ "<s> 11 w=WLTL ti=00 rt=2030 t=1 i=0 r=r tp=lightning c=? rr=0-9999 a=t f=f", "fics% ", BLOCK_START + "52" + BLOCK_SEPARATOR + "158" + BLOCK_SEPARATOR, "<sr> 11 16", "fics% ", "Creating: WLTL (2030) gbtami (1771) rated lightning 1 0", "{Game 85 (WLTL vs. gbtami) Creating rated lightning match.}", "", "<12> rnbqkbnr pppppppp -------- -------- -------- -------- PPPPPPPP RNBQKBNR W -1 1 1 1 1 0 85 WLTL gbtami -1 1 0 39 39 60000 60000 1 none (0:00.000) none 1 0 0\n\nGame 85: A disconnection will be considered a forfeit.", BLOCK_END, "fics% " ] me = self.connection.players.get('gbtami') me.ratings[TYPE_LIGHTNING] = 1771 opponent = self.connection.players.get('WLTL') opponent.ratings[TYPE_LIGHTNING] = 2030 game = FICSGame(opponent, me, gameno=85, rated=True, game_type=GAME_TYPES['lightning'], private=False, minutes=1, inc=0, board=FICSBoard(60000, 60000, fen=FEN_START)) me.game = game opponent.game = game self.runAndAssertEquals("playGameCreated", lines, (game, )) gamemodel = self.games_persp.cur_gmwidg().gamemodel def on_game_started(game): p1 = gamemodel.players[1] p1.move_queue.put_nowait(Move(newMove(G8, F6))) gamemodel.connect("game_started", on_game_started) lines = [ "<12> rnbqkbnr pppppppp -------- -------- -------- -P------ P-PPPPPP RNBQKBNR B -1 1 1 1 1 0 85 WLTL gbtami 1 1 0 39 39 60000 60000 1 P/b2-b3 (0:00.000) b3 1 0 0", "fics% " ] game = self.connection.games[game] def coro(): yield from self.connection.process_lines(lines) self.loop.run_until_complete(coro()) self.assertEqual(game.move_queue.qsize(), 0) lines = [ BLOCK_START + "59" + BLOCK_SEPARATOR + "1" + BLOCK_SEPARATOR, "<12> rnbqkb-r pppppppp -----n-- -------- -------- -P------ P-PPPPPP RNBQKBNR W -1 1 1 1 1 1 85 WLTL gbtami -1 1 0 39 39 60000 60000 2 N/g8-f6 (0:00.000) Nf6 1 1 0", BLOCK_END, "fics% ", "<12> rnbqkb-r pppppppp -----n-- -------- -------- -P----P- P-PPPP-P RNBQKBNR B -1 1 1 1 1 0 85 WLTL gbtami 1 1 0 39 39 59900 60000 2 P/g2-g3 (0:00.100) g3 1 1 285", "fics% " ] def coro(): yield from self.connection.process_lines(lines) self.loop.run_until_complete(coro()) self.assertEqual(game.move_queue.qsize(), 0) self.assertEqual(gamemodel.ply, 3) print(gamemodel.boards[-1])
def onObserveGameCreated(self, matchlist): log.debug("'%s'" % (matchlist[1].string), extra={ "task": (self.connection.username, "BM.onObserveGameCreated") }) if self.connection.USCN: # TODO? is this ok? game_type = GAME_TYPES["blitz"] castleSigns = ("k", "q") else: gameno, wname, wrating, bname, brating, rated, gametype, minutes, inc = matchlist[ 1].groups() wrating = parseRating(wrating) brating = parseRating(brating) game_type = GAME_TYPES[gametype] style12 = matchlist[-1].groups()[0] castleSigns = self.generateCastleSigns(style12, game_type) gameno, relation, curcol, ply, wname, bname, wms, bms, gain, lastmove, fen = \ self.parseStyle12(style12, castleSigns) gameno = int(gameno) self.castleSigns[gameno] = castleSigns wplayer = self.connection.players.get(wname) bplayer = self.connection.players.get(bname) if relation == IC_POS_OBSERVING_EXAMINATION: pgnHead = [("Event", "FICS %s %s game" % (rated, game_type.fics_name)), ("Site", "freechess.org"), ("White", wname), ("Black", bname), ("Result", "*"), ("SetUp", "1"), ("FEN", fen)] pgn = "\n".join(['[%s "%s"]' % line for line in pgnHead]) + "\n*\n" game = FICSGame(wplayer, bplayer, gameno=gameno, rated=rated == "rated", game_type=game_type, minutes=int(minutes), inc=int(inc), board=FICSBoard(wms, bms, pgn=pgn), relation=relation) game = self.connection.games.get(game) self.gamesImObserving[game] = wms, bms self.gamemodelStartedEvents[game.gameno] = threading.Event() self.emit("obsGameCreated", game) self.gamemodelStartedEvents[game.gameno].wait() else: game = FICSGame(wplayer, bplayer, gameno=gameno, rated=rated == "rated", game_type=game_type, minutes=int(minutes), inc=int(inc), relation=relation) game = self.connection.games.get(game, emit=False) if not game.supported: log.warning("Trying to follow an unsupported type game %s" % game.game_type) return if game.gameno in self.gamemodelStartedEvents: log.warning("%s already in gamemodelstartedevents" % game.gameno) return self.gamesImObserving[game] = wms, bms self.queuedStyle12s[game.gameno] = [] self.queuedEmits[game.gameno] = [] self.gamemodelStartedEvents[game.gameno] = threading.Event() # FICS doesn't send the move list after 'observe' and 'follow' commands self.connection.client.run_command("moves %d" % game.gameno)
def parseGame(self, matchlist, gameclass, in_progress=False, gameno=None): """ Parses the header and movelist for an observed or stored game from its matchlist (an re.match object) into a gameclass (FICSGame or subclass of) object. in_progress - should be True for an observed game matchlist, and False for stored/adjourned games """ # ################ observed game movelist example: # Movelist for game 64: # # Ajido (2281) vs. IMgooeyjim (2068) --- Thu Oct 14, 20:36 PDT 2010 # Rated standard match, initial time: 15 minutes, increment: 3 seconds. # # Move Ajido IMgooeyjim # ---- --------------------- --------------------- # 1. d4 (0:00.000) Nf6 (0:00.000) # 2. c4 (0:04.061) g6 (0:00.969) # 3. Nc3 (0:13.280) Bg7 (0:06.422) # {Still in progress} * # # ################# stored game example: # BwanaSlei (1137) vs. mgatto (1336) --- Wed Nov 5, 20:56 PST 2008 # Rated blitz match, initial time: 5 minutes, increment: 0 seconds. # # Move BwanaSlei mgatto # ---- --------------------- --------------------- # 1. e4 (0:00.000) c5 (0:00.000) # 2. d4 (0:05.750) cxd4 (0:03.020) # ... # 23. Qxf3 (1:05.500) # {White lost connection; game adjourned} * # # ################# stored wild/3 game with style12: # kurushi (1626) vs. mgatto (1627) --- Thu Nov 4, 10:33 PDT 2010 # Rated wild/3 match, initial time: 3 minutes, increment: 0 seconds. # # <12> nqbrknrn pppppppp -------- -------- -------- -------- PPPPPPPP NQBRKNRN W -1 0 0 0 0 0 17 kurushi mgatto -4 3 0 39 39 169403 45227 1 none (0:00.000) none 0 1 0 # # Move kurushi mgatto # ---- --------------------- --------------------- # 1. Nb3 (0:00.000) d5 (0:00.000) # 2. Nhg3 (0:00.386) e5 (0:03.672) # ... # 28. Rxd5 (0:00.412) # {Black lost connection; game adjourned} * # # ################# stored game movelist following stored game(s): # Stored games for mgatto: # C Opponent On Type Str M ECO Date # 1: W BabyLurking Y [ br 5 0] 29-13 W27 D37 Fri Nov 5, 04:41 PDT 2010 # 2: W gbtami N [ wr 5 0] 32-34 W14 --- Thu Oct 21, 00:14 PDT 2010 # # mgatto (1233) vs. BabyLurking (1455) --- Fri Nov 5, 04:33 PDT 2010 # Rated blitz match, initial time: 5 minutes, increment: 0 seconds. # # Move mgatto BabyLurking # ---- ---------------- ---------------- # 1. Nf3 (0:00) d5 (0:00) # 2. d4 (0:03) Nf6 (0:00) # 3. c4 (0:03) e6 (0:00) # {White lost connection; game adjourned} * # # ################## stored game movelist following stored game(s): # ## Note: A wild stored game in this format won't be parseable into a board because # ## it doesn't come with a style12 that has the start position, so we warn and return # ################## # Stored games for mgatto: # C Opponent On Type Str M ECO Date # 1: W gbtami N [ wr 5 0] 32-34 W14 --- Thu Oct 21, 00:14 PDT 2010 # # mgatto (1627) vs. gbtami (1881) --- Thu Oct 21, 00:10 PDT 2010 # Rated wild/fr match, initial time: 5 minutes, increment: 0 seconds. # # Move mgatto gbtami # ---- ---------------- ---------------- # 1. d4 (0:00) b6 (0:00) # 2. b3 (0:06) d5 (0:03) # 3. c4 (0:08) e6 (0:03) # 4. e3 (0:04) dxc4 (0:02) # 5. bxc4 (0:02) g6 (0:09) # 6. Nd3 (0:12) Bg7 (0:02) # 7. Nc3 (0:10) Ne7 (0:03) # 8. Be2 (0:08) c5 (0:05) # 9. a4 (0:07) cxd4 (0:38) # 10. exd4 (0:06) Bxd4 (0:03) # 11. O-O (0:10) Qc6 (0:06) # 12. Bf3 (0:16) Qxc4 (0:04) # 13. Bxa8 (0:03) Rxa8 (0:14) # {White lost connection; game adjourned} * # # ################# other reasons the game could be stored/adjourned: # Game courtesyadjourned by (Black|White) # Still in progress # This one must be a FICS bug # Game adjourned by mutual agreement # (White|Black) lost connection; game adjourned # Game adjourned by ((server shutdown)|(adjudication)|(simul holder)) index = 0 if in_progress: gameno = int(matchlist[index].groups()[0]) index += 2 header1 = matchlist[index] if isinstance(matchlist[index], str) \ else matchlist[index].group() matches = moveListHeader1.match(header1).groups() wname, wrating, bname, brating = matches[:4] if self.connection.FatICS: year, month, day, hour, minute, timezone = matches[11:] else: weekday, month, day, hour, minute, timezone, year = matches[4:11] month = months.index(month) + 1 wrating = parseRating(wrating) brating = parseRating(brating) rated, game_type, minutes, increment = \ moveListHeader2.match(matchlist[index + 1]).groups() minutes = int(minutes) increment = int(increment) game_type = GAME_TYPES[game_type] reason = matchlist[-1].group().lower() if in_progress: result = None result_str = "*" elif "1-0" in reason: result = WHITEWON result_str = "1-0" elif "0-1" in reason: result = BLACKWON result_str = "0-1" elif "1/2-1/2" in reason: result = DRAW result_str = "1/2-1/2" else: result = ADJOURNED result_str = "*" result, reason = parse_reason(result, reason, wname=wname) index += 3 if matchlist[index].startswith("<12>"): style12 = matchlist[index][5:] castleSigns = self.generateCastleSigns(style12, game_type) gameno, relation, curcol, ply, wname, bname, wms, bms, gain, lastmove, \ fen = self.parseStyle12(style12, castleSigns) initialfen = fen movesstart = index + 4 else: if game_type.rating_type == TYPE_WILD: # we need a style12 start position to correctly parse a wild/* board log.error("BoardManager.parseGame: no style12 for %s board." % game_type.fics_name) return None castleSigns = ("k", "q") initialfen = None movesstart = index + 2 if in_progress: self.castleSigns[gameno] = castleSigns moves = {} times = {} wms = bms = minutes * 60 * 1000 for line in matchlist[movesstart:-1]: if not moveListMoves.match(line): log.error("BoardManager.parseGame: unmatched line: \"%s\"" % repr(line)) raise Exception( "BoardManager.parseGame: unmatched line: \"%s\"" % repr(line)) moveno, wmove, whour, wmin, wsec, wmsec, bmove, bhour, bmin, bsec, bmsec = \ moveListMoves.match(line).groups() whour = 0 if whour is None else int(whour[0]) bhour = 0 if bhour is None else int(bhour[0]) ply = int(moveno) * 2 - 2 if wmove: moves[ply] = wmove wms -= (int(whour) * 60 * 60 * 1000) + (int(wmin) * 60 * 1000) + (int(wsec) * 1000) if wmsec is not None: wms -= int(wmsec) else: wmsec = 0 if increment > 0: wms += (increment * 1000) times[ply] = "%01d:%02d:%02d.%03d" % (int(whour), int(wmin), int(wsec), int(wmsec)) if bmove: moves[ply + 1] = bmove bms -= (int(bhour) * 60 * 60 * 1000) + (int(bmin) * 60 * 1000) + (int(bsec) * 1000) if bmsec is not None: bms -= int(bmsec) else: bmsec = 0 if increment > 0: bms += (increment * 1000) times[ply + 1] = "%01d:%02d:%02d.%03d" % (int(bhour), int(bmin), int(bsec), int(bmsec)) if in_progress and gameno in self.queuedStyle12s: # Apply queued board updates for style12 in self.queuedStyle12s[gameno]: gameno, relation, curcol, ply, wname, bname, wms, bms, gain, lastmove, fen = \ self.parseStyle12(style12, castleSigns) if lastmove is None: continue moves[ply - 1] = lastmove # Updated the queuedMoves in case there has been a takeback for moveply in list(moves.keys()): if moveply > ply - 1: del moves[moveply] del self.queuedStyle12s[gameno] pgnHead = [ ("Event", "FICS %s %s game" % (rated.lower(), game_type.fics_name)), ("Site", "freechess.org"), ("White", wname), ("Black", bname), ("TimeControl", "%d+%d" % (minutes * 60, increment)), ("Result", result_str), ("WhiteClock", msToClockTimeTag(wms)), ("BlackClock", msToClockTimeTag(bms)), ] if wrating != 0: pgnHead += [("WhiteElo", wrating)] if brating != 0: pgnHead += [("BlackElo", brating)] if year and month and day and hour and minute: pgnHead += [ ("Date", "%04d.%02d.%02d" % (int(year), int(month), int(day))), ("Time", "%02d:%02d:00" % (int(hour), int(minute))), ] if initialfen: pgnHead += [("SetUp", "1"), ("FEN", initialfen)] if game_type.variant_type == FISCHERRANDOMCHESS: pgnHead += [("Variant", "Fischerandom")] # FR is the only variant used in this tag by the PGN generator @ # ficsgames.org. They put all the other wild/* stuff only in the # "Event" header. elif game_type.variant_type == CRAZYHOUSECHESS: pgnHead += [("Variant", "Crazyhouse")] elif game_type.variant_type in (WILDCASTLECHESS, WILDCASTLESHUFFLECHESS): pgnHead += [("Variant", "Wildcastle")] elif game_type.variant_type == ATOMICCHESS: pgnHead += [("Variant", "Atomic")] elif game_type.variant_type == LOSERSCHESS: pgnHead += [("Variant", "Losers")] elif game_type.variant_type == SUICIDECHESS: pgnHead += [("Variant", "Suicide")] pgn = "\n".join(['[%s "%s"]' % line for line in pgnHead]) + "\n" moves = sorted(moves.items()) for ply, move in moves: if ply % 2 == 0: pgn += "%d. " % (ply // 2 + 1) time = times[ply] pgn += "%s {[%%emt %s]} " % (move, time) pgn += "*\n" wplayer = self.connection.players.get(wname) bplayer = self.connection.players.get(bname) for player, rating in ((wplayer, wrating), (bplayer, brating)): if game_type.rating_type in player.ratings and \ player.ratings[game_type.rating_type] != rating: player.ratings[game_type.rating_type] = rating player.emit("ratings_changed", game_type.rating_type, player) game = gameclass(wplayer, bplayer, game_type=game_type, result=result, rated=(rated.lower() == "rated"), minutes=minutes, inc=increment, board=FICSBoard(wms, bms, pgn=pgn)) if in_progress: game.gameno = gameno else: if gameno is not None: game.gameno = gameno game.reason = reason game = self.connection.games.get(game, emit=False) return game
def onStyle12(self, match): style12 = match.groups()[0] gameno = int(style12.split()[15]) if gameno in self.queuedStyle12s: self.queuedStyle12s[gameno].append(style12) return try: self.gamemodelStartedEvents[gameno].wait() except KeyError: pass if gameno in self.castleSigns: castleSigns = self.castleSigns[gameno] else: castleSigns = ("k", "q") gameno, relation, curcol, ply, wname, bname, wms, bms, gain, lastmove, fen = \ self.parseStyle12(style12, castleSigns) # examine starts with a <12> line only if lastmove is None and relation == IC_POS_EXAMINATING: pgnHead = [("Event", "FICS examined game"), ("Site", "freechess.org"), ("White", wname), ("Black", bname), ("Result", "*"), ("SetUp", "1"), ("FEN", fen)] pgn = "\n".join(['[%s "%s"]' % line for line in pgnHead]) + "\n*\n" wplayer = self.connection.players.get(wname) bplayer = self.connection.players.get(bname) # examine from console or got mexamine in observed game if self.connection.examined_game is None: no_smoves = True game = FICSGame(wplayer, bplayer, gameno=int(gameno), game_type=GAME_TYPES["examined"], minutes=0, inc=0, board=FICSBoard(0, 0, pgn=pgn), relation=relation) self.connection.examined_game = game else: # examine an archived game from GUI no_smoves = False game = self.connection.examined_game game.gameno = int(gameno) game.relation = relation # game.game_type = GAME_TYPES["examined"] game = self.connection.games.get(game) # don't start new game in puzzlebot/endgamebot when they just reuse gameno if game.relation == IC_POS_OBSERVING_EXAMINATION or \ (game.board is not None and game.board.pgn == pgn): self.emit("boardUpdate", gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms) return game.relation = relation game.board = FICSBoard(0, 0, pgn=pgn) self.gamesImObserving[game] = wms, bms # start a new game now or after smoves self.gamemodelStartedEvents[game.gameno] = threading.Event() if no_smoves: self.emit("exGameCreated", game) self.gamemodelStartedEvents[game.gameno].wait() else: if isinstance(game, FICSHistoryGame): self.connection.client.run_command( "smoves %s %s" % (self.connection.history_owner, game.history_no)) elif isinstance(game, FICSJournalGame): self.connection.client.run_command( "smoves %s %%%s" % (self.connection.journal_owner, game.journal_no)) elif isinstance(game, FICSAdjournedGame): self.connection.client.run_command( "smoves %s %s" % (self.connection.stored_owner, game.opponent.name)) self.connection.client.run_command("forward 999") else: self.emit("boardUpdate", gameno, ply, curcol, lastmove, fen, wname, bname, wms, bms)
def on_icc_send_moves(self, data): log.debug("DG_SEND_MOVES %s" % data) # gamenumber algebraic-move smith-move time clock send_moves = data gameno, san_move, alg_move, time, clock = send_moves.split() gameno = int(gameno) try: game = self.connection.games.get_game_by_gameno(gameno) except KeyError: log.debug("Game %s is not in self.connection.games" % gameno) return fen = "" if game == self.theGameImPlaying: curcol, ply, wms, bms = self.my_game_info else: curcol, ply, wms, bms = self.gamesImObserving[game] if curcol == WHITE: wms = int(clock) * 1000 else: bms = int(clock) * 1000 ply += 1 curcol = 1 - curcol if game == self.theGameImPlaying: self.my_game_info = (curcol, ply, wms, bms) else: self.gamesImObserving[game] = (curcol, ply, wms, bms) if gameno in self.queued_send_moves: self.queued_send_moves[gameno].append(send_moves) if self.moves_to_go and len( self.queued_send_moves[gameno]) < self.moves_to_go: return if self.moves_to_go == 0 or self.moves_to_go is None: log.debug("put san_move to move_queue %s" % san_move) game.move_queue.put_nowait( (gameno, ply, curcol, san_move, fen, game.wplayer.name, game.bplayer.name, wms, bms)) self.emit("timesUpdate", gameno, wms, bms) else: if game.gameno not in self.gamemodelStartedEvents: return if game.gameno not in self.queuedEmits: return pgnHead = [ ("Event", "ICC %s %s game" % (game.display_rated.lower(), game.game_type.fics_name)), ("Site", "chessclub.com"), ("White", game.wplayer.name), ("Black", game.bplayer.name), ("Result", "*"), ("TimeControl", "%d+%d" % (game.minutes * 60, game.inc)), ] wrating = game.wplayer.ratings[game.game_type.rating_type] brating = game.bplayer.ratings[game.game_type.rating_type] if wrating != 0: pgnHead += [("WhiteElo", wrating)] if brating != 0: pgnHead += [("BlackElo", brating)] pgn = "\n".join(['[%s "%s"]' % line for line in pgnHead]) + "\n" moves = self.queued_send_moves[gameno] ply = 0 for send_moves in moves: gameno_, san_move, alg_move, time, clock = send_moves.split() if ply % 2 == 0: pgn += "%d. " % (ply // 2 + 1) pgn += "%s {[%%emt %s]} " % (san_move, time) ply += 1 pgn += "*\n" del self.queued_send_moves[gameno] self.moves_to_go = None wms = bms = 0 game = FICSGame(game.wplayer, game.bplayer, game_type=game.game_type, result=game.result, rated=game.rated, minutes=game.minutes, inc=game.inc, board=FICSBoard(wms, bms, pgn=pgn)) in_progress = True if in_progress: game.gameno = gameno else: if gameno is not None: game.gameno = gameno # game.reason = reason game = self.connection.games.get(game, emit=False) self.emit("obsGameCreated", game) try: self.gamemodelStartedEvents[game.gameno].wait() except KeyError: pass for emit in self.queuedEmits[game.gameno]: emit() del self.queuedEmits[game.gameno] curcol, ply, wms, bms = self.gamesImObserving[game] self.emit("timesUpdate", game.gameno, wms, bms)
def on_icc_my_game_started(self, data): log.debug("DG_MY_GAME_STARTED %s" % data) # gamenumber whitename blackname wild-number rating-type rated # white-initial white-increment black-initial black-increment # played-game {ex-string} white-rating black-rating game-id # white-titles black-titles irregular-legality irregular-semantics # uses-plunkers fancy-timecontrol promote-to-king # 685 Salsicha MaxiBomb 0 Blitz 1 3 0 3 0 1 {} 2147 2197 1729752694 {} {} 0 0 0 {} 0 # 259 Rikikilord ARMH 0 Blitz 1 2 12 2 12 0 {Ex: Rikikilord 0} 1532 1406 1729752286 {} {} 0 0 0 {} 0 gameno, wname, bname, wild, rtype, rated, wmin, winc, bmin, binc, played_game, rest = data.split( " ", 11) parts = rest.split("}", 1)[1].split() wrating = int(parts[0]) brating = int(parts[1]) gameno = int(gameno) wplayer = self.connection.players.get(wname) bplayer = self.connection.players.get(bname) if int(wild) > 0: game_type = GAME_TYPES["w%s" % wild] else: game_type = GAME_TYPES[rtype.lower()] log.debug("DG_MY_GAME_STARTED game type is %s" % game_type) for player, rating in ((wplayer, wrating), (bplayer, brating)): try: if player.ratings[game_type.rating_type] != rating: player.ratings[game_type.rating_type] = rating player.emit("ratings_changed", game_type.rating_type, player) except IndexError: log.debug( "!!! game_type.rating_type %s is out of range in player.ratings %s" % (game_type.rating_type, player.ratings)) wms = bms = int(wmin) * 60 * 1000 + int(winc) * 1000 # TODO: maybe use DG_POSITION_BEGIN2 and DG_PAST_MOVE ? fen = FEN_START game = FICSGame(wplayer, bplayer, gameno=gameno, rated=rated == "1", game_type=game_type, minutes=int(wmin), inc=int(winc), board=FICSBoard(wms, bms, fen=fen)) if self.connection.examined_game is not None: pgnHead = [("Event", "ICC examined game"), ("Site", "chessclub.com"), ("White", wname), ("Black", bname), ("Result", "*"), ("SetUp", "1"), ("FEN", fen)] pgn = "\n".join(['[%s "%s"]' % line for line in pgnHead]) + "\n*\n" game.relation = IC_POS_EXAMINATING game.game_type = GAME_TYPES["examined"] game.board.pgn = pgn game = self.connection.games.get(game) for player in (wplayer, bplayer): if player.status != IC_STATUS_PLAYING: player.status = IC_STATUS_PLAYING if player.game != game: player.game = game self.theGameImPlaying = game self.my_game_info = (WHITE, 0, wms, bms) self.gamemodelStartedEvents[gameno] = asyncio.Event() self.connection.client.run_command("follow") if self.connection.examined_game is not None: self.emit("exGameCreated", game) else: if int(wild) in (1, 2, 3, 4, 20, 21, 22): # several wild variant (including loadfen/loadgame) need # a starting FEN coming in a DG_POSITION_BEGIN datgram log.debug("wild20 is waiting for a starting FEN...") else: self.emit("playGameCreated", game)