diff --git a/.gitignore b/.gitignore
index ea8c4bf..96ef6c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
/target
+Cargo.lock
diff --git a/Cargo.lock b/Cargo.lock
index f6aaef8..c8091a3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -31,9 +31,9 @@ checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
[[package]]
name = "ncurses"
-version = "5.99.0"
+version = "5.100.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15699bee2f37e9f8828c7b35b2bc70d13846db453f2d507713b758fabe536b82"
+checksum = "a7db07ca287f6f4fb267e8b2ab0f9eb68f5a311a97315aaee845afa98f8a416b"
dependencies = [
"cc",
"libc",
diff --git a/Cargo.toml b/Cargo.toml
index 98b4b7d..ab75090 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,5 +7,5 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-ncurses = "5.71.1"
+ncurses = "5.100.0"
rand = "0.8.0"
diff --git a/README.md b/README.md
index ec8f171..f1197ac 100644
--- a/README.md
+++ b/README.md
@@ -39,3 +39,22 @@ Click the image for asciinema
#### Maybe in the future
- [ ] Autoplay the game using a simple pathfinding algorithm (to show on [r/unixporn](https://reddit.com/r/unixporn) of course :clown_face:)
+
+#### Notes
+
+A few notes about the complexity of the game and how I should improve the game
+
+
+Read More
+
+The complexity of the program is O(n) every tick (time which changes relative to the speed)
+
+However the place, I can improve is the redrawing of the game
+
+As of commit
+f9be68e
+the game redraws the total board and the total snake every tick.
+
+I think this can be improved by only drawing the parts of the snake and the board when needed
+
+
diff --git a/src/game/backend.rs b/src/game/backend.rs
index e3addda..83d2ef7 100644
--- a/src/game/backend.rs
+++ b/src/game/backend.rs
@@ -2,6 +2,7 @@ extern crate rand;
use core::iter::Iterator;
use rand::Rng;
use std::collections::LinkedList;
+use std::ops::Sub;
use std::thread::sleep;
use std::time::Duration;
pub enum Direction {
@@ -58,6 +59,12 @@ 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);
+ }
+}
impl Cell {
pub fn new(l: i32, c: i32, t: CellType) -> Cell {
Cell {
@@ -80,6 +87,15 @@ impl Cell {
pub fn chtype(&mut self, ctype: CellType) {
self.ctype = ctype;
}
+ pub fn is_adjacent(&self, other: &Cell) -> Option {
+ match *self - *other {
+ (0, 1) => Some(Direction::Left),
+ (1, 0) => Some(Direction::Down),
+ (-1, 0) => Some(Direction::Right),
+ (0, -1) => Some(Direction::Up),
+ _ => None,
+ }
+ }
}
impl Copy for CellType {}
@@ -136,6 +152,7 @@ impl Board {
let mut snake_iter = snake.iter();
snake_iter.next();
for snake_cell in snake_iter {
+ // O(n) ; don't know how to reduce this complexity
if snake.posyx() == snake_cell.posyx() {
self.gamestate = GameState::Failed(FailState::Snake);
return true;
@@ -167,6 +184,7 @@ impl Board {
let mut snake_iter = snake.iter();
for snake_cell in snake_iter.next() {
if *snake_cell == food {
+ // O(n) ; I think this is nessacary/ I don't know how to reduce the order
// if food collides with the snake body then set food to a new random position and set spawned food to false
// so that the snake_iter is started again from the front of the snake
food = Cell::random(self.maxlines, self.maxcols);
diff --git a/src/game/frontend.rs b/src/game/frontend.rs
index 6a11723..5cccbf7 100644
--- a/src/game/frontend.rs
+++ b/src/game/frontend.rs
@@ -1,7 +1,8 @@
// use ncurses::*;
-use crate::game::backend::{Board, Snake};
+use crate::game::backend::{Board, Cell, Direction, Snake};
use ncurses::{
- box_, delwin, keypad, mvwaddstr, newwin, stdscr, wborder, wclrtobot, wmove, wrefresh, WINDOW,
+ 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 {
let game_win: WINDOW;
@@ -30,13 +31,58 @@ pub fn destroy_window(win: WINDOW) {
pub fn draw_snake(snake: &Snake, game_win: WINDOW) {
// let mut snake_iter = snake.iter();
+ let (mut prev, mut current, _next): (&Cell, &Cell, &Cell);
+ let mut snake_iter = snake.iter();
wmove(game_win, 0, 0);
wclrtobot(game_win);
box_(game_win, 0, 0);
- for snake_cell in snake.iter() {
- let (snake_l, snake_c): (i32, i32) = snake_cell.posyx();
- mvwaddstr(game_win, snake_l, snake_c, "o");
+
+ // I want to draw the snake as ascii box charachters
+ // So I'll need to know the last and next cell of the snake to draw the current snake_cell
+ // For some reason the snake goes invisible after the first food
+ 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, &format!("H"));
+ let _current = snake_iter.next();
+ // current = match _current {
+ // Some(cell) => cell,
+ // None => return,
+ // };
+ if _current.is_some() {
+ current = _current.unwrap();
+ } else {
+ return;
+ } // the match is equivalent to this block of code
+ // this should be none in the initial run
+ // as of now this will panic as soon as the game starts
+ // I need to match this with Some(Cell) and None and if
+ // none then just straight exit from the function
+
+ // The head is never in current so the head is not being printed as of now
+ for next in snake_iter {
+ // O(n) the whole snake is redrawn every single tick
+ let (snake_l, snake_c): (i32, i32) = current.posyx();
+ // mvwaddstr(game_win, snake_l, snake_c, "o");
+ let snake_char = match (
+ prev.is_adjacent(current).unwrap(),
+ next.is_adjacent(current).unwrap(),
+ ) {
+ (Direction::Up, Direction::Down) | (Direction::Down, Direction::Up) => "║", //186, //boxdraw double vertical line ║ code 186
+ (Direction::Up, Direction::Left) | (Direction::Left, Direction::Left) => "╝", //188, // ╝
+ (Direction::Up, Direction::Right) | (Direction::Right, Direction::Up) => "╚", //200, // ╚
+ (Direction::Down, Direction::Left) | (Direction::Left, Direction::Down) => "╗", //187, // ╗
+ (Direction::Down, Direction::Right) | (Direction::Right, Direction::Down) => "╔", //,201, // ╔
+ (Direction::Left, Direction::Right) | (Direction::Right, Direction::Left) => "═", //205 ═
+ _ => " ",
+ };
+ mvwaddstr(
+ game_win, snake_l, snake_c, // &format!("{}", snake_char as char),
+ // &format!("{}", snake_char),
+ "o",
+ );
+ prev = current;
+ current = next;
}
+ mvwaddstr(game_win, current.posyx().0, current.posyx().1, "t");
wrefresh(game_win);
}
@@ -60,15 +106,16 @@ pub fn _log(snake: &Snake, board: &Board) {
// ),
// );
- // for snake_cell in snake.iter() {
- // let (scl, scc): (i32, i32) = snake_cell.posyx();
- // waddstr(stdscr(), &format!("cell: {} {} ", scl, scc));
- // }
- // mvwaddstr(
- // stdscr(),
- // 2,
- // 0,
- // &format!("snake_size {}", snake.iter().size_hint().0),
- // );
+ wmove(stdscr(), 2, 0);
+ for snake_cell in snake.iter() {
+ let (scl, scc): (i32, i32) = snake_cell.posyx();
+ waddstr(stdscr(), &format!("cell: {} {} ", scl, scc));
+ }
+ mvwaddstr(
+ stdscr(),
+ 3,
+ 0,
+ &format!("snake_size {}", snake.iter().size_hint().0),
+ );
wrefresh(stdscr());
}
diff --git a/src/game/mod.rs b/src/game/mod.rs
index 9fb1595..f2c30b6 100644
--- a/src/game/mod.rs
+++ b/src/game/mod.rs
@@ -22,9 +22,9 @@ pub fn start() {
let mut board = Board::new(mlines - vmargin * 2, mcols - hmargin * 2);
nodelay(game_win, true);
loop {
- frontend::draw_snake(&snake, 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::_log(&snake, &board);
+ frontend::_log(&snake, &board);
if board.check_collision(&snake) {
// Add stuff here to show the score and
// how You lose screen
diff --git a/src/main.rs b/src/main.rs
index 9ae1405..51ba3f0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -17,6 +17,10 @@ fn main() {
noecho();
let (mut mlines, mut mcols): (i32, i32) = (0, 0);
getmaxyx(stdscr(), &mut mlines, &mut mcols);
+ // let (mlines, mcols) = match getmaxyx(stdscr()) {
+ // Ok(size) => (size.lines, size.columns),
+ // Err(e) => panic!(e),
+ // };
if (mlines < 20) || (mcols < 35) {
refresh();
endwin();