Print game state differences to log
This commit is contained in:
parent
9b0b9d5680
commit
4ad7a022dc
2 changed files with 224 additions and 21 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
/target
|
||||
Cargo.lock
|
||||
Cargo.lock
|
||||
*.log
|
242
src/game.rs
242
src/game.rs
|
@ -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 => (),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue