gemini refact
This commit is contained in:
parent
3e1775428d
commit
b5dd94fd3a
|
|
@ -361,35 +361,175 @@ impl MoveRules {
|
|||
with_excedents: bool,
|
||||
ignored_rules: Vec<TricTracRule>,
|
||||
) -> Vec<(CheckerMove, CheckerMove)> {
|
||||
let (dice1, dice2) = self.dice.values;
|
||||
let (dice_max, dice_min) = if dice1 > dice2 {
|
||||
(dice1, dice2)
|
||||
} else {
|
||||
(dice2, dice1)
|
||||
};
|
||||
let mut moves_seqs = self.get_possible_moves_sequences_by_dices(
|
||||
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
|
||||
// lowest die
|
||||
let ignore_empty = !moves_seqs.is_empty();
|
||||
let mut moves_seqs_order2 = self.get_possible_moves_sequences_by_dices(
|
||||
dice_min,
|
||||
dice_max,
|
||||
with_excedents,
|
||||
ignore_empty,
|
||||
ignored_rules,
|
||||
);
|
||||
moves_seqs.append(&mut moves_seqs_order2);
|
||||
let empty_removed = moves_seqs
|
||||
// Etape 1: Générer tous les mouvements potentiels sans appliquer les règles complexes récursives.
|
||||
let mut potential_moves = self.generate_all_potential_moves(with_excedents);
|
||||
|
||||
// Etape 2: Appliquer les filtres pour les règles complexes de manière itérative.
|
||||
|
||||
// Règle: MustFillQuarter
|
||||
if !ignored_rules.contains(&TricTracRule::MustFillQuarter) {
|
||||
let filling_moves: Vec<_> = potential_moves
|
||||
.iter()
|
||||
.filter(|(c1, c2)| *c1 != EMPTY_MOVE && *c2 != EMPTY_MOVE);
|
||||
if empty_removed.count() > 0 {
|
||||
moves_seqs.retain(|(c1, c2)| *c1 != EMPTY_MOVE && *c2 != EMPTY_MOVE);
|
||||
.filter(|moves| {
|
||||
let mut board = self.board.clone();
|
||||
if board.move_checker(&Color::White, moves.0).is_ok()
|
||||
&& board.move_checker(&Color::White, moves.1).is_ok()
|
||||
{
|
||||
return board.any_quarter_filled(Color::White);
|
||||
}
|
||||
false
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
if !filling_moves.is_empty() {
|
||||
potential_moves = filling_moves;
|
||||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
.any(|(m1, m2)| *m1 != EMPTY_MOVE && *m2 != EMPTY_MOVE);
|
||||
if has_two_dice_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
|
||||
}
|
||||
|
|
@ -447,16 +587,18 @@ impl MoveRules {
|
|||
pub fn get_quarter_filling_moves_sequences(&self) -> Vec<(CheckerMove, CheckerMove)> {
|
||||
let mut moves_seqs = Vec::new();
|
||||
let color = &Color::White;
|
||||
let ignored_rules = vec![TricTracRule::Exit, TricTracRule::MustFillQuarter];
|
||||
for moves in self.get_possible_moves_sequences(true, ignored_rules) {
|
||||
// Utilise la nouvelle méthode non-récursive
|
||||
let potential_moves = self.generate_all_potential_moves(true);
|
||||
|
||||
for moves in potential_moves {
|
||||
let mut board = self.board.clone();
|
||||
board.move_checker(color, moves.0).unwrap();
|
||||
board.move_checker(color, moves.1).unwrap();
|
||||
// println!("get_quarter_filling_moves_sequences board : {:?}", board);
|
||||
// On ne peut pas juste unwrap, il faut gérer l'erreur
|
||||
if board.move_checker(color, moves.0).is_ok() && board.move_checker(color, moves.1).is_ok() {
|
||||
if board.any_quarter_filled(*color) && !moves_seqs.contains(&moves) {
|
||||
moves_seqs.push(moves);
|
||||
}
|
||||
}
|
||||
}
|
||||
moves_seqs
|
||||
}
|
||||
|
||||
|
|
@ -468,64 +610,10 @@ impl MoveRules {
|
|||
ignore_empty: bool,
|
||||
ignored_rules: Vec<TricTracRule>,
|
||||
) -> Vec<(CheckerMove, CheckerMove)> {
|
||||
let mut moves_seqs = Vec::new();
|
||||
let color = &Color::White;
|
||||
let forbid_exits = self.has_checkers_outside_last_quarter();
|
||||
for first_move in
|
||||
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
|
||||
// NOTE: Cette fonction est maintenant obsolète et remplacée par la logique dans get_possible_moves_sequences.
|
||||
// On la garde pour la compatibilité mais elle devrait être enlevée à terme.
|
||||
// Pour l'instant, on délègue à la nouvelle implémentation.
|
||||
self.get_possible_moves_sequences(with_excedents, ignored_rules)
|
||||
}
|
||||
|
||||
fn _get_direct_exit_moves(&self, state: &GameState) -> Vec<CheckerMove> {
|
||||
|
|
|
|||
Loading…
Reference in a new issue