simplified some part of the game code, made some quality of life change
This commit is contained in:
parent
385adb2cf1
commit
25a3c0fa86
8 changed files with 152 additions and 85 deletions
|
@ -12,3 +12,10 @@ class BombState(Enum):
|
|||
WON = 3 # the bomb sunk the last boat
|
||||
|
||||
ERROR = -1 # the bomb could not be placed
|
||||
|
||||
@property
|
||||
def success(self):
|
||||
"""
|
||||
:return: Vrai si la valeur correspond à une case qui a été touché
|
||||
"""
|
||||
return self in [self.TOUCHED, self.SUNKEN, self.WON]
|
||||
|
|
|
@ -3,11 +3,13 @@ from typing import TYPE_CHECKING
|
|||
|
||||
import pyglet
|
||||
|
||||
from source.core.enums import BombState
|
||||
from source.core.error import InvalidBombPosition, PositionAlreadyShot
|
||||
from source.gui.scene import Result
|
||||
from source.gui.scene.abc import Scene
|
||||
from source.gui import widget, texture
|
||||
from source import core
|
||||
from source.network.packet import PacketChat, PacketBombPlaced, PacketBoatPlaced
|
||||
from source.network.packet import PacketChat, PacketBombPlaced, PacketBoatPlaced, PacketBombState
|
||||
from source.type import Point2D
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -18,7 +20,7 @@ class Game(Scene):
|
|||
def __init__(self, window: "Window",
|
||||
connection: socket.socket,
|
||||
|
||||
boat_sizes: list,
|
||||
boats_length: list,
|
||||
name_ally: str,
|
||||
name_enemy: str,
|
||||
grid_width: int,
|
||||
|
@ -29,12 +31,11 @@ class Game(Scene):
|
|||
super().__init__(window, **kwargs)
|
||||
|
||||
self.connection = connection
|
||||
self.boat_sizes = boat_sizes
|
||||
self.boats_length = boats_length
|
||||
self.name_ally = name_ally
|
||||
self.name_enemy = name_enemy
|
||||
self.grid_width = grid_width
|
||||
self.grid_height = grid_height
|
||||
self.my_turn = my_turn # is it the player turn ?
|
||||
|
||||
self.batch_label = pyglet.graphics.Batch()
|
||||
self.batch_button_background = pyglet.graphics.Batch()
|
||||
|
@ -58,7 +59,7 @@ class Game(Scene):
|
|||
|
||||
x=75, y=0.25, width=0.35, height=0.5,
|
||||
|
||||
boats_length=self.boat_sizes,
|
||||
boats_length=self.boats_length,
|
||||
|
||||
grid_style=texture.Grid.Style1,
|
||||
boat_style=texture.Grid.Boat.Style1,
|
||||
|
@ -74,10 +75,6 @@ class Game(Scene):
|
|||
|
||||
def board_ally_ready(widget):
|
||||
self.boat_ready_ally = True
|
||||
|
||||
self.me_ready()
|
||||
if self.boat_ready_enemy: self.refresh_turn_text()
|
||||
|
||||
PacketBoatPlaced().send_connection(connection)
|
||||
|
||||
self.grid_ally.add_listener("on_all_boats_placed", board_ally_ready)
|
||||
|
@ -102,6 +99,7 @@ class Game(Scene):
|
|||
def board_enemy_bomb(widget, cell: Point2D):
|
||||
if not (self.boat_ready_ally and self.boat_ready_enemy): return
|
||||
if not self.my_turn: return
|
||||
|
||||
PacketBombPlaced(position=cell).send_connection(connection)
|
||||
self.my_turn = False
|
||||
|
||||
|
@ -222,7 +220,6 @@ class Game(Scene):
|
|||
|
||||
anchor_x="center",
|
||||
|
||||
text="Placer vos bateaux",
|
||||
font_size=20,
|
||||
|
||||
batch=self.batch_label
|
||||
|
@ -231,28 +228,132 @@ class Game(Scene):
|
|||
self.board_ally = core.Board(rows=self.grid_height, columns=self.grid_width)
|
||||
self.board_enemy = core.Board(rows=self.grid_height, columns=self.grid_width)
|
||||
|
||||
self.boat_ready_ally: bool = False # does the player finished placing his boat ?
|
||||
self.boat_ready_enemy: bool = False # does the opponent finished placing his boat ?
|
||||
self._my_turn = my_turn # is it the player turn ?
|
||||
self._boat_ready_ally: bool = False # does the player finished placing his boat ?
|
||||
self._boat_ready_enemy: bool = False # does the opponent finished placing his boat ?
|
||||
self._boat_broken_ally: int = 0
|
||||
self._boat_broken_enemy: int = 0
|
||||
|
||||
def boat_broken_ally(self):
|
||||
self._boat_broken_ally += 1
|
||||
self.score_ally.text = str(self._boat_broken_ally)
|
||||
self._refresh_turn_text()
|
||||
|
||||
def boat_broken_enemy(self):
|
||||
self._boat_broken_enemy += 1
|
||||
self.score_enemy.text = str(self._boat_broken_enemy)
|
||||
# function
|
||||
|
||||
def me_ready(self):
|
||||
self.label_state.text = "L'adversaire place ses bateaux"
|
||||
|
||||
def refresh_turn_text(self):
|
||||
self.label_state.text = "Placer vos bombes" if self.my_turn else "L'adversaire place ses bombes"
|
||||
def _refresh_turn_text(self):
|
||||
self.label_state.text = (
|
||||
"Placer vos bateaux" if not self.boat_ready_ally else
|
||||
"L'adversaire place ses bateaux..." if not self.boat_ready_enemy else
|
||||
"Placer vos bombes" if self.my_turn else
|
||||
"L'adversaire place ses bombes..."
|
||||
)
|
||||
|
||||
def game_end(self, won: bool):
|
||||
self.window.add_scene(Result, won=won)
|
||||
|
||||
# property
|
||||
|
||||
@property
|
||||
def boat_broken_ally(self):
|
||||
return self._boat_broken_ally
|
||||
|
||||
@boat_broken_ally.setter
|
||||
def boat_broken_ally(self, boat_broken_ally: int):
|
||||
self._boat_broken_ally = boat_broken_ally
|
||||
self.score_ally.text = str(self._boat_broken_ally)
|
||||
|
||||
@property
|
||||
def boat_broken_enemy(self):
|
||||
return self._boat_broken_enemy
|
||||
|
||||
@boat_broken_enemy.setter
|
||||
def boat_broken_enemy(self, boat_broken_enemy: int):
|
||||
self._boat_broken_enemy = boat_broken_enemy
|
||||
self.score_enemy.text = str(self._boat_broken_enemy)
|
||||
|
||||
@property
|
||||
def my_turn(self):
|
||||
return self._my_turn
|
||||
|
||||
@my_turn.setter
|
||||
def my_turn(self, my_turn: bool):
|
||||
self._my_turn = my_turn
|
||||
self._refresh_turn_text()
|
||||
|
||||
@property
|
||||
def boat_ready_ally(self):
|
||||
return self._boat_ready_ally
|
||||
|
||||
@boat_ready_ally.setter
|
||||
def boat_ready_ally(self, boat_ready_ally: bool):
|
||||
self._boat_ready_ally = boat_ready_ally
|
||||
self._refresh_turn_text()
|
||||
|
||||
@property
|
||||
def boat_ready_enemy(self):
|
||||
return self._boat_ready_enemy
|
||||
|
||||
@boat_ready_enemy.setter
|
||||
def boat_ready_enemy(self, boat_ready_enemy: bool):
|
||||
self._boat_ready_enemy = boat_ready_enemy
|
||||
self._refresh_turn_text()
|
||||
|
||||
# network
|
||||
|
||||
def network_on_chat(self, connection: socket.socket, packet: PacketChat):
|
||||
print(packet.message)
|
||||
|
||||
def network_on_boat_placed(self, connection: socket.socket, packet: PacketBoatPlaced):
|
||||
self.boat_ready_enemy = True
|
||||
|
||||
def network_on_bomb_placed(self, connection: socket.socket, packet: PacketBombPlaced):
|
||||
try:
|
||||
# essaye de poser la bombe sur la grille alliée
|
||||
bomb_state = self.grid_ally.board.bomb(packet.position)
|
||||
except (InvalidBombPosition, PositionAlreadyShot):
|
||||
# si une erreur se produit, signale l'erreur
|
||||
bomb_state = BombState.ERROR
|
||||
# l'opposant va rejouer, ce n'est donc pas notre tour
|
||||
self.my_turn = False
|
||||
else:
|
||||
# si la bombe a bien été placé, affiche la sur la grille visuel allié
|
||||
self.grid_ally.place_bomb(packet.position, bomb_state.success)
|
||||
# c'est à notre tour si l'opposant à loupé sa bombe
|
||||
self.my_turn = not bomb_state.success
|
||||
|
||||
# envoie le résultat à l'autre joueur
|
||||
PacketBombState(position=packet.position, bomb_state=bomb_state).send_connection(connection)
|
||||
|
||||
if bomb_state.success:
|
||||
# si la bombe a touché un bateau, incrémente le score
|
||||
self.boat_broken_enemy += 1
|
||||
|
||||
if bomb_state is BombState.WON:
|
||||
# si l'ennemie à gagner, alors l'on a perdu
|
||||
self.game_end(won=False)
|
||||
return True # coupe la connexion
|
||||
|
||||
def network_on_bomb_state(self, connection: socket.socket, packet: PacketBombState):
|
||||
if packet.bomb_state is BombState.ERROR:
|
||||
# si une erreur est survenue, on rejoue
|
||||
self.my_turn = True
|
||||
return
|
||||
|
||||
# on rejoue uniquement si la bombe à toucher
|
||||
self.my_turn = packet.bomb_state.success
|
||||
|
||||
if packet.bomb_state.success:
|
||||
# si la bombe à toucher, incrémente le score
|
||||
self.boat_broken_ally += 1
|
||||
|
||||
# place la bombe sur la grille ennemie visuelle
|
||||
self.grid_enemy.place_bomb(packet.position, packet.bomb_state.success)
|
||||
|
||||
if packet.bomb_state is BombState.WON:
|
||||
# si cette bombe a touché le dernier bateau, alors l'on a gagné
|
||||
self.game_end(won=True)
|
||||
return True # coupe la connexion
|
||||
|
||||
# event
|
||||
|
||||
def on_draw(self):
|
||||
self.background.draw()
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ class RoomCreate(Scene):
|
|||
self.input_boat_amount.text = str(self.boat_size_amount.get(self.boat_size, 0))
|
||||
|
||||
self.label_boat_recap.text = ""
|
||||
for size, amount in self.boat_size_amount.items():
|
||||
for size, amount in sorted(self.boat_size_amount.items(), key=lambda v: v[0]):
|
||||
self.label_boat_recap.text += f"Taille: {size}, Quantité: {amount}\n"
|
||||
|
||||
self.button_boat_size_previous = self.add_widget(
|
||||
|
@ -199,7 +199,6 @@ class RoomCreate(Scene):
|
|||
)
|
||||
|
||||
def next_boat_size():
|
||||
if self.boat_size >= min(int(self.input_width.text), int(self.input_height.text)): return
|
||||
self.boat_size += 1
|
||||
update_boat_size_text()
|
||||
|
||||
|
@ -269,7 +268,7 @@ class RoomCreate(Scene):
|
|||
grid_width=int(self.input_width.text),
|
||||
grid_height=int(self.input_height.text),
|
||||
host_start=self.checkbox_host_start.state,
|
||||
boat_size=[size for size, quantity in self.boat_size_amount.items() for _ in range(quantity)]
|
||||
boats_length=[size for size, quantity in self.boat_size_amount.items() for _ in range(quantity)]
|
||||
)
|
||||
|
||||
self.window.set_scene(RoomHost, settings=settings)
|
||||
|
|
|
@ -47,7 +47,8 @@ class GameGrid(BoxWidget):
|
|||
self.rows = rows
|
||||
self.columns = columns
|
||||
|
||||
self.boats_length = [] if boats_length is None else boats_length # the list of the size of the boats to place
|
||||
# the list of the size of the boats to place
|
||||
self.boats_length = [] if boats_length is None else sorted(boats_length, reverse=True)
|
||||
self.preview_color = preview_color
|
||||
|
||||
self.board = Board(rows=self.rows, columns=self.columns)
|
||||
|
|
|
@ -43,7 +43,7 @@ class Client(StoppableThread):
|
|||
|
||||
connection=connection,
|
||||
|
||||
boat_sizes=settings.boat_size,
|
||||
boats_length=settings.boats_length,
|
||||
name_ally=self.username,
|
||||
name_enemy=settings.username,
|
||||
grid_width=settings.grid_width,
|
||||
|
|
|
@ -52,7 +52,7 @@ class Host(StoppableThread):
|
|||
|
||||
connection=connection,
|
||||
|
||||
boat_sizes=self.settings.boat_size,
|
||||
boats_length=self.settings.boats_length,
|
||||
name_ally=self.settings.username,
|
||||
name_enemy=packet_username.username,
|
||||
grid_width=self.settings.grid_width,
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import socket
|
||||
from typing import Any
|
||||
|
||||
from source.core.enums import BombState
|
||||
from source.core.error import InvalidBombPosition, PositionAlreadyShot
|
||||
from source.gui.scene import Game
|
||||
from source.network.packet.abc import Packet
|
||||
from source.network import packet
|
||||
|
@ -23,6 +21,13 @@ def game_network(
|
|||
:param connection: the connection with the other player
|
||||
"""
|
||||
|
||||
game_methods = {
|
||||
packet.PacketChat: game_scene.network_on_chat,
|
||||
packet.PacketBoatPlaced: game_scene.network_on_boat_placed,
|
||||
packet.PacketBombPlaced: game_scene.network_on_bomb_placed,
|
||||
packet.PacketBombState: game_scene.network_on_bomb_state,
|
||||
}
|
||||
|
||||
while True:
|
||||
data: Any = Packet.from_connection(connection)
|
||||
|
||||
|
@ -30,53 +35,7 @@ def game_network(
|
|||
if thread.stopped: return # vérifie si le thread n'est pas censé s'arrêter
|
||||
continue
|
||||
|
||||
match type(data):
|
||||
case packet.PacketChat:
|
||||
print(data.message)
|
||||
|
||||
case packet.PacketBoatPlaced:
|
||||
game_scene.boat_ready_enemy = True
|
||||
if game_scene.boat_ready_ally:
|
||||
in_pyglet_context(game_scene.refresh_turn_text)
|
||||
|
||||
case packet.PacketBombPlaced:
|
||||
try:
|
||||
bomb_state = game_scene.grid_ally.board.bomb(data.position)
|
||||
except (InvalidBombPosition, PositionAlreadyShot):
|
||||
bomb_state = BombState.ERROR
|
||||
|
||||
packet.PacketBombState(position=data.position, bomb_state=bomb_state).send_connection(connection)
|
||||
|
||||
touched = bomb_state in [BombState.TOUCHED, BombState.SUNKEN, BombState.WON]
|
||||
|
||||
if bomb_state is not BombState.ERROR:
|
||||
in_pyglet_context(game_scene.grid_ally.place_bomb, data.position, touched)
|
||||
|
||||
if touched:
|
||||
in_pyglet_context(game_scene.boat_broken_enemy)
|
||||
|
||||
game_scene.my_turn = not (touched or (bomb_state is BombState.ERROR))
|
||||
in_pyglet_context(game_scene.refresh_turn_text)
|
||||
|
||||
if bomb_state is BombState.WON:
|
||||
in_pyglet_context(game_scene.game_end, won=False)
|
||||
return # coupe la connexion
|
||||
|
||||
case packet.PacketBombState:
|
||||
print(data.bomb_state)
|
||||
if data.bomb_state is BombState.ERROR:
|
||||
game_scene.my_turn = True
|
||||
continue
|
||||
|
||||
touched = data.bomb_state in [BombState.TOUCHED, BombState.SUNKEN, BombState.WON]
|
||||
game_scene.my_turn = touched
|
||||
in_pyglet_context(game_scene.refresh_turn_text)
|
||||
|
||||
if touched:
|
||||
in_pyglet_context(game_scene.boat_broken_ally)
|
||||
|
||||
in_pyglet_context(game_scene.grid_enemy.place_bomb, data.position, touched)
|
||||
|
||||
if data.bomb_state is BombState.WON:
|
||||
in_pyglet_context(game_scene.game_end, won=True)
|
||||
return # coupe la connexion
|
||||
if in_pyglet_context(
|
||||
game_methods[type(data)], # récupère la methode relié ce type de donnée
|
||||
connection, data
|
||||
): return # Appelle la méthode. Si elle renvoie True, arrête le thread
|
||||
|
|
|
@ -10,13 +10,13 @@ class PacketSettings(Packet):
|
|||
grid_width: int = field()
|
||||
grid_height: int = field()
|
||||
host_start: bool = field()
|
||||
boat_size: list = field()
|
||||
boats_length: list = field()
|
||||
|
||||
packet_size: int = 51
|
||||
packet_format: str = ">16sBB?32B"
|
||||
|
||||
def to_bytes(self):
|
||||
boat_size = self.boat_size + ([0] * (32 - len(self.boat_size)))
|
||||
boat_size = self.boats_length + ([0] * (32 - len(self.boats_length)))
|
||||
|
||||
return struct.pack(
|
||||
self.packet_format,
|
||||
|
@ -31,12 +31,12 @@ class PacketSettings(Packet):
|
|||
|
||||
@classmethod
|
||||
def from_bytes(cls, data: bytes):
|
||||
username, grid_width, grid_height, host_start, *boat_size = struct.unpack(cls.packet_format, data)
|
||||
username, grid_width, grid_height, host_start, *boats_length = struct.unpack(cls.packet_format, data)
|
||||
|
||||
return cls(
|
||||
username=username.replace(b"\x00", b"").decode("utf-8"),
|
||||
grid_width=grid_width,
|
||||
grid_height=grid_height,
|
||||
host_start=host_start,
|
||||
boat_size=list(filter(lambda value: value != 0, boat_size))
|
||||
boats_length=list(filter(lambda value: value != 0, boats_length))
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue