diff --git a/Cargo.lock b/Cargo.lock index c8091a3..8d97fe6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,7 +94,7 @@ dependencies = [ [[package]] name = "snake" -version = "0.2.0" +version = "0.2.1" dependencies = [ "ncurses", "rand", diff --git a/Cargo.toml b/Cargo.toml index ab75090..fcc0f7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snake" -version = "0.2.0" +version = "0.2.1" authors = ["Uttarayan Mondal "] edition = "2018" diff --git a/README.md b/README.md index 552ccea..d4246b6 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,10 @@ A few notes about the game and how I should improve the game Rust specific stuff I learned -> [char](https://doc.rust-lang.org/stable/std/primitive.char.html) and [std::char](https://doc.rust-lang.org/stable/std/char/index.html) are different +> [char](https://doc.rust-lang.org/stable/std/primitive.char.html) and [std::char](https://doc.rust-lang.org/stable/std/char/index.html) are not the same. +> [char](https://doc.rust-lang.org/stable/std/primitive.char.html) is the primitive type [std::char](https://doc.rust-lang.org/stable/std/char/index.html) is the char module. -> [char](https://doc.rust-lang.org/stable/std/primitive.char.html) is the primitive type [std::char](https://doc.rust-lang.org/stable/std/char/index.html) is the char module. All the functions are not completely same for both (as of rust v1.49.0) +> As of Sat, 23 Jan 2021 21:49:13 +0000 the char::from_u32 (used in this program) is not valid in primitive [char](https://doc.rust-lang.org/stable/std/primitive.char.html) but is valid in [std::char](https://doc.rust-lang.org/stable/std/char/index.html) > [ncursesw](httsp://docs.rs/ncursesw) is not needed to print unicode characters. I have no clue where I got that idea from. diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md new file mode 100644 index 0000000..5d15e14 --- /dev/null +++ b/docs/CHANGELOG.md @@ -0,0 +1,4 @@ +- v0.2.1 + + - > Change all the i32 variables to u32. + - > Changed the snake logic a bit so that the snake doesn't clear the whole board for every draw diff --git a/src/game/backend.rs b/src/game/backend.rs index bc5b578..51fd9fd 100644 --- a/src/game/backend.rs +++ b/src/game/backend.rs @@ -61,8 +61,8 @@ pub enum CellType { Empty, } pub struct Cell { - line: i32, - col: i32, + line: u32, + col: u32, ctype: CellType, } impl PartialEq for Cell { @@ -77,28 +77,37 @@ impl PartialEq for Cell { impl Sub for Cell { type Output = (i32, i32); fn sub(self, rhs: Cell) -> (i32, i32) { - return (self.line - rhs.line, self.col - rhs.col); + return ( + self.line as i32 - rhs.line as i32, + self.col as i32 - rhs.col as i32, + ); } } impl Cell { - pub fn new(l: i32, c: i32, t: CellType) -> Cell { + pub fn new(l: u32, c: u32, t: CellType) -> Cell { Cell { line: l, col: c, ctype: t, } } - pub fn random(lines: i32, cols: i32) -> Cell { + pub fn random(lines: u32, cols: u32) -> Cell { let mut rng = rand::thread_rng(); Cell::new( - rng.gen_range(1..lines - 1), - rng.gen_range(1..cols - 1), + rng.gen_range(1..lines - 1) as u32, + rng.gen_range(1..cols - 1) as u32, CellType::Food, ) } - pub fn posyx(&self) -> (i32, i32) { + pub fn posyx(&self) -> (u32, u32) { return (self.line, self.col); } + pub fn posy(&self) -> u32 { + return self.line; + } + pub fn posx(&self) -> u32 { + return self.col; + } pub fn chtype(&mut self, ctype: CellType) { self.ctype = ctype; } @@ -138,15 +147,15 @@ enum GameState { } pub struct Board { - maxlines: i32, - maxcols: i32, + maxlines: u32, + maxcols: u32, gamestate: GameState, food: Cell, } // impl Board<'_> { impl Board { - pub fn new(maxlines: i32, maxcols: i32) -> Board { + pub fn new(maxlines: u32, maxcols: u32) -> Board { Board { maxlines, maxcols, @@ -155,7 +164,7 @@ impl Board { } } pub fn check_collision(&mut self, snake: &Snake) -> bool { - let (snake_line, snake_col): (i32, i32) = snake.posyx(); + let (snake_line, snake_col): (u32, u32) = snake.posyx(); if (snake_line >= self.maxlines - 1) || (snake_col >= self.maxcols - 1) || (snake_line <= 0) @@ -182,9 +191,12 @@ impl Board { return false; } } - pub fn food_posyx(&self) -> (i32, i32) { + pub fn food_posyx(&self) -> (u32, u32) { return self.food.posyx(); } + // pub fn food_posy(&self) -> u32 { + // return self.food.line; + // } pub fn eat_food(&mut self, snake: &mut Snake) { snake.grow(); // self.food.chtype(CellType::Empty); @@ -217,7 +229,8 @@ pub struct Snake { body: LinkedList, direction: Direction, grow: bool, - speed: i32, + speed: u32, + last_tail: Option, } impl Snake { pub fn new(head: Cell) -> Snake { @@ -230,14 +243,14 @@ impl Snake { direction: Direction::Right, grow: false, speed: 15, + last_tail: Some(head), } } - pub fn posyx(&self) -> (i32, i32) { + pub fn posyx(&self) -> (u32, u32) { return (self.head.line, self.head.col); } pub fn smove(&mut self, _direction: Direction) { // smove because move is already a keyword - let mut tail: Cell; let direction: Direction; if self.direction == _direction.opposite() { direction = self.direction @@ -245,18 +258,22 @@ impl Snake { direction = _direction } if self.grow == false { - tail = self.body.pop_back().unwrap(); - tail.chtype(CellType::Empty); + self.last_tail = Some(self.body.pop_back().unwrap()); + // self.grow = false; } - let (dl, dc) = match direction { + let (dl, dc): (i32, i32) = match direction { Direction::Up => (-1, 0), Direction::Down => (1, 0), Direction::Left => (0, -1), Direction::Right => (0, 1), }; self.direction = direction; - self.head = Cell::new(self.head.line + dl, self.head.col + dc, CellType::Snake); + self.head = Cell::new( + ((self.head.line as i32) + dl) as u32, + ((self.head.col as i32) + dc) as u32, + CellType::Snake, + ); self.body.push_front(self.head); self.grow = false; } @@ -274,4 +291,10 @@ impl Snake { pub fn iter(&self) -> impl Iterator { return self.body.iter(); } + pub fn remove(&self) -> Option { + return self.last_tail; + } + pub fn set_speed(&mut self, speed: u32) { + self.speed = speed; + } } diff --git a/src/game/frontend.rs b/src/game/frontend.rs index df6475b..63cf414 100644 --- a/src/game/frontend.rs +++ b/src/game/frontend.rs @@ -4,15 +4,15 @@ use ncurses::{ box_, delwin, keypad, mvwaddstr, newwin, stdscr, waddstr, wborder, wclrtobot, wmove, wrefresh, WINDOW, }; -pub fn game_window(mlines: i32, mcols: i32, vmargin: i32, hmargin: i32) -> WINDOW { +pub fn game_window(mlines: u32, mcols: u32, vmargin: u32, hmargin: u32) -> WINDOW { let game_win: WINDOW; - let (lines, cols): (i32, i32); - let (starty, startx): (i32, i32); + let (lines, cols): (u32, u32); + let (starty, startx): (u32, u32); lines = mlines - vmargin * 2; cols = mcols - hmargin * 2; starty = vmargin; startx = hmargin; - game_win = newwin(lines, cols, starty, startx); + game_win = newwin(lines as i32, cols as i32, starty as i32, startx as i32); box_(game_win, 0, 0); keypad(game_win, true); wrefresh(game_win); @@ -32,7 +32,7 @@ pub fn draw_snake(snake: &Snake, game_win: WINDOW) { let (mut prev, mut current, _next): (&Cell, &Cell, &Cell); let mut snake_iter = snake.iter(); wmove(game_win, 0, 0); - wclrtobot(game_win); + // wclrtobot(game_win); box_(game_win, 0, 0); // I want to draw the snake as ascii box charachters @@ -41,10 +41,16 @@ pub fn draw_snake(snake: &Snake, game_win: WINDOW) { prev = snake_iter.next().unwrap(); // currently this should be head. On initial run this should be the only snake_cell mvwaddstr( game_win, - prev.posyx().0, - prev.posyx().1, + prev.posy() as i32, + prev.posx() as i32, &format!("{}", std::char::from_u32(0x0298).unwrap_or('O')), ); + match snake.remove() { + Some(tail) => { + mvwaddstr(game_win, tail.posy() as i32, tail.posx() as i32, " "); + } + None => (), + } let _current = snake_iter.next(); current = match _current { Some(cell) => cell, @@ -52,7 +58,7 @@ pub fn draw_snake(snake: &Snake, game_win: WINDOW) { }; for next in snake_iter { // O(n) the whole snake is redrawn every single tick - let (snake_l, snake_c): (i32, i32) = current.posyx(); + let (snake_l, snake_c): (u32, u32) = current.posyx(); // mvwaddstr(game_win, snake_l, snake_c, "o"); let snake_char: u32 = match ( prev.is_adjacent(current).unwrap(), @@ -68,8 +74,8 @@ pub fn draw_snake(snake: &Snake, game_win: WINDOW) { }; mvwaddstr( game_win, - snake_l, - snake_c, + snake_l as i32, + snake_c as i32, &format!("{}", std::char::from_u32(snake_char).unwrap_or('o')), ); prev = current; @@ -78,8 +84,8 @@ pub fn draw_snake(snake: &Snake, game_win: WINDOW) { mvwaddstr( game_win, - current.posyx().0, - current.posyx().1, + current.posy() as i32, + current.posx() as i32, &format!( "{}", std::char::from_u32(match current.is_adjacent(prev).unwrap() { @@ -93,22 +99,22 @@ pub fn draw_snake(snake: &Snake, game_win: WINDOW) { } pub fn draw_board(board: &Board, game_win: WINDOW) { - let (food_l, food_c): (i32, i32) = board.food_posyx(); + let (food_l, food_c): (u32, u32) = board.food_posyx(); mvwaddstr( game_win, - food_l, - food_c, + food_l as i32, + food_c as i32, &format!("{}", std::char::from_u32(0x0298).unwrap_or('F')), ); } -pub fn _log(snake: &Snake, board: &Board) { - let (shl, shc): (i32, i32) = snake.posyx(); - let (bfl, bfc): (i32, i32) = board.food_posyx(); +pub fn _log(_snake: &Snake, _board: &Board) { + let (shl, shc): (u32, u32) = _snake.posyx(); + let (stl, stc): (u32, u32) = _snake.remove().unwrap().posyx(); mvwaddstr(stdscr(), 0, 0, &format!("snake:head: {} {} ", shl, shc)); - mvwaddstr(stdscr(), 1, 0, &format!("board:food: {} {} ", bfl, bfc)); + mvwaddstr(stdscr(), 1, 0, &format!("snake:tail: {} {} ", stl, stc)); wmove(stdscr(), 2, 0); - for snake_cell in snake.iter() { + for snake_cell in _snake.iter() { waddstr( stdscr(), &format!( diff --git a/src/game/mod.rs b/src/game/mod.rs index f3e6a20..f19b4bc 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -10,21 +10,21 @@ pub fn start() { let (mut mlines, mut mcols): (i32, i32) = (0, 0); let game_win: WINDOW; let mut ch: i32; - let (vmargin, hmargin): (i32, i32) = (5, 10); + let (vmargin, hmargin): (u32, u32) = (5, 10); getmaxyx(stdscr(), &mut mlines, &mut mcols); - game_win = frontend::game_window(mlines, mcols, vmargin, hmargin); + game_win = frontend::game_window(mlines as u32, mcols as u32, vmargin, hmargin); let mut snake = Snake::new(Cell::new( - mlines / 2 - vmargin, - mcols / 2 - hmargin, + mlines as u32 / 2 - vmargin, + mcols as u32 / 2 - hmargin, backend::CellType::Snake, )); //Initialise snake in the middle of the screen - let mut board = Board::new(mlines - vmargin * 2, mcols - hmargin * 2); + let mut board = Board::new(mlines as u32 - vmargin * 2, mcols as u32 - hmargin * 2); nodelay(game_win, true); loop { frontend::draw_snake(&snake, game_win); // always draw snake before board because the snake will clear the game win frontend::draw_board(&board, game_win); - // frontend::_log(&snake, &board); + frontend::_log(&snake, &board); if board.check_collision(&snake) { // Add stuff here to show the score and // how You lose screen @@ -46,9 +46,12 @@ pub fn start() { //112 is keycode for 'p' 0 => (), //resume 1 => { - snake = - Snake::new(Cell::new(mlines / 2, mcols / 2, backend::CellType::Snake)); //Initialise snake in the middle of the screen - board = Board::new(mlines - vmargin * 2, mcols - hmargin * 2); + snake = Snake::new(Cell::new( + mlines as u32 / 2, + mcols as u32 / 2, + backend::CellType::Snake, + )); //Initialise snake in the middle of the screen + board = Board::new(mlines as u32 - vmargin * 2, mcols as u32 - hmargin * 2); } //restart 2 => break, //exit _ => (), //other charachters just in case