gemini refact
This commit is contained in:
parent
3e1775428d
commit
b5dd94fd3a
|
|
@ -361,35 +361,175 @@ impl MoveRules {
|
||||||
with_excedents: bool,
|
with_excedents: bool,
|
||||||
ignored_rules: Vec<TricTracRule>,
|
ignored_rules: Vec<TricTracRule>,
|
||||||
) -> Vec<(CheckerMove, CheckerMove)> {
|
) -> Vec<(CheckerMove, CheckerMove)> {
|
||||||
let (dice1, dice2) = self.dice.values;
|
// Etape 1: Générer tous les mouvements potentiels sans appliquer les règles complexes récursives.
|
||||||
let (dice_max, dice_min) = if dice1 > dice2 {
|
let mut potential_moves = self.generate_all_potential_moves(with_excedents);
|
||||||
(dice1, dice2)
|
|
||||||
} else {
|
// Etape 2: Appliquer les filtres pour les règles complexes de manière itérative.
|
||||||
(dice2, dice1)
|
|
||||||
};
|
// Règle: MustFillQuarter
|
||||||
let mut moves_seqs = self.get_possible_moves_sequences_by_dices(
|
if !ignored_rules.contains(&TricTracRule::MustFillQuarter) {
|
||||||
dice_max,
|
let filling_moves: Vec<_> = potential_moves
|
||||||
dice_min,
|
.iter()
|
||||||
with_excedents,
|
.filter(|moves| {
|
||||||
false,
|
let mut board = self.board.clone();
|
||||||
ignored_rules.clone(),
|
if board.move_checker(&Color::White, moves.0).is_ok()
|
||||||
);
|
&& board.move_checker(&Color::White, moves.1).is_ok()
|
||||||
// if we got valid sequences with the highest die, we don't accept sequences using only the
|
{
|
||||||
// lowest die
|
return board.any_quarter_filled(Color::White);
|
||||||
let ignore_empty = !moves_seqs.is_empty();
|
}
|
||||||
let mut moves_seqs_order2 = self.get_possible_moves_sequences_by_dices(
|
false
|
||||||
dice_min,
|
})
|
||||||
dice_max,
|
.cloned()
|
||||||
with_excedents,
|
.collect();
|
||||||
ignore_empty,
|
|
||||||
ignored_rules,
|
if !filling_moves.is_empty() {
|
||||||
);
|
potential_moves = filling_moves;
|
||||||
moves_seqs.append(&mut moves_seqs_order2);
|
}
|
||||||
let empty_removed = moves_seqs
|
}
|
||||||
|
|
||||||
|
// Règle: Règles de sortie (Exit)
|
||||||
|
if !ignored_rules.contains(&TricTracRule::Exit) {
|
||||||
|
// Filtrer les mouvements qui ne respectent pas les règles de base de sortie.
|
||||||
|
potential_moves.retain(|moves| self.check_exit_rules(moves).is_ok());
|
||||||
|
|
||||||
|
// Gérer ExitByEffectPossible: si un mouvement sans excédent est possible, les mouvements avec excédent sont interdits.
|
||||||
|
let non_excess_moves = self.generate_all_potential_moves(false);
|
||||||
|
if !non_excess_moves.is_empty() {
|
||||||
|
// Vérifier s'il existe des mouvements valides sans excédent
|
||||||
|
let has_valid_non_excess_move = non_excess_moves.iter().any(|moves| {
|
||||||
|
self.check_exit_rules(moves).is_ok()
|
||||||
|
&& self.check_corner_rules(moves).is_ok()
|
||||||
|
&& self.check_opponent_can_fill_quarter_rule(moves).is_ok()
|
||||||
|
});
|
||||||
|
|
||||||
|
if has_valid_non_excess_move {
|
||||||
|
potential_moves.retain(|moves| {
|
||||||
|
!self.is_exit_by_excess(moves, &non_excess_moves)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Règle: MustPlayAllDice
|
||||||
|
let has_two_dice_move = potential_moves
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(c1, c2)| *c1 != EMPTY_MOVE && *c2 != EMPTY_MOVE);
|
.any(|(m1, m2)| *m1 != EMPTY_MOVE && *m2 != EMPTY_MOVE);
|
||||||
if empty_removed.count() > 0 {
|
if has_two_dice_move {
|
||||||
moves_seqs.retain(|(c1, c2)| *c1 != EMPTY_MOVE && *c2 != EMPTY_MOVE);
|
potential_moves.retain(|(m1, m2)| *m1 != EMPTY_MOVE && *m2 != EMPTY_MOVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Règle: MustPlayStrongerDie
|
||||||
|
if !has_two_dice_move && !potential_moves.is_empty() {
|
||||||
|
let (dice1, dice2) = self.dice.values;
|
||||||
|
if dice1 != dice2 {
|
||||||
|
let stronger_die = cmp::max(dice1, dice2);
|
||||||
|
let uses_stronger_die = potential_moves.iter().any(|(m1, _)| {
|
||||||
|
if m1.get_from() == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let dist = (m1.get_to() as i8 - m1.get_from() as i8).unsigned_abs();
|
||||||
|
dist == stronger_die
|
||||||
|
});
|
||||||
|
if uses_stronger_die {
|
||||||
|
potential_moves.retain(|(m1, _)| {
|
||||||
|
if m1.get_from() == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let dist = (m1.get_to() as i8 - m1.get_from() as i8).unsigned_abs();
|
||||||
|
dist == stronger_die
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if potential_moves.is_empty() && with_excedents {
|
||||||
|
return vec![(EMPTY_MOVE, EMPTY_MOVE)];
|
||||||
|
}
|
||||||
|
|
||||||
|
potential_moves
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper pour `get_possible_moves_sequences`.
|
||||||
|
/// Détermine si un mouvement est une sortie "par effet" (avec excédent)
|
||||||
|
/// en vérifiant s'il n'existe pas dans la liste des mouvements sans excédent.
|
||||||
|
fn is_exit_by_excess(
|
||||||
|
&self,
|
||||||
|
moves: &(CheckerMove, CheckerMove),
|
||||||
|
non_excess_moves: &[(CheckerMove, CheckerMove)],
|
||||||
|
) -> bool {
|
||||||
|
if !moves.0.is_exit() && !moves.1.is_exit() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
!non_excess_moves.contains(moves)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Nouvelle fonction itérative pour générer les mouvements bruts.
|
||||||
|
fn generate_all_potential_moves(
|
||||||
|
&self,
|
||||||
|
with_excedents: bool,
|
||||||
|
) -> Vec<(CheckerMove, CheckerMove)> {
|
||||||
|
let mut moves_seqs = Vec::new();
|
||||||
|
let color = &Color::White;
|
||||||
|
let forbid_exits = self.has_checkers_outside_last_quarter();
|
||||||
|
let (dice1, dice2) = self.dice.values;
|
||||||
|
let dice_orders = if dice1 == dice2 {
|
||||||
|
vec![(dice1, dice2)]
|
||||||
|
} else {
|
||||||
|
vec![(dice1, dice2), (dice2, dice1)]
|
||||||
|
};
|
||||||
|
|
||||||
|
for (d1, d2) in dice_orders {
|
||||||
|
for first_move in
|
||||||
|
self.board
|
||||||
|
.get_possible_moves(*color, d1, with_excedents, false, forbid_exits)
|
||||||
|
{
|
||||||
|
let mut board2 = self.board.clone();
|
||||||
|
if board2.move_checker(color, first_move).is_err() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut has_second_dice_move = false;
|
||||||
|
for second_move in
|
||||||
|
board2.get_possible_moves(*color, d2, with_excedents, true, forbid_exits)
|
||||||
|
{
|
||||||
|
let current_moves = (first_move, second_move);
|
||||||
|
|
||||||
|
// Valider la séquence en la simulant sur un plateau vierge
|
||||||
|
let mut scratch_board = self.board.clone();
|
||||||
|
if scratch_board.move_checker(color, current_moves.0).is_ok()
|
||||||
|
&& scratch_board.move_checker(color, current_moves.1).is_ok()
|
||||||
|
{
|
||||||
|
// Si l'exécution est valide, appliquer les autres règles
|
||||||
|
if self.check_corner_rules(¤t_moves).is_ok()
|
||||||
|
&& self
|
||||||
|
.check_opponent_can_fill_quarter_rule(¤t_moves)
|
||||||
|
.is_ok()
|
||||||
|
&& !(self.is_move_by_puissance(¤t_moves)
|
||||||
|
&& self.can_take_corner_by_effect())
|
||||||
|
{
|
||||||
|
if !moves_seqs.contains(¤t_moves) {
|
||||||
|
moves_seqs.push(current_moves);
|
||||||
|
}
|
||||||
|
has_second_dice_move = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !has_second_dice_move {
|
||||||
|
let current_moves = (first_move, EMPTY_MOVE);
|
||||||
|
if self.check_corner_rules(¤t_moves).is_ok()
|
||||||
|
&& self
|
||||||
|
.check_opponent_can_fill_quarter_rule(¤t_moves)
|
||||||
|
.is_ok()
|
||||||
|
&& !(self.is_move_by_puissance(¤t_moves)
|
||||||
|
&& self.can_take_corner_by_effect())
|
||||||
|
{
|
||||||
|
if !moves_seqs.contains(¤t_moves) {
|
||||||
|
moves_seqs.push(current_moves);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
moves_seqs
|
moves_seqs
|
||||||
}
|
}
|
||||||
|
|
@ -447,14 +587,16 @@ 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;
|
||||||
let ignored_rules = vec![TricTracRule::Exit, TricTracRule::MustFillQuarter];
|
// Utilise la nouvelle méthode non-récursive
|
||||||
for moves in self.get_possible_moves_sequences(true, ignored_rules) {
|
let potential_moves = self.generate_all_potential_moves(true);
|
||||||
|
|
||||||
|
for moves in potential_moves {
|
||||||
let mut board = self.board.clone();
|
let mut board = self.board.clone();
|
||||||
board.move_checker(color, moves.0).unwrap();
|
// On ne peut pas juste unwrap, il faut gérer l'erreur
|
||||||
board.move_checker(color, moves.1).unwrap();
|
if board.move_checker(color, moves.0).is_ok() && board.move_checker(color, moves.1).is_ok() {
|
||||||
// println!("get_quarter_filling_moves_sequences board : {:?}", board);
|
if board.any_quarter_filled(*color) && !moves_seqs.contains(&moves) {
|
||||||
if board.any_quarter_filled(*color) && !moves_seqs.contains(&moves) {
|
moves_seqs.push(moves);
|
||||||
moves_seqs.push(moves);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
moves_seqs
|
moves_seqs
|
||||||
|
|
@ -468,64 +610,10 @@ impl MoveRules {
|
||||||
ignore_empty: bool,
|
ignore_empty: bool,
|
||||||
ignored_rules: Vec<TricTracRule>,
|
ignored_rules: Vec<TricTracRule>,
|
||||||
) -> Vec<(CheckerMove, CheckerMove)> {
|
) -> Vec<(CheckerMove, CheckerMove)> {
|
||||||
let mut moves_seqs = Vec::new();
|
// NOTE: Cette fonction est maintenant obsolète et remplacée par la logique dans get_possible_moves_sequences.
|
||||||
let color = &Color::White;
|
// On la garde pour la compatibilité mais elle devrait être enlevée à terme.
|
||||||
let forbid_exits = self.has_checkers_outside_last_quarter();
|
// Pour l'instant, on délègue à la nouvelle implémentation.
|
||||||
for first_move in
|
self.get_possible_moves_sequences(with_excedents, ignored_rules)
|
||||||
self.board
|
|
||||||
.get_possible_moves(*color, dice1, with_excedents, false, forbid_exits)
|
|
||||||
{
|
|
||||||
let mut board2 = self.board.clone();
|
|
||||||
if board2.move_checker(color, first_move).is_err() {
|
|
||||||
println!("err move");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX : the goal here is to replicate moves_allowed() checks without using get_possible_moves_sequences to
|
|
||||||
// avoid an infinite loop...
|
|
||||||
let mut has_second_dice_move = false;
|
|
||||||
for second_move in
|
|
||||||
board2.get_possible_moves(*color, dice2, with_excedents, true, forbid_exits)
|
|
||||||
{
|
|
||||||
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.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));
|
|
||||||
has_second_dice_move = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !has_second_dice_move
|
|
||||||
&& with_excedents
|
|
||||||
&& !ignore_empty
|
|
||||||
&& self.check_corner_rules(&(first_move, EMPTY_MOVE)).is_ok()
|
|
||||||
&& self
|
|
||||||
.check_opponent_can_fill_quarter_rule(&(first_move, EMPTY_MOVE))
|
|
||||||
.is_ok()
|
|
||||||
&& !(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
|
|
||||||
moves_seqs.push((first_move, EMPTY_MOVE));
|
|
||||||
}
|
|
||||||
//if board2.get_color_fields(*color).is_empty() {
|
|
||||||
}
|
|
||||||
moves_seqs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _get_direct_exit_moves(&self, state: &GameState) -> Vec<CheckerMove> {
|
fn _get_direct_exit_moves(&self, state: &GameState) -> Vec<CheckerMove> {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue