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],
|
2025-03-25 11:07:45 +00:00
|
|
|
world: &mut World,
|
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-16 08:00:24 +00:00
|
|
|
GameState::Won(_) => (),
|
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
|
|
|
}
|
|
|
|
}
|