use crate::{ board::{BoardSlot, BoardSlotState}, game::{GameState, MillGame, 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: GameState, ) -> Result<()> { MillGame::log(&format!("AI at state {:?}", state)); match state { GameState::Placing => { if let Some(placable) = stones .iter_mut() .find(|stone| stone.state == StoneState::ReadyToBePlaced) { let mut free_slots: Vec<&mut BoardSlot> = board .iter_mut() .flatten() .flatten() .filter(|slot| *slot.state.lock().unwrap() == BoardSlotState::Empty) .collect(); let len = free_slots.len(); let slot = &mut free_slots[Random::range(0, len as u32) as usize]; scene.on_scene(|scene| { MillGame::place_stone(placable, slot, self.player_color, scene)?; Ok(()) })?; } } GameState::Removing => { let mut other_color: Vec<&mut BoardSlot> = board .iter_mut() .flatten() .flatten() .filter( |slot| match (*slot.state.lock().unwrap(), self.player_color) { (BoardSlotState::Black(_), PlayerColor::White) => true, (BoardSlotState::White(_), PlayerColor::Black) => true, _ => false, }, ) .collect(); let len = other_color.len(); let slot = &mut other_color[Random::range(0, len as u32) as usize]; scene.on_scene(|scene| { MillGame::remove_stone(slot, scene)?; Ok(()) })?; } GameState::Main => { let mut same_color: Vec<&BoardSlot> = board .iter() .flatten() .flatten() .filter( |slot| match (*slot.state.lock().unwrap(), self.player_color) { (BoardSlotState::White(_), PlayerColor::White) => true, (BoardSlotState::Black(_), PlayerColor::Black) => true, _ => false, }, ) .collect(); loop { let len = same_color.len(); let slot = &mut same_color[Random::range(0, len as u32) as usize]; // find free neighbour field if let Some(neighbour) = match Random::range(0, 6) as usize { 0 => { if slot.x > 0 { Some(&board[slot.x - 1][slot.y][slot.z]) } else { None } } 1 => { if slot.x < 2 { Some(&board[slot.x + 1][slot.y][slot.z]) } else { None } } 2 => { if slot.y > 0 { Some(&board[slot.x][slot.y - 1][slot.z]) } else { None } } 3 => { if slot.y < 2 { Some(&board[slot.x][slot.y + 1][slot.z]) } else { None } } 4 => { if slot.z > 0 { Some(&board[slot.x][slot.y][slot.z - 1]) } else { None } } 5 => { if slot.z < 2 { Some(&board[slot.x][slot.y][slot.z + 1]) } else { None } } // 6 => , // 7 => , // 8 => , // 9 => , _ => unreachable!(), } { let mut neighbour_state = neighbour.state.lock().unwrap(); let mut slot_state = slot.state.lock().unwrap(); match (*neighbour_state, *slot_state) { (BoardSlotState::Empty, BoardSlotState::Black(e)) => { *neighbour_state = BoardSlotState::Black(e); *slot_state = BoardSlotState::Empty; } (BoardSlotState::Empty, BoardSlotState::White(e)) => { *neighbour_state = BoardSlotState::White(e); *slot_state = BoardSlotState::Empty; } _ => (), } } } } } MillGame::log("finish AI"); Ok(()) } }