홈으로 돌아가기

Python의 Battleship 라이브러리: Field 및 Ship 클래스

이 기사는 Python의 Battleship 게임 로직 라이브러리 생성을 분해합니다. Field 및 Ship 클래스, 좌표 검증 방법, 함선 배치 및 일반적인 오류를 설명합니다. 최적의 아키텍처를 위한 코드 예제 및 리팩토링 권장 사항을 제공합니다.

Battleship 라이브러리 만들기: Python의 Field 및 Ship
Advertisement 728x90

파이썬으로 배틀십 게임 로직 라이브러리 개발하기: 아키텍처와 흔한 실수

이 라이브러리는 수학적으로 최적화된 알고리즘에 중점을 두고 클래식 배틀십 게임의 로직을 구현합니다. 주요 클래스는 게임 보드를 나타내는 Field와 함선을 관리하는 Ship입니다. 필드는 리스트의 리스트를 사용한 10x10 행렬로 저장되며, 기호로 상태를 표시합니다: 빈 셀은 공백, 손상되지 않은 함선 부분은 '1', 빗나간 공격은 '.', 파괴된 셀은 'X'입니다.

Field 클래스는 보드 생성, 좌표 검증, 함선 배치, 공격 처리 등을 담당합니다. 좌표는 'a1' 형식으로 입력되며, 문자 A-J는 행에, 숫자 1-10은 열에 대응합니다. 규칙은 고정되어 있습니다: 4칸 함선 1개, 3칸 함선 2개, 2칸 함선 3개, 1칸 함선 4개; 함선은 모서리에서도 서로 접촉해서는 안 됩니다.

Field 클래스 구현하기

초기화는 빈 그리드를 생성합니다:

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

display() 메서드는 좌표와 함께 필드를 콘솔에 출력합니다. 초기 버전에는 오류가 있었습니다—line.insert(0, letter) 메서드는 반복 호출 시 원본 그리드를 변경하여 문자를 추가했습니다. 수정: 구조를 변경하지 않고 문자를 별도로 출력합니다.

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

좌표 검증은 비공개 메서드 _validation_coordinate()로 분리됩니다. 문자열 길이(2-3자), A-J 내 문자 존재, 1-10 내 숫자 존재를 확인합니다. find_coordinate() 메서드는 셀 상태를 결정합니다: clear, hitted, destroyed, not_damaged, was_beaten.

좌표 변환을 위한 딕셔너리는 속성 self.rows와 self.columns로 저장됩니다:

Google AdInline article slot
  • rows: {'a': 0, 'b': 1, ..., 'j': 9}
  • columns: {'1': 0, '2': 1, ..., '10': 9}

Ship 클래스와 함선 배치

Ship 클래스는 매개변수를 딕셔너리에 저장합니다:

class Ship:
    def __init__(self):
        self.parameters = {
            'alive coordinates': [],
            'hitted coordinates': [],
            'alive': True
        }
        self.field = None
    def set_field(self, field):
        self.field = field

Field의 add_ship(ship, coordinate_line, length) 메서드는 'a1-a2-a3'과 같은 문자열을 기반으로 함선을 배치합니다. 먼저, _ship_line_validation()으로 라인 검증: 좌표로 파싱, 선형성(수평/수직) 확인, 길이 일치 확인. 그런 다음 각 좌표에 대해 ship.set_coordinate_in_ship(coordinate)를 호출하여 그리드에 '1'을 설정합니다.

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

Field-Ship 관계는 양방향입니다: Field는 ship.set_field(self)를 호출하고, Ship은 검증을 위해 self.field를 사용합니다. 이는 기본 계층의 캡슐화 원칙을 위반하지만 API를 단순화합니다.

Google AdInline article slot

리팩토링 통찰

이 프로젝트는 초보자들이 자주 하는 주요 실수를 드러냈습니다:

  • 메서드 오버로딩: find_coordinate()는 검증, 검색, 출력을 결합했습니다—_validation_coordinate()get_cell_state()로 분리했습니다.
  • 데이터 변이: display()에서 insert()를 피하고 복사본으로 작업합니다.
  • 하드코딩된 딕셔너리: 클래스 상수로 추출하거나 변환에 ord()를 사용합니다.
  • 반환 값: 표준화: 성공은 True/False, 오류는 문자열.

최적의 게임플레이를 위해 확률적 검색 알고리즘을 통합하세요: 명중 시 인접 셀을 스캔하고; 파괴 시 데크를 확률에서 제외합니다.

핵심 요약

  • 상태를 나타내는 기호가 있는 리스트 행렬로서의 Field; 딕셔너리 self.rows/self.columns를 통한 좌표 검증.
  • Ship은 alive/hitted 좌표를 저장; set_field()를 통한 Field와의 양방향 연결.
  • coordinate_line('a1-a2')를 통한 배치; 선형성과 완충 구역 확인.
  • display()에서 그리드 변이 피하기; 공통 검사를 비공개 메서드로 추출.
  • 고급 알고리즘을 위해: 그리드와 별도로 공격 확률 맵을 저장.

— Editorial Team

Advertisement 728x90

다음 읽기