Exemplo n.º 1
0
    def test_start_fen(self):
        result = sf.start_fen("capablanca")
        self.assertEqual(result, CAPA)

        result = sf.start_fen("capahouse")
        self.assertEqual(result, CAPAHOUSE)

        result = sf.start_fen("xiangqi")
        self.assertEqual(result, XIANGQI)

        result = sf.start_fen("grandhouse")
        self.assertEqual(result, GRANDHOUSE)

        result = sf.start_fen("shogun")
        self.assertEqual(result, SHOGUN)
Exemplo n.º 2
0
def pgn(doc):
    variant = C2V[doc["v"]]
    mlist = decode_moves(doc["m"], variant)
    chess960 = bool(int(doc.get("z"))) if "z" in doc else False

    if variant == "xiangqi" or variant == "grand" or variant == "grandhouse" or variant == "shako" or variant == "janggi":
        mlist = list(map(zero2grand, mlist))

    fen = doc["if"] if "if" in doc else sf.start_fen(variant)
    mlist = sf.get_san_moves(variant, fen, mlist, chess960)

    moves = " ".join(
        (move if ind % 2 == 1 else "%s. %s" % (((ind + 1) // 2) + 1, move)
         for ind, move in enumerate(mlist)))
    no_setup = fen == STANDARD_FEN and not chess960
    # Use lichess format for crazyhouse games to support easy import
    setup_fen = fen if variant != "crazyhouse" else fen.replace("[]", "")

    return '[Event "{}"]\n[Site "{}"]\n[Date "{}"]\n[Round "-"]\n[White "{}"]\n[Black "{}"]\n[Result "{}"]\n[TimeControl "{}+{}"]\n[WhiteElo "{}"]\n[BlackElo "{}"]\n[Variant "{}"]\n{fen}{setup}\n{} {}\n'.format(
        "PyChess " + ("rated" if "y" in doc and doc["y"] == 1 else "casual") +
        " game",
        URI + "/" + doc["_id"],
        doc["d"].strftime("%Y.%m.%d"),
        doc["us"][0],
        doc["us"][1],
        C2R[doc["r"]],
        doc["b"] * 60,
        doc["i"],
        doc["p0"]["e"] if "p0" in doc else "?",
        doc["p1"]["e"] if "p1" in doc else "?",
        variant.capitalize() if not chess960 else VARIANT_960_TO_PGN[variant],
        moves,
        C2R[doc["r"]],
        fen="" if no_setup else '[FEN "%s"]\n' % setup_fen,
        setup="" if no_setup else '[SetUp "1"]\n')
Exemplo n.º 3
0
 def start_fen(self, variant, chess960=False, disabled_fen=""):
     if chess960:
         new_fen = self.shuffle_start()
         while new_fen == disabled_fen:
             new_fen = self.shuffle_start()
         return new_fen
     return sf.start_fen(variant)
Exemplo n.º 4
0
def sanitize_fen(variant, initial_fen, chess960):
    # Initial_fen needs validation to prevent segfaulting in pyffish
    sanitized_fen = initial_fen

    start_fen = sf.start_fen(variant)  # self.board.start_fen(self.variant)
    start = start_fen.split()
    init = initial_fen.split()

    # Cut off tail
    if len(init) > 6:
        init = init[:6]
        sanitized_fen = " ".join(init)

    # We need starting color
    invalid0 = len(init) < 2

    # Only piece types listed in variant start position can be used later
    if variant == "makruk" or variant == "cambodian":
        non_piece = "~+0123456789[]fF"
    else:
        non_piece = "~+0123456789[]"
    invalid1 = any((c not in start[0] + non_piece for c in init[0]))

    # Required number of rows
    invalid2 = start[0].count("/") != init[0].count("/")

    # Accept zh FEN in lichess format (they use / instead if [] for pockets)
    if invalid2 and variant == "crazyhouse":
        if (init[0].count("/") == 8) and ("[" not in init[0]) and ("]" not in init[0]):
            k = init[0].rfind("/")
            init[0] = init[0][:k] + "[" + init[0][k + 1:] + "]"
            sanitized_fen = " ".join(init)
            invalid2 = False

    # Allowed starting colors
    invalid3 = len(init) > 1 and init[1] not in "bw"

    # Castling rights (and piece virginity) check
    invalid4 = False
    if variant == "seirawan" or variant == "shouse":
        invalid4 = len(init) > 2 and any((c not in "KQABCDEFGHkqabcdefgh-" for c in init[2]))
    elif chess960:
        if all((c in "KQkq-" for c in init[2])):
            chess960 = False
        else:
            invalid4 = len(init) > 2 and any((c not in "ABCDEFGHIJabcdefghij-" for c in init[2]))
    elif variant[-5:] != "shogi":
        invalid4 = len(init) > 2 and any((c not in start[2] + "-" for c in init[2]))

    # Number of kings
    invalid5 = init[0].count("k") != 1 or init[0].count("K") != 1

    if invalid0 or invalid1 or invalid2 or invalid3 or invalid4 or invalid5:
        print(invalid0, invalid1, invalid2, invalid3, invalid4, invalid5)
        sanitized_fen = start_fen
        return False, start_fen
    else:
        return True, sanitized_fen
Exemplo n.º 5
0
 def newgame(self, variant, time_control):
     with self.lock:
         self.rank_conversion = sf.start_fen(variant).count('/') + 1 == 10
         self.process.stdin.write('new\n')
         self.process.stdin.write('variant {}\n'.format(variant))
         if self.partner:
             self.process.stdin.write('partner test\n')
         self.process.stdin.write('level {}\n'.format(time_control.format_xboard()))
         self.process.stdin.flush()
Exemplo n.º 6
0
 def __init__(self, engine1, engine2, time_control, variant='chess', games=1, start_fens=None):
     self.two_boards = sf.two_boards(variant)
     self.engines = [Engine([engine1]), Engine([engine2])]
     self.board2_engines = [Engine([engine1]), Engine([engine2])] if self.two_boards else None
     self.time_control = time_control
     self.variant = variant
     self.games = games
     self.start_fens = start_fens if start_fens else [sf.start_fen(variant)]
     self.score = [0, 0, 0]
Exemplo n.º 7
0
 def __init__(self, engine1, engine2, time_control, variant='chess', start_fen=None):
     self.engines = [engine1, engine2]
     self.time_control = time_control
     self.variant = variant
     self.start_fen = start_fen or sf.start_fen(variant)
     self.moves = []
     self.result = None
     self.partner = None
     self.obtained_holdings = ''
     self.clock_times = [self.time_control.time, self.time_control.time]
     self.lock = threading.RLock()
Exemplo n.º 8
0
 def start_fen(self, variant, chess960=False):
     # pyffish gives internal color representation for shogi
     # "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL[-] w 0 1"
     if variant == "shogi":
         return SHOGI_FEN
     elif variant == "kyotoshogi":
         return KYOTOSHOGI_FEN
     elif variant == "minishogi":
         return MINISHOGI_FEN
     else:
         if chess960:
             return self.shuffle_start()
         else:
             return sf.start_fen(variant)
Exemplo n.º 9
0
 def test_validate_fen(self):
     # valid
     for variant, positions in variant_positions.items():
         for fen in positions:
             self.assertEqual(sf.validate_fen(fen, variant), sf.FEN_OK, "{}: {}".format(variant, fen))
     # invalid
     for variant, positions in invalid_variant_positions.items():
         for fen in positions:
             self.assertNotEqual(sf.validate_fen(fen, variant), sf.FEN_OK, "{}: {}".format(variant, fen))
     # chess960
     self.assertEqual(sf.validate_fen(CHESS960, "chess", True), sf.FEN_OK, "{}: {}".format(variant, fen))
     self.assertEqual(sf.validate_fen("nrbqbkrn/pppppppp/8/8/8/8/PPPPPPPP/NRBQBKRN w BGbg - 0 1", "newzealand", True), sf.FEN_OK, "{}: {}".format(variant, fen))
     # all variants starting positions
     for variant in sf.variants():
         fen = sf.start_fen(variant)
         self.assertEqual(sf.validate_fen(fen, variant), sf.FEN_OK, "{}: {}".format(variant, fen))
Exemplo n.º 10
0
    def test_short_castling(self):
        legals = [
            'f5f4', 'a7a6', 'b7b6', 'c7c6', 'd7d6', 'e7e6', 'i7i6', 'j7j6',
            'a7a5', 'b7b5', 'c7c5', 'e7e5', 'i7i5', 'j7j5', 'b8a6', 'b8c6',
            'h6g4', 'h6i4', 'h6j5', 'h6f7', 'h6g8', 'h6i8', 'd5a2', 'd5b3',
            'd5f3', 'd5c4', 'd5e4', 'd5c6', 'd5e6', 'd5f7', 'd5g8', 'j8g8',
            'j8h8', 'j8i8', 'e8f7', 'c8b6', 'c8d6', 'g6g2', 'g6g3', 'g6f4',
            'g6g4', 'g6h4', 'g6e5', 'g6g5', 'g6i5', 'g6a6', 'g6b6', 'g6c6',
            'g6d6', 'g6e6', 'g6f6', 'g6h8', 'f8f7', 'f8g8', 'f8i8'
        ]
        moves = [
            'b2b4', 'f7f5', 'c2c3', 'g8d5', 'a2a4', 'h8g6', 'f2f3', 'i8h6',
            'h2h3'
        ]
        result = sf.legal_moves("capablanca", CAPA, moves)
        self.assertCountEqual(legals, result)
        self.assertIn("f8i8", result)

        moves = [
            'a2a4', 'f7f5', 'b2b3', 'g8d5', 'b1a3', 'i8h6', 'c1a2', 'h8g6',
            'c2c4'
        ]
        result = sf.legal_moves("capablanca", CAPA, moves)
        self.assertIn("f8i8", result)

        moves = [
            'f2f4', 'g7g6', 'g1d4', 'j7j6', 'h1g3', 'b8a6', 'i1h3', 'h7h6'
        ]
        result = sf.legal_moves("capablanca", CAPA, moves)
        self.assertIn("f1i1", result)

        # Check that chess960 castling notation is used for otherwise ambiguous castling move
        # d1e1 is a normal king move, so castling has to be d1f1
        result = sf.legal_moves(
            "diana", "rbnk1r/pppbpp/3p2/5P/PPPPPB/RBNK1R w KQkq - 2 3", [])
        self.assertIn("d1f1", result)

        # Test configurable piece perft
        legals = [
            'a3a4', 'b3b4', 'c3c4', 'd3d4', 'e3e4', 'f3f4', 'g3g4', 'e1e2',
            'f1f2', 'b1a2', 'b1b2', 'b1c2', 'c1b2', 'c1c2', 'c1d2', 'a1a2',
            'g1g2', 'd1c2', 'd1d2', 'd1e2'
        ]
        result = sf.legal_moves("yarishogi", sf.start_fen("yarishogi"), [])
        self.assertCountEqual(legals, result)
Exemplo n.º 11
0
    def test_encode_decode(self):
        for idx, variant in enumerate(VARIANTS):
            print(idx, variant)
            variant = variant.rstrip("960")
            FEN = sf.start_fen(variant)
            # fill the pockets with possible pieces
            for empty_pocket in ("[]", "[-]"):
                if empty_pocket in FEN:
                    pocket = "".join([
                        i for i in set(FEN.split()[0])
                        if i in string.ascii_letters and i not in "Kk"
                    ])
                    parts = FEN.split(empty_pocket)
                    FEN = "%s[%s]%s" % (parts[0], pocket, parts[1])

            board = FairyBoard(variant, initial_fen=FEN)
            moves = board.legal_moves()

            saved_restored = decode_moves(encode_moves(moves, variant),
                                          variant)
            self.assertEqual(saved_restored, moves)
Exemplo n.º 12
0
 def start_fen(self, variant, chess960=False):
     if chess960:
         return self.shuffle_start()
     else:
         return sf.start_fen(variant)
Exemplo n.º 13
0
    print(board.fen)
    board.print_pos()
    print(board.legal_moves())

    board = FairyBoard("minishogi")
    print(board.fen)
    board.print_pos()
    print(board.legal_moves())

    board = FairyBoard("kyotoshogi")
    print(board.fen)
    board.print_pos()
    print(board.legal_moves())

    print("--- SHOGUN ---")
    print(sf.start_fen("shogun"))
    board = FairyBoard("shogun")
    for move in ("c2c4", "b8c6", "b2b4", "b7b5", "c4b5", "c6b8"):
        print("push move", move, board.get_san(move))
        if board.move_stack:
            print("is_checked(), insuff material, draw?", board.is_checked(), board.insufficient_material(), board.is_claimable_draw())
        board.push(move)
        board.print_pos()
        print(board.fen)
        print(board.legal_moves())

    FEN = "rnb+fkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNB+FKBNR w KQkq - 0 1"
    board = FairyBoard("shogun", initial_fen=FEN)
    for move in ("c2c4", "h7h6", "c4c5", "h6h5", "c5c6+", "h8h6", "c6b7", "g7g6", "b7a8", "c8a6", "a8b7", "b8c6", "d1b3", "a6e2+", "b3b6", "e7e6", "b6c7", "P@h4", "c7c8", "e2c4", "f1c4", "h6h8", "c4e6+", "g8h6", "b2b4", "h8g8", "b4b5", "g6g5", "b5c6", "f8e7", "c6c7", "d7e6", "c8b8", "B@b6"):
        print("push move", move, board.get_san(move))
        if board.move_stack:
Exemplo n.º 14
0
def sanitize_fen(variant, initial_fen, chess960):
    # Initial_fen needs validation to prevent segfaulting in pyffish
    sanitized_fen = initial_fen

    start_fen = sf.start_fen(variant)  # self.board.start_fen(self.variant)
    start = start_fen.split()
    init = initial_fen.split()

    # Cut off tail
    if len(init) > 6:
        init = init[:6]
        sanitized_fen = " ".join(init)

    # We need starting color
    invalid0 = len(init) < 2

    # Only piece types listed in variant start position can be used later
    if variant == "makruk" or variant == "cambodian":
        non_piece = "~+0123456789[]fF"
    else:
        non_piece = "~+0123456789[]"
    invalid1 = any((c not in start[0] + non_piece for c in init[0]))

    # Required number of rows
    invalid2 = start[0].count("/") != init[0].count("/")

    # Accept zh FEN in lichess format (they use / instead if [] for pockets)
    if invalid2 and variant == "crazyhouse":
        if (init[0].count("/") == 8) and ("[" not in init[0]) and ("]" not in init[0]):
            k = init[0].rfind("/")
            init[0] = init[0][:k] + "[" + init[0][k + 1:] + "]"
            sanitized_fen = " ".join(init)
            invalid2 = False

    # Allowed starting colors
    invalid3 = len(init) > 1 and init[1] not in "bw"

    # Castling rights (and piece virginity) check
    invalid4 = False
    if variant == "seirawan" or variant == "shouse":
        invalid4 = len(init) > 2 and any((c not in "KQABCDEFGHkqabcdefgh-" for c in init[2]))
    elif chess960:
        if all((c in "KQkq-" for c in init[2])):
            chess960 = False
        else:
            invalid4 = len(init) > 2 and any((c not in "ABCDEFGHIJabcdefghij-" for c in init[2]))
    elif variant[-5:] != "shogi":
        invalid4 = len(init) > 2 and any((c not in start[2] + "-" for c in init[2]))

    # Castling right need rooks and king placed in starting square
    if not invalid4:
        rows = init[0].split("/")
        backRankB = rows[1] if (variant == 'shako') else rows[0]
        backRankW = rows[-2] if (variant == 'shako') else rows[-1]
        rookPosQ = 1 if (variant == 'shako') else 0
        rookPosK = -2 if (variant == 'shako') else -1
        if ("q" in init[2] and backRankB[rookPosQ] != 'r') or \
            ("k" in init[2] and backRankB[rookPosK] != 'r') or \
                ("Q" in init[2] and backRankW[rookPosQ] != 'R') or \
                ("K" in init[2] and backRankW[rookPosK] != 'R'):
            invalid4 = True

    # Number of kings
    invalid5 = init[0].count("k") != 1 or init[0].count("K") != 1

    # Opp king already in check
    curr_color = init[1]
    opp_color = "w" if curr_color == "b" else "b"
    init[1] = init[1].replace(curr_color, opp_color)
    board = FairyBoard(variant, " ".join(init), chess960)
    invalid6 = board.is_checked()

    if invalid0 or invalid1 or invalid2 or invalid3 or invalid4 or invalid5 or invalid6:
        print(invalid0, invalid1, invalid2, invalid3, invalid4, invalid5, invalid6)
        sanitized_fen = start_fen
        return False, start_fen
    else:
        return True, sanitized_fen
Exemplo n.º 15
0
def sanitize_fen(variant, initial_fen, chess960):
    # Prevent this particular one to fail on our general sastling check
    if variant == "capablanca" and initial_fen == CONSERVATIVE_CAPA_FEN:
        return True, initial_fen

    # Initial_fen needs validation to prevent segfaulting in pyffish
    sanitized_fen = initial_fen

    start_fen = sf.start_fen(variant)  # self.board.start_fen(self.variant)
    start = start_fen.split()
    init = initial_fen.split()

    # Cut off tail
    if len(init) > 6:
        init = init[:6]
        sanitized_fen = " ".join(init)

    # We need starting color
    invalid0 = len(init) < 2

    # Only piece types listed in variant start position can be used later
    if variant == "dobutsu":
        non_piece = "~+0123456789[]hH-"
    elif variant == "orda":
        non_piece = "~+0123456789[]qH-"
    else:
        non_piece = "~+0123456789[]-"
    invalid1 = any((c not in start[0] + non_piece for c in init[0]))

    # Required number of rows
    invalid2 = start[0].count("/") != init[0].count("/")

    # Accept zh FEN in lichess format (they use / instead if [] for pockets)
    if invalid2 and variant == "crazyhouse":
        if (init[0].count("/") == 8) and ("[" not in init[0]) and ("]" not in init[0]):
            k = init[0].rfind("/")
            init[0] = init[0][:k] + "[" + init[0][k + 1:] + "]"
            sanitized_fen = " ".join(init)
            invalid2 = False

    # Allowed starting colors
    invalid3 = len(init) > 1 and init[1] not in "bw"

    # Castling rights (and piece virginity) check
    invalid4 = False
    if len(init) > 2:
        if variant in ("seirawan", "shouse"):
            invalid4 = any((c not in "KQABCDEFGHkqabcdefgh-" for c in init[2]))
        elif chess960:
            if all((c in "KQkq-" for c in init[2])):
                chess960 = False
            else:
                invalid4 = any((c not in "ABCDEFGHIJabcdefghij-" for c in init[2]))
        elif variant[-5:] != "shogi" and variant not in ("dobutsu", "gorogoro", "gorogoroplus"):
            invalid4 = any((c not in start[2] + "-" for c in init[2]))

        # Castling right need rooks and king placed in starting square
        if (not invalid2) and (not invalid4) and not (chess960 and (variant in ("seirawan", "shouse"))):
            rows = init[0].split("/")
            backRankB = rows[1] if (variant == 'shako') else rows[0]
            backRankW = rows[-2] if (variant == 'shako') else rows[-1]
            # cut off pockets
            k = backRankW.rfind("[")
            if k > 0:
                backRankW = backRankW[:k]
            rookPosQ = 1 if (variant == 'shako') else 0
            rookPosK = -2 if (variant == 'shako') else -1
            if ("q" in init[2] and backRankB[rookPosQ] != 'r') or \
                ("k" in init[2] and backRankB[rookPosK] != 'r') or \
                    ("Q" in init[2] and backRankW[rookPosQ] != 'R') or \
                    ("K" in init[2] and backRankW[rookPosK] != 'R'):
                invalid4 = True

    # Number of kings
    bking = "l" if variant == "dobutsu" else "k"
    wking = "L" if variant == "dobutsu" else "K"
    invalid5 = init[0].count(bking) != 1 or init[0].count(wking) != 1

    # Opp king already in check
    curr_color = init[1]
    opp_color = "w" if curr_color == "b" else "b"
    init[1] = init[1].replace(curr_color, opp_color)
    board = FairyBoard(variant, " ".join(init), chess960)
    invalid6 = board.is_checked()

    if invalid0 or invalid1 or invalid2 or invalid3 or invalid4 or invalid5 or invalid6:
        print(invalid0, invalid1, invalid2, invalid3, invalid4, invalid5, invalid6)
        sanitized_fen = start_fen
        return False, start_fen
    return True, sanitized_fen
Exemplo n.º 16
0
def pgn(doc):
    variant = C2V[doc["v"]]
    mlist = decode_moves(doc["m"], variant)
    chess960 = bool(int(doc.get("z"))) if "z" in doc else False

    if variant[-5:] == "shogi":
        mlist = list(map(uci2usi, mlist))
    elif variant == "xiangqi" or variant == "grand" or variant == "grandhouse" or variant == "shako":
        mlist = list(map(zero2grand, mlist))

    fen = doc[
        "if"] if "if" in doc else SHOGI_FEN if variant == "shogi" else MINISHOGI_FEN if variant == "minishogi" else KYOTOSHOGI_FEN if variant == "kyotoshogi" else sf.start_fen(
            variant)
    mlist = sf.get_san_moves(variant, fen, mlist, chess960)

    moves = " ".join(
        (move if ind % 2 == 1 else "%s. %s" % (((ind + 1) // 2) + 1, move)
         for ind, move in enumerate(mlist)))
    no_setup = fen == STANDARD_FEN and not chess960
    return '[Event "{}"]\n[Site "{}"]\n[Date "{}"]\n[Round "-"]\n[White "{}"]\n[Black "{}"]\n[Result "{}"]\n[TimeControl "{}+{}"]\n[WhiteElo "{}"]\n[BlackElo "{}"]\n[Variant "{}"]\n{fen}{setup}\n{} {}\n'.format(
        "PyChess " + ("rated" if doc["y"] == 1 else "casual") + " game",
        URI + "/" + doc["_id"],
        doc["d"].strftime("%Y.%m.%d"),
        doc["us"][0],
        doc["us"][1],
        C2R[doc["r"]],
        doc["b"] * 60,
        doc["i"],
        doc["p0"]["e"],
        doc["p1"]["e"],
        variant.capitalize() if not chess960 else VARIANT_960_TO_PGN[variant],
        moves,
        C2R[doc["r"]],
        fen="" if no_setup else '[FEN "%s"]\n' % fen,
        setup="" if no_setup else '[SetUp "1"]\n')
Exemplo n.º 17
0
def pgn(doc):
    variant = C2V[doc["v"]]
    mlist = decode_moves(doc["m"], variant)
    if len(mlist) == 0:
        return None

    chess960 = bool(int(doc.get("z"))) if "z" in doc else False

    initial_fen = doc.get("if")
    usi_format = variant.endswith("shogi") and doc.get("uci") is None

    if usi_format:
        # wplayer, bplayer = bplayer, wplayer
        if initial_fen:
            # print("load_game() USI SFEN was:", initial_fen)
            parts = initial_fen.split()
            if len(parts) > 3 and parts[1] in "wb":
                pockets = "[%s]" % parts[2] if parts[2] not in "-0" else ""
                initial_fen = parts[0] + pockets + (
                    " w" if parts[1] == "b" else " b") + " 0 " + parts[3]
            else:
                initial_fen = parts[0] + (" w"
                                          if parts[1] == "b" else " b") + " 0"
            # print("   changed to:", initial_fen)

    if usi_format and variant == "shogi":
        mirror = mirror9
        mlist = list(map(mirror, mlist))

    elif usi_format and (variant == "minishogi" or variant == "kyotoshogi"):
        mirror = mirror5
        mlist = list(map(mirror, mlist))

    elif variant == "xiangqi" or variant == "grand" or variant == "grandhouse" or variant == "shako" or variant == "janggi":
        mlist = list(map(zero2grand, mlist))

    fen = initial_fen if initial_fen is not None else sf.start_fen(variant)
    # print(variant, fen, mlist)
    try:
        mlist = sf.get_san_moves(variant, fen, mlist, chess960)
    except Exception:
        try:
            mlist = sf.get_san_moves(variant, fen, mlist[:-1], chess960)
        except Exception:
            log.error("Movelist contains invalid move %s" % mlist)
            mlist = mlist[0]

    moves = " ".join(
        (move if ind % 2 == 1 else "%s. %s" % (((ind + 1) // 2) + 1, move)
         for ind, move in enumerate(mlist)))
    no_setup = fen == STANDARD_FEN and not chess960
    # Use lichess format for crazyhouse games to support easy import
    setup_fen = fen if variant != "crazyhouse" else fen.replace("[]", "")

    return '[Event "{}"]\n[Site "{}"]\n[Date "{}"]\n[Round "-"]\n[White "{}"]\n[Black "{}"]\n[Result "{}"]\n[TimeControl "{}+{}"]\n[WhiteElo "{}"]\n[BlackElo "{}"]\n[Variant "{}"]\n{fen}{setup}\n{} {}\n'.format(
        "PyChess " + ("rated" if "y" in doc and doc["y"] == 1 else "casual") +
        " game",
        URI + "/" + doc["_id"],
        doc["d"].strftime("%Y.%m.%d"),
        doc["us"][0],
        doc["us"][1],
        C2R[doc["r"]],
        doc["b"] * 60,
        doc["i"],
        doc["p0"]["e"] if "p0" in doc else "?",
        doc["p1"]["e"] if "p1" in doc else "?",
        variant.capitalize() if not chess960 else VARIANT_960_TO_PGN[variant],
        moves,
        C2R[doc["r"]],
        fen="" if no_setup else '[FEN "%s"]\n' % setup_fen,
        setup="" if no_setup else '[SetUp "1"]\n')
Exemplo n.º 18
0
    def __init__(self,
                 app,
                 gameId,
                 variant,
                 initial_fen,
                 wplayer,
                 bplayer,
                 base=1,
                 inc=0,
                 level=0,
                 rated=False,
                 chess960=False):
        self.db = app["db"]
        self.users = app["users"]
        self.games = app["games"]
        self.tasks = app["tasks"]
        self.highscore = app["highscore"]
        self.saved = False
        self.variant = variant
        self.initial_fen = initial_fen
        self.wplayer = wplayer
        self.bplayer = bplayer
        self.rated = rated
        self.base = base
        self.inc = inc
        self.level = level if level is not None else 0
        self.chess960 = chess960

        self.white_rating = wplayer.get_rating(variant, chess960)
        self.wrating = "%s%s" % (int(
            round(self.white_rating.mu,
                  0)), "?" if self.white_rating.phi > PROVISIONAL_PHI else "")
        self.wrdiff = 0
        self.black_rating = bplayer.get_rating(variant, chess960)
        self.brating = "%s%s" % (int(
            round(self.black_rating.mu,
                  0)), "?" if self.black_rating.phi > PROVISIONAL_PHI else "")
        self.brdiff = 0

        self.spectators = set()
        self.draw_offers = set()
        self.rematch_offers = set()
        self.messages = collections.deque([], 200)
        self.date = datetime.utcnow()

        self.ply_clocks = [{
            "black": (base * 1000 * 60) + 0 if base > 0 else inc * 1000,
            "white": (base * 1000 * 60) + 0 if base > 0 else inc * 1000,
            "movetime":
            0
        }]
        self.dests = {}
        self.promotions = []
        self.lastmove = None
        self.check = False
        self.status = CREATED
        self.result = "*"
        self.bot_game = False
        self.last_server_clock = monotonic()

        self.id = gameId
        # print("Game", self.variant, self.initial_fen, self.chess960)

        # Initial_fen needs validation to prevent segfaulting in pyffish
        if self.initial_fen:
            start_fen = sf.start_fen(
                self.variant)  # self.board.start_fen(self.variant)
            start = start_fen.split()
            init = self.initial_fen.split()

            # Cut off tail
            if len(init) > 6:
                init = init[:6]
                self.initial_fen = " ".join(init)

            # We need starting color
            invalid0 = len(init) < 2

            # Only piece types listed in variant start position can be used later
            invalid1 = any(
                (c not in start[0] + "~+" for c in init[0] if not c.isdigit()))

            # Required number of rows
            invalid2 = start[0].count("/") != init[0].count("/")

            # Allowed starting colors
            invalid3 = len(init) > 1 and init[1] not in "bw"

            # Castling rights (and piece virginity) check
            invalid4 = False
            if self.variant == "seirawan" or self.variant == "shouse":
                invalid4 = len(init) > 2 and any(
                    (c not in "KQABCDEFGHkqabcdefgh-" for c in init[2]))
            elif self.chess960:
                if all((c in "KQkq-" for c in init[2])):
                    self.chess960 = False
                else:
                    invalid4 = len(init) > 2 and any(
                        (c not in "ABCDEFGHIJabcdefghij-" for c in init[2]))
            elif self.variant[-5:] != "shogi":
                invalid4 = len(init) > 2 and any(
                    (c not in start[2] + "-" for c in init[2]))

            if invalid0 or invalid1 or invalid2 or invalid3 or invalid4:
                log.error("Got invalid initial_fen %s for game %s" %
                          (self.initial_fen, self.id))
                print(invalid0, invalid1, invalid2, invalid3, invalid4)
                self.initial_fen = start_fen

        if self.chess960 and self.initial_fen:
            if self.wplayer.fen960_as_white == self.initial_fen:
                self.initial_fen = ""

        self.board = self.create_board(self.variant, self.initial_fen,
                                       self.chess960)
        self.initial_fen = self.board.initial_fen
        self.wplayer.fen960_as_white = self.initial_fen

        self.bot_game = self.bplayer.bot or self.wplayer.bot
        self.random_mover = self.wplayer.username == "Random-Mover" or self.bplayer.username == "Random-Mover"
        self.random_move = ""

        self.set_dests()
        if self.board.move_stack:
            self.check = self.board.is_checked()

        self.steps = [{
            "fen":
            self.initial_fen if self.initial_fen else self.board.initial_fen,
            "san":
            None,
            "turnColor":
            "black" if self.board.color == BLACK else "white",
            "check":
            self.check
        }]

        self.stopwatch = Clock(self)