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)
|
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)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
|
306
src/game.rs
306
src/game.rs
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicU32, Ordering::SeqCst},
|
atomic::{AtomicU32, Ordering::SeqCst},
|
||||||
Arc, Mutex,
|
Arc, Mutex, MutexGuard,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -28,6 +28,7 @@ pub struct Stone {
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||||
pub enum GameState {
|
pub enum GameState {
|
||||||
Placing,
|
Placing,
|
||||||
|
Removing,
|
||||||
Main,
|
Main,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,11 +38,26 @@ pub enum PlayerColor {
|
||||||
Black,
|
Black,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||||
|
pub enum MillState {
|
||||||
|
White,
|
||||||
|
Black,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
impl PlayerColor {
|
impl PlayerColor {
|
||||||
pub fn swap(&mut self) {
|
pub fn swap(&mut self) {
|
||||||
*self = match *self {
|
*self = match *self {
|
||||||
PlayerColor::White => PlayerColor::Black,
|
PlayerColor::White => {
|
||||||
PlayerColor::Black => 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() {
|
if let Some(me) = weak_self.upgrade() {
|
||||||
|
Self::log("start game");
|
||||||
|
|
||||||
*me.state.lock().unwrap() = GameState::Placing;
|
*me.state.lock().unwrap() = GameState::Placing;
|
||||||
*me.current_player.lock().unwrap() = PlayerColor::White;
|
*me.current_player.lock().unwrap() = PlayerColor::Black;
|
||||||
|
|
||||||
me.next_game_step()?;
|
me.next_game_step()?;
|
||||||
}
|
}
|
||||||
|
@ -210,22 +228,13 @@ impl MillGame {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_game_step(&self) -> Result<()> {
|
fn next_game_step(&self) -> Result<()> {
|
||||||
match *self.current_player.lock().unwrap() {
|
Self::log("next_game_step");
|
||||||
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)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
|
||||||
|
Self::log(&format!("\tstate: {:?}", state));
|
||||||
|
|
||||||
match *state {
|
match *state {
|
||||||
GameState::Placing => {
|
GameState::Placing => {
|
||||||
if !self
|
if !self
|
||||||
|
@ -241,34 +250,91 @@ impl MillGame {
|
||||||
.iter()
|
.iter()
|
||||||
.any(|stones| stones.state == StoneState::ReadyToBePlaced)
|
.any(|stones| stones.state == StoneState::ReadyToBePlaced)
|
||||||
{
|
{
|
||||||
|
Self::log("change state to Main");
|
||||||
*state = GameState::Main;
|
*state = GameState::Main;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
GameState::Main => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if *self.current_player.lock().unwrap() == self.simple_ai.player_color {
|
if self.check_for_mill() != MillState::None {
|
||||||
match self.simple_ai.player_color {
|
Self::log("change state to Removing");
|
||||||
PlayerColor::White => self.simple_ai.step(
|
*state = GameState::Removing;
|
||||||
&mut *self.white_stones.lock().unwrap(),
|
} else {
|
||||||
self.board.lock().unwrap().slots(),
|
self.current_player.lock().unwrap().swap();
|
||||||
&mut *self.scene.lock().unwrap(),
|
}
|
||||||
)?,
|
}
|
||||||
PlayerColor::Black => self.simple_ai.step(
|
GameState::Removing => {
|
||||||
&mut *self.black_stones.lock().unwrap(),
|
if !self
|
||||||
self.board.lock().unwrap().slots(),
|
.black_stones
|
||||||
&mut *self.scene.lock().unwrap(),
|
.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();
|
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()?;
|
self.next_game_step()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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]> {
|
fn init_nine_stones(engine: &Arc<Engine>, color: Color) -> Result<[EntityObject; 9]> {
|
||||||
Ok((0..9)
|
Ok((0..9)
|
||||||
.map(|_| Self::init_stone(engine, color))
|
.map(|_| Self::init_stone(engine, color))
|
||||||
|
@ -327,9 +393,19 @@ impl MillGame {
|
||||||
player_color: PlayerColor,
|
player_color: PlayerColor,
|
||||||
scene: &mut Scene,
|
scene: &mut Scene,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
Self::log("place_stone");
|
||||||
|
|
||||||
match player_color {
|
match player_color {
|
||||||
PlayerColor::White => slot.state = BoardSlotState::White(stone.stone),
|
PlayerColor::White => {
|
||||||
PlayerColor::Black => slot.state = BoardSlotState::Black(stone.stone),
|
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;
|
stone.state = StoneState::Placed;
|
||||||
|
@ -342,16 +418,115 @@ impl MillGame {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_for_mill(&self) -> Result<bool> {
|
pub fn remove_stone(slot: &mut BoardSlot, scene: &mut Scene) -> Result<()> {
|
||||||
let slots = self.board.lock().unwrap().slots();
|
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 x in 0..3 {
|
||||||
for y 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 {
|
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 {
|
EngineEvent::MouseButtonDown(button) => match button {
|
||||||
MouseButton::Left => {
|
MouseButton::Left => {
|
||||||
|
let state = *self.state.lock().unwrap();
|
||||||
|
Self::log(&format!("User click at state {:?}", state));
|
||||||
|
|
||||||
|
match state {
|
||||||
|
GameState::Placing => {
|
||||||
let mut placed = false;
|
let mut placed = false;
|
||||||
|
|
||||||
self.scene.lock().unwrap().on_scene(|scene| {
|
self.check_mouse_click(|me, slot, scene| {
|
||||||
if let Some(world_space) = scene.screen_space_to_world(
|
let current_player = *self.current_player.lock().unwrap();
|
||||||
self.mouse_x.load(SeqCst),
|
|
||||||
self.mouse_y.load(SeqCst),
|
|
||||||
)? {
|
|
||||||
if let Some(slot) = self
|
|
||||||
.board
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.close_to_marker(world_space.truncate())
|
|
||||||
{
|
|
||||||
if let Some(placable) = self
|
if let Some(placable) = self
|
||||||
.black_stones
|
.stones(current_player)
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.find(|stone| stone.state == StoneState::ReadyToBePlaced)
|
.find(|stone| stone.state == StoneState::ReadyToBePlaced)
|
||||||
{
|
{
|
||||||
Self::place_stone(placable, slot, PlayerColor::Black, scene)?;
|
Self::place_stone(placable, slot, current_player, scene)?;
|
||||||
|
|
||||||
placed = true;
|
placed = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if placed {
|
if placed {
|
||||||
self.current_player.lock().unwrap().swap();
|
|
||||||
self.next_game_step()?;
|
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::Middle => self.camera_controls.lock().unwrap().hold(),
|
||||||
MouseButton::Right => (),
|
MouseButton::Right => (),
|
||||||
MouseButton::Forward => (),
|
MouseButton::Forward => (),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
board::{BoardSlot, BoardSlotState},
|
board::{BoardSlot, BoardSlotState},
|
||||||
game::{MillGame, PlayerColor, Stone, StoneState},
|
game::{GameState, MillGame, PlayerColor, Stone, StoneState},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -20,7 +20,12 @@ impl SimpleAI {
|
||||||
stones: &mut [Stone; 9],
|
stones: &mut [Stone; 9],
|
||||||
board: &mut [[[BoardSlot; 3]; 3]; 3],
|
board: &mut [[[BoardSlot; 3]; 3]; 3],
|
||||||
scene: &mut SceneHandle,
|
scene: &mut SceneHandle,
|
||||||
|
state: GameState,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
MillGame::log(&format!("AI at state {:?}", state));
|
||||||
|
|
||||||
|
match state {
|
||||||
|
GameState::Placing => {
|
||||||
if let Some(placable) = stones
|
if let Some(placable) = stones
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.find(|stone| stone.state == StoneState::ReadyToBePlaced)
|
.find(|stone| stone.state == StoneState::ReadyToBePlaced)
|
||||||
|
@ -42,6 +47,33 @@ impl SimpleAI {
|
||||||
Ok(())
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue