From 31bb0c1d113c25b07673fa5604f38ee2214f1e78 Mon Sep 17 00:00:00 2001 From: Faraphel Date: Tue, 10 Jan 2023 18:16:58 +0100 Subject: [PATCH] added a prototypal test server --- source/core/Board.py | 12 ++- source/core/enums/bomb.py | 2 + source/core/error/InvalidBombPosition.py | 3 + source/core/error/__init__.py | 1 + source/reseau_test/client.py | 107 ++++++++++++++++++++--- source/reseau_test/server.py | 102 +++++++++++++++++++-- 6 files changed, 206 insertions(+), 21 deletions(-) create mode 100644 source/core/error/InvalidBombPosition.py diff --git a/source/core/Board.py b/source/core/Board.py index f59b4c9..03ad3f3 100644 --- a/source/core/Board.py +++ b/source/core/Board.py @@ -2,8 +2,8 @@ import numpy as np from source.core.Boat import Boat from source.core.enums import Orientation, BombState -from source.core.error import InvalidBoatPosition, PositionAlreadyShot -from source.utils import copy_array_offset +from source.core.error import InvalidBoatPosition, PositionAlreadyShot, InvalidBombPosition +from source.utils import copy_array_offset, in_bbox class Board: @@ -49,7 +49,8 @@ class Board: board_mat_sum_old: int = board_mat.sum() # add the boat to the board matrice - copy_array_offset(boat_mat, board_mat, offset=position) + try: copy_array_offset(boat_mat, board_mat, offset=position) + except ValueError: raise InvalidBoatPosition(boat, position) # get the new board matrice sum board_mat_sum_new: int = board_mat.sum() @@ -73,6 +74,11 @@ class Board: :position: the position where to shoot :raise: PositionAlreadyShot if the position have already been shot before """ + + # if the bomb is inside the board + x, y = position + if x >= self._width or y >= self._height: raise InvalidBombPosition(position) + # if this position have already been shot if not self._bombs[position]: raise PositionAlreadyShot(position) diff --git a/source/core/enums/bomb.py b/source/core/enums/bomb.py index faccddd..eaba00a 100644 --- a/source/core/enums/bomb.py +++ b/source/core/enums/bomb.py @@ -6,3 +6,5 @@ class BombState(Enum): TOUCHED = 1 SUNKEN = 2 WON = 3 + + ERROR = 10 diff --git a/source/core/error/InvalidBombPosition.py b/source/core/error/InvalidBombPosition.py new file mode 100644 index 0000000..e1454ef --- /dev/null +++ b/source/core/error/InvalidBombPosition.py @@ -0,0 +1,3 @@ +class InvalidBombPosition(Exception): + def __init__(self, position: tuple[int, int]): + super().__init__(f"The bomb can't be placed at {position}.") diff --git a/source/core/error/__init__.py b/source/core/error/__init__.py index 03b0c70..898a244 100644 --- a/source/core/error/__init__.py +++ b/source/core/error/__init__.py @@ -1,2 +1,3 @@ from .InvalidBoatPosition import InvalidBoatPosition from .PositionAlreadyShot import PositionAlreadyShot +from .InvalidBombPosition import InvalidBombPosition diff --git a/source/reseau_test/client.py b/source/reseau_test/client.py index bfe6ee4..7f039e9 100644 --- a/source/reseau_test/client.py +++ b/source/reseau_test/client.py @@ -1,24 +1,105 @@ import json import socket +import sys from source.core.Board import Board from source.core.Boat import Boat -from source.core.enums import Orientation - - -board = Board(5) -board.add_boat(Boat(3, Orientation.VERTICAL), (0, 4)) -board.add_boat(Boat(4, Orientation.HORIZONTAL), (4, 1)) -board.bomb((2, 2)) - -board_json = json.dumps(board.to_json()) - +from source.core.enums import Orientation, BombState +from source.core.error import InvalidBoatPosition, InvalidBombPosition, PositionAlreadyShot with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect(("127.0.0.1", 7878)) - s.send(board_json.encode()) + print(f"[Client] Connecté avec {s}") - data = s.recv(1024) + width: int = int.from_bytes(s.recv(32), "big") + height: int = int.from_bytes(s.recv(32), "big") - print(data) + print(width, height) + + board = Board(width, height) + + boat_count: int = int.from_bytes(s.recv(32), "big") + + for _ in range(boat_count): + while True: + try: + print(board) + x = int(input("valeur X du bateau ? (int) : ")) + y = int(input("valeur Y du bateau ? (int) : ")) + o = input("orientation du bateau ? (H|V) : ") + board.add_boat(Boat(3, Orientation(o)), (x, y)) + + except InvalidBoatPosition: + print("Position du bateau invalide.", file=sys.stderr) + + else: + break + + message = s.recv(32) + s.send(b"ready") + + print("Phase de bombardement") + + while True: + + # tour de l'adversaire + + while True: + print("En attente du joueur adverse...") + + x = int.from_bytes(s.recv(32), "big") + y = int.from_bytes(s.recv(32), "big") + + try: + bomb_state = board.bomb((x, y)) + s.send(bomb_state.value.to_bytes(32, "big")) + + match bomb_state: + case bomb_state.NOTHING: + print("Raté !") + break + + case BombState.TOUCHED: + print("Touché !") + + case BombState.SUNKEN: + print("Coulé !") + + case BombState.WON: + print("Perdu !") + break + + except (InvalidBombPosition, PositionAlreadyShot) as e: + s.send(BombState.ERROR.value.to_bytes(32, "big")) + s.send(f"Error : {str(e)}".encode()) + + # mon tour + + while True: + x = int(input("valeur X de la bombe ? (int) : ")) + y = int(input("valeur Y de la bombe ? (int) : ")) + + s.send(x.to_bytes(32, "big")) + s.send(y.to_bytes(32, "big")) + + bomb_state = BombState(int.from_bytes(s.recv(32), "big")) + + match bomb_state: + case BombState.ERROR: + error = s.recv(1024) + print(error, file=sys.stderr) + + case BombState.NOTHING: + print("Raté !") + break + + case BombState.TOUCHED: + print("Touché !") + + case BombState.SUNKEN: + print("Coulé !") + + case BombState.WON: + print("Gagné !") + break diff --git a/source/reseau_test/server.py b/source/reseau_test/server.py index 138747c..d3f266f 100644 --- a/source/reseau_test/server.py +++ b/source/reseau_test/server.py @@ -1,18 +1,110 @@ import json import socket +import sys from source.core.Board import Board +from source.core.Boat import Boat +from source.core.enums import Orientation, BombState +from source.core.error import InvalidBoatPosition, InvalidBombPosition, PositionAlreadyShot with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(("127.0.0.1", 7878)) s.listen() conn, addr = s.accept() - message = conn.recv(1024) - conn.send(b"SALUT") + print(f"[Serveur] Connecté avec {addr}") - print(conn, addr, message) + width: int = int(input("Largeur du plateau ? (int) : ")) + height: int = int(input("Longueur du plateau ? (int) : ")) - board_json = json.loads(message) - print(Board.from_json(board_json)) + conn.send(width.to_bytes(32, "big")) + conn.send(height.to_bytes(32, "big")) + + board = Board(width, height) + + boat_count: int = int(input("Nombre de bateau ? (int) : ")) + + conn.send(boat_count.to_bytes(32, "big")) + + for _ in range(boat_count): + while True: + try: + print(board) + x = int(input("valeur X du bateau ? (int) : ")) + y = int(input("valeur Y du bateau ? (int) : ")) + o = input("orientation du bateau ? (H|V) : ") + board.add_boat(Boat(3, Orientation(o)), (x, y)) + + except InvalidBoatPosition: + print("Position du bateau invalide.", file=sys.stderr) + + else: + break + + conn.send(b"ready") + message = conn.recv(32) + + print("Phase de bombardement") + + while True: + # posé les bombes + + while True: + x = int(input("valeur X de la bombe ? (int) : ")) + y = int(input("valeur Y de la bombe ? (int) : ")) + + conn.send(x.to_bytes(32, "big")) + conn.send(y.to_bytes(32, "big")) + + bomb_state = BombState(int.from_bytes(conn.recv(32), "big")) + + match bomb_state: + case BombState.ERROR: + error = conn.recv(1024) + print(error, file=sys.stderr) + + case BombState.NOTHING: + print("Raté !") + break + + case BombState.TOUCHED: + print("Touché !") + + case BombState.SUNKEN: + print("Coulé !") + + case BombState.WON: + print("Gagné !") + break + + # tour de l'adversaire + + while True: + print("En attente du joueur adverse...") + + x = int.from_bytes(conn.recv(32), "big") + y = int.from_bytes(conn.recv(32), "big") + + try: + bomb_state = board.bomb((x, y)) + conn.send(bomb_state.value.to_bytes(32, "big")) + + match bomb_state: + case bomb_state.NOTHING: + print("Raté !") + break + + case BombState.TOUCHED: + print("Touché !") + + case BombState.SUNKEN: + print("Coulé !") + + case BombState.WON: + print("Perdu !") + break + + except (InvalidBombPosition, PositionAlreadyShot) as e: + s.send(BombState.ERROR.value.to_bytes(32, "big")) + s.send(f"Error : {str(e)}".encode())