wip check jans
This commit is contained in:
parent
b528fa3ac6
commit
3879265dce
|
|
@ -70,7 +70,8 @@ impl Bot {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_points(&self) -> u8 {
|
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) {
|
fn choose_move(&self) -> (CheckerMove, CheckerMove) {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
impl Default for GameState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -248,10 +239,15 @@ impl GameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check points are correct
|
// Check points are correct
|
||||||
let rules_points: u8 = self.get_points().iter().map(|r| r.0).sum();
|
// let (board, moves) = if *color == Color::Black {
|
||||||
if rules_points != *points {
|
// (board.mirror(), (moves.0.mirror(), moves.1.mirror()))
|
||||||
return false;
|
// } 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 } => {
|
Move { player_id, moves } => {
|
||||||
// Check player exists
|
// Check player exists
|
||||||
|
|
@ -266,8 +262,13 @@ impl GameState {
|
||||||
}
|
}
|
||||||
let color = &self.players[player_id].color;
|
let color = &self.players[player_id].color;
|
||||||
|
|
||||||
let rules = MoveRules::new(color, &self.board, self.dice, moves);
|
let rules = MoveRules::new(color, &self.board, self.dice);
|
||||||
if !rules.moves_follow_rules() {
|
let moves = if *color == Color::Black {
|
||||||
|
(moves.0.mirror(), moves.1.mirror())
|
||||||
|
} else {
|
||||||
|
*moves
|
||||||
|
};
|
||||||
|
if !rules.moves_follow_rules(&moves) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,60 +36,56 @@ pub enum MoveError {
|
||||||
pub struct MoveRules {
|
pub struct MoveRules {
|
||||||
pub board: Board,
|
pub board: Board,
|
||||||
pub dice: Dice,
|
pub dice: Dice,
|
||||||
pub moves: (CheckerMove, CheckerMove),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MoveRules {
|
impl MoveRules {
|
||||||
/// Revert board if color is black
|
/// Revert board if color is black
|
||||||
pub fn new(
|
pub fn new(color: &Color, board: &Board, dice: Dice) -> Self {
|
||||||
color: &Color,
|
let board = if *color == Color::Black {
|
||||||
board: &Board,
|
board.mirror()
|
||||||
dice: Dice,
|
|
||||||
moves: &(CheckerMove, CheckerMove),
|
|
||||||
) -> Self {
|
|
||||||
let (board, moves) = if *color == Color::Black {
|
|
||||||
(board.mirror(), (moves.0.mirror(), moves.1.mirror()))
|
|
||||||
} else {
|
} 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 possibles on the board
|
||||||
// Check moves conforms to the dice
|
// Check moves conforms to the dice
|
||||||
// Check move is allowed by the rules (to desactivate when playing with schools)
|
// 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
|
/// ---- 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;
|
let color = &Color::White;
|
||||||
// Check move is physically possible
|
// Check move is physically possible
|
||||||
if !self.board.move_possible(color, &self.moves.0) {
|
if !self.board.move_possible(color, &moves.0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chained_move : "Tout d'une"
|
// 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) {
|
if !self.board.move_possible(color, &chained_move) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if !self.board.move_possible(color, &self.moves.1) {
|
} else if !self.board.move_possible(color, &moves.1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ----- moves_follows_dices : Second of three checks for moves
|
/// ----- 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
|
// Prise de coin par puissance
|
||||||
if self.is_move_by_puissance() {
|
if self.is_move_by_puissance(moves) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (dice1, dice2) = self.dice.values;
|
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);
|
let move1_dices = self.get_move_compatible_dices(move1);
|
||||||
if move1_dices.is_empty() {
|
if move1_dices.is_empty() {
|
||||||
|
|
@ -144,10 +140,10 @@ impl MoveRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ---- moves_allowed : Third of three checks for moves
|
/// ---- moves_allowed : Third of three checks for moves
|
||||||
fn moves_allowed(&self) -> Result<(), MoveError> {
|
fn moves_allowed(&self, moves: &(CheckerMove, CheckerMove)) -> Result<(), MoveError> {
|
||||||
self.check_corner_rules(&self.moves)?;
|
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() {
|
if self.can_take_corner_by_effect() {
|
||||||
return Err(MoveError::CornerByEffectPossible);
|
return Err(MoveError::CornerByEffectPossible);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -157,17 +153,13 @@ impl MoveRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si possible, les deux dés doivent être joués
|
// Si possible, les deux dés doivent être joués
|
||||||
let (m1, m2) = self.moves;
|
if moves.0.get_from() == 0 || moves.1.get_from() == 0 {
|
||||||
if m1.get_from() == 0 || m2.get_from() == 0 {
|
|
||||||
let mut possible_moves_sequences = self.get_possible_moves_sequences(true);
|
let mut possible_moves_sequences = self.get_possible_moves_sequences(true);
|
||||||
println!("{:?}", possible_moves_sequences);
|
println!("{:?}", possible_moves_sequences);
|
||||||
possible_moves_sequences.retain(|moves| self.check_exit_rules(moves).is_ok());
|
possible_moves_sequences.retain(|moves| self.check_exit_rules(moves).is_ok());
|
||||||
// possible_moves_sequences.retain(|moves| self.check_corner_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(&moves) && !possible_moves_sequences.is_empty() {
|
||||||
if !possible_moves_sequences.contains(&self.moves)
|
if *moves == (EMPTY_MOVE, EMPTY_MOVE) {
|
||||||
&& !possible_moves_sequences.is_empty()
|
|
||||||
{
|
|
||||||
if self.moves == (EMPTY_MOVE, EMPTY_MOVE) {
|
|
||||||
return Err(MoveError::MustPlayAllDice);
|
return Err(MoveError::MustPlayAllDice);
|
||||||
}
|
}
|
||||||
let empty_removed = possible_moves_sequences
|
let empty_removed = possible_moves_sequences
|
||||||
|
|
@ -181,10 +173,10 @@ impl MoveRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check exit rules
|
// 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 ----
|
// --- 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;
|
let in_opponent_side = farthest > 12;
|
||||||
if in_opponent_side && self.board.is_quarter_fillable(Color::Black, farthest) {
|
if in_opponent_side && self.board.is_quarter_fillable(Color::Black, farthest) {
|
||||||
return Err(MoveError::OpponentCanFillQuarter);
|
return Err(MoveError::OpponentCanFillQuarter);
|
||||||
|
|
@ -192,7 +184,7 @@ impl MoveRules {
|
||||||
|
|
||||||
// --- remplir cadran si possible & conserver cadran rempli si possible ----
|
// --- remplir cadran si possible & conserver cadran rempli si possible ----
|
||||||
let filling_moves_sequences = self.get_quarter_filling_moves_sequences();
|
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);
|
return Err(MoveError::MustFillQuarter);
|
||||||
}
|
}
|
||||||
// no rule was broken
|
// no rule was broken
|
||||||
|
|
@ -290,7 +282,7 @@ impl MoveRules {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_possible_moves_sequences(
|
pub fn get_possible_moves_sequences(
|
||||||
&self,
|
&self,
|
||||||
with_excedents: bool,
|
with_excedents: bool,
|
||||||
) -> Vec<(CheckerMove, CheckerMove)> {
|
) -> Vec<(CheckerMove, CheckerMove)> {
|
||||||
|
|
@ -321,7 +313,7 @@ impl MoveRules {
|
||||||
moves_seqs
|
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 mut moves_seqs = Vec::new();
|
||||||
let color = &Color::White;
|
let color = &Color::White;
|
||||||
for moves in self.get_possible_moves_sequences(true) {
|
for moves in self.get_possible_moves_sequences(true) {
|
||||||
|
|
@ -414,11 +406,10 @@ impl MoveRules {
|
||||||
moves
|
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 (dice1, dice2) = self.dice.values;
|
||||||
let (move1, move2): &(CheckerMove, CheckerMove) = &self.moves;
|
let dist1 = (moves.0.get_to() as i8 - moves.0.get_from() as i8).unsigned_abs();
|
||||||
let dist1 = (move1.get_to() as i8 - move1.get_from() as i8).unsigned_abs();
|
let dist2 = (moves.1.get_to() as i8 - moves.1.get_from() as i8).unsigned_abs();
|
||||||
let dist2 = (move2.get_to() as i8 - move2.get_from() as i8).unsigned_abs();
|
|
||||||
|
|
||||||
// Both corners must be empty
|
// Both corners must be empty
|
||||||
let (count1, _color) = self.board.get_field_checkers(12).unwrap();
|
let (count1, _color) = self.board.get_field_checkers(12).unwrap();
|
||||||
|
|
@ -428,8 +419,8 @@ impl MoveRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
let color = &Color::White;
|
let color = &Color::White;
|
||||||
move1.get_to() == move2.get_to()
|
moves.0.get_to() == moves.1.get_to()
|
||||||
&& move1.get_to() == self.board.get_color_corner(color)
|
&& moves.0.get_to() == self.board.get_color_corner(color)
|
||||||
&& (cmp::min(dist1, dist2) == cmp::min(dice1, dice2) - 1
|
&& (cmp::min(dist1, dist2) == cmp::min(dice1, dice2) - 1
|
||||||
&& cmp::max(dist1, dist2) == cmp::max(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,
|
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.dice.values = (5, 5);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(8, 12).unwrap(),
|
CheckerMove::new(8, 12).unwrap(),
|
||||||
CheckerMove::new(8, 12).unwrap(),
|
CheckerMove::new(8, 12).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.is_move_by_puissance());
|
assert!(state.is_move_by_puissance(&moves));
|
||||||
assert!(state.moves_follows_dices());
|
assert!(state.moves_follows_dices(&moves));
|
||||||
assert!(state.moves_allowed().is_ok());
|
assert!(state.moves_allowed(&moves).is_ok());
|
||||||
|
|
||||||
// opponent corner must be empty
|
// opponent corner must be empty
|
||||||
state.board.set_positions([
|
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,
|
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.is_move_by_puissance(&moves));
|
||||||
assert!(!state.moves_follows_dices());
|
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
|
// 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([
|
state.board.set_positions([
|
||||||
|
|
@ -508,15 +499,15 @@ mod tests {
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Err(MoveError::CornerByEffectPossible),
|
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
|
// on a déjà pris son coin : on ne peux plus y deplacer des dames par puissance
|
||||||
state.board.set_positions([
|
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,
|
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.is_move_by_puissance(&moves));
|
||||||
assert!(!state.moves_follows_dices());
|
assert!(!state.moves_follows_dices(&moves));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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,
|
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.dice.values = (5, 5);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(20, 0).unwrap(),
|
CheckerMove::new(20, 0).unwrap(),
|
||||||
CheckerMove::new(20, 0).unwrap(),
|
CheckerMove::new(20, 0).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_follows_dices());
|
assert!(state.moves_follows_dices(&moves));
|
||||||
assert!(state.moves_allowed().is_ok());
|
assert!(state.moves_allowed(&moves).is_ok());
|
||||||
|
|
||||||
// toutes les dames doivent être dans le jan de retour
|
// toutes les dames doivent être dans le jan de retour
|
||||||
state.board.set_positions([
|
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,
|
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.dice.values = (5, 5);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(20, 0).unwrap(),
|
CheckerMove::new(20, 0).unwrap(),
|
||||||
CheckerMove::new(20, 0).unwrap(),
|
CheckerMove::new(20, 0).unwrap(),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Err(MoveError::ExitNeedsAllCheckersOnLastQuarter),
|
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
|
// 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,
|
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.dice.values = (5, 5);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(20, 0).unwrap(),
|
CheckerMove::new(20, 0).unwrap(),
|
||||||
CheckerMove::new(23, 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é
|
// on doit jouer le nombre excédant le plus éloigné
|
||||||
state.board.set_positions([
|
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,
|
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.dice.values = (5, 5);
|
||||||
state.moves = (
|
let moves = (
|
||||||
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());
|
assert_eq!(Err(MoveError::ExitNotFasthest), state.moves_allowed(&moves));
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(20, 0).unwrap(),
|
CheckerMove::new(20, 0).unwrap(),
|
||||||
CheckerMove::new(21, 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
|
// Cas de la dernière dame
|
||||||
state.board.set_positions([
|
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,
|
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.dice.values = (5, 5);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(23, 0).unwrap(),
|
CheckerMove::new(23, 0).unwrap(),
|
||||||
CheckerMove::new(0, 0).unwrap(),
|
CheckerMove::new(0, 0).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_follows_dices());
|
assert!(state.moves_follows_dices(&moves));
|
||||||
assert!(state.moves_allowed().is_ok());
|
assert!(state.moves_allowed(&moves).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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,
|
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.dice.values = (5, 5);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(11, 16).unwrap(),
|
CheckerMove::new(11, 16).unwrap(),
|
||||||
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([
|
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,
|
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.dice.values = (5, 5);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(11, 16).unwrap(),
|
CheckerMove::new(11, 16).unwrap(),
|
||||||
CheckerMove::new(11, 16).unwrap(),
|
CheckerMove::new(11, 16).unwrap(),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Err(MoveError::OpponentCanFillQuarter),
|
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,
|
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.dice.values = (5, 4);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(1, 6).unwrap(),
|
CheckerMove::new(1, 6).unwrap(),
|
||||||
CheckerMove::new(2, 6).unwrap(),
|
CheckerMove::new(2, 6).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_allowed().is_ok());
|
assert!(state.moves_allowed(&moves).is_ok());
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(1, 5).unwrap(),
|
CheckerMove::new(1, 5).unwrap(),
|
||||||
CheckerMove::new(2, 7).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([
|
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,
|
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.dice.values = (2, 3);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(6, 8).unwrap(),
|
CheckerMove::new(6, 8).unwrap(),
|
||||||
CheckerMove::new(6, 9).unwrap(),
|
CheckerMove::new(6, 9).unwrap(),
|
||||||
);
|
);
|
||||||
assert_eq!(Err(MoveError::MustFillQuarter), state.moves_allowed());
|
assert_eq!(Err(MoveError::MustFillQuarter), state.moves_allowed(&moves));
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(2, 4).unwrap(),
|
CheckerMove::new(2, 4).unwrap(),
|
||||||
CheckerMove::new(5, 8).unwrap(),
|
CheckerMove::new(5, 8).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_allowed().is_ok());
|
assert!(state.moves_allowed(&moves).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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,
|
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.dice.values = (1, 3);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(22, 0).unwrap(),
|
CheckerMove::new(22, 0).unwrap(),
|
||||||
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));
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(22, 23).unwrap(),
|
CheckerMove::new(22, 23).unwrap(),
|
||||||
CheckerMove::new(23, 0).unwrap(),
|
CheckerMove::new(23, 0).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_allowed().is_ok());
|
assert!(state.moves_allowed(&moves).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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,
|
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.dice.values = (2, 1);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(10, 12).unwrap(),
|
CheckerMove::new(10, 12).unwrap(),
|
||||||
CheckerMove::new(11, 12).unwrap(),
|
CheckerMove::new(11, 12).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_follows_dices());
|
assert!(state.moves_follows_dices(&moves));
|
||||||
assert!(state.moves_allowed().is_ok());
|
assert!(state.moves_allowed(&moves).is_ok());
|
||||||
|
|
||||||
// par puissance
|
// par puissance
|
||||||
state.dice.values = (3, 2);
|
state.dice.values = (3, 2);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(10, 12).unwrap(),
|
CheckerMove::new(10, 12).unwrap(),
|
||||||
CheckerMove::new(11, 12).unwrap(),
|
CheckerMove::new(11, 12).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_follows_dices());
|
assert!(state.moves_follows_dices(&moves));
|
||||||
assert!(state.moves_allowed().is_ok());
|
assert!(state.moves_allowed(&moves).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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,
|
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.dice.values = (2, 1);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(0, 0).unwrap(),
|
CheckerMove::new(0, 0).unwrap(),
|
||||||
CheckerMove::new(0, 0).unwrap(),
|
CheckerMove::new(0, 0).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_follows_dices());
|
assert!(state.moves_follows_dices(&moves));
|
||||||
assert!(state.moves_allowed().is_ok());
|
assert!(state.moves_allowed(&moves).is_ok());
|
||||||
|
|
||||||
state.board.set_positions([
|
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,
|
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.dice.values = (2, 1);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(23, 24).unwrap(),
|
CheckerMove::new(23, 24).unwrap(),
|
||||||
CheckerMove::new(0, 0).unwrap(),
|
CheckerMove::new(0, 0).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_follows_dices());
|
assert!(state.moves_follows_dices(&moves));
|
||||||
// let res = state.moves_allowed();
|
// let res = state.moves_allowed(&moves);
|
||||||
// println!("{:?}", res);
|
// 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(),
|
||||||
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]
|
#[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,
|
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.dice.values = (2, 3);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(12, 14).unwrap(),
|
CheckerMove::new(12, 14).unwrap(),
|
||||||
CheckerMove::new(1, 4).unwrap(),
|
CheckerMove::new(1, 4).unwrap(),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Err(MoveError::CornerNeedsTwoCheckers),
|
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,
|
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.dice.values = (2, 3);
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(12, 14).unwrap(),
|
CheckerMove::new(12, 14).unwrap(),
|
||||||
CheckerMove::new(0, 0).unwrap(),
|
CheckerMove::new(0, 0).unwrap(),
|
||||||
);
|
);
|
||||||
// let poss = state.get_possible_moves_sequences(&Color::White, true);
|
// let poss = state.get_possible_moves_sequences(&Color::White, true);
|
||||||
// println!("{:?}", poss);
|
// println!("{:?}", poss);
|
||||||
assert_eq!(Err(MoveError::MustPlayStrongerDie), state.moves_allowed());
|
assert_eq!(
|
||||||
state.moves = (
|
Err(MoveError::MustPlayStrongerDie),
|
||||||
|
state.moves_allowed(&moves)
|
||||||
|
);
|
||||||
|
let moves = (
|
||||||
CheckerMove::new(12, 15).unwrap(),
|
CheckerMove::new(12, 15).unwrap(),
|
||||||
CheckerMove::new(0, 0).unwrap(),
|
CheckerMove::new(0, 0).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_allowed().is_ok());
|
assert!(state.moves_allowed(&moves).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -771,29 +768,25 @@ mod tests {
|
||||||
let mut state = MoveRules::default();
|
let mut state = MoveRules::default();
|
||||||
|
|
||||||
// Chained moves
|
// Chained moves
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(1, 5).unwrap(),
|
CheckerMove::new(1, 5).unwrap(),
|
||||||
CheckerMove::new(5, 9).unwrap(),
|
CheckerMove::new(5, 9).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(state.moves_possible());
|
assert!(state.moves_possible(&moves));
|
||||||
|
|
||||||
// not chained moves
|
// not chained moves
|
||||||
state.moves = (
|
let moves = (
|
||||||
CheckerMove::new(1, 5).unwrap(),
|
CheckerMove::new(1, 5).unwrap(),
|
||||||
CheckerMove::new(6, 9).unwrap(),
|
CheckerMove::new(6, 9).unwrap(),
|
||||||
);
|
);
|
||||||
assert!(!state.moves_possible());
|
assert!(!state.moves_possible(&moves));
|
||||||
|
|
||||||
// black moves
|
// black moves
|
||||||
let state = MoveRules::new(
|
let state = MoveRules::new(&Color::Black, &Board::default(), Dice::default());
|
||||||
&Color::Black,
|
let moves = (
|
||||||
&Board::default(),
|
CheckerMove::new(24, 20).unwrap().mirror(),
|
||||||
Dice::default(),
|
CheckerMove::new(20, 19).unwrap().mirror(),
|
||||||
&(
|
|
||||||
CheckerMove::new(24, 20).unwrap(),
|
|
||||||
CheckerMove::new(20, 19).unwrap(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
assert!(state.moves_possible());
|
assert!(state.moves_possible(&moves));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
use crate::board::Board;
|
use crate::board::Board;
|
||||||
use crate::dice::Dice;
|
use crate::dice::Dice;
|
||||||
|
use crate::game_rules_moves::MoveRules;
|
||||||
|
use crate::player::Color;
|
||||||
|
use crate::CheckerMove;
|
||||||
|
|
||||||
#[derive(std::cmp::PartialEq, Debug)]
|
#[derive(std::cmp::PartialEq, Debug)]
|
||||||
pub enum PointsRule {
|
enum Jan {
|
||||||
FilledQuarter,
|
FilledQuarter { points: u8 },
|
||||||
// jans de récompense :
|
// jans de récompense :
|
||||||
// - battre une dame seule (par autant de façons de le faire, y compris
|
// - battre une dame seule (par autant de façons de le faire, y compris
|
||||||
// utilisant une dame du coin de repos)
|
// utilisant une dame du coin de repos)
|
||||||
|
|
@ -15,11 +18,105 @@ pub enum PointsRule {
|
||||||
// - si on ne peut pas jouer ses deux dés
|
// - si on ne peut pas jouer ses deux dés
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PointsRules {
|
#[derive(Debug)]
|
||||||
fn board(&self) -> &Board;
|
struct PossibleJan {
|
||||||
fn dice(&self) -> &Dice;
|
pub jan: Jan,
|
||||||
|
pub ways: Vec<(CheckerMove, CheckerMove)>,
|
||||||
|
}
|
||||||
|
|
||||||
fn get_points(&self) -> Vec<(u8, PointsRule)> {
|
/// PointsRules always consider that the current player is White
|
||||||
Vec::new()
|
/// 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) {
|
||||||
|
if board.move_checker(&color, cmove).is_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