wip check jans
This commit is contained in:
parent
b528fa3ac6
commit
0df394c0b1
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue