Tic-Tac-Toe (Monte Carlo)

"""
Monte Carlo Tic-Tac-Toe Player
"""

import random
import poc_ttt_gui
import poc_ttt_provided as provided

# Constants for Monte Carlo simulator
# You may change the values of these constants as desired, but
#  do not change their names.
NTRIALS = 3    # Number of trials to run
SCORE_CURRENT = 1.0 # Score for squares played by the current player
SCORE_OTHER = 1.0   # Score for squares played by the other player

# Add your functions here.
def mc_trial(board, player):
    """
    This function takes a current board and the next player to move. 
    The function should play a game starting with the given player by making random moves, 
    alternating between players. The function should return when the game is over. 
    The modified board will contain the state of the game, so the function does not return anything. 
    In other words, the function should modify the board input.
    """
    while (board.check_win() == None):
            if player == 2:
                random_tile = (board.get_empty_squares())[random.randrange(len(board.get_empty_squares()))] 
                board.move(random_tile[0],random_tile[1] ,player)
                player = provided.switch_player(player)
                
            elif player == 3:
                random_tile = board.get_empty_squares()[random.randrange(len(board.get_empty_squares()))] 
                board.move(random_tile[0],random_tile[1] ,player)
                player = provided.switch_player(player)
 
def mc_update_scores(scores, board, player):
    """
    This function takes a grid of scores (a list of lists) with the same dimensions as the Tic-Tac-Toe board, 
    a board from a completed game, and which player the machine player is. 
    The function should score the completed board and update the scores grid. 
    As the function updates the scores grid directly, it does not return anything
    """
    scoresheet = scores
    
    if board.check_win() != provided.DRAW:
        
        if board.check_win() == player:
            for dummy_row in range(board.get_dim()):
                for dummy_col in range(board.get_dim()):
                    if board.square(dummy_row, dummy_col) == player:
                        scoresheet[dummy_row][dummy_col] += SCORE_CURRENT
                    elif board.square(dummy_row, dummy_col) == provided.EMPTY:
                        scoresheet[dummy_row][dummy_col] += 0 
                    else:
                        scoresheet[dummy_row][dummy_col] -= SCORE_OTHER


        elif board.check_win() != player:
            for dummy_row in range(board.get_dim()):
                for dummy_col in range(board.get_dim()):
                    if board.square(dummy_row, dummy_col) == player:
                        scoresheet[dummy_row][dummy_col] -= SCORE_CURRENT
                    elif board.square(dummy_row, dummy_col) == provided.EMPTY:
                        scoresheet[dummy_row][dummy_col] += 0 
                    else:
                        scoresheet[dummy_row][dummy_col] += SCORE_OTHER  
         
    
def get_best_move(board, scores):
    """
    This function takes a current board and a grid of scores. 
    The function should find all of the empty squares with the maximum score and randomly return one of them as a (row, column) tuple. 
    It is an error to call this function with a board that has no empty squares (there is no possible next move), 
    so your function may do whatever it wants in that case. The case where the board is full will not be tested.
    """
    sorted_scores = []
    for dummy_row in range(board.get_dim()):
        for dummy_col in range(board.get_dim()):
            sorted_scores.append(scores[dummy_row][dummy_col])
    sorted_scores = sorted(sorted_scores)
    
    for dummy_index in range(len(sorted_scores) - 1, -1, -1):
        for dummy_row in range(board.get_dim()):
                for dummy_col in range(board.get_dim()):
                    if board.square(dummy_row, dummy_col) == provided.EMPTY:
                            if sorted_scores[dummy_index] == scores[dummy_row][dummy_col]:
                                return (dummy_row, dummy_col)

def mc_move(board, player, trials):
    """
    This function takes a current board, 
    which player the machine player is, and the number of trials to run. 
    The function should use the Monte Carlo simulation described above to return a move 
    for the machine player in the form of a (row, column) tuple. 
    Be sure to use the other functions you have written!
    """
    score_sheet = [[0 for dummy_col in range(board.get_dim())] for dummy_row in range(board.get_dim())]
    for dummy_num in range(trials):
        new_board = board.clone()
        mc_trial(new_board, player)
        mc_update_scores(score_sheet, new_board, player)
    
    return get_best_move(board, score_sheet)

provided.play_game(mc_move, NTRIALS, False)        
poc_ttt_gui.run_gui(3, provided.PLAYERX, mc_move, NTRIALS, False)
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s