Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions docs/USER_MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
<img src="../assets/sahara/joueur2.png" style="width: 100px; margin: 5px;">
<img src="../assets/nordique/joueur1.png" style="width: 100px; margin: 5px;">
<img src="../assets/nordique/joueur2.png" style="width: 100px; margin: 5px;">
<img src="assets/pirate/joueur1.png" style="width: 100px; margin: 5px;">
<img src="assets/pirate/joueur2.png" style="width: 100px; margin: 5px;">
<img src="assets/urbain/joueur1.png" style="width: 100px; margin: 5px;">
<img src="assets/urbain/joueur2.png" style="width: 100px; margin: 5px;">
<img src="assets/montagne/joueur1.png" style="width: 100px; margin: 5px;">
<img src="assets/montagne/joueur2.png" style="width: 100px; margin: 5px;">
<img src="../assets/pirate/joueur1.png" style="width: 100px; margin: 5px;">
<img src="../assets/pirate/joueur2.png" style="width: 100px; margin: 5px;">
<img src="../assets/urbain/joueur1.png" style="width: 100px; margin: 5px;">
<img src="../assets/urbain/joueur2.png" style="width: 100px; margin: 5px;">
<img src="../assets/montagne/joueur1.png" style="width: 100px; margin: 5px;">
<img src="../assets/montagne/joueur2.png" style="width: 100px; margin: 5px;">
</div>

> [!TIP]
Expand Down Expand Up @@ -166,6 +166,9 @@ Pour jouer en réseau :
5. Entrez un nom de partie identique pour les deux joueurs
6. Le serveur attribuera automatiquement les rôles (Joueur 1 ou 2)

> [!NOTE]
> Serveur déployé sur `potel.dev` sur le port `5000`

> [!IMPORTANT]
> Pour jouer en réseau sur Internet, assurez-vous que le port utilisé (par défaut 5000) est ouvert dans votre pare-feu et correctement redirigé si vous utilisez un routeur.

Expand Down
80 changes: 55 additions & 25 deletions src/isolation/bot.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import random
from typing import List, Tuple, Optional
from src.captures import is_threatened
from typing import List, Tuple, Optional, Dict, Set
import time
from src.captures import is_threatened, has_valid_move

class IsolationBot:
"""
Expand All @@ -12,46 +13,75 @@ def __init__(self, player_id: int):
params :
player_id - l'identifiant du joueur (1 ou 2)
"""
self.player_id = player_id - 1
self.player_id = player_id - 1
self.opponent_id = 1 - self.player_id
self.time_limit = 1.0

def get_valid_moves(self, board: List[List[List]], player: int) -> List[Tuple[int, int]]:
def get_valid_moves(self, board: List[List[List]]) -> List[Tuple[int, int]]:
"""
fonction : retourne tous les coups valides pour un joueur
fonction : trouve tous les coups valides pour un joueur
params :
board - l'état actuel du plateau
player - l'identifiant du joueur (0 ou 1)
retour : liste des positions (ligne, colonne) valides
board - plateau de jeu
retour : liste des positions valides
"""
valid_moves = []
for row in range(len(board)):
for column in range(len(board[0])):
if board[row][column][0] is None and not is_threatened(board, row, column, 1 - player, check_all_pieces=True):
valid_moves.append((row, column))
rows = len(board)
cols = len(board[0]) if rows > 0 else 0

for i in range(rows):
for j in range(cols):
if board[i][j][0] is None and not is_threatened(board, i, j, self.player_id, check_all_pieces=True):
valid_moves.append((i, j))

return valid_moves

def evaluate_move(self, board: List[List[List]], move: Tuple[int, int]) -> int:
"""
fonction : évalue un coup en calculant combien de coups seront disponibles pour l'adversaire
params :
board - plateau de jeu
move - coup à évaluer (row, col)
retour : score du coup (plus petit = meilleur)
"""
row, col = move
board[row][col][0] = self.player_id

opponent_moves = 0
for i in range(len(board)):
for j in range(len(board[0])):
if board[i][j][0] is None and not is_threatened(board, i, j, self.opponent_id, check_all_pieces=True):
opponent_moves += 1

board[row][col][0] = None

return -opponent_moves

def get_move(self, board: List[List[List]]) -> Optional[Tuple[int, int]]:
"""
fonction : détermine le meilleur coup à jouer
params :
board - l'état actuel du plateau
retour : Position (ligne, colonne) du meilleur coup
board - plateau de jeu
retour : position (row, col) du meilleur coup, ou None s'il n'y a pas de coup valide
"""
valid_moves = self.get_valid_moves(board, self.player_id)
start_time = time.time()

valid_moves = self.get_valid_moves(board)

if not valid_moves:
return None

if len(valid_moves) == 1:
return valid_moves[0]


evaluated_moves = []
for move in valid_moves:
row, column = move
board[row][column][0] = self.player_id
opponent_moves = self.get_valid_moves(board, self.opponent_id)
board[row][column][0] = None
score = self.evaluate_move(board, move)
evaluated_moves.append((move, score))

if len(opponent_moves) == 0:
return move

return random.choice(valid_moves)
if time.time() - start_time > self.time_limit:
break

evaluated_moves.sort(key=lambda x: x[1], reverse=True)

top_moves = [move for move, _ in evaluated_moves[:min(3, len(evaluated_moves))]]
return random.choice(top_moves)
4 changes: 2 additions & 2 deletions src/isolation/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def on_click(self, row: int, col: int) -> bool:
# gestion du tour du bot
if self.round_turn == 1 and self.game_mode == "Bot":
self.render.edit_info_label("Bot is thinking...")
pygame.time.set_timer(pygame.USEREVENT, 500) # délai pour l'action du bot
pygame.time.set_timer(pygame.USEREVENT, 10) # délai pour l'action du bot
self._bot_timer_set = True
else:
self.render.edit_info_label(f"Player {self.round_turn + 1}'s turn - Place your tower")
Expand Down Expand Up @@ -221,7 +221,7 @@ def load_game(self) -> None:
self.render.edit_info_label(f"Player {self.round_turn + 1}'s turn - Place your tower")
self.render.run_game_loop()
if getattr(self.render, "end_popup_action", None) == "play_again":
from src.windows.selector.selector import Selector
from src.windows.selector import Selector
Selector()
self.cleanup()

Expand Down
2 changes: 1 addition & 1 deletion src/windows/screens/base_screen.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pygame
from src.windows.components.navbar.navbar import NavBar
from src.windows.components.navbar import NavBar
from src.utils.logger import Logger
from src.utils.theme_manager import ThemeManager
from src.windows.font_manager import FontManager
Expand Down
2 changes: 0 additions & 2 deletions src/windows/screens/game_config/game_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,11 @@ def setup_ui(self):
"""
procédure : configure l'interface utilisateur de l'écran.
"""
padding = 20
element_spacing = 20
label_spacing = 10
current_y = self.navbar_height + 200

button_font = self.font_manager.get_font(30)
title_font = self.font_manager.get_font(24)
self.font = self.font_manager.get_font(20)

self.labels = []
Expand Down
2 changes: 0 additions & 2 deletions src/windows/screens/network/create_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,11 @@ def __init__(self):
Logger.error("CreateGameScreen", "Failed to load quadrant configurations.")

def setup_ui(self):
padding = 20
element_spacing = 20
label_spacing = 10
current_y = self.navbar_height + 200

button_font = self.font_manager.get_font(30)
title_font = self.font_manager.get_font(24)
self.font = self.font_manager.get_font(20)

self.labels = []
Expand Down
29 changes: 12 additions & 17 deletions src/windows/screens/network/join_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ def __init__(self):
Logger.error("JoinGameScreen", "Failed to load quadrant configurations.")
self.selected_quadrants = None

self.background = pygame.image.load('assets/pirate/background.png').convert()
theme = self.theme_manager.current_theme
self.background = pygame.image.load(f'assets/{theme}/background.png').convert()
Logger.info("JoinGameScreen", f"Using theme: {theme} for background")

self.icon_green_circle = pygame.image.load('assets/Basic_GUI_Bundle/ButtonsIcons/IconButton_Large_Green_Circle.png').convert_alpha()
self.icon_red_circle = pygame.image.load('assets/Basic_GUI_Bundle/ButtonsIcons/IconButton_Large_Red_Circle.png').convert_alpha()

Expand Down Expand Up @@ -69,25 +72,17 @@ def on_game_list_received(self, games):
Logger.info("JoinGameScreen", f"Received {len(games)} games from server")

def setup_ui(self):
try:
self.title_font = pygame.font.SysFont('Arial', 48, bold=True)
self.status_font = pygame.font.SysFont('Arial', 20, bold=True)
self.host_font = pygame.font.SysFont('Arial', 18)
self.button_font = pygame.font.SysFont('Arial', 18, bold=True)
self.footer_font = pygame.font.SysFont('Arial', 14)
except Exception as e:
Logger.error("JoinGameScreen", f"Font loading error: {str(e)}")
self.title_font = pygame.font.Font(None, 48)
self.status_font = pygame.font.Font(None, 20)
self.host_font = pygame.font.Font(None, 18)
self.button_font = pygame.font.Font(None, 18)
self.footer_font = pygame.font.Font(None, 14)
self.title_font = self.font_manager.get_font(48)
self.status_font = self.font_manager.get_font(20)
self.host_font = self.font_manager.get_font(18)
self.button_font = self.font_manager.get_font(18)
self.footer_font = self.font_manager.get_font(14)

panel_width = int(self.width * 0.7)
panel_height = int(self.height * 0.6)
self.panel_x = (self.width - panel_width) // 2

self.panel_y = self.navbar_height + 60
self.panel_y = self.navbar_height + 120

self.panel_width = panel_width
self.panel_height = panel_height
Expand Down Expand Up @@ -298,8 +293,8 @@ def draw_screen(self):
title_join = self.title_font.render("JOIN A GAME", True, (255, 255, 255))
title_network_x = (self.width - title_network.get_width()) // 2
title_join_x = (self.width - title_join.get_width()) // 2
self.screen.blit(title_network, (title_network_x, self.panel_y - 90))
self.screen.blit(title_join, (title_join_x, self.panel_y - 40))
self.screen.blit(title_network, (title_network_x, self.panel_y - 110))
self.screen.blit(title_join, (title_join_x, self.panel_y - 60))

self.refresh_button.draw(self.screen)

Expand Down
6 changes: 1 addition & 5 deletions src/windows/selector/quadrant_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,7 @@ def draw_quadrant(self, screen: pygame.Surface, quadrant_data: List[List[List[Op
x_offset (int): coordonnée x du coin supérieur gauche de la zone de dessin du quadrant.
y_offset (int): coordonnée y du coin supérieur gauche de la zone de dessin du quadrant.
cell_size (int): taille en pixels d'une cellule dans la prévisualisation.
"""
if quadrant_data is None:
Logger.error("QuadrantHandler", "Call draw_quadrant with quadrant_data to none.")
return

"""
for row_i, row in enumerate(quadrant_data):
for col_i, cell_state in enumerate(row):
x1 = x_offset + col_i * cell_size
Expand Down