mirrors for open_spiel
This commit is contained in:
parent
47142d593f
commit
d53b65c947
7 changed files with 164 additions and 30 deletions
|
|
@ -71,7 +71,7 @@ impl Bot {
|
|||
debug!(">>>> {:?} BOT handle", self.color);
|
||||
let game = self.strategy.get_mut_game();
|
||||
let internal_event = if self.color == Color::Black {
|
||||
&event.get_mirror()
|
||||
&event.get_mirror(false)
|
||||
} else {
|
||||
event
|
||||
};
|
||||
|
|
@ -126,7 +126,7 @@ impl Bot {
|
|||
return if self.color == Color::Black {
|
||||
debug!(" bot (internal) evt : {internal_event:?} ; points : {player_points:?}");
|
||||
debug!("<<<< end {:?} BOT handle", self.color);
|
||||
internal_event.map(|evt| evt.get_mirror())
|
||||
internal_event.map(|evt| evt.get_mirror(false))
|
||||
} else {
|
||||
debug!("<<<< end {:?} BOT handle", self.color);
|
||||
internal_event
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
use crate::board::{Board, CheckerMove};
|
||||
use crate::dice::Dice;
|
||||
use crate::game_rules_moves::MoveRules;
|
||||
use crate::game_rules_points::{PointsRules, PossibleJans};
|
||||
use crate::game_rules_points::{PointsRules, PossibleJans, PossibleJansMethods};
|
||||
use crate::player::{Color, Player, PlayerId};
|
||||
use log::{debug, error};
|
||||
|
||||
// use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::{fmt, str};
|
||||
|
||||
|
|
@ -143,6 +143,40 @@ impl GameState {
|
|||
game
|
||||
}
|
||||
|
||||
pub fn mirror(&self) -> GameState {
|
||||
let mirrored_active_player = if self.active_player_id == 1 { 2 } else { 1 };
|
||||
let mut mirrored_players = HashMap::new();
|
||||
if let Some(p2) = self.players.get(&2) {
|
||||
mirrored_players.insert(1, p2.mirror());
|
||||
}
|
||||
if let Some(p1) = self.players.get(&1) {
|
||||
mirrored_players.insert(2, p1.mirror());
|
||||
}
|
||||
let mirrored_history = self
|
||||
.history
|
||||
.clone()
|
||||
.iter()
|
||||
.map(|evt| evt.get_mirror(false))
|
||||
.collect();
|
||||
|
||||
let (move1, move2) = self.dice_moves;
|
||||
GameState {
|
||||
stage: self.stage,
|
||||
turn_stage: self.turn_stage,
|
||||
board: self.board.mirror(),
|
||||
active_player_id: mirrored_active_player,
|
||||
// active_player_id: self.active_player_id,
|
||||
players: mirrored_players,
|
||||
history: mirrored_history,
|
||||
dice: self.dice,
|
||||
dice_points: self.dice_points,
|
||||
dice_moves: (move1.mirror(), move2.mirror()),
|
||||
dice_jans: self.dice_jans.mirror(),
|
||||
roll_first: self.roll_first,
|
||||
schools_enabled: self.schools_enabled,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_schools_enabled(&mut self, schools_enabled: bool) {
|
||||
self.schools_enabled = schools_enabled;
|
||||
}
|
||||
|
|
@ -436,10 +470,12 @@ impl GameState {
|
|||
Roll { player_id } => {
|
||||
// Check player exists
|
||||
if !self.players.contains_key(player_id) {
|
||||
error!("unknown player_id");
|
||||
return false;
|
||||
}
|
||||
// Check player is currently the one making their move
|
||||
if self.active_player_id != *player_id {
|
||||
error!("not active player_id");
|
||||
return false;
|
||||
}
|
||||
// Check the turn stage
|
||||
|
|
@ -536,6 +572,7 @@ impl GameState {
|
|||
*moves
|
||||
};
|
||||
if !rules.moves_follow_rules(&moves) {
|
||||
// println!(">>> rules not followed ");
|
||||
error!("rules not followed ");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -555,7 +592,7 @@ impl GameState {
|
|||
|
||||
pub fn init_player(&mut self, player_name: &str) -> Option<PlayerId> {
|
||||
if self.players.len() > 2 {
|
||||
println!("more than two players");
|
||||
// println!("more than two players");
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -869,10 +906,12 @@ impl GameEvent {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_mirror(&self) -> Self {
|
||||
pub fn get_mirror(&self, preserve_player: bool) -> Self {
|
||||
// let mut mirror = self.clone();
|
||||
let mirror_player_id = if let Some(player_id) = self.player_id() {
|
||||
if player_id == 1 {
|
||||
if preserve_player {
|
||||
player_id
|
||||
} else if player_id == 1 {
|
||||
2
|
||||
} else {
|
||||
1
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ impl MoveRules {
|
|||
|
||||
fn get_board_from_color(color: &Color, board: &Board) -> Board {
|
||||
if *color == Color::Black {
|
||||
println!("get_board_from_color -> mirror of {}", board);
|
||||
board.mirror()
|
||||
} else {
|
||||
board.clone()
|
||||
|
|
@ -74,6 +75,7 @@ impl MoveRules {
|
|||
moves: &(CheckerMove, CheckerMove),
|
||||
// ignored_rules: Vec<TricTracRule>,
|
||||
) -> bool {
|
||||
println!("in moves_follow_rules");
|
||||
// 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)
|
||||
|
|
@ -81,7 +83,8 @@ impl MoveRules {
|
|||
let is_allowed = self.moves_allowed(moves);
|
||||
// let is_allowed = self.moves_allowed(moves, ignored_rules);
|
||||
if is_allowed.is_err() {
|
||||
info!("Move not allowed : {:?}", is_allowed.unwrap_err());
|
||||
println!("Move not allowed : {:?}", is_allowed.unwrap_err());
|
||||
// info!("Move not allowed : {:?}", is_allowed.unwrap_err());
|
||||
false
|
||||
} else {
|
||||
true
|
||||
|
|
@ -99,6 +102,10 @@ impl MoveRules {
|
|||
if let Ok((field_count, Some(field_color))) = self.board.get_field_checkers(move0_from)
|
||||
{
|
||||
if color != field_color || field_count < 2 {
|
||||
println!(
|
||||
"Move not physically possible 1. field_color {:?}, count {}",
|
||||
field_color, field_count
|
||||
);
|
||||
info!("Move not physically possible");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -110,6 +117,7 @@ impl MoveRules {
|
|||
if !self.board.passage_possible(color, &moves.0)
|
||||
|| !self.board.move_possible(color, &chained_move)
|
||||
{
|
||||
println!("Tout d'une : Move not physically possible");
|
||||
info!("Tout d'une : Move not physically possible");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -117,6 +125,11 @@ impl MoveRules {
|
|||
|| !self.board.move_possible(color, &moves.1)
|
||||
{
|
||||
// Move is not physically possible
|
||||
println!("Move not physically possible 2");
|
||||
println!(
|
||||
"board: {}, color: {:?} move: {:?}",
|
||||
self.board, color, moves
|
||||
);
|
||||
info!("Move not physically possible");
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,10 +69,26 @@ pub type PossibleJans = HashMap<Jan, Vec<(CheckerMove, CheckerMove)>>;
|
|||
pub trait PossibleJansMethods {
|
||||
fn push(&mut self, jan: Jan, cmoves: (CheckerMove, CheckerMove));
|
||||
fn merge(&mut self, other: Self);
|
||||
fn mirror(&self) -> Self;
|
||||
// fn get_points(&self) -> u8;
|
||||
}
|
||||
|
||||
impl PossibleJansMethods for PossibleJans {
|
||||
fn mirror(&self) -> Self {
|
||||
self.clone()
|
||||
.into_iter()
|
||||
.map(|(jan, moves)| {
|
||||
(
|
||||
jan,
|
||||
moves
|
||||
.into_iter()
|
||||
.map(|(m1, m2)| (m1.mirror(), m2.mirror()))
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn push(&mut self, jan: Jan, cmoves: (CheckerMove, CheckerMove)) {
|
||||
if let Some(ways) = self.get_mut(&jan) {
|
||||
if !ways.contains(&cmoves) {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,16 @@ impl Player {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn mirror(&self) -> Self {
|
||||
let mut player = self.clone();
|
||||
player.color = if self.color == Color::White {
|
||||
Color::Black
|
||||
} else {
|
||||
Color::White
|
||||
};
|
||||
player
|
||||
}
|
||||
|
||||
pub fn to_bits_string(&self) -> String {
|
||||
format!(
|
||||
"{:0>4b}{:0>4b}{:b}{:b}",
|
||||
|
|
|
|||
|
|
@ -50,9 +50,14 @@ impl TricTrac {
|
|||
self.game_state.active_player_id - 1
|
||||
}
|
||||
|
||||
fn get_legal_actions(&self, player_id: u64) -> Vec<usize> {
|
||||
if player_id == self.current_player_idx() {
|
||||
get_valid_action_indices(&self.game_state)
|
||||
fn get_legal_actions(&self, player_idx: u64) -> Vec<usize> {
|
||||
if player_idx == self.current_player_idx() {
|
||||
if player_idx == 0 {
|
||||
get_valid_action_indices(&self.game_state)
|
||||
} else {
|
||||
let mirror = self.game_state.mirror();
|
||||
get_valid_action_indices(&mirror)
|
||||
}
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
|
|
@ -80,14 +85,18 @@ impl TricTrac {
|
|||
}
|
||||
|
||||
fn apply_action(&mut self, action_idx: usize) -> PyResult<()> {
|
||||
if let Some(event) =
|
||||
TrictracAction::from_action_index(action_idx).and_then(|a| a.to_event(&self.game_state))
|
||||
{
|
||||
println!("get event {:?}", event);
|
||||
if let Some(event) = TrictracAction::from_action_index(action_idx).and_then(|a| {
|
||||
let needs_mirror = self.game_state.active_player_id == 2;
|
||||
let game_state = if needs_mirror {
|
||||
&self.game_state.mirror()
|
||||
} else {
|
||||
&self.game_state
|
||||
};
|
||||
a.to_event(game_state)
|
||||
.map(|e| if needs_mirror { e.get_mirror(false) } else { e })
|
||||
}) {
|
||||
if self.game_state.validate(&event) {
|
||||
println!("valid event");
|
||||
self.game_state.consume(&event);
|
||||
println!("state {}", self.game_state);
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(pyo3::exceptions::PyRuntimeError::new_err(
|
||||
|
|
@ -113,8 +122,20 @@ impl TricTrac {
|
|||
[self.get_score(1), self.get_score(2)]
|
||||
}
|
||||
|
||||
fn get_tensor(&self, player: PlayerId) -> Vec<i8> {
|
||||
self.game_state.to_vec()
|
||||
fn get_tensor(&self, player_idx: u64) -> Vec<i8> {
|
||||
if player_idx == 0 {
|
||||
self.game_state.to_vec()
|
||||
} else {
|
||||
self.game_state.mirror().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_observation_string(&self, player_idx: u64) -> String {
|
||||
if player_idx == 0 {
|
||||
format!("{}", self.game_state)
|
||||
} else {
|
||||
format!("{}", self.game_state.mirror())
|
||||
}
|
||||
}
|
||||
|
||||
/// Afficher l'état du jeu (pour le débogage)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
use std::cmp::{max, min};
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
|
||||
use crate::{CheckerMove, GameEvent, GameState};
|
||||
use crate::board::Board;
|
||||
use crate::{CheckerMove, Dice, GameEvent, GameState};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// 1 (Roll) + 1 (Go) + 512 (mouvements possibles)
|
||||
|
|
@ -60,6 +61,22 @@ impl TrictracAction {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn mirror(&self) -> TrictracAction {
|
||||
match self {
|
||||
TrictracAction::Roll => TrictracAction::Roll,
|
||||
TrictracAction::Go => TrictracAction::Go,
|
||||
TrictracAction::Move {
|
||||
dice_order,
|
||||
checker1,
|
||||
checker2,
|
||||
} => TrictracAction::Move {
|
||||
dice_order: *dice_order,
|
||||
checker1: if *checker1 == 0 { 0 } else { 25 - checker1 },
|
||||
checker2: if *checker2 == 0 { 0 } else { 25 - checker2 },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_event(&self, state: &GameState) -> Option<GameEvent> {
|
||||
match self {
|
||||
TrictracAction::Roll => {
|
||||
|
|
@ -197,8 +214,6 @@ pub fn get_valid_actions(game_state: &GameState) -> Vec<TrictracAction> {
|
|||
let rules = crate::MoveRules::new(&color, &game_state.board, game_state.dice);
|
||||
let possible_moves = rules.get_possible_moves_sequences(true, vec![]);
|
||||
|
||||
// Modififier checker_moves_to_trictrac_action si on doit gérer Black
|
||||
assert_eq!(color, crate::Color::White);
|
||||
for (move1, move2) in possible_moves {
|
||||
valid_actions.push(checker_moves_to_trictrac_action(
|
||||
&move1, &move2, &color, game_state,
|
||||
|
|
@ -213,8 +228,6 @@ pub fn get_valid_actions(game_state: &GameState) -> Vec<TrictracAction> {
|
|||
possible_moves.push((CheckerMove::default(), CheckerMove::default()));
|
||||
}
|
||||
|
||||
// Modififier checker_moves_to_trictrac_action si on doit gérer Black
|
||||
assert_eq!(color, crate::Color::White);
|
||||
for (move1, move2) in possible_moves {
|
||||
valid_actions.push(checker_moves_to_trictrac_action(
|
||||
&move1, &move2, &color, game_state,
|
||||
|
|
@ -230,18 +243,40 @@ pub fn get_valid_actions(game_state: &GameState) -> Vec<TrictracAction> {
|
|||
valid_actions
|
||||
}
|
||||
|
||||
// Valid only for White player
|
||||
fn checker_moves_to_trictrac_action(
|
||||
move1: &CheckerMove,
|
||||
move2: &CheckerMove,
|
||||
color: &crate::Color,
|
||||
state: &GameState,
|
||||
) -> TrictracAction {
|
||||
let dice = &state.dice;
|
||||
let board = &state.board;
|
||||
|
||||
if color == &crate::Color::Black {
|
||||
white_checker_moves_to_trictrac_action(
|
||||
move1,
|
||||
move2,
|
||||
// &move1.clone().mirror(),
|
||||
// &move2.clone().mirror(),
|
||||
dice,
|
||||
&board.clone().mirror(),
|
||||
)
|
||||
.mirror()
|
||||
} else {
|
||||
white_checker_moves_to_trictrac_action(move1, move2, dice, board)
|
||||
}
|
||||
}
|
||||
|
||||
fn white_checker_moves_to_trictrac_action(
|
||||
move1: &CheckerMove,
|
||||
move2: &CheckerMove,
|
||||
dice: &Dice,
|
||||
board: &Board,
|
||||
) -> TrictracAction {
|
||||
let to1 = move1.get_to();
|
||||
let to2 = move2.get_to();
|
||||
let from1 = move1.get_from();
|
||||
let from2 = move2.get_from();
|
||||
let dice = state.dice;
|
||||
|
||||
let mut diff_move1 = if to1 > 0 {
|
||||
// Mouvement sans sortie
|
||||
|
|
@ -277,14 +312,14 @@ fn checker_moves_to_trictrac_action(
|
|||
}
|
||||
let dice_order = diff_move1 == dice.values.0 as usize;
|
||||
|
||||
let checker1 = state.board.get_field_checker(color, from1) as usize;
|
||||
let mut tmp_board = state.board.clone();
|
||||
let checker1 = board.get_field_checker(&crate::Color::White, from1) as usize;
|
||||
let mut tmp_board = board.clone();
|
||||
// should not raise an error for a valid action
|
||||
let move_res = tmp_board.move_checker(color, *move1);
|
||||
let move_res = tmp_board.move_checker(&crate::Color::White, *move1);
|
||||
if move_res.is_err() {
|
||||
panic!("error while moving checker {move_res:?}");
|
||||
}
|
||||
let checker2 = tmp_board.get_field_checker(color, from2) as usize;
|
||||
let checker2 = tmp_board.get_field_checker(&crate::Color::White, from2) as usize;
|
||||
TrictracAction::Move {
|
||||
dice_order,
|
||||
checker1,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue