Implement major part of main game
This commit is contained in:
parent
2720750829
commit
a83c3a4ab6
4 changed files with 435 additions and 190 deletions
26
.vscode/launch.json
vendored
Normal file
26
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug executable 'mill_game'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=mill_game",
|
||||||
|
"--package=mill_game"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "mill_game",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
83
src/board.rs
83
src/board.rs
|
@ -14,7 +14,7 @@ pub struct BoardSlot {
|
||||||
pub y: usize,
|
pub y: usize,
|
||||||
pub z: usize,
|
pub z: usize,
|
||||||
|
|
||||||
pub state: Mutex<BoardSlotState>,
|
state: Mutex<BoardSlotState>,
|
||||||
pub position: Vector2<f32>,
|
pub position: Vector2<f32>,
|
||||||
pub slot_marker: Option<Entity>,
|
pub slot_marker: Option<Entity>,
|
||||||
}
|
}
|
||||||
|
@ -100,10 +100,22 @@ impl BoardSlot {
|
||||||
Ok(mesh)
|
Ok(mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn state(&self) -> BoardSlotState {
|
||||||
|
*self.state.lock().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_state(&self, state: BoardSlotState) {
|
||||||
|
*self.state.lock().unwrap() = state;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn valid(&self) -> bool {
|
pub fn valid(&self) -> bool {
|
||||||
*self.state.lock().unwrap() != BoardSlotState::Invalid
|
*self.state.lock().unwrap() != BoardSlotState::Invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
*self.state.lock().unwrap() == BoardSlotState::Empty
|
||||||
|
}
|
||||||
|
|
||||||
pub fn white(&self) -> bool {
|
pub fn white(&self) -> bool {
|
||||||
match *self.state.lock().unwrap() {
|
match *self.state.lock().unwrap() {
|
||||||
BoardSlotState::White(_) => true,
|
BoardSlotState::White(_) => true,
|
||||||
|
@ -290,6 +302,75 @@ impl Board {
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_neighbours<'a>(
|
||||||
|
slot: &BoardSlot,
|
||||||
|
board: &'a [[[BoardSlot; 3]; 3]; 3],
|
||||||
|
) -> Vec<&'a BoardSlot> {
|
||||||
|
let mut neighbours = Vec::new();
|
||||||
|
|
||||||
|
for i in 0..6 {
|
||||||
|
// find free neighbour field
|
||||||
|
if let Some(neighbour) = match i {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => unreachable!(),
|
||||||
|
} {
|
||||||
|
let neighbour_state = neighbour.state.lock().unwrap();
|
||||||
|
|
||||||
|
match *neighbour_state {
|
||||||
|
BoardSlotState::Empty => {
|
||||||
|
neighbours.push(neighbour);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
neighbours
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Board {
|
impl Board {
|
||||||
|
|
333
src/game.rs
333
src/game.rs
|
@ -27,6 +27,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 {
|
||||||
|
Waiting,
|
||||||
Placing,
|
Placing,
|
||||||
Removing,
|
Removing,
|
||||||
Main,
|
Main,
|
||||||
|
@ -60,6 +61,13 @@ impl PlayerColor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn other(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
PlayerColor::White => PlayerColor::Black,
|
||||||
|
PlayerColor::Black => PlayerColor::White,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MillGame {
|
pub struct MillGame {
|
||||||
|
@ -78,6 +86,8 @@ pub struct MillGame {
|
||||||
|
|
||||||
turn_finished: AtomicBool,
|
turn_finished: AtomicBool,
|
||||||
|
|
||||||
|
selected_field: Mutex<Option<(usize, usize, usize)>>,
|
||||||
|
|
||||||
simple_ai: SimpleAI,
|
simple_ai: SimpleAI,
|
||||||
|
|
||||||
white_player_label: Arc<Label>,
|
white_player_label: Arc<Label>,
|
||||||
|
@ -185,7 +195,7 @@ impl MillGame {
|
||||||
white_stones: Mutex::new(white_stones.unwrap()),
|
white_stones: Mutex::new(white_stones.unwrap()),
|
||||||
black_stones: Mutex::new(black_stones.unwrap()),
|
black_stones: Mutex::new(black_stones.unwrap()),
|
||||||
|
|
||||||
state: Mutex::new(GameState::Placing),
|
state: Mutex::new(GameState::Waiting),
|
||||||
current_player: Mutex::new(PlayerColor::White),
|
current_player: Mutex::new(PlayerColor::White),
|
||||||
|
|
||||||
scene: Mutex::new(scene),
|
scene: Mutex::new(scene),
|
||||||
|
@ -196,6 +206,8 @@ impl MillGame {
|
||||||
|
|
||||||
turn_finished: AtomicBool::new(false),
|
turn_finished: AtomicBool::new(false),
|
||||||
|
|
||||||
|
selected_field: Mutex::default(),
|
||||||
|
|
||||||
simple_ai: SimpleAI::new(PlayerColor::White),
|
simple_ai: SimpleAI::new(PlayerColor::White),
|
||||||
|
|
||||||
grid: grid.clone(),
|
grid: grid.clone(),
|
||||||
|
@ -233,7 +245,7 @@ impl MillGame {
|
||||||
|
|
||||||
pub fn finish_turn(&self) {
|
pub fn finish_turn(&self) {
|
||||||
Self::log(&format!(
|
Self::log(&format!(
|
||||||
"{:?} finised turn",
|
"{:?} finished turn",
|
||||||
*self.current_player.lock().unwrap()
|
*self.current_player.lock().unwrap()
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -241,12 +253,10 @@ impl MillGame {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_game_step(&self) -> Result<()> {
|
fn next_game_step(&self) -> Result<()> {
|
||||||
Self::log("next_game_step");
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
|
||||||
Self::log(&format!("\tstate: {:?}", state));
|
Self::log(&format!(" ===== NEW TURN ({:?}) =====", state));
|
||||||
|
|
||||||
match *state {
|
match *state {
|
||||||
GameState::Placing => {
|
GameState::Placing => {
|
||||||
|
@ -295,6 +305,7 @@ impl MillGame {
|
||||||
GameState::Main => {
|
GameState::Main => {
|
||||||
self.current_player.lock().unwrap().swap();
|
self.current_player.lock().unwrap().swap();
|
||||||
}
|
}
|
||||||
|
GameState::Waiting => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,14 +329,14 @@ impl MillGame {
|
||||||
if player == self.simple_ai.player_color {
|
if player == self.simple_ai.player_color {
|
||||||
Self::log("current player is AI");
|
Self::log("current player is AI");
|
||||||
|
|
||||||
self.simple_ai.step(
|
if !self.simple_ai.step(
|
||||||
&mut self.stones(self.simple_ai.player_color),
|
&mut self.stones(self.simple_ai.player_color),
|
||||||
self.board.lock().unwrap().slots(),
|
self.board.lock().unwrap().slots(),
|
||||||
&mut *self.scene.lock().unwrap(),
|
&mut *self.scene.lock().unwrap(),
|
||||||
*self.state.lock().unwrap(),
|
&mut *self.state.lock().unwrap(),
|
||||||
)?;
|
)? {
|
||||||
|
self.finish_turn();
|
||||||
self.finish_turn();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::log("leave next_game_step");
|
Self::log("leave next_game_step");
|
||||||
|
@ -360,7 +371,7 @@ impl MillGame {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let vertex_buffer = Buffer::builder()
|
let vertex_buffer = Buffer::builder()
|
||||||
.set_data(&Objects::create_cylinder(1.0, 0.25, 12))
|
.set_data(&Objects::create_cylinder(1.1, 0.25, 30))
|
||||||
.set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
|
.set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
|
||||||
.set_memory_usage(MemoryUsage::CpuOnly)
|
.set_memory_usage(MemoryUsage::CpuOnly)
|
||||||
.build(engine.device().clone())?;
|
.build(engine.device().clone())?;
|
||||||
|
@ -394,22 +405,26 @@ impl MillGame {
|
||||||
|
|
||||||
pub fn place_stone(
|
pub fn place_stone(
|
||||||
stone: &mut Stone,
|
stone: &mut Stone,
|
||||||
slot: &mut BoardSlot,
|
(x, y, z): (usize, usize, usize),
|
||||||
|
board: &mut [[[BoardSlot; 3]; 3]; 3],
|
||||||
player_color: PlayerColor,
|
player_color: PlayerColor,
|
||||||
scene: &mut Scene,
|
scene: &mut Scene,
|
||||||
) -> Result<()> {
|
state: &mut GameState,
|
||||||
|
) -> Result<MillState> {
|
||||||
Self::log("place_stone");
|
Self::log("place_stone");
|
||||||
|
|
||||||
|
let slot = &board[x][y][z];
|
||||||
|
|
||||||
match player_color {
|
match player_color {
|
||||||
PlayerColor::White => {
|
PlayerColor::White => {
|
||||||
Self::log(&format!("place white stone"));
|
Self::log(&format!("place white stone"));
|
||||||
|
|
||||||
*slot.state.lock().unwrap() = BoardSlotState::White(stone.stone);
|
slot.set_state(BoardSlotState::White(stone.stone));
|
||||||
}
|
}
|
||||||
PlayerColor::Black => {
|
PlayerColor::Black => {
|
||||||
Self::log(&format!("place black stone"));
|
Self::log(&format!("place black stone"));
|
||||||
|
|
||||||
*slot.state.lock().unwrap() = BoardSlotState::Black(stone.stone);
|
slot.set_state(BoardSlotState::Black(stone.stone));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,13 +435,67 @@ impl MillGame {
|
||||||
let location = entity.get_component_mut::<Location>()?;
|
let location = entity.get_component_mut::<Location>()?;
|
||||||
location.set_position(slot.position.extend(0.0));
|
location.set_position(slot.position.extend(0.0));
|
||||||
|
|
||||||
Ok(())
|
let millstate = Self::check_for_mill(&board[x][y][z], board);
|
||||||
|
|
||||||
|
if millstate != MillState::None {
|
||||||
|
*state = GameState::Removing;
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::log(&format!("return place stone with {:?}", millstate));
|
||||||
|
|
||||||
|
Ok(millstate)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_stone(slot: &mut BoardSlot, scene: &mut Scene) -> Result<()> {
|
pub fn move_stone(
|
||||||
|
(x, y, z): (usize, usize, usize),
|
||||||
|
(tx, ty, tz): (usize, usize, usize),
|
||||||
|
scene: &mut Scene,
|
||||||
|
board: &mut [[[BoardSlot; 3]; 3]; 3],
|
||||||
|
state: &mut GameState,
|
||||||
|
) -> Result<MillState> {
|
||||||
|
Self::log(&format!(
|
||||||
|
"move stone ({:?}) to ({:?})",
|
||||||
|
(x, y, z),
|
||||||
|
(tx, ty, tz)
|
||||||
|
));
|
||||||
|
|
||||||
|
let slot = &board[x][y][z];
|
||||||
|
let neighbour = &board[tx][ty][tz];
|
||||||
|
|
||||||
|
if neighbour.state() != BoardSlotState::Empty {
|
||||||
|
Self::log("neighbour not empty");
|
||||||
|
return Ok(MillState::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
neighbour.set_state(slot.state());
|
||||||
|
slot.set_state(BoardSlotState::Empty);
|
||||||
|
|
||||||
|
scene
|
||||||
|
.entity_mut(match neighbour.state() {
|
||||||
|
BoardSlotState::Black(e) => e,
|
||||||
|
BoardSlotState::White(e) => e,
|
||||||
|
|
||||||
|
_ => unreachable!(),
|
||||||
|
})?
|
||||||
|
.get_component_mut::<Location>()?
|
||||||
|
.set_position(neighbour.position.extend(0.0));
|
||||||
|
|
||||||
|
let millstate = Self::check_for_mill(&board[tx][ty][tz], board);
|
||||||
|
|
||||||
|
if millstate != MillState::None {
|
||||||
|
Self::log("mill found!");
|
||||||
|
*state = GameState::Removing;
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::log(&format!("return move stone with {:?}", millstate));
|
||||||
|
|
||||||
|
Ok(millstate)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_stone(stone: &mut Stone, slot: &mut BoardSlot, scene: &mut Scene) -> Result<()> {
|
||||||
Self::log("remove_stone");
|
Self::log("remove_stone");
|
||||||
|
|
||||||
let entity = match *slot.state.lock().unwrap() {
|
let entity = match slot.state() {
|
||||||
BoardSlotState::Black(e) => {
|
BoardSlotState::Black(e) => {
|
||||||
Self::log(&format!("\tremove black stone"));
|
Self::log(&format!("\tremove black stone"));
|
||||||
|
|
||||||
|
@ -441,9 +510,11 @@ impl MillGame {
|
||||||
};
|
};
|
||||||
|
|
||||||
scene.remove_entity(entity)?;
|
scene.remove_entity(entity)?;
|
||||||
Self::log("\t -> TODO: set stone state to Dead");
|
|
||||||
|
|
||||||
*slot.state.lock().unwrap() = BoardSlotState::Empty;
|
assert_ne!(stone.state, StoneState::Dead);
|
||||||
|
stone.state = StoneState::Dead;
|
||||||
|
|
||||||
|
slot.set_state(BoardSlotState::Empty);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -460,19 +531,25 @@ impl MillGame {
|
||||||
MillState::None
|
MillState::None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_for_mill(&self, slot: &BoardSlot, board: &[[[BoardSlot; 3]; 3]; 3]) -> MillState {
|
pub fn check_for_mill(slot: &BoardSlot, board: &[[[BoardSlot; 3]; 3]; 3]) -> MillState {
|
||||||
Self::log("check for mill");
|
Self::log("check for mill");
|
||||||
|
|
||||||
let state = Self::check_mill(
|
if !(slot.x == 0 && slot.y == 0)
|
||||||
&board[slot.x][slot.y][0],
|
&& !(slot.x == 2 && slot.y == 0)
|
||||||
&board[slot.x][slot.y][1],
|
&& !(slot.x == 0 && slot.y == 2)
|
||||||
&board[slot.x][slot.y][2],
|
&& !(slot.x == 2 && slot.y == 2)
|
||||||
);
|
{
|
||||||
|
let state = Self::check_mill(
|
||||||
|
&board[slot.x][slot.y][0],
|
||||||
|
&board[slot.x][slot.y][1],
|
||||||
|
&board[slot.x][slot.y][2],
|
||||||
|
);
|
||||||
|
|
||||||
if state != MillState::None {
|
if state != MillState::None {
|
||||||
Self::log(&format!("mill found {:?}", state));
|
Self::log(&format!("mill found {:?}", state));
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = Self::check_mill(
|
let state = Self::check_mill(
|
||||||
|
@ -530,6 +607,21 @@ impl MillGame {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_neighbour((x, y, z): (usize, usize, usize), (tx, ty, tz): (usize, usize, usize)) -> bool {
|
||||||
|
if (x == tx && y == ty)
|
||||||
|
&& ((x == 0 && y == 0)
|
||||||
|
|| (x == 2 && y == 0)
|
||||||
|
|| (x == 0 && y == 2)
|
||||||
|
|| (x == 2 && y == 2))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
(x as i32 - tx as i32).abs() == 1
|
||||||
|
|| (y as i32 - ty as i32).abs() == 1
|
||||||
|
|| (z as i32 - tz as i32).abs() == 1
|
||||||
|
}
|
||||||
|
|
||||||
pub fn log(s: &str) {
|
pub fn log(s: &str) {
|
||||||
println!("{}", s);
|
println!("{}", s);
|
||||||
}
|
}
|
||||||
|
@ -561,86 +653,141 @@ impl EngineObject for MillGame {
|
||||||
&mut *self.scene.lock().unwrap(),
|
&mut *self.scene.lock().unwrap(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
EngineEvent::MouseButtonDown(button) => match button {
|
EngineEvent::MouseButtonDown(button) => {
|
||||||
MouseButton::Left => {
|
match button {
|
||||||
let mut state = self.state.lock().unwrap();
|
MouseButton::Left => {
|
||||||
Self::log(&format!("User click at state {:?}", state));
|
let mut state = self.state.lock().unwrap();
|
||||||
|
Self::log(&format!("User click at state {:?}", state));
|
||||||
|
|
||||||
match *state {
|
match *state {
|
||||||
GameState::Placing => {
|
GameState::Placing => {
|
||||||
let mut placed = false;
|
let mut placed = false;
|
||||||
let mut mill_found = false;
|
let mut mill_found = false;
|
||||||
|
|
||||||
self.check_mouse_click(|me, (x, y, z), board, scene| {
|
self.check_mouse_click(|me, (x, y, z), board, scene| {
|
||||||
let current_player = *self.current_player.lock().unwrap();
|
let current_player = *self.current_player.lock().unwrap();
|
||||||
|
|
||||||
if let Some(placable) = self
|
if let Some(placable) = self
|
||||||
.stones(current_player)
|
.stones(current_player)
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.find(|stone| stone.state == StoneState::ReadyToBePlaced)
|
.find(|stone| stone.state == StoneState::ReadyToBePlaced)
|
||||||
{
|
|
||||||
Self::place_stone(
|
|
||||||
placable,
|
|
||||||
&mut board[x][y][z],
|
|
||||||
current_player,
|
|
||||||
scene,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if me.check_for_mill(&board[x][y][z], board) != MillState::None
|
|
||||||
{
|
{
|
||||||
mill_found = true;
|
if board[x][y][z].is_empty() {
|
||||||
*state = GameState::Removing;
|
if Self::place_stone(
|
||||||
|
placable,
|
||||||
|
(x, y, z),
|
||||||
|
board,
|
||||||
|
current_player,
|
||||||
|
scene,
|
||||||
|
&mut *state,
|
||||||
|
)? != MillState::None
|
||||||
|
{
|
||||||
|
mill_found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
placed = true;
|
||||||
|
} else {
|
||||||
|
Self::log(&format!(
|
||||||
|
"slot ({:?}), not empty ({:?})",
|
||||||
|
(x, y, z),
|
||||||
|
board[x][y][z].state()
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
placed = true;
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if placed && !mill_found {
|
||||||
|
self.finish_turn();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if placed && !mill_found {
|
|
||||||
self.finish_turn();
|
|
||||||
}
|
}
|
||||||
}
|
GameState::Removing => {
|
||||||
GameState::Removing => {
|
let mut removed = false;
|
||||||
let mut removed = false;
|
|
||||||
|
|
||||||
self.check_mouse_click(|me, (x, y, z), board, scene| {
|
self.check_mouse_click(|me, (x, y, z), board, scene| {
|
||||||
let slot = &mut board[x][y][z];
|
let slot = &mut board[x][y][z];
|
||||||
|
|
||||||
Self::log(&format!(
|
Self::log(&format!(
|
||||||
"state {:?} - player {:?}",
|
"state {:?} - player {:?}",
|
||||||
slot.state,
|
slot.state(),
|
||||||
*self.current_player.lock().unwrap()
|
*self.current_player.lock().unwrap()
|
||||||
));
|
));
|
||||||
|
|
||||||
if match (
|
if match (slot.state(), *self.current_player.lock().unwrap()) {
|
||||||
*slot.state.lock().unwrap(),
|
(BoardSlotState::Black(_), PlayerColor::White) => true,
|
||||||
*self.current_player.lock().unwrap(),
|
(BoardSlotState::White(_), PlayerColor::Black) => true,
|
||||||
) {
|
_ => false,
|
||||||
(BoardSlotState::Black(_), PlayerColor::White) => true,
|
} {
|
||||||
(BoardSlotState::White(_), PlayerColor::Black) => true,
|
let mut stones = self
|
||||||
_ => false,
|
.stones(self.current_player.lock().unwrap().other());
|
||||||
} {
|
|
||||||
removed = true;
|
let stone = stones
|
||||||
Self::remove_stone(slot, scene)?;
|
.iter_mut()
|
||||||
|
.find(|s| {
|
||||||
|
s.stone
|
||||||
|
== match slot.state() {
|
||||||
|
BoardSlotState::Black(e) => e,
|
||||||
|
BoardSlotState::White(e) => e,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Self::remove_stone(stone, slot, scene)?;
|
||||||
|
|
||||||
|
removed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if removed {
|
||||||
|
self.finish_turn();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if removed {
|
|
||||||
self.finish_turn();
|
|
||||||
}
|
}
|
||||||
|
GameState::Main => {
|
||||||
|
self.check_mouse_click(|me, (tx, ty, tz), board, scene| {
|
||||||
|
let mut selected_slot = me.selected_field.lock().unwrap();
|
||||||
|
|
||||||
|
match *selected_slot {
|
||||||
|
Some((x, y, z)) => {
|
||||||
|
if Self::is_neighbour((x, y, z), (tx, ty, tz)) {
|
||||||
|
if Self::move_stone((x,y,z), (tx,ty,tz), scene, board, &mut state)? == MillState::None {
|
||||||
|
*selected_slot = None;
|
||||||
|
self.finish_turn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let slot = &board[tx][ty][tz];
|
||||||
|
|
||||||
|
match (
|
||||||
|
slot.state(),
|
||||||
|
*me.current_player.lock().unwrap(),
|
||||||
|
) {
|
||||||
|
(BoardSlotState::Black(_), PlayerColor::Black)
|
||||||
|
| (BoardSlotState::White(_), PlayerColor::White) => {
|
||||||
|
*selected_slot = Some((tx, ty, tz));
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
GameState::Waiting => (),
|
||||||
}
|
}
|
||||||
GameState::Main => todo!(),
|
|
||||||
}
|
}
|
||||||
|
MouseButton::Middle => self.camera_controls.lock().unwrap().hold(),
|
||||||
|
MouseButton::Right => (),
|
||||||
|
MouseButton::Forward => (),
|
||||||
|
MouseButton::Backward => (),
|
||||||
}
|
}
|
||||||
MouseButton::Middle => self.camera_controls.lock().unwrap().hold(),
|
}
|
||||||
MouseButton::Right => (),
|
|
||||||
MouseButton::Forward => (),
|
|
||||||
MouseButton::Backward => (),
|
|
||||||
},
|
|
||||||
EngineEvent::MouseButtonUp(button) => match button {
|
EngineEvent::MouseButtonUp(button) => match button {
|
||||||
MouseButton::Left => (),
|
MouseButton::Left => (),
|
||||||
MouseButton::Middle => self.camera_controls.lock().unwrap().release(),
|
MouseButton::Middle => self.camera_controls.lock().unwrap().release(),
|
||||||
|
|
183
src/simple_ai.rs
183
src/simple_ai.rs
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
board::{BoardSlot, BoardSlotState},
|
board::{Board, BoardSlot, BoardSlotState},
|
||||||
game::{GameState, MillGame, PlayerColor, Stone, StoneState},
|
game::{GameState, MillGame, MillState, PlayerColor, Stone, StoneState},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -20,29 +20,45 @@ 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,
|
state: &mut GameState,
|
||||||
) -> Result<()> {
|
) -> Result<bool> {
|
||||||
MillGame::log(&format!("AI at state {:?}", state));
|
MillGame::log(&format!("AI at state {:?}", *state));
|
||||||
|
|
||||||
match state {
|
let mut found_a_mill = false;
|
||||||
|
|
||||||
|
match *state {
|
||||||
GameState::Placing => {
|
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)
|
||||||
{
|
{
|
||||||
let mut free_slots: Vec<&mut BoardSlot> = board
|
let (x, y, z) = {
|
||||||
.iter_mut()
|
let free_slots: Vec<&BoardSlot> = board
|
||||||
.flatten()
|
.iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.filter(|slot| *slot.state.lock().unwrap() == BoardSlotState::Empty)
|
.flatten()
|
||||||
.collect();
|
.filter(|slot| slot.state() == BoardSlotState::Empty)
|
||||||
|
.collect();
|
||||||
|
|
||||||
let len = free_slots.len();
|
let len = free_slots.len();
|
||||||
|
|
||||||
let slot = &mut free_slots[Random::range(0, len as u32) as usize];
|
let slot = &free_slots[Random::range(0, len as u32) as usize];
|
||||||
|
|
||||||
|
(slot.x, slot.y, slot.z)
|
||||||
|
};
|
||||||
|
|
||||||
scene.on_scene(|scene| {
|
scene.on_scene(|scene| {
|
||||||
MillGame::place_stone(placable, slot, self.player_color, scene)?;
|
if MillGame::place_stone(
|
||||||
|
placable,
|
||||||
|
(x, y, z),
|
||||||
|
board,
|
||||||
|
self.player_color,
|
||||||
|
scene,
|
||||||
|
state,
|
||||||
|
)? != MillState::None
|
||||||
|
{
|
||||||
|
found_a_mill = true;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
@ -53,115 +69,90 @@ impl SimpleAI {
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.flatten()
|
.flatten()
|
||||||
.flatten()
|
.flatten()
|
||||||
.filter(
|
.filter(|slot| match (slot.state(), self.player_color) {
|
||||||
|slot| match (*slot.state.lock().unwrap(), self.player_color) {
|
(BoardSlotState::Black(_), PlayerColor::White) => true,
|
||||||
(BoardSlotState::Black(_), PlayerColor::White) => true,
|
(BoardSlotState::White(_), PlayerColor::Black) => true,
|
||||||
(BoardSlotState::White(_), PlayerColor::Black) => true,
|
_ => false,
|
||||||
_ => false,
|
})
|
||||||
},
|
|
||||||
)
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let len = other_color.len();
|
let len = other_color.len();
|
||||||
|
|
||||||
let slot = &mut other_color[Random::range(0, len as u32) as usize];
|
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();
|
||||||
|
|
||||||
scene.on_scene(|scene| {
|
scene.on_scene(|scene| {
|
||||||
MillGame::remove_stone(slot, scene)?;
|
MillGame::remove_stone(stone, slot, scene)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
GameState::Main => {
|
GameState::Main => {
|
||||||
let mut same_color: Vec<&BoardSlot> = board
|
let same_color: Vec<&BoardSlot> = board
|
||||||
.iter()
|
.iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.flatten()
|
.flatten()
|
||||||
.filter(
|
.filter(|slot| match (slot.state(), self.player_color) {
|
||||||
|slot| match (*slot.state.lock().unwrap(), self.player_color) {
|
(BoardSlotState::White(_), PlayerColor::White) => true,
|
||||||
(BoardSlotState::White(_), PlayerColor::White) => true,
|
(BoardSlotState::Black(_), PlayerColor::Black) => true,
|
||||||
(BoardSlotState::Black(_), PlayerColor::Black) => true,
|
_ => false,
|
||||||
_ => false,
|
})
|
||||||
},
|
|
||||||
)
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let len = same_color.len();
|
let len = same_color.len();
|
||||||
let slot = &mut same_color[Random::range(0, len as u32) as usize];
|
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();
|
||||||
|
|
||||||
// find free neighbour field
|
if !neighbours.is_empty() {
|
||||||
if let Some(neighbour) = match Random::range(0, 6) as usize {
|
let neighbour =
|
||||||
0 => {
|
&neighbours[Random::range(0, neighbours.len() as u32) as usize];
|
||||||
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) {
|
if neighbour.state() == BoardSlotState::Empty {
|
||||||
(BoardSlotState::Empty, BoardSlotState::Black(e)) => {
|
let (x, y, z) = (slot.x, slot.y, slot.z);
|
||||||
*neighbour_state = BoardSlotState::Black(e);
|
let (tx, ty, tz) = (neighbour.x, neighbour.y, neighbour.z);
|
||||||
*slot_state = BoardSlotState::Empty;
|
|
||||||
}
|
|
||||||
(BoardSlotState::Empty, BoardSlotState::White(e)) => {
|
|
||||||
*neighbour_state = BoardSlotState::White(e);
|
|
||||||
*slot_state = BoardSlotState::Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => (),
|
scene.on_scene(|scene| {
|
||||||
|
if MillGame::move_stone(
|
||||||
|
(x, y, z),
|
||||||
|
(tx, ty, tz),
|
||||||
|
scene,
|
||||||
|
board,
|
||||||
|
state,
|
||||||
|
)? != MillState::None
|
||||||
|
{
|
||||||
|
found_a_mill = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GameState::Waiting => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
MillGame::log("finish AI");
|
MillGame::log("finish AI");
|
||||||
|
|
||||||
Ok(())
|
Ok(found_a_mill)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue