파이썬으로 배틀십 게임 로직 라이브러리 개발하기: 아키텍처와 흔한 실수
이 라이브러리는 수학적으로 최적화된 알고리즘에 중점을 두고 클래식 배틀십 게임의 로직을 구현합니다. 주요 클래스는 게임 보드를 나타내는 Field와 함선을 관리하는 Ship입니다. 필드는 리스트의 리스트를 사용한 10x10 행렬로 저장되며, 기호로 상태를 표시합니다: 빈 셀은 공백, 손상되지 않은 함선 부분은 '1', 빗나간 공격은 '.', 파괴된 셀은 'X'입니다.
Field 클래스는 보드 생성, 좌표 검증, 함선 배치, 공격 처리 등을 담당합니다. 좌표는 'a1' 형식으로 입력되며, 문자 A-J는 행에, 숫자 1-10은 열에 대응합니다. 규칙은 고정되어 있습니다: 4칸 함선 1개, 3칸 함선 2개, 2칸 함선 3개, 1칸 함선 4개; 함선은 모서리에서도 서로 접촉해서는 안 됩니다.
Field 클래스 구현하기
초기화는 빈 그리드를 생성합니다:
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로 저장됩니다:
- 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를 단순화합니다.
리팩토링 통찰
이 프로젝트는 초보자들이 자주 하는 주요 실수를 드러냈습니다:
- 메서드 오버로딩: 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
아직 댓글이 없습니다.