Tworzenie biblioteki logiki gry w Statki w Pythonie: architektura i typowe błędy
Biblioteka implementuje logikę klasycznej gry w Statki z naciskiem na matematycznie optymalne algorytmy. Główne klasy to Field do reprezentowania planszy i Ship do zarządzania statkami. Plansza przechowywana jest jako macierz 10x10 z list list, gdzie symbole oznaczają stany: spacja — puste pole, '1' — żywa część statku, '.' — pudło, 'X' — zniszczone pole.
Klasa Field odpowiada za tworzenie planszy, walidację współrzędnych, rozmieszczanie statków i obsługę strzałów. Współrzędne wprowadza się w formacie 'a1', gdzie litery A-J odpowiadają wierszom, cyfry 1-10 — kolumnom. Zasady są stałe: 1 statek 4-polowy, 2 trzyplanszowe, 3 dwupolowe, 4 jednopolowe; statki nie stykają się nawet rogami.
Implementacja klasy Field
Inicjalizacja tworzy pustą siatkę:
class Field:
def __init__(self):
height = 10
weight = 10
self.grid = [[' ' for i in range(weight)] for i in range(height)]
Metoda display() wyświetla planszę w konsoli ze współrzędnymi. Pierwsza wersja zawierała błąd — metoda line.insert(0, letter) mutowała oryginalny grid, dodając litery przy wielokrotnych wywołaniach. Poprawka: drukowanie litery osobno bez zmiany struktury.
def display(self):
print(' 1 2 3 4 5 6 7 8 9 10')
letters = 'ABCDEFGHIJ'
count_letters = 0
for line in self.grid:
print(letters[count_letters], *line)
count_letters += 1
Walidacja współrzędnych wydzielona do prywatnej metody _validation_coordinate(). Sprawdza długość ciągu (2-3 znaki), obecność litery w A-J i cyfry w 1-10. Metoda find_coordinate() określa stan pola: clear, hitted, destroyed, not_damaged, was_beaten.
Słowniki do konwersji współrzędnych przechowywane jako atrybuty self.rows i self.columns:
- rows: {'a': 0, 'b': 1, ..., 'j': 9}
- columns: {'1': 0, '2': 1, ..., '10': 9}
Klasa Ship i rozmieszczanie statków
Klasa Ship przechowuje parametry w słowniku:
class Ship:
def __init__(self):
self.parameters = {
'alive coordinates': [],
'hitted coordinates': [],
'alive': True
}
self.field = None
def set_field(self, field):
self.field = field
Metoda add_ship(ship, coordinate_line, length) w Field rozmieszcza statek według ciągu postaci 'a1-a2-a3'. Najpierw walidacja linii _ship_line_validation(): rozbicie na współrzędne, sprawdzenie liniowości (poziomo/pionowo), zgodność długości. Następnie dla każdej współrzędnej wywołanie ship.set_coordinate_in_ship(coordinate), ustawienie '1' w grid.
def add_ship(self, ship, coordinate_line, length):
ship.set_field(self)
if not self._ship_line_validation(coordinate_line):
return False
coordinates = coordinate_line.split('-')
if length != len(coordinates):
return False
for coordinate in coordinates:
result = ship.set_coordinate_in_ship(coordinate)
if result:
rows = self.rows[coordinate[0]]
columns = self.columns[coordinate[1:]]
self.grid[rows][columns] = '1'
return True
Połączenie Field-Ship jest dwukierunkowe: Field wywołuje ship.set_field(self), Ship używa self.field do walidacji. To narusza zasadę enkapsulacji podstawowych warstw, ale upraszcza API.
Wnioski z refaktoryzacji
Projekt ujawnił kluczowe problemy początkujących:
- Przeciążanie metod: find_coordinate() łączył walidację, wyszukiwanie i wyświetlanie — podzielić na _validation_coordinate() i get_cell_state().
- Mutacja danych: Unikać insert() w display(), pracować z kopiami.
- Zakodowane słowniki: Wydzielić do stałych klasowych lub użyć ord() do konwersji.
- Wartości zwracane: Ujednolicić: True/False dla sukcesu, ciągi dla błędów.
Dla optymalnej gry zintegrować algorytmy wyszukiwania probabilistycznego: przy trafieniu skanować sąsiednie pola, przy zniszczeniu — wykluczać pola z prawdopodobieństw.
Co jest ważne
- Field jako macierz list z symbolami dla stanów; walidacja współrzędnych przez słowniki self.rows/self.columns.
- Ship przechowuje alive/hitted coordinates; dwukierunkowe połączenie z Field przez set_field().
-Rozmieszczanie według coordinate_line ('a1-a2'); sprawdzanie liniowości i stref buforowych.
- Unikać mutacji grid w display(); wydzielać wspólne sprawdzenia do prywatnych metod.
- Dla zaawansowanych algorytmów: przechowywać mapę prawdopodobieństwa strzałów oddzielnie od grid.
— Editorial Team
Brak komentarzy.