2023-05-09 16:58:07 +00:00
|
|
|
use crate::{
|
|
|
|
board::{BoardSlot, BoardSlotState},
|
2023-05-10 05:47:10 +00:00
|
|
|
game::{GameState, MillGame, 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-10 05:47:10 +00:00
|
|
|
state: GameState,
|
2023-05-09 16:58:07 +00:00
|
|
|
) -> Result<()> {
|
2023-05-10 05:47:10 +00:00
|
|
|
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()
|
2023-05-10 18:05:12 +00:00
|
|
|
.filter(|slot| *slot.state.lock().unwrap() == BoardSlotState::Empty)
|
2023-05-10 05:47:10 +00:00
|
|
|
.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()
|
2023-05-10 18:05:12 +00:00
|
|
|
.filter(
|
|
|
|
|slot| match (*slot.state.lock().unwrap(), 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();
|
|
|
|
|
|
|
|
let slot = &mut other_color[Random::range(0, len as u32) as usize];
|
|
|
|
|
|
|
|
scene.on_scene(|scene| {
|
|
|
|
MillGame::remove_stone(slot, scene)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
})?;
|
|
|
|
}
|
2023-05-10 18:05:12 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-05-09 16:58:07 +00:00
|
|
|
}
|
|
|
|
|
2023-05-10 05:47:10 +00:00
|
|
|
MillGame::log("finish AI");
|
|
|
|
|
2023-05-09 16:58:07 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|