Skip to content

Commit 6f57861

Browse files
committed
chore: Add is_over and possible_moves methods to GameState
1 parent 7956328 commit 6f57861

File tree

2 files changed

+108
-2
lines changed

2 files changed

+108
-2
lines changed

python/socha/_socha.pyi

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,18 @@ class GameState:
106106
def clone_current_player(self) -> Hare: ...
107107
def clone_other_player(self) -> Hare: ...
108108
def update_player(self, player: Hare) -> None: ...
109+
def is_over(self) -> bool: ...
110+
def possible_moves(self) -> List[Move]: ...
109111

110112
class RulesEngine:
111113
@staticmethod
112114
def calculates_carrots(distance: int) -> int: ...
113115
@staticmethod
114-
def can_exchange_carrots(board: Board, player: Hare, count: int) -> bool: ...
116+
def can_exchange_carrots(board: Board, player: Hare, count: int) -> None: ...
115117
@staticmethod
116-
def can_eat_salad(board: Board, player: Hare) -> bool: ...
118+
def can_eat_salad(board: Board, player: Hare) -> None: ...
119+
@staticmethod
120+
def has_to_eat_salad(board: Board, player: Hare) -> None: ...
117121
@staticmethod
118122
def can_advance_to(
119123
board: Board, new_position: int, player: Hare, other_player: Hare

src/plugin/game_state.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
use itertools::Itertools;
12
use pyo3::*;
23

4+
use super::action::advance::Advance;
5+
use super::action::card::Card;
6+
use super::action::eat_salad::EatSalad;
7+
use super::action::exchange_carrots::ExchangeCarrots;
8+
use super::action::fall_back::FallBack;
9+
use super::action::Action;
310
use super::board::Board;
11+
use super::constants::PluginConstants;
12+
use super::field::Field;
413
use super::hare::Hare;
514
use super::r#move::Move;
615

@@ -58,6 +67,99 @@ impl GameState {
5867
}
5968
}
6069

70+
pub fn is_over(&self) -> bool {
71+
let player_one_in_goal = self.player_one.is_in_goal();
72+
let player_two_in_goal = self.player_two.is_in_goal();
73+
let both_had_last_chance = self.turn % 2 == 0;
74+
let rounds_exceeded = self.turn / 2 == PluginConstants::ROUND_LIMIT;
75+
76+
player_one_in_goal || player_two_in_goal && both_had_last_chance || rounds_exceeded
77+
}
78+
79+
pub fn possible_moves(&self) -> Vec<Move> {
80+
let mut moves = Vec::new();
81+
82+
moves.append(&mut self.possible_advance_moves());
83+
moves.append(&mut self.possible_eat_salad_moves());
84+
moves.append(&mut self.possible_exchange_carrots_moves());
85+
moves.append(&mut self.possible_fall_back_moves());
86+
87+
moves
88+
}
89+
90+
fn possible_exchange_carrots_moves(&self) -> Vec<Move> {
91+
let moves: Vec<Move> = vec![
92+
Move::new(Action::ExchangeCarrots(ExchangeCarrots::new(-10))),
93+
Move::new(Action::ExchangeCarrots(ExchangeCarrots::new(10))),
94+
];
95+
96+
moves
97+
.into_iter()
98+
.filter(|m| m.perform(&mut self.clone()).is_ok())
99+
.collect()
100+
}
101+
102+
fn possible_fall_back_moves(&self) -> Vec<Move> {
103+
let moves: Vec<Move> = vec![Move::new(Action::FallBack(FallBack::new()))];
104+
105+
moves
106+
.into_iter()
107+
.filter(|m| m.perform(&mut self.clone()).is_ok())
108+
.collect()
109+
}
110+
111+
fn possible_eat_salad_moves(&self) -> Vec<Move> {
112+
let moves: Vec<Move> = vec![Move::new(Action::EatSalad(EatSalad::new()))];
113+
114+
moves
115+
.into_iter()
116+
.filter(|m| m.perform(&mut self.clone()).is_ok())
117+
.collect()
118+
}
119+
120+
fn possible_advance_moves(&self) -> Vec<Move> {
121+
let current_player = self.clone_current_player();
122+
let max_distance =
123+
(((-1.0 + (1 + 8 * current_player.carrots) as f64).sqrt()) / 2.0) as usize;
124+
125+
let mut moves = Vec::new();
126+
127+
for distance in 1..=max_distance {
128+
if let Some(Field::Hare) = self.board.get_field(current_player.position + distance) {
129+
for k in 0..current_player.cards.len() {
130+
for combination in current_player.cards.iter().combinations(k) {
131+
moves.push(Move::new(Action::Advance(Advance::new(
132+
distance,
133+
combination.iter().map(|&c| *c).collect(),
134+
))));
135+
}
136+
}
137+
}
138+
139+
if self.board.get_field(current_player.position + distance) == Some(Field::Market) {
140+
let cards = vec![
141+
Card::FallBack,
142+
Card::HurryAhead,
143+
Card::EatSalad,
144+
Card::SwapCarrots,
145+
];
146+
for card in cards {
147+
moves.push(Move::new(Action::Advance(Advance::new(
148+
distance,
149+
vec![card],
150+
))));
151+
}
152+
}
153+
154+
moves.push(Move::new(Action::Advance(Advance::new(distance, vec![]))));
155+
}
156+
157+
moves
158+
.into_iter()
159+
.filter(|m| m.perform(&mut self.clone()).is_ok())
160+
.collect()
161+
}
162+
61163
pub fn __repr__(&self) -> String {
62164
format!("{:?}", self)
63165
}

0 commit comments

Comments
 (0)