From 6e20961dcf24b458ca3e4569d18238285df3352f Mon Sep 17 00:00:00 2001 From: ParsaAminpour Date: Sat, 27 Jul 2024 16:59:30 +0330 Subject: [PATCH] implementing multi-threading for reactions functionality --- Cargo.lock | 77 ++++++++++++++++++++++++++++ Cargo.toml | 1 + src/lib.rs | 143 ++++++++++++++++++++++++++++++++++++++++++++-------- src/main.rs | 43 ++++++---------- 4 files changed, 215 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d249ea3..de47d4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -59,6 +74,21 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bindgen" version = "0.69.4" @@ -343,6 +373,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + [[package]] name = "glob" version = "0.3.1" @@ -544,6 +580,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.11" @@ -667,6 +712,15 @@ dependencies = [ "syn", ] +[[package]] +name = "object" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +dependencies = [ + "memchr", +] + [[package]] name = "oboe" version = "0.6.1" @@ -753,6 +807,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + [[package]] name = "pkg-config" version = "0.3.30" @@ -888,6 +948,7 @@ dependencies = [ "rodio", "sed", "sled", + "tokio", ] [[package]] @@ -904,6 +965,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -1084,6 +1151,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "1.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d040ac2b29ab03b09d4129c2f5bbd012a3ac2f79d38ff506a4bf8dd34b0eac8a" +dependencies = [ + "backtrace", + "pin-project-lite", +] + [[package]] name = "toml_datetime" version = "0.6.6" diff --git a/Cargo.toml b/Cargo.toml index 4bacf4c..1906b24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ rand = "0.8.5" rodio = "0.19.0" sed = "0.1.0" sled = "0.34.7" +tokio = "1.39.1" diff --git a/src/lib.rs b/src/lib.rs index 2e192d7..2eb5965 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -use std::{io::{stdout, Result, Stdout, Write}, thread::sleep, vec}; +use std::{borrow::{Borrow, BorrowMut}, clone, io::{stdout, Result, Stdout, Write}, thread::{self, sleep}, vec}; use crossterm::{ cursor::{Hide, MoveTo, Show}, event::{poll, read, Event, KeyCode}, style::{ Color, Print, ResetColor, SetBackgroundColor, SetForegroundColor}, terminal::{enable_raw_mode, size, Clear, ClearType}, ExecutableCommand, QueueableCommand @@ -6,7 +6,7 @@ use crossterm::{ use std::fs::File; use std::io::BufReader; -use rodio::{Decoder, OutputStream, source::Source}; +use rodio::{buffer, source::Source, Decoder, OutputStream}; use ndarray::{Array2, Array}; use inline_colorization::*; @@ -57,23 +57,6 @@ pub enum Sound { BoatCrashed(String) } -pub fn handle_sound(sound_file: String) { - let (_stream, stream_handler) = OutputStream::try_default().unwrap(); - let file = BufReader::new(File::open(sound_file).unwrap()); - let source = Decoder::new(file).unwrap(); - - stream_handler.play_raw(source.convert_samples()).unwrap(); -} - -pub fn handle_sound2(sound_file: String) { - let (_stream, handle) = rodio::OutputStream::try_default().unwrap(); - let sink = rodio::Sink::try_new(&handle).unwrap(); - - let file = std::fs::File::open(sound_file.to_string()).unwrap(); - sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); - - sink.sleep_until_end(); -} #[derive(Debug)] pub struct Game2DMatrix { @@ -278,7 +261,7 @@ impl Game2DMatrix { Ok(()) } - + pub fn reactions(&mut self, /*screen: &mut Stdout*/) -> Result<()> { let user_j: usize = self.player_j as usize; @@ -292,7 +275,7 @@ impl Game2DMatrix { self.game_staus = GameStatus::DEATH; } - // enemies + /////////////////////////////// Take reaction to the enemies chars. /////////////////////////////// let mut enemies_to_remove: Vec = vec![]; for (idx, enemy) in self.enemies.iter_mut().enumerate() { @@ -315,19 +298,22 @@ impl Game2DMatrix { } } } + enemies_to_remove.sort_unstable_by(|a, b| b.cmp(a)); // Sort in reverse order for idx in enemies_to_remove { self.enemies.remove(idx); self.enemy_killed += 1; } - // Take reaction to the fuel chars. + + /////////////////////////////// Take reaction to the fuel chars. /////////////////////////////// for fuel in self.fuels.iter() { if (fuel.location.element_j-2..fuel.location.element_j+2).contains(&self.player_i) && (fuel.location.element_i == self.player_j) { self.gas += 30; } } + /////////////////////////////// Take reaction to bottom of the screen /////////////////////////////// self.enemies.retain(|enemy| { enemy.location.element_i < self.max_screen_j - 3 }); @@ -338,7 +324,120 @@ impl Game2DMatrix { (fuel.location.element_i > self.max_screen_j - 3) ) ); + Ok(()) + } + + + + pub fn reactions2(self: &'static mut Self) -> Result<()> { + let user_j: usize = self.player_j as usize; + + let arc_game = Arc::new(Mutex::new(self)); + let cloned_game = Arc::clone(&arc_game); + + let handle_accidents = thread::spawn(move || { + let mut game = cloned_game.lock().unwrap(); + + if game.gas == 0 { + game.game_staus = GameStatus::DEATH; + } + + // handling the boat accidentation with ground + if game.player_i <= game.ground[user_j].0 || game.player_i >= game.ground[user_j].1 + { + game.game_staus = GameStatus::DEATH; + } + }); + + + /////////////////////////////// Take reaction to the enemies with the player /////////////////////////////// + let cloned_game2 = Arc::clone(&arc_game); + + let handle_enemy_accident_with_player = std::thread::spawn(move || { + let mut game = cloned_game2.lock().unwrap(); + let (player_i, player_j) = (game.player_i, game.player_j); + + let game_status: bool = game.enemies.iter().any(|enemy| { + (enemy.location.element_j-1..enemy.location.element_j+1).contains(&player_i) && + enemy.location.element_i == player_j + }); + + if game_status { game.game_staus = GameStatus::DEATH; } + }); + + + /////////////////////////////// Take reaction to the fuel chars. /////////////////////////////// + let cloned_game3 = Arc::clone(&arc_game); + + let handle_fuel_reaction = std::thread::spawn(move || { + let mut game = cloned_game3.lock().unwrap(); + let (player_i, player_j) = (game.player_i, game.player_j); + + let res: bool = game.fuels.iter().any(|fuel| { + (fuel.location.element_j-2..fuel.location.element_j+2).contains(&player_i) && + (fuel.location.element_i == player_j) + }); + + if res { game.gas += 40; } + }); + + + /////////////////////////////// Take reaction to the enemies with the player /////////////////////////////// + let mut enemies_to_remove :Vec = Vec::new(); + let mut game_in_main_thread = arc_game.lock().unwrap(); + + for (idx, enemy) in &mut game_in_main_thread.enemies.iter_mut().enumerate() { + for bullet in Arc::clone(&arc_game).lock().unwrap().bullets.iter_mut() { + if bullet.active && (enemy.location.element_i-1..enemy.location.element_i+1).contains(&bullet.location.element_i) && + (enemy.location.element_j-2..enemy.location.element_j+2).contains(&bullet.location.element_j) + { + enemy.logo = ' '.to_string(); + enemies_to_remove.push(idx); + sleep(Duration::from_millis(100)); + bullet.active = false; + bullet.logo = ' '.to_string(); + } + } + } + + enemies_to_remove.sort_unstable_by(|a, b| b.cmp(a)); // Sort in reverse order + for idx in enemies_to_remove { + game_in_main_thread.enemies.remove(idx); + game_in_main_thread.enemy_killed += 1; + } + + + /////////////////////////////// Take reaction to bottom of the screen /////////////////////////////// + // self.enemies.retain(|enemy| { + // enemy.location.element_i < self.max_screen_j - 3 + // }); + + // self.fuels.retain(|fuel| + // !((fuel.location.element_j-1..fuel.location.element_j+1).contains(&self.player_i) && + // (fuel.location.element_i == self.player_j) || + // (fuel.location.element_i > self.max_screen_j - 3) + // ) + // ); + + + handle_accidents.join().unwrap(); + handle_enemy_accident_with_player.join().unwrap(); + handle_fuel_reaction.join().unwrap(); Ok(()) } } + + + +pub fn handle_sound(sound_file: String){ + let (_stream, handle) = rodio::OutputStream::try_default().unwrap(); + let sink = rodio::Sink::try_new(&handle).unwrap(); + + let file = std::fs::File::open(sound_file.to_string()).unwrap(); + sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap()); + + sink.sleep_until_end(); +} + + diff --git a/src/main.rs b/src/main.rs index 68845a3..fd700af 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ use std::time::Duration; use river_raid::*; use std::sync::{Arc, Mutex}; use std::cell::RefCell; +use tokio::task; fn main() -> Result<()> { let mut screen = stdout(); @@ -23,23 +24,22 @@ fn main() -> Result<()> { while nd2array.game_staus == GameStatus::ALIVE { // implementing the keyboard binding. - if poll(Duration::from_millis(10))? { + if poll(Duration::from_millis(5))? { let key = read().unwrap(); while poll(Duration::from_millis(0)).unwrap() { let _ = read(); } - // Bug related to the Refrence counted while single thread and multi-thread processes are combined with eachother. - let rc_nd2array = Rc::new(RefCell::new(nd2array)); - + // Bug the 'static input in the reactions function borrowed the nd2array, therefore we could NOT use that. + // let rc_nd2array = Rc::new(RefCell::new(nd2array)); match key { Event::Key(event) => { match event.code { KeyCode::Char('q') => { break; }, - KeyCode::Right => if nd2array.player_i + 1 < nd2array.max_screen_i { cloned_nd2array.player_i += 2; }, + KeyCode::Right => if nd2array.player_i + 1 < nd2array.max_screen_i { nd2array.player_i += 2; }, KeyCode::Left => if nd2array.player_i - 1 > 0 { nd2array.player_i -= 2; }, @@ -48,29 +48,18 @@ fn main() -> Result<()> { KeyCode::Down => if nd2array.player_j + 1 < nd2array.max_screen_j { nd2array.player_j += 1; }, KeyCode::Char(' ') => { - let atomic_nd2array = Arc::new(Mutex::new(nd2array)); - let cloned_atomic_nd2array = Arc::clone(&atomic_nd2array); - - let handle_bullet_drowing = std::thread::spawn(move || { - let mut locked_atomic_nd2array = cloned_atomic_nd2array.lock().unwrap(); - - locked_atomic_nd2array.bullets.push(Bullet { - location: Location { - element_i: Arc::clone(&atomic_nd2array).lock().unwrap().player_j, - element_j: Arc::clone(&atomic_nd2array).lock().unwrap().player_i, - }, - active: true, - logo: '🔥'.to_string() - }); - - }); - - let handle_sound = thread::spawn(move || { - handle_sound2("src/assets/laser_ray_zap_singleshot.wav".to_string()); + thread::spawn(move || { + handle_sound("src/assets/laser_ray_zap_singleshot.wav".to_string()); }); - handle_bullet_drowing.join().unwrap(); - handle_sound.join().unwrap(); + nd2array.bullets.push(Bullet { + location: Location { + element_i: nd2array.player_j, + element_j: nd2array.player_i, + }, + active: true, + logo: '🔥'.to_string() + }); } _ => {} } @@ -80,7 +69,7 @@ fn main() -> Result<()> { } // let rc_nd2array = Rc::new(&nd2array); - sleep(Duration::from_millis(66)); + sleep(Duration::from_millis(60)); nd2array.reactions().unwrap(); nd2array.draw(&mut screen, rand::thread_rng().gen_bool(0.1), rand::thread_rng().gen_bool(0.01)).unwrap();