Start removing state
This commit is contained in:
parent
686dae95bf
commit
7a41b66aa6
3 changed files with 321 additions and 75 deletions
18
src/board.rs
18
src/board.rs
|
@ -81,6 +81,24 @@ impl BoardSlot {
|
|||
|
||||
Ok(mesh)
|
||||
}
|
||||
|
||||
pub fn valid(&self) -> bool {
|
||||
self.state != BoardSlotState::Invalid
|
||||
}
|
||||
|
||||
pub fn white(&self) -> bool {
|
||||
match self.state {
|
||||
BoardSlotState::White(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn black(&self) -> bool {
|
||||
match self.state {
|
||||
BoardSlotState::Black(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
|
|
306
src/game.rs
306
src/game.rs
|
@ -1,6 +1,6 @@
|
|||
use std::sync::{
|
||||
atomic::{AtomicU32, Ordering::SeqCst},
|
||||
Arc, Mutex,
|
||||
Arc, Mutex, MutexGuard,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
|
@ -28,6 +28,7 @@ pub struct Stone {
|
|||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
pub enum GameState {
|
||||
Placing,
|
||||
Removing,
|
||||
Main,
|
||||
}
|
||||
|
||||
|
@ -37,11 +38,26 @@ pub enum PlayerColor {
|
|||
Black,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
pub enum MillState {
|
||||
White,
|
||||
Black,
|
||||
None,
|
||||
}
|
||||
|
||||
impl PlayerColor {
|
||||
pub fn swap(&mut self) {
|
||||
*self = match *self {
|
||||
PlayerColor::White => PlayerColor::Black,
|
||||
PlayerColor::Black => PlayerColor::White,
|
||||
PlayerColor::White => {
|
||||
MillGame::log("swapped to black player");
|
||||
|
||||
PlayerColor::Black
|
||||
}
|
||||
PlayerColor::Black => {
|
||||
MillGame::log("swapped to white player");
|
||||
|
||||
PlayerColor::White
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -196,8 +212,10 @@ impl MillGame {
|
|||
}
|
||||
|
||||
if let Some(me) = weak_self.upgrade() {
|
||||
Self::log("start game");
|
||||
|
||||
*me.state.lock().unwrap() = GameState::Placing;
|
||||
*me.current_player.lock().unwrap() = PlayerColor::White;
|
||||
*me.current_player.lock().unwrap() = PlayerColor::Black;
|
||||
|
||||
me.next_game_step()?;
|
||||
}
|
||||
|
@ -210,22 +228,13 @@ impl MillGame {
|
|||
}
|
||||
|
||||
fn next_game_step(&self) -> Result<()> {
|
||||
match *self.current_player.lock().unwrap() {
|
||||
PlayerColor::White => {
|
||||
self.black_player_label
|
||||
.set_background(Color::try_from("#9b9292")?)?;
|
||||
self.white_player_label.set_background(Color::Yellow)?;
|
||||
}
|
||||
PlayerColor::Black => {
|
||||
self.white_player_label
|
||||
.set_background(Color::try_from("#9b9292")?)?;
|
||||
self.black_player_label.set_background(Color::Yellow)?;
|
||||
}
|
||||
}
|
||||
Self::log("next_game_step");
|
||||
|
||||
{
|
||||
let mut state = self.state.lock().unwrap();
|
||||
|
||||
Self::log(&format!("\tstate: {:?}", state));
|
||||
|
||||
match *state {
|
||||
GameState::Placing => {
|
||||
if !self
|
||||
|
@ -241,34 +250,91 @@ impl MillGame {
|
|||
.iter()
|
||||
.any(|stones| stones.state == StoneState::ReadyToBePlaced)
|
||||
{
|
||||
Self::log("change state to Main");
|
||||
*state = GameState::Main;
|
||||
}
|
||||
}
|
||||
GameState::Main => {}
|
||||
}
|
||||
}
|
||||
|
||||
if *self.current_player.lock().unwrap() == self.simple_ai.player_color {
|
||||
match self.simple_ai.player_color {
|
||||
PlayerColor::White => self.simple_ai.step(
|
||||
&mut *self.white_stones.lock().unwrap(),
|
||||
self.board.lock().unwrap().slots(),
|
||||
&mut *self.scene.lock().unwrap(),
|
||||
)?,
|
||||
PlayerColor::Black => self.simple_ai.step(
|
||||
&mut *self.black_stones.lock().unwrap(),
|
||||
self.board.lock().unwrap().slots(),
|
||||
&mut *self.scene.lock().unwrap(),
|
||||
)?,
|
||||
if self.check_for_mill() != MillState::None {
|
||||
Self::log("change state to Removing");
|
||||
*state = GameState::Removing;
|
||||
} else {
|
||||
self.current_player.lock().unwrap().swap();
|
||||
}
|
||||
}
|
||||
GameState::Removing => {
|
||||
if !self
|
||||
.black_stones
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|stones| stones.state == StoneState::ReadyToBePlaced)
|
||||
&& !self
|
||||
.white_stones
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|stones| stones.state == StoneState::ReadyToBePlaced)
|
||||
{
|
||||
Self::log("change state to Main");
|
||||
*state = GameState::Main;
|
||||
} else {
|
||||
Self::log("change state to Placing");
|
||||
*state = GameState::Placing;
|
||||
}
|
||||
|
||||
self.current_player.lock().unwrap().swap();
|
||||
}
|
||||
GameState::Main => {
|
||||
if self.check_for_mill() != MillState::None {
|
||||
Self::log("change state to Removing");
|
||||
*state = GameState::Removing;
|
||||
} else {
|
||||
self.current_player.lock().unwrap().swap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let player = *self.current_player.lock().unwrap();
|
||||
|
||||
Self::log(&format!("current player {:?}", player));
|
||||
|
||||
match player {
|
||||
PlayerColor::White => {
|
||||
self.black_player_label
|
||||
.set_background(Color::try_from("#9b9292")?)?;
|
||||
self.white_player_label.set_background(Color::Yellow)?;
|
||||
}
|
||||
PlayerColor::Black => {
|
||||
self.white_player_label
|
||||
.set_background(Color::try_from("#9b9292")?)?;
|
||||
self.black_player_label.set_background(Color::Yellow)?;
|
||||
}
|
||||
}
|
||||
|
||||
if player == self.simple_ai.player_color {
|
||||
Self::log("current player is AI");
|
||||
|
||||
self.simple_ai.step(
|
||||
&mut self.stones(self.simple_ai.player_color),
|
||||
self.board.lock().unwrap().slots(),
|
||||
&mut *self.scene.lock().unwrap(),
|
||||
*self.state.lock().unwrap(),
|
||||
)?;
|
||||
|
||||
self.next_game_step()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stones(&self, player_color: PlayerColor) -> MutexGuard<'_, [Stone; 9]> {
|
||||
match player_color {
|
||||
PlayerColor::White => self.white_stones.lock().unwrap(),
|
||||
PlayerColor::Black => self.black_stones.lock().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn init_nine_stones(engine: &Arc<Engine>, color: Color) -> Result<[EntityObject; 9]> {
|
||||
Ok((0..9)
|
||||
.map(|_| Self::init_stone(engine, color))
|
||||
|
@ -327,9 +393,19 @@ impl MillGame {
|
|||
player_color: PlayerColor,
|
||||
scene: &mut Scene,
|
||||
) -> Result<()> {
|
||||
Self::log("place_stone");
|
||||
|
||||
match player_color {
|
||||
PlayerColor::White => slot.state = BoardSlotState::White(stone.stone),
|
||||
PlayerColor::Black => slot.state = BoardSlotState::Black(stone.stone),
|
||||
PlayerColor::White => {
|
||||
Self::log(&format!("place white stone"));
|
||||
|
||||
slot.state = BoardSlotState::White(stone.stone);
|
||||
}
|
||||
PlayerColor::Black => {
|
||||
Self::log(&format!("place black stone"));
|
||||
|
||||
slot.state = BoardSlotState::Black(stone.stone);
|
||||
}
|
||||
}
|
||||
|
||||
stone.state = StoneState::Placed;
|
||||
|
@ -342,16 +418,115 @@ impl MillGame {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_for_mill(&self) -> Result<bool> {
|
||||
let slots = self.board.lock().unwrap().slots();
|
||||
pub fn remove_stone(slot: &mut BoardSlot, scene: &mut Scene) -> Result<()> {
|
||||
Self::log("remove_stone");
|
||||
|
||||
let entity = match slot.state {
|
||||
BoardSlotState::Black(e) => {
|
||||
Self::log(&format!("\tremove black stone"));
|
||||
|
||||
e
|
||||
}
|
||||
BoardSlotState::White(e) => {
|
||||
Self::log(&format!("\tremove white stone"));
|
||||
|
||||
e
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
scene.remove_entity(entity)?;
|
||||
|
||||
slot.state = BoardSlotState::Empty;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_mill(s1: &BoardSlot, s2: &BoardSlot, s3: &BoardSlot) -> MillState {
|
||||
if s1.valid() && s2.valid() && s3.valid() {
|
||||
if s1.white() && s2.white() && s3.white() {
|
||||
return MillState::White;
|
||||
} else if s1.black() && s2.black() && s3.black() {
|
||||
return MillState::Black;
|
||||
}
|
||||
}
|
||||
|
||||
MillState::None
|
||||
}
|
||||
|
||||
pub fn check_for_mill(&self) -> MillState {
|
||||
Self::log("check for mill");
|
||||
|
||||
let mut board = self.board.lock().unwrap();
|
||||
let slots = board.slots();
|
||||
|
||||
for x in 0..3 {
|
||||
for y in 0..3 {
|
||||
let state = Self::check_mill(&slots[x][y][0], &slots[x][y][1], &slots[x][y][2]);
|
||||
|
||||
if state != MillState::None {
|
||||
Self::log(&format!("mill found {:?}", state));
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for x in 0..3 {
|
||||
for z in 0..3 {
|
||||
//
|
||||
let state = Self::check_mill(&slots[x][0][z], &slots[x][1][z], &slots[x][2][z]);
|
||||
|
||||
if state != MillState::None {
|
||||
Self::log(&format!("mill found {:?}", state));
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for y in 0..3 {
|
||||
for z in 0..3 {
|
||||
let state = Self::check_mill(&slots[0][y][z], &slots[1][y][z], &slots[2][y][z]);
|
||||
|
||||
if state != MillState::None {
|
||||
Self::log(&format!("mill found {:?}", state));
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MillState::None
|
||||
}
|
||||
|
||||
fn check_mouse_click<F>(&self, f: F) -> Result<()>
|
||||
where
|
||||
F: FnOnce(&Self, &mut BoardSlot, &mut Scene) -> Result<()>,
|
||||
{
|
||||
Self::log("check_mouse_click");
|
||||
|
||||
self.scene.lock().unwrap().on_scene(|scene| {
|
||||
if let Some(world_space) =
|
||||
scene.screen_space_to_world(self.mouse_x.load(SeqCst), self.mouse_y.load(SeqCst))?
|
||||
{
|
||||
if let Some(slot) = self
|
||||
.board
|
||||
.lock()
|
||||
.unwrap()
|
||||
.close_to_marker(world_space.truncate())
|
||||
{
|
||||
Self::log("click is close to marker");
|
||||
|
||||
f(self, slot, scene)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn log(s: &str) {
|
||||
println!("{}", s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,41 +553,62 @@ impl EngineObject for MillGame {
|
|||
}
|
||||
EngineEvent::MouseButtonDown(button) => match button {
|
||||
MouseButton::Left => {
|
||||
let state = *self.state.lock().unwrap();
|
||||
Self::log(&format!("User click at state {:?}", state));
|
||||
|
||||
match state {
|
||||
GameState::Placing => {
|
||||
let mut placed = false;
|
||||
|
||||
self.scene.lock().unwrap().on_scene(|scene| {
|
||||
if let Some(world_space) = scene.screen_space_to_world(
|
||||
self.mouse_x.load(SeqCst),
|
||||
self.mouse_y.load(SeqCst),
|
||||
)? {
|
||||
if let Some(slot) = self
|
||||
.board
|
||||
.lock()
|
||||
.unwrap()
|
||||
.close_to_marker(world_space.truncate())
|
||||
{
|
||||
self.check_mouse_click(|me, slot, scene| {
|
||||
let current_player = *self.current_player.lock().unwrap();
|
||||
|
||||
if let Some(placable) = self
|
||||
.black_stones
|
||||
.lock()
|
||||
.unwrap()
|
||||
.stones(current_player)
|
||||
.iter_mut()
|
||||
.find(|stone| stone.state == StoneState::ReadyToBePlaced)
|
||||
{
|
||||
Self::place_stone(placable, slot, PlayerColor::Black, scene)?;
|
||||
Self::place_stone(placable, slot, current_player, scene)?;
|
||||
|
||||
placed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
if placed {
|
||||
self.current_player.lock().unwrap().swap();
|
||||
self.next_game_step()?;
|
||||
}
|
||||
}
|
||||
GameState::Removing => {
|
||||
let mut removed = false;
|
||||
|
||||
self.check_mouse_click(|me, slot, scene| {
|
||||
Self::log(&format!(
|
||||
"state {:?} - player {:?}",
|
||||
slot.state,
|
||||
*self.current_player.lock().unwrap()
|
||||
));
|
||||
|
||||
if match (slot.state, *self.current_player.lock().unwrap()) {
|
||||
(BoardSlotState::Black(_), PlayerColor::White) => true,
|
||||
(BoardSlotState::White(_), PlayerColor::Black) => true,
|
||||
_ => false,
|
||||
} {
|
||||
removed = true;
|
||||
Self::remove_stone(slot, scene)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
if removed {
|
||||
self.next_game_step()?;
|
||||
}
|
||||
}
|
||||
GameState::Main => todo!(),
|
||||
}
|
||||
}
|
||||
MouseButton::Middle => self.camera_controls.lock().unwrap().hold(),
|
||||
MouseButton::Right => (),
|
||||
MouseButton::Forward => (),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
board::{BoardSlot, BoardSlotState},
|
||||
game::{MillGame, PlayerColor, Stone, StoneState},
|
||||
game::{GameState, MillGame, PlayerColor, Stone, StoneState},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
|
@ -20,7 +20,12 @@ impl SimpleAI {
|
|||
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)
|
||||
|
@ -42,6 +47,33 @@ impl SimpleAI {
|
|||
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 other_color[Random::range(0, len as u32) as usize];
|
||||
|
||||
scene.on_scene(|scene| {
|
||||
MillGame::remove_stone(slot, scene)?;
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
GameState::Main => todo!(),
|
||||
}
|
||||
|
||||
MillGame::log("finish AI");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue