Skip to content

Commit

Permalink
Add roadmap for remaining implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Casper-Guo committed May 18, 2024
1 parent f0f6812 commit 2e38db3
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 25 deletions.
7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ build-backend = "setuptools.build_meta"
[tool.ruff]
line-length = 96
indent-width = 4
exclude = ["royal_game/_exceptions.py", "royal_game/__init__.py", "royal_game/tests/*.py"]
exclude = [
"royal_game/_exceptions.py",
"royal_game/__init__.py",
"royal_game/tests/*.py",
"royal_game/players/*.py"
]

[tool.ruff.format]
quote-style = "double"
Expand Down
10 changes: 7 additions & 3 deletions royal_game/_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Custom exception types."""

from royal_game.modules.player import Player

class GridError(Exception):
pass

Expand All @@ -28,7 +26,13 @@ class GameError(Exception):
pass

class InvalidPlayer(GameError):
def __init__(self, player: Player) -> None:
def __init__(self, player) -> None:
"""
player is a Player class object.
Annotating this type is impossible due to circular imports.
"""

message = f"Player {player.name} has not implemented select_move."
super().__init__(message)

Expand Down
15 changes: 15 additions & 0 deletions royal_game/modules/board.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def __repr__(self):
return fmt

def __int__(self) -> int:
"""Recalculate the integer representation since the board may be modified."""
board_int = 0
offset = 0

Expand All @@ -136,6 +137,14 @@ def __int__(self) -> int:

return board_int

def __eq__(self, other: object) -> bool:
if not isinstance(other, Board):
return NotImplemented
return self.__int__() == other.__int__()

def __hash__(self) -> int:
return self.__int__()

def is_end_state(self):
"""
Check if the board is at an end state.
Expand All @@ -144,3 +153,9 @@ def is_end_state(self):
all 7 pieces to the end grid.
"""
return self.board["BE"].num_pieces == 7 or self.board["WE"].num_pieces == 7

"""
Logic to be implemented:
1, Get available moves on the board, based on the dice roll
2, Execute a move and modify the board, including validity check
"""
23 changes: 14 additions & 9 deletions royal_game/modules/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,17 @@ def __init__(self, player1: Player, player2: Player):
self.player1 = player1
self.player2 = player2
self.board = Board()

"""
Game loop basic design:
1, roll dices. If 0, skip to 5
2, send available moves to player
3, player returns selected move
4, update board
5, determine who has the next turn
"""
self.white_turn = True

def play(self) -> None:
"""
Implement the game loop.
1, roll dices. If 0, skip to 5
2, send available moves to player
3, player returns selected move
4, update board
5, determine who has the next turn
"""
while not self.board.is_end_state():
pass
9 changes: 9 additions & 0 deletions royal_game/modules/player.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
"""Implements player interface."""

from typing import Iterable

from royal_game.modules.board import Board
from royal_game.modules.move import Move


class Player:
"""Player evaluates board state and selects from available actions."""
Expand All @@ -9,3 +14,7 @@ def __init__(self, name: str) -> None:

def __repr__(self) -> str:
return self.name

def select_move(self, board: Board, available_moves: Iterable[Move]) -> Move:
"""All subclasses must implement this method."""
pass
32 changes: 21 additions & 11 deletions royal_game/players/example.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
"""An example player implementation."""

# from royal_game.modules.player import Player
# from typing import Iterable
# from royal_game.modules.board import Board
# from royal_game.modules.move import Move
from royal_game.modules.player import Player
from typing import Iterable
from royal_game.modules.board import Board
from royal_game.modules.move import Move

# class SamplePlayer(Player):
# """You must implement the select_move method!"""
# def __init__(self):
# choose a name for your player
# super().__init__(name)
# def select_move(self, board: Board, available_moves: Iterable[Move]) -> Move:
# pass
class SamplePlayer(Player):
"""You must implement the select_move method!"""
def __init__(self):
"""choose a name for your player"""
super().__init__("{name goes here}")
def select_move(self, board: Board, available_moves: Iterable[Move]) -> Move:
"""
Select a move based on some heuristic.
The complete board state can be accessed through board.board by indexing
with the name of the grids. The grid representation is reproduced below:
white (W): W4 W3 W2 W1 WS WE W14 W13
public: 5 6 7 8 9 10 11 12
black (B): B4 B3 B2 B1 BS BE B14 B13
"""
pass
3 changes: 2 additions & 1 deletion royal_game/tests/test_board.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ def test_init():
assert board.board["B14"].status == GridStatus.empty
assert int(board.board["WS"]) == 2
assert int(board.board["BE"]) == 1
assert int(board) == 174518804524


def test_check_endstate():
assert Board(966988398624).is_end_state()
assert not Board(829549445216).is_end_state()
assert Board(599282155520).is_end_state()
assert not Board(829549445216).is_end_state()
assert not Board(597403107328).is_end_state()

0 comments on commit 2e38db3

Please sign in to comment.