示例#1
0
    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)
示例#2
0
    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 on_player_who(self, match):
     for blitz, status, name, titles in whomatch_re.findall(match.string):
         player = self.connection.players.get(name)
         if not player.online:
             player.online = True
         status = STATUS[status]
         if player.status != status:
             player.status = status
         titles = self.parseTitles(titles)
         if not player.titles >= titles:
             player.titles |= titles
         blitz = parseRating(blitz)
         if player.ratings[TYPE_BLITZ] != blitz:
             player.ratings[TYPE_BLITZ] = blitz
             player.emit("ratings_changed", TYPE_BLITZ, player)
示例#4
0
 def on_player_who(self, match):
     for blitz, status, name, titles in whomatch_re.findall(match.string):
         player = self.connection.players.get(name)
         if not player.online:
             player.online = True
         status = STATUS[status]
         if player.status != status:
             player.status = status
         titles = self.parseTitles(titles)
         if not player.titles >= titles:
             player.titles |= titles
         blitz = parseRating(blitz)
         if player.ratings[TYPE_BLITZ] != blitz:
             player.ratings[TYPE_BLITZ] = blitz
             player.emit("ratings_changed", TYPE_BLITZ, player)
    def on_game_list(self, matchlist):
        games = []
        for match in matchlist[:-1]:
            if isinstance(match, str):
                if match:
                    parts0, parts1 = match.split("[")
                    gameno, wrating, wname, brating, bname = parts0.split()
                    private = parts1[0]
                    shorttype = parts1[1]
                    rated = parts1[2]
                    min = parts1[3:6]
                    inc = parts1[7:10]
                else:
                    continue
            else:
                gameno, wrating, wname, brating, bname, private, shorttype, rated, min, inc, whour, wmin, wsec, bhour, bmin, bsec, wmat, bmat, color, movno = (
                    match.groups())
            try:
                gametype = GAME_TYPES_BY_SHORT_FICS_NAME[shorttype]
            except KeyError:
                return

            wplayer = self.connection.players.get(wname)
            bplayer = self.connection.players.get(bname)
            game = FICSGame(
                wplayer,
                bplayer,
                gameno=int(gameno),
                rated=(rated == "r"),
                private=(private == "p"),
                minutes=int(min),
                inc=int(inc),
                game_type=gametype,
            )

            for player, rating in ((wplayer, wrating), (bplayer, brating)):
                if player.status != IC_STATUS_PLAYING:
                    player.status = IC_STATUS_PLAYING
                if player.game != game:
                    player.game = game
                rating = parseRating(rating)
                if player.ratings[gametype.rating_type] != rating:
                    player.ratings[gametype.rating_type] = rating
                    player.emit("ratings_changed", gametype.rating_type,
                                player)
            game = self.connection.games.get(game, emit=False)
            games.append(game)
        self.connection.games.emit("FICSGameCreated", games)
示例#6
0
    def on_game_list(self, matchlist):
        games = []
        for match in matchlist[:-1]:
            if isinstance(match, str):
                if match:
                    parts0, parts1 = match.split("[")
                    gameno, wrating, wname, brating, bname = parts0.split()
                    private = parts1[0]
                    shorttype = parts1[1]
                    rated = parts1[2]
                    min = parts1[3:6]
                    inc = parts1[7:10]
                else:
                    continue
            else:
                gameno, wrating, wname, brating, bname, private, shorttype, rated, min, \
                    inc, whour, wmin, wsec, bhour, bmin, bsec, wmat, bmat, color, movno = match.groups()
            try:
                gametype = GAME_TYPES_BY_SHORT_FICS_NAME[shorttype]
            except KeyError:
                return

            wplayer = self.connection.players.get(wname)
            bplayer = self.connection.players.get(bname)
            game = FICSGame(wplayer,
                            bplayer,
                            gameno=int(gameno),
                            rated=(rated == "r"),
                            private=(private == "p"),
                            minutes=int(min),
                            inc=int(inc),
                            game_type=gametype)

            for player, rating in ((wplayer, wrating), (bplayer, brating)):
                if player.status != IC_STATUS_PLAYING:
                    player.status = IC_STATUS_PLAYING
                if player.game != game:
                    player.game = game
                rating = parseRating(rating)
                if gametype.rating_type in player.ratings and \
                        player.ratings[gametype.rating_type] != rating:
                    player.ratings[gametype.rating_type] = rating
                    player.emit("ratings_changed", gametype.rating_type, player)
            game = self.connection.games.get(game, emit=False)
            games.append(game)
        self.connection.games.emit("FICSGameCreated", games)
示例#7
0
    def on_player_available(self, matches):
        name, titles, blitz, std, wild, light, bughouse = matches[0].groups()
        player = self.connection.players.get(name)

        if not player.online:
            player.online = True
        if player.status != IC_STATUS_AVAILABLE:
            player.status = IC_STATUS_AVAILABLE
        titles = self.parseTitles(titles)
        if not player.titles >= titles:
            player.titles |= titles

        for rating_type, rating in ((TYPE_BLITZ, blitz), (TYPE_STANDARD, std),
                                    (TYPE_LIGHTNING, light), (TYPE_WILD, wild),
                                    (TYPE_BUGHOUSE, bughouse)):
            rating = parseRating(rating)
            if player.ratings[rating_type] != rating:
                player.ratings[rating_type] = rating
                player.emit("ratings_changed", rating_type, player)
示例#8
0
    def on_player_available(self, matches):
        name, titles, blitz, std, wild, light, bughouse = matches[0].groups()
        player = self.connection.players.get(name)

        if not player.online:
            player.online = True
        if player.status != IC_STATUS_AVAILABLE:
            player.status = IC_STATUS_AVAILABLE
        titles = self.parseTitles(titles)
        if not player.titles >= titles:
            player.titles |= titles

        for rating_type, rating in ((TYPE_BLITZ, blitz), (TYPE_STANDARD, std),
                              (TYPE_LIGHTNING, light), (TYPE_WILD, wild),
                              (TYPE_BUGHOUSE, bughouse)):
            rating = parseRating(rating)
            if player.ratings[rating_type] != rating:
                player.ratings[rating_type] = rating
                player.emit("ratings_changed", rating_type, player)
    def on_player_connectI(self, match, set_online=True):
        # bslwBzSLx
        # gbtami 001411E1663P1483P1720P0P1646P0P0P1679P
        name, status, titlehex, blitz, blitzdev, std, stddev, light, lightdev, wild, wilddev, bughouse, bughousedev, crazyhouse, crazyhousedev, suicide, suicidedev, losers, losersdev, atomic, atomicdev = (
            match.groups())
        player = self.connection.players.get(name)

        titles = parse_title_hex(titlehex)
        if not player.titles >= titles:
            player.titles |= titles

        for rating_type, elo, dev in (
            (TYPE_BLITZ, blitz, blitzdev),
            (TYPE_STANDARD, std, stddev),
            (TYPE_LIGHTNING, light, lightdev),
            (TYPE_ATOMIC, atomic, atomicdev),
            (TYPE_WILD, wild, wilddev),
            (TYPE_CRAZYHOUSE, crazyhouse, crazyhousedev),
            (TYPE_BUGHOUSE, bughouse, bughousedev),
            (TYPE_LOSERS, losers, losersdev),
            (TYPE_SUICIDE, suicide, suicidedev),
        ):
            rating = parseRating(elo)
            if player.ratings[rating_type] != rating:
                player.ratings[rating_type] = rating
                player.emit("ratings_changed", rating_type, player)
            player.deviations[rating_type] = DEVIATION[dev]

        # do last so rating info is there when notifications are generated
        status = STATUS[status]
        if player.status != status:
            player.status = status
        if set_online and not player.online:
            player.online = True

        return player
示例#10
0
    def on_player_connectI(self, match, set_online=True):
        # bslwBzSLx
        # gbtami 001411E1663P1483P1720P0P1646P0P0P1679P
        name, status, titlehex, blitz, blitzdev, std, stddev, light, lightdev, \
            wild, wilddev, bughouse, bughousedev, crazyhouse, crazyhousedev, \
            suicide, suicidedev, losers, losersdev, atomic, atomicdev = match.groups()
        player = self.connection.players.get(name)

        titles = parse_title_hex(titlehex)
        if not player.titles >= titles:
            player.titles |= titles

        for rating_type, elo, dev in \
                ((TYPE_BLITZ, blitz, blitzdev),
                 (TYPE_STANDARD, std, stddev),
                 (TYPE_LIGHTNING, light, lightdev),
                 (TYPE_ATOMIC, atomic, atomicdev),
                 (TYPE_WILD, wild, wilddev),
                 (TYPE_CRAZYHOUSE, crazyhouse, crazyhousedev),
                 (TYPE_BUGHOUSE, bughouse, bughousedev),
                 (TYPE_LOSERS, losers, losersdev),
                 (TYPE_SUICIDE, suicide, suicidedev)):
            rating = parseRating(elo)
            if player.ratings[rating_type] != rating:
                player.ratings[rating_type] = rating
                player.emit("ratings_changed", rating_type, player)
            player.deviations[rating_type] = DEVIATION[dev]

        # do last so rating info is there when notifications are generated
        status = STATUS[status]
        if player.status != status:
            player.status = status
        if set_online and not player.online:
            player.online = True

        return player
示例#11
0
    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)
示例#12
0
    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
示例#13
0
    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)
示例#14
0
    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 on_icc_games(self, data):
        # 1267      guest2504            1400 KQkr(C)              20u  5  12       W:  1
        # 1060      guest7400            1489 DeadGuyKai            bu  3   0       W: 21
        # 791 1506 PlotinusRedux             guest3090             bu  2  12       W: 21
        # 47 2357 *IM_Danchevski       2683 *GM_Morozevich       Ex: scratch      W: 35
        # 101      Replayer2                 Replayer2            Ex: scratch      W:  1
        # 117 2760 *GM_Topalov          2823 *GM_Caruana          Ex: StLouis16 %0 W: 29
        # 119 1919 stansai              2068 Agrimont             Ex: continuation W: 53
        # 456 games displayed (282 played, 174 examined).
        previous_games = list(self.connection.games.values())
        games = []
        games_got = []
        lines = data.split("\n")
        for line in lines:
            # print(line)
            try:
                parts = line.split()
                index = 0

                gameno = parts[index]
                index += 1

                if parts[index].isdigit():
                    wrating = parts[index]
                    index += 1
                else:
                    wrating = "----"

                wname = parts[index]
                index += 1

                if parts[index].isdigit():
                    brating = parts[index]
                    index += 1
                else:
                    brating = "----"

                bname = parts[index]
                index += 1

                if parts[index] == "Ex:":
                    shorttype = "e"
                    rated = ""
                    min = "0"
                    inc = "0"
                else:
                    rated = parts[index][-1]
                    shorttype = parts[index][:-1]
                    index += 1
                    min = parts[index]
                    index += 1
                    inc = parts[index]
                private = ""
            except IndexError:
                continue

            try:
                gametype = GAME_TYPES_BY_SHORT_FICS_NAME[shorttype]
            except KeyError:
                # TODO: handle ICC wild types
                # print("key error in GAME_TYPES_BY_SHORT_FICS_NAME: %s" % shorttype)
                continue

            wplayer = self.connection.players.get(wname)
            bplayer = self.connection.players.get(bname)
            game = FICSGame(
                wplayer,
                bplayer,
                gameno=int(gameno),
                rated=(rated == "r"),
                private=(private == "p"),
                minutes=int(min),
                inc=int(inc),
                game_type=gametype,
            )

            for player, rating in ((wplayer, wrating), (bplayer, brating)):
                if player.status != IC_STATUS_PLAYING:
                    player.status = IC_STATUS_PLAYING
                if player.game != game:
                    player.game = game
                rating = parseRating(rating)
                if player.ratings[gametype.rating_type] != rating:
                    player.ratings[gametype.rating_type] = rating
                    player.emit("ratings_changed", gametype.rating_type,
                                player)
            if game not in previous_games:
                game = self.connection.games.get(game, emit=False)
                games.append(game)
            games_got.append(game)

        for game in previous_games:
            if (game not in games_got
                    and game not in self.connection.bm.gamesImObserving
                    and game is not self.connection.bm.theGameImPlaying):
                self.connection.games.game_ended(game)
                game.wplayer.game = None
                game.bplayer.game = None

        self.connection.games.emit("FICSGameCreated", games)
示例#16
0
    def on_icc_games(self, data):
        # 1267      guest2504            1400 KQkr(C)              20u  5  12       W:  1
        # 1060      guest7400            1489 DeadGuyKai            bu  3   0       W: 21
        # 791 1506 PlotinusRedux             guest3090             bu  2  12       W: 21
        # 47 2357 *IM_Danchevski       2683 *GM_Morozevich       Ex: scratch      W: 35
        # 101      Replayer2                 Replayer2            Ex: scratch      W:  1
        # 117 2760 *GM_Topalov          2823 *GM_Caruana          Ex: StLouis16 %0 W: 29
        # 119 1919 stansai              2068 Agrimont             Ex: continuation W: 53
        # 456 games displayed (282 played, 174 examined).
        previous_games = list(self.connection.games.values())
        games = []
        games_got = []
        lines = data.split("\n")
        for line in lines:
            # print(line)
            try:
                parts = line.split()
                index = 0

                gameno = parts[index]
                index += 1

                if parts[index].isdigit():
                    wrating = parts[index]
                    index += 1
                else:
                    wrating = "----"

                wname = parts[index]
                index += 1

                if parts[index].isdigit():
                    brating = parts[index]
                    index += 1
                else:
                    brating = "----"

                bname = parts[index]
                index += 1

                if parts[index] == "Ex:":
                    shorttype = "e"
                    rated = ""
                    min = "0"
                    inc = "0"
                else:
                    rated = parts[index][-1]
                    shorttype = parts[index][:-1]
                    index += 1
                    min = parts[index]
                    index += 1
                    inc = parts[index]
                private = ""
            except IndexError:
                continue

            try:
                gametype = GAME_TYPES_BY_SHORT_FICS_NAME[shorttype]
            except KeyError:
                # TODO: handle ICC wild types
                # print("key error in GAME_TYPES_BY_SHORT_FICS_NAME: %s" % shorttype)
                continue

            wplayer = self.connection.players.get(wname)
            bplayer = self.connection.players.get(bname)
            game = FICSGame(wplayer,
                            bplayer,
                            gameno=int(gameno),
                            rated=(rated == "r"),
                            private=(private == "p"),
                            minutes=int(min),
                            inc=int(inc),
                            game_type=gametype)

            for player, rating in ((wplayer, wrating), (bplayer, brating)):
                if player.status != IC_STATUS_PLAYING:
                    player.status = IC_STATUS_PLAYING
                if player.game != game:
                    player.game = game
                rating = parseRating(rating)
                if player.ratings[gametype.rating_type] != rating:
                    player.ratings[gametype.rating_type] = rating
                    player.emit("ratings_changed", gametype.rating_type, player)
            if game not in previous_games:
                game = self.connection.games.get(game, emit=False)
                games.append(game)
            games_got.append(game)

        for game in previous_games:
            if game not in games_got and \
                game not in self.connection.bm.gamesImObserving and \
                    game is not self.connection.bm.theGameImPlaying:
                self.connection.games.game_ended(game)
                game.wplayer.game = None
                game.bplayer.game = None

        self.connection.games.emit("FICSGameCreated", games)