use crate::{ board::{Board, BoardSlot, BoardSlotState}, game::{GameState, LogSeverity, MillGame, MillState, PlayerColor, Stone, StoneState}, }; use anyhow::Result; use engine::prelude::*; pub struct SimpleAI { pub player_color: PlayerColor, } impl SimpleAI { pub fn new(player_color: PlayerColor) -> Self { Self { player_color } } pub fn step( &self, stones: &mut [Stone; 9], board: &mut [[[BoardSlot; 3]; 3]; 3], scene: &mut SceneHandle, state: &mut GameState, ) -> Result<()> { MillGame::log(&format!("AI at state {:?}", *state), LogSeverity::Debug); let mut found_a_mill = false; match *state { GameState::Placing => { if let Some(placable) = stones .iter_mut() .find(|stone| stone.state == StoneState::ReadyToBePlaced) { let (x, y, z) = { let free_slots: Vec<&BoardSlot> = board .iter() .flatten() .flatten() .filter(|slot| slot.state() == BoardSlotState::Empty) .collect(); let len = free_slots.len(); let slot = &free_slots[Random::range(0, len as u32) as usize]; (slot.x, slot.y, slot.z) }; scene.on_scene(|scene| { if MillGame::place_stone( placable, (x, y, z), board, self.player_color, scene, state, )? != MillState::None { found_a_mill = true; } Ok(()) })?; } } GameState::Removing => { let mut other_color: Vec<&mut BoardSlot> = board .iter_mut() .flatten() .flatten() .filter(|slot| match (slot.state(), self.player_color) { (BoardSlotState::Black(_), PlayerColor::White) => true, (BoardSlotState::White(_), PlayerColor::Black) => true, _ => false, }) .collect(); let len = other_color.len(); let slot: &mut &mut BoardSlot = &mut other_color[Random::range(0, len as u32) as usize]; let stone = stones .iter_mut() .find(|s| { s.stone == match slot.state() { BoardSlotState::Black(e) => e, BoardSlotState::White(e) => e, _ => unreachable!(), } }) .unwrap(); MillGame::log("[AI] remove stone", LogSeverity::Debug); scene.on_scene(|scene| { MillGame::remove_stone(stone, slot, scene)?; Ok(()) })?; } GameState::Main => { scene.on_scene(|scene| { loop { let same_color: Vec<&BoardSlot> = board .iter() .flatten() .flatten() .filter(|slot| match (slot.state(), self.player_color) { (BoardSlotState::White(_), PlayerColor::White) => true, (BoardSlotState::Black(_), PlayerColor::Black) => true, _ => false, }) .collect(); let len = same_color.len(); let slot = &same_color[Random::range(0, len as u32) as usize]; let n = Board::get_neighbours(slot, board); let neighbours: Vec<&&BoardSlot> = n .iter() .filter(|n| n.state() == BoardSlotState::Empty) .collect(); if !neighbours.is_empty() { let neighbour = &neighbours[Random::range(0, neighbours.len() as u32) as usize]; if neighbour.state() == BoardSlotState::Empty { let (x, y, z) = (slot.x, slot.y, slot.z); let (tx, ty, tz) = (neighbour.x, neighbour.y, neighbour.z); let mut successful_move = false; MillGame::log("[AI] going to make a move", LogSeverity::Debug); if let Some(millstate) = MillGame::move_stone( (x, y, z), (tx, ty, tz), scene, board, state, )? { MillGame::log("[AI] successful move", LogSeverity::Debug); if MillState::None != millstate { MillGame::log("[AI] found a mill", LogSeverity::Debug); found_a_mill = true; } successful_move = true; } else { MillGame::log("[AI] move failed", LogSeverity::Debug); } if successful_move { break; } } } } Ok(()) })?; } GameState::Waiting => unreachable!(), } if found_a_mill { self.step(stones, board, scene, state)?; } MillGame::log("finish AI", LogSeverity::Debug); Ok(()) } }