From cbf08728f43414efaf3e685533cdb8d40bc9d208 Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 10:45:51 +0300 Subject: [PATCH 01/19] board started :DDD --- resouces/board.png | Bin 0 -> 9129 bytes src/main.rs | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 resouces/board.png diff --git a/resouces/board.png b/resouces/board.png new file mode 100644 index 0000000000000000000000000000000000000000..4a2abbf790a52c2662124161e7f7257d5397c59c GIT binary patch literal 9129 zcmeHNdrVVj6u(ejB2b1z3?L}44KqinLta$`>nyAk0xWS8LE~d?8hJVkG8k&2Rf}Vg z0Y-5d2>1_@umfhyS1VSFsiMF|5IUUe3M40-Ne`rzK%?{sN1=Kd)8PA~U6&F$?u z-}!yN^Sc$r3bxx?J6mHIW*f=l#$lMrFm6>=41DI4Z=gGVFv*D99)Z<%x(?wdW*>(~ zhhtdXh2=AQ%<*%JSboB`b=W-q@3Rlej^GE=%s4^(JoZNeD+)hbmdg7u1HAe8HY~^>4I@*86F+a6B#$-=>{FYxer$=vC-rx2u+5#^67MZpbN9OPT zsd5Wzf83fHx7Vl$z0(rB= zJRh4VuN4;FUoAW7AUzc>+SmFGm%S&}qm1>I!zST7kQLc-zLr|Jb?jqY*#CWgJNrrV z-m=3zb^MJlKk{)AzKwSKuaOI_twPI9TMMec_^!`ab6Va&Ii+|#9=b5!7!sd8Gv2n9 zo87n8M&F>e@~pGri75eXHmrIdN~gD}B7w<7Qn3NMAAP^R#I7_t%c5 zD#Qi^l}SsODvK!`IM-Ps9^ihCUTwtk8d$Gce3aE@+Dcx`iXD{2?0KEK)=6$Rj*|#7 zxWWpRXo0NH9jp*`GGy#fRuW*{tf%Z}kii}n2fQNwN%dDW&_=)6_r`jD5&XsZdUw0&TyYhoyuqC1kE;EZoZV;!*Can0GtfxVY2&mVRm7oA{{UO zSriB-eey3uP>$RRIbldkpGk3D_>=uR@_Zlp|uE zzmc?*$*6wskP_9AZV0oFcWVK>rpC@fwR&sJVFA_Ar3_&(02hY9yf%!hFpiGTIAZ@_ zAzF|9B;^vZQ;}g@wT<1-+B8)dY)DYid23Sb;HX>=cxyIzn)?S5VbH86C7pozgC&BZ zs1~#MCYr(E?&FF?uWZ0Bf)&PPQ#c^CK3fLwI>eN!!n`-M1^8i(CdhIM)4~W)-^50AosM$EJ8$otE z3;m1!K?U+g>&wWwzFeZ!wyE9f<)zKhVgBF>b(T6CPkBp5;UHiK7u#K0g*ix(oxQR? z%_}^|AoH$g^g(7TS^o$!*kdb!ujpOBVH(-l6Eei7?=s8JanUxC3E^sSTpo#tqi}r@ z!O1jzRx;x{-KSV_WfFd|FFJ;jSqMbG{3nnjJa^&);EuIn8VWWs4+Wc;H#FdI>dh+v zJ&0H}D2YY2=FS2+B66oKvHUZCaS_@;m<>0+1=V1!hWa5D7-cC({A-E|h)4icomv{9 zV`(5-A62F;80bcjqLyx%3JfY;0#of2fZ9gn`dAX6ww>W2L_IaYgZv?t&bRZqYDk8-_J9KlvbB$nLbw_= zixgNEab2U7Q(>JsmLZ2V^93>8D4ZLGbE9y+sP&^&exq=%qw$0VStpTEIM;q4X%x6adAz4kv4&gZ3h^Rs@# q Date: Sat, 6 May 2023 10:53:59 +0300 Subject: [PATCH 02/19] more resources :D --- resouces/bracc.png | Bin 0 -> 357 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 resouces/bracc.png diff --git a/resouces/bracc.png b/resouces/bracc.png new file mode 100644 index 0000000000000000000000000000000000000000..66c0f4203ebdf90b90fda14e7de3e493df213852 GIT binary patch literal 357 zcmeAS@N?(olHy`uVBq!ia0vp^79h;Q3?%1AoYnzSjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCils0(?ST|Ns9FWQHEPTnD6>N`m}?|1&(@Zr}yvaTa()7BevL9R^{>R)2Sowte(fRXwx98vaU9YX5H*;Bd-f@$CPpXWq)B-crROe|4E5~wu7TPi0 z_tEwp8A8(@P4c{=e2R5)g2T1o$q`F3j%f+5xRpM&beZIr(6FX+8V+`cRvg$Vd}2RS mtDszi7SJzzsS%!OzP=0~HU|)cz@^~HAj;F#&t;ucLK6T03w`qd literal 0 HcmV?d00001 From baa61a1f0481914db323edde726779ee9c4ffcfa Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 10:54:34 +0300 Subject: [PATCH 03/19] CENTERED THE THING (grid up next) --- src/main.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 73ebca8..de6f672 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,18 +6,28 @@ fn main() { let _rust_orange = Color::new(222, 165, 132, 255); let _ray_white = Color::new(255, 255, 255, 255); + //images let board_image = Image::load_image("resouces/board.png").expect("WHAT DA HAILLL"); let _ = rl .load_texture(&thread, "resouces/board.png") .expect("couldn't load texture :("); + let _ = rl + .load_texture(&thread, "resouces/bracc.png") + .expect("couldn't load texture :("); + + let circle_image = Image::load_image("resouces/bracc.png").expect("WHAT DA HAILLL"); + let _ = rl + .load_texture(&thread, "resouces/bracc.png") + .expect("couldn't load texture :("); + //textures let board_texture = rl .load_texture_from_image(&thread, &board_image) .expect("WHAT DA HAILL"); - println!( - "width: {} \n height: {}.", - board_texture.width, board_texture.height - ); + + let circle_texture = rl + .load_texture_from_image(&thread, &circle_image) + .expect("WHAT DA HAILL"); let square_widf = board_texture.width / NROW; let square_heif = board_texture.height / NCOL; let square_wewant = (square_widf * NROW / 2, square_heif * 3 / 2); @@ -30,6 +40,7 @@ fn main() { d.clear_background(Color::WHITE); //d.draw_circle_gradient(240, 240, 100 as f32, Color::ORANGE, Color::RED); d.draw_circle(square_wewant.0, square_wewant.1, 55.0, Color::YELLOW); + d.draw_texture(&circle_texture, 7, 9, Color::VIOLET); d.draw_texture(&board_texture, 0, 0, Color::VIOLET); if let Some(pressed_key) = pressed_key { // Certain keyboards may have keys raylib does not expect. Uncomment this line if so. From b61e95aa19509b68813a1aa96c184074585241ba Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 10:54:45 +0300 Subject: [PATCH 04/19] removed pooopy unused thiongs --- src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index de6f672..c2f2056 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,14 +32,13 @@ fn main() { let square_heif = board_texture.height / NCOL; 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 rl.set_target_fps(60); while !rl.window_should_close() { let pressed_key = rl.get_key_pressed(); let mut d = rl.begin_drawing(&thread); d.clear_background(Color::WHITE); - //d.draw_circle_gradient(240, 240, 100 as f32, Color::ORANGE, Color::RED); - d.draw_circle(square_wewant.0, square_wewant.1, 55.0, Color::YELLOW); d.draw_texture(&circle_texture, 7, 9, Color::VIOLET); d.draw_texture(&board_texture, 0, 0, Color::VIOLET); if let Some(pressed_key) = pressed_key { From 06c11312672e8ca73bce501d2c483f6a1ea32c57 Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 11:25:24 +0300 Subject: [PATCH 05/19] added circle coordinate function --- src/main.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index c2f2056..8191468 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use raylib::prelude::*; const NROW: i32 = 6; const NCOL: i32 = 7; + fn main() { let (mut rl, thread) = raylib::init().size(640, 480).title("Hello, World").build(); @@ -39,7 +40,7 @@ fn main() { let pressed_key = rl.get_key_pressed(); let mut d = rl.begin_drawing(&thread); d.clear_background(Color::WHITE); - d.draw_texture(&circle_texture, 7, 9, Color::VIOLET); + d.draw_texture(&circle_texture, 7, 350, Color::VIOLET); d.draw_texture(&board_texture, 0, 0, Color::VIOLET); if let Some(pressed_key) = pressed_key { // Certain keyboards may have keys raylib does not expect. Uncomment this line if so. @@ -48,3 +49,25 @@ fn main() { } } } + +const STARTX: i32 = 7; +const STARTY: i32 = 9; +const WX: i32 = 13; +const WY: i32 = 15; +const CIRCLEWIDTH: i32 = 55; +fn get_circle_coords(row: i32, column: i32) -> (i32, i32) { + let mut returned: (i32, i32) = (STARTX, STARTY); + match row { + 1 => {} + _ => { + returned.0 = STARTX + (CIRCLEWIDTH * (row - 1)) + (WX * (row - 1)); + } + }; + match column { + 1 => {} + _ => { + returned.0 = STARTY + (CIRCLEWIDTH * (column - 1)) + (WY * (column - 1)); + } + }; + returned +} From 89dc143f1acdf9ea5394397782fb4bcbb1c94121 Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 11:25:49 +0300 Subject: [PATCH 06/19] silly TODO comment --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index 8191468..d6202bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,6 +50,7 @@ fn main() { } } +//TODO move this to a struct const STARTX: i32 = 7; const STARTY: i32 = 9; const WX: i32 = 13; From f31f25971581462970712c9f9dae34ad1ab17e6b Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 11:37:38 +0300 Subject: [PATCH 07/19] working circle drawing :D --- src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index d6202bd..822d2ab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,8 +39,9 @@ fn main() { while !rl.window_should_close() { let pressed_key = rl.get_key_pressed(); let mut d = rl.begin_drawing(&thread); + let (x, y) = get_circle_coords(7, 2); d.clear_background(Color::WHITE); - d.draw_texture(&circle_texture, 7, 350, Color::VIOLET); + d.draw_texture(&circle_texture, x, y, Color::VIOLET); d.draw_texture(&board_texture, 0, 0, Color::VIOLET); if let Some(pressed_key) = pressed_key { // Certain keyboards may have keys raylib does not expect. Uncomment this line if so. @@ -53,8 +54,7 @@ fn main() { //TODO move this to a struct const STARTX: i32 = 7; const STARTY: i32 = 9; -const WX: i32 = 13; -const WY: i32 = 15; +const WX: i32 = 15; const CIRCLEWIDTH: i32 = 55; fn get_circle_coords(row: i32, column: i32) -> (i32, i32) { let mut returned: (i32, i32) = (STARTX, STARTY); @@ -67,7 +67,7 @@ fn get_circle_coords(row: i32, column: i32) -> (i32, i32) { match column { 1 => {} _ => { - returned.0 = STARTY + (CIRCLEWIDTH * (column - 1)) + (WY * (column - 1)); + returned.1 = STARTY + (CIRCLEWIDTH * (column - 1)) + (WX * (column - 1)); } }; returned From 95108e132366e0b85712201e80bdb1d0115e354d Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 11:49:57 +0300 Subject: [PATCH 08/19] cargo fix my beloved --- src/gamedata/algorithms.rs | 18 +++---- src/gamedata/heuristic.rs | 26 +++++------ src/gamedata/indices.rs | 8 ++-- src/gamedata/mod.rs | 8 ++-- src/gamedata/score_checkers.rs | 85 +++++++++++++++++----------------- src/gamedata/tests.rs | 22 ++++----- 6 files changed, 83 insertions(+), 84 deletions(-) diff --git a/src/gamedata/algorithms.rs b/src/gamedata/algorithms.rs index 31e7919..6bf0171 100644 --- a/src/gamedata/algorithms.rs +++ b/src/gamedata/algorithms.rs @@ -8,7 +8,7 @@ pub fn minimax_decision(board: &Board, disk: Disk, depth: &i32) -> Board { } fn maximise(board: &Board, disk: &Disk, depth: &i32) -> (Option, i32) { match board.game_over() || *depth == 0 { - true => return (None, get_score(board, *disk)), + true => (None, get_score(board, *disk)), false => { let (mut max_child, mut max_utility): (Option, i32) = (None, i32::MIN); for child in board.get_children(*disk) { @@ -23,7 +23,7 @@ fn maximise(board: &Board, disk: &Disk, depth: &i32) -> (Option, i32) { } fn minimise(board: &Board, disk: &Disk, depth: &i32) -> (Option, i32) { match board.game_over() || *depth == 0 { - true => return (None, get_score(board, flip_disk(*disk))), + true => (None, get_score(board, flip_disk(*disk))), false => { let (mut min_child, mut min_utility): (Option, i32) = (None, i32::MAX); for child in board.get_children(*disk) { @@ -40,16 +40,16 @@ fn minimise(board: &Board, disk: &Disk, depth: &i32) -> (Option, i32) { fn minimax_test() { let mut board = Board::default(); let mut disk = Disk::BLU; - let depth = 5; - let turn1 = board.play(disk, minimax_decision(&board, disk, &5).last_move); + let _depth = 5; + let _turn1 = board.play(disk, minimax_decision(&board, disk, &5).last_move); disk = flip_disk(disk); - let turn2 = board.play(disk, minimax_decision(&board, disk, &5).last_move); + let _turn2 = board.play(disk, minimax_decision(&board, disk, &5).last_move); disk = flip_disk(disk); - let turn3 = board.play(disk, minimax_decision(&board, disk, &5).last_move); + let _turn3 = board.play(disk, minimax_decision(&board, disk, &5).last_move); disk = flip_disk(disk); - let turn4 = board.play(disk, minimax_decision(&board, disk, &5).last_move); + let _turn4 = board.play(disk, minimax_decision(&board, disk, &5).last_move); disk = flip_disk(disk); - let turn5 = board.play(disk, minimax_decision(&board, disk, &5).last_move); + let _turn5 = board.play(disk, minimax_decision(&board, disk, &5).last_move); for column in board.columns.as_rows() { column .iter() @@ -58,7 +58,7 @@ fn minimax_test() { x }) .count(); - println!(""); + println!(); } assert!(false); } diff --git a/src/gamedata/heuristic.rs b/src/gamedata/heuristic.rs index a16b44c..413af63 100644 --- a/src/gamedata/heuristic.rs +++ b/src/gamedata/heuristic.rs @@ -24,7 +24,7 @@ pub fn get_score(board: &Board, disk: Disk) -> i32 { potential_streaks(&sequences, &disk) + potential_wins(&sequences, &disk) + score * SCORE_DIFF } fn potential_wins(sequences: &Vec>, _disk: &Disk) -> i32 { - let count: i32 = sequences.iter().count() as i32; + let count: i32 = sequences.len() as i32; // for win in sequences { // if win // .iter() @@ -70,7 +70,7 @@ fn get_streaks(board: &Array2D, player_disk: &Disk) -> Vec> { for index in empty_indices { let moves = get_legal_moves(&index, (board.num_rows(), board.num_columns())); for direction in moves { - let mut sequence = heur_scan(&board, &index, direction.clone(), 4, *player_disk); + let sequence = heur_scan(board, &index, direction.clone(), 4, *player_disk); //dbg!(&index, &direction, &poopy); match sequence .iter() @@ -95,7 +95,7 @@ fn get_wins(board: &Array2D, player_disk: &Disk) -> Vec> { for direction in moves { let mut win: Vec = Vec::with_capacity(4); win.append(&mut heur_scan( - &board, + board, &index, direction.clone(), 4, @@ -115,7 +115,7 @@ fn get_wins(board: &Array2D, player_disk: &Disk) -> Vec> { } let opp_direction = flip_direction(direction.clone()); let mut opp_sequence = heur_scan( - &board, + board, &index, opp_direction, (4 - win.len() + 1) as i32, @@ -157,31 +157,31 @@ fn heur_scan( // dbg!(current_index); //go to next element match direction { - Direction::DOWN => { + Direction::Down => { if current_index.0 == 0 { break; } current_index = dec_row(¤t_index, 1); } - Direction::UP => { + Direction::Up => { if current_index.0 == board.num_rows() - 1 { break; } current_index = inc_row(¤t_index, 1); } - Direction::LEFT => { + Direction::Left => { if current_index.1 == 0 { break; } current_index = dec_col(¤t_index, 1); } - Direction::RIGHT => { + Direction::Right => { if current_index.1 == board.num_columns() - 1 { break; } current_index = inc_col(¤t_index, 1); } - Direction::UPRIGHT => { + Direction::UpRight => { if current_index.0 == board.num_rows() - 1 || current_index.1 == board.num_columns() - 1 { @@ -189,20 +189,20 @@ fn heur_scan( } current_index = inc_both(¤t_index, 1); } - Direction::UPLEFT => { + Direction::UpLeft => { if current_index.0 == board.num_columns() - 1 || current_index.1 == 0 { break; } current_index = inc_dec(¤t_index, 1); } - Direction::DOWNRIGHT => { + Direction::DownRight => { if current_index.0 == 0 || current_index.1 == board.num_columns() - 1 { break; } current_index = dec_inc(¤t_index, 1); } - Direction::DOWNLEFT => { + Direction::DownLeft => { if current_index.0 == 0 || current_index.1 == 0 { break; } @@ -233,7 +233,7 @@ fn streak_test_1() { let sequences = get_streaks(&board.columns, &Disk::BLU); assert_eq!(18, potential_streaks(&sequences, &Disk::BLU)); board.play(Disk::BLU, 0); - let sequences = get_streaks(&board.columns, &Disk::BLU); + let _sequences = get_streaks(&board.columns, &Disk::BLU); board.play(Disk::BLU, 3); board.play(Disk::BLU, 3); board.play(Disk::BLU, 3); diff --git a/src/gamedata/indices.rs b/src/gamedata/indices.rs index f49bc40..2b4f9b1 100644 --- a/src/gamedata/indices.rs +++ b/src/gamedata/indices.rs @@ -1,15 +1,15 @@ pub fn inc_row((row, col): &(usize, usize), value: usize) -> (usize, usize) { - (row + value as usize, *col) + (row + value, *col) } pub fn inc_col((row, col): &(usize, usize), value: usize) -> (usize, usize) { - (*row, col + value as usize) + (*row, col + value) } pub fn dec_row((row, col): &(usize, usize), value: usize) -> (usize, usize) { - (row - value as usize, *col) + (row - value, *col) } pub fn dec_col((row, col): &(usize, usize), value: usize) -> (usize, usize) { - (*row, col - value as usize) + (*row, col - value) } pub fn inc_both((row, col): &(usize, usize), value: usize) -> (usize, usize) { (row + value, col + value) diff --git a/src/gamedata/mod.rs b/src/gamedata/mod.rs index 31c78f0..877b08c 100644 --- a/src/gamedata/mod.rs +++ b/src/gamedata/mod.rs @@ -34,11 +34,11 @@ impl Board { (self.red_score, self.blu_score) } fn play(&mut self, disk: Disk, col: usize) -> bool { - let column = &self.columns.as_columns()[col as usize]; + let column = &self.columns.as_columns()[col]; let empty = column.iter().filter(|&a| matches!(a, Disk::EMPTY)).count(); // dbg!(empty); let top = column.len() - empty; - match self.columns.set(top, col as usize, disk) { + match self.columns.set(top, col, disk) { Ok(_) => { self.score_check((top, col)); self.last_move = col; @@ -87,9 +87,9 @@ impl Board { } } } - Disk::EMPTY => return, + Disk::EMPTY => (), }, - None => return, + None => (), } } fn game_over(&self) -> bool { diff --git a/src/gamedata/score_checkers.rs b/src/gamedata/score_checkers.rs index 387f344..e2730a9 100644 --- a/src/gamedata/score_checkers.rs +++ b/src/gamedata/score_checkers.rs @@ -10,9 +10,8 @@ pub fn scan( direction: Direction, depth: i32, ) -> i32 { - let current_disk: &Disk; - match board.get(index.0, index.1) { - Some(disk) => current_disk = disk, + let current_disk: &Disk = match board.get(index.0, index.1) { + Some(disk) => disk, None => return 0, }; let mut current_index = *index; @@ -28,33 +27,33 @@ pub fn scan( // dbg!(current_index); //go to next element match direction { - Direction::DOWN => { + Direction::Down => { if current_index.0 == 0 { break; } current_index = dec_row(¤t_index, 1); } - Direction::UP => { + Direction::Up => { if current_index.0 == board.num_rows() - 1 { break; } current_index = inc_row(¤t_index, 1); } - Direction::LEFT => { + Direction::Left => { if current_index.1 == 0 { break; } current_index = dec_col(¤t_index, 1); // current_index.1 -= 1; } - Direction::RIGHT => { + Direction::Right => { if current_index.1 == board.num_columns() - 1 { break; } current_index = inc_col(¤t_index, 1); // current_index.1 += 1; } - Direction::UPRIGHT => { + Direction::UpRight => { if current_index.0 == board.num_rows() - 1 || current_index.1 == board.num_columns() - 1 { @@ -64,7 +63,7 @@ pub fn scan( // current_index.1 += 1; // current_index.0 += 1; } - Direction::UPLEFT => { + Direction::UpLeft => { if current_index.0 == board.num_columns() - 1 || current_index.1 == 0 { break; } @@ -73,7 +72,7 @@ pub fn scan( // current_index.0 += 1; current_index = inc_dec(¤t_index, 1); } - Direction::DOWNRIGHT => { + Direction::DownRight => { if current_index.0 == 0 || current_index.1 == board.num_columns() - 1 { break; } @@ -81,7 +80,7 @@ pub fn scan( // current_index.1 += 1; // current_index.0 -= 1; } - Direction::DOWNLEFT => { + Direction::DownLeft => { if current_index.0 == 0 || current_index.1 == 0 { break; } @@ -108,46 +107,46 @@ pub fn get_legal_moves( let _max_row = ncol - 1; let mut moves: Vec = vec![]; match *col { - 0 => moves.push(Direction::UP), - _max_row => moves.push(Direction::DOWN), + 0 => moves.push(Direction::Up), + _max_row => moves.push(Direction::Down), _ => { - moves.push(Direction::UP); - moves.push(Direction::DOWN); + moves.push(Direction::Up); + moves.push(Direction::Down); } }; match *row { - 0 => moves.push(Direction::RIGHT), - _max_row => moves.push(Direction::LEFT), + 0 => moves.push(Direction::Right), + _max_row => moves.push(Direction::Left), _ => { - moves.push(Direction::LEFT); - moves.push(Direction::RIGHT) + moves.push(Direction::Left); + moves.push(Direction::Right) } }; - if moves.contains(&Direction::UP) && moves.contains(&Direction::LEFT) { - moves.push(Direction::UPLEFT); + if moves.contains(&Direction::Up) && moves.contains(&Direction::Left) { + moves.push(Direction::UpLeft); } - if moves.contains(&Direction::UP) && moves.contains(&Direction::RIGHT) { - moves.push(Direction::UPRIGHT); + if moves.contains(&Direction::Up) && moves.contains(&Direction::Right) { + moves.push(Direction::UpRight); } - if moves.contains(&Direction::DOWN) && moves.contains(&Direction::LEFT) { - moves.push(Direction::DOWNLEFT); + if moves.contains(&Direction::Down) && moves.contains(&Direction::Left) { + moves.push(Direction::DownLeft); } - if moves.contains(&Direction::DOWN) && moves.contains(&Direction::RIGHT) { - moves.push(Direction::DOWNRIGHT); + if moves.contains(&Direction::Down) && moves.contains(&Direction::Right) { + moves.push(Direction::DownRight); } moves } #[derive(Clone, Debug, PartialEq, Eq)] pub enum Direction { - UP, - DOWN, - LEFT, - RIGHT, - UPLEFT, - UPRIGHT, - DOWNLEFT, - DOWNRIGHT, + Up, + Down, + Left, + Right, + UpLeft, + UpRight, + DownLeft, + DownRight, } // serves nothing except do what matches!() should have done all along // matches works too I'm just dumb @@ -156,13 +155,13 @@ pub fn variant_eq(a: &T, b: &T) -> bool { } pub fn flip_direction(direction: Direction) -> Direction { match direction { - Direction::UP => Direction::DOWN, - Direction::DOWN => Direction::UP, - Direction::LEFT => Direction::RIGHT, - Direction::RIGHT => Direction::LEFT, - Direction::UPLEFT => Direction::DOWNRIGHT, - Direction::UPRIGHT => Direction::DOWNLEFT, - Direction::DOWNLEFT => Direction::UPRIGHT, - Direction::DOWNRIGHT => Direction::UPLEFT, + Direction::Up => Direction::Down, + Direction::Down => Direction::Up, + Direction::Left => Direction::Right, + Direction::Right => Direction::Left, + Direction::UpLeft => Direction::DownRight, + Direction::UpRight => Direction::DownLeft, + Direction::DownLeft => Direction::UpRight, + Direction::DownRight => Direction::UpLeft, } } diff --git a/src/gamedata/tests.rs b/src/gamedata/tests.rs index b003439..3686800 100644 --- a/src/gamedata/tests.rs +++ b/src/gamedata/tests.rs @@ -54,8 +54,8 @@ fn scan_updown() { board.play(Disk::BLU, 0); board.play(Disk::BLU, 0); board.play(Disk::BLU, 0); - assert_eq!(4, scan(&board.columns, &(4, 0), Direction::DOWN, 4)); - assert_eq!(4, scan(&board.columns, &(3, 0), Direction::DOWN, 4)); + assert_eq!(4, scan(&board.columns, &(4, 0), Direction::Down, 4)); + assert_eq!(4, scan(&board.columns, &(3, 0), Direction::Down, 4)); } #[test] fn scan_updown2() { @@ -64,7 +64,7 @@ fn scan_updown2() { board.play(Disk::RED, 0); board.play(Disk::BLU, 0); board.play(Disk::BLU, 0); - assert_eq!(1, scan(&board.columns, &(0, 0), Direction::UP, 4)); + assert_eq!(1, scan(&board.columns, &(0, 0), Direction::Up, 4)); } #[test] fn scan_forwardback() { @@ -74,8 +74,8 @@ fn scan_forwardback() { board.play(Disk::BLU, 2); board.play(Disk::BLU, 3); - assert_eq!(4, scan(&board.columns, &(0, 0), Direction::RIGHT, 4)); - assert_eq!(4, scan(&board.columns, &(0, 3), Direction::LEFT, 4)); + assert_eq!(4, scan(&board.columns, &(0, 0), Direction::Right, 4)); + assert_eq!(4, scan(&board.columns, &(0, 3), Direction::Left, 4)); } #[test] fn scan_forwardback2() { @@ -84,8 +84,8 @@ fn scan_forwardback2() { board.play(Disk::BLU, 1); board.play(Disk::RED, 2); board.play(Disk::BLU, 3); - assert_eq!(2, scan(&board.columns, &(0, 0), Direction::RIGHT, 4)); - assert_eq!(1, scan(&board.columns, &(0, 3), Direction::LEFT, 4)); + assert_eq!(2, scan(&board.columns, &(0, 0), Direction::Right, 4)); + assert_eq!(1, scan(&board.columns, &(0, 3), Direction::Left, 4)); } #[test] fn scan_diag1() { @@ -100,8 +100,8 @@ fn scan_diag1() { board.play(Disk::RED, 3); board.play(Disk::RED, 3); board.play(Disk::BLU, 3); - assert_eq!(4, scan(&board.columns, &(0, 0), Direction::UPRIGHT, 4)); - assert_eq!(4, scan(&board.columns, &(3, 3), Direction::DOWNLEFT, 4)); + assert_eq!(4, scan(&board.columns, &(0, 0), Direction::UpRight, 4)); + assert_eq!(4, scan(&board.columns, &(3, 3), Direction::DownLeft, 4)); } #[test] fn scan_diag2() { @@ -117,8 +117,8 @@ fn scan_diag2() { board.play(Disk::RED, 0); board.play(Disk::BLU, 0); dbg!(&board.columns.as_columns()); - assert_eq!(4, scan(&board.columns, &(0, 3), Direction::UPLEFT, 4)); - assert_eq!(4, scan(&board.columns, &(3, 0), Direction::DOWNRIGHT, 4)); + assert_eq!(4, scan(&board.columns, &(0, 3), Direction::UpLeft, 4)); + assert_eq!(4, scan(&board.columns, &(3, 0), Direction::DownRight, 4)); } #[test] fn variant_eq_test() { From 080452137efe21e1b0a2105eb5683e842ade39c3 Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 12:24:29 +0300 Subject: [PATCH 09/19] game state struct --- src/bored/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/bored/mod.rs b/src/bored/mod.rs index 87c2771..b4fb469 100644 --- a/src/bored/mod.rs +++ b/src/bored/mod.rs @@ -1,2 +1,20 @@ +use crate::gamedata::{Board, Disk}; + #[cfg(test)] mod tests; +pub struct GameState { + circles: Vec<(i32, i32, Disk)>, + empty: Vec, + player_turn: bool, + board: Board, +} +impl Default for GameState { + fn default() -> Self { + Self { + circles: vec![], + empty: vec![], + player_turn: false, + board: Board::default(), + } + } +} From cd4ee43e9b1422a293b27d8c1a3f590c4d718421 Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 12:24:37 +0300 Subject: [PATCH 10/19] mouse position function --- src/main.rs | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/main.rs b/src/main.rs index 822d2ab..9dab2cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,22 +1,20 @@ +use oxidised4::bored::GameState; use raylib::prelude::*; const NROW: i32 = 6; const NCOL: i32 = 7; +const BOARDSTART: (i32, i32) = (0, 0); fn main() { let (mut rl, thread) = raylib::init().size(640, 480).title("Hello, World").build(); - let _rust_orange = Color::new(222, 165, 132, 255); - let _ray_white = Color::new(255, 255, 255, 255); //images let board_image = Image::load_image("resouces/board.png").expect("WHAT DA HAILLL"); let _ = rl .load_texture(&thread, "resouces/board.png") .expect("couldn't load texture :("); - let _ = rl .load_texture(&thread, "resouces/bracc.png") .expect("couldn't load texture :("); - let circle_image = Image::load_image("resouces/bracc.png").expect("WHAT DA HAILLL"); let _ = rl .load_texture(&thread, "resouces/bracc.png") @@ -29,25 +27,23 @@ fn main() { let circle_texture = rl .load_texture_from_image(&thread, &circle_image) .expect("WHAT DA HAILL"); - let square_widf = board_texture.width / NROW; - let square_heif = board_texture.height / NCOL; - let square_wewant = (square_widf * NROW / 2, square_heif * 3 / 2); - let square_center = square_widf / 2; + let square_widf = board_texture.width / NCOL; + dbg!(square_widf); + let square_heif = board_texture.height / NROW; + 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 state: GameState = GameState::default(); rl.set_target_fps(60); while !rl.window_should_close() { - let pressed_key = rl.get_key_pressed(); let mut d = rl.begin_drawing(&thread); - let (x, y) = get_circle_coords(7, 2); - d.clear_background(Color::WHITE); - d.draw_texture(&circle_texture, x, y, Color::VIOLET); - d.draw_texture(&board_texture, 0, 0, Color::VIOLET); - if let Some(pressed_key) = pressed_key { - // Certain keyboards may have keys raylib does not expect. Uncomment this line if so. - // let pressed_key: u32 = unsafe { std::mem::transmute(pressed_key) }; - d.draw_text(&format!("{:?}", pressed_key), 100, 12, 10, Color::BLACK); + if d.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { + let column = get_mouse_column(&d, square_widf); + d.draw_texture(&circle_texture, column, STARTY, Color::VIOLET); } + d.clear_background(Color::WHITE); + d.draw_texture(&board_texture, BOARDSTART.0, BOARDSTART.1, Color::VIOLET); } } @@ -72,3 +68,15 @@ fn get_circle_coords(row: i32, column: i32) -> (i32, i32) { }; returned } +fn get_mouse_column(rl: &RaylibHandle, sw: i32) -> i32 { + //row,col return + let mouse_pos = rl.get_mouse_x(); + dbg!(mouse_pos); + for num in 1..NCOL { + dbg!(mouse_pos < sw * (num) - STARTX); + if (mouse_pos > sw * (num - 1) + STARTX) && (mouse_pos < sw * (num) - STARTX) { + return num; + } + } + 10 +} From f896fc1c3ad69d5b9f4a61c53025b2a86dbb5910 Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 12:57:19 +0300 Subject: [PATCH 11/19] I am stopdid with indexes --- src/bored/mod.rs | 10 +++++----- src/main.rs | 40 ++++++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/bored/mod.rs b/src/bored/mod.rs index b4fb469..82ad42d 100644 --- a/src/bored/mod.rs +++ b/src/bored/mod.rs @@ -3,16 +3,16 @@ use crate::gamedata::{Board, Disk}; #[cfg(test)] mod tests; pub struct GameState { - circles: Vec<(i32, i32, Disk)>, - empty: Vec, - player_turn: bool, - board: Board, + pub circles: Vec<(i32, i32, Disk)>, + pub bottom: Vec, + pub player_turn: bool, + pub board: Board, } impl Default for GameState { fn default() -> Self { Self { circles: vec![], - empty: vec![], + bottom: vec![], player_turn: false, board: Board::default(), } diff --git a/src/main.rs b/src/main.rs index 9dab2cc..899915c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use oxidised4::bored::GameState; +use oxidised4::{bored::GameState, gamedata::Disk}; use raylib::prelude::*; const NROW: i32 = 6; const NCOL: i32 = 7; @@ -33,14 +33,24 @@ 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 state: GameState = GameState::default(); + let mut state: GameState = GameState::default(); rl.set_target_fps(60); while !rl.window_should_close() { let mut d = rl.begin_drawing(&thread); if d.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { let column = get_mouse_column(&d, square_widf); - d.draw_texture(&circle_texture, column, STARTY, Color::VIOLET); + let coords = get_circle_coords(1, column); + state.circles.push((coords.1, coords.0, Disk::RED)); + } + for circle in &state.circles { + let (x, y, disk) = circle; + let color = match disk { + Disk::RED => Color::RED, + Disk::BLU => Color::BLUE, + 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); @@ -48,22 +58,23 @@ fn main() { } //TODO move this to a struct -const STARTX: i32 = 7; -const STARTY: i32 = 9; -const WX: i32 = 15; -const CIRCLEWIDTH: i32 = 55; -fn get_circle_coords(row: i32, column: i32) -> (i32, i32) { +const STARTX: i32 = 9; +const STARTY: i32 = 7; +const WX: i32 = 14; +const WY: i32 = 14; +const CIRCLEWIDTH: i32 = 56; +fn get_circle_coords(x: i32, y: i32) -> (i32, i32) { let mut returned: (i32, i32) = (STARTX, STARTY); - match row { + match x { 1 => {} _ => { - returned.0 = STARTX + (CIRCLEWIDTH * (row - 1)) + (WX * (row - 1)); + returned.0 = STARTX + (CIRCLEWIDTH * (x - 1)) + (WX * (x - 1)); } }; - match column { + match y { 1 => {} _ => { - returned.1 = STARTY + (CIRCLEWIDTH * (column - 1)) + (WX * (column - 1)); + returned.1 = STARTY + (CIRCLEWIDTH * (y - 1)) + (WY * (y - 1)); } }; returned @@ -72,11 +83,12 @@ fn get_mouse_column(rl: &RaylibHandle, sw: i32) -> i32 { //row,col return let mouse_pos = rl.get_mouse_x(); dbg!(mouse_pos); - for num in 1..NCOL { + for num in 1..NCOL + 1 { dbg!(mouse_pos < sw * (num) - STARTX); if (mouse_pos > sw * (num - 1) + STARTX) && (mouse_pos < sw * (num) - STARTX) { + dbg!(num); return num; } } - 10 + -100 } From 01b8d7fb15479eb7f5bc630374cf2e6614bb323d Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 12:57:49 +0300 Subject: [PATCH 12/19] when I come to look back at this...in 2 days --- src/main.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index 899915c..13845ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,23 +58,23 @@ fn main() { } //TODO move this to a struct -const STARTX: i32 = 9; -const STARTY: i32 = 7; +const STARTY: i32 = 9; +const STARTX: i32 = 7; const WX: i32 = 14; const WY: i32 = 14; const CIRCLEWIDTH: i32 = 56; fn get_circle_coords(x: i32, y: i32) -> (i32, i32) { - let mut returned: (i32, i32) = (STARTX, STARTY); + let mut returned: (i32, i32) = (STARTY, STARTX); match x { 1 => {} _ => { - returned.0 = STARTX + (CIRCLEWIDTH * (x - 1)) + (WX * (x - 1)); + returned.0 = STARTY + (CIRCLEWIDTH * (x - 1)) + (WX * (x - 1)); } }; match y { 1 => {} _ => { - returned.1 = STARTY + (CIRCLEWIDTH * (y - 1)) + (WY * (y - 1)); + returned.1 = STARTX + (CIRCLEWIDTH * (y - 1)) + (WY * (y - 1)); } }; returned @@ -84,8 +84,8 @@ fn get_mouse_column(rl: &RaylibHandle, sw: i32) -> i32 { let mouse_pos = rl.get_mouse_x(); dbg!(mouse_pos); for num in 1..NCOL + 1 { - dbg!(mouse_pos < sw * (num) - STARTX); - if (mouse_pos > sw * (num - 1) + STARTX) && (mouse_pos < sw * (num) - STARTX) { + dbg!(mouse_pos < sw * (num) - STARTY); + if (mouse_pos > sw * (num - 1) + STARTY) && (mouse_pos < sw * (num) - STARTY) { dbg!(num); return num; } From e42a30a4c603c0984435e74070d7af389c64b398 Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 13:57:39 +0300 Subject: [PATCH 13/19] RED/BLU? more like P1 P2 --- src/gamedata/algorithms.rs | 2 +- src/gamedata/heuristic.rs | 66 ++++++++--------- src/gamedata/mod.rs | 26 +++---- src/gamedata/tests.rs | 148 ++++++++++++++++++------------------- 4 files changed, 121 insertions(+), 121 deletions(-) diff --git a/src/gamedata/algorithms.rs b/src/gamedata/algorithms.rs index 6bf0171..258a258 100644 --- a/src/gamedata/algorithms.rs +++ b/src/gamedata/algorithms.rs @@ -39,7 +39,7 @@ fn minimise(board: &Board, disk: &Disk, depth: &i32) -> (Option, i32) { #[test] fn minimax_test() { let mut board = Board::default(); - let mut disk = Disk::BLU; + let mut disk = Disk::P2; let _depth = 5; let _turn1 = board.play(disk, minimax_decision(&board, disk, &5).last_move); disk = flip_disk(disk); diff --git a/src/gamedata/heuristic.rs b/src/gamedata/heuristic.rs index 413af63..f52d920 100644 --- a/src/gamedata/heuristic.rs +++ b/src/gamedata/heuristic.rs @@ -17,8 +17,8 @@ pub fn get_score(board: &Board, disk: Disk) -> i32 { //this should be summing up a bunch of functions defined below this one let sequences = get_streaks(&board.columns, &disk); let score: i32 = match disk { - Disk::RED => board.red_score - board.blu_score, - Disk::BLU => board.blu_score - board.red_score, + Disk::P1 => board.p1_score - board.p2_score, + Disk::P2 => board.p2_score - board.p1_score, Disk::EMPTY => panic!("Why would you ever"), }; potential_streaks(&sequences, &disk) + potential_wins(&sequences, &disk) + score * SCORE_DIFF @@ -225,44 +225,44 @@ fn heur_scan( #[test] fn streak_test_1() { let mut board = Board::default(); - board.play(Disk::BLU, 3); - board.play(Disk::BLU, 3); - board.play(Disk::BLU, 3); - board.play(Disk::BLU, 2); - board.play(Disk::BLU, 1); - let sequences = get_streaks(&board.columns, &Disk::BLU); - assert_eq!(18, potential_streaks(&sequences, &Disk::BLU)); - board.play(Disk::BLU, 0); - let _sequences = get_streaks(&board.columns, &Disk::BLU); - board.play(Disk::BLU, 3); - board.play(Disk::BLU, 3); - board.play(Disk::BLU, 3); - board.play(Disk::BLU, 3); - let sequences = get_streaks(&board.columns, &Disk::BLU); - assert_eq!(12, potential_streaks(&sequences, &Disk::BLU)); + board.play(Disk::P2, 3); + board.play(Disk::P2, 3); + board.play(Disk::P2, 3); + board.play(Disk::P2, 2); + board.play(Disk::P2, 1); + let sequences = get_streaks(&board.columns, &Disk::P2); + assert_eq!(18, potential_streaks(&sequences, &Disk::P2)); + board.play(Disk::P2, 0); + let _sequences = get_streaks(&board.columns, &Disk::P2); + board.play(Disk::P2, 3); + board.play(Disk::P2, 3); + 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)); } #[test] fn win_test_flipping() { let mut board = Board::default(); - board.play(Disk::BLU, 3); - board.play(Disk::RED, 4); - board.play(Disk::BLU, 4); - board.play(Disk::RED, 5); - board.play(Disk::RED, 5); - board.play(Disk::RED, 6); - board.play(Disk::RED, 6); - board.play(Disk::RED, 6); - board.play(Disk::BLU, 6); - let sequences = get_wins(&board.columns, &Disk::BLU); + board.play(Disk::P2, 3); + board.play(Disk::P1, 4); + board.play(Disk::P2, 4); + board.play(Disk::P1, 5); + board.play(Disk::P1, 5); + board.play(Disk::P1, 6); + board.play(Disk::P1, 6); + board.play(Disk::P1, 6); + board.play(Disk::P2, 6); + let sequences = get_wins(&board.columns, &Disk::P2); dbg!(&sequences); - assert_eq!(POT_WIN, potential_wins(&sequences, &Disk::BLU)); + assert_eq!(POT_WIN, potential_wins(&sequences, &Disk::P2)); } #[test] fn win_test_flipping_hard() { let mut board = Board::default(); - board.play(Disk::BLU, 1); - board.play(Disk::BLU, 2); - board.play(Disk::BLU, 4); - let sequences = get_wins(&board.columns, &Disk::BLU); - assert_eq!(POT_WIN, potential_wins(&sequences, &Disk::BLU)); + board.play(Disk::P2, 1); + board.play(Disk::P2, 2); + board.play(Disk::P2, 4); + let sequences = get_wins(&board.columns, &Disk::P2); + assert_eq!(POT_WIN, potential_wins(&sequences, &Disk::P2)); } diff --git a/src/gamedata/mod.rs b/src/gamedata/mod.rs index 877b08c..7efa4a5 100644 --- a/src/gamedata/mod.rs +++ b/src/gamedata/mod.rs @@ -10,8 +10,8 @@ pub use indices::*; #[derive(Clone)] pub struct Board { - red_score: i32, - blu_score: i32, + p1_score: i32, + p2_score: i32, columns: Array2D, last_move: usize, } @@ -21,8 +21,8 @@ impl Default for Board { let columns = Array2D::filled_with(Disk::EMPTY, 6, 7); Self { - red_score: 0, - blu_score: 0, + p1_score: 0, + p2_score: 0, columns, last_move: 0, } @@ -31,7 +31,7 @@ impl Default for Board { impl Board { fn getscore(&self) -> (i32, i32) { - (self.red_score, self.blu_score) + (self.p1_score, self.p2_score) } fn play(&mut self, disk: Disk, col: usize) -> bool { let column = &self.columns.as_columns()[col]; @@ -55,7 +55,7 @@ impl Board { ); match self.columns.get(index.0, index.1) { Some(disk) => match disk { - Disk::RED => { + Disk::P1 => { for _move in moves { let mut consecutive = scan(&self.columns, &index, _move.clone(), 4); if consecutive < 4 { @@ -67,11 +67,11 @@ impl Board { ) } if consecutive - 1 == 4 { - self.red_score += 1 + self.p1_score += 1 } } } - Disk::BLU => { + Disk::P2 => { for _move in moves { let mut consecutive = scan(&self.columns, &index, _move.clone(), 4); if consecutive < 4 { @@ -83,7 +83,7 @@ impl Board { ) } if consecutive - 1 == 4 { - self.blu_score += 1 + self.p2_score += 1 } } } @@ -115,14 +115,14 @@ impl Board { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Disk { - RED, - BLU, + P1, + P2, EMPTY, } pub fn flip_disk(disk: Disk) -> Disk { match disk { - Disk::RED => Disk::BLU, - Disk::BLU => Disk::RED, + Disk::P1 => Disk::P2, + Disk::P2 => Disk::P1, Disk::EMPTY => Disk::EMPTY, //why..just why } } diff --git a/src/gamedata/tests.rs b/src/gamedata/tests.rs index 3686800..4a0a595 100644 --- a/src/gamedata/tests.rs +++ b/src/gamedata/tests.rs @@ -11,68 +11,68 @@ use super::*; #[test] fn play() { let mut board = Board::default(); - assert!(board.play(Disk::BLU, 0)); - assert!(board.play(Disk::BLU, 0)); - assert!(board.play(Disk::BLU, 0)); - assert!(board.play(Disk::BLU, 0)); - assert_eq!(1, board.blu_score); - assert!(board.play(Disk::BLU, 0)); - assert!(board.play(Disk::BLU, 0)); - assert!(!board.play(Disk::BLU, 0)); + assert!(board.play(Disk::P2, 0)); + assert!(board.play(Disk::P2, 0)); + assert!(board.play(Disk::P2, 0)); + assert!(board.play(Disk::P2, 0)); + assert_eq!(1, board.p2_score); + assert!(board.play(Disk::P2, 0)); + assert!(board.play(Disk::P2, 0)); + assert!(!board.play(Disk::P2, 0)); - assert!(board.play(Disk::BLU, 1)); - assert!(board.play(Disk::BLU, 1)); - assert!(board.play(Disk::BLU, 1)); - assert!(board.play(Disk::BLU, 1)); - assert!(board.play(Disk::BLU, 1)); - assert!(board.play(Disk::BLU, 1)); - assert!(!board.play(Disk::BLU, 1)); + assert!(board.play(Disk::P2, 1)); + assert!(board.play(Disk::P2, 1)); + assert!(board.play(Disk::P2, 1)); + assert!(board.play(Disk::P2, 1)); + assert!(board.play(Disk::P2, 1)); + assert!(board.play(Disk::P2, 1)); + assert!(!board.play(Disk::P2, 1)); - assert!(board.play(Disk::BLU, 2)); - assert!(board.play(Disk::BLU, 2)); - assert!(board.play(Disk::BLU, 2)); - assert!(board.play(Disk::BLU, 2)); - assert!(board.play(Disk::BLU, 2)); - assert!(board.play(Disk::BLU, 2)); - assert!(!board.play(Disk::BLU, 2)); + assert!(board.play(Disk::P2, 2)); + assert!(board.play(Disk::P2, 2)); + assert!(board.play(Disk::P2, 2)); + assert!(board.play(Disk::P2, 2)); + assert!(board.play(Disk::P2, 2)); + assert!(board.play(Disk::P2, 2)); + assert!(!board.play(Disk::P2, 2)); - assert!(board.play(Disk::BLU, 3)); - assert!(board.play(Disk::BLU, 3)); - assert!(board.play(Disk::BLU, 3)); - assert!(board.play(Disk::BLU, 3)); - assert!(board.play(Disk::BLU, 3)); - assert!(board.play(Disk::BLU, 3)); - assert!(!board.play(Disk::BLU, 3)); + assert!(board.play(Disk::P2, 3)); + assert!(board.play(Disk::P2, 3)); + assert!(board.play(Disk::P2, 3)); + assert!(board.play(Disk::P2, 3)); + assert!(board.play(Disk::P2, 3)); + assert!(board.play(Disk::P2, 3)); + assert!(!board.play(Disk::P2, 3)); } #[test] fn scan_updown() { let mut board = Board::default(); - board.play(Disk::BLU, 0); - board.play(Disk::BLU, 0); - board.play(Disk::BLU, 0); - board.play(Disk::BLU, 0); - board.play(Disk::BLU, 0); - board.play(Disk::BLU, 0); - board.play(Disk::BLU, 0); + board.play(Disk::P2, 0); + board.play(Disk::P2, 0); + board.play(Disk::P2, 0); + board.play(Disk::P2, 0); + board.play(Disk::P2, 0); + board.play(Disk::P2, 0); + board.play(Disk::P2, 0); assert_eq!(4, scan(&board.columns, &(4, 0), Direction::Down, 4)); assert_eq!(4, scan(&board.columns, &(3, 0), Direction::Down, 4)); } #[test] fn scan_updown2() { let mut board = Board::default(); - board.play(Disk::BLU, 0); - board.play(Disk::RED, 0); - board.play(Disk::BLU, 0); - board.play(Disk::BLU, 0); + board.play(Disk::P2, 0); + board.play(Disk::P1, 0); + board.play(Disk::P2, 0); + board.play(Disk::P2, 0); assert_eq!(1, scan(&board.columns, &(0, 0), Direction::Up, 4)); } #[test] fn scan_forwardback() { let mut board = Board::default(); - board.play(Disk::BLU, 0); - board.play(Disk::BLU, 1); - board.play(Disk::BLU, 2); - board.play(Disk::BLU, 3); + board.play(Disk::P2, 0); + board.play(Disk::P2, 1); + board.play(Disk::P2, 2); + board.play(Disk::P2, 3); assert_eq!(4, scan(&board.columns, &(0, 0), Direction::Right, 4)); assert_eq!(4, scan(&board.columns, &(0, 3), Direction::Left, 4)); @@ -80,59 +80,59 @@ fn scan_forwardback() { #[test] fn scan_forwardback2() { let mut board = Board::default(); - board.play(Disk::BLU, 0); - board.play(Disk::BLU, 1); - board.play(Disk::RED, 2); - board.play(Disk::BLU, 3); + board.play(Disk::P2, 0); + board.play(Disk::P2, 1); + board.play(Disk::P1, 2); + board.play(Disk::P2, 3); assert_eq!(2, scan(&board.columns, &(0, 0), Direction::Right, 4)); assert_eq!(1, scan(&board.columns, &(0, 3), Direction::Left, 4)); } #[test] fn scan_diag1() { let mut board = Board::default(); - board.play(Disk::BLU, 0); - board.play(Disk::RED, 1); - board.play(Disk::BLU, 1); - board.play(Disk::RED, 2); - board.play(Disk::RED, 2); - board.play(Disk::BLU, 2); - board.play(Disk::RED, 3); - board.play(Disk::RED, 3); - board.play(Disk::RED, 3); - board.play(Disk::BLU, 3); + board.play(Disk::P2, 0); + board.play(Disk::P1, 1); + board.play(Disk::P2, 1); + board.play(Disk::P1, 2); + board.play(Disk::P1, 2); + board.play(Disk::P2, 2); + board.play(Disk::P1, 3); + board.play(Disk::P1, 3); + board.play(Disk::P1, 3); + board.play(Disk::P2, 3); assert_eq!(4, scan(&board.columns, &(0, 0), Direction::UpRight, 4)); assert_eq!(4, scan(&board.columns, &(3, 3), Direction::DownLeft, 4)); } #[test] fn scan_diag2() { let mut board = Board::default(); - board.play(Disk::BLU, 3); - board.play(Disk::RED, 2); - board.play(Disk::BLU, 2); - board.play(Disk::RED, 1); - board.play(Disk::RED, 1); - board.play(Disk::BLU, 1); - board.play(Disk::RED, 0); - board.play(Disk::RED, 0); - board.play(Disk::RED, 0); - board.play(Disk::BLU, 0); + board.play(Disk::P2, 3); + board.play(Disk::P1, 2); + board.play(Disk::P2, 2); + board.play(Disk::P1, 1); + board.play(Disk::P1, 1); + board.play(Disk::P2, 1); + board.play(Disk::P1, 0); + board.play(Disk::P1, 0); + board.play(Disk::P1, 0); + board.play(Disk::P2, 0); dbg!(&board.columns.as_columns()); assert_eq!(4, scan(&board.columns, &(0, 3), Direction::UpLeft, 4)); assert_eq!(4, scan(&board.columns, &(3, 0), Direction::DownRight, 4)); } #[test] fn variant_eq_test() { - assert!(score_checkers::variant_eq(&Disk::RED, &Disk::RED)); - assert!(matches!(Disk::RED, Disk::RED)); - assert!(matches!(&Disk::BLU, &Disk::BLU)); - assert!(!score_checkers::variant_eq(&Disk::BLU, &Disk::RED)); - assert!(!matches!(Disk::BLU, Disk::RED)); + assert!(score_checkers::variant_eq(&Disk::P1, &Disk::P1)); + assert!(matches!(Disk::P1, Disk::P1)); + assert!(matches!(&Disk::P2, &Disk::P2)); + assert!(!score_checkers::variant_eq(&Disk::P2, &Disk::P1)); + assert!(!matches!(Disk::P2, Disk::P1)); } #[test] fn game_over_test() { let mut board = Board::default(); assert!(!board.game_over()); - board.columns = Array2D::filled_with(Disk::BLU, 7, 6); + board.columns = Array2D::filled_with(Disk::P2, 7, 6); assert!(board.game_over()); board.columns.set(0, 0, Disk::EMPTY).expect("balls"); assert!(!board.game_over()); From 5bebf782eb28607fe38c232570a1958a15366b57 Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 17:50:59 +0300 Subject: [PATCH 14/19] play state and menu state are separate now --- src/bored/mod.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/bored/mod.rs b/src/bored/mod.rs index 82ad42d..9e064bc 100644 --- a/src/bored/mod.rs +++ b/src/bored/mod.rs @@ -1,14 +1,16 @@ +use raylib::prelude::Color; + use crate::gamedata::{Board, Disk}; #[cfg(test)] mod tests; -pub struct GameState { +pub struct PlayState { pub circles: Vec<(i32, i32, Disk)>, pub bottom: Vec, pub player_turn: bool, pub board: Board, } -impl Default for GameState { +impl Default for PlayState { fn default() -> Self { Self { circles: vec![], @@ -18,3 +20,21 @@ impl Default for GameState { } } } +pub struct MenuState { + difficulty: i32, + p1: (Color, Disk), + p2: (Color, Disk), +} +impl Default for MenuState { + fn default() -> Self { + Self { + difficulty: 3, + p1: (Color::RED, Disk::P1), + p2: (Color::YELLOW, Disk::P2), + } + } +} +pub enum GameState { + Play(PlayState), + MainMenu(MenuState), +} From 1c8aa43983407646cf7bcf4f4e38cafb8a08f61b Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 18:04:32 +0300 Subject: [PATCH 15/19] refactor to adjust for playstates --- src/main.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 13845ee..e84deef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use oxidised4::{bored::GameState, gamedata::Disk}; +use oxidised4::{bored::PlayState, gamedata::Disk}; use raylib::prelude::*; const NROW: i32 = 6; const NCOL: i32 = 7; @@ -33,7 +33,7 @@ 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: GameState = GameState::default(); + let mut state: PlayState = PlayState::default(); rl.set_target_fps(60); while !rl.window_should_close() { @@ -41,13 +41,13 @@ fn main() { if d.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { let column = get_mouse_column(&d, square_widf); let coords = get_circle_coords(1, column); - state.circles.push((coords.1, coords.0, Disk::RED)); + state.circles.push((coords.1, coords.0, Disk::P1)); } for circle in &state.circles { let (x, y, disk) = circle; let color = match disk { - Disk::RED => Color::RED, - Disk::BLU => Color::BLUE, + Disk::P1 => Color::RED, + Disk::P2 => Color::BLUE, Disk::EMPTY => Color::WHITE, }; d.draw_texture(&circle_texture, *x, *y, color); From f6ebf19ef44318d435e55d0cc464c652977ba943 Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 20:26:47 +0300 Subject: [PATCH 16/19] my first if let statement :D --- src/main.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index e84deef..a2b7e69 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,9 +39,10 @@ fn main() { while !rl.window_should_close() { let mut d = rl.begin_drawing(&thread); if d.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { - let column = get_mouse_column(&d, square_widf); - let coords = get_circle_coords(1, column); - state.circles.push((coords.1, coords.0, Disk::P1)); + if let Some(column) = get_mouse_column(&d, square_widf) { + let coords = get_circle_coords(1, column); + state.circles.push((coords.1, coords.0, Disk::P1)); + } } for circle in &state.circles { let (x, y, disk) = circle; @@ -79,7 +80,7 @@ fn get_circle_coords(x: i32, y: i32) -> (i32, i32) { }; returned } -fn get_mouse_column(rl: &RaylibHandle, sw: i32) -> i32 { +fn get_mouse_column(rl: &RaylibHandle, sw: i32) -> Option { //row,col return let mouse_pos = rl.get_mouse_x(); dbg!(mouse_pos); @@ -87,8 +88,8 @@ fn get_mouse_column(rl: &RaylibHandle, sw: i32) -> i32 { dbg!(mouse_pos < sw * (num) - STARTY); if (mouse_pos > sw * (num - 1) + STARTY) && (mouse_pos < sw * (num) - STARTY) { dbg!(num); - return num; + return Some(num); } } - -100 + None } From 59474b531a3fac4cf77956f46d243cb5e834aa6d Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 22:26:41 +0300 Subject: [PATCH 17/19] ALMOST DONE AAAAA --- src/bored/mod.rs | 38 +++++++++++- src/gamedata/algorithms.rs | 118 +++++++++++++++++++++++++++++++++++-- src/gamedata/heuristic.rs | 10 ++-- src/gamedata/mod.rs | 13 ++-- src/main.rs | 46 +++++++-------- 5 files changed, 181 insertions(+), 44 deletions(-) diff --git a/src/bored/mod.rs b/src/bored/mod.rs index 9e064bc..26209c1 100644 --- a/src/bored/mod.rs +++ b/src/bored/mod.rs @@ -1,6 +1,11 @@ use raylib::prelude::Color; -use crate::gamedata::{Board, Disk}; +use crate::gamedata::{algorithms::minimax_decision, Board, Disk}; +pub const STARTY: i32 = 9; +pub const STARTX: i32 = 7; +const WX: i32 = 14; +const WY: i32 = 14; +const CIRCLEWIDTH: i32 = 56; #[cfg(test)] mod tests; @@ -14,12 +19,32 @@ impl Default for PlayState { fn default() -> Self { Self { circles: vec![], - bottom: vec![], - player_turn: false, + bottom: vec![6, 6, 6, 6, 6, 6, 6], + player_turn: true, board: Board::default(), } } } +impl PlayState { + pub fn play_human(&mut self, column: i32) { + self.board.play(Disk::P1, column as usize); + + self.bottom[column as usize] -= 1; + let (x, y) = get_circle_coords(column, self.bottom[column as usize]); + self.circles.push((x, y, Disk::P1)); + self.player_turn = false; + } + pub fn play_cpu(&mut self, cook: fn(&Board, Disk, &i32) -> Board) { + self.board + .play(Disk::P2, cook(&self.board, Disk::P2, &5).last_move as usize); + let column: i32 = self.board.last_move; + self.bottom[column as usize] -= 1; + let (x, y) = get_circle_coords(column, self.bottom[column as usize]); + self.circles.push((x, y, Disk::P2)); + self.player_turn = false; + self.player_turn = true; + } +} pub struct MenuState { difficulty: i32, p1: (Color, Disk), @@ -38,3 +63,10 @@ pub enum GameState { Play(PlayState), MainMenu(MenuState), } + +fn get_circle_coords(x: i32, y: i32) -> (i32, i32) { + let mut returned: (i32, i32) = (0, 0); + returned.0 = STARTY + (CIRCLEWIDTH * x) + (WX * x); + returned.1 = STARTX + (CIRCLEWIDTH * y) + (WY * y); + returned +} diff --git a/src/gamedata/algorithms.rs b/src/gamedata/algorithms.rs index 258a258..d3132f6 100644 --- a/src/gamedata/algorithms.rs +++ b/src/gamedata/algorithms.rs @@ -36,20 +36,128 @@ fn minimise(board: &Board, disk: &Disk, depth: &i32) -> (Option, i32) { } } } + +pub fn minimax_decision_pruning(board: &Board, disk: Disk, depth: &i32) -> Board { + let (child, _) = maximise_pruning(board, &disk, depth, i32::MIN, i32::MAX); + match child { + Some(state) => state, + None => Board::default(), + } +} +fn maximise_pruning( + board: &Board, + disk: &Disk, + depth: &i32, + alpha: i32, + mut beta: i32, +) -> (Option, i32) { + match board.game_over() || *depth == 0 { + true => (None, get_score(board, *disk)), + false => { + let (mut max_child, mut max_utility): (Option, i32) = (None, i32::MIN); + for child in board.get_children(*disk) { + let (_, utility) = + minimise_pruning(&child, &flip_disk(*disk), &(depth - 1), alpha, beta); + if utility <= alpha { + break; + } + if utility < beta { + beta = utility; + } + + if utility > max_utility { + (max_child, max_utility) = (Some(child), utility) + } + } + (max_child, max_utility) + } + } +} +fn minimise_pruning( + board: &Board, + disk: &Disk, + depth: &i32, + mut alpha: i32, + beta: i32, +) -> (Option, i32) { + match board.game_over() || *depth == 0 { + true => (None, get_score(board, flip_disk(*disk))), + false => { + let (mut min_child, mut min_utility): (Option, i32) = (None, i32::MAX); + for child in board.get_children(*disk) { + let (_, utility) = + maximise_pruning(&child, &flip_disk(*disk), &(depth - 1), alpha, beta); + if utility >= beta { + break; + } + if utility > alpha { + alpha = utility; + } + if utility < min_utility { + (min_child, min_utility) = (Some(child), utility) + } + } + (min_child, min_utility) + } + } +} #[test] fn minimax_test() { let mut board = Board::default(); let mut disk = Disk::P2; let _depth = 5; - let _turn1 = board.play(disk, minimax_decision(&board, disk, &5).last_move); + let _turn1 = board.play(disk, minimax_decision(&board, disk, &5).last_move as usize); + dbg!(&board.columns); disk = flip_disk(disk); - let _turn2 = board.play(disk, minimax_decision(&board, disk, &5).last_move); + let _turn2 = board.play(disk, minimax_decision(&board, disk, &5).last_move as usize); disk = flip_disk(disk); - let _turn3 = board.play(disk, minimax_decision(&board, disk, &5).last_move); + let _turn3 = board.play(disk, minimax_decision(&board, disk, &5).last_move as usize); disk = flip_disk(disk); - let _turn4 = board.play(disk, minimax_decision(&board, disk, &5).last_move); + let _turn4 = board.play(disk, minimax_decision(&board, disk, &5).last_move as usize); disk = flip_disk(disk); - let _turn5 = board.play(disk, minimax_decision(&board, disk, &5).last_move); + let _turn5 = board.play(disk, minimax_decision(&board, disk, &5).last_move as usize); + for column in board.columns.as_rows() { + column + .iter() + .map(|x| { + print!("{:#?},", x); + x + }) + .count(); + println!(); + } + assert!(false); +} +#[test] +fn minimax_pruning_test() { + let mut board = Board::default(); + let mut disk = Disk::P2; + let _depth = 5; + let _turn1 = board.play( + disk, + minimax_decision_pruning(&board, disk, &5).last_move as usize, + ); + dbg!(&board.columns); + disk = flip_disk(disk); + let _turn2 = board.play( + disk, + minimax_decision_pruning(&board, disk, &5).last_move as usize, + ); + disk = flip_disk(disk); + let _turn3 = board.play( + disk, + minimax_decision_pruning(&board, disk, &5).last_move as usize, + ); + disk = flip_disk(disk); + let _turn4 = board.play( + disk, + minimax_decision_pruning(&board, disk, &5).last_move as usize, + ); + disk = flip_disk(disk); + let _turn5 = board.play( + disk, + minimax_decision_pruning(&board, disk, &5).last_move as usize, + ); for column in board.columns.as_rows() { column .iter() diff --git a/src/gamedata/heuristic.rs b/src/gamedata/heuristic.rs index f52d920..58403da 100644 --- a/src/gamedata/heuristic.rs +++ b/src/gamedata/heuristic.rs @@ -6,11 +6,11 @@ use super::{ Board, Disk, }; //multipliers -const POT_STREAK: i32 = 4; //one streak is kind of poopy -const POT_STREAKS: i32 = 6; +const POT_STREAK: i32 = 3; //one streak is kind of poopy +const POT_STREAKS: i32 = 4; const POT_WIN: i32 = 5; // should be nerfed if its just 1 potential win -const POT_WINS: i32 = 8; -const SCORE_DIFF: i32 = 6; +const POT_WINS: i32 = 6; +const SCORE_DIFF: i32 = 40; const MAX_WINS: i32 = 17; pub fn get_score(board: &Board, disk: Disk) -> i32 { @@ -231,7 +231,7 @@ fn streak_test_1() { board.play(Disk::P2, 2); board.play(Disk::P2, 1); let sequences = get_streaks(&board.columns, &Disk::P2); - assert_eq!(18, potential_streaks(&sequences, &Disk::P2)); + assert_eq!(POT_STREAKS * 3, potential_streaks(&sequences, &Disk::P2)); board.play(Disk::P2, 0); let _sequences = get_streaks(&board.columns, &Disk::P2); board.play(Disk::P2, 3); diff --git a/src/gamedata/mod.rs b/src/gamedata/mod.rs index 7efa4a5..9506583 100644 --- a/src/gamedata/mod.rs +++ b/src/gamedata/mod.rs @@ -1,4 +1,4 @@ -mod algorithms; +pub mod algorithms; mod heuristic; mod indices; mod score_checkers; @@ -13,7 +13,7 @@ pub struct Board { p1_score: i32, p2_score: i32, columns: Array2D, - last_move: usize, + pub last_move: i32, } impl Default for Board { @@ -30,10 +30,10 @@ impl Default for Board { } impl Board { - fn getscore(&self) -> (i32, i32) { + pub fn getscore(&self) -> (i32, i32) { (self.p1_score, self.p2_score) } - fn play(&mut self, disk: Disk, col: usize) -> bool { + pub fn play(&mut self, disk: Disk, col: usize) -> bool { let column = &self.columns.as_columns()[col]; let empty = column.iter().filter(|&a| matches!(a, Disk::EMPTY)).count(); // dbg!(empty); @@ -41,7 +41,8 @@ impl Board { match self.columns.set(top, col, disk) { Ok(_) => { self.score_check((top, col)); - self.last_move = col; + self.last_move = col as i32; + //dbg!(self.p1_score, self.p2_score); true } Err(_) => false, @@ -92,7 +93,7 @@ impl Board { None => (), } } - fn game_over(&self) -> bool { + pub fn game_over(&self) -> bool { self.columns .as_row_major() .iter() diff --git a/src/main.rs b/src/main.rs index a2b7e69..d49a8c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,7 @@ -use oxidised4::{bored::PlayState, gamedata::Disk}; +use oxidised4::{ + bored::PlayState, + gamedata::{algorithms::minimax_decision_pruning, Disk}, +}; use raylib::prelude::*; const NROW: i32 = 6; const NCOL: i32 = 7; @@ -38,17 +41,26 @@ fn main() { rl.set_target_fps(60); while !rl.window_should_close() { let mut d = rl.begin_drawing(&thread); - if d.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) { - if let Some(column) = get_mouse_column(&d, square_widf) { - let coords = get_circle_coords(1, column); - state.circles.push((coords.1, coords.0, Disk::P1)); + 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 => 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::BLUE, + Disk::P2 => Color::YELLOW, Disk::EMPTY => Color::WHITE, }; d.draw_texture(&circle_texture, *x, *y, color); @@ -59,27 +71,11 @@ fn main() { } //TODO move this to a struct -const STARTY: i32 = 9; -const STARTX: i32 = 7; +pub const STARTY: i32 = 9; +pub const STARTX: i32 = 7; const WX: i32 = 14; const WY: i32 = 14; const CIRCLEWIDTH: i32 = 56; -fn get_circle_coords(x: i32, y: i32) -> (i32, i32) { - let mut returned: (i32, i32) = (STARTY, STARTX); - match x { - 1 => {} - _ => { - returned.0 = STARTY + (CIRCLEWIDTH * (x - 1)) + (WX * (x - 1)); - } - }; - match y { - 1 => {} - _ => { - returned.1 = STARTX + (CIRCLEWIDTH * (y - 1)) + (WY * (y - 1)); - } - }; - returned -} fn get_mouse_column(rl: &RaylibHandle, sw: i32) -> Option { //row,col return let mouse_pos = rl.get_mouse_x(); @@ -88,7 +84,7 @@ fn get_mouse_column(rl: &RaylibHandle, sw: i32) -> Option { dbg!(mouse_pos < sw * (num) - STARTY); if (mouse_pos > sw * (num - 1) + STARTY) && (mouse_pos < sw * (num) - STARTY) { dbg!(num); - return Some(num); + return Some(num - 1); } } None From 31f5b2cdc71dee239cb33df57a21cf60eab3735a Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 23:14:19 +0300 Subject: [PATCH 18/19] EVERYTHING IS WORKING --- src/bored/mod.rs | 54 ++++++++++++++++++++++++++-- src/gamedata/heuristic.rs | 3 +- src/main.rs | 76 +++++++++++++++++++++++---------------- 3 files changed, 98 insertions(+), 35 deletions(-) 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(); From bc2e56f4b9e485b75f6d4b8845c5bd9a48fbfe5b Mon Sep 17 00:00:00 2001 From: LinlyBoi Date: Sat, 6 May 2023 23:24:15 +0300 Subject: [PATCH 19/19] time calculation + feature selection --- src/bored/mod.rs | 8 +++++--- src/main.rs | 27 ++++++++++++++++----------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/bored/mod.rs b/src/bored/mod.rs index 95148e8..10cdbf0 100644 --- a/src/bored/mod.rs +++ b/src/bored/mod.rs @@ -38,9 +38,11 @@ impl PlayState { self.circles.push((x, y, Disk::P1)); self.player_turn = false; } - pub fn play_cpu(&mut self, cook: fn(&Board, Disk, &i32) -> Board) { - self.board - .play(Disk::P2, cook(&self.board, Disk::P2, &5).last_move as usize); + pub fn play_cpu(&mut self, diff: &i32, cook: fn(&Board, Disk, &i32) -> Board) { + self.board.play( + Disk::P2, + cook(&self.board, Disk::P2, diff).last_move as usize, + ); let column: i32 = self.board.last_move; self.bottom[column as usize] -= 1; let (x, y) = get_circle_coords(column, self.bottom[column as usize]); diff --git a/src/main.rs b/src/main.rs index 31f4d04..a98e191 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use std::time::Instant; + use oxidised4::{ bored::{GameState, MenuState, PlayState, Strategy}, gamedata::{ @@ -63,14 +65,20 @@ fn main() { } } } - 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); + false => { + dbg!(); + let time = Instant::now(); + match strategy { + Strategy::MiniMax => state.play_cpu(&difficulty, minimax_decision), + Strategy::AlphaBeta => { + state.play_cpu(&difficulty, minimax_decision_pruning) + } + }; + println!( + "Time elapsed in cpu turn: {} ms", + time.elapsed().as_millis() + ); + } } for circle in state.clone().circles { @@ -93,11 +101,8 @@ const STARTY: i32 = 9; fn get_mouse_column(rl: &RaylibHandle, sw: i32) -> Option { //row,col return let mouse_pos = rl.get_mouse_x(); - dbg!(mouse_pos); for num in 1..NCOL + 1 { - dbg!(mouse_pos < sw * (num) - STARTY); if (mouse_pos > sw * (num - 1) + STARTY) && (mouse_pos < sw * (num) - STARTY) { - dbg!(num); return Some(num - 1); } }