oops i forgot to commit. started working on a gui, fixed some bugs and added a search_depth setting

This commit is contained in:
Vincent Rodley 2025-08-20 12:37:15 +12:00
parent cee3be9334
commit 3ef31d350b
6 changed files with 229 additions and 16 deletions

BIN
Baloo2-Bold.ttf Normal file

Binary file not shown.

View File

@ -14,3 +14,6 @@ pvp lan todo:
remember the last ip you played against. remember ip input with a name? remember the last ip you played against. remember ip input with a name?
stop multiple ppl joining one game (or add spectators) stop multiple ppl joining one game (or add spectators)
make it so when ppl leave, the game ends instead of hanging or crashing. make it so when ppl leave, the game ends instead of hanging or crashing.
player vs computer todo:
sometimes it prioritizes vertical 3-in-a-rows instead of a win. (balance threat and winning)

30
button.py Normal file
View File

@ -0,0 +1,30 @@
import pygame
class Button:
def __init__(self, x, y, width, height, text, color, hover_color, text_color, action, font, font_size, extra_data = None):
self.rect = pygame.Rect(x, y, width, height)
self.text = text
self.color = color
self.hover_color = hover_color
self.text_color = text_color
self.current_color = color
self.action = action
self.font = pygame.font.Font(font, font_size)
self.extra_data = extra_data
def draw(self, screen):
pygame.draw.rect(screen, self.current_color, self.rect)
text_surface = self.font.render(self.text, True, self.text_color)
text_rect = text_surface.get_rect(center=self.rect.center)
screen.blit(text_surface, text_rect)
def handle_event(self, event):
if event.type == pygame.MOUSEMOTION:
if self.rect.collidepoint(event.pos):
self.current_color = self.hover_color
else:
self.current_color = self.color
elif event.type == pygame.MOUSEBUTTONDOWN:
if self.rect.collidepoint(event.pos):
self.action(self)

111
guitest.py Normal file
View File

@ -0,0 +1,111 @@
# Imports
import pygame
from pygame import Vector2 as v2, Color as Colour
from button import Button
# some constst
WINDOW_SIZE = (768, 768)
WINDOW_SCALE = 1
TARGET_FPS = 60
# pygame inits
pygame.init()
display = pygame.display.set_mode(v2(WINDOW_SIZE)*WINDOW_SCALE)
clock = pygame.time.Clock()
# more variable inits
menu = "start"
tiles = []
# menu functions
def change_menu(targetMenu):
global menu
menu = targetMenu
display.fill('black')
def start_game_func(*_):
change_menu("game")
def settings_menu(*_):
change_menu("settings")
def go_back(*_):
change_menu("start")
# gets called when you click on a tile
def tile_press(tile):
tile_id,x,y = tile.extra_data
print(f"TILE {tile_id} at {x},{y} PRESSED")
# Main block
if __name__ == "__main__":
# You're running the game, therefore running = True
running = True
# Button inits
width = 280
height = 75
x = WINDOW_SIZE[0] / 2 - width / 2 # center of the screen horizontally
y = (WINDOW_SIZE[1] / 2 - height / 2) # center of the screen vertically
start_button = Button(x, y - 100, width, height, "Start Game", (0, 150, 0), (255, 0, 0), (255, 255, 255), start_game_func, "Baloo2-Bold.ttf", 50)
settings_button = Button(x, y-100+height*2, width, height, "Settings", (0, 150, 0), (255, 0, 0), (255, 255, 255), settings_menu, "Baloo2-Bold.ttf", 50)
go_back_button = Button(x, y, width, height, "Go back", (0, 150, 0), (255, 0, 0), (255, 255, 255), go_back, "Baloo2-Bold.ttf", 50)
# Game loop
while running:
# handles user input
for event in pygame.event.get():
# Lets you actually close the game, or ESC out
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# Handles all the inputs for the buttons
if menu == "start":
start_button.handle_event(event)
settings_button.handle_event(event)
elif menu == "settings":
go_back_button.handle_event(event)
elif menu == "game":
for tile in tiles:
tile.handle_event(event)
else:
# very descriptive error message
print("You broke smth idek what tbh")
running = False
# Display stuff!
# so depending on what menu you're in, draw different stuff
if menu == "start":
start_button.draw(display)
settings_button.draw(display)
elif menu == "settings":
go_back_button.draw(display)
# basic connect-4 ahh grid
elif menu == "game":
COLS = 7
ROWS = 6
tiles = []
for c in range(COLS):
for r in range(ROWS):
tile = Button(50*c+50, 50*r+50, 30, 30, str(len(tiles)), (255, 255, 255), (150, 150, 150), (255, 0, 0), tile_press, None, 30, (len(tiles),c,r))
tiles.append(tile)
for tile in tiles:
tile.draw(display)
else:
# very descriptive error msg
print("you broke smth.")
running = False
# flip the display and clock the tick so stuff actually updates
pygame.display.flip()
clock.tick(TARGET_FPS)

98
main.py
View File

@ -83,10 +83,6 @@ def printBoard(board):
============================={C.END}""" ============================={C.END}"""
bottom = f"{C.BOLD}==1===2===3===4===5===6===7=={C.END}" bottom = f"{C.BOLD}==1===2===3===4===5===6===7=={C.END}"
# print(f""" {C.BOLD}CONNECT FOUR
# ============================={C.END}
# {'\n'.join(rows)}
# {C.BOLD}==1===2===3===4===5===6===7=={C.END}""")
print(f"{top}\n{'\n'.join(rows)}\n{bottom}") print(f"{top}\n{'\n'.join(rows)}\n{bottom}")
@ -124,13 +120,18 @@ def checkWin(board, player):
if all(board[col + i][row - i] == player for i in range(winCount)): if all(board[col + i][row - i] == player for i in range(winCount)):
return [(col + i, row - i) for i in range(winCount)] return [(col + i, row - i) for i in range(winCount)]
def checkFull(board):
if all('O' not in col for col in board):
return True
return False
def isTerminalNode(board): def isTerminalNode(board):
if checkWin(board, 'R'): if checkWin(board, 'R'):
return "WinX" return "WinX"
elif checkWin(board, 'Y'): elif checkWin(board, 'Y'):
return "WinY" return "WinY"
elif checkFull(board):
if all('O' not in col for col in board):
return "Draw" return "Draw"
return False return False
@ -253,7 +254,17 @@ def cpu_move_provider(player, board):
best_score = float('-inf') if player == 'R' else float('inf') best_score = float('-inf') if player == 'R' else float('inf')
best_move = None best_move = None
# try:
# with open("settings.json", "r") as f:
# settings = json.load(f)
# print(f"Settings: {settings}")
# search_depth = settings.get("cpu_search_depth", 5)
# print(f"search depth: {search_depth}")
# except (FileNotFoundError, json.JSONDecodeError):
# search_depth = 5
search_depth = 5 search_depth = 5
maximising = True if player == 'R' else False maximising = True if player == 'R' else False
for move in allowedMoves: for move in allowedMoves:
@ -288,7 +299,6 @@ def play_game(player1_get_move, player2_get_move):
clear() clear()
printBoard(board) printBoard(board)
# Get column from correct player
if player == 'R': if player == 'R':
col = player1_get_move(player, board) col = player1_get_move(player, board)
else: else:
@ -311,6 +321,13 @@ def play_game(player1_get_move, player2_get_move):
input("Press ENTER to return to the menu.") input("Press ENTER to return to the menu.")
break break
if checkFull(board):
clear()
printBoard(board)
print("Its a draw!")
input("Press ENTER to return to the menu.")
break
player = 'Y' if player == 'R' else 'R' player = 'Y' if player == 'R' else 'R'
# =========================== # ===========================
@ -321,12 +338,12 @@ def play_local_pvp():
def play_lan_server(): def play_lan_server():
print("PvP LAN is in maintenance due to exploits.!") print("PvP LAN is in maintenance due to exploits.!")
input("Press Enter to return to menu...") input("Press ENTER to return to menu...")
return return
def play_lan_client(): def play_lan_client():
print("PvP LAN is in maintenance due to exploits.!") print("PvP LAN is in maintenance due to exploits.!")
input("Press Enter to return to menu...") input("Press ENTER to return to menu...")
return return
def play_vs_computer(): def play_vs_computer():
@ -338,7 +355,7 @@ def play_vs_computer():
raise ValueError raise ValueError
break break
except ValueError: except ValueError:
print("Enter 'r', 'red', 'y' or 'yellow'.") print("ENTER 'r', 'red', 'y' or 'yellow'.")
if inp in ["r", "red"]: if inp in ["r", "red"]:
play_game(local_move_provider, cpu_move_provider) play_game(local_move_provider, cpu_move_provider)
@ -357,7 +374,8 @@ def edit_settings():
# Default settings if no file exists # Default settings if no file exists
default_settings = { default_settings = {
"display_mode": "coloured_text" # options: coloured_text, coloured_background, emojis "display_mode": "coloured_text", # options: coloured_text, coloured_background, emojis
"cpu_search_depth": 5 # options: 1-9
} }
# Load existing settings # Load existing settings
@ -377,12 +395,13 @@ def edit_settings():
with open(settings_file, "w") as f: with open(settings_file, "w") as f:
json.dump(settings, f, indent=4) json.dump(settings, f, indent=4)
print("Settings saved.") print("Settings saved.")
input("Press Enter to return to main menu...") input("Press ENTER to return to main menu...")
while True: while True:
clear() clear()
print("=== Settings Menu ===") print("=== Settings Menu ===")
print("1. Display Mode") print("1. Display Mode")
print("2. CPU Search Depth")
print("--------------------") print("--------------------")
print("S. Save and Exit") print("S. Save and Exit")
print("E. Exit without Saving") print("E. Exit without Saving")
@ -414,7 +433,31 @@ def edit_settings():
settings["display_mode"] = modes[int(sub_choice) - 1][0] settings["display_mode"] = modes[int(sub_choice) - 1][0]
print(f"Display mode set to {settings['display_mode']}") print(f"Display mode set to {settings['display_mode']}")
else: else:
input("Invalid choice. Press Enter to try again...") input("Invalid choice. Press ENTER to try again...")
elif choice == "2":
# CPU Search Depth submenu
while True:
clear()
print("=== CPU Search Depth ===")
print(f"Depth: {C.BOLD}{settings["cpu_search_depth"]}{C.END}")
print("B. Go Back")
sub_choice = input("Choose a value 1-9, or the use + / - keys: ").strip()
if sub_choice.lower() == 'b':
break
elif sub_choice in ["1","2","3","4","5","6","7","8","9"]:
settings["cpu_search_depth"] = sub_choice
elif sub_choice in ['+', '-']:
settings["cpu_search_depth"] = eval(f"{settings["cpu_search_depth"]} {sub_choice}1")
if settings["cpu_search_depth"] > 9:
settings["cpu_search_depth"] = 9
elif settings["cpu_search_depth"] < 1:
settings["cpu_search_depth"] = 1
else:
input("Invalid choice. Press ENTER to try again...")
elif choice == "save" or choice == "s": elif choice == "save" or choice == "s":
save_settings() save_settings()
@ -429,7 +472,7 @@ def edit_settings():
return return
else: else:
input("Invalid choice. Press Enter to try again...") input("Invalid choice. Press ENTER to try again...")
while True: while True:
clear() clear()
@ -457,4 +500,29 @@ while True:
elif choice == "6": elif choice == "6":
break break
else: else:
input("Invalid choice. Press Enter to try again...") input("Invalid choice. Press ENTER to try again...")
"""
RED Drawstring
3
4
4
3
5
3
3
3
5
1
1
1
7
7
7
2
2
2
6
6
6
"""

View File

@ -1,3 +1,4 @@
{ {
"display_mode": "coloured_background" "display_mode": "emojis",
"cpu_search_depth": 6
} }