"""Go game data models.
This module provides Pydantic models for representing Go game concepts:
- Move coordinates and validation
- Player decisions
- Position analysis and evaluation
- Territory control tracking
Example:
>>> from haive.games.go.models import GoMoveModel, GoAnalysis
>>>
>>> # Create and validate a move
>>> move = GoMoveModel(move=(3, 4), board_size=19)
>>> move.to_tuple()
(3, 4)
>>>
>>> # Create a position analysis
>>> analysis = GoAnalysis(
... territory_control={"black": 45, "white": 40},
... strong_positions=[(3, 3), (15, 15)],
... weak_positions=[(0, 0)],
... suggested_strategies=["Strengthen the center group"]
... )
"""
from typing import Literal
from pydantic import BaseModel, Field, field_validator
[docs]
class GoMoveModel(BaseModel):
"""A model representing a move in Go.
This model validates and stores move coordinates, ensuring they are
within the bounds of the game board.
Attributes:
move (Tuple[int, int]): The (row, col) coordinates of the move.
board_size (int): Size of the game board (default 19x19).
Example:
>>> move = GoMoveModel(move=(3, 4))
>>> move.validate_move((3, 4), {"board_size": 19})
(3, 4)
>>> move.to_tuple()
(3, 4)
>>>
>>> # Invalid move raises error
>>> GoMoveModel(move=(19, 19)) # Out of bounds
ValueError: Move (19, 19) is out of bounds for a 19x19 board.
"""
move: tuple[int, int] = Field(
..., description="Move coordinates as (row, col) tuple."
)
board_size: int = Field(default=19, description="Size of the game board (NxN).")
[docs]
@field_validator("move")
@classmethod
def validate_move(cls, move: tuple[int, int], values) -> tuple[int, int]:
"""Validate that a move is within board bounds.
Args:
move (Tuple[int, int]): The move coordinates to validate.
values (dict): Dictionary containing model field values.
Returns:
Tuple[int, int]: The validated move coordinates.
Raises:
ValueError: If move coordinates are outside board bounds.
"""
row, col = move
board_size = values.get("board_size", 19)
if not (0 <= row < board_size and 0 <= col < board_size):
raise ValueError(
f"Move {move} is out of bounds for a {board_size}x{board_size} board."
)
return move
[docs]
def to_tuple(self) -> tuple[int, int]:
"""Convert the move to a simple coordinate tuple.
Returns:
Tuple[int, int]: The move coordinates as (row, col).
"""
return self.move
[docs]
class GoPlayerDecision(BaseModel):
"""A model representing a player's move decision.
This model encapsulates a player's decision about their next move,
including validation of the move coordinates.
Attributes:
move (GoMoveModel): The chosen move coordinates and validation.
Example:
>>> decision = GoPlayerDecision(
... move=GoMoveModel(move=(3, 4))
... )
>>> decision.move.to_tuple()
(3, 4)
"""
move: GoMoveModel = Field(..., description="The player's chosen move.")
[docs]
class GoAnalysis(BaseModel):
"""A model for storing Go position analysis.
This model captures a comprehensive analysis of a Go position,
including territory control, key positions, and strategic advice.
Attributes:
territory_control (Dict[str, int]): Estimated territory for each player.
strong_positions (List[Tuple[int, int]]): List of strong positions.
weak_positions (List[Tuple[int, int]]): List of vulnerable positions.
suggested_strategies (List[str]): List of strategic recommendations.
Example:
>>> analysis = GoAnalysis(
... territory_control={"black": 45, "white": 40},
... strong_positions=[(3, 3), (15, 15)],
... weak_positions=[(0, 0)],
... suggested_strategies=[
... "Strengthen the center group",
... "Consider invading the top right"
... ]
... )
"""
territory_control: dict[Literal["black", "white"], int] = Field(
..., description="Estimated territory control points for each player."
)
strong_positions: list[tuple[int, int]] = Field(
default_factory=list, description="List of strategically strong positions."
)
weak_positions: list[tuple[int, int]] = Field(
default_factory=list,
description="List of vulnerable positions needing attention.",
)
suggested_strategies: list[str] = Field(
default_factory=list,
description="List of strategic recommendations for the position.",
)