fix: allowed moves infinite loop
This commit is contained in:
parent
38100a61b2
commit
6478f5043d
|
|
@ -1,6 +1,6 @@
|
||||||
mod strategy;
|
mod strategy;
|
||||||
|
|
||||||
use store::{CheckerMove, Color, GameEvent, GameState, PlayerId, PointsRules, TurnStage};
|
use store::{CheckerMove, Color, GameEvent, GameState, PlayerId, PointsRules, Stage, TurnStage};
|
||||||
pub use strategy::default::DefaultStrategy;
|
pub use strategy::default::DefaultStrategy;
|
||||||
|
|
||||||
pub trait BotStrategy: std::fmt::Debug {
|
pub trait BotStrategy: std::fmt::Debug {
|
||||||
|
|
@ -61,6 +61,9 @@ impl Bot {
|
||||||
pub fn handle_event(&mut self, event: &GameEvent) -> Option<GameEvent> {
|
pub fn handle_event(&mut self, event: &GameEvent) -> Option<GameEvent> {
|
||||||
let game = self.strategy.get_mut_game();
|
let game = self.strategy.get_mut_game();
|
||||||
game.consume(event);
|
game.consume(event);
|
||||||
|
if game.stage == Stage::Ended {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
if game.active_player_id == self.player_id {
|
if game.active_player_id == self.player_id {
|
||||||
return match game.turn_stage {
|
return match game.turn_stage {
|
||||||
TurnStage::MarkAdvPoints => Some(GameEvent::Mark {
|
TurnStage::MarkAdvPoints => Some(GameEvent::Mark {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ impl BotStrategy for DefaultStrategy {
|
||||||
|
|
||||||
fn choose_move(&self) -> (CheckerMove, CheckerMove) {
|
fn choose_move(&self) -> (CheckerMove, CheckerMove) {
|
||||||
let rules = MoveRules::new(&self.color, &self.game.board, self.game.dice);
|
let rules = MoveRules::new(&self.color, &self.game.board, self.game.dice);
|
||||||
let possible_moves = rules.get_possible_moves_sequences(true);
|
let possible_moves = rules.get_possible_moves_sequences(true, vec![]);
|
||||||
let choosen_move = *possible_moves
|
let choosen_move = *possible_moves
|
||||||
.first()
|
.first()
|
||||||
.unwrap_or(&(CheckerMove::default(), CheckerMove::default()));
|
.unwrap_or(&(CheckerMove::default(), CheckerMove::default()));
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,14 @@ impl GameRunner {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(winner) = self.state.determine_winner() {
|
||||||
|
// panic!("WE HAVE A WINNER!");
|
||||||
|
next_event = Some(store::GameEvent::EndGame {
|
||||||
|
reason: store::EndGameReason::PlayerWon { winner },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
next_event
|
next_event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@ Organisation store / server / client selon <https://herluf-ba.github.io/making-a
|
||||||
|
|
||||||
_store_ est la bibliothèque contenant le _reducer_ qui transforme l'état du jeu en fonction des évènements. Elle est utilisée par le _server_ et le _client_. Seuls les évènements sont transmis entre clients et serveur.
|
_store_ est la bibliothèque contenant le _reducer_ qui transforme l'état du jeu en fonction des évènements. Elle est utilisée par le _server_ et le _client_. Seuls les évènements sont transmis entre clients et serveur.
|
||||||
|
|
||||||
|
## Config neovim debugger launchers
|
||||||
|
|
||||||
|
Cela se passe dans la config neovim (lua/plugins/overrides.lua)
|
||||||
|
|
||||||
## Organisation du store
|
## Organisation du store
|
||||||
|
|
||||||
lib
|
lib
|
||||||
|
|
@ -24,6 +28,7 @@ lib
|
||||||
## Algorithme de détermination des coups
|
## Algorithme de détermination des coups
|
||||||
|
|
||||||
- strategy::choose_move
|
- strategy::choose_move
|
||||||
|
|
||||||
- GameRules.get_possible_moves_sequences(with_excedents: bool)
|
- GameRules.get_possible_moves_sequences(with_excedents: bool)
|
||||||
- get_possible_moves_sequences_by_dices(dice_max, dice_min, with_excedents, false);
|
- get_possible_moves_sequences_by_dices(dice_max, dice_min, with_excedents, false);
|
||||||
- get_possible_moves_sequences_by_dices(dice_min, dice_max, with_excedents, true);
|
- get_possible_moves_sequences_by_dices(dice_min, dice_max, with_excedents, true);
|
||||||
|
|
@ -41,7 +46,7 @@ lib
|
||||||
- can_take_corner_by_effect ok
|
- can_take_corner_by_effect ok
|
||||||
- get_possible_moves_sequences -> cf. l.15
|
- get_possible_moves_sequences -> cf. l.15
|
||||||
- check_exit_rules
|
- check_exit_rules
|
||||||
- get_possible_moves_sequences -> cf l.15
|
- get_possible_moves_sequences(without exedents) -> cf l.15
|
||||||
- get_quarter_filling_moves_sequences
|
- get_quarter_filling_moves_sequences
|
||||||
- get_possible_moves_sequences -> cf l.15
|
- get_possible_moves_sequences -> cf l.15
|
||||||
- state.consume (RollResult) (ok)
|
- state.consume (RollResult) (ok)
|
||||||
|
|
|
||||||
|
|
@ -441,7 +441,7 @@ impl Board {
|
||||||
let blocked = self.blocked(color, cmove.to).unwrap_or(true);
|
let blocked = self.blocked(color, cmove.to).unwrap_or(true);
|
||||||
// Check if there is a player's checker on the 'from' square
|
// Check if there is a player's checker on the 'from' square
|
||||||
let has_checker = self.get_checkers_color(cmove.from).unwrap_or(None) == Some(color);
|
let has_checker = self.get_checkers_color(cmove.from).unwrap_or(None) == Some(color);
|
||||||
has_checker && !blocked
|
(has_checker && !blocked) || cmove == &EMPTY_MOVE
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return if there is a quarter filled by the color
|
/// Return if there is a quarter filled by the color
|
||||||
|
|
@ -651,6 +651,12 @@ mod tests {
|
||||||
assert!(board.set(&Color::White, 23, -3).is_err());
|
assert!(board.set(&Color::White, 23, -3).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn move_possible() {
|
||||||
|
let board = Board::new();
|
||||||
|
assert!(board.move_possible(&Color::White, &EMPTY_MOVE));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_color_fields() {
|
fn get_color_fields() {
|
||||||
let board = Board::new();
|
let board = Board::new();
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use crate::dice::Dice;
|
||||||
use crate::game_rules_moves::MoveRules;
|
use crate::game_rules_moves::MoveRules;
|
||||||
use crate::game_rules_points::{PointsRules, PossibleJans};
|
use crate::game_rules_points::{PointsRules, PossibleJans};
|
||||||
use crate::player::{Color, Player, PlayerId};
|
use crate::player::{Color, Player, PlayerId};
|
||||||
use log::error;
|
use log::{error, info};
|
||||||
|
|
||||||
// use itertools::Itertools;
|
// use itertools::Itertools;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -170,7 +170,7 @@ impl GameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn who_plays(&self) -> Option<&Player> {
|
pub fn who_plays(&self) -> Option<&Player> {
|
||||||
self.players.get(&self.active_player_id)
|
self.get_active_player()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_white_player(&self) -> Option<&Player> {
|
pub fn get_white_player(&self) -> Option<&Player> {
|
||||||
|
|
@ -392,7 +392,9 @@ impl GameState {
|
||||||
self.stage = Stage::InGame;
|
self.stage = Stage::InGame;
|
||||||
self.turn_stage = TurnStage::RollDice;
|
self.turn_stage = TurnStage::RollDice;
|
||||||
}
|
}
|
||||||
EndGame { reason: _ } => self.stage = Stage::Ended,
|
EndGame { reason: _ } => {
|
||||||
|
self.stage = Stage::Ended;
|
||||||
|
}
|
||||||
PlayerJoined { player_id, name } => {
|
PlayerJoined { player_id, name } => {
|
||||||
let color = if !self.players.is_empty() {
|
let color = if !self.players.is_empty() {
|
||||||
Color::White
|
Color::White
|
||||||
|
|
@ -542,6 +544,13 @@ impl GameState {
|
||||||
}
|
}
|
||||||
p.points = sum_points % 12;
|
p.points = sum_points % 12;
|
||||||
p.holes += holes;
|
p.holes += holes;
|
||||||
|
|
||||||
|
if points > 0 && p.holes > 15 {
|
||||||
|
info!(
|
||||||
|
"player {:?} holes : {:?} added points : {:?}",
|
||||||
|
player_id, p.holes, points
|
||||||
|
)
|
||||||
|
}
|
||||||
p
|
p
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,13 @@ pub enum MoveError {
|
||||||
MustPlayStrongerDie,
|
MustPlayStrongerDie,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(std::cmp::PartialEq, Debug, Clone)]
|
||||||
|
pub enum TricTracRule {
|
||||||
|
Exit,
|
||||||
|
MustFillQuarter,
|
||||||
|
Corner,
|
||||||
|
}
|
||||||
|
|
||||||
/// MoveRules always consider that the current player is White
|
/// MoveRules always consider that the current player is White
|
||||||
/// You must use 'mirror' functions on board & CheckerMoves if player is Black
|
/// You must use 'mirror' functions on board & CheckerMoves if player is Black
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -62,12 +69,17 @@ impl MoveRules {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn moves_follow_rules(&self, moves: &(CheckerMove, CheckerMove)) -> bool {
|
pub fn moves_follow_rules(
|
||||||
|
&self,
|
||||||
|
moves: &(CheckerMove, CheckerMove),
|
||||||
|
// ignored_rules: Vec<TricTracRule>,
|
||||||
|
) -> bool {
|
||||||
// Check moves possibles on the board
|
// Check moves possibles on the board
|
||||||
// Check moves conforms to the dice
|
// Check moves conforms to the dice
|
||||||
// Check move is allowed by the rules (to desactivate when playing with schools)
|
// Check move is allowed by the rules (to desactivate when playing with schools)
|
||||||
self.moves_possible(moves) && self.moves_follows_dices(moves) && {
|
self.moves_possible(moves) && self.moves_follows_dices(moves) && {
|
||||||
let is_allowed = self.moves_allowed(moves);
|
let is_allowed = self.moves_allowed(moves);
|
||||||
|
// let is_allowed = self.moves_allowed(moves, ignored_rules);
|
||||||
if is_allowed.is_err() {
|
if is_allowed.is_err() {
|
||||||
info!("Move not allowed : {:?}", is_allowed.unwrap_err());
|
info!("Move not allowed : {:?}", is_allowed.unwrap_err());
|
||||||
false
|
false
|
||||||
|
|
@ -165,7 +177,11 @@ impl MoveRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ---- moves_allowed : Third of three checks for moves
|
/// ---- moves_allowed : Third of three checks for moves
|
||||||
pub fn moves_allowed(&self, moves: &(CheckerMove, CheckerMove)) -> Result<(), MoveError> {
|
pub fn moves_allowed(
|
||||||
|
&self,
|
||||||
|
moves: &(CheckerMove, CheckerMove),
|
||||||
|
// ignored_rules: Vec<TricTracRule>,
|
||||||
|
) -> Result<(), MoveError> {
|
||||||
self.check_corner_rules(moves)?;
|
self.check_corner_rules(moves)?;
|
||||||
|
|
||||||
if self.is_move_by_puissance(moves) {
|
if self.is_move_by_puissance(moves) {
|
||||||
|
|
@ -179,7 +195,7 @@ impl MoveRules {
|
||||||
|
|
||||||
// Si possible, les deux dés doivent être joués
|
// Si possible, les deux dés doivent être joués
|
||||||
if moves.0.get_from() == 0 || moves.1.get_from() == 0 {
|
if moves.0.get_from() == 0 || moves.1.get_from() == 0 {
|
||||||
let mut possible_moves_sequences = self.get_possible_moves_sequences(true);
|
let mut possible_moves_sequences = self.get_possible_moves_sequences(true, vec![]);
|
||||||
possible_moves_sequences.retain(|moves| self.check_exit_rules(moves).is_ok());
|
possible_moves_sequences.retain(|moves| self.check_exit_rules(moves).is_ok());
|
||||||
// possible_moves_sequences.retain(|moves| self.check_corner_rules(moves).is_ok());
|
// possible_moves_sequences.retain(|moves| self.check_corner_rules(moves).is_ok());
|
||||||
if !possible_moves_sequences.contains(moves) && !possible_moves_sequences.is_empty() {
|
if !possible_moves_sequences.contains(moves) && !possible_moves_sequences.is_empty() {
|
||||||
|
|
@ -197,21 +213,42 @@ impl MoveRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check exit rules
|
// check exit rules
|
||||||
|
// if !ignored_rules.contains(&TricTracRule::Exit) {
|
||||||
self.check_exit_rules(moves)?;
|
self.check_exit_rules(moves)?;
|
||||||
|
// }
|
||||||
|
|
||||||
// --- interdit de jouer dans un cadran que l'adversaire peut encore remplir ----
|
// --- interdit de jouer dans un cadran que l'adversaire peut encore remplir ----
|
||||||
|
self.check_opponent_can_fill_quarter_rule(moves)?;
|
||||||
|
|
||||||
|
// --- remplir cadran si possible & conserver cadran rempli si possible ----
|
||||||
|
// if !ignored_rules.contains(&TricTracRule::MustFillQuarter) {
|
||||||
|
self.check_must_fill_quarter_rule(moves)?;
|
||||||
|
// }
|
||||||
|
// no rule was broken
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- interdit de jouer dans un cadran que l'adversaire peut encore remplir ----
|
||||||
|
fn check_opponent_can_fill_quarter_rule(
|
||||||
|
&self,
|
||||||
|
moves: &(CheckerMove, CheckerMove),
|
||||||
|
) -> Result<(), MoveError> {
|
||||||
let farthest = cmp::max(moves.0.get_to(), moves.1.get_to());
|
let farthest = cmp::max(moves.0.get_to(), moves.1.get_to());
|
||||||
let in_opponent_side = farthest > 12;
|
let in_opponent_side = farthest > 12;
|
||||||
if in_opponent_side && self.board.is_quarter_fillable(Color::Black, farthest) {
|
if in_opponent_side && self.board.is_quarter_fillable(Color::Black, farthest) {
|
||||||
return Err(MoveError::OpponentCanFillQuarter);
|
return Err(MoveError::OpponentCanFillQuarter);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// --- remplir cadran si possible & conserver cadran rempli si possible ----
|
fn check_must_fill_quarter_rule(
|
||||||
|
&self,
|
||||||
|
moves: &(CheckerMove, CheckerMove),
|
||||||
|
) -> Result<(), MoveError> {
|
||||||
let filling_moves_sequences = self.get_quarter_filling_moves_sequences();
|
let filling_moves_sequences = self.get_quarter_filling_moves_sequences();
|
||||||
if !filling_moves_sequences.contains(moves) && !filling_moves_sequences.is_empty() {
|
if !filling_moves_sequences.contains(moves) && !filling_moves_sequences.is_empty() {
|
||||||
return Err(MoveError::MustFillQuarter);
|
return Err(MoveError::MustFillQuarter);
|
||||||
}
|
}
|
||||||
// no rule was broken
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,12 +304,16 @@ impl MoveRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
// toutes les sorties directes sont autorisées, ainsi que les nombres défaillants
|
// toutes les sorties directes sont autorisées, ainsi que les nombres défaillants
|
||||||
let possible_moves_sequences = self.get_possible_moves_sequences(false);
|
let ignored_rules = vec![TricTracRule::Exit];
|
||||||
if !possible_moves_sequences.contains(moves) {
|
let possible_moves_sequences_without_excedent =
|
||||||
|
self.get_possible_moves_sequences(false, ignored_rules);
|
||||||
|
if possible_moves_sequences_without_excedent.contains(moves) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
// À ce stade au moins un des déplacements concerne un nombre en excédant
|
// À ce stade au moins un des déplacements concerne un nombre en excédant
|
||||||
// - si d'autres séquences de mouvements sans nombre en excédant étaient possibles, on
|
// - si d'autres séquences de mouvements sans nombre en excédant sont possibles, on
|
||||||
// refuse cette séquence
|
// refuse cette séquence
|
||||||
if !possible_moves_sequences.is_empty() {
|
if !possible_moves_sequences_without_excedent.is_empty() {
|
||||||
return Err(MoveError::ExitByEffectPossible);
|
return Err(MoveError::ExitByEffectPossible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -312,13 +353,13 @@ impl MoveRules {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_possible_moves_sequences(
|
pub fn get_possible_moves_sequences(
|
||||||
&self,
|
&self,
|
||||||
with_excedents: bool,
|
with_excedents: bool,
|
||||||
|
ignored_rules: Vec<TricTracRule>,
|
||||||
) -> Vec<(CheckerMove, CheckerMove)> {
|
) -> Vec<(CheckerMove, CheckerMove)> {
|
||||||
let (dice1, dice2) = self.dice.values;
|
let (dice1, dice2) = self.dice.values;
|
||||||
let (dice_max, dice_min) = if dice1 > dice2 {
|
let (dice_max, dice_min) = if dice1 > dice2 {
|
||||||
|
|
@ -326,8 +367,13 @@ impl MoveRules {
|
||||||
} else {
|
} else {
|
||||||
(dice2, dice1)
|
(dice2, dice1)
|
||||||
};
|
};
|
||||||
let mut moves_seqs =
|
let mut moves_seqs = self.get_possible_moves_sequences_by_dices(
|
||||||
self.get_possible_moves_sequences_by_dices(dice_max, dice_min, with_excedents, false);
|
dice_max,
|
||||||
|
dice_min,
|
||||||
|
with_excedents,
|
||||||
|
false,
|
||||||
|
ignored_rules.clone(),
|
||||||
|
);
|
||||||
// if we got valid sequences with the highest die, we don't accept sequences using only the
|
// if we got valid sequences with the highest die, we don't accept sequences using only the
|
||||||
// lowest die
|
// lowest die
|
||||||
let ignore_empty = !moves_seqs.is_empty();
|
let ignore_empty = !moves_seqs.is_empty();
|
||||||
|
|
@ -336,6 +382,7 @@ impl MoveRules {
|
||||||
dice_max,
|
dice_max,
|
||||||
with_excedents,
|
with_excedents,
|
||||||
ignore_empty,
|
ignore_empty,
|
||||||
|
ignored_rules,
|
||||||
);
|
);
|
||||||
moves_seqs.append(&mut moves_seqs_order2);
|
moves_seqs.append(&mut moves_seqs_order2);
|
||||||
let empty_removed = moves_seqs
|
let empty_removed = moves_seqs
|
||||||
|
|
@ -400,7 +447,8 @@ impl MoveRules {
|
||||||
pub fn get_quarter_filling_moves_sequences(&self) -> Vec<(CheckerMove, CheckerMove)> {
|
pub fn get_quarter_filling_moves_sequences(&self) -> Vec<(CheckerMove, CheckerMove)> {
|
||||||
let mut moves_seqs = Vec::new();
|
let mut moves_seqs = Vec::new();
|
||||||
let color = &Color::White;
|
let color = &Color::White;
|
||||||
for moves in self.get_possible_moves_sequences(true) {
|
let ignored_rules = vec![TricTracRule::Exit, TricTracRule::MustFillQuarter];
|
||||||
|
for moves in self.get_possible_moves_sequences(true, ignored_rules) {
|
||||||
let mut board = self.board.clone();
|
let mut board = self.board.clone();
|
||||||
board.move_checker(color, moves.0).unwrap();
|
board.move_checker(color, moves.0).unwrap();
|
||||||
board.move_checker(color, moves.1).unwrap();
|
board.move_checker(color, moves.1).unwrap();
|
||||||
|
|
@ -418,6 +466,7 @@ impl MoveRules {
|
||||||
dice2: u8,
|
dice2: u8,
|
||||||
with_excedents: bool,
|
with_excedents: bool,
|
||||||
ignore_empty: bool,
|
ignore_empty: bool,
|
||||||
|
ignored_rules: Vec<TricTracRule>,
|
||||||
) -> Vec<(CheckerMove, CheckerMove)> {
|
) -> Vec<(CheckerMove, CheckerMove)> {
|
||||||
let mut moves_seqs = Vec::new();
|
let mut moves_seqs = Vec::new();
|
||||||
let color = &Color::White;
|
let color = &Color::White;
|
||||||
|
|
@ -439,24 +488,37 @@ impl MoveRules {
|
||||||
board2.get_possible_moves(*color, dice2, with_excedents, true, forbid_exits)
|
board2.get_possible_moves(*color, dice2, with_excedents, true, forbid_exits)
|
||||||
{
|
{
|
||||||
if self.check_corner_rules(&(first_move, second_move)).is_ok()
|
if self.check_corner_rules(&(first_move, second_move)).is_ok()
|
||||||
|
&& self
|
||||||
|
.check_opponent_can_fill_quarter_rule(&(first_move, second_move))
|
||||||
|
.is_ok()
|
||||||
&& !(self.is_move_by_puissance(&(first_move, second_move))
|
&& !(self.is_move_by_puissance(&(first_move, second_move))
|
||||||
&& self.can_take_corner_by_effect())
|
&& self.can_take_corner_by_effect())
|
||||||
|
&& (ignored_rules.contains(&TricTracRule::Exit)
|
||||||
|
|| self.check_exit_rules(&(first_move, second_move)).is_ok())
|
||||||
|
&& (ignored_rules.contains(&TricTracRule::MustFillQuarter)
|
||||||
|
|| self
|
||||||
|
.check_must_fill_quarter_rule(&(first_move, second_move))
|
||||||
|
.is_ok())
|
||||||
{
|
{
|
||||||
moves_seqs.push((first_move, second_move));
|
moves_seqs.push((first_move, second_move));
|
||||||
has_second_dice_move = true;
|
has_second_dice_move = true;
|
||||||
}
|
}
|
||||||
// TODO : autres règles à vérifier (cf. moves_allowed)
|
|
||||||
// - check_exit_rules -> utilise get_possible_moves_sequences !
|
|
||||||
// - get_quarter_filling_moves_sequences -> utilise get_possible_moves_sequences !
|
|
||||||
}
|
}
|
||||||
if !has_second_dice_move
|
if !has_second_dice_move
|
||||||
&& with_excedents
|
&& with_excedents
|
||||||
&& !ignore_empty
|
&& !ignore_empty
|
||||||
&& self.check_corner_rules(&(first_move, EMPTY_MOVE)).is_ok()
|
&& self.check_corner_rules(&(first_move, EMPTY_MOVE)).is_ok()
|
||||||
// TODO : autres règles à vérifier (cf. moves_allowed)
|
&& self
|
||||||
// - can_take_corner_by_effect
|
.check_opponent_can_fill_quarter_rule(&(first_move, EMPTY_MOVE))
|
||||||
// - check_exit_rules
|
.is_ok()
|
||||||
// - get_quarter_filling_moves_sequences
|
&& !(self.is_move_by_puissance(&(first_move, EMPTY_MOVE))
|
||||||
|
&& self.can_take_corner_by_effect())
|
||||||
|
&& (ignored_rules.contains(&TricTracRule::Exit)
|
||||||
|
|| self.check_exit_rules(&(first_move, EMPTY_MOVE)).is_ok())
|
||||||
|
&& (ignored_rules.contains(&TricTracRule::MustFillQuarter)
|
||||||
|
|| self
|
||||||
|
.check_must_fill_quarter_rule(&(first_move, EMPTY_MOVE))
|
||||||
|
.is_ok())
|
||||||
{
|
{
|
||||||
// empty move
|
// empty move
|
||||||
moves_seqs.push((first_move, EMPTY_MOVE));
|
moves_seqs.push((first_move, EMPTY_MOVE));
|
||||||
|
|
@ -1078,6 +1140,9 @@ mod tests {
|
||||||
CheckerMove::new(9, 11).unwrap(),
|
CheckerMove::new(9, 11).unwrap(),
|
||||||
CheckerMove::new(11, 14).unwrap(),
|
CheckerMove::new(11, 14).unwrap(),
|
||||||
);
|
);
|
||||||
assert_eq!(vec![moves], state.get_possible_moves_sequences(true));
|
assert_eq!(
|
||||||
|
vec![moves],
|
||||||
|
state.get_possible_moves_sequences(true, vec![])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -331,7 +331,7 @@ impl PointsRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jan qui ne peut : dés non jouables
|
// Jan qui ne peut : dés non jouables
|
||||||
let poss = self.move_rules.get_possible_moves_sequences(true);
|
let poss = self.move_rules.get_possible_moves_sequences(true, vec![]);
|
||||||
let moves = poss.iter().fold(vec![], |mut acc, (m1, m2)| {
|
let moves = poss.iter().fold(vec![], |mut acc, (m1, m2)| {
|
||||||
acc.push(*m1);
|
acc.push(*m1);
|
||||||
acc.push(*m2);
|
acc.push(*m2);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue