示例#1
0
class TestStockfish(unittest.TestCase):
    def setUp(self):
        self.stockfish = Stockfish()

    def test_get_best_move(self):
        best_move = self.stockfish.get_best_move()
        self.assertIn(best_move, (
            'e2e4',
            'g1f3',
        ))

        self.stockfish.set_position(['e2e4', 'e7e6'])
        best_move = self.stockfish.get_best_move()
        self.assertIn(best_move, (
            'd2d4',
            'g1f3',
        ))

        # mate
        self.stockfish.set_position(['f2f3', 'e7e5', 'g2g4', 'd8h4'])
        self.assertFalse(self.stockfish.get_best_move())

    def test_is_move_correct(self):
        self.assertFalse(self.stockfish.is_move_correct('e2e1'))
        self.assertTrue(self.stockfish.is_move_correct('a2a3'))
        self.stockfish.set_position(['e2e4', 'e7e6'])
        self.assertFalse(self.stockfish.is_move_correct('e2e1'))
        self.assertTrue(self.stockfish.is_move_correct('a2a3'))
示例#2
0
class TestStockfish(unittest.TestCase):
    def setUp(self):
        self.stockfish = Stockfish()

    def test_get_best_move(self):
        best_move = self.stockfish.get_best_move()
        self.assertIn(best_move, (
            'e2e4',
            'g1f3',
            'b1c3',
        ))

        self.stockfish.set_position(['e2e4', 'e7e6'])
        best_move = self.stockfish.get_best_move()
        self.assertIn(best_move, (
            'd2d4',
            'g1f3',
        ))

        # mate
        self.stockfish.set_position(['f2f3', 'e7e5', 'g2g4', 'd8h4'])
        self.assertFalse(self.stockfish.get_best_move())

    def test_set_fen_position(self):
        self.stockfish.set_fen_position(
            "7r/1pr1kppb/2n1p2p/2NpP2P/5PP1/1P6/P6K/R1R2B2 w - - 1 27")
        self.assertTrue(self.stockfish.is_move_correct('f4f5'))
        self.assertFalse(self.stockfish.is_move_correct('a1c1'))

    def test_is_move_correct(self):
        self.assertFalse(self.stockfish.is_move_correct('e2e1'))
        self.assertTrue(self.stockfish.is_move_correct('a2a3'))
        self.stockfish.set_position(['e2e4', 'e7e6'])
        self.assertFalse(self.stockfish.is_move_correct('e2e1'))
        self.assertTrue(self.stockfish.is_move_correct('a2a3'))
示例#3
0
class TestStockfish(unittest.TestCase):

    def setUp(self):
        self.stockfish = Stockfish()

    def test_get_best_move(self):
        best_move = self.stockfish.get_best_move()
        self.assertIn(best_move, ('e2e4', 'g1f3',))

        self.stockfish.set_position(['e2e4', 'e7e6'])
        best_move = self.stockfish.get_best_move()
        self.assertIn(best_move, ('d2d4', 'g1f3',))

        # mate
        self.stockfish.set_position(['f2f3', 'e7e5', 'g2g4', 'd8h4'])
        self.assertFalse(self.stockfish.get_best_move())

    def test_is_move_correct(self):
        self.assertFalse(self.stockfish.is_move_correct('e2e1'))
        self.assertTrue(self.stockfish.is_move_correct('a2a3'))
        self.stockfish.set_position(['e2e4', 'e7e6'])
        self.assertFalse(self.stockfish.is_move_correct('e2e1'))
        self.assertTrue(self.stockfish.is_move_correct('a2a3'))
示例#4
0
class ChessGame:
    def __init__(self, fen):
        """ constructor taking initial FEN position""" 
        self.d_engine = Stockfish()
        self.setFen(fen)

    def setFen(self, fen):
        """ set board in fen notation """
        self.d_engine.set_fen(fen)

    def move(self, algMove):
        """ move in long algebraic notation, send to stockfish """
        if self.d_engine.is_move_correct(algMove):
            print("correct")

    def bestMove(self):
        return self.d_engine.get_best_move()
示例#5
0
class ChessGame:
    def __init__(self, fen):
        """ constructor taking initial FEN position"""
        self.d_engine = Stockfish()
        self.setFen(fen)

    def setFen(self, fen):
        """ set board in fen notation """
        self.d_engine.set_fen(fen)

    def move(self, algMove):
        """ move in long algebraic notation, send to stockfish """
        if self.d_engine.is_move_correct(algMove):
            print("correct")

    def bestMove(self):
        return self.d_engine.get_best_move()
示例#6
0
class Game:
    def __init__(self):
        self.engine = Stockfish()
        self.board = Board()

    def sync_engine(self):
        self.engine.set_position(self.board.move_list)

    def get_best_move(self) -> str:
        return self.engine.get_best_move()

    def is_move_correct(self, move: str) -> bool:
        return self.engine.is_move_correct(move)

    def make_move(self, move) -> bool:
        if self.is_move_correct(move):
            self.board.make_move(move)
            self.sync_engine()
            return True
        else:
            return False

    def make_best_move(self):
        self.make_move(self.get_best_move())
示例#7
0
""" Before running do
    pip install stockfish
    to get the stockfish python interface """

from stockfish import Stockfish

stockfish = Stockfish()
stockfish.set_position(['e2e4', 'e7e6'])
stockfish.depth = 20
print(stockfish.get_best_move())
print(stockfish.is_move_correct('a2a3'))
示例#8
0
 def get_move_from_board_states(board_state_before, board_state_after,
                                previous_moves, chess_engine: Stockfish):
     """
     Determine the move given the state before the move and the state after the move.
     """
     # Determine the sids in the prev state that differ in the current state
     changed_before = [
         sid for sid in board_state_before if sid not in board_state_after
         or board_state_after[sid] != board_state_before[sid]
     ]
     # Determine the sids in the current state that differ from the prev state
     changed_after = [
         sid for sid in board_state_after if sid not in board_state_before
         or board_state_after[sid] != board_state_before[sid]
     ]
     # Check for promoted pieces
     promoted_piece = None
     pieces_before = ''.join(
         sorted([
             p for p in board_state_before.values()
             if p in Board.get_white_pieces()
         ]))
     pieces_after = ''.join(
         sorted([
             p for p in board_state_after.values()
             if p in Board.get_white_pieces()
         ]))
     if pieces_before != pieces_after:
         differing_pieces = pieces_before + pieces_after
         for p in pieces_before:
             if p in pieces_after:
                 differing_pieces.replace(p, '', 2)
         log.info(
             f"Found differing pieces between states: {differing_pieces}")
         potential_piece = differing_pieces.replace('p', '')
         if len(differing_pieces
                ) != 2 or 'p' not in differing_pieces or len(
                    potential_piece) != 1:
             raise InvalidMove('Piece promotion is invalid.')
         promoted_piece = potential_piece
     # If no change raise exception
     if len(changed_before) == 0 or len(changed_after) == 0:
         raise NoMoveFound()
     # If more than one sid was changed in the after board state this could be a castling move
     if len(changed_after) != 1:
         # Construct a set of all the pieces involved in the move
         pieces_moved = set([board_state_before[k]
                             for k in changed_before] +
                            [board_state_after[k] for k in changed_after])
         # Check if the move is a castling move
         is_castling_move = len(pieces_moved) == 2 and (
             ('r' in pieces_moved and 'k' in pieces_moved) or
             ('R' in pieces_moved and 'K' in pieces_moved))
         # If it is a castling move, filter out board state changes that are not related to the king
         if is_castling_move:
             log.info('Castling move detected.')
             board_state_before = {
                 k: board_state_before[k]
                 for k in board_state_before
                 if (board_state_before[k] == 'k'
                     or board_state_before[k] == 'K')
             }
             board_state_after = {
                 k: board_state_after[k]
                 for k in board_state_after
                 if (board_state_after[k] == 'k'
                     or board_state_after[k] == 'K')
             }
             changed_before = [
                 sid for sid in board_state_before
                 if sid not in board_state_after
                 or board_state_after[sid] != board_state_before[sid]
             ]
             changed_after = [
                 sid for sid in board_state_after
                 if sid not in board_state_before
                 or board_state_after[sid] != board_state_before[sid]
             ]
         else:
             raise InvalidMove('Move affected too many sids.')
     # Get the move end sid
     e_sid = changed_after[0]
     piece_moved = board_state_after[
         e_sid] if promoted_piece is None else promoted_piece
     # Find the move start sid
     s_sid = None
     for sid in changed_before:
         if board_state_before[sid] == piece_moved:
             s_sid = sid
     if s_sid is None:
         raise InvalidMove('Could not find move start.')
     move = f"{s_sid}{e_sid}{promoted_piece if promoted_piece is not None else ''}"
     # Verify that the move is valid
     chess_engine.set_position(previous_moves)
     if not chess_engine.is_move_correct(move):
         raise InvalidMove(f"Move {move} is invalid.")
     return move
示例#9
0
class Game:  # handles game logic + interacts with stockfish
    def __init__(self):
        abs_path = os.path.dirname(__file__)  # local path
        rel_path = 'stockfish-10-win/stockfish-10-win/stockfish_x86-64-modern.exe'
        self.sf = Stockfish(os.path.join(
            abs_path, rel_path))  # pull the engine from compiled file
        self.m_skill_level = 0  # skill level of engine
        self.m_cur_turn = 0  # 0 for player turn, 1 for computer turn
        self.m_in_game = False  # see if we're still in game
        self.m_move_his = []  # move history to update position in stockfish
        self.num_moves = 0  # number of moves (extraneous, may remove)
        self.set_skill_level(
            self.request_skill_level())  # request a skill level for engine
        self.choose_side(self.request_side())  # request a starting side
        self.m_starting_side = 0
        self.m_board = Board(self.m_cur_turn)

    def set_skill_level(self, d_level):  # function to set a skill level
        self.sf.set_skill_level(d_level)
        self.m_skill_level = d_level

    def choose_side(self, d_side):  # function to set a starting side
        self.m_cur_turn = d_side
        self.m_starting_side = d_side

    def check_for_mate(
        self, val
    ):  # function periodically checks if there is a checkmate and ends game if true
        # we can check for checkmate by looking at what stockfish thinks is the best move
        # if stockfish says only 1 move is the best move, we're in check
        # if no move is the best move, we're in checkmate.
        moves = self.sf.get_best_move()
        mate = 0
        print(moves)
        if moves == None:
            mate = 1
        return mate

    def check_for_castle(self, start, end):
        r_a = 0
        r_b = 0
        if start == 60:  # black side
            print('black king \n')
            if (start - end) == -2:  # castled 'h' rook
                r_a = 63
                r_b = 61
            else:  # castled 'a' rook
                r_a = 56
                r_b = 59
        elif start == 4:  # white side
            if (start - end) == -2:  # h rook
                r_a = 7
                r_b = 5
            else:
                r_a = 0
                r_b = 3
        self.m_board.change_pos(r_a, r_b)
        return 1

    def updateBoard(self, move):
        # first two characters of move are start, last two are end
        start_pos = move[:2]
        ind_pos_s = (ord(start_pos[0]) - 97) + ((int(start_pos[1]) - 1) * 8)
        end_pos = move[2:4]
        ind_pos_e = (ord(end_pos[0]) - 97) + ((int(end_pos[1]) - 1) * 8)

        # check for special moves occuring
        # check if a king in its original position has moved.
        print('Index: ' + str(ind_pos_s) + '\n' + 'Type: ' +
              str(self.m_board.get_piece_at(ind_pos_s)) + '\n\n\n\n')
        if (self.m_board.get_piece_at(ind_pos_s) == 1):
            print('castling!')
            self.check_for_castle(ind_pos_s, ind_pos_e)
        self.m_board.change_pos(ind_pos_s, ind_pos_e)
        return 1

    def endGame(self, ):
        # if mate is triggered, loser will be whoever's current turn it is
        win = 0
        w_side = 0
        if self.m_cur_turn == 0:  # white lost
            w_side = 1
            if self.m_cur_turn != self.m_starting_side:
                win = 1
        else:  # black lost
            if self.m_cur_turn != self.m_starting_side:
                win = 1
        if win:
            print('you won!')
        else:
            print('you lost!')
        return 1

    def request_side(self, ):  # prompts user for choosing a starting side
        side_set = False
        side = "white"
        count = 0
        c_side = 0
        while not side_set and count < 5:
            count = count + 1
            side = input('Which side? (type in white, black or random): ')
            if side == 'white' or side == 'black' or side == 'random':
                if side == 'black':
                    # if black, computer goes first
                    c_side = 1
                elif side == 'white':
                    # if white, player goes first
                    c_side = 0
                else:
                    if (random.randint(0, 999) / 100) > 5:
                        c_side = 1
                    else:
                        c_side = 0
                side_set = True
            elif count == 5:
                print("Setting to default side of white.")
                c_side = 0
                side_set = True
            else:
                print("Invalid input" + "\n")
        return c_side

    def request_skill_level(
        self, ):  # prompts user for inputting a skill level for engine
        level_set = False
        count = 0
        while not level_set and count < 5:
            count = count + 1
            skill = input(
                'What skill level? (integers between 1 and 21 inclusive): ')
            if skill.isdigit() and int(skill) > 0 and int(skill) < 22:
                level_set = True
            elif count == 5:
                print("Setting to default of skill level 5.")
                skill = 5
            else:
                print("Invalid input" + "\n")
        return skill

    def run(self, ):
        print('Game is now starting.')
        in_game = True
        # start game
        self.m_board.print_board_state()
        while in_game:
            # check if currently in checkmate (to end game)
            mate = self.check_for_mate()
            if mate:  # game is now over
                break
            turn = "your" if self.m_cur_turn == 0 else "the computer's"
            print("It is now " + turn + " turn." + "\n")
            if self.m_cur_turn == 0:
                move_done = 0
                while not move_done:
                    move = input('Enter your move: ' + '\n').strip()
                    # first check if valid move format (letter + number + letter + number)
                    valid = re.search(rule, move)
                    if valid and self.sf.is_move_correct(move):
                        # valid move syntax and able to be made
                        self.m_move_his.append(move)
                        self.sf.set_position(self.m_move_his)
                        print("You entered the move: " + move + '\n')
                        move_done = 1
                    else:
                        print("Invalid move, please enter a different move." +
                              '\n')
                self.m_cur_turn = 1
            else:  # computer's turn
                move = self.sf.get_best_move()
                print("The computer moves: " + move + '\n')
                self.m_move_his.append(move)
                self.sf.set_position(self.m_move_his)
                self.m_cur_turn = 0
            self.num_moves = self.num_moves + 1
            self.updateBoard(move)
            self.m_board.print_board_state()
        self.endGame()