mill_game/src/simple_ai.rs

180 lines
6.4 KiB
Rust
Raw Normal View History

2023-05-09 16:58:07 +00:00
use crate::{
2023-05-11 12:00:24 +00:00
board::{Board, BoardSlot, BoardSlotState},
2023-05-11 15:00:42 +00:00
game::{GameState, LogSeverity, MillGame, MillState, PlayerColor, Stone, StoneState},
2023-05-09 16:58:07 +00:00
};
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,
2023-05-11 12:00:24 +00:00
state: &mut GameState,
2023-05-16 07:05:04 +00:00
) -> Result<()> {
2023-05-11 15:00:42 +00:00
MillGame::log(&format!("AI at state {:?}", *state), LogSeverity::Debug);
2023-05-10 05:47:10 +00:00
2023-05-11 12:00:24 +00:00
let mut found_a_mill = false;
match *state {
2023-05-10 05:47:10 +00:00
GameState::Placing => {
if let Some(placable) = stones
.iter_mut()
.find(|stone| stone.state == StoneState::ReadyToBePlaced)
{
2023-05-11 12:00:24 +00:00
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();
2023-05-10 05:47:10 +00:00
2023-05-11 12:00:24 +00:00
let slot = &free_slots[Random::range(0, len as u32) as usize];
2023-05-10 05:47:10 +00:00
2023-05-11 12:00:24 +00:00
(slot.x, slot.y, slot.z)
};
2023-05-10 05:47:10 +00:00
scene.on_scene(|scene| {
2023-05-11 12:00:24 +00:00
if MillGame::place_stone(
placable,
(x, y, z),
board,
self.player_color,
scene,
state,
)? != MillState::None
{
found_a_mill = true;
}
2023-05-10 05:47:10 +00:00
Ok(())
})?;
}
}
GameState::Removing => {
let mut other_color: Vec<&mut BoardSlot> = board
.iter_mut()
.flatten()
.flatten()
2023-05-11 12:00:24 +00:00
.filter(|slot| match (slot.state(), self.player_color) {
(BoardSlotState::Black(_), PlayerColor::White) => true,
(BoardSlotState::White(_), PlayerColor::Black) => true,
_ => false,
})
2023-05-10 05:47:10 +00:00
.collect();
let len = other_color.len();
2023-05-11 12:00:24 +00:00
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();
2023-05-10 05:47:10 +00:00
2023-05-16 07:05:04 +00:00
MillGame::log("[AI] remove stone", LogSeverity::Debug);
2023-05-10 05:47:10 +00:00
scene.on_scene(|scene| {
2023-05-11 12:00:24 +00:00
MillGame::remove_stone(stone, slot, scene)?;
2023-05-10 05:47:10 +00:00
Ok(())
})?;
}
2023-05-10 18:05:12 +00:00
GameState::Main => {
2023-05-16 07:05:04 +00:00
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];
2023-05-10 18:05:12 +00:00
2023-05-16 07:05:04 +00:00
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);
2023-05-10 18:05:12 +00:00
2023-05-16 07:05:04 +00:00
let mut successful_move = false;
2023-05-11 12:00:24 +00:00
2023-05-16 07:05:04 +00:00
MillGame::log("[AI] going to make a move", LogSeverity::Debug);
2023-05-11 12:00:24 +00:00
2023-05-12 07:04:48 +00:00
if let Some(millstate) = MillGame::move_stone(
2023-05-11 12:00:24 +00:00
(x, y, z),
(tx, ty, tz),
scene,
board,
state,
2023-05-12 07:04:48 +00:00
)? {
2023-05-16 07:05:04 +00:00
MillGame::log("[AI] successful move", LogSeverity::Debug);
2023-05-12 07:04:48 +00:00
if MillState::None != millstate {
2023-05-16 07:05:04 +00:00
MillGame::log("[AI] found a mill", LogSeverity::Debug);
2023-05-12 07:04:48 +00:00
found_a_mill = true;
}
2023-05-11 12:00:24 +00:00
2023-05-16 07:05:04 +00:00
successful_move = true;
} else {
MillGame::log("[AI] move failed", LogSeverity::Debug);
}
2023-05-11 12:00:24 +00:00
2023-05-16 07:05:04 +00:00
if successful_move {
break;
}
}
2023-05-10 18:05:12 +00:00
}
}
2023-05-16 07:05:04 +00:00
Ok(())
})?;
2023-05-10 18:05:12 +00:00
}
2023-05-11 12:00:24 +00:00
GameState::Waiting => unreachable!(),
2023-05-09 16:58:07 +00:00
}
2023-05-16 07:05:04 +00:00
if found_a_mill {
self.step(stones, board, scene, state)?;
}
2023-05-11 15:00:42 +00:00
MillGame::log("finish AI", LogSeverity::Debug);
2023-05-10 05:47:10 +00:00
2023-05-16 07:05:04 +00:00
Ok(())
2023-05-09 16:58:07 +00:00
}
}