Snake doesn't clear the board every run

also changed all i32 to u32
This commit is contained in:
Uttarayan Mondal
2021-01-25 02:48:54 +05:30
parent eeaa8a2675
commit 8bc7770bf3
7 changed files with 90 additions and 53 deletions
Generated
+1 -1
View File
@@ -94,7 +94,7 @@ dependencies = [
[[package]] [[package]]
name = "snake" name = "snake"
version = "0.2.0" version = "0.2.1"
dependencies = [ dependencies = [
"ncurses", "ncurses",
"rand", "rand",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "snake" name = "snake"
version = "0.2.0" version = "0.2.1"
authors = ["Uttarayan Mondal <uttarayan21@gmail.com>"] authors = ["Uttarayan Mondal <uttarayan21@gmail.com>"]
edition = "2018" edition = "2018"
+3 -2
View File
@@ -79,9 +79,10 @@ A few notes about the game and how I should improve the game
<summary>Rust specific stuff I learned</summary> <summary>Rust specific stuff I learned</summary>
> [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. > [ncursesw](httsp://docs.rs/ncursesw) is not needed to print unicode characters. I have no clue where I got that idea from.
+4
View File
@@ -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
+43 -20
View File
@@ -61,8 +61,8 @@ pub enum CellType {
Empty, Empty,
} }
pub struct Cell { pub struct Cell {
line: i32, line: u32,
col: i32, col: u32,
ctype: CellType, ctype: CellType,
} }
impl PartialEq for Cell { impl PartialEq for Cell {
@@ -77,28 +77,37 @@ impl PartialEq for Cell {
impl Sub for Cell { impl Sub for Cell {
type Output = (i32, i32); type Output = (i32, i32);
fn sub(self, rhs: Cell) -> (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 { impl Cell {
pub fn new(l: i32, c: i32, t: CellType) -> Cell { pub fn new(l: u32, c: u32, t: CellType) -> Cell {
Cell { Cell {
line: l, line: l,
col: c, col: c,
ctype: t, ctype: t,
} }
} }
pub fn random(lines: i32, cols: i32) -> Cell { pub fn random(lines: u32, cols: u32) -> Cell {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
Cell::new( Cell::new(
rng.gen_range(1..lines - 1), rng.gen_range(1..lines - 1) as u32,
rng.gen_range(1..cols - 1), rng.gen_range(1..cols - 1) as u32,
CellType::Food, CellType::Food,
) )
} }
pub fn posyx(&self) -> (i32, i32) { pub fn posyx(&self) -> (u32, u32) {
return (self.line, self.col); 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) { pub fn chtype(&mut self, ctype: CellType) {
self.ctype = ctype; self.ctype = ctype;
} }
@@ -138,15 +147,15 @@ enum GameState {
} }
pub struct Board { pub struct Board {
maxlines: i32, maxlines: u32,
maxcols: i32, maxcols: u32,
gamestate: GameState, gamestate: GameState,
food: Cell, food: Cell,
} }
// impl Board<'_> { // impl Board<'_> {
impl Board { impl Board {
pub fn new(maxlines: i32, maxcols: i32) -> Board { pub fn new(maxlines: u32, maxcols: u32) -> Board {
Board { Board {
maxlines, maxlines,
maxcols, maxcols,
@@ -155,7 +164,7 @@ impl Board {
} }
} }
pub fn check_collision(&mut self, snake: &Snake) -> bool { 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) if (snake_line >= self.maxlines - 1)
|| (snake_col >= self.maxcols - 1) || (snake_col >= self.maxcols - 1)
|| (snake_line <= 0) || (snake_line <= 0)
@@ -182,9 +191,12 @@ impl Board {
return false; return false;
} }
} }
pub fn food_posyx(&self) -> (i32, i32) { pub fn food_posyx(&self) -> (u32, u32) {
return self.food.posyx(); return self.food.posyx();
} }
// pub fn food_posy(&self) -> u32 {
// return self.food.line;
// }
pub fn eat_food(&mut self, snake: &mut Snake) { pub fn eat_food(&mut self, snake: &mut Snake) {
snake.grow(); snake.grow();
// self.food.chtype(CellType::Empty); // self.food.chtype(CellType::Empty);
@@ -217,7 +229,8 @@ pub struct Snake {
body: LinkedList<Cell>, body: LinkedList<Cell>,
direction: Direction, direction: Direction,
grow: bool, grow: bool,
speed: i32, speed: u32,
last_tail: Option<Cell>,
} }
impl Snake { impl Snake {
pub fn new(head: Cell) -> Snake { pub fn new(head: Cell) -> Snake {
@@ -230,14 +243,14 @@ impl Snake {
direction: Direction::Right, direction: Direction::Right,
grow: false, grow: false,
speed: 15, 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); return (self.head.line, self.head.col);
} }
pub fn smove(&mut self, _direction: Direction) { pub fn smove(&mut self, _direction: Direction) {
// smove because move is already a keyword // smove because move is already a keyword
let mut tail: Cell;
let direction: Direction; let direction: Direction;
if self.direction == _direction.opposite() { if self.direction == _direction.opposite() {
direction = self.direction direction = self.direction
@@ -245,18 +258,22 @@ impl Snake {
direction = _direction direction = _direction
} }
if self.grow == false { if self.grow == false {
tail = self.body.pop_back().unwrap(); self.last_tail = Some(self.body.pop_back().unwrap());
tail.chtype(CellType::Empty);
// self.grow = false; // self.grow = false;
} }
let (dl, dc) = match direction { let (dl, dc): (i32, i32) = match direction {
Direction::Up => (-1, 0), Direction::Up => (-1, 0),
Direction::Down => (1, 0), Direction::Down => (1, 0),
Direction::Left => (0, -1), Direction::Left => (0, -1),
Direction::Right => (0, 1), Direction::Right => (0, 1),
}; };
self.direction = direction; 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.body.push_front(self.head);
self.grow = false; self.grow = false;
} }
@@ -274,4 +291,10 @@ impl Snake {
pub fn iter(&self) -> impl Iterator<Item = &Cell> { pub fn iter(&self) -> impl Iterator<Item = &Cell> {
return self.body.iter(); return self.body.iter();
} }
pub fn remove(&self) -> Option<Cell> {
return self.last_tail;
}
pub fn set_speed(&mut self, speed: u32) {
self.speed = speed;
}
} }
+26 -20
View File
@@ -4,15 +4,15 @@ use ncurses::{
box_, delwin, keypad, mvwaddstr, newwin, stdscr, waddstr, wborder, wclrtobot, wmove, wrefresh, box_, delwin, keypad, mvwaddstr, newwin, stdscr, waddstr, wborder, wclrtobot, wmove, wrefresh,
WINDOW, 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 game_win: WINDOW;
let (lines, cols): (i32, i32); let (lines, cols): (u32, u32);
let (starty, startx): (i32, i32); let (starty, startx): (u32, u32);
lines = mlines - vmargin * 2; lines = mlines - vmargin * 2;
cols = mcols - hmargin * 2; cols = mcols - hmargin * 2;
starty = vmargin; starty = vmargin;
startx = hmargin; 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); box_(game_win, 0, 0);
keypad(game_win, true); keypad(game_win, true);
wrefresh(game_win); 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 prev, mut current, _next): (&Cell, &Cell, &Cell);
let mut snake_iter = snake.iter(); let mut snake_iter = snake.iter();
wmove(game_win, 0, 0); wmove(game_win, 0, 0);
wclrtobot(game_win); // wclrtobot(game_win);
box_(game_win, 0, 0); box_(game_win, 0, 0);
// I want to draw the snake as ascii box charachters // 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 prev = snake_iter.next().unwrap(); // currently this should be head. On initial run this should be the only snake_cell
mvwaddstr( mvwaddstr(
game_win, game_win,
prev.posyx().0, prev.posy() as i32,
prev.posyx().1, prev.posx() as i32,
&format!("{}", std::char::from_u32(0x0298).unwrap_or('O')), &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(); let _current = snake_iter.next();
current = match _current { current = match _current {
Some(cell) => cell, Some(cell) => cell,
@@ -52,7 +58,7 @@ pub fn draw_snake(snake: &Snake, game_win: WINDOW) {
}; };
for next in snake_iter { for next in snake_iter {
// O(n) the whole snake is redrawn every single tick // 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"); // mvwaddstr(game_win, snake_l, snake_c, "o");
let snake_char: u32 = match ( let snake_char: u32 = match (
prev.is_adjacent(current).unwrap(), prev.is_adjacent(current).unwrap(),
@@ -68,8 +74,8 @@ pub fn draw_snake(snake: &Snake, game_win: WINDOW) {
}; };
mvwaddstr( mvwaddstr(
game_win, game_win,
snake_l, snake_l as i32,
snake_c, snake_c as i32,
&format!("{}", std::char::from_u32(snake_char).unwrap_or('o')), &format!("{}", std::char::from_u32(snake_char).unwrap_or('o')),
); );
prev = current; prev = current;
@@ -78,8 +84,8 @@ pub fn draw_snake(snake: &Snake, game_win: WINDOW) {
mvwaddstr( mvwaddstr(
game_win, game_win,
current.posyx().0, current.posy() as i32,
current.posyx().1, current.posx() as i32,
&format!( &format!(
"{}", "{}",
std::char::from_u32(match current.is_adjacent(prev).unwrap() { 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) { 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( mvwaddstr(
game_win, game_win,
food_l, food_l as i32,
food_c, food_c as i32,
&format!("{}", std::char::from_u32(0x0298).unwrap_or('F')), &format!("{}", std::char::from_u32(0x0298).unwrap_or('F')),
); );
} }
pub fn _log(snake: &Snake, board: &Board) { pub fn _log(_snake: &Snake, _board: &Board) {
let (shl, shc): (i32, i32) = snake.posyx(); let (shl, shc): (u32, u32) = _snake.posyx();
let (bfl, bfc): (i32, i32) = board.food_posyx(); let (stl, stc): (u32, u32) = _snake.remove().unwrap().posyx();
mvwaddstr(stdscr(), 0, 0, &format!("snake:head: {} {} ", shl, shc)); 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); wmove(stdscr(), 2, 0);
for snake_cell in snake.iter() { for snake_cell in _snake.iter() {
waddstr( waddstr(
stdscr(), stdscr(),
&format!( &format!(
+12 -9
View File
@@ -10,21 +10,21 @@ pub fn start() {
let (mut mlines, mut mcols): (i32, i32) = (0, 0); let (mut mlines, mut mcols): (i32, i32) = (0, 0);
let game_win: WINDOW; let game_win: WINDOW;
let mut ch: i32; let mut ch: i32;
let (vmargin, hmargin): (i32, i32) = (5, 10); let (vmargin, hmargin): (u32, u32) = (5, 10);
getmaxyx(stdscr(), &mut mlines, &mut mcols); 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( let mut snake = Snake::new(Cell::new(
mlines / 2 - vmargin, mlines as u32 / 2 - vmargin,
mcols / 2 - hmargin, mcols as u32 / 2 - hmargin,
backend::CellType::Snake, backend::CellType::Snake,
)); //Initialise snake in the middle of the screen )); //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); nodelay(game_win, true);
loop { loop {
frontend::draw_snake(&snake, game_win); // always draw snake before board because the snake will clear the game win 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::draw_board(&board, game_win);
// frontend::_log(&snake, &board); frontend::_log(&snake, &board);
if board.check_collision(&snake) { if board.check_collision(&snake) {
// Add stuff here to show the score and // Add stuff here to show the score and
// how You lose screen // how You lose screen
@@ -46,9 +46,12 @@ pub fn start() {
//112 is keycode for 'p' //112 is keycode for 'p'
0 => (), //resume 0 => (), //resume
1 => { 1 => {
snake = snake = Snake::new(Cell::new(
Snake::new(Cell::new(mlines / 2, mcols / 2, backend::CellType::Snake)); //Initialise snake in the middle of the screen mlines as u32 / 2,
board = Board::new(mlines - vmargin * 2, mcols - hmargin * 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 } //restart
2 => break, //exit 2 => break, //exit
_ => (), //other charachters just in case _ => (), //other charachters just in case