Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
Casper-Guo committed May 18, 2024
1 parent 2e38db3 commit bb51bf4
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 7 deletions.
8 changes: 7 additions & 1 deletion royal_game/_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ def __init__(self, player) -> None:
class MoveError(Exception):
pass

# ImpossibleMove denotes a move that is invalid in any circumstances
# InvalidMove denotes a move that is invalid on a specific board
class ImpossibleMove(MoveError):
def __init__(self) -> None:
super().__init__(f"The requested move is impossible.")
super().__init__("The requested move is impossible.")

class InvalidMove(MoveError):
def __init__(self) -> None:
super().__init__("This move is invalid.")
20 changes: 19 additions & 1 deletion royal_game/modules/board.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
start_end_iter,
white_iter,
)
from royal_game._exceptions import InvalidNumberofPieces
from royal_game._exceptions import InvalidMove, InvalidNumberofPieces
from royal_game.modules.grid import Grid, StartEndGrid
from royal_game.modules.grid_status import GridStatus
from royal_game.modules.move import Move


class Board:
Expand Down Expand Up @@ -159,3 +160,20 @@ def is_end_state(self):
1, Get available moves on the board, based on the dice roll
2, Execute a move and modify the board, including validity check
"""

def get_available_moves(self, white_turn: bool, dice_roll: int) -> tuple[Move]:
"""Return a tuple of valid moves."""
pass

def make_move(self, move: Move) -> None:
"""
Modify the board based on the board.
Limited validity check implemented.
"""
if move.is_onboard:
if self.board[move.grid2].status != GridStatus.empty:
raise InvalidMove
else:
if self.board[move.grid1].status == self.board[move.grid2].status:
raise InvalidMove
45 changes: 42 additions & 3 deletions royal_game/modules/game.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
"""Implements game loop."""

from royal_game._exceptions import InvalidPlayer
import logging
from random import choices

from royal_game._exceptions import InvalidMove, InvalidPlayer
from royal_game.modules.board import Board
from royal_game.modules.player import Player

logging.basicConfig(filename="games.log", filemode="w", format="%(levelname)s: %(message)s")
logger = logging.getLogger(__name__)


class Game:
"""
Expand All @@ -25,7 +31,7 @@ def __init__(self, player1: Player, player2: Player):
self.board = Board()
self.white_turn = True

def play(self) -> None:
def play(self) -> bool:
"""
Implement the game loop.
Expand All @@ -34,6 +40,39 @@ def play(self) -> None:
3, player returns selected move
4, update board
5, determine who has the next turn
Return true if white wins, and vice versa
"""
# pre-game output, player names etc.

while not self.board.is_end_state():
pass
dice_roll = choices(
[0, 1, 2, 3, 4], weights=[1 / 16, 1 / 4, 3 / 8, 1 / 4, 1 / 16], k=1
)

if dice_roll == 0:
logger.info(
"%s rolled a zero. The turn is automatically passed",
self.player1 if self.white_turn else self.player2,
)
self.white_turn = not self.white_turn
continue

available_moves = self.board.get_available_moves(self.white_turn, dice_roll)
move_selected = (
self.player1.select_move(self.board, available_moves)
if self.white_turn
else self.player2(self.board, available_moves)
)

try:
logger.info(move_selected)
self.board.make_move(move_selected)
except InvalidMove as e:
logger.critical(move_selected)
raise e

if not move_selected.is_rosette:
self.white_turn = not self.white_turn

# end of game output, results + any metadata
2 changes: 1 addition & 1 deletion royal_game/modules/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ class Grid:
def __init__(
self, name: str, is_rosette: bool, status: GridStatus = GridStatus.empty
) -> None:
self.status = status
self.name = name
self.is_rosette = is_rosette
self.status = status

def __str__(self) -> str:
symbol = " "
Expand Down
18 changes: 17 additions & 1 deletion royal_game/modules/move.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,30 @@ class Move:
"""Move representation and benchmarking metadata."""

def __init__(
self, grid1: str, grid2: str, is_rosette: bool, is_capture: bool, is_ascension: bool
self,
grid1: str,
grid2: str,
is_rosette: bool,
is_capture: bool,
is_ascension: bool,
is_onboard: bool,
) -> None:
self.grid1 = grid1
self.grid2 = grid2
self.is_rosette = is_rosette
self.is_capture = is_capture
self.is_ascension = is_ascension
self.is_onboard = is_onboard

try:
if int(is_rosette) + int(is_capture) + int(is_ascension) > 1:
raise ImpossibleMove
if self.grid1 == self.grid2:
raise ImpossibleMove
if (self.grid1[0] == "W" and self.grid2[0] == "B") or (
self.grid1[0] == "B" and self.grid2[0] == "W"
):
raise ImpossibleMove
except ImpossibleMove as e:
print(self)
raise e
Expand All @@ -36,6 +49,9 @@ def __repr__(self) -> str:
f"{capture if self.is_capture else ""}{ascension if self.is_ascension else ""}"
)

# It would be a nice QoL improvement to implement a full partial order
# so moves can be reasonably sorted
# Not urgent due to minimal player interaction and need for nice interface
def __eq__(self, other: object) -> bool:
if not isinstance(other, Move):
return NotImplemented
Expand Down

0 comments on commit bb51bf4

Please sign in to comment.