diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md
index 7f29c26..befad05 100644
--- a/docs/USER_MANUAL.md
+++ b/docs/USER_MANUAL.md
@@ -11,12 +11,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
> [!TIP]
@@ -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.
diff --git a/src/isolation/bot.py b/src/isolation/bot.py
index 0435838..537d989 100644
--- a/src/isolation/bot.py
+++ b/src/isolation/bot.py
@@ -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:
"""
@@ -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)
\ No newline at end of file
+ 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)
\ No newline at end of file
diff --git a/src/isolation/game.py b/src/isolation/game.py
index 8d27cff..e0d0020 100644
--- a/src/isolation/game.py
+++ b/src/isolation/game.py
@@ -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")
@@ -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()
diff --git a/src/windows/components/navbar/navbar.py b/src/windows/components/navbar.py
similarity index 100%
rename from src/windows/components/navbar/navbar.py
rename to src/windows/components/navbar.py
diff --git a/src/windows/screens/base_screen.py b/src/windows/screens/base_screen.py
index be95e36..b9a408c 100644
--- a/src/windows/screens/base_screen.py
+++ b/src/windows/screens/base_screen.py
@@ -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
diff --git a/src/windows/screens/game_config/game_config.py b/src/windows/screens/game_config/game_config.py
index f296eed..3c3aea3 100644
--- a/src/windows/screens/game_config/game_config.py
+++ b/src/windows/screens/game_config/game_config.py
@@ -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 = []
diff --git a/src/windows/screens/network/create_game.py b/src/windows/screens/network/create_game.py
index 6bc2dd8..a8675e8 100644
--- a/src/windows/screens/network/create_game.py
+++ b/src/windows/screens/network/create_game.py
@@ -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 = []
diff --git a/src/windows/screens/network/join_game.py b/src/windows/screens/network/join_game.py
index 077533c..50c474b 100644
--- a/src/windows/screens/network/join_game.py
+++ b/src/windows/screens/network/join_game.py
@@ -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()
@@ -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
@@ -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)
diff --git a/src/windows/selector/quadrant_handler.py b/src/windows/selector/quadrant_handler.py
index 0308a3f..62bedce 100644
--- a/src/windows/selector/quadrant_handler.py
+++ b/src/windows/selector/quadrant_handler.py
@@ -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