diff --git a/src/bored/mod.rs b/src/bored/mod.rs index 26209c1..95148e8 100644 --- a/src/bored/mod.rs +++ b/src/bored/mod.rs @@ -1,4 +1,7 @@ -use raylib::prelude::Color; +use raylib::{ + prelude::{Color, MouseButton}, + RaylibHandle, +}; use crate::gamedata::{algorithms::minimax_decision, Board, Disk}; pub const STARTY: i32 = 9; @@ -9,6 +12,7 @@ const CIRCLEWIDTH: i32 = 56; #[cfg(test)] mod tests; +#[derive(Clone)] pub struct PlayState { pub circles: Vec<(i32, i32, Disk)>, pub bottom: Vec, @@ -45,10 +49,18 @@ impl PlayState { self.player_turn = true; } } +#[derive(Clone)] pub struct MenuState { - difficulty: i32, + pub difficulty: i32, p1: (Color, Disk), p2: (Color, Disk), + pub selection: Selection, + pub strategy: Strategy, +} +#[derive(Clone)] +pub enum Strategy { + MiniMax, + AlphaBeta, } impl Default for MenuState { fn default() -> Self { @@ -56,13 +68,51 @@ impl Default for MenuState { difficulty: 3, p1: (Color::RED, Disk::P1), p2: (Color::YELLOW, Disk::P2), + selection: Selection::Difficulty, + strategy: Strategy::MiniMax, } } } +impl MenuState { + pub fn init(&mut self, rl: &RaylibHandle) -> bool { + dbg!(&self.selection); + match self.selection { + Selection::Difficulty => { + if rl.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { + self.difficulty = 3; + self.selection = Selection::Cooking; + } + if rl.is_mouse_button_pressed(MouseButton::MOUSE_RIGHT_BUTTON) { + self.difficulty = 5; + self.selection = Selection::Cooking; + } + } + Selection::Cooking => { + if rl.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { + self.difficulty = 3; + self.selection = Selection::Done; + } + if rl.is_mouse_button_pressed(MouseButton::MOUSE_RIGHT_BUTTON) { + self.difficulty = 5; + self.selection = Selection::Done; + } + } + Selection::Done => return true, + } + false + } +} +#[derive(Clone)] pub enum GameState { Play(PlayState), MainMenu(MenuState), } +#[derive(Clone, Debug)] +pub enum Selection { + Difficulty, + Cooking, + Done, +} fn get_circle_coords(x: i32, y: i32) -> (i32, i32) { let mut returned: (i32, i32) = (0, 0); diff --git a/src/gamedata/heuristic.rs b/src/gamedata/heuristic.rs index 58403da..4b18552 100644 --- a/src/gamedata/heuristic.rs +++ b/src/gamedata/heuristic.rs @@ -11,7 +11,6 @@ const POT_STREAKS: i32 = 4; const POT_WIN: i32 = 5; // should be nerfed if its just 1 potential win const POT_WINS: i32 = 6; const SCORE_DIFF: i32 = 40; -const MAX_WINS: i32 = 17; pub fn get_score(board: &Board, disk: Disk) -> i32 { //this should be summing up a bunch of functions defined below this one @@ -239,7 +238,7 @@ fn streak_test_1() { board.play(Disk::P2, 3); board.play(Disk::P2, 3); let sequences = get_streaks(&board.columns, &Disk::P2); - assert_eq!(12, potential_streaks(&sequences, &Disk::P2)); + assert_eq!(POT_STREAKS * 2, potential_streaks(&sequences, &Disk::P2)); } #[test] fn win_test_flipping() { diff --git a/src/main.rs b/src/main.rs index d49a8c1..31f4d04 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ use oxidised4::{ - bored::PlayState, - gamedata::{algorithms::minimax_decision_pruning, Disk}, + bored::{GameState, MenuState, PlayState, Strategy}, + gamedata::{ + algorithms::{minimax_decision, minimax_decision_pruning}, + Disk, + }, }; use raylib::prelude::*; const NROW: i32 = 6; @@ -36,46 +39,57 @@ fn main() { let _square_wewant = (square_widf * NROW / 2, square_heif * 3 / 2); let _square_center = square_widf / 2; //7,9 are the values to center the circle - let mut state: PlayState = PlayState::default(); + let mut state: GameState = GameState::MainMenu(MenuState::default()); + let mut strategy = Strategy::MiniMax; + let mut difficulty = 3; rl.set_target_fps(60); while !rl.window_should_close() { let mut d = rl.begin_drawing(&thread); - match state.player_turn { - true => { - if d.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { - if let Some(column) = get_mouse_column(&d, square_widf) { - state.play_human(column); - } + match &mut state { + GameState::MainMenu(ref mut mstate) => { + if mstate.init(&d) { + strategy = mstate.strategy.clone(); + difficulty = mstate.difficulty.clone(); + state = GameState::Play(PlayState::default()); } } - false => state.play_cpu(minimax_decision_pruning), - } - if state.board.game_over() { - let scores = state.board.getscore(); - println!("Player score: {} \n CPU Score: {}", scores.0, scores.1); - } + GameState::Play(ref mut state) => { + match state.player_turn { + true => { + if d.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { + if let Some(column) = get_mouse_column(&d, square_widf) { + state.play_human(column); + } + } + } + false => match strategy { + Strategy::MiniMax => state.play_cpu(minimax_decision), + Strategy::AlphaBeta => state.play_cpu(minimax_decision_pruning), + }, + } + if state.board.game_over() { + let scores = state.board.getscore(); + println!("Player score: {} \n CPU Score: {}", scores.0, scores.1); + } - for circle in &state.circles { - let (x, y, disk) = circle; - let color = match disk { - Disk::P1 => Color::RED, - Disk::P2 => Color::YELLOW, - Disk::EMPTY => Color::WHITE, - }; - d.draw_texture(&circle_texture, *x, *y, color); + for circle in state.clone().circles { + let (x, y, disk) = circle; + let color = match disk { + Disk::P1 => Color::RED, + Disk::P2 => Color::YELLOW, + Disk::EMPTY => Color::WHITE, + }; + d.draw_texture(&circle_texture, x, y, color); + } + d.clear_background(Color::WHITE); + d.draw_texture(&board_texture, BOARDSTART.0, BOARDSTART.1, Color::VIOLET); + } } - d.clear_background(Color::WHITE); - d.draw_texture(&board_texture, BOARDSTART.0, BOARDSTART.1, Color::VIOLET); } } -//TODO move this to a struct -pub const STARTY: i32 = 9; -pub const STARTX: i32 = 7; -const WX: i32 = 14; -const WY: i32 = 14; -const CIRCLEWIDTH: i32 = 56; +const STARTY: i32 = 9; fn get_mouse_column(rl: &RaylibHandle, sw: i32) -> Option { //row,col return let mouse_pos = rl.get_mouse_x();