Snake doesn't clear the board every run
also changed all i32 to u32
This commit is contained in:
Generated
+1
-1
@@ -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
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user