| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
| import math |
| import csv |
|
|
|
|
| class Architecture(nn.Module): |
| def __init__(self) -> None: |
| super(Architecture, self).__init__() |
| self.input_size = 9 |
| self.hidden_size_1 = 9 |
| self.hidden_size_2 = 9 |
| self.hidden_size_3 = 9 |
| self.hidden_size_4 = 9 |
| self.hidden_size_5 = 9 |
| self.hidden_size_6 = 9 |
| self.hidden_size_7 = 9 |
| self.output_size = 9 |
|
|
| self.fc1 = nn.Linear(self.input_size, self.hidden_size_1) |
| self.fc2 = nn.Linear(self.hidden_size_1, self.hidden_size_2) |
| self.fc3 = nn.Linear(self.hidden_size_2, self.hidden_size_3) |
| self.fc4 = nn.Linear(self.hidden_size_3, self.hidden_size_4) |
| self.fc5 = nn.Linear(self.hidden_size_4, self.hidden_size_5) |
| self.fc6 = nn.Linear(self.hidden_size_5, self.hidden_size_6) |
| self.fc7 = nn.Linear(self.hidden_size_6, self.hidden_size_7) |
| self.fc8 = nn.Linear(self.hidden_size_7, self.output_size) |
|
|
| self.loss = nn.CrossEntropyLoss() |
| self.relu = nn.ReLU() |
|
|
| def inference(self, x): |
| with torch.no_grad(): |
| x1 = self.relu(self.fc1(x)) |
| x2 = self.relu(self.fc2(x1)) |
| x3 = self.relu(self.fc3(x2)) |
| x4 = self.relu(self.fc4(x3)) |
| x5 = self.relu(self.fc5(x4)) |
| x6 = self.relu(self.fc6(x5)) |
| x7 = self.relu(self.fc7(x6)) |
| x8 = self.fc8(x7) |
| return x8 |
|
|
| def load_model(): |
| model = Architecture() |
| model.load_state_dict(torch.load('./model_weights.pth')) |
| return model |
|
|
| def inference_model(model, input): |
| return model.inference(input) |
|
|
| def minimax(board, depth, is_maximizing): |
| if check_winner(board) == 2: |
| return 1 |
| if check_winner(board) == 1: |
| return -1 |
| if check_winner(board) == 3: |
| return 0 |
| |
| if is_maximizing: |
| best_score = -math.inf |
| for i in range(9): |
| if board[i] == 0: |
| board[i] = 2 |
| score = minimax(board, depth + 1, False) |
| board[i] = 0 |
| best_score = max(score, best_score) |
| return best_score |
| else: |
| best_score = math.inf |
| for i in range(9): |
| if board[i] == 0: |
| board[i] = 1 |
| score = minimax(board, depth + 1, True) |
| board[i] = 0 |
| best_score = min(score, best_score) |
| return best_score |
|
|
| def best_move_minimax(board): |
| best_score = -math.inf |
| move = None |
| for i in range(9): |
| if board[i] == 0: |
| board[i] = 2 |
| score = minimax(board, 0, False) |
| board[i] = 0 |
| if score > best_score: |
| best_score = score |
| move = i |
| return move |
|
|
| def oracle(board, position): |
| output_board = [0] * 9 |
| output_board[position] = 2 |
|
|
| |
| minimax_move = best_move_minimax(board) |
|
|
| |
| if minimax_move == position: |
| return 1 |
| else: |
| return -1 |
|
|
|
|
| def print_in_csv(board, position, comparison_result): |
| output_board = [0] * 9 |
| output_board[position] = 2 |
| with open('game_state.csv', 'a', newline='') as f: |
| writer = csv.writer(f) |
| writer.writerow([ |
| ','.join(map(str, board)), |
| ','.join(map(str, output_board)), |
| comparison_result |
| ]) |
|
|
| def decode_prediction(prediction, board): |
| result = torch.argmax(prediction) |
| position = result.item() |
| comparison_result = oracle(board, position) |
| print(f'Oracle comparison result: {comparison_result}') |
| print_in_csv(board, position, comparison_result) |
| board[position] = 2 |
| return board |
|
|
| def encode_input(input): |
| return torch.tensor(input, dtype=torch.float32) |
|
|
|
|
| def play(): |
| model = load_model() |
| model.eval() |
| print(model.inference(torch.randn(9))) |
|
|
|
|
| def print_board(board): |
| |
| visual_board = [' ' if x == 0 else 'X' if x == 1 else 'O' for x in board] |
|
|
| print(f'{visual_board[0]} | {visual_board[1]} | {visual_board[2]}') |
| print('---------') |
| print(f'{visual_board[3]} | {visual_board[4]} | {visual_board[5]}') |
| print('---------') |
| print(f'{visual_board[6]} | {visual_board[7]} | {visual_board[8]}') |
| print('---------') |
|
|
|
|
| def check_winner(board): |
| |
| for i in range(0, 9, 3): |
| if board[i] == board[i + 1] == board[i + 2] == 1: |
| return 1 |
| if board[i] == board[i + 1] == board[i + 2] == 2: |
| return 2 |
|
|
| |
| for i in range(3): |
| if board[i] == board[i + 3] == board[i + 6] == 1: |
| return 1 |
| if board[i] == board[i + 3] == board[i + 6] == 2: |
| return 2 |
|
|
| |
| if board[0] == board[4] == board[8] == 1: |
| return 1 |
| if board[0] == board[4] == board[8] == 2: |
| return 2 |
|
|
| if board[2] == board[4] == board[6] == 1: |
| return 1 |
| if board[2] == board[4] == board[6] == 2: |
| return 2 |
|
|
| |
| if all(cell != 0 for cell in board): |
| return 3 |
|
|
| return 0 |
|
|
|
|
| def simulate_game(): |
|
|
| board = [0, 0, 0, 0, 0, 0, 0, 0, 0] |
| end = False |
|
|
| while end != True: |
| print_board(board) |
| move = int(input('Enter move: ')) |
| if move <= 9 and move >= 1 and board[move - 1] == 0: |
| board[move - 1] = 1 |
| print_board(board) |
| if check_winner(board) == 1: |
| print('You win') |
| end = True |
| break |
| if check_winner(board) == 3: |
| print('Draw') |
| end = True |
| break |
| print('Computer is thinking...') |
| intput = encode_input(board) |
| model = load_model() |
| prediction = inference_model(model, intput) |
| output = decode_prediction(prediction, board) |
| board = output |
| if check_winner(board) == 2: |
| print_board(board) |
| print('Computer wins') |
| end = True |
| break |
| if check_winner(board) == 3: |
| print('Draw') |
| end = True |
| break |
|
|
| else: |
| print('Invalid move') |
|
|
|
|
| if __name__ == '__main__': |
| simulate_game() |
|
|