Advertisement
alkkofficial

Untitled

Jun 24th, 2023
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.28 KB | None | 0 0
  1. # imports
  2. import numpy as np
  3. import torch
  4. import torch.nn as nn
  5. import chess
  6. import torch.nn.init as init
  7. # set up AI (Sequential NN)
  8.  
  9.  
  10. class Tanh200(nn.Module):
  11. def __init__(self):
  12. super(Tanh200, self).__init__()
  13.  
  14. def forward(self, x):
  15. return torch.tanh(x / 200)
  16.  
  17.  
  18. class Agent(nn.Module):
  19. def __init__(self):
  20. super().__init__()
  21. self.fc1 = nn.Linear(833, 2048)
  22. self.bn1 = nn.BatchNorm1d(2048)
  23. self.dropout1 = nn.Dropout(p=0.45)
  24. self.relu = nn.LeakyReLU(0.05)
  25. self.layer2 = nn.Linear(2048, 1)
  26. self.dropout2 = nn.Dropout(p=0.45)
  27. self.tanh200 = Tanh200()
  28. self.hidden_layers = nn.ModuleList()
  29.  
  30. # Initialize weights of Linear layers using Xavier initialization
  31. init.xavier_uniform_(self.fc1.weight)
  32. init.xavier_uniform_(self.layer2.weight)
  33.  
  34. self.loss = nn.MSELoss()
  35.  
  36. def forward(self, x):
  37. x = self.fc1(x)
  38. x = self.bn1(x)
  39. x = self.dropout1(x)
  40. x = self.relu(x)
  41. x = self.layer2(x)
  42. x = self.dropout2(x)
  43. x = self.tanh200(x)
  44. return x
  45.  
  46.  
  47. model = Agent()
  48. weights_path = "./zlv7_pro.pt"
  49. state_dict = torch.load(weights_path, map_location=torch.device("cpu"))
  50. model.load_state_dict(state_dict)
  51.  
  52. # set up important functions
  53. # board_data - this function will turn a python-chess board into a matrix for the AI to evaluate
  54. def board_data(board):
  55. board_array = np.zeros((8, 8, 13), dtype=np.int8)
  56. for i in range(64):
  57. piece = board.piece_at(i)
  58. if piece is not None:
  59. color = int(piece.color)
  60. piece_type = piece.piece_type - 1
  61. board_array[i // 8][i % 8][piece_type + 6 * color] = 1
  62. else:
  63. board_array[i // 8][i % 8][-1] = 1
  64. board_array = board_array.flatten()
  65. return board_array
  66.  
  67.  
  68. def static_eval(board):
  69. matrix_game = np.array([board_data(board)])
  70. matrix_game = np.concatenate(
  71. (matrix_game, np.array([[0]])), axis=1
  72. ) # 0 because static evals typically returns evaluation from white's POV
  73. matrix_game = torch.tensor(matrix_game, dtype=torch.float32)
  74. score = model(matrix_game)
  75. score = float(score)
  76. return score
  77.  
  78.  
  79. def negamax_ab(board, alpha, beta, colour, model, depth=2):
  80. if depth == 0 or board.is_game_over(): # check if the depth is 0 or "terminal node"
  81. if colour == 1:
  82. move_turn = 0 # my eval accepts 0 for white and black for 1 :/
  83. else:
  84. move_turn = 1
  85. # game after one hot encoding
  86. matrix_game = np.array([board_data(board)])
  87. matrix_game = np.concatenate(
  88. (matrix_game, np.array([[move_turn]])), axis=1
  89. ) # have to append the move turn - the AI needs to know this
  90. matrix_game = torch.tensor(matrix_game, dtype=torch.float32)
  91. model.eval()
  92. score = model(
  93. matrix_game
  94. ) # EVALUTATION - high score for winning (if white/black wins, high score, vice versa)
  95. score = float(score)
  96. if board.is_game_over():
  97. return score * colour * (1 if board.turn == chess.WHITE else -1)
  98. return score * colour
  99.  
  100. child_nodes = list(board.legal_moves)
  101. # child_nodes = order_moves(child_nodes) # make an ordermove function
  102. best_score = -np.inf
  103. for child in child_nodes:
  104. board.push(child) # Push the current child move on the board
  105. score = -negamax_ab(board, -beta, -alpha, -colour, model, depth - 1)
  106. board.pop() # Pop the current child move from the board
  107.  
  108. best_score = max(best_score, score)
  109. alpha = max(alpha, best_score)
  110. if alpha >= beta:
  111. break
  112. return best_score
  113.  
  114. # set up chess game
  115.  
  116. NUMBER_OF_GAMES = 10
  117.  
  118.  
  119. # NOTE: this function analyses moves by NUMBER OF NODES SEARCHED
  120. def analyse_move_nodes(board, ready, max_nodes):
  121. if ready:
  122. legal_moves = list(board.legal_moves)
  123. turn = board.turn
  124. colour = 1
  125. if turn == chess.WHITE:
  126. colour = 1
  127. else:
  128. colour = -1
  129. m_dict = {}
  130. n_count = 1
  131. max_nodes = min(len(legal_moves), max_nodes)
  132. for move in legal_moves:
  133. if n_count < max_nodes:
  134. board.push(move)
  135. move_score = negamax_ab(
  136. board, -np.inf, np.inf, -colour, 2)
  137. m_dict[str(move)] = move_score
  138. if colour == -1:
  139. m_dict = {
  140. k: v
  141. for k, v in sorted(
  142. m_dict.items(), key=lambda item: item[1], reverse=False
  143. ) # reverse=False to find the best move with highest score
  144. }
  145. else:
  146. m_dict = {
  147. k: v
  148. for k, v in sorted(
  149. m_dict.items(), key=lambda item: item[1], reverse=True
  150. ) # reverse=False to find the best move with highest score
  151. }
  152. best_move = list(m_dict.keys())[0] # best move, first key
  153. board.pop()
  154. n_count += 1
  155. m = iter(m_dict)
  156. best_move = next(m) # first move after sorting, best move
  157. colour = colour * -1 # TODO: check if this line is needed
  158. return best_move
  159.  
  160.  
  161. # NOTE: this function analyses moves by DEPTH
  162. def analyse_move(board, ready, depth=2):
  163. if ready:
  164. legal_moves = list(board.legal_moves)
  165. turn = board.turn
  166. colour = 0
  167. if turn == chess.WHITE:
  168. colour = 1
  169. else:
  170. colour = -1
  171. m_dict = {}
  172. for move in legal_moves:
  173. board.push(move)
  174. move_score = negamax_ab(board, -np.inf, np.inf, colour, model, depth)
  175. m_dict[str(move)] = move_score
  176. board.pop()
  177. m_dict = {
  178. k: v
  179. for k, v in sorted(m_dict.items(), key=lambda item: item[1], reverse=False)
  180. } # reverse=True to find best move with highest score
  181. m = iter(m_dict)
  182. best_move = next(m) # first move after sorting, best move
  183. colour = colour * -1 # TODO: check if this line is needed
  184. return best_move
  185.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement