In: Computer Science
For this assignment, you will implement the minimax algorithm with alpha-beta pruning in order to find the optimal move for a game of generalized tic-tac-toe. In this version of the game, the players can choose different board sizes, for example 4x4 or 5x5, instead of the normal 3x3. The game proceeds with the usual rules for tic-tac-toe (see https://en.wikipedia.org/wiki/Tic-tac-toe).
Requirements
You are to modify the mp2basecode (below) program to implement the alpha-beta search for making the computer’s move. This will require implementing additional methods for testing for terminal states and finding the utility of states, among others. You can follow the textbook’s pseudocode for the algorithm.
Additional Requirements
The name of your source code file should be mp2.py. All your code should be within a single file.
You can only import numpy, random, and math packages.
Your code should follow good coding practices, including good use of whitespace and use of both inline and block comments.
You need to use meaningful identifier names that conform to standard naming conventions.
import numpy as np import random import math # self class is responsible for representing the game board class GenGameBoard: # Constructor method - initializes each position variable and the board size def __init__(self, boardSize): self.boardSize = boardSize # Holds the size of the board self.marks = np.empty((boardSize, boardSize),dtype='str') # Holds the mark for each position self.marks[:,:] = ' ' # Prints the game board using current marks def printBoard(self): # Prthe column numbers print(' ',end='') for j in range(self.boardSize): print(" "+str(j+1), end='') # Prthe rows with marks print("") for i in range(self.boardSize): # Prthe line separating the row print(" ",end='') for j in range(self.boardSize): print("--",end='') print("-") # Prthe row number print(i+1,end='') # Prthe marks on self row for j in range(self.boardSize): print("|"+self.marks[i][j],end='') print("|") # Prthe line separating the last row print(" ",end='') for j in range(self.boardSize): print("--",end='') print("-") # Attempts to make a move given the row,col and mark # If move cannot be made, returns False and prints a message if mark is 'X' # Otherwise, returns True def makeMove(self, row, col, mark): possible = False # Variable to hold the return value if row==-1 and col==-1: return False # Change the row,col entries to array indexes row = row - 1 col = col - 1 if row<0 or row>=self.boardSize or col<0 or col>=self.boardSize: print("Not a valid row or column!") return False # Check row and col, and make sure space is empty # If empty, set the position to the mark and change possible to True if self.marks[row][col] == ' ': self.marks[row][col] = mark possible = True # Prout the message to the player if the move was not possible if not possible and mark=='X': print("\nself position is already taken!") return possible # Determines whether a game winning condition exists # If so, returns True, and False otherwise def checkWin(self, mark): won = False # Variable holding the return value # Check wins by examining each combination of positions # Check each row for i in range(self.boardSize): won = True for j in range(self.boardSize): if self.marks[i][j]!=mark: won=False break if won: break # Check each column if not won: for i in range(self.boardSize): won = True for j in range(self.boardSize): if self.marks[j][i]!=mark: won=False break if won: break # Check first diagonal if not won: for i in range(self.boardSize): won = True if self.marks[i][i]!=mark: won=False break # Check second diagonal if not won: for i in range(self.boardSize): won = True if self.marks[self.boardSize-1-i][i]!=mark: won=False break return won # Determines whether the board is full # If full, returns True, and False otherwise def noMoreMoves(self): return (self.marks!=' ').all() # TODO - this method should run minimax to determine the value of each move # Then make best move for the computer by placing the mark in the best spot def makeCompMove(self): # This code chooses a random computer move - just for testing purposes # REMOVE THIS AFTER IMPLEMENTING AI # Make sure the move was possible, if not try again row, col = -1, -1 while not self.makeMove(row, col, 'O'): col = random.randint(1,boardSize) row = random.randint(1,boardSize) print("Computer chose: "+str(row)+","+str(col)) # Run alpha beta search here # Print out the header info print("CLASS: Artificial Intelligence, Lewis University") print("NAME: [put your name here]") LOST = 0 WON = 1 DRAW = 2 wrongInput = False boardSize = int(input("Please enter the size of the board n (e.g. n=3,4,5,...): ")) # Create the game board of the given size board = GenGameBoard(boardSize) board.printBoard() # Print the board before starting the game loop # Game loop while True: # *** Player's move *** # Try to make the move and check if it was possible # If not possible get col,row inputs from player row, col = -1, -1 while not board.makeMove(row, col, 'X'): print("Player's Move") row, col = input("Choose your move (row, column): ").split(',') row = int(row) col = int(col) # Display the board again board.printBoard() # Check for ending condition # If game is over, check if player won and end the game if board.checkWin('X'): # Player won result = WON break elif board.noMoreMoves(): # No moves left -> draw result = DRAW break # *** Computer's move *** board.makeCompMove() # Print out the board again board.printBoard() # Check for ending condition # If game is over, check if computer won and end the game if board.checkWin('O'): # Computer won result = LOST break elif board.noMoreMoves(): # No moves left -> draw result = DRAW break # Check the game result and print out the appropriate message print("GAME OVER") if result==WON: print("You Won!") elif result==LOST: print("You Lost!") else: print("It was a draw!")
# TODO - this method should run minimax to determine the value of
each move
# Then make best move for the computer by placing the mark in the
best spot
def makeCompMove(self):
# This code chooses a random computer move - just for testing
purposes
# REMOVE THIS AFTER IMPLEMENTING AI
# Make sure the move was possible, if not try again
row, col = -1, -1
while not self.makeMove(row, col, 'O'):
col = random.randint(1,boardSize)
row = random.randint(1,boardSize)
print("Computer chose: "+str(row)+","+str(col))
# Run alpha beta search here
minimax(0, 0, True, self.marks, self.MIN, self.MAX)
def minimax(self, depth, nodeIndex, maximizingPlayer, values,
alpha, beta):
# Terminating condition. i.e leaf node is reached
if depth == self.boardSize:
return values[nodeIndex]
if maximizingPlayer:
best = self.MIN
# Recur for left and right children
for i in range(0, 2):
val = minimax(depth + 1, nodeIndex * 2 + i, False, values, alpha,
beta)
best = max(best, val)
alpha = max(alpha, best)
# Alpha Beta Pruning
if beta <= alpha:
break
return best
else:
best = self.MAX
# Recur for left and right children
for i in range(0, 2):
val = minimax(depth + 1, nodeIndex * 2 + i, True, values, alpha,
beta)
best = min(best, val)
beta = min(beta, best)
# Alpha Beta Pruning
if beta <= alpha:
break
return best