На этом шаге мы начнем реализацию необходимых классов.
Игра Connect Four во многом похожа на крестики-нолики. Обе они ведутся на поле в виде сетки, и для выигрыша требуется, чтобы игрок расположил фишки в ряд. Но в Connect Four сетка больше, что предполагает гораздо больше способов выиграть, поэтому оценить каждую позицию значительно сложнее.
Представленный далее код (файл connectfour.py) будет выглядеть в чем-то очень знакомым, но структуры данных и метод оценки сильно отличаются от использованных для игры в крестики-нолики. Обе игры реализованы как подклассы тех же базовых классов Piece и Board, с которыми мы познакомились в предыдущих шагах, что делает функцию minimax() пригодной для обеих игр.
from __future__ import annotations from typing import List, Optional, Tuple from enum import Enum from board import Piece, Board, Move class C4Piece(Piece, Enum): B = "B" R = "R" E = " " # пустое поле @property def opposite(self) -> C4Piece: if self == C4Piece.B: return C4Piece.R elif self == C4Piece.R: return C4Piece.B else: return C4Piece.E def __str__(self) -> str: return self.value
Класс C4Piece практически идентичен классу TTTPiece.
Теперь определим функцию для генерации всех потенциальных выигрышных сегментов в сетке Connect Four определенного размера (файл connectfour.py).
def generate_segments(num_columns: int, num_rows: int, segment_length: int) -> List[List[Tuple[int, int]]]: segments: List[List[Tuple[int, int]]] = [] # генерируем вертикальные сегменты for c in range(num_columns): for r in range(num_rows - segment_length + 1): segment: List[Tuple[ int , int ]] = [] for t in range(segment_length): segment.append((c, r + t)) segments.append(segment) # генерируем горизонтальные сегменты for c in range(num_columns - segment_length + 1): for r in range(num_rows): segment = [] for t in range(segment_length): segment.append((c + t, r)) segments.append(segment) # генерируем сегменты диагонали из нижнего левого в верхний правый угол for c in range(num_columns - segment_length + 1): for r in range(num_rows - segment_length + 1): segment = [] for t in range(segment_length): segment.append((c + t, r + t)) segments.append(segment) # генерируем сегменты диагонали из верхнего левого в нижний правый угол for c in range(num_columns - segment_length + 1): for r in range(segment_length - 1, num_rows): segment = [] for t in range(segment_length): segment.append((c + t, r - t)) segments.append(segment) return segments
Эта функция возвращает список списков ячеек сетки (кортежей, состоящих из комбинаций "столбец/строка"). Каждый список в списке содержит четыре ячейки сетки. Мы будем называть списки, состоящие из четырех ячеек сетки, сегментами. Если какой-либо сегмент на доске окажется окрашен в один цвет, это будет означать, что данный цвет выиграл.
На следующем шаге мы закончим изучение этого вопроса.