Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solution #524

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
166 changes: 141 additions & 25 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,150 @@
class Deck:
def __init__(self, row, column, is_alive=True):
pass
def __init__(self, row: int, column: int, is_alive: bool = True) -> None:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding validation for the row and column parameters to ensure they are within acceptable ranges (e.g., 0 to 9 for a 10x10 grid). This will prevent invalid deck positions.

self.row = row
self.column = column
self.is_alive = is_alive


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],
Comment on lines +11 to +12

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be beneficial to validate the start and end coordinates to ensure they form a valid ship (either horizontal or vertical, and within bounds).

is_drowned: bool = False
) -> None:
self.start = start
self.end = end
self.is_drowned = is_drowned
self.decks = self.create_decks()

def get_deck(self, row, column):
# Find the corresponding deck in the list
pass
def create_decks(self) -> list[Deck]:
start_row, start_column = self.start
end_row, end_column = self.end
if start_row == end_row:
return [
Deck(start_row, current_column)
for current_column in range(start_column, end_column + 1)
]
return [
Deck(current_row, start_column)
for current_row in range(start_row, end_row + 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 get_deck(self, row: int, column: int) -> Deck | None:
for deck in self.decks:
if deck.row == row and deck.column == column:
return deck

def check_if_drowned(self) -> None:
for deck in self.decks:
if deck.is_alive:
return
self.is_drowned = True

def fire(self, row: int, column: int) -> None:
deck = self.get_deck(row, column)
if deck:
deck.is_alive = False
self.check_if_drowned()


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]]) -> None:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constructor for Battleship assumes a specific format for the ships parameter. Consider adding validation to ensure the input matches the expected format.

self.field = {}

for ship in ships:
start, end = ship
start_row, start_column = start
end_row, end_column = end
ship_instance = Ship(start, end)
if start_row == end_row:
for current_column in range(start_column, end_column + 1):
self.field[(start_row, current_column)] = ship_instance
else:
for current_row in range(start_row, end_row + 1):
self.field[(current_row, start_column)] = ship_instance

if not self._validate_field():
raise ValueError("Invalid field configuration")

def fire(self, location: tuple[int, int]) -> str:
if location not in self.field:
return "Miss!"

ship = self.field[location]
ship.fire(*location)
return "Sunk!" if ship.is_drowned else "Hit!"

def print_field(self) -> None:
for row in range(10):
for column in range(10):
ship = self.field.get((row, column))
if not ship:
print("~", end="")
continue

deck = ship.get_deck(row, column)
if deck.is_alive:
print(u"\u25A1", end="")
elif ship.is_drowned:
print("x", end="")
else:
print("*", end="")

print()

def _validate_field(self) -> bool:
ships = list(set(self.field.values()))
if len(ships) != 10:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _validate_field method assumes a fixed number of ships and decks. If you plan to support different configurations, consider making these values configurable.

print(f"The total number of the ships should be 10, "
f"but got {len(ships)} instead")
return False

single_deck, double_deck, three_deck, four_deck = [0, 0, 0, 0]
for ship in ships:
decks = len(ship.decks)
if decks == 1:
single_deck += 1
elif decks == 2:
double_deck += 1
elif decks == 3:
three_deck += 1
elif decks == 4:
four_deck += 1
wrong = 0
if single_deck != 4:
print(f"Field should have 4 single-deck ships, "
f"but got {single_deck} instead")
wrong += 1
if double_deck != 3:
print(f"Field should have 3 double-deck ships, "
f"but got {double_deck} instead")
wrong += 1
if three_deck != 2:
print(f"Field should have 2 three-deck ships, "
f"but got {three_deck} instead")
wrong += 1
if four_deck != 1:
print(f"Field should have 1 four-deck ship, "
f"but got {four_deck} instead")
wrong += 1
if wrong > 0:
return False

for deck_location, ship in self.field.items():
current_row, current_column = deck_location
for row in range(current_row - 1, current_row + 2):
for column in range(current_column - 1, current_column + 2):
neighbor_location = (row, column)
if (
0 <= row <= 9
and 0 <= column <= 9
and neighbor_location != deck_location
):
neighbor = self.field.get(neighbor_location)
if neighbor and neighbor is not ship:
print("Ships shouldn't be located "
"in the neighboring cells "
"(even if cells are neighbors by diagonal)")
return False
return True
Loading