diff --git a/src/game.rs b/src/game.rs index 4e3b6d6..3253f79 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,7 +1,7 @@ -use ncurses::{mvprintw, attroff, attron, A_BOLD, COLOR_PAIR, addstr }; +use crate::snake::Snake; +use crate::utils::{Direction, Position}; +use ncurses::{addstr, attroff, attron, mvprintw, A_BOLD, COLOR_PAIR}; use rand::Rng; -use crate::snake::{Snake}; -use crate::utils::{ Position, Direction }; pub struct Game { username: String, @@ -19,22 +19,22 @@ struct Food { impl Food { fn new(value: i32) -> Self { Food { - value: value, + value, icon: "$".to_string(), pos: Position::new(12, 10), } } - fn display(&self) -> () { + fn display(&self) { attron(COLOR_PAIR(1) | A_BOLD()); mvprintw(self.pos.posy, self.pos.posx, self.icon.as_str()); attroff(COLOR_PAIR(1) | A_BOLD()); } - fn relocate(&mut self, width: i32, height: i32) -> () { + fn relocate(&mut self, width: i32, height: i32) { let mut rng = rand::thread_rng(); - self.pos.posy = rng.gen_range(1..=height-2); - self.pos.posx = rng.gen_range(1..=width-2); + self.pos.posy = rng.gen_range(1..=height - 2); + self.pos.posx = rng.gen_range(1..=width - 2); } } @@ -53,7 +53,7 @@ impl Game { } } - pub fn update_score(&mut self, width: i32, height: i32) -> () { + pub fn update_score(&mut self, width: i32, height: i32) { if let Some(head) = self.snake.snake.front_mut() { if head.pos == self.food.pos { self.score += self.food.value; @@ -67,28 +67,40 @@ impl Game { match ch { 119 | 259 => match self.snake.direction { Direction::BOTTOM => {} - _ => self.snake.direction = Direction::TOP, + _ => { + self.snake.direction = Direction::TOP; + self.snake.speed = 4; + } }, // w 97 | 260 => match self.snake.direction { Direction::RIGHT => {} - _ => self.snake.direction = Direction::LEFT, + _ => { + self.snake.direction = Direction::LEFT; + self.snake.speed = 4; + } }, // A 115 | 258 => match self.snake.direction { Direction::TOP => {} - _ => self.snake.direction = Direction::BOTTOM, + _ => { + self.snake.direction = Direction::BOTTOM; + self.snake.speed = 4; + } }, //s 100 | 261 => match self.snake.direction { Direction::LEFT => {} - _ => self.snake.direction = Direction::RIGHT, + _ => { + self.snake.direction = Direction::RIGHT; + self.snake.speed = 4; + } }, // D _ => {} } } - pub fn display(&mut self) -> () { + pub fn display(&mut self) { let data = format!("USER : {} | SCORE : {}", self.username, self.score); addstr(&data); self.snake.display(); self.food.display(); } -} \ No newline at end of file +} diff --git a/src/game_window.rs b/src/game_window.rs index c11e44a..ad8ba32 100644 --- a/src/game_window.rs +++ b/src/game_window.rs @@ -7,6 +7,12 @@ pub struct GameWindow { pub window_height: i32, } +impl Default for GameWindow { + fn default() -> Self { + Self::new() + } +} + impl GameWindow { pub fn new() -> Self { initscr(); @@ -38,7 +44,13 @@ impl GameWindow { endwin(); } - pub fn pause_menu(&mut self, height: i32, width: i32, title: String, is_gameover : bool) -> Action { + pub fn pause_menu( + &mut self, + height: i32, + width: i32, + title: String, + is_gameover: bool, + ) -> Action { let mut component: Component = Component::new(height, width, self.window_height, self.window_width); @@ -62,14 +74,15 @@ impl GameWindow { napms(100); match getch() { ERR => {} - 27 => { + 27 => { component.del(); - return Action::QUIT + return Action::QUIT; + } + x => { + if let Err(n) = component.handle_input(x) { + return n; + } } - x => match component.handle_input(x) { - Err(n) => return n, - _ => {} - }, } } } @@ -92,20 +105,21 @@ impl GameWindow { napms(100); match getch() { ERR => {} - 27 => { + 27 => { component.del(); - return Action::QUIT + return Action::QUIT; + } + x => { + if let Err(n) = component.handle_input(x) { + return n; + } } - x => match component.handle_input(x) { - Err(n) => return n, - _ => {} - }, } } } - pub fn get_name(&mut self, height : i32, width: i32) -> String{ - let title: String = String::from("You Name?"); + pub fn get_name(&mut self, height: i32, width: i32) -> String { + let title: String = String::from("You Name?"); let mut component: Component = Component::new(height, width, self.window_height, self.window_width); @@ -118,16 +132,18 @@ impl GameWindow { component.display(); component.refresh(); napms(100); - match getch(){ - ERR => {}, + match getch() { + ERR => {} 10 | 27 => break, c => { - if c == 263 && name.len() > 0 { + if c == 263 && !name.is_empty() { name.truncate(name.len() - 1); - } - else if ( c >= 48 && c <= 57) || ( c >= 65 && c <= 90 ) || ( c >= 97 && c <= 122 ){ + } else if (48..=57).contains(&c) + || (65..=90).contains(&c) + || (97..=122).contains(&c) + { let ch = char::from_u32(c as u32).unwrap(); - name = format!("{}{}",name, ch ); + name = format!("{}{}", name, ch); } } }; @@ -136,6 +152,4 @@ impl GameWindow { component.del(); name } - } - diff --git a/src/main.rs b/src/main.rs index 64c447d..dcadd88 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,20 @@ use ncurses::*; use viper::game::Game; -use viper::game_window::{*}; +use viper::game_window::*; use viper::window_component::Action; fn main() { + timeout(0); + let mut window = GameWindow::new(); 'new_game: loop { - match window.start_menu(6, 30 ){ - Action::QUIT => break 'new_game, - _ => {} + if let Action::QUIT = window.start_menu(6, 30) { + break 'new_game; } let name: String = window.get_name(6, 30); - let mut game: Game = Game::new( - name, - window.window_width, - window.window_height, - ); + let mut game: Game = Game::new(name, window.window_width, window.window_height); 'curr_game: loop { - let mut is_gameover : bool = false; + let mut is_gameover: bool = false; 'game: loop { clear(); game.display(); @@ -31,21 +28,25 @@ fn main() { break 'game; } }; - napms(100); match getch() { - ERR => {} + ERR => { + game.snake.speed = 1; + } 27 => break 'game, n => game.control_snake(n), } + let speed = 100 / game.snake.speed; + napms(speed); } let msg: String = format!("Score : {}", game.score); match window.pause_menu(6, 30, msg, is_gameover) { Action::QUIT => break 'new_game, Action::RESTART => break 'curr_game, - Action::RESUME => {}, + Action::RESUME => {} _ => {} } } } window.exit(); } + diff --git a/src/snake.rs b/src/snake.rs index f427385..65ab2a0 100644 --- a/src/snake.rs +++ b/src/snake.rs @@ -1,8 +1,8 @@ +use ncurses::{attroff, attron, mvprintw, A_BOLD}; use std::collections::HashSet; use std::collections::VecDeque; -use ncurses::{mvprintw, attroff, attron, A_BOLD }; -use crate::utils::{Position, Direction}; +use crate::utils::{Direction, Position}; #[derive(Clone, Copy, Debug)] enum Part { @@ -20,6 +20,7 @@ pub struct SnakeBodyPart { pub struct Snake { pub snake: VecDeque, pub direction: Direction, + pub speed: i32, texture: (String, String, String), snake_hash: HashSet, } @@ -28,22 +29,20 @@ impl SnakeBodyPart { fn new(position: Position, part: Part) -> Self { SnakeBodyPart { pos: position, - part: part, + part, } } - fn display(&self, texture: (String, String, String)) -> () { - let ch: String; - match self.part { - Part::HEAD => ch = texture.0.clone(), - Part::BODY => ch = texture.1.clone(), - Part::TAIL => ch = texture.2.clone(), - } + fn display(&self, texture: (String, String, String)) { + let ch: String = match self.part { + Part::HEAD => texture.0.clone(), + Part::BODY => texture.1.clone(), + Part::TAIL => texture.2.clone(), + }; mvprintw(self.pos.posy, self.pos.posx, ch.as_str()); } } - impl Snake { pub fn new(position: Position, texture: (String, String, String)) -> Self { let p1 = SnakeBodyPart::new(position, Part::HEAD); @@ -52,10 +51,11 @@ impl Snake { let hash_set: HashSet = HashSet::from([p1.pos.hash(), p2.pos.hash(), p3.pos.hash()]); let snake: VecDeque = VecDeque::from([p1, p2, p3]); Snake { - snake: snake, + snake, direction: Direction::RIGHT, - texture: texture, + texture, snake_hash: hash_set, + speed: 1, } } @@ -73,10 +73,11 @@ impl Snake { } self.snake.push_front(p); } + Ok(()) } - pub fn extend_back(&mut self) -> () { + pub fn extend_back(&mut self) { if let Some(curr_tail) = self.snake.back_mut() { curr_tail.part = Part::BODY; let p: SnakeBodyPart = @@ -106,7 +107,7 @@ impl Snake { Ok(()) } - pub fn display(&self) -> () { + pub fn display(&self) { attron(A_BOLD()); for part in self.snake.iter() { part.display(self.texture.clone()); diff --git a/src/window_component.rs b/src/window_component.rs index 75a3c8e..83f941b 100644 --- a/src/window_component.rs +++ b/src/window_component.rs @@ -1,41 +1,39 @@ -use ncurses::{wattroff, wattron, box_, delwin, mvwprintw, newwin, wrefresh, A_BOLD, COLOR_PAIR, KEY_ENTER, wclear }; use crate::utils::Position; +use ncurses::{ + box_, delwin, mvwprintw, newwin, wattroff, wattron, wclear, wrefresh, A_BOLD, COLOR_PAIR, + KEY_ENTER, +}; #[derive(Clone, Copy)] -pub enum Action{ +pub enum Action { QUIT, RESUME, RESTART, - START + START, } -pub struct Choice -{ +pub struct Choice { text: String, handler: Action, } - pub struct Component { win: *mut i8, height: i32, width: i32, - cur_y : i32, + cur_y: i32, options: Vec, option_len: usize, option_selected: usize, inputs: String, input_len: usize, - title :String, - title_pos: Position + title: String, + title_pos: Position, } -impl Choice{ +impl Choice { pub fn new(text: String, handler: Action) -> Self { - Choice { - text: text, - handler: handler, - } + Choice { text, handler } } } @@ -45,16 +43,16 @@ impl Component { let posx = (window_width - width) / 2; Component { win: newwin(height, width, posy, posx), - height: height, - width: width, + height, + width, cur_y: 1, options: Vec::new(), option_len: 0, option_selected: 0, - title : String::new(), - title_pos : Position::new(0, 0), + title: String::new(), + title_pos: Position::new(0, 0), input_len: 0, - inputs : String::new() + inputs: String::new(), } } @@ -69,7 +67,7 @@ impl Component { self.title_pos.posy = 1; } - pub fn add_choice(&mut self, choice : Choice) { + pub fn add_choice(&mut self, choice: Choice) { self.options.push(choice); self.option_len += 1; if self.option_len as i32 == self.height { @@ -82,15 +80,19 @@ impl Component { pub fn display(&mut self) { // displaying the title - wattron(self.win,COLOR_PAIR(1) | A_BOLD()); - mvwprintw(self.win, self.title_pos.posy, self.title_pos.posx, self.title.as_str()); - wattroff(self.win,COLOR_PAIR(1) | A_BOLD()); + wattron(self.win, COLOR_PAIR(1) | A_BOLD()); + mvwprintw( + self.win, + self.title_pos.posy, + self.title_pos.posx, + self.title.as_str(), + ); + wattroff(self.win, COLOR_PAIR(1) | A_BOLD()); self.cur_y = 2; //displaying inputs if self.input_len > 0 { - - let line = format!("+{}+", "-".repeat(self.width as usize - 4) ); + let line = format!("+{}+", "-".repeat(self.width as usize - 4)); mvwprintw(self.win, self.cur_y, 1, line.as_str()); self.cur_y += 1; let p = (self.width - (self.inputs.len() as i32)) / 2; @@ -101,17 +103,15 @@ impl Component { mvwprintw(self.win, self.cur_y, 1, line.as_str()); } - // displaying the options - if self.option_len > 0 { + if self.option_len > 0 { for i in 0..self.option_len { let p = (self.width - (self.options[i].text.len() as i32)) / 2; if i == self.option_selected { wattron(self.win, A_BOLD()); mvwprintw(self.win, self.cur_y, p, self.options[i].text.as_str()); wattroff(self.win, A_BOLD()); - } - else{ + } else { mvwprintw(self.win, self.cur_y, p, self.options[i].text.as_str()); } self.cur_y += 1; @@ -122,22 +122,18 @@ impl Component { pub fn handle_input(&mut self, x: i32) -> Result<(), Action> { match x { 115 | 258 => { - self.option_selected = ( self.option_selected + 1 ) % self.option_len; - }, + self.option_selected = (self.option_selected + 1) % self.option_len; + } 119 | 259 => { if self.option_selected == 0 { self.option_selected = self.option_len - 1; + } else { + self.option_selected = (self.option_selected - 1) % self.option_len; } - else { - self.option_selected = ( self.option_selected - 1 ) % self.option_len; - } - }, + } KEY_ENTER | 10 => { - match self.option_handler(self.options[self.option_selected].handler){ - Err(n) => return Err(n), - _ => {} - }; - }, + self.option_handler(self.options[self.option_selected].handler)?; + } _ => {} } Ok(()) @@ -148,17 +144,29 @@ impl Component { self.input_len as i32 } - pub fn update_input(&mut self, input: String, index: i32) -> () { + pub fn update_input(&mut self, input: String, index: i32) { let _ = index - 1; self.inputs = input; } - fn option_handler(&mut self, action : Action ) -> Result<(), Action> { + fn option_handler(&mut self, action: Action) -> Result<(), Action> { match action { - Action::QUIT => { self.del(); return Err(Action::QUIT) }, - Action::RESTART => { self.del(); return Err(Action::RESTART) }, - Action::RESUME => { self.del(); return Err(Action::RESUME) }, - Action::START => { self.del(); return Err(Action::START )} + Action::QUIT => { + self.del(); + Err(Action::QUIT) + } + Action::RESTART => { + self.del(); + Err(Action::RESTART) + } + Action::RESUME => { + self.del(); + Err(Action::RESUME) + } + Action::START => { + self.del(); + Err(Action::START) + } } } @@ -173,5 +181,4 @@ impl Component { pub fn clear(&self) { wclear(self.win); } - }