Esempio n. 1
0
    def make_hypothetical_move(start, finish, chessboard):
        """
        Make a hypothetical move, this will be used to generate the possibilities to be
        stored in the chess tree

        This method has a ton of redundant code with the make_move() method 
        so I should probably 
        
        input:
        starting coordinate: example "e4"
        ending coordinate: example "e5"
        chessboard: chessboard that you want to move
        
        output:
        "Move success" or "Move invalid"
        
        Uses the RulesEnforcer() to make sure that the move is valid
        
        """
        #deepcopy the chessboard so that it does not affect the original
        mychessboard = copy.deepcopy(chessboard[:])

        #map start and finish to gameboard coordinates
        start = RulesEnforcer.coordinate_mapper(start)
        finish = RulesEnforcer.coordinate_mapper(finish)

        #need to move alot of this logic to the rules enforcer
        start_cor0 = start[0]
        start_cor1 = start[1]

        finish_cor0 = finish[0]
        finish_cor1 = finish[1]

        #check if destination is white, black or empty
        start_color = mychessboard[start_cor0][start_cor1].split('-')[0]
        start_piece = mychessboard[start_cor0][start_cor1].split('-')[1]

        #check if destination is white, black or empty
        destination_color = mychessboard[finish_cor0][finish_cor1].split(
            '-')[0]
        destination_piece = mychessboard[finish_cor0][finish_cor1].split(
            '-')[1]

        #cannot move if starting square is empty
        if start_color == '0':
            return "Starting square is empty!"

        mypiece = mychessboard[start_cor0][start_cor1]
        mychessboard[start_cor0][start_cor1] = '0-0'
        mychessboard[finish_cor0][finish_cor1] = mypiece

        return mychessboard
Esempio n. 2
0
    def __init__(self, ai_depth):
        """
        Creates a chessboard with pieces
        
        params:
        ai_depth: max number of moves to search into the future
        
        Notation:
        ------------
        000 == empty space  
        
        "b-p"   == black pawn
        "b-r"   == black rook
        "b-r"   == black rook
        "b-n"   == black knight
        "b-b"   == black bishop
        "b-q"   == black queen
        "b-k"   == black king  
        
        "w-k"   == white king

        ... etc etc you get the idea
        
        
        As soon as the chess game is initialized, the chess computer will start calculating

        """

        ChessAi.__init__(self, ai_depth)
        RulesEnforcer.__init__(self)
        #super(ChessGame, self).__init__()

        self.ai_depth = ai_depth

        #initialize the chessboard
        self.chessboard = [["0-0"] * 8 for i in range(8)]
        """Track aspects of the game"""
        #track which pieces have been taken
        self.white_taken = []
        self.black_taken = []

        #track which moves have been made in the game, key: move number, value: len 2 list of white and black move
        self.moves_made = {}

        #track the number of moves made
        self.move_count = 0

        #track whose turn it is (white always starts)
        self.current_turn = "w"

        #create pawns
        for i in range(8):
            self.chessboard[1][i] = 'b-p'
            self.chessboard[6][i] = 'w-p'

        #create rooks
        self.chessboard[0][0] = 'b-r'
        self.chessboard[0][7] = 'b-r'
        self.chessboard[7][0] = 'w-r'
        self.chessboard[7][7] = 'w-r'

        #create knights
        self.chessboard[0][1] = 'b-n'
        self.chessboard[0][6] = 'b-n'
        self.chessboard[7][1] = 'w-n'
        self.chessboard[7][6] = 'w-n'

        #create bishops
        self.chessboard[0][2] = 'b-b'
        self.chessboard[0][5] = 'b-b'
        self.chessboard[7][2] = 'w-b'
        self.chessboard[7][5] = 'w-b'

        #create queen and king
        self.chessboard[0][3] = 'b-q'
        self.chessboard[0][4] = 'b-k'
        self.chessboard[7][3] = 'w-q'
        self.chessboard[7][4] = 'w-k'

        self.game_over = False
Esempio n. 3
0
    def make_move(self, start, finish):
        """
        Make a move
        
        input:
        starting coordinate: example "e4"
        ending coordinate: example "e5"
        
        output:
        "Move success" or "Move invalid", self.chessboard is updated with the move made
        
        Uses the RulesEnforcer() to make sure that the move is valid
        
        """

        #map start and finish to gameboard coordinates
        start = RulesEnforcer.coordinate_mapper(start)
        finish = RulesEnforcer.coordinate_mapper(finish)

        #need to move alot of this logic to the rules enforcer
        start_cor0 = start[0]
        start_cor1 = start[1]

        finish_cor0 = finish[0]
        finish_cor1 = finish[1]

        #check if destination is white, black or empty
        start_color = self.chessboard[start_cor0][start_cor1].split('-')[0]
        start_piece = self.chessboard[start_cor0][start_cor1].split('-')[1]

        #check if destination is white, black or empty
        destination_color = self.chessboard[finish_cor0][finish_cor1].split(
            '-')[0]
        destination_piece = self.chessboard[finish_cor0][finish_cor1].split(
            '-')[1]

        #cannot move if starting square is empty
        if start_color == '0':
            return "Starting square is empty!"

        #cannot move the other person's piece
        if self.current_turn != start_color:
            return "Cannot move the other person's piece!"

        #cannot take your own piece
        if self.current_turn == destination_color:
            return "invalid move, cannot take your own piece!"
        elif self.current_turn != destination_color and destination_color != '0':
            if destination_piece == 'k':
                self.game_over = True
                return "game over, " + self.current_turn + " has won"
            elif self.current_turn == 'w':
                self.black_taken.append(destination_piece)
            elif self.current_turn == 'b':
                self.white_taken.append(destination_piece)
        else:
            pass

        mypiece = self.chessboard[start_cor0][start_cor1]
        self.chessboard[start_cor0][start_cor1] = '0-0'
        self.chessboard[finish_cor0][finish_cor1] = mypiece

        #if the move is a success, change the turn state
        if self.current_turn == "w":
            self.current_turn = "b"
        elif self.current_turn == "b":
            self.current_turn = "w"

        return self.chessboard
Esempio n. 4
0
    def tree_generator(self, depth_override=None):
        """
        Brute force tree generation.  Generates all possible moves (will probably need to add pruning later) 
        
        input: current chess position (8 x 8 2d array)
        output: returns nothing but sets the current game state at self.current_game_state
        
        My Notes:
        We should be able to use the position_evaluator to prune and make the tree generation smarter...
        
        Tree generation needs to be done carefully, if we just generate trees based on all possible moves, 
        the size of the tree can easily explode.
        
        For example, just assuming that we have around 20 possible moves at each turn, after around 6 moves the size
        of the tree explodes to 64 million moves (20^6).  This is crazy!
        
        If I can somehow narrow down the tree search to about 5 moves per tree, 
        then the size of the tree can be drastically reduced, 
        and I could possible compute 10 moves into the future without running out of memory 
        or taking up too much CPU power.
        I guess after the second move, I don't really need to store the position in the tree, I can just store the score...
        
        For the first iteration, just calculate three moves into the future

        """

        #first, lets try to look one move into the future.  Then we will expand the AI to look more moves into the future

        #initialize the tree by putting the current state into the parent node of the chessboard.
        self.current_game_state = TreeNode([copy.deepcopy(self.chessboard), 0])
        current_positions = [self.current_game_state]

        #track the number of moves into the future you are calculating.
        current_depth = 1

        #override the target depth if depth is explicitly defined
        target_depth = depth_override or self.depth

        #get the current turn
        current_turn = copy.copy(self.current_turn)

        #keep searching until the desired AI depth has been reached.
        while current_depth <= target_depth:
            for position in current_positions:
                #returns a dictionary of possible chess moves
                pos_moves = RulesEnforcer.all_possible_moves(
                    position.data[0], current_turn)

                #now we need to generate all possible moves in the future...
                #we will do this by iterating through the pos moves dictionary
                for start, moves in pos_moves.items():
                    for move in moves:
                        current_pos = position.data[0]
                        new_pos = ChessAi.make_hypothetical_move(
                            start, move, current_pos)

                        if current_turn == 'w':
                            score = ChessAi.position_evaluator(new_pos)
                        else:
                            #if black, store the negative score because black wants to play the best move
                            score = -ChessAi.position_evaluator(new_pos)

                        if current_depth > 1:
                            position.add_child([new_pos, score])
                        else:
                            position.add_child([new_pos, score, start, move])

            current_depth += 1

            #now, populate the new current positions list
            new_positions = []
            for position in current_positions:
                new_positions += position.children
            current_positions = new_positions

            #now, switch the turn
            if current_turn == 'w':
                current_turn = 'b'
            else:
                current_turn = 'w'

        #run the heuristic algorithm on the list of possible moves you can make to narrow down your search space.
        #hmm...the problem with this is that unless the heuristic algorithm is very good
        #you might miss out on really good moves such as a queen sacrifice...I'm not sure what to do here...
        #pos_evaluated is an array of ints representing the quality of the moves e.g. [3,4,5,6,4]
        """
Esempio n. 5
0
    def __init__(self, payload, invalidPQ):
        """
        Creates a chessboard with pieces
        
        params:
        ai_depth: max number of moves to search into the future
        
        Notation:
        ------------
        000 == empty space  
        
        "b-p"   == black pawn
        "b-r"   == black rook
        "b-r"   == black rook
        "b-n"   == black knight
        "b-b"   == black bishop
        "b-q"   == black queen
        "b-k"   == black king  
        
        "w-k"   == white king

        ... etc etc you get the idea
        
        
        As soon as the chess game is initialized, the chess computer will start calculating

        """

        ChessAi.__init__(self, payload['level'])
        RulesEnforcer.__init__(self)
        #super(ChessGame, self).__init__()

        self.ai_depth = payload['level']

        chessboard1 = [["0-0"] * 12 for i in range(12)]

        self.invalidPQ = invalidPQ

        def fill(color, code, position):
            chessboard1[position[0]][position[1]] = color + '-'
            if code == 'rook':
                chessboard1[position[0]][position[1]] += 'r'
            elif code == 'pawn':
                chessboard1[position[0]][position[1]] += 'p'
            elif code == 'knight':
                chessboard1[position[0]][position[1]] += 'n'
            elif code == 'bishop':
                chessboard1[position[0]][position[1]] += 'b'
            elif code == 'queen':
                chessboard1[position[0]][position[1]] += 'q'
            elif code == 'king':
                chessboard1[position[0]][position[1]] += 'k'

        def okPQ(i, j):
            for k in range(len(self.invalidPQ)):
                if i == self.invalidPQ[k][0] and j == self.invalidPQ[k][1]:
                    return False
            return True

        #initialize the chessboard
        self.chessboard = [["0-0"] * 8 for i in range(8)]

        y = payload['board']
        for row in y:
            for column, values in row.items(
            ) if type(row) is dict else enumerate(row):
                if values['ai'] == True:
                    fill('b', values['code'], values['position'])
                else:
                    fill('w', values['code'], values['position'])
        """Track aspects of the game"""
        #track which pieces have been taken
        self.white_taken = []
        self.black_taken = []

        #track whose turn it is (white always starts)
        self.current_turn = "b"

        maxCounter = 0
        self.finalP = 0
        self.finalQ = 0
        for p in range(4):
            for q in range(4):
                if okPQ(p, q):
                    counter = 0
                    hasAiPiece = False
                    hasKing = False
                    hasOpponentPiece = False
                    for i in range(8):
                        for j in range(8):
                            if chessboard1[i + p][j + q] != '0-0':
                                counter += 1
                            if chessboard1[i + p][j + q][0] == 'b':
                                hasAiPiece = True
                            if chessboard1[i + p][j +
                                                  q][2] == 'k' and chessboard1[
                                                      i + p][j + q][0] == 'w':
                                hasKing = True
                            if chessboard1[i + p][j + q][0] == 'w':
                                hasOpponentPiece = True
                    if counter > maxCounter and hasAiPiece and hasKing and hasOpponentPiece:
                        maxCounter = counter
                        self.finalP = p
                        self.finalQ = q

        for i in range(8):
            for j in range(8):
                self.chessboard[i][j] = chessboard1[i +
                                                    self.finalP][j +
                                                                 self.finalQ]

        self.game_over = False