wip debug get_valid_actions for black
This commit is contained in:
parent
65180d8164
commit
817dbd77a7
10 changed files with 200 additions and 41 deletions
|
|
@ -114,7 +114,7 @@ impl Environment for TrictracEnvironment {
|
||||||
let player2_id = 2;
|
let player2_id = 2;
|
||||||
|
|
||||||
// Commencer la partie
|
// Commencer la partie
|
||||||
game.consume(&GameEvent::BeginGame { goes_first: 1 });
|
let _ = game.consume(&GameEvent::BeginGame { goes_first: 1 });
|
||||||
|
|
||||||
let current_state = TrictracState::from_game_state(&game);
|
let current_state = TrictracState::from_game_state(&game);
|
||||||
TrictracEnvironment {
|
TrictracEnvironment {
|
||||||
|
|
@ -145,7 +145,7 @@ impl Environment for TrictracEnvironment {
|
||||||
self.game.init_player("Opponent");
|
self.game.init_player("Opponent");
|
||||||
|
|
||||||
// Commencer la partie
|
// Commencer la partie
|
||||||
self.game.consume(&GameEvent::BeginGame { goes_first: 1 });
|
let _ = self.game.consume(&GameEvent::BeginGame { goes_first: 1 });
|
||||||
|
|
||||||
self.current_state = TrictracState::from_game_state(&self.game);
|
self.current_state = TrictracState::from_game_state(&self.game);
|
||||||
self.episode_reward = 0.0;
|
self.episode_reward = 0.0;
|
||||||
|
|
@ -282,7 +282,7 @@ impl TrictracEnvironment {
|
||||||
// Appliquer l'événement si valide
|
// Appliquer l'événement si valide
|
||||||
if let Some(event) = action.to_event(&self.game) {
|
if let Some(event) = action.to_event(&self.game) {
|
||||||
if self.game.validate(&event) {
|
if self.game.validate(&event) {
|
||||||
self.game.consume(&event);
|
let _ = self.game.consume(&event);
|
||||||
// reward += REWARD_VALID_MOVE;
|
// reward += REWARD_VALID_MOVE;
|
||||||
// Simuler le résultat des dés après un Roll
|
// Simuler le résultat des dés après un Roll
|
||||||
if matches!(action, TrictracAction::Roll) {
|
if matches!(action, TrictracAction::Roll) {
|
||||||
|
|
@ -295,7 +295,7 @@ impl TrictracEnvironment {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if self.game.validate(&dice_event) {
|
if self.game.validate(&dice_event) {
|
||||||
self.game.consume(&dice_event);
|
let _ = self.game.consume(&dice_event);
|
||||||
let (points, adv_points) = self.game.dice_points;
|
let (points, adv_points) = self.game.dice_points;
|
||||||
reward += REWARD_RATIO * (points as f32 - adv_points as f32);
|
reward += REWARD_RATIO * (points as f32 - adv_points as f32);
|
||||||
if points > 0 {
|
if points > 0 {
|
||||||
|
|
@ -397,7 +397,7 @@ impl TrictracEnvironment {
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.game.validate(&event) {
|
if self.game.validate(&event) {
|
||||||
self.game.consume(&event);
|
let _ = self.game.consume(&event);
|
||||||
if calculate_points {
|
if calculate_points {
|
||||||
let dice_roll_count = self
|
let dice_roll_count = self
|
||||||
.game
|
.game
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ impl Environment for TrictracEnvironment {
|
||||||
let player2_id = 2;
|
let player2_id = 2;
|
||||||
|
|
||||||
// Commencer la partie
|
// Commencer la partie
|
||||||
game.consume(&GameEvent::BeginGame { goes_first: 1 });
|
let _ = game.consume(&GameEvent::BeginGame { goes_first: 1 });
|
||||||
|
|
||||||
let current_state = TrictracState::from_game_state(&game);
|
let current_state = TrictracState::from_game_state(&game);
|
||||||
TrictracEnvironment {
|
TrictracEnvironment {
|
||||||
|
|
@ -136,7 +136,7 @@ impl Environment for TrictracEnvironment {
|
||||||
self.game.init_player("Opponent");
|
self.game.init_player("Opponent");
|
||||||
|
|
||||||
// Commencer la partie
|
// Commencer la partie
|
||||||
self.game.consume(&GameEvent::BeginGame { goes_first: 1 });
|
let _ = self.game.consume(&GameEvent::BeginGame { goes_first: 1 });
|
||||||
|
|
||||||
self.current_state = TrictracState::from_game_state(&self.game);
|
self.current_state = TrictracState::from_game_state(&self.game);
|
||||||
self.episode_reward = 0.0;
|
self.episode_reward = 0.0;
|
||||||
|
|
@ -252,7 +252,7 @@ impl TrictracEnvironment {
|
||||||
// Appliquer l'événement si valide
|
// Appliquer l'événement si valide
|
||||||
if let Some(event) = action.to_event(&self.game) {
|
if let Some(event) = action.to_event(&self.game) {
|
||||||
if self.game.validate(&event) {
|
if self.game.validate(&event) {
|
||||||
self.game.consume(&event);
|
let _ = self.game.consume(&event);
|
||||||
// reward += REWARD_VALID_MOVE;
|
// reward += REWARD_VALID_MOVE;
|
||||||
// Simuler le résultat des dés après un Roll
|
// Simuler le résultat des dés après un Roll
|
||||||
if matches!(action, TrictracAction::Roll) {
|
if matches!(action, TrictracAction::Roll) {
|
||||||
|
|
@ -265,7 +265,7 @@ impl TrictracEnvironment {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if self.game.validate(&dice_event) {
|
if self.game.validate(&dice_event) {
|
||||||
self.game.consume(&dice_event);
|
let _ = self.game.consume(&dice_event);
|
||||||
let (points, adv_points) = self.game.dice_points;
|
let (points, adv_points) = self.game.dice_points;
|
||||||
reward += REWARD_RATIO * (points as f32 - adv_points as f32);
|
reward += REWARD_RATIO * (points as f32 - adv_points as f32);
|
||||||
if points > 0 {
|
if points > 0 {
|
||||||
|
|
@ -367,7 +367,7 @@ impl TrictracEnvironment {
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.game.validate(&event) {
|
if self.game.validate(&event) {
|
||||||
self.game.consume(&event);
|
let _ = self.game.consume(&event);
|
||||||
if calculate_points {
|
if calculate_points {
|
||||||
let dice_roll_count = self
|
let dice_roll_count = self
|
||||||
.game
|
.game
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ impl Bot {
|
||||||
|
|
||||||
let init_player_points = game.who_plays().map(|p| (p.points, p.holes));
|
let init_player_points = game.who_plays().map(|p| (p.points, p.holes));
|
||||||
let turn_stage = game.turn_stage;
|
let turn_stage = game.turn_stage;
|
||||||
game.consume(internal_event);
|
let _ = game.consume(internal_event);
|
||||||
if game.stage == Stage::Ended {
|
if game.stage == Stage::Ended {
|
||||||
debug!("<<<< end {:?} BOT handle", self.color);
|
debug!("<<<< end {:?} BOT handle", self.color);
|
||||||
return None;
|
return None;
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ impl BoardGameBoard for TrictracBoard {
|
||||||
fn play(&mut self, mv: Self::Move) -> Result<(), PlayError> {
|
fn play(&mut self, mv: Self::Move) -> Result<(), PlayError> {
|
||||||
self.check_can_play(mv)?;
|
self.check_can_play(mv)?;
|
||||||
if let Some(evt) = mv.to_event(&self.0) {
|
if let Some(evt) = mv.to_event(&self.0) {
|
||||||
self.0.consume(&evt);
|
let _ = self.0.consume(&evt);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(PlayError::UnavailableMove)
|
Err(PlayError::UnavailableMove)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use trictrac_bot::{Bot, BotStrategy};
|
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
|
use trictrac_bot::{Bot, BotStrategy};
|
||||||
use trictrac_store::{CheckerMove, DiceRoller, GameEvent, GameState, PlayerId, TurnStage};
|
use trictrac_store::{CheckerMove, DiceRoller, GameEvent, GameState, PlayerId, TurnStage};
|
||||||
|
|
||||||
// Application Game
|
// Application Game
|
||||||
|
|
@ -67,7 +67,7 @@ impl GameRunner {
|
||||||
"--------------- new valid event {event:?} (stage {:?}) -----------",
|
"--------------- new valid event {event:?} (stage {:?}) -----------",
|
||||||
self.state.turn_stage
|
self.state.turn_stage
|
||||||
);
|
);
|
||||||
self.state.consume(event);
|
let _ = self.state.consume(event).inspect_err(|e| error!("{}", e));
|
||||||
debug!(
|
debug!(
|
||||||
" --> stage {:?} ; active player points {:?}",
|
" --> stage {:?} ; active player points {:?}",
|
||||||
self.state.turn_stage,
|
self.state.turn_stage,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use std::fmt;
|
||||||
pub type Field = usize;
|
pub type Field = usize;
|
||||||
pub type FieldWithCount = (Field, i8);
|
pub type FieldWithCount = (Field, i8);
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Serialize, PartialEq, Eq, Deserialize)]
|
#[derive(Debug, Copy, Clone, Serialize, PartialEq, Eq, Deserialize, Hash)]
|
||||||
pub struct CheckerMove {
|
pub struct CheckerMove {
|
||||||
from: Field,
|
from: Field,
|
||||||
to: Field,
|
to: Field,
|
||||||
|
|
@ -439,6 +439,7 @@ impl Board {
|
||||||
check_rest_corner_exit: bool,
|
check_rest_corner_exit: bool,
|
||||||
forbid_exits: bool,
|
forbid_exits: bool,
|
||||||
) -> Vec<CheckerMove> {
|
) -> Vec<CheckerMove> {
|
||||||
|
// println!("------- board.get_possible_moves...");
|
||||||
let mut moves = Vec::new();
|
let mut moves = Vec::new();
|
||||||
|
|
||||||
let get_dest = |from| {
|
let get_dest = |from| {
|
||||||
|
|
@ -453,6 +454,7 @@ impl Board {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut farthest_exit_move = 25;
|
||||||
for (field, count) in self.get_color_fields(color) {
|
for (field, count) in self.get_color_fields(color) {
|
||||||
// check rest corner exit
|
// check rest corner exit
|
||||||
if field == self.get_color_corner(&color) && count == 2 && check_rest_corner_exit {
|
if field == self.get_color_corner(&color) && count == 2 && check_rest_corner_exit {
|
||||||
|
|
@ -463,8 +465,11 @@ impl Board {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if !(0..25).contains(&dest) {
|
if !(0..25).contains(&dest) {
|
||||||
|
// if with_excedants && !forbid_exits && field < farthest_exit_move && 2 < count {
|
||||||
if with_excedants && !forbid_exits {
|
if with_excedants && !forbid_exits {
|
||||||
dest = 0;
|
dest = 0;
|
||||||
|
farthest_exit_move = field;
|
||||||
|
// println!("farthest is now {farthest_exit_move}");
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -834,4 +839,27 @@ mod tests {
|
||||||
assert_eq!(4, board.get_field_checker(&Color::White, 2));
|
assert_eq!(4, board.get_field_checker(&Color::White, 2));
|
||||||
assert_eq!(6, board.get_field_checker(&Color::White, 3));
|
assert_eq!(6, board.get_field_checker(&Color::White, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_possible_moves() {
|
||||||
|
let mut board = Board::new();
|
||||||
|
board.set_positions(
|
||||||
|
&Color::White,
|
||||||
|
[
|
||||||
|
-8, -3, -1, -1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let moves = vec![
|
||||||
|
CheckerMove::new(19, 22).unwrap(),
|
||||||
|
CheckerMove::new(20, 23).unwrap(),
|
||||||
|
CheckerMove::new(21, 24).unwrap(),
|
||||||
|
CheckerMove::new(22, 0).unwrap(),
|
||||||
|
CheckerMove::new(23, 0).unwrap(),
|
||||||
|
CheckerMove::new(24, 0).unwrap(),
|
||||||
|
];
|
||||||
|
assert_eq!(
|
||||||
|
moves,
|
||||||
|
board.get_possible_moves(Color::White, 3, true, true, false,)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use log::{debug, error};
|
||||||
|
|
||||||
// use itertools::Itertools;
|
// use itertools::Itertools;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashMap;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::{fmt, str};
|
use std::{fmt, str};
|
||||||
|
|
||||||
|
|
@ -140,7 +140,9 @@ impl GameState {
|
||||||
let mut game = Self::default();
|
let mut game = Self::default();
|
||||||
if let Some(p1) = game.init_player(p1_name) {
|
if let Some(p1) = game.init_player(p1_name) {
|
||||||
game.init_player(p2_name);
|
game.init_player(p2_name);
|
||||||
game.consume(&GameEvent::BeginGame { goes_first: p1 });
|
let _ = game
|
||||||
|
.consume(&GameEvent::BeginGame { goes_first: p1 })
|
||||||
|
.inspect_err(|e| error!("{}", e));
|
||||||
}
|
}
|
||||||
game
|
game
|
||||||
}
|
}
|
||||||
|
|
@ -327,7 +329,7 @@ impl GameState {
|
||||||
let mut bit_count: u8 = 0;
|
let mut bit_count: u8 = 0;
|
||||||
|
|
||||||
// helper to push a single bit
|
// helper to push a single bit
|
||||||
let mut push_bit = |bit: u8, output: &mut Vec<u8>, current: &mut u8, bit_count: &mut u8| {
|
let push_bit = |bit: u8, output: &mut Vec<u8>, current: &mut u8, bit_count: &mut u8| {
|
||||||
*current = (*current << 1) | (bit & 1);
|
*current = (*current << 1) | (bit & 1);
|
||||||
*bit_count += 1;
|
*bit_count += 1;
|
||||||
|
|
||||||
|
|
@ -339,7 +341,7 @@ impl GameState {
|
||||||
};
|
};
|
||||||
|
|
||||||
// helper to push a string of '0'/'1'
|
// helper to push a string of '0'/'1'
|
||||||
let mut push_bits_str =
|
let push_bits_str =
|
||||||
|bits: &str, output: &mut Vec<u8>, current: &mut u8, bit_count: &mut u8| {
|
|bits: &str, output: &mut Vec<u8>, current: &mut u8, bit_count: &mut u8| {
|
||||||
for b in bits.bytes() {
|
for b in bits.bytes() {
|
||||||
push_bit(b - b'0', output, current, bit_count);
|
push_bit(b - b'0', output, current, bit_count);
|
||||||
|
|
@ -1120,7 +1122,7 @@ mod tests {
|
||||||
let mut game_state = init_test_gamestate(TurnStage::MarkPoints);
|
let mut game_state = init_test_gamestate(TurnStage::MarkPoints);
|
||||||
game_state.schools_enabled = true;
|
game_state.schools_enabled = true;
|
||||||
let pid = game_state.active_player_id;
|
let pid = game_state.active_player_id;
|
||||||
game_state.consume(
|
let _ = game_state.consume(
|
||||||
&(GameEvent::Mark {
|
&(GameEvent::Mark {
|
||||||
player_id: pid,
|
player_id: pid,
|
||||||
points: 13,
|
points: 13,
|
||||||
|
|
@ -1132,7 +1134,7 @@ mod tests {
|
||||||
assert_eq!(game_state.turn_stage, TurnStage::HoldOrGoChoice);
|
assert_eq!(game_state.turn_stage, TurnStage::HoldOrGoChoice);
|
||||||
|
|
||||||
// Go
|
// Go
|
||||||
game_state.consume(
|
let _ = game_state.consume(
|
||||||
&(GameEvent::Go {
|
&(GameEvent::Go {
|
||||||
player_id: game_state.active_player_id,
|
player_id: game_state.active_player_id,
|
||||||
}),
|
}),
|
||||||
|
|
@ -1146,7 +1148,7 @@ mod tests {
|
||||||
let mut game_state = init_test_gamestate(TurnStage::MarkPoints);
|
let mut game_state = init_test_gamestate(TurnStage::MarkPoints);
|
||||||
game_state.schools_enabled = true;
|
game_state.schools_enabled = true;
|
||||||
let pid = game_state.active_player_id;
|
let pid = game_state.active_player_id;
|
||||||
game_state.consume(
|
let _ = game_state.consume(
|
||||||
&(GameEvent::Mark {
|
&(GameEvent::Mark {
|
||||||
player_id: pid,
|
player_id: pid,
|
||||||
points: 13,
|
points: 13,
|
||||||
|
|
@ -1156,7 +1158,7 @@ mod tests {
|
||||||
CheckerMove::new(1, 3).unwrap(),
|
CheckerMove::new(1, 3).unwrap(),
|
||||||
CheckerMove::new(1, 3).unwrap(),
|
CheckerMove::new(1, 3).unwrap(),
|
||||||
);
|
);
|
||||||
game_state.consume(
|
let _ = game_state.consume(
|
||||||
&(GameEvent::Move {
|
&(GameEvent::Move {
|
||||||
player_id: game_state.active_player_id,
|
player_id: game_state.active_player_id,
|
||||||
moves,
|
moves,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use crate::game::GameState;
|
||||||
use crate::player::Color;
|
use crate::player::Color;
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[derive(std::cmp::PartialEq, Debug)]
|
#[derive(std::cmp::PartialEq, Debug)]
|
||||||
pub enum MoveError {
|
pub enum MoveError {
|
||||||
|
|
@ -22,7 +23,7 @@ pub enum MoveError {
|
||||||
// sans nombre en excédant est possible
|
// sans nombre en excédant est possible
|
||||||
ExitByEffectPossible,
|
ExitByEffectPossible,
|
||||||
// Sortie avec nombre en excédant d'une dame qui n'est pas la plus éloignée
|
// Sortie avec nombre en excédant d'une dame qui n'est pas la plus éloignée
|
||||||
ExitNotFasthest,
|
ExitNotFarthest,
|
||||||
// Jeu dans un cadran que l'adversaire peut encore remplir
|
// Jeu dans un cadran que l'adversaire peut encore remplir
|
||||||
OpponentCanFillQuarter,
|
OpponentCanFillQuarter,
|
||||||
// remplir cadran si possible & conserver cadran rempli si possible ----
|
// remplir cadran si possible & conserver cadran rempli si possible ----
|
||||||
|
|
@ -348,6 +349,7 @@ impl MoveRules {
|
||||||
let board_to_check = if moves.0.get_to() == moves.1.get_from() {
|
let board_to_check = if moves.0.get_to() == moves.1.get_from() {
|
||||||
// Chained move: apply first move to get the board state
|
// Chained move: apply first move to get the board state
|
||||||
let mut board_copy = self.board.clone();
|
let mut board_copy = self.board.clone();
|
||||||
|
println!("mv 352");
|
||||||
let _ = board_copy.move_checker(&Color::White, moves.0);
|
let _ = board_copy.move_checker(&Color::White, moves.0);
|
||||||
board_copy
|
board_copy
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -355,7 +357,7 @@ impl MoveRules {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut checkers = board_to_check.get_color_fields(Color::White);
|
let mut checkers = board_to_check.get_color_fields(Color::White);
|
||||||
checkers.sort_by(|a, b| b.0.cmp(&a.0));
|
checkers.sort_by(|a, b| a.0.cmp(&b.0));
|
||||||
|
|
||||||
// Check if we have a filled quarter that must be preserved
|
// Check if we have a filled quarter that must be preserved
|
||||||
let has_filled_quarter = board_to_check.any_quarter_filled(Color::White);
|
let has_filled_quarter = board_to_check.any_quarter_filled(Color::White);
|
||||||
|
|
@ -367,7 +369,7 @@ impl MoveRules {
|
||||||
if has_filled_quarter {
|
if has_filled_quarter {
|
||||||
// When a quarter is filled, we can only exit from fields with >2 checkers
|
// When a quarter is filled, we can only exit from fields with >2 checkers
|
||||||
// Find the farthest field with >2 checkers (removing one won't break the quarter)
|
// Find the farthest field with >2 checkers (removing one won't break the quarter)
|
||||||
let mut available_checkers: Vec<_> =
|
let available_checkers: Vec<_> =
|
||||||
checkers.iter().filter(|(_, count)| *count > 2).collect();
|
checkers.iter().filter(|(_, count)| *count > 2).collect();
|
||||||
|
|
||||||
if !available_checkers.is_empty() {
|
if !available_checkers.is_empty() {
|
||||||
|
|
@ -413,7 +415,7 @@ impl MoveRules {
|
||||||
if moves.0.get_to() == 0 && moves.1.get_to() == 0 {
|
if moves.0.get_to() == 0 && moves.1.get_to() == 0 {
|
||||||
// Deux coups sortants en excédant
|
// Deux coups sortants en excédant
|
||||||
if cmp::max(moves.0.get_from(), moves.1.get_from()) > next_farthest {
|
if cmp::max(moves.0.get_from(), moves.1.get_from()) > next_farthest {
|
||||||
return Err(MoveError::ExitNotFasthest);
|
return Err(MoveError::ExitNotFarthest);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Un seul coup sortant en excédant le coup sortant doit concerner la plus éloignée du bord
|
// Un seul coup sortant en excédant le coup sortant doit concerner la plus éloignée du bord
|
||||||
|
|
@ -423,7 +425,7 @@ impl MoveRules {
|
||||||
moves.1.get_from()
|
moves.1.get_from()
|
||||||
};
|
};
|
||||||
if exit_move_field != farthest {
|
if exit_move_field != farthest {
|
||||||
return Err(MoveError::ExitNotFasthest);
|
return Err(MoveError::ExitNotFarthest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -465,6 +467,11 @@ impl MoveRules {
|
||||||
if empty_removed.count() > 0 {
|
if empty_removed.count() > 0 {
|
||||||
moves_seqs.retain(|(c1, c2)| *c1 != EMPTY_MOVE && *c2 != EMPTY_MOVE);
|
moves_seqs.retain(|(c1, c2)| *c1 != EMPTY_MOVE && *c2 != EMPTY_MOVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deduplicate
|
||||||
|
let mut set = HashSet::new();
|
||||||
|
moves_seqs.retain(|x| set.insert(*x));
|
||||||
|
|
||||||
moves_seqs
|
moves_seqs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -524,8 +531,11 @@ impl MoveRules {
|
||||||
let ignored_rules = vec![TricTracRule::Exit, TricTracRule::MustFillQuarter];
|
let ignored_rules = vec![TricTracRule::Exit, TricTracRule::MustFillQuarter];
|
||||||
for moves in self.get_possible_moves_sequences(true, ignored_rules) {
|
for moves in self.get_possible_moves_sequences(true, ignored_rules) {
|
||||||
let mut board = self.board.clone();
|
let mut board = self.board.clone();
|
||||||
|
println!("mv 534");
|
||||||
board.move_checker(color, moves.0).unwrap();
|
board.move_checker(color, moves.0).unwrap();
|
||||||
|
println!("mv 536 {:?} {:?}", self.board, moves);
|
||||||
board.move_checker(color, moves.1).unwrap();
|
board.move_checker(color, moves.1).unwrap();
|
||||||
|
println!("done 536");
|
||||||
// println!("get_quarter_filling_moves_sequences board : {:?}", board);
|
// 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);
|
||||||
|
|
@ -545,11 +555,13 @@ impl MoveRules {
|
||||||
let mut moves_seqs = Vec::new();
|
let mut moves_seqs = Vec::new();
|
||||||
let color = &Color::White;
|
let color = &Color::White;
|
||||||
let forbid_exits = self.has_checkers_outside_last_quarter();
|
let forbid_exits = self.has_checkers_outside_last_quarter();
|
||||||
|
// println!("==== First");
|
||||||
for first_move in
|
for first_move in
|
||||||
self.board
|
self.board
|
||||||
.get_possible_moves(*color, dice1, with_excedents, false, forbid_exits)
|
.get_possible_moves(*color, dice1, with_excedents, false, forbid_exits)
|
||||||
{
|
{
|
||||||
let mut board2 = self.board.clone();
|
let mut board2 = self.board.clone();
|
||||||
|
println!("mv 560");
|
||||||
if board2.move_checker(color, first_move).is_err() {
|
if board2.move_checker(color, first_move).is_err() {
|
||||||
println!("err move");
|
println!("err move");
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -558,6 +570,7 @@ impl MoveRules {
|
||||||
// XXX : the goal here is to replicate moves_allowed() checks without using get_possible_moves_sequences to
|
// XXX : the goal here is to replicate moves_allowed() checks without using get_possible_moves_sequences to
|
||||||
// avoid an infinite loop...
|
// avoid an infinite loop...
|
||||||
let mut has_second_dice_move = false;
|
let mut has_second_dice_move = false;
|
||||||
|
// println!(" ==== Second");
|
||||||
for second_move in
|
for second_move in
|
||||||
board2.get_possible_moves(*color, dice2, with_excedents, true, forbid_exits)
|
board2.get_possible_moves(*color, dice2, with_excedents, true, forbid_exits)
|
||||||
{
|
{
|
||||||
|
|
@ -572,9 +585,22 @@ impl MoveRules {
|
||||||
&& (ignored_rules.contains(&TricTracRule::MustFillQuarter)
|
&& (ignored_rules.contains(&TricTracRule::MustFillQuarter)
|
||||||
|| self
|
|| self
|
||||||
.check_must_fill_quarter_rule(&(first_move, second_move))
|
.check_must_fill_quarter_rule(&(first_move, second_move))
|
||||||
|
// .inspect_err(|e| {
|
||||||
|
// println!(
|
||||||
|
// " 2nd (must fill quar): {:?} - {:?}, {:?}",
|
||||||
|
// e, first_move, second_move
|
||||||
|
// )
|
||||||
|
// })
|
||||||
.is_ok())
|
.is_ok())
|
||||||
{
|
{
|
||||||
moves_seqs.push((first_move, second_move));
|
if second_move.get_to() == 0
|
||||||
|
&& first_move.get_to() == 0
|
||||||
|
&& second_move.get_from() < first_move.get_from()
|
||||||
|
{
|
||||||
|
moves_seqs.push((second_move, first_move));
|
||||||
|
} else {
|
||||||
|
moves_seqs.push((first_move, second_move));
|
||||||
|
}
|
||||||
has_second_dice_move = true;
|
has_second_dice_move = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -825,7 +851,7 @@ mod tests {
|
||||||
CheckerMove::new(20, 0).unwrap(),
|
CheckerMove::new(20, 0).unwrap(),
|
||||||
CheckerMove::new(23, 0).unwrap(),
|
CheckerMove::new(23, 0).unwrap(),
|
||||||
);
|
);
|
||||||
assert_eq!(Err(MoveError::ExitNotFasthest), state.moves_allowed(&moves));
|
assert_eq!(Err(MoveError::ExitNotFarthest), state.moves_allowed(&moves));
|
||||||
let moves = (
|
let moves = (
|
||||||
CheckerMove::new(20, 0).unwrap(),
|
CheckerMove::new(20, 0).unwrap(),
|
||||||
CheckerMove::new(21, 0).unwrap(),
|
CheckerMove::new(21, 0).unwrap(),
|
||||||
|
|
@ -1371,5 +1397,48 @@ mod tests {
|
||||||
vec![moves],
|
vec![moves],
|
||||||
state.get_possible_moves_sequences(true, vec![])
|
state.get_possible_moves_sequences(true, vec![])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
state.dice.values = (5, 3);
|
||||||
|
state.board.set_positions(
|
||||||
|
&crate::Color::White,
|
||||||
|
[
|
||||||
|
-8, -3, -1, -1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let moves = (
|
||||||
|
CheckerMove::new(23, 0).unwrap(),
|
||||||
|
CheckerMove::new(24, 0).unwrap(),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec![moves],
|
||||||
|
state.get_possible_moves_sequences(true, vec![])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_possible_moves_sequences_by_dices() {
|
||||||
|
let mut state = MoveRules::default();
|
||||||
|
|
||||||
|
state.dice.values = (5, 3);
|
||||||
|
state.board.set_positions(
|
||||||
|
&crate::Color::White,
|
||||||
|
[
|
||||||
|
-8, -3, -1, -1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let moves = (
|
||||||
|
CheckerMove::new(23, 0).unwrap(),
|
||||||
|
CheckerMove::new(24, 0).unwrap(),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec![moves],
|
||||||
|
state.get_possible_moves_sequences_by_dices(
|
||||||
|
state.dice.values.0,
|
||||||
|
state.dice.values.1,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
vec![]
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ impl TricTrac {
|
||||||
game_state.init_player("player2");
|
game_state.init_player("player2");
|
||||||
|
|
||||||
// Commencer la partie avec le joueur 1
|
// Commencer la partie avec le joueur 1
|
||||||
game_state.consume(&GameEvent::BeginGame { goes_first: 1 });
|
let _ = game_state.consume(&GameEvent::BeginGame { goes_first: 1 });
|
||||||
|
|
||||||
TricTrac { game_state }
|
TricTrac { game_state }
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +69,8 @@ impl TricTrac {
|
||||||
}
|
}
|
||||||
|
|
||||||
let dice = Dice { values: dices };
|
let dice = Dice { values: dices };
|
||||||
self.game_state
|
let _ = self
|
||||||
|
.game_state
|
||||||
.consume(&GameEvent::RollResult { player_id, dice });
|
.consume(&GameEvent::RollResult { player_id, dice });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +87,7 @@ impl TricTrac {
|
||||||
.map(|e| if needs_mirror { e.get_mirror(false) } else { e })
|
.map(|e| if needs_mirror { e.get_mirror(false) } else { e })
|
||||||
}) {
|
}) {
|
||||||
if self.game_state.validate(&event) {
|
if self.game_state.validate(&event) {
|
||||||
self.game_state.consume(&event);
|
let _ = self.game_state.consume(&event);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
return Err(pyo3::exceptions::PyRuntimeError::new_err(
|
return Err(pyo3::exceptions::PyRuntimeError::new_err(
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,7 @@ impl TrictracAction {
|
||||||
let checker_move1 = CheckerMove::new(from1, to1).unwrap_or_default();
|
let checker_move1 = CheckerMove::new(from1, to1).unwrap_or_default();
|
||||||
|
|
||||||
let mut tmp_board = state.board.clone();
|
let mut tmp_board = state.board.clone();
|
||||||
|
println!("mv training_common 127");
|
||||||
let move_result = tmp_board.move_checker(color, checker_move1);
|
let move_result = tmp_board.move_checker(color, checker_move1);
|
||||||
if move_result.is_err() {
|
if move_result.is_err() {
|
||||||
None
|
None
|
||||||
|
|
@ -262,14 +263,14 @@ fn checker_moves_to_trictrac_action(
|
||||||
|
|
||||||
if color == &crate::Color::Black {
|
if color == &crate::Color::Black {
|
||||||
white_checker_moves_to_trictrac_action(
|
white_checker_moves_to_trictrac_action(
|
||||||
move1,
|
// move1,
|
||||||
move2,
|
// move2,
|
||||||
// &move1.clone().mirror(),
|
&move1.clone().mirror(),
|
||||||
// &move2.clone().mirror(),
|
&move2.clone().mirror(),
|
||||||
dice,
|
dice,
|
||||||
&board.clone().mirror(),
|
&board.clone().mirror(),
|
||||||
)
|
)
|
||||||
.map(|a| a.mirror())
|
// .map(|a| a.mirror())
|
||||||
} else {
|
} else {
|
||||||
white_checker_moves_to_trictrac_action(move1, move2, dice, board)
|
white_checker_moves_to_trictrac_action(move1, move2, dice, board)
|
||||||
}
|
}
|
||||||
|
|
@ -323,8 +324,10 @@ fn white_checker_moves_to_trictrac_action(
|
||||||
let checker1 = board.get_field_checker(&crate::Color::White, from1) as usize;
|
let checker1 = board.get_field_checker(&crate::Color::White, from1) as usize;
|
||||||
let mut tmp_board = board.clone();
|
let mut tmp_board = board.clone();
|
||||||
// should not raise an error for a valid action
|
// should not raise an error for a valid action
|
||||||
|
println!("mv training_common 327");
|
||||||
tmp_board.move_checker(&crate::Color::White, *move1)?;
|
tmp_board.move_checker(&crate::Color::White, *move1)?;
|
||||||
let checker2 = tmp_board.get_field_checker(&crate::Color::White, from2) as usize;
|
let checker2 = tmp_board.get_field_checker(&crate::Color::White, from2) as usize;
|
||||||
|
println!("white action {checker1} {checker2}");
|
||||||
Ok(TrictracAction::Move {
|
Ok(TrictracAction::Move {
|
||||||
dice_order,
|
dice_order,
|
||||||
checker1,
|
checker1,
|
||||||
|
|
@ -379,7 +382,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_valid_actions_fillquarter() {
|
fn get_valid_actions() {
|
||||||
let mut state = GameState::new_with_players("white", "black");
|
let mut state = GameState::new_with_players("white", "black");
|
||||||
state.active_player_id = 2;
|
state.active_player_id = 2;
|
||||||
state.dice = Dice { values: (5, 3) };
|
state.dice = Dice { values: (5, 3) };
|
||||||
|
|
@ -394,8 +397,64 @@ mod tests {
|
||||||
let actions = vec![TrictracAction::Move {
|
let actions = vec![TrictracAction::Move {
|
||||||
dice_order: true,
|
dice_order: true,
|
||||||
checker1: 11,
|
checker1: 11,
|
||||||
checker2: 14,
|
checker2: 13,
|
||||||
}];
|
}];
|
||||||
assert_eq!(Some(actions), get_valid_actions(&state).ok());
|
assert_eq!(Some(actions), super::get_valid_actions(&state).ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn checker_moves_to_trictrac_action() {
|
||||||
|
let mut state = GameState::new_with_players("white", "black");
|
||||||
|
state.turn_stage = crate::TurnStage::Move;
|
||||||
|
state.dice = Dice { values: (5, 3) };
|
||||||
|
|
||||||
|
// White player
|
||||||
|
state.active_player_id = 1;
|
||||||
|
state.board.set_positions(
|
||||||
|
&crate::Color::White,
|
||||||
|
[
|
||||||
|
-8, -3, -1, -1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let ttaction = super::checker_moves_to_trictrac_action(
|
||||||
|
&CheckerMove::new(23, 0).unwrap(),
|
||||||
|
&CheckerMove::new(24, 0).unwrap(),
|
||||||
|
&crate::Color::White,
|
||||||
|
&state,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Some(TrictracAction::Move {
|
||||||
|
dice_order: true,
|
||||||
|
checker1: 11,
|
||||||
|
checker2: 13, // because the 11th has left
|
||||||
|
}),
|
||||||
|
ttaction.ok()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Black player
|
||||||
|
state.active_player_id = 2;
|
||||||
|
state.board.set_positions(
|
||||||
|
&crate::Color::White,
|
||||||
|
[
|
||||||
|
-3, -3, -2, -2, -2, -2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 3, 8,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let ttaction = super::checker_moves_to_trictrac_action(
|
||||||
|
&CheckerMove::new(2, 0).unwrap(),
|
||||||
|
&CheckerMove::new(1, 0).unwrap(),
|
||||||
|
&crate::Color::Black,
|
||||||
|
&state,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Some(TrictracAction::Move {
|
||||||
|
dice_order: true,
|
||||||
|
checker1: 11,
|
||||||
|
checker2: 13, // because the 11th has left
|
||||||
|
}),
|
||||||
|
ttaction.ok()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue