Print game state differences to log

This commit is contained in:
hodasemi 2023-05-12 14:53:01 +02:00
parent 9b0b9d5680
commit 4ad7a022dc
2 changed files with 224 additions and 21 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
/target
Cargo.lock
*.log

View file

@ -1,4 +1,6 @@
use std::{
fs::OpenOptions,
io::Write,
sync::{
atomic::{AtomicBool, AtomicU32, Ordering::SeqCst},
Arc, Mutex, MutexGuard,
@ -8,7 +10,10 @@ use std::{
use anyhow::Result;
use assetpath::AssetPath;
use engine::prelude::{cgmath::vec3, *};
use engine::prelude::{
cgmath::{vec3, Vector2},
*,
};
use crate::{
board::{Board, BoardSlot, BoardSlotState},
@ -49,12 +54,14 @@ pub enum MillState {
None,
}
#[derive(Debug, Clone, Copy)]
pub enum LogSeverity {
Basic,
Debug,
}
const LOG_SEVERITY: LogSeverity = LogSeverity::Debug;
const LOG_SEVERITY: LogSeverity = LogSeverity::Basic;
const LOG_FILE: &str = "millgame.log";
impl PlayerColor {
pub fn swap(&mut self) {
@ -80,6 +87,135 @@ impl PlayerColor {
}
}
#[derive(Default, Debug)]
struct TurnState {
white_infos: Vec<(StoneState, Entity, Option<Vector2<f32>>)>,
black_infos: Vec<(StoneState, Entity, Option<Vector2<f32>>)>,
board_infos: Vec<((usize, usize, usize), Vector2<f32>, BoardSlotState)>,
}
impl TurnState {
pub fn new(game: &MillGame) -> Result<Self> {
let mut white_infos = Vec::new();
let mut black_infos = Vec::new();
game.scene.lock().unwrap().on_scene(|scene| {
for white_stone in game.white_stones.lock().unwrap().iter() {
let pos = match white_stone.state {
StoneState::ReadyToBePlaced => None,
StoneState::Placed => Some(
scene
.entity(white_stone.stone)?
.get_component::<Location>()?
.position()
.truncate(),
),
StoneState::Dead => None,
};
white_infos.push((white_stone.state, white_stone.stone, pos));
}
for black_stone in game.black_stones.lock().unwrap().iter() {
let pos = match black_stone.state {
StoneState::ReadyToBePlaced => None,
StoneState::Placed => Some(
scene
.entity(black_stone.stone)?
.get_component::<Location>()?
.position()
.truncate(),
),
StoneState::Dead => None,
};
black_infos.push((black_stone.state, black_stone.stone, pos));
}
Ok(())
})?;
let board_infos: Vec<((usize, usize, usize), Vector2<f32>, BoardSlotState)> = game
.board
.lock()
.unwrap()
.slots()
.iter()
.flatten()
.flatten()
.map(|slot| ((slot.x, slot.y, slot.z), slot.position, slot.state()))
.collect();
Ok(Self {
white_infos,
black_infos,
board_infos,
})
}
pub fn diff(&self, other: &Self) -> (Self, Self) {
let mut my_diffs = Self::default();
let mut other_diffs = Self::default();
for my_info in self.white_infos.iter() {
let other_info = other.white_infos.iter().find(|o| my_info.1 == o.1).unwrap();
if my_info.0 != other_info.0 || my_info.2 != other_info.2 {
my_diffs.white_infos.push(*my_info);
other_diffs.white_infos.push(*other_info);
}
}
for my_info in self.black_infos.iter() {
let other_info = other.black_infos.iter().find(|o| my_info.1 == o.1).unwrap();
if my_info.0 != other_info.0 || my_info.2 != other_info.2 {
my_diffs.black_infos.push(*my_info);
other_diffs.black_infos.push(*other_info);
}
}
for my_slot in self.board_infos.iter() {
let other_slot = other.board_infos.iter().find(|o| my_slot.0 == o.0).unwrap();
if my_slot.2 != other_slot.2 {
my_diffs.board_infos.push(*my_slot);
other_diffs.board_infos.push(*other_slot);
}
}
(my_diffs, other_diffs)
}
pub fn log(&self, severity: LogSeverity) {
if !self.white_infos.is_empty() {
MillGame::log(" == WHITE STONES ==", severity);
for white_info in self.white_infos.iter() {
MillGame::log(&format!("{:?}", white_info), severity);
}
}
if !self.black_infos.is_empty() {
MillGame::log(" == BLACK STONES ==", severity);
for black_info in self.black_infos.iter() {
MillGame::log(&format!("{:?}", black_info), severity);
}
}
MillGame::log(" == BOARD ==", severity);
for board_info in self.board_infos.iter() {
MillGame::log(&format!("{:?}", board_info), severity);
}
}
pub fn is_empty(&self) -> bool {
self.white_infos.is_empty() && self.black_infos.is_empty() && self.board_infos.is_empty()
}
}
pub struct MillGame {
engine: Arc<Engine>,
last_turn_timing: Mutex<Duration>,
@ -98,6 +234,7 @@ pub struct MillGame {
mouse_y: AtomicU32,
turn_finished: AtomicBool,
turn_states: Mutex<Vec<TurnState>>,
selected_field: Mutex<Option<(usize, usize, usize)>>,
@ -105,10 +242,10 @@ pub struct MillGame {
white_player_label: Arc<Label>,
black_player_label: Arc<Label>,
start_button: Arc<Button>,
grid: Arc<Grid>,
_start_button: Arc<Button>,
_grid: Arc<Grid>,
gui: Arc<GuiBuilder>,
_gui: Arc<GuiBuilder>,
}
impl MillGame {
@ -222,17 +359,18 @@ impl MillGame {
mouse_y: AtomicU32::new(0),
turn_finished: AtomicBool::new(false),
turn_states: Mutex::default(),
selected_field: Mutex::default(),
simple_ai: SimpleAI::new(PlayerColor::White),
grid: grid.clone(),
_grid: grid.clone(),
white_player_label,
black_player_label,
start_button: start_button.clone(),
_start_button: start_button.clone(),
gui,
_gui: gui,
});
start_button.set_callback({
@ -245,7 +383,7 @@ impl MillGame {
}
if let Some(me) = weak_self.upgrade() {
Self::log("start game", LogSeverity::Debug);
Self::log(" ===== START GAME =====", LogSeverity::Basic);
*me.state.lock().unwrap() = GameState::Placing;
*me.current_player.lock().unwrap() = PlayerColor::Black;
@ -271,15 +409,46 @@ impl MillGame {
self.turn_finished.store(true, SeqCst);
}
fn print_game_state(&self, severity: LogSeverity, log_state: bool) -> Result<()> {
let current_turn_state = TurnState::new(self)?;
// verity that last turn actually something happened
debug_assert!(!current_turn_state.is_empty());
if log_state {
current_turn_state.log(severity);
}
let mut turn_states = self.turn_states.lock().unwrap();
if !turn_states.is_empty() {
let (new_diff, old_diff) = current_turn_state.diff(turn_states.last().unwrap());
Self::log(" ===== OLD DIFF =====", severity);
old_diff.log(severity);
Self::log(" ===== NEW DIFF =====", severity);
new_diff.log(severity);
}
turn_states.push(current_turn_state);
Ok(())
}
fn next_game_step(&self) -> Result<()> {
{
let mut state = self.state.lock().unwrap();
Self::log(
&format!(" ===== NEW TURN ({:?}) =====", state),
&format!(
" =========================== NEW TURN ({:?}) ===========================",
state
),
LogSeverity::Basic,
);
self.print_game_state(LogSeverity::Basic, false)?;
match *state {
GameState::Placing => {
if !self
@ -440,7 +609,11 @@ impl MillGame {
match player_color {
PlayerColor::White => {
Self::log(
&format!(" ==> white stone placed at {:?}", (x, y, z)),
&format!(
" ==> white stone ({:?}) placed at {:?}",
stone.stone,
(x, y, z)
),
LogSeverity::Basic,
);
@ -448,7 +621,11 @@ impl MillGame {
}
PlayerColor::Black => {
Self::log(
&format!(" ==> black stone placed at {:?}", (x, y, z)),
&format!(
" ==> black stone ({:?}) placed at {:?}",
stone.stone,
(x, y, z)
),
LogSeverity::Basic,
);
@ -507,7 +684,8 @@ impl MillGame {
BoardSlotState::Black(e) => {
Self::log(
&format!(
" ==> black stone moved from {:?} to {:?}",
" ==> black stone ({:?}) moved from {:?} to {:?}",
e,
(x, y, z),
(tx, ty, tz)
),
@ -519,7 +697,8 @@ impl MillGame {
BoardSlotState::White(e) => {
Self::log(
&format!(
" ==> white stone moved from {:?} to {:?}",
" ==> white stone ({:?}) moved from {:?} to {:?}",
e,
(x, y, z),
(tx, ty, tz)
),
@ -556,7 +735,8 @@ impl MillGame {
BoardSlotState::Black(e) => {
Self::log(
&format!(
" ==> white player removes black stone at {:?}",
" ==> white player removes black stone ({:?}) at {:?}",
e,
(slot.x, slot.y, slot.z)
),
LogSeverity::Basic,
@ -567,7 +747,8 @@ impl MillGame {
BoardSlotState::White(e) => {
Self::log(
&format!(
" ==> black player removes white stone at {:?}",
" ==> black player removes white stone ({:?}) at {:?}",
e,
(slot.x, slot.y, slot.z)
),
LogSeverity::Basic,
@ -693,10 +874,16 @@ impl MillGame {
pub fn log(s: &str, log_severity: LogSeverity) {
match (LOG_SEVERITY, log_severity) {
(LogSeverity::Basic, LogSeverity::Basic) => println!("{}", s),
(LogSeverity::Basic, LogSeverity::Basic) => Self::write(s),
(LogSeverity::Basic, LogSeverity::Debug) => (),
(LogSeverity::Debug, LogSeverity::Basic) => println!("{}", s),
(LogSeverity::Debug, LogSeverity::Debug) => println!("{}", s),
(LogSeverity::Debug, LogSeverity::Basic) => Self::write(s),
(LogSeverity::Debug, LogSeverity::Debug) => Self::write(s),
}
}
fn write(s: &str) {
if let Ok(mut file) = OpenOptions::new().append(true).create(true).open(&LOG_FILE) {
if let Err(_) = file.write_all(format!("{}\n", s.to_string()).as_bytes()) {}
}
}
}
@ -842,6 +1029,11 @@ impl EngineObject for MillGame {
) {
(BoardSlotState::Black(_), PlayerColor::Black)
| (BoardSlotState::White(_), PlayerColor::White) => {
Self::log(
&format!("Selected ({:?})", (tx, ty, tz)),
LogSeverity::Basic,
);
*selected_slot = Some((tx, ty, tz));
}
@ -857,7 +1049,17 @@ impl EngineObject for MillGame {
}
}
MouseButton::Middle => self.camera_controls.lock().unwrap().hold(),
MouseButton::Right => (),
MouseButton::Right => {
let mut selected_slot = self.selected_field.lock().unwrap();
if selected_slot.is_some() {
Self::log(
&format!("Released selection ({:?})", selected_slot.unwrap()),
LogSeverity::Basic,
);
*selected_slot = None;
}
}
MouseButton::Forward => (),
MouseButton::Backward => (),
}