棋盘的types设计,设计了棋手和点位;棋手是为了区分先手后手,敌方我方;比如后手固定是黑棋或者是位于棋盘下方的棋手,我这里约定为统一先手为“执黑方“;敌方拿到棋盘的时候,如果设计的是从对方手上获得, 那么需要根据player来确定是否要翻转棋局。

import enum
from collections import namedtuple

__all__ = [
    'Player',
    'Point',
]


class Player(enum.Enum):
    black = 0
    white = 1

    @property
    def other(self):
        return Player.black if self == Player.white else Player.white

    def __str__(self):
        return 'black' if self == Player.black else 'white'


# Point class is used to represent a location on the board.
class Point(namedtuple('Point', 'row col')):
    pass

棋盘的board、move、gamestate设计:

import numpy as np
import copy
from amazontypes import Player, Point


# class IllegalMoveError(Exception):
#     pass


class IllegalMoveError(Exception):
    def __init__(self, message="Illegal move attempted", *args):
        super(IllegalMoveError, self).__init__(message, *args)  # Correct usage of super in Python 2
        self.message = message  # Store the message in an instance variable

    def __str__(self):
        # This method returns the string representation of the error, which will be used when the error is printed
        return self.message


class Board:
    def __init__(self, size=10):
        self.size = size
        self.board = np.zeros((3, size, size), dtype=int)
        self.init_amazons_positions()
        self.stage = 0
        self.selected_amazon = None

    def init_amazons_positions(self):
        positions = [Point(1, 4), Point(1, 7), Point(4, 1), Point(4, 10),
                     Point(7, 1), Point(7, 10), Point(10, 4), Point(10, 7)]
        for i, pos in enumerate(positions):
            self.board[0 if i < 4 else 1, pos.row - 1, pos.col - 1] = 1

    def select_amazon(self, point):
        if self.stage != 0:
            raise IllegalMoveError("Not in the selection stage")
        if self.board[0, point.row - 1, point.col - 1] != 1:
            raise IllegalMoveError("No amazon at selected position")
        self.selected_amazon = point
        self.stage = 1

    def move_amazon(self, point):
        if self.stage != 1:
            raise IllegalMoveError("Not in the move stage")
        if not self.is_queen_move(self.selected_amazon, point):
            raise IllegalMoveError("Invalid move for amazon")
        self.board[0, self.selected_amazon.row - 1, self.selected_amazon.col - 1] = 0
        self.board[0, point.row - 1, point.col - 1] = 1
        self.selected_amazon = point
        self.stage = 2

    def place_obstacle(self, point):
        if self.stage != 2:
            raise IllegalMoveError("Not in the obstacle placement stage")
        if self.board[:, point.row - 1, point.col - 1].any():
            raise IllegalMoveError("Obstacle cannot be placed here")
        self.board[2, point.row - 1, point.col - 1] = 1
        self.stage = 0

    def is_queen_move(self, start, end):
        if (start.row == end.row and start.col == end.col) or self.board[:, end.row - 1, end.col - 1].any():
            return False
        dy, dx = end.row - start.row, end.col - start.col
        if abs(dy) != abs(dx) and dy != 0 and dx != 0:
            return False
        step_y = (dy and (1 if dy > 0 else -1))
        step_x = (dx and (1 if dx > 0 else -1))
        y, x = start.row + step_y - 1, start.col + step_x - 1
        while (y + 1, x + 1) != (end.row, end.col):
            if self.board[:, y, x].any():
                return False
            y += step_y
            x += step_x
        return True

    def has_stone(self, row, col):
        # Adjust from 1-based to 0-based indexing internally
        return self.board[:, row - 1, col - 1].any()

    def __deepcopy__(self, memory_dict=None):
        if memory_dict is None:
            memory_dict = {}
        # Check if the object is already in the memory dictionary
        if id(self) in memory_dict:
            return memory_dict[id(self)]

        # Create a new copy and add it to the memory dictionary
        new_board = Board(self.size)
        memory_dict[id(self)] = new_board

        new_board.board = np.copy(self.board)
        new_board.stage = self.stage
        new_board.selected_amazon = copy.deepcopy(self.selected_amazon, memory_dict)

        return new_board


class Move:
    def __init__(self, action, point):
        self.action = action
        self.point = point

    @classmethod
    def select(cls, point):
        return cls('select', point)

    @classmethod
    def move(cls, point):
        return cls('move', point)

    @classmethod
    def place(cls, point):
        return cls('place', point)


class GameState:
    def __init__(self, board, next_player, previous=None, move=None):
        self.board = copy.deepcopy(board)
        self.next_player = next_player
        self.previous_state = previous
        self.last_move = move

    def apply_move(self, move):
        new_board = copy.deepcopy(self.board)
        if move.action == 'select':
            new_board.select_amazon(move.point)
        elif move.action == 'move':
            new_board.move_amazon(move.point)
        elif move.action == 'place':
            new_board.place_obstacle(move.point)
        return GameState(new_board, self.next_player.other, self, move)

    @classmethod
    def new_game(cls):
        board = Board()
        return GameState(board, Player.black)

GameState存储棋盘的任何一手的实际状态;Move是某一手的所有动作;Board定义了棋盘的格式和所有合法的动作和先后顺序。