diff --git a/Game/gamestate.py b/Game/gamestate.py index 734f737..9c7b41b 100644 --- a/Game/gamestate.py +++ b/Game/gamestate.py @@ -19,7 +19,7 @@ class GameState: _playfield: list[list[int]] _finished: bool - _winner: int + _winner: int = None def __init__(self, playfiled_dimensions: tuple[int, int] = (3,3)): """ @@ -93,3 +93,13 @@ def playfield_value(self, position: tuple[int, int]) -> int: int: The value at the specified position on the playfield. """ return self._playfield[position[0]][position[1]] + + @property + def playfield_dimensions(self) -> tuple[int, int]: + """ + Returns the size of the playfield. + + Returns: + tuple[int, int]: The size of the playfield. + """ + return (len(self._playfield), len(self._playfield[0])) diff --git a/Game/rulebase.py b/Game/rulebase.py index efdade3..a9e324b 100644 --- a/Game/rulebase.py +++ b/Game/rulebase.py @@ -72,14 +72,18 @@ def check_win(self, state: GameState): return # Check vertical lines - for column in state.playfield.T: + for column in transpose(state.playfield): if len(set(column)) == 1 and column[0] != 0: state.set_winner(column[0]) return # Check diagonals - diagonal1 = [state.playfield[i][i] for i in range(min(state.playfield_dimensions))] - diagonal2 = [state.playfield[i][j] for i, j in zip(range(min(state.playfield_dimensions)), range(max(state.playfield_dimensions)-1, -1, -1))] + if state.playfield_dimensions[0] != state.playfield_dimensions[1]: + # playfield is not square and thus has no diagonal winning condition + return + + diagonal1 = [state.playfield[i][i] for i in range(state.playfield_dimensions[0])] + diagonal2 = [state.playfield[i][j] for i in range(state.playfield_dimensions[0]) for j in range(state.playfield_dimensions[0], -1)] if len(set(diagonal1)) == 1 and diagonal1[0] != 0: state.set_winner(diagonal1[0]) return @@ -91,7 +95,7 @@ def check_win(self, state: GameState): state.set_winner(0) return - return 0 + return def is_game_state_valid(self, state: GameState) -> bool: """ @@ -122,3 +126,16 @@ def explain(self, state: GameState, prev: tuple[int, int], new: tuple[int, int]) """ return "" # TODO + +def transpose(matrix: list[list[int]]) -> list[list[int]]: + """ + Transpose a matrix. + + Args: + matrix (list[list[int]]): The matrix to transpose. + + Returns: + list[list[int]]: The transposed matrix. + + """ + return [list(row) for row in zip(*matrix)] diff --git a/Game/test_rulebase.py b/Game/test_rulebase.py new file mode 100644 index 0000000..ae1357a --- /dev/null +++ b/Game/test_rulebase.py @@ -0,0 +1,73 @@ +from gamestate import GameState +from rulebase import RuleBase + +def test_is_move_valid(): + # Create a GameState object + state = GameState() + + # Create a RuleBase object + rulebase = RuleBase() + + # Test case 1: Valid move + new_position = (0, 0) + assert rulebase.is_move_valid(state, new_position) == True + + # Test case 2: Invalid move (position already occupied) + state.set_player_position(1, new_position) + assert rulebase.is_move_valid(state, new_position) == False + +def test_check_win(): + + # Test case 1: No winner + state = GameState() + rulebase = RuleBase() + rulebase.check_win(state) + assert state.winner == 0 & state.finished == False + + # Test case 2: Horizontal win + state = GameState() + rulebase = RuleBase() + state._playfield = [[1, 1, 1], [0, 2, 0], [2, 0, 2]] + rulebase.check_win(state) + assert state.winner == 1 & state.finished == True + + # Test case 3: Vertical win + state = GameState() + rulebase = RuleBase() + state._playfield = [[1, 0, 2], [1, 0, 2], [1, 2, 0]] + rulebase.check_win(state) + assert state.winner == 1 & state.finished == True + + # Test case 4: Diagonal win + state = GameState() + rulebase = RuleBase() + state._playfield = [[1, 0, 2], [2, 1, 0], [2, 0, 1]] + rulebase.check_win(state) + assert state.winner == 1 & state.finished == True + + # Test case 5: Draw + state = GameState() + rulebase = RuleBase() + state._playfield = [[1, 2, 1], [1, 2, 2], [2, 1, 1]] + rulebase.check_win(state) + assert state.winner == 0 and state.finished == True + +def test_is_game_state_valid(): + # Create a GameState object + state = GameState() + + # Create a RuleBase object + rulebase = RuleBase() + + # Test case 1: Valid game state + assert rulebase.is_game_state_valid(state) == True + + # Test case 2: Invalid game state (difference in player counts > 1) + state.set_player_position(1, (0, 0)) + state.set_player_position(1, (0, 1)) + assert rulebase.is_game_state_valid(state) == False + +# Run the test cases +test_is_move_valid() +test_check_win() +test_is_game_state_valid()