commit d552ad232869d835bca3118dc23fc0c3ea5c72c6 Author: The-Tysonator Date: Sun Apr 23 12:00:40 2023 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc6664a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_STORE +venv/ \ No newline at end of file diff --git a/assets/font.ttf b/assets/font.ttf new file mode 100755 index 0000000..a9e0e6c Binary files /dev/null and b/assets/font.ttf differ diff --git a/assets/menu.png b/assets/menu.png new file mode 100755 index 0000000..0ea63e0 Binary files /dev/null and b/assets/menu.png differ diff --git a/assets/restart.png b/assets/restart.png new file mode 100755 index 0000000..b8ceb25 Binary files /dev/null and b/assets/restart.png differ diff --git a/assets/vsai.png b/assets/vsai.png new file mode 100755 index 0000000..0b8c644 Binary files /dev/null and b/assets/vsai.png differ diff --git a/assets/vshuman.png b/assets/vshuman.png new file mode 100755 index 0000000..9de1685 Binary files /dev/null and b/assets/vshuman.png differ diff --git a/button.py b/button.py new file mode 100755 index 0000000..4714719 --- /dev/null +++ b/button.py @@ -0,0 +1,29 @@ +# Imports +import pygame + +# Buton +class Button(): + + # Constructor Method + def __init__(self, image, x, y): + self.image = image + self.rect = self.image.get_rect() + self.rect.x = x + self.rect.y = y + self.clicked = False + + # Draw + def draw(self, screen): + # Action + action = False + # Click + if self.rect.collidepoint(pygame.mouse.get_pos()): + if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False: + self.clicked = True + if pygame.mouse.get_pressed()[0] == 0 and self.clicked == True: + self.clicked = False + action = True + # Draw Button + screen.blit(self.image, self.rect) + # Return Action + return action \ No newline at end of file diff --git a/game_functions.py b/game_functions.py new file mode 100755 index 0000000..fb79312 --- /dev/null +++ b/game_functions.py @@ -0,0 +1,189 @@ +# Imports +import pygame, time, random + +# Animate X +def animate_X(screen, cell_x, cell_y): + # Position + cell_x *= 100 + cell_y *= 100 + # Animation + for i in range(35): + pygame.draw.line(screen, (255, 100, 100), (cell_x + 50 - i, cell_y + 50 - i), (cell_x + 50 + i, cell_y + 50 + i), 6) + pygame.draw.line(screen, (255, 100, 100), (cell_x + 50 - i, cell_y + 50 + i), (cell_x + 50 + i, cell_y + 50 - i), 6) + pygame.display.update() + time.sleep(0.006) + +# Animate 0 +def animate_0(screen, cell_x, cell_y): + # Position + cell_x *= 100 + cell_y *= 100 + # Animation + for i in range(39): + pygame.draw.circle(screen, (100, 100, 255), (cell_x + 50, cell_y + 50), i) + if i > 6: + pygame.draw.circle(screen, (255, 255, 200), (cell_x + 50, cell_y + 50), i - 6) + pygame.display.update() + time.sleep(0.006) + +# Draw Board +def draw_board(screen, board): + # Background Color + screen.fill((255, 255, 200)) + # Grid + for i in range(1,3): + pygame.draw.line(screen, (0, 0, 0), (i * 100, 0), (i * 100, 300), 6) + pygame.draw.line(screen, (0, 0, 0), (0, i * 100), (300, i * 100), 6) + # Markers + row_count = 0 + for y in board: + column_count = 0 + for x in y: + row_count *= 100 + column_count *= 100 + if x == 1: + pygame.draw.line(screen, (255, 100, 100), (column_count + 15, row_count + 15), (column_count + 85, row_count + 85), 6) + pygame.draw.line(screen, (255, 100, 100), (column_count + 85, row_count + 15), (column_count + 15, row_count + 85), 6) + elif x == -1: + pygame.draw.circle(screen, (100, 100, 255), (column_count + 50, row_count + 50), 39) + pygame.draw.circle(screen, (255, 255, 200), (column_count + 50, row_count + 50), 33) + row_count /= 100 + column_count /= 100 + column_count += 1 + row_count += 1 + +# Check Winner +def check_winner(board): + # Winner + winner = None + # Check Draw + found_zero = True + for column in board: + for row in column: + if row == 0: + found_zero = False + if found_zero: + winner = 0 + # Check Rows + if winner == None or winner == 0: + for row in board: + row_sum = 0 + for column in row: + row_sum += column + if row_sum == 3: + winner = 1 + break + elif row_sum == -3: + winner = -1 + break + # Check Columns + if winner == None or winner == 0: + for column in range(3): + column_sum = 0 + for y in board: + column_sum += y[column] + if column_sum == 3: + winner = 1 + break + elif column_sum == -3: + winner = -1 + break + # Check Diagonals + if winner == None or winner == 0: + diagonal_sum = 0 + for i in range(3): + diagonal_sum += board[i][i] + if diagonal_sum == 3: + winner = 1 + elif diagonal_sum == -3: + winner = -1 + if winner == None or winner == 0: + diagonal_sum = 0 + for i in range(3): + row = 2 - i + column = i + diagonal_sum += board[row][column] + if diagonal_sum == 3: + winner = 1 + elif diagonal_sum == -3: + winner = -1 + return winner + +# AI Move +def ai_move(board): + # Move Loop + while True: + # Block Rows + for row_counter, row in enumerate(board): + player_one = 0 + player_two = 0 + empty_space = None + for column_counter, column in enumerate(row): + if column == 1: + player_one += 1 + if column == -1: + player_two += 1 + if column == 0: + empty_space = [row_counter, column_counter] + if player_one == 2 or player_two == 2: + if empty_space != None: + return empty_space[0], empty_space[1] + # Block Columns + for column in range(3): + player_one = 0 + player_two = 0 + empty_space = None + for row in range(3): + if board[row][column] == 1: + player_one += 1 + if board[row][column] == -1: + player_two += 1 + if board[row][column] == 0: + empty_space = [row, column] + if player_one == 2 or player_one == 2: + if empty_space != None: + return empty_space[0], empty_space[1] + # Block Diagonals + player_one = 0 + player_two = 0 + empty_space = None + for i in range(3): + if board[i][i] == 1: + player_one += 1 + if board[i][i] == -1: + player_two += 1 + if board[i][i] == 0: + empty_space = [i, i] + if player_one == 2 or player_two == 2: + if empty_space != None: + return empty_space[0], empty_space[1] + player_one = 0 + player_two = 0 + empty_space = None + if board[0][2] == 1: + player_one += 1 + if board[0][2] == -1: + player_two += 1 + if board[0][2] == 0: + empty_space = [0, 2] + if board[1][1] == 1: + player_one += 1 + if board[1][1] == -1: + player_two += 1 + if board[1][1] == 0: + empty_space = [0, 0] + if board[2][0] == 1: + player_one += 1 + if board[2][0] == -1: + player_two += 1 + if board[2][0] == 0: + empty_space = [2, 0] + if player_one == 2 or player_two == 2: + if empty_space != None: + return empty_space[0], empty_space[1] + # Random + while True: + row = random.randint(0, 2) + column = random.randint(0, 2) + if board[row][column] == 0: + return row, column \ No newline at end of file diff --git a/main.py b/main.py new file mode 100755 index 0000000..c70aa72 --- /dev/null +++ b/main.py @@ -0,0 +1,235 @@ +# Imports +import pygame, random +from button import Button +from game_functions import animate_X, animate_0, draw_board, check_winner, ai_move + +# Setup +pygame.init() +screen = pygame.display.set_mode((300, 300)) +pygame.display.set_caption("TicTacToe") +clock = pygame.time.Clock() +pygame.font.init() +font = pygame.font.Font("./assets/font.ttf", 70) + +# Buttons +button_human = Button(pygame.image.load("./assets/vshuman.png"), 50, 135) +button_ai = Button(pygame.image.load("./assets/vsai.png"), 50, 185) +button_menu = Button(pygame.image.load("./assets/menu.png"), 50, 135) +button_restart = Button(pygame.image.load("./assets/restart.png"), 50, 185) + +# Title Screen +def screen_title(): + # Game Loop + counter = 0 + run = True + while run: + # Tick + clock.tick(30) + # Event Handler + for event in pygame.event.get(): + # Quit + if event.type == pygame.QUIT: + pygame.quit() + exit() + counter += 1 + if counter == 120: + run = False + # Display Title Screen + if run: + screen.fill((255, 255, 200)) + text = font.render("Tic", 1, (255, 100, 100)) + screen.blit(text, (25, 15)) + text = font.render("Tac", 1, (0, 0, 0)) + screen.blit(text, (95, 15)) + text = font.render("Toe", 1, (100, 100, 255)) + screen.blit(text, (180, 15)) + text = font.render("by", 1, (0, 0, 0)) + screen.blit(text, (120, 107)) + text = font.render("Tylan", 1, (255, 100, 100)) + screen.blit(text, (5, 210)) + text = font.render("Tyson", 1, (100, 100, 255)) + screen.blit(text, (140, 210)) + # Update Display + pygame.display.update() + +# Menu Screen +def screen_menu(): + # Game Loop + option = None + run = True + while run: + # Tick + clock.tick(30) + # Event Handler + for event in pygame.event.get(): + # Quit + if event.type == pygame.QUIT: + pygame.quit() + exit() + # Display Title + screen.fill((255, 255, 200)) + text = font.render("Tic", 1, (255, 100, 100)) + screen.blit(text, (25, 15)) + text = font.render("Tac", 1, (0, 0, 0)) + screen.blit(text, (95, 15)) + text = font.render("Toe", 1, (100, 100, 255)) + screen.blit(text, (180, 15)) + # Buttons + if button_human.draw(screen): + option = "human" + run = False + if button_ai.draw(screen): + option = "ai" + run = False + # Update Display + pygame.display.update() + # Return Option + return option + +# Winner Screen +def screen_winner(winner, restart_option): + # Game Loop + option = None + run = True + while run: + # Tick + clock.tick(30) + # Event Handler + for event in pygame.event.get(): + # Quit + if event.type == pygame.QUIT: + pygame.quit() + exit() + # Display Title + screen.fill((255, 255, 200)) + if winner == 0: + text = font.render("Draw!", 1, (0, 0, 0)) + screen.blit(text, (75, 15)) + if winner == 1: + text = font.render("X Won!", 1, (255, 100, 100)) + screen.blit(text, (60, 15)) + if winner == -1: + text = font.render("0 Won!", 1, (100, 100, 255)) + screen.blit(text, (60, 15)) + # Buttons + if button_menu.draw(screen): + option = None + run = False + if button_restart.draw(screen): + option = restart_option + run = False + # Update Display + pygame.display.update() + # Return Option + return option + +# Title Screen +screen_title() + +# Game Loop +option = None +human_first_run = True +ai_first_run = True +run = True +while run: + # Tick + clock.tick(30) + # Menu + if option == None: + option = screen_menu() + # VS Human + if option == "human": + if human_first_run: + start = random.randint(1, 2) + if start == 1: + player = 1 + else: + player = -1 + mouse_position = None + clicked = False + human_first_run = False + board = [ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0] + ] + draw_board(screen, board) + for event in pygame.event.get(): + if event.type == pygame.MOUSEBUTTONDOWN and clicked == False: + clicked = True + if event.type == pygame.MOUSEBUTTONUP and clicked == True: + clicked = False + mouse_position = pygame.mouse.get_pos() + cell_x = mouse_position[0] + cell_y = mouse_position[1] + if board[cell_y // 100][cell_x // 100] == 0: + board[cell_y // 100][cell_x // 100] = player + if player == 1: + animate_X(screen, cell_x // 100, cell_y // 100) + elif player == -1: + animate_0(screen, cell_x // 100, cell_y // 100) + player *= - 1 + if event.type == pygame.QUIT: + run = False + winner = check_winner(board) + if winner != None: + human_first_run = True + option = screen_winner(winner, "human") + pygame.display.update() + # VS AI + if option == "ai": + if ai_first_run: + start = random.randint(1, 2) + player = 1 + mouse_position = None + clicked = False + ai_first_run = False + board = [ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0] + ] + if start == 1: + draw_board(screen, board) + pygame.display.update() + row, column = ai_move(board) + board[row][column] = player + animate_X(screen, column, row) + player *= -1 + start = 0 + draw_board(screen, board) + for event in pygame.event.get(): + if event.type == pygame.MOUSEBUTTONDOWN and clicked == False: + clicked = True + if event.type == pygame.MOUSEBUTTONUP and clicked == True: + clicked = False + mouse_position = pygame.mouse.get_pos() + mouse_position = pygame.mouse.get_pos() + cell_x = mouse_position[0] + cell_y = mouse_position[1] + if board[cell_y // 100][cell_x // 100] == 0: + board[cell_y // 100][cell_x // 100] = player + if player == 1: + animate_X(screen, cell_x // 100, cell_y // 100) + elif player == -1: + animate_0(screen, cell_x // 100, cell_y // 100) + player *= - 1 + winner = check_winner(board) + if winner == None: + row, column = ai_move(board) + board[row][column] = player + if player == 1: + animate_X(screen, column, row) + elif player == -1: + animate_0(screen, column, row) + player *= -1 + if event.type == pygame.QUIT: + run = False + winner = check_winner(board) + if winner != None: + ai_first_run = True + option = screen_winner(winner, "ai") + pygame.display.update() + +# Quit Pygame +pygame.quit() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..49f851d --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pygame==2.3.0