Guest User

tictactoe

a guest
Apr 15th, 2024
125
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.05 KB | None | 0 0
  1. import math, random, pickle, numpy as np
  2.  
  3.  
  4.  
  5. class boardFunctions:
  6.     def __init__(self, boardState):
  7.         # Current state of the board
  8.         self.boardState = boardState
  9.  
  10.     # Return 1/-1 if player has won, return 0 if draw, return 2 if game ongoing
  11.     def checkWin(self, board) :
  12.         winIndices =  [[0,3,6], [1,4,7], [2,5,8], [0,1,2], [3,4,5], [6,7,8], [0,4,8], [2,4,6]]
  13.         for element in winIndices :
  14.             winCheckSum = (board[element[0]] + board[element[1]] + board[element[2]]) / 3
  15.             if abs(winCheckSum) == 1 :
  16.                 return winCheckSum
  17.         if 0 in board :
  18.             return 2
  19.         else :
  20.             return 0
  21.    
  22.     # Prints a  certain boardstate
  23.     def print(self, board) :
  24.         boardDisp = [' '] * 9
  25.         for i in range(len(board)):
  26.             if board[i] == 1 :
  27.                 boardDisp[i] = 'X'
  28.             elif board[i] == -1 :
  29.                 boardDisp[i] = 'O'
  30.             i += 1
  31.         print('-----')
  32.         print(boardDisp[0], boardDisp[1], boardDisp[2])
  33.         print(boardDisp[3], boardDisp[4], boardDisp[5])
  34.         print(boardDisp[6], boardDisp[7], boardDisp[8])
  35.         print('-----')
  36.    
  37.     # Helper func for imputting indices as a row and column
  38.     def rowColumn(self, row, column) :
  39.         i = (3 * row) + column
  40.         return i
  41.  
  42.     # Prompts the user to imput a move and updates the specified board
  43.     def playerInput(self, board, player) :
  44.         column = int(input('Column? '))
  45.         row = int(input('Row? '))
  46.         space = self.rowColumn(row, column)
  47.         if board[space] == 0 :
  48.             board[space] = player
  49.         else:
  50.             if self.checkWin(board) == 0 :
  51.                 print('Square already filled. Try again')
  52.                 self.playerInput(player)
  53.             else :
  54.                 return
  55.    
  56.     # Plays a move on the specified board in a random empty square
  57.     def randomMove(self, board, player) :
  58.         board[random.choice([idx for idx, val in enumerate(board) if 0 == val])] = player
  59. bfunc = boardFunctions([0] * 9)
  60.  
  61. class minimax :
  62.     def __init__(self) :
  63.         self.minimaxSeed = 4
  64.    
  65.     def moveSearch(self, board, player, depth) :
  66.         winState = bfunc.checkWin(bfunc.boardState)
  67.         if abs(winState) == 1 :
  68.             if depth == 0 :
  69.                 return
  70.             else :
  71.                 return winState * player * -1
  72.         elif winState == 0:
  73.             if depth == 0 :
  74.                 return
  75.             else :
  76.                 return 0
  77.         elif winState == 2 :
  78.             moveList = []
  79.             i = 0
  80.             while i < 9 :
  81.                 if board[i] == 0 :
  82.                     moveList.append(i)
  83.                 i += 1
  84.             j = 0
  85.             valueList = [0] * len(moveList)
  86.             while j < len(moveList) :
  87.                 board[moveList[j]] = player
  88.                 valueList[j] = self.moveSearch(board, -1 * player, depth + 1)
  89.                 board[moveList[j]] = 0
  90.                 j += 1
  91.             if depth == 0 :
  92.                 maxValue = max(valueList)
  93.                 maxIndices = [idx for idx, val in enumerate(valueList) if maxValue == val]
  94.                 boardStateInt = sum([(2**j)*abs(bfunc.boardState[j]) + 1 + self.minimaxSeed for j in range(len(valueList))])
  95.                 boardStateSeed = int(((100*abs(math.cos(boardStateInt)))%1)*100) % len(maxIndices)
  96.                 return moveList[maxIndices[boardStateSeed]]
  97.             else :
  98.                 return max(valueList) * -1
  99.    
  100.     def minimaxMove(self, board, player) :
  101.         board[self.moveSearch(board, player, 0)] = player
  102.    
  103.     def minimaxGame(self, startingPlayer) :
  104.         i = 0
  105.         while bfunc.checkWin(bfunc.boardState) == 2 :
  106.             self.minimaxMove(bfunc.boardState, startingPlayer * ((-1) ** i))
  107.             bfunc.print(bfunc.boardState)
  108.             i += 1
  109. mmx = minimax()
  110.  
  111. class pickler:
  112.     def __init__(self, path) :
  113.         self.picklePath = path
  114.    
  115.     def encode(self, data, fileName):
  116.         with open(self.picklePath + '/' + fileName + '.pickle', 'wb') as f:
  117.             pickle.dump(data, f)
  118.    
  119.     def decode(self, fileName) :
  120.         with open(self.picklePath + '/' + fileName + '.pickle', 'rb') as f :
  121.             return pickle.load(f)
  122. pkl = pickler('C:/Users/riley/Documents/PythonProjects/Neural/pickles/')
  123.  
  124. class neuralNetwork:
  125.     def __init__(self) :
  126.         pass # eventually will put all neural network related functions inside this class
  127.  
  128. def sigmoid(x) :
  129.     return 1/(1 + np.exp(-x))  
  130.  
  131. def derivativeSigmoid(x) :
  132.     return sigmoid(x) * (1 - sigmoid(x))
  133.  
  134. def inverseSigmoid(x) :
  135.     return np.log(x / (1 - x))
  136.  
  137. def sigmoidArray(array) :
  138.     arr = np.copy(array)
  139.     arr = [[sigmoid(j) for j in i] for i in arr]
  140.     arr = np.reshape(arr,array.shape)
  141.     return arr
  142.  
  143. layerSizes = [10,20,9]
  144. neuralPlayer = 1
  145.  
  146. weightMatrices = pkl.decode('weights')
  147. biasMatrices = pkl.decode('biases')
  148.  
  149.  
  150.  
  151. def neuralValuePass(board, player) :
  152.     layers = [np.concatenate(([player], board)).reshape((layerSizes[0],1))]
  153.     for i in range(len(weightMatrices)) :
  154.         layers.append(sigmoidArray(np.matmul(weightMatrices[i], layers[i]) + biasMatrices[i]))
  155.     return layers
  156.  
  157. def neuralMoveSelect(board, player) :
  158.     moveSelection = np.argmax(neuralValuePass(board,player)[-1])
  159.     return moveSelection
  160.  
  161. def neuralMove(board, player) :
  162.     move = neuralMoveSelect(board, player)
  163.     if board[move] == 0 :
  164.         board[move] = player
  165.     else :
  166.         return
  167.  
  168. def cost(board, player) :
  169.     nnwValues = neuralValuePass(board, player)[-1].reshape(9)
  170.     mmxValues = np.zeros(9)
  171.     mmxValues[mmx.moveSearch(board, player, 0)] = 1
  172.     costValues = [(mmxValues[i] - nnwValues[i]) ** 2 for i in range(9)]
  173.     return sum(costValues)
  174.  
  175. layers = [i.reshape((i.shape)[0]) for i in neuralValuePass(bfunc.boardState, 1)]
  176.  
  177. mmxValues = np.zeros(9)
  178. mmxValues[mmx.moveSearch(bfunc.boardState, neuralPlayer, 0)] = 1
  179.  
  180. def layerGradients(layers) :
  181.     layerGradients = [0] * len(weightMatrices)
  182.     layerGradients[-1] = [2 * (layers[-1][i] - mmxValues[i]) for i in range(len(layers[-1]))]
  183.     layerGradients[-2] = [sum([(weightMatrices[-1][j][i]) * (derivativeSigmoid(inverseSigmoid(layers[-1][j]))) * (2 * (layers[-1][j] - mmxValues[j])) for j in range(len(layers[-1]))]) for i in range(len(layers[-2]))]
  184.     return layerGradients
  185.  
  186. def weightGradients(weights) :
  187.     weightGradients = [0] * len(weights)
  188.     weightGradients[-1] = np.copy(weights[-1])
  189.     weightGradients[-1] = [[(layers[-2][j]) * (derivativeSigmoid(inverseSigmoid(layers[-1][i]))) * (2 * (layers[-1][i] - mmxValues[i])) for j in range(len(weightGradients[-1][i]))] for i in range(len(weightGradients[-1]))]
  190.     weightGradients[-1] = np.reshape(weightGradients[-1],weights[-1].shape)
  191.  
  192.     weightGradients[-2] = np.copy(weights[-2])
  193.     weightGradients[-2] = [[(layers[-3][j]) * (derivativeSigmoid(inverseSigmoid(layers[-2][i]))) * (layerGradients(layers)[-2][j]) for j in range(len(weightGradients[-2][i]))] for i in range(len(weightGradients[-2]))]
  194.     weightGradients[-2] = np.reshape(weightGradients[-2],weights[-2].shape)
  195.     return weightGradients
  196.  
  197. def biasGradients(biases) :
  198.     biasGradients = [0] * len(biases)
  199.     biasGradients[-1] = np.copy(biases[-1])
  200.     biasGradients[-1] = [[(1) * (derivativeSigmoid(inverseSigmoid(layers[-1][i]))) * (2 * (layers[-1][i] - mmxValues[i])) for j in range(len(biasGradients[-1][i]))] for i in range(len(biasGradients[-1]))]
  201.     biasGradients[-1] = np.reshape(biasGradients[-1],biases[-1].shape)
  202.  
  203.     biasGradients[-2] = np.copy(biases[-2])
  204.     biasGradients[-2] = [[(1) * (derivativeSigmoid(inverseSigmoid(layers[-2][i]))) * (layerGradients(layers)[-2][j]) for j in range(len(biasGradients[-2][i]))] for i in range(len(biasGradients[-2]))]
  205.     biasGradients[-2] = np.reshape(biasGradients[-2],biases[-2].shape)
  206.     return biasGradients
  207.  
  208. layerGradients(layers)
  209. weightGradients(weightMatrices)
  210. biasGradients(biasMatrices)
  211.  
  212.  
  213.  
  214. '''
  215. To-Do List:
  216. - Weight/bias shape check
  217. - Gradient Descent
  218. - Training
  219. - Major clean up/refactor
  220. - GUI???'''
  221.  
Advertisement
Add Comment
Please, Sign In to add comment