Powrót do strony głównej

Biblioteka Bitwy morskiej na Pythonie: klasy Field i Ship

Artykuł analizuje tworzenie biblioteki logiki Bitwy morskiej na Pythonie. Opisano klasy Field i Ship, metody walidacji współrzędnych, rozmieszczania statków i typowe błędy. Przedstawiono przykłady kodu i rekomendacje dotyczące refaktoringu dla optymalnej architektury.

Tworzenie biblioteki Bitwy morskiej: Field i Ship na Pythonie
Advertisement 728x90

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ę:

Google AdInline article slot
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:

Google AdInline article slot
  • 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.

Google AdInline article slot

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

Advertisement 728x90

Czytaj dalej