commit 48987665ac8b305a369fc07e8ae182d67964a36a Author: kromskii2 <146603192+kromskii2@users.noreply.github.com> Date: Thu Nov 7 10:32:02 2024 +0700 Add files via upload diff --git a/README.md b/README.md new file mode 100644 index 0000000..58df1bc --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +"# Tic-Tac-Toe-AI" diff --git a/main.py b/main.py new file mode 100644 index 0000000..7dc2aae --- /dev/null +++ b/main.py @@ -0,0 +1,147 @@ +import pygame +import numpy as np +import torch +import random +import torch.nn as nn +import torch.optim as optim + +# Параметры игры и обучения +BOARD_SIZE = 10 # Изменили размер доски на 10x10 +WIN_LENGTH = 5 # Нужно собрать 5 в ряд для победы +WIN_REWARD = 1 +DRAW_REWARD = 0.5 +LOSE_REWARD = -1 +ALPHA = 0.1 +GAMMA = 0.9 +CELL_SIZE = 60 # Размер клетки на экране (уменьшен для 10x10) +SCREEN_SIZE = BOARD_SIZE * CELL_SIZE + +# Инициализация Pygame +pygame.init() +screen = pygame.display.set_mode((SCREEN_SIZE, SCREEN_SIZE)) +pygame.display.set_caption("Tic-Tac-Toe AI") + +# Цвета +WHITE = (255, 255, 255) +BLACK = (0, 0, 0) +RED = (255, 0, 0) +BLUE = (0, 0, 255) + +# Нейронная сеть +class TicTacToeNet(nn.Module): + def __init__(self): + super(TicTacToeNet, self).__init__() + self.fc1 = nn.Linear(BOARD_SIZE * BOARD_SIZE, 128) + self.fc2 = nn.Linear(128, 128) + self.fc3 = nn.Linear(128, BOARD_SIZE * BOARD_SIZE) + + def forward(self, x): + x = torch.relu(self.fc1(x)) + x = torch.relu(self.fc2(x)) + return self.fc3(x) + +model = TicTacToeNet() +optimizer = optim.Adam(model.parameters(), lr=0.001) +loss_fn = nn.MSELoss() + +def get_empty_cells(board): + return [(i, j) for i in range(BOARD_SIZE) for j in range(BOARD_SIZE) if board[i][j] == 0] + +def check_winner(board, player): + for row in range(BOARD_SIZE): + for col in range(BOARD_SIZE): + if board[row][col] == player: + if check_direction(board, player, row, col, 1, 0) or \ + check_direction(board, player, row, col, 0, 1) or \ + check_direction(board, player, row, col, 1, 1) or \ + check_direction(board, player, row, col, 1, -1): + return True + return False + +def check_direction(board, player, row, col, dr, dc): + count = 0 + for _ in range(WIN_LENGTH): + if 0 <= row < BOARD_SIZE and 0 <= col < BOARD_SIZE and board[row][col] == player: + count += 1 + row += dr + col += dc + else: + break + return count == WIN_LENGTH + +def train_step(state, action, reward, next_state, done): + state_tensor = torch.FloatTensor(state).view(1, -1) + next_state_tensor = torch.FloatTensor(next_state).view(1, -1) + q_values = model(state_tensor) + q_next = model(next_state_tensor).detach() + target = q_values.clone() + target[0][action] = reward + GAMMA * torch.max(q_next) if not done else reward + optimizer.zero_grad() + loss = loss_fn(q_values, target) + loss.backward() + optimizer.step() + +# Функция для отрисовки игрового поля +def draw_board(board): + screen.fill(WHITE) + for i in range(1, BOARD_SIZE): + pygame.draw.line(screen, BLACK, (0, i * CELL_SIZE), (SCREEN_SIZE, i * CELL_SIZE), 2) + pygame.draw.line(screen, BLACK, (i * CELL_SIZE, 0), (i * CELL_SIZE, SCREEN_SIZE), 2) + for row in range(BOARD_SIZE): + for col in range(BOARD_SIZE): + if board[row][col] == 1: + pygame.draw.circle(screen, BLUE, (col * CELL_SIZE + CELL_SIZE // 2, row * CELL_SIZE + CELL_SIZE // 2), CELL_SIZE // 3, 2) + elif board[row][col] == 2: + pygame.draw.line(screen, RED, (col * CELL_SIZE + 20, row * CELL_SIZE + 20), + (col * CELL_SIZE + CELL_SIZE - 20, row * CELL_SIZE + CELL_SIZE - 20), 2) + pygame.draw.line(screen, RED, (col * CELL_SIZE + CELL_SIZE - 20, row * CELL_SIZE + 20), + (col * CELL_SIZE + 20, row * CELL_SIZE + CELL_SIZE - 20), 2) + pygame.display.flip() + +# Игра против компьютера с визуализацией +def play_game(): + board = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int) + done = False + player_turn = 1 + + while not done: + draw_board(board) + pygame.time.delay(500) + + if player_turn == 1: + state = board.flatten() + state_tensor = torch.FloatTensor(state).view(1, -1) + q_values = model(state_tensor) + action = torch.argmax(q_values).item() + row, col = divmod(action, BOARD_SIZE) + if board[row][col] == 0: + board[row][col] = 1 + reward = WIN_REWARD if check_winner(board, 1) else 0 + done = reward != 0 or not get_empty_cells(board) + player_turn = 2 + else: + reward = LOSE_REWARD + done = True + else: + empty_cells = get_empty_cells(board) + row, col = random.choice(empty_cells) + board[row][col] = 2 + reward = LOSE_REWARD if check_winner(board, 2) else 0 + done = reward != 0 or not get_empty_cells(board) + player_turn = 1 + + next_state = board.flatten() + train_step(state, row * BOARD_SIZE + col, reward, next_state, done) + draw_board(board) + pygame.time.delay(1000) + +# Цикл обучения и игры +for episode in range(1000): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + exit() + play_game() + if episode % 100 == 0: + print(f"Episode {episode} complete") +print("Модель обучена.")