From 41d65e3e8c66a9b210fa1fabcdc19e618d00f56b Mon Sep 17 00:00:00 2001 From: Alya Date: Tue, 19 Nov 2024 14:03:33 +0200 Subject: [PATCH 1/2] Battle --- app/main.py | 144 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 119 insertions(+), 25 deletions(-) diff --git a/app/main.py b/app/main.py index 626f41cf..116580e7 100644 --- a/app/main.py +++ b/app/main.py @@ -1,34 +1,128 @@ +from typing import List, Tuple + + class Deck: - def __init__(self, row, column, is_alive=True): - pass + def __init__(self, row: int, + column: int, + is_alive: bool = True) -> None: + self.row = row + self.column = column + self.is_alive = is_alive + + def hit(self) -> None: + self.is_alive = False class Ship: - def __init__(self, start, end, is_drowned=False): - # Create decks and save them to a list `self.decks` - pass + def __init__(self, start: Tuple[int, int], + end: Tuple[int, int]) -> None: + self.start = start + self.end = end + self.decks: List[Deck] = [] + self.is_drowned = False + self._create_decks() - def get_deck(self, row, column): - # Find the corresponding deck in the list - pass + def _create_decks(self) -> None: + if self.start[0] == self.end[0]: # Horizontal ship + for col in range(self.start[1], self.end[1] + 1): + self.decks.append(Deck(self.start[0], col)) + elif self.start[1] == self.end[1]: # Vertical ship + for row in range(self.start[0], self.end[0] + 1): + self.decks.append(Deck(row, self.start[1])) - def fire(self, row, column): - # Change the `is_alive` status of the deck - # And update the `is_drowned` value if it's needed - pass + def fire(self, row: int, col: int) -> str: + # Check if this cell matches a deck + for deck in self.decks: + if deck.row == row and deck.column == col: + deck.hit() + if all(not d.is_alive for d in self.decks): + self.is_drowned = True + return "Sunk!" if self.is_drowned else "Hit!" + return "Miss!" class Battleship: - def __init__(self, ships): - # Create a dict `self.field`. - # Its keys are tuples - the coordinates of the non-empty cells, - # A value for each cell is a reference to the ship - # which is located in it - pass - - def fire(self, location: tuple): - # This function should check whether the location - # is a key in the `self.field` - # If it is, then it should check if this cell is the last alive - # in the ship or not. - pass + def __init__(self, + ships: List[Tuple[Tuple[int, int], Tuple[int, int]]]) -> None: + self.field: dict[Tuple[int, int], Ship] = {} + self.ships: List[Ship] = [] + self._validate_field(ships) + self._place_ships(ships) + + def _place_ships( + self, + ships: List[Tuple[Tuple[int, int], Tuple[int, int]]] + ) -> None: + # Place the ships on the field and store them + for ship_coords in ships: + start, end = ship_coords + ship = Ship(start, end) + self.ships.append(ship) + for deck in ship.decks: + self.field[(deck.row, deck.column)] = ship + + def _validate_field( + self, + ships: List[Tuple[Tuple[int, int], Tuple[int, int]]] + ) -> None: + ship_sizes = {1: 4, 2: 3, 3: 2, 4: 1} + ship_counts = {1: 0, 2: 0, 3: 0, 4: 0} + + for ship_coords in ships: + start, end = ship_coords + if start[0] == end[0]: + size = end[1] - start[1] + 1 + elif start[1] == end[1]: + size = end[0] - start[0] + 1 + else: + raise ValueError("Ships must be either " + "horizontal or vertical.") + + if size not in ship_counts: + raise ValueError("Invalid ship size.") + ship_counts[size] += 1 + + # Check if the ship sizes match the expected counts + for size, count in ship_counts.items(): + if count != ship_sizes[size]: + raise ValueError(f"Invalid number of ships with {size} decks.") + + # Check that ships are not in neighboring cells + for ship_coords in ships: + for (row, col) in self._get_adjacent_cells(ship_coords): + if (row, col) in self.field: + raise ValueError("Ships cannot be in neighboring cells.") + + def _get_adjacent_cells( + self, + ship_coords: Tuple[Tuple[int, int], Tuple[int, int]] + ) -> set: + start, end = ship_coords + adjacent_cells = set() + + # Determine all adjacent cells around the ship + for row in range(start[0] - 1, end[0] + 2): + for col in range(start[1] - 1, end[1] + 2): + if ((row, col) != (start[0], start[1]) and (row, col) + != (end[0], end[1])): + adjacent_cells.add((row, col)) + return adjacent_cells + + def fire(self, location: Tuple[int, int]) -> str: + if location in self.field: + ship = self.field[location] + return ship.fire(location[0], location[1]) + return "Miss!" + + def print_field(self) -> None: + for row in range(10): + for col in range(10): + if (row, col) in self.field: + ship = self.field[(row, col)] + if ship.is_drowned: + print("x", end=" ") + else: + print("*", end=" ") + else: + print("~", end=" ") + print() From cd57275b8ef7cd29cd0a4ad7a4c78a8483fb8117 Mon Sep 17 00:00:00 2001 From: Alya Date: Tue, 19 Nov 2024 14:11:52 +0200 Subject: [PATCH 2/2] Battle --- app/main.py | 55 +++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/app/main.py b/app/main.py index 116580e7..d00fdefa 100644 --- a/app/main.py +++ b/app/main.py @@ -2,9 +2,7 @@ class Deck: - def __init__(self, row: int, - column: int, - is_alive: bool = True) -> None: + def __init__(self, row: int, column: int, is_alive: bool = True) -> None: self.row = row self.column = column self.is_alive = is_alive @@ -14,8 +12,9 @@ def hit(self) -> None: class Ship: - def __init__(self, start: Tuple[int, int], - end: Tuple[int, int]) -> None: + def __init__( + self, + start: Tuple[int, int], end: Tuple[int, int]) -> None: self.start = start self.end = end self.decks: List[Deck] = [] @@ -42,8 +41,9 @@ def fire(self, row: int, col: int) -> str: class Battleship: - def __init__(self, - ships: List[Tuple[Tuple[int, int], Tuple[int, int]]]) -> None: + def __init__( + self, + ships: List[Tuple[Tuple[int, int], Tuple[int, int]]]) -> None: self.field: dict[Tuple[int, int], Ship] = {} self.ships: List[Ship] = [] self._validate_field(ships) @@ -51,11 +51,13 @@ def __init__(self, def _place_ships( self, - ships: List[Tuple[Tuple[int, int], Tuple[int, int]]] - ) -> None: + ships: List[Tuple[Tuple[int, int], Tuple[int, int]]]) -> None: # Place the ships on the field and store them for ship_coords in ships: start, end = ship_coords + # First, check if the ship is adjacent to any other ship + if self._check_adjacent_cells(start, end): + raise ValueError("Ships cannot be in neighboring cells.") ship = Ship(start, end) self.ships.append(ship) for deck in ship.decks: @@ -63,8 +65,7 @@ def _place_ships( def _validate_field( self, - ships: List[Tuple[Tuple[int, int], Tuple[int, int]]] - ) -> None: + ships: List[Tuple[Tuple[int, int], Tuple[int, int]]]) -> None: ship_sizes = {1: 4, 2: 3, 3: 2, 4: 1} ship_counts = {1: 0, 2: 0, 3: 0, 4: 0} @@ -87,27 +88,31 @@ def _validate_field( if count != ship_sizes[size]: raise ValueError(f"Invalid number of ships with {size} decks.") - # Check that ships are not in neighboring cells - for ship_coords in ships: - for (row, col) in self._get_adjacent_cells(ship_coords): - if (row, col) in self.field: - raise ValueError("Ships cannot be in neighboring cells.") - def _get_adjacent_cells( self, - ship_coords: Tuple[Tuple[int, int], Tuple[int, int]] - ) -> set: - start, end = ship_coords + start: Tuple[int, int], end: Tuple[int, int]) -> set: adjacent_cells = set() - # Determine all adjacent cells around the ship - for row in range(start[0] - 1, end[0] + 2): - for col in range(start[1] - 1, end[1] + 2): - if ((row, col) != (start[0], start[1]) and (row, col) - != (end[0], end[1])): + if start[0] == end[0]: + for row in range(start[0] - 1, start[0] + 2): + for col in range(start[1] - 1, end[1] + 2): adjacent_cells.add((row, col)) + elif start[1] == end[1]: # Vertical ship + for row in range(start[0] - 1, end[0] + 2): + for col in range(start[1] - 1, start[1] + 2): + adjacent_cells.add((row, col)) + return adjacent_cells + def _check_adjacent_cells( + self, + start: Tuple[int, int], end: Tuple[int, int]) -> bool: + adjacent_cells = self._get_adjacent_cells(start, end) + for cell in adjacent_cells: + if cell in self.field: + return True + return False + def fire(self, location: Tuple[int, int]) -> str: if location in self.field: ship = self.field[location]