use std::{fs::OpenOptions, io::Write, sync::Arc, time::Duration}; use anyhow::Result; use assetpath::AssetPath; use engine::prelude::{ cgmath::{vec3, Vector2}, *, }; use crate::{ board::{Board, BoardSlot, BoardSlotState}, objects::Objects, simple_ai::SimpleAI, }; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum StoneState { ReadyToBePlaced, Placed, Dead, } pub struct Stone { pub stone: Entity, pub state: StoneState, } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum GameState { Waiting, Placing, Removing, Main, Won(PlayerColor), } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum PlayerColor { White, Black, } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum MillState { White, Black, None, } #[derive(Debug, Clone, Copy)] pub enum LogSeverity { Basic, Debug, } const LOG_SEVERITY: LogSeverity = LogSeverity::Basic; const LOG_FILE: &str = "millgame.log"; const EXTRA_LOG_FILE: &str = "millgame_extra.log"; impl PlayerColor { pub fn swap(&mut self) { *self = match *self { PlayerColor::White => { MillGame::log("swapped to black player", LogSeverity::Debug); PlayerColor::Black } PlayerColor::Black => { MillGame::log("swapped to white player", LogSeverity::Debug); PlayerColor::White } } } pub fn other(&self) -> Self { match self { PlayerColor::White => PlayerColor::Black, PlayerColor::Black => PlayerColor::White, } } } #[derive(Default, Debug)] struct TurnState { white_infos: Vec<(StoneState, Entity, Option>)>, black_infos: Vec<(StoneState, Entity, Option>)>, board_infos: Vec<((usize, usize, usize), Vector2, BoardSlotState)>, } impl TurnState { pub fn new(world: &World, game: &MillGame) -> Result { let mut white_infos = Vec::new(); let mut black_infos = Vec::new(); for white_stone in game.white_stones.iter() { let pos = match white_stone.state { StoneState::ReadyToBePlaced => None, StoneState::Placed => Some( world .entity(white_stone.stone)? .get_component::()? .position() .truncate(), ), StoneState::Dead => None, }; white_infos.push((white_stone.state, white_stone.stone, pos)); } for black_stone in game.black_stones.iter() { let pos = match black_stone.state { StoneState::ReadyToBePlaced => None, StoneState::Placed => Some( world .entity(black_stone.stone)? .get_component::()? .position() .truncate(), ), StoneState::Dead => None, }; black_infos.push((black_stone.state, black_stone.stone, pos)); } let board_infos: Vec<((usize, usize, usize), Vector2, BoardSlotState)> = game .board .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 { last_turn_timing: Duration, board: Board, white_stones: [Stone; 9], black_stones: [Stone; 9], state: GameState, current_player: PlayerColor, mouse_x: u32, mouse_y: u32, turn_finished: bool, turn_states: Vec, selected_field: Option<(usize, usize, usize)>, white_player_label: Arc