Ejemplo n.º 1
0
 def maxABValue(self, board, ply, turn, alpha, beta):
     """ Find the alpha-beta value for the next move for this player
         at a given board configuation. Returns score."""
     if board.gameOver():
         return turn.score(board)
     score = -INFINITY
     for m in board.legalMoves(self):
         if ply == 0:
             #print "turn.score(board) in beta Value is: " + str(turn.score(board))
             return turn.score(board)
         # make a new player to play the other side
         opponent = Player(self.opp, self.type, self.ply)
         # Copy the board so that we don't ruin it
         nextBoard = cp.deepcopy(board)
         nextBoard.makeMove(self, m)
         #score is the larger value between the old score and the value created by the function minABValue called on opp
         score = max(
             score,
             opponent.minABValue(nextBoard, ply - 1, turn, alpha, beta))
         #if new score is larger than old betaValue prune rest of tree branch
         if (score >= beta):
             return score
         #update alpha
         alpha = max(alpha, score)
         #print "score in maxABValue is: " + str(s)
     return score
Ejemplo n.º 2
0
    def minimax(self, game, phasing_player, depth=0, move=None):
        game_over = game.game_over()
        if game_over or depth is self.maximum_depth:
            return [self.minimax_score(game, depth, game_over), move]

        depth += 1

        scores = []
        moves = []
        legal_moves = game.get_legal_moves(phasing_player)
        last_move = game.game_board_log[-1]
        next_player = self.get_opposite_player(phasing_player)

        print(
            f"------Depth {depth} Player {phasing_player} Legal moves: {legal_moves}"
        )

        for move in legal_moves:
            possible_game = MancalaBoard(6, 6, last_move)
            take_another_turn = possible_game.play(phasing_player, move)

            if take_another_turn is True:
                next_player = phasing_player

            score = self.minimax(possible_game, next_player, depth, move)[0]
            scores.append(score)
            moves.append(move)

        # Do the min or max calculation
        if phasing_player == self.player_number:
            score_index = scores.index(max(scores))
            return [max(scores), moves[int(score_index)]]
        else:
            score_index = scores.index(min(scores))
            return [min(scores), moves[int(score_index)]]
Ejemplo n.º 3
0
 def alphaBetaMove(self, board, ply):
     """ Choose a move with alpha beta pruning.  Returns (score, move) """
     move = -1
     alpha = -INFINITY
     beta = INFINITY
     score = -INFINITY
     turn = self
     for m in board.legalMoves(self):
         #for each legal move
         if ply == 0:
             #if we're at ply 0, we need to call our eval function & return
             return (self.score(board), m)
         if board.gameOver():
             return (-1, -1)  # Can't make a move, the game is over
         nb = cp.deepcopy(board)
         #make a new board
         nb.makeMove(self, m)
         #try the move
         opp = Player(self.opp, self.type, self.ply)
         s = opp.minABValue(nb, ply - 1, turn, alpha, beta)
         #and see what the opponent would do next
         if s > score:
             #if the result is better than our best score so far, save that move,score
             move = m
             score = s
         alpha = max(score, alpha)
     #return the best score and move so far
     return score, move
Ejemplo n.º 4
0
 def minABValue(self, board, ply, turn, alpha, beta):
     """ Find the alpha-beta value for the next move for this player
     at a given board configuation. Returns score."""
     if board.gameOver():
         return turn.score(board)
     score = INFINITY
     for m in board.legalMoves(self):
         if ply == 0:
             #print "turn.score(board) in minValue is: " + str(turn.score(board))
             return turn.score(board)
         # make a new player to play the other side
         opponent = Player(self.opp, self.type, self.ply)
         # Copy the board so that we don't ruin it
         nextBoard = cp.deepcopy(board)
         nextBoard.makeMove(self, m)
         #new score is the min value between old score and value when you call maxAB val on opponent
         score = min(
             score,
             opponent.maxABValue(nextBoard, ply - 1, turn, alpha, beta))
         #if new score is smaller than alphaValue prune rest of tree branch
         if (score <= alpha):
             return score
         #update beta
         beta = min(beta, score)
         #print "score in minABValue is: " + str(s)
     return score
Ejemplo n.º 5
0
    def __init__(self, master, p1, p2):
        self.CUPW = 75
        self.HEIGHT = 400
        self.BOARDW = 700
        self.PAD = 0
        self.game = MancalaBoard()
        self.p1 = p1
        self.p2 = p2
        self.BINW = self.BOARDW / self.game.NCUPS

        self.turn = p1
        self.wait = p2
        self.root = master

        frame = tk.Frame(master)
        frame.pack()

        # Create the board
        self.makeBoard(frame)

        displayStr = "Welcome to Mancala"

        self.status = tk.Label(frame, text=displayStr)
        self.status.pack(side=tk.BOTTOM)

        self.frame = frame
Ejemplo n.º 6
0
 def play_move_and_create_node(self, parent_node, move):
     mancala_board = MancalaBoard(6, 6, parent_node.current_board_state)
     extra_turn = mancala_board.play(parent_node.player, move)
     # Switch players
     next_player = self.get_next_player(parent_node.player, extra_turn)
     # Add new node to the tree
     return MCTSNode(mancala_board, next_player, move, parent_node)
Ejemplo n.º 7
0
 def score(self, board):
     """ Returns the score for this player given the state of the board """
     if board.hasWon(self.num):
         return 100.0
     elif board.hasWon(self.opp):
         return 0.0
     else:
         return 50.0
Ejemplo n.º 8
0
    def pick_pot_with_extra_turn(self, extra_turn_setting):
        last_move = self.mancala.game_board_log[-1]
        legal_moves = self.mancala.get_legal_moves(self.player_number)
        for move in legal_moves:
            possible_game = MancalaBoard(6, 6, last_move)
            take_another_turn = possible_game.play(self.player_number, move)
            if take_another_turn is extra_turn_setting:
                return move

        return self.pick_random()
 def run_simulation(self, board_state, player_number, max_depth=5):
     mancala_board = MancalaBoard(6, 6, board_state)
     simulated_game = Game(
         mancala_board, player.Player(1, "random", mancala_board,
                                      max_depth),
         player.Player(2, "random", mancala_board, max_depth))
     # Run simulation and determine winner
     game_logs = simulated_game.play(player_number)
     winner = game_logs[-1][-1]['current_winning_player']
     # Return reward
     return self.get_reward(winner)
Ejemplo n.º 10
0
def init():
    pots = 6
    stones = 4
    first_player = 1
    player_types = [
        "minimax", "alphabeta", "random", "rightpot", "leftpot",
        "potwithfewest", "potwithmost", "takeanotherturn", "avoidanotherturn"
    ]

    for game_number in range(6000):
        mancala_board = MancalaBoard(pots, stones, None, game_number)
        player_one_type = random.choice(player_types)
        player_two_type = random.choice(player_types)
        max_lookahead = 6
        print(
            f"player_one_type {player_one_type}, player_two_type {player_two_type}"
        )
        game = Game(mancala_board,
                    Player(1, player_one_type, mancala_board, max_lookahead),
                    Player(2, player_two_type, mancala_board, max_lookahead))
        game_logs = game.play(first_player)
        print(f"game_logs : {game_logs[-1]}")

        game_final_result = {
            "game_number":
            game_number,
            "winner":
            mancala_board.winning_player,
            "final_score_player_1":
            mancala_board.game_board_log[-1][2][0],
            "final_score_player_2":
            mancala_board.game_board_log[-1][2][1],
            "final_score_difference":
            abs(mancala_board.game_board_log[-1][2][0] -
                mancala_board.game_board_log[-1][2][1]),
            "game_length_by_turns":
            len(mancala_board.game_board_log) - 2,
            "player_one_turns":
            mancala_board.player_turns[0],
            "player_two_turns":
            mancala_board.player_turns[1],
        }

        with open('kalah_game_board_data.csv', 'a',
                  newline='') as game_board_csv, open(
                      'kalah_game_state_data.csv', 'a',
                      newline='') as game_state_csv:
            game_board_writer = csv.writer(game_board_csv)
            game_board_writer.writerow(game_logs[0])

            game_state_writer = csv.writer(game_state_csv)
            game_state_writer.writerow([game_final_result] + game_logs[1])
Ejemplo n.º 11
0
 def chooseMove(self, board):
     """ Returns the next move that this player wants to make """
     if self.type == self.HUMAN:
         move = input("Please enter your move:")
         while not board.legalMove(self, move):
             print(move, "is not valid")
             move = input("Please enter your move")
         return move
     elif self.type == self.ABPRUNE:
         val, move = self.alphaBetaMove(board, 15)
         print("chose move", move, " with value", val)
         return move
     else:
         print("Unknown player type")
         return -1
Ejemplo n.º 12
0
def generate_game(player_one_type,
                  player_two_type,
                  max_lookahead=5,
                  time_limit=5):
    pots = 6
    stones = 4
    first_player = 1

    mancala_board = MancalaBoard(pots, stones, None)
    print(
        f"player_one_type {player_one_type}, player_two_type {player_two_type}"
    )
    game = Game(
        mancala_board,
        Player(1, player_one_type, mancala_board, max_lookahead, time_limit),
        Player(2, player_two_type, mancala_board, max_lookahead, time_limit))
    game.play(first_player)
    game_outcome = {
        "player_one":
        player_one_type,
        "player_two":
        player_two_type,
        "winner":
        str(mancala_board.winning_player),
        "final_score_player_1":
        str(mancala_board.game_board_log[-1][2][0]),
        "final_score_player_2":
        str(mancala_board.game_board_log[-1][2][1]),
        "final_score_difference":
        str(
            abs(mancala_board.game_board_log[-1][2][0] -
                mancala_board.game_board_log[-1][2][1])),
    }
    print(game_outcome)

    return ",".join(game_outcome.values())
Ejemplo n.º 13
0
    def minimax_alpha_beta(self,
                           game,
                           phasing_player,
                           alpha=float("-inf"),
                           beta=float("inf"),
                           best_move=None,
                           depth=-1):
        game_over = game.game_over()
        if game_over:
            return [
                self.minimax_alpha_beta_score(game, depth, game_over),
                best_move
            ]
        elif depth is self.maximum_depth:
            game.clear_board()
            return [
                self.minimax_alpha_beta_score(game, depth, game_over),
                best_move
            ]

        depth += 1

        legal_moves = game.get_legal_moves(phasing_player)
        last_move = game.game_board_log[-1]
        next_player = self.get_opposite_player(phasing_player)

        print(
            f"------Depth {depth} Player {phasing_player} Legal moves: {legal_moves}"
        )

        for index, move in enumerate(legal_moves, start=0):
            possible_game = MancalaBoard(6, 6, last_move)
            take_another_turn = possible_game.play(phasing_player, move)
            # See what the next player will do
            if phasing_player == self.player_number:  #is maximising node
                result = self.minimax_alpha_beta(possible_game, next_player,
                                                 alpha, beta, move, depth)[0]
                if result > alpha:
                    print(
                        f" Max best move: {best_move} - result {result} is more than {alpha}, set alpha to {result}"
                    )
                    alpha = result
                    best_move = move

                if alpha >= beta:  # Pruning
                    break

            else:  #is minimising node
                result = self.minimax_alpha_beta(possible_game, next_player,
                                                 alpha, beta, move, depth)[0]
                if result < beta:
                    print(
                        f" Min best move: {best_move} - result {result} is less than {beta}, set beta to {result}"
                    )
                    beta = result
                    best_move = move

                if beta <= alpha:  # Pruning
                    break

        best_score = alpha if phasing_player == self.player_number else beta
        return [best_score, best_move]
Ejemplo n.º 14
0
class MancalaWindow:
    """# A very simple GUI for playing the game of Mancala."""
    def __init__(self, master, p1, p2):
        self.CUPW = 75
        self.HEIGHT = 400
        self.BOARDW = 700
        self.PAD = 0
        self.game = MancalaBoard()
        self.p1 = p1
        self.p2 = p2
        self.BINW = self.BOARDW / self.game.NCUPS

        self.turn = p1
        self.wait = p2
        self.root = master

        frame = tk.Frame(master)
        frame.pack()

        # Create the board
        self.makeBoard(frame)

        displayStr = "Welcome to Mancala"

        self.status = tk.Label(frame, text=displayStr)
        self.status.pack(side=tk.BOTTOM)

        self.frame = frame

    def enableBoard(self):
        """ Allow a human player to make moves by clicking"""
        for i in [0, 1]:
            for j in range(self.game.NCUPS):
                self.cups[i][j].bind("<Button-1>", self.callback)

    def disableBoard(self):
        """ Prevent the human player from clicking while the computer thinks"""
        for i in [0, 1]:
            for j in range(self.game.NCUPS):
                self.cups[i][j].unbind("<Button-1>")

    def makeBoard(self, frame):
        """ Create the board """
        boardFrame = tk.Frame(frame)
        boardFrame.pack(side=tk.TOP)

        self.button = tk.Button(frame,
                                text="Start New Game",
                                command=self.newgame)
        self.button.pack(side=tk.BOTTOM)

        gamef = tk.Frame(boardFrame)
        topRow = tk.Frame(gamef)
        bottomRow = tk.Frame(gamef)
        topRow.pack(side=tk.TOP)
        bottomRow.pack(side=tk.TOP)
        tmpCups = []
        tmpCups2 = []

        binW = self.BOARDW / self.game.NCUPS
        binH = self.HEIGHT / 2

        for i in range(self.game.NCUPS):
            c = tk.Canvas(bottomRow, width=binW, height=binH)
            c.pack(side=tk.LEFT)
            tmpCups += [c]
            c = tk.Canvas(topRow, width=binW, height=binH)
            c.pack(side=tk.LEFT)
            tmpCups2 += [c]

        self.cups = [tmpCups, tmpCups2]
        self.p1cup = tk.Canvas(boardFrame, width=self.CUPW, height=self.HEIGHT)
        self.p2cup = tk.Canvas(boardFrame, width=self.CUPW, height=self.HEIGHT)

        self.p2cup.pack(side=tk.LEFT)
        gamef.pack(side=tk.LEFT)
        self.p1cup.pack(side=tk.LEFT)

        self.drawBoard()

    def drawBoard(self):
        """ Draw the board on the canvas """
        self.p2cup.create_oval(self.PAD,
                               self.PAD,
                               self.CUPW,
                               0.9 * self.HEIGHT,
                               width=2)
        binW = self.BOARDW / self.game.NCUPS
        binH = self.HEIGHT / 2
        for j in [0, 1]:
            for i in range(self.game.NCUPS):

                self.cups[j][i].create_rectangle(self.PAD, self.PAD, binW,
                                                 binH)
        self.p1cup.create_oval(self.PAD,
                               self.PAD + 0.1 * self.HEIGHT,
                               self.CUPW,
                               self.HEIGHT,
                               width=2)

    def newgame(self):
        """ Start a new game between the players """
        self.game.reset()
        self.turn = self.p1
        self.wait = self.p2
        s = "Player " + str(self.turn) + "'s turn"
        if self.turn.type != Player.HUMAN:
            s += " Please wait..."
        self.status['text'] = s
        self.resetStones()
        self.continueGame()

    # Board must be disabled to call continueGame
    def continueGame(self):
        """ Find out what to do next.  If the game is over, report who
            won.  If it's a human player's turn, enable the board for
            a click.  If it's a computer player's turn, choose the next move."""
        self.root.update()
        if self.game.gameOver():
            if self.game.hasWon(self.p1.num):
                self.status['text'] = "Player " + str(self.p1) + " wins"
            elif self.game.hasWon(self.p2.num):
                self.status['text'] = "Player " + str(self.p2) + " wins"
            else:
                self.status['text'] = "Tie game"
            return
        if self.turn.type == Player.HUMAN:
            self.enableBoard()
        else:
            move = self.turn.chooseMove(self.game)
            playAgain = self.game.makeMove(self.turn, move)
            if not playAgain:
                self.swapTurns()
            self.resetStones()
            self.continueGame()

    def swapTurns(self):
        """ Change whose turn it is"""
        temp = self.turn
        self.turn = self.wait
        self.wait = temp
        statusstr = "Player " + str(self.turn) + "\'s turn "
        if self.turn.type != Player.HUMAN:
            statusstr += "Please wait..."
        self.status['text'] = statusstr

    def resetStones(self):
        """ Clear the stones and redraw them """
        # Put the stones in the cups
        for i in range(len(self.game.P2Cups)):
            index = (len(self.game.P2Cups) - i) - 1
            self.clearCup(self.cups[1][index])
            # put the number of stones at the top of the canvas
            self.cups[1][index].create_text(self.BINW / 2,
                                            0.05 * self.HEIGHT,
                                            text=str(self.game.P2Cups[i]),
                                            tag="num")
        for i in range(len(self.game.P1Cups)):
            # put the number of stones at the bottom of the canvas
            self.clearCup(self.cups[0][i])
            self.cups[0][i].create_text(self.BINW / 2,
                                        0.05 * self.HEIGHT,
                                        text=str(self.game.P1Cups[i]),
                                        tag="num")
        self.clearCup(self.p1cup)
        self.clearCup(self.p2cup)
        self.p2cup.create_text(self.CUPW / 2,
                               10,
                               text=str(self.game.scoreCups[1]),
                               tag="num")
        self.p1cup.create_text(self.CUPW / 2,
                               10 + 0.1 * self.HEIGHT,
                               text=str(self.game.scoreCups[0]),
                               tag="num")

    def clearCup(self, cup):
        """ Clear the stones in the given cup"""
        titems = cup.find_withtag("num")
        stones = cup.find_withtag("stone")
        cup.delete(titems)
        cup.delete(stones)

    def callback(self, event):
        """ Handle the human player's move"""
        # calculate which box the click was in
        moveAgain = True
        self.disableBoard()
        if self.turn.num == 1:
            for i in range(len(self.cups[0])):
                if self.cups[0][i] == event.widget:
                    if self.game.legalMove(self.turn, i + 1):
                        moveAgain = self.game.makeMove(self.turn, i + 1)
                        if not moveAgain:
                            self.swapTurns()
                        self.resetStones()
        else:
            for i in range(len(self.cups[1])):
                if self.cups[1][i] == event.widget:
                    index = self.game.NCUPS - i
                    if self.game.legalMove(self.turn, index):
                        moveAgain = self.game.makeMove(self.turn, index)
                        if not moveAgain:
                            self.swapTurns()
                        self.resetStones()
        if moveAgain:
            self.enableBoard()
        else:
            self.continueGame()

    def mainloop(self):
        self.frame.mainloop()