wip check jans

This commit is contained in:
Henri Bourcereau 2024-05-25 19:56:38 +02:00
parent b528fa3ac6
commit 0df394c0b1
6 changed files with 246 additions and 139 deletions

View file

@ -70,7 +70,8 @@ impl Bot {
}
fn calculate_points(&self) -> u8 {
self.game.get_points().iter().map(|r| r.0).sum()
// self.game.get_points().iter().map(|r| r.0).sum()
0
}
fn choose_move(&self) -> (CheckerMove, CheckerMove) {

View file

@ -509,10 +509,15 @@ impl Board {
return Ok(());
}
let checker_color = self.get_checkers_color(field)?;
// let checker_color = self.get_checkers_color(field)?;
let (count, checker_color) = self.get_field_checkers(field)?;
// error if the case contains the other color
if checker_color.is_some() && Some(color) != checker_color {
return Err(Error::FieldInvalid);
return if count > 1 {
Err(Error::FieldBlocked)
} else {
Err(Error::FieldBlockedByOne)
};
}
let unit = match color {
Color::White => 1,

View file

@ -14,6 +14,8 @@ pub enum Error {
PlayerInvalid,
/// Field blocked
FieldBlocked,
/// Field blocked
FieldBlockedByOne,
/// Invalid field
FieldInvalid,
/// Not your turn
@ -40,6 +42,7 @@ impl fmt::Display for Error {
Error::PlayerInvalid => write!(f, "Invalid player"),
Error::DoublingNotPermitted => write!(f, "Doubling not permitted"),
Error::FieldBlocked => write!(f, "Field blocked"),
Error::FieldBlockedByOne => write!(f, "Field blocked by one opponent"),
Error::FieldInvalid => write!(f, "Invalid field"),
Error::NotYourTurn => write!(f, "Not your turn"),
Error::MoveInvalid => write!(f, "Invalid move"),

View file

@ -60,15 +60,6 @@ impl fmt::Display for GameState {
}
}
impl PointsRules for GameState {
fn board(&self) -> &Board {
&self.board
}
fn dice(&self) -> &Dice {
&self.dice
}
}
impl Default for GameState {
fn default() -> Self {
Self {
@ -248,10 +239,15 @@ impl GameState {
}
// Check points are correct
let rules_points: u8 = self.get_points().iter().map(|r| r.0).sum();
if rules_points != *points {
return false;
}
// let (board, moves) = if *color == Color::Black {
// (board.mirror(), (moves.0.mirror(), moves.1.mirror()))
// } else {
// (board.clone(), *moves)
// };
// let rules_points: u8 = self.get_points().iter().map(|r| r.0).sum();
// if rules_points != *points {
// return false;
// }
}
Move { player_id, moves } => {
// Check player exists
@ -266,8 +262,13 @@ impl GameState {
}
let color = &self.players[player_id].color;
let rules = MoveRules::new(color, &self.board, self.dice, moves);
if !rules.moves_follow_rules() {
let rules = MoveRules::new(color, &self.board, self.dice);
let moves = if *color == Color::Black {
(moves.0.mirror(), moves.1.mirror())
} else {
*moves
};
if !rules.moves_follow_rules(&moves) {
return false;
}
}

View file

@ -36,60 +36,56 @@ pub enum MoveError {
pub struct MoveRules {
pub board: Board,
pub dice: Dice,
pub moves: (CheckerMove, CheckerMove),
}
impl MoveRules {
/// Revert board if color is black
pub fn new(
color: &Color,
board: &Board,
dice: Dice,
moves: &(CheckerMove, CheckerMove),
) -> Self {
let (board, moves) = if *color == Color::Black {
(board.mirror(), (moves.0.mirror(), moves.1.mirror()))
pub fn new(color: &Color, board: &Board, dice: Dice) -> Self {
let board = if *color == Color::Black {
board.mirror()
} else {
(board.clone(), *moves)
board.clone()
};
Self { board, dice, moves }
Self { board, dice }
}
pub fn moves_follow_rules(&self) -> bool {
pub fn moves_follow_rules(&self, moves: &(CheckerMove, CheckerMove)) -> bool {
// Check moves possibles on the board
// Check moves conforms to the dice
// Check move is allowed by the rules (to desactivate when playing with schools)
self.moves_possible() && self.moves_follows_dices() && self.moves_allowed().is_ok()
self.moves_possible(moves)
&& self.moves_follows_dices(moves)
&& self.moves_allowed(moves).is_ok()
}
/// ---- moves_possibles : First of three checks for moves
fn moves_possible(&self) -> bool {
fn moves_possible(&self, moves: &(CheckerMove, CheckerMove)) -> bool {
let color = &Color::White;
// Check move is physically possible
if !self.board.move_possible(color, &self.moves.0) {
if !self.board.move_possible(color, &moves.0) {
return false;
}
// Chained_move : "Tout d'une"
if let Ok(chained_move) = self.moves.0.chain(self.moves.1) {
if let Ok(chained_move) = moves.0.chain(moves.1) {
if !self.board.move_possible(color, &chained_move) {
return false;
}
} else if !self.board.move_possible(color, &self.moves.1) {
} else if !self.board.move_possible(color, &moves.1) {
return false;
}
true
}
/// ----- moves_follows_dices : Second of three checks for moves
fn moves_follows_dices(&self) -> bool {
fn moves_follows_dices(&self, moves: &(CheckerMove, CheckerMove)) -> bool {
// Prise de coin par puissance
if self.is_move_by_puissance() {
if self.is_move_by_puissance(moves) {
return true;
}
let (dice1, dice2) = self.dice.values;
let (move1, move2): &(CheckerMove, CheckerMove) = &self.moves;
let (move1, move2): &(CheckerMove, CheckerMove) = &moves;
let move1_dices = self.get_move_compatible_dices(move1);
if move1_dices.is_empty() {
@ -144,10 +140,10 @@ impl MoveRules {
}
/// ---- moves_allowed : Third of three checks for moves
fn moves_allowed(&self) -> Result<(), MoveError> {
self.check_corner_rules(&self.moves)?;
fn moves_allowed(&self, moves: &(CheckerMove, CheckerMove)) -> Result<(), MoveError> {
self.check_corner_rules(&moves)?;
if self.is_move_by_puissance() {
if self.is_move_by_puissance(moves) {
if self.can_take_corner_by_effect() {
return Err(MoveError::CornerByEffectPossible);
} else {
@ -157,17 +153,13 @@ impl MoveRules {
}
// Si possible, les deux dés doivent être joués
let (m1, m2) = self.moves;
if m1.get_from() == 0 || m2.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);
println!("{:?}", possible_moves_sequences);
possible_moves_sequences.retain(|moves| self.check_exit_rules(moves).is_ok());
// possible_moves_sequences.retain(|moves| self.check_corner_rules(moves).is_ok());
// TODO : exclure de ces possibilités celles qui devraient provoquer des CornerNeedsTwoCheckers & ExitNeedsAllCheckersOnLastQuarter...
if !possible_moves_sequences.contains(&self.moves)
&& !possible_moves_sequences.is_empty()
{
if self.moves == (EMPTY_MOVE, EMPTY_MOVE) {
if !possible_moves_sequences.contains(&moves) && !possible_moves_sequences.is_empty() {
if *moves == (EMPTY_MOVE, EMPTY_MOVE) {
return Err(MoveError::MustPlayAllDice);
}
let empty_removed = possible_moves_sequences
@ -181,10 +173,10 @@ impl MoveRules {
}
// check exit rules
self.check_exit_rules(&self.moves)?;
self.check_exit_rules(moves)?;
// --- interdit de jouer dans cadran que l'adversaire peut encore remplir ----
let farthest = cmp::max(self.moves.0.get_to(), self.moves.1.get_to());
let farthest = cmp::max(moves.0.get_to(), moves.1.get_to());
let in_opponent_side = farthest > 12;
if in_opponent_side && self.board.is_quarter_fillable(Color::Black, farthest) {
return Err(MoveError::OpponentCanFillQuarter);
@ -192,7 +184,7 @@ impl MoveRules {
// --- remplir cadran si possible & conserver cadran rempli si possible ----
let filling_moves_sequences = self.get_quarter_filling_moves_sequences();
if !filling_moves_sequences.contains(&self.moves) && !filling_moves_sequences.is_empty() {
if !filling_moves_sequences.contains(moves) && !filling_moves_sequences.is_empty() {
return Err(MoveError::MustFillQuarter);
}
// no rule was broken
@ -290,7 +282,7 @@ impl MoveRules {
Ok(())
}
fn get_possible_moves_sequences(
pub fn get_possible_moves_sequences(
&self,
with_excedents: bool,
) -> Vec<(CheckerMove, CheckerMove)> {
@ -321,7 +313,7 @@ impl MoveRules {
moves_seqs
}
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 color = &Color::White;
for moves in self.get_possible_moves_sequences(true) {
@ -414,11 +406,10 @@ impl MoveRules {
moves
}
fn is_move_by_puissance(&self) -> bool {
fn is_move_by_puissance(&self, moves: &(CheckerMove, CheckerMove)) -> bool {
let (dice1, dice2) = self.dice.values;
let (move1, move2): &(CheckerMove, CheckerMove) = &self.moves;
let dist1 = (move1.get_to() as i8 - move1.get_from() as i8).unsigned_abs();
let dist2 = (move2.get_to() as i8 - move2.get_from() as i8).unsigned_abs();
let dist1 = (moves.0.get_to() as i8 - moves.0.get_from() as i8).unsigned_abs();
let dist2 = (moves.1.get_to() as i8 - moves.1.get_from() as i8).unsigned_abs();
// Both corners must be empty
let (count1, _color) = self.board.get_field_checkers(12).unwrap();
@ -428,8 +419,8 @@ impl MoveRules {
}
let color = &Color::White;
move1.get_to() == move2.get_to()
&& move1.get_to() == self.board.get_color_corner(color)
moves.0.get_to() == moves.1.get_to()
&& moves.0.get_to() == self.board.get_color_corner(color)
&& (cmp::min(dist1, dist2) == cmp::min(dice1, dice2) - 1
&& cmp::max(dist1, dist2) == cmp::max(dice1, dice2) - 1)
}
@ -487,20 +478,20 @@ mod tests {
10, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15,
]);
state.dice.values = (5, 5);
state.moves = (
let moves = (
CheckerMove::new(8, 12).unwrap(),
CheckerMove::new(8, 12).unwrap(),
);
assert!(state.is_move_by_puissance());
assert!(state.moves_follows_dices());
assert!(state.moves_allowed().is_ok());
assert!(state.is_move_by_puissance(&moves));
assert!(state.moves_follows_dices(&moves));
assert!(state.moves_allowed(&moves).is_ok());
// opponent corner must be empty
state.board.set_positions([
10, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -13,
]);
assert!(!state.is_move_by_puissance());
assert!(!state.moves_follows_dices());
assert!(!state.is_move_by_puissance(&moves));
assert!(!state.moves_follows_dices(&moves));
// Si on a la possibilité de prendre son coin à la fois par effet, c'est à dire naturellement, et aussi par puissance, on doit le prendre par effet
state.board.set_positions([
@ -508,15 +499,15 @@ mod tests {
]);
assert_eq!(
Err(MoveError::CornerByEffectPossible),
state.moves_allowed()
state.moves_allowed(&moves)
);
// on a déjà pris son coin : on ne peux plus y deplacer des dames par puissance
state.board.set_positions([
8, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15,
]);
assert!(!state.is_move_by_puissance());
assert!(!state.moves_follows_dices());
assert!(!state.is_move_by_puissance(&moves));
assert!(!state.moves_follows_dices(&moves));
}
#[test]
@ -527,25 +518,25 @@ mod tests {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0,
]);
state.dice.values = (5, 5);
state.moves = (
let moves = (
CheckerMove::new(20, 0).unwrap(),
CheckerMove::new(20, 0).unwrap(),
);
assert!(state.moves_follows_dices());
assert!(state.moves_allowed().is_ok());
assert!(state.moves_follows_dices(&moves));
assert!(state.moves_allowed(&moves).is_ok());
// toutes les dames doivent être dans le jan de retour
state.board.set_positions([
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0,
]);
state.dice.values = (5, 5);
state.moves = (
let moves = (
CheckerMove::new(20, 0).unwrap(),
CheckerMove::new(20, 0).unwrap(),
);
assert_eq!(
Err(MoveError::ExitNeedsAllCheckersOnLastQuarter),
state.moves_allowed()
state.moves_allowed(&moves)
);
// on ne peut pas sortir une dame avec un nombre excédant si on peut en jouer une avec un nombre défaillant
@ -553,39 +544,42 @@ mod tests {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 2, 0,
]);
state.dice.values = (5, 5);
state.moves = (
let moves = (
CheckerMove::new(20, 0).unwrap(),
CheckerMove::new(23, 0).unwrap(),
);
assert_eq!(Err(MoveError::ExitByEffectPossible), state.moves_allowed());
assert_eq!(
Err(MoveError::ExitByEffectPossible),
state.moves_allowed(&moves)
);
// on doit jouer le nombre excédant le plus éloigné
state.board.set_positions([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0,
]);
state.dice.values = (5, 5);
state.moves = (
let moves = (
CheckerMove::new(20, 0).unwrap(),
CheckerMove::new(23, 0).unwrap(),
);
assert_eq!(Err(MoveError::ExitNotFasthest), state.moves_allowed());
state.moves = (
assert_eq!(Err(MoveError::ExitNotFasthest), state.moves_allowed(&moves));
let moves = (
CheckerMove::new(20, 0).unwrap(),
CheckerMove::new(21, 0).unwrap(),
);
assert!(state.moves_allowed().is_ok());
assert!(state.moves_allowed(&moves).is_ok());
// Cas de la dernière dame
state.board.set_positions([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
]);
state.dice.values = (5, 5);
state.moves = (
let moves = (
CheckerMove::new(23, 0).unwrap(),
CheckerMove::new(0, 0).unwrap(),
);
assert!(state.moves_follows_dices());
assert!(state.moves_allowed().is_ok());
assert!(state.moves_follows_dices(&moves));
assert!(state.moves_allowed(&moves).is_ok());
}
#[test]
@ -595,23 +589,23 @@ mod tests {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0,
]);
state.dice.values = (5, 5);
state.moves = (
let moves = (
CheckerMove::new(11, 16).unwrap(),
CheckerMove::new(11, 16).unwrap(),
);
assert!(state.moves_allowed().is_ok());
assert!(state.moves_allowed(&moves).is_ok());
state.board.set_positions([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, -12, 0, 0, 0, 0, 1, 0,
]);
state.dice.values = (5, 5);
state.moves = (
let moves = (
CheckerMove::new(11, 16).unwrap(),
CheckerMove::new(11, 16).unwrap(),
);
assert_eq!(
Err(MoveError::OpponentCanFillQuarter),
state.moves_allowed()
state.moves_allowed(&moves)
);
}
@ -622,31 +616,31 @@ mod tests {
3, 3, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0,
]);
state.dice.values = (5, 4);
state.moves = (
let moves = (
CheckerMove::new(1, 6).unwrap(),
CheckerMove::new(2, 6).unwrap(),
);
assert!(state.moves_allowed().is_ok());
state.moves = (
assert!(state.moves_allowed(&moves).is_ok());
let moves = (
CheckerMove::new(1, 5).unwrap(),
CheckerMove::new(2, 7).unwrap(),
);
assert_eq!(Err(MoveError::MustFillQuarter), state.moves_allowed());
assert_eq!(Err(MoveError::MustFillQuarter), state.moves_allowed(&moves));
state.board.set_positions([
2, 3, 2, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]);
state.dice.values = (2, 3);
state.moves = (
let moves = (
CheckerMove::new(6, 8).unwrap(),
CheckerMove::new(6, 9).unwrap(),
);
assert_eq!(Err(MoveError::MustFillQuarter), state.moves_allowed());
state.moves = (
assert_eq!(Err(MoveError::MustFillQuarter), state.moves_allowed(&moves));
let moves = (
CheckerMove::new(2, 4).unwrap(),
CheckerMove::new(5, 8).unwrap(),
);
assert!(state.moves_allowed().is_ok());
assert!(state.moves_allowed(&moves).is_ok());
}
#[test]
@ -656,17 +650,17 @@ mod tests {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
]);
state.dice.values = (1, 3);
state.moves = (
let moves = (
CheckerMove::new(22, 0).unwrap(),
CheckerMove::new(0, 0).unwrap(),
);
assert_eq!(Err(MoveError::MustPlayAllDice), state.moves_allowed());
state.moves = (
assert_eq!(Err(MoveError::MustPlayAllDice), state.moves_allowed(&moves));
let moves = (
CheckerMove::new(22, 23).unwrap(),
CheckerMove::new(23, 0).unwrap(),
);
assert!(state.moves_allowed().is_ok());
assert!(state.moves_allowed(&moves).is_ok());
}
#[test]
@ -677,21 +671,21 @@ mod tests {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]);
state.dice.values = (2, 1);
state.moves = (
let moves = (
CheckerMove::new(10, 12).unwrap(),
CheckerMove::new(11, 12).unwrap(),
);
assert!(state.moves_follows_dices());
assert!(state.moves_allowed().is_ok());
assert!(state.moves_follows_dices(&moves));
assert!(state.moves_allowed(&moves).is_ok());
// par puissance
state.dice.values = (3, 2);
state.moves = (
let moves = (
CheckerMove::new(10, 12).unwrap(),
CheckerMove::new(11, 12).unwrap(),
);
assert!(state.moves_follows_dices());
assert!(state.moves_allowed().is_ok());
assert!(state.moves_follows_dices(&moves));
assert!(state.moves_allowed(&moves).is_ok());
}
#[test]
@ -701,31 +695,31 @@ mod tests {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]);
state.dice.values = (2, 1);
state.moves = (
let moves = (
CheckerMove::new(0, 0).unwrap(),
CheckerMove::new(0, 0).unwrap(),
);
assert!(state.moves_follows_dices());
assert!(state.moves_allowed().is_ok());
assert!(state.moves_follows_dices(&moves));
assert!(state.moves_allowed(&moves).is_ok());
state.board.set_positions([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
]);
state.dice.values = (2, 1);
state.moves = (
let moves = (
CheckerMove::new(23, 24).unwrap(),
CheckerMove::new(0, 0).unwrap(),
);
assert!(state.moves_follows_dices());
// let res = state.moves_allowed();
assert!(state.moves_follows_dices(&moves));
// let res = state.moves_allowed(&moves);
// println!("{:?}", res);
assert!(state.moves_allowed().is_ok());
assert!(state.moves_allowed(&moves).is_ok());
state.moves = (
let moves = (
CheckerMove::new(0, 0).unwrap(),
CheckerMove::new(0, 0).unwrap(),
);
assert_eq!(Err(MoveError::MustPlayAllDice), state.moves_allowed());
assert_eq!(Err(MoveError::MustPlayAllDice), state.moves_allowed(&moves));
}
#[test]
@ -735,13 +729,13 @@ mod tests {
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0,
]);
state.dice.values = (2, 3);
state.moves = (
let moves = (
CheckerMove::new(12, 14).unwrap(),
CheckerMove::new(1, 4).unwrap(),
);
assert_eq!(
Err(MoveError::CornerNeedsTwoCheckers),
state.moves_allowed()
state.moves_allowed(&moves)
);
}
@ -752,18 +746,21 @@ mod tests {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0, 0,
]);
state.dice.values = (2, 3);
state.moves = (
let moves = (
CheckerMove::new(12, 14).unwrap(),
CheckerMove::new(0, 0).unwrap(),
);
// let poss = state.get_possible_moves_sequences(&Color::White, true);
// println!("{:?}", poss);
assert_eq!(Err(MoveError::MustPlayStrongerDie), state.moves_allowed());
state.moves = (
assert_eq!(
Err(MoveError::MustPlayStrongerDie),
state.moves_allowed(&moves)
);
let moves = (
CheckerMove::new(12, 15).unwrap(),
CheckerMove::new(0, 0).unwrap(),
);
assert!(state.moves_allowed().is_ok());
assert!(state.moves_allowed(&moves).is_ok());
}
#[test]
@ -771,29 +768,25 @@ mod tests {
let mut state = MoveRules::default();
// Chained moves
state.moves = (
let moves = (
CheckerMove::new(1, 5).unwrap(),
CheckerMove::new(5, 9).unwrap(),
);
assert!(state.moves_possible());
assert!(state.moves_possible(&moves));
// not chained moves
state.moves = (
let moves = (
CheckerMove::new(1, 5).unwrap(),
CheckerMove::new(6, 9).unwrap(),
);
assert!(!state.moves_possible());
assert!(!state.moves_possible(&moves));
// black moves
let state = MoveRules::new(
&Color::Black,
&Board::default(),
Dice::default(),
&(
CheckerMove::new(24, 20).unwrap(),
CheckerMove::new(20, 19).unwrap(),
),
let state = MoveRules::new(&Color::Black, &Board::default(), Dice::default());
let moves = (
CheckerMove::new(24, 20).unwrap().mirror(),
CheckerMove::new(20, 19).unwrap().mirror(),
);
assert!(state.moves_possible());
assert!(state.moves_possible(&moves));
}
}

View file

@ -1,9 +1,13 @@
use crate::board::Board;
use crate::dice::Dice;
use crate::game_rules_moves::MoveRules;
use crate::player::Color;
use crate::CheckerMove;
use crate::Error;
#[derive(std::cmp::PartialEq, Debug)]
pub enum PointsRule {
FilledQuarter,
enum Jan {
FilledQuarter { points: u8 },
// jans de récompense :
// - battre une dame seule (par autant de façons de le faire, y compris
// utilisant une dame du coin de repos)
@ -15,11 +19,111 @@ pub enum PointsRule {
// - si on ne peut pas jouer ses deux dés
}
pub trait PointsRules {
fn board(&self) -> &Board;
fn dice(&self) -> &Dice;
#[derive(Debug)]
struct PossibleJan {
pub jan: Jan,
pub ways: Vec<(CheckerMove, CheckerMove)>,
}
fn get_points(&self) -> Vec<(u8, PointsRule)> {
Vec::new()
/// PointsRules always consider that the current player is White
/// You must use 'mirror' function on board if player is Black
#[derive(Default)]
pub struct PointsRules {
pub board: Board,
pub dice: Dice,
pub move_rules: MoveRules,
}
impl PointsRules {
/// Revert board if color is black
pub fn new(color: &Color, board: &Board, dice: Dice) -> Self {
let board = if *color == Color::Black {
board.mirror()
} else {
board.clone()
};
let move_rules = MoveRules::new(color, &board, dice);
// let move_rules = MoveRules::new(color, &self.board, dice, moves);
Self {
board,
dice,
move_rules,
}
}
fn get_jans(&self, board: &Board, dices: &Vec<u8>) -> Vec<PossibleJan> {
let mut jans = Vec::new();
if dices.is_empty() {
return jans;
}
let color = Color::White;
let mut dices = dices.clone();
let mut board = board.clone();
let fields = board.get_color_fields(color);
if let Some(dice) = dices.pop() {
for (from, _) in fields {
let to = if from + dice as usize > 24 {
0
} else {
from + dice as usize
};
if let Ok(cmove) = CheckerMove::new(from, to) {
match board.move_checker(&color, cmove) {
Err(Error::FieldBlockedByOne) => {
// TODO : prise en puissance
}
Err(_) => {}
Ok(()) => {
// TODO : check if it's a jan
let next_dice_jan = self.get_jans(&board, &dices);
// TODO : merge jans du dé courant et du prochain dé
}
}
}
}
}
// TODO : mouvement en puissance ?
// TODO : tout d'une (sans doublons avec 1 + 1) ?
jans
}
pub fn get_points(&self) -> usize {
let mut points = 0;
let jans = self.get_jans(&self.board, &vec![self.dice.values.0, self.dice.values.1]);
// Jans de remplissage
let filling_moves_sequences = self.move_rules.get_quarter_filling_moves_sequences();
points += 4 * filling_moves_sequences.len();
// Points par simple par moyen Points par doublet par moyen Nombre de moyens possibles Bénéficiaire
// « JAN RARE »
// Jan de six tables 4 n/a 1 Joueur
// Jan de deux tables 4 6 1 Joueur
// Jan de mézéas 4 6 1 Joueur
// Contre jan de deux tables 4 6 1 Adversaire
// Contre jan de mézéas 4 6 1 Adversaire
// « JAN DE RÉCOMPENSE »
// Battre à vrai une dame
// située dans la table des grands jans 2 1, 2 ou 3 Joueur
// 4 1 ou 2 Joueur
// Battre à vrai une dame
// située dans la table des petits jans 4 1, 2 ou 3 Joueur
// 6 1 ou 2 Joueur
// Battre le coin adverse 4 6 1 Joueur
// « JAN QUI NE PEUT »
// Battre à faux une dame
// située dans la table des grands jans 2 4 1 Adversaire
// Battre à faux une dame
// située dans la table des petits jans 4 6 1 Adversaire
// Pour chaque dé non jouable (dame impuissante) 2 2 n/a Adversaire
// « JAN DE REMPLISSAGE »
// Faire un petit jan, un grand jan ou un jan de retour 4 1, 2, ou 3 Joueur
// 6 1 ou 2 Joueur
// Conserver un petit jan, un grand jan ou un jan de retour 4 6 1 Joueur
// « AUTRE »
// Sortir le premier toutes ses dames 4 6 n/a Joueur
points
}
}