From 6f9a5bd91fd9db573ac8fbd2582c917a6d0bdd75 Mon Sep 17 00:00:00 2001 From: Uttarayan Mondal Date: Mon, 18 Jan 2021 03:28:18 +0530 Subject: [PATCH] Basic playable version --- src/game/backend.rs | 88 +++++++++++++++++++++++++++++++++++++------- src/game/frontend.rs | 38 +++++++++++++++---- src/game/mod.rs | 10 ++--- src/menu.rs | 5 ++- 4 files changed, 115 insertions(+), 26 deletions(-) diff --git a/src/game/backend.rs b/src/game/backend.rs index ac8a3b5..93cbffa 100644 --- a/src/game/backend.rs +++ b/src/game/backend.rs @@ -1,6 +1,9 @@ extern crate rand; +use core::iter::Iterator; use rand::Rng; use std::collections::LinkedList; +use std::thread::sleep; +use std::time::Duration; pub enum Direction { Up, Down, @@ -13,6 +16,29 @@ impl Clone for Direction { *self } } +impl PartialEq for Direction { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (&Self::Up, &Self::Up) => true, + (&Self::Down, &Self::Down) => true, + (&Self::Left, &Self::Left) => true, + (&Self::Right, &Self::Right) => true, + _ => false, + } + } +} + +impl Direction { + fn opposite(&self) -> Self { + match *self { + Direction::Up => Direction::Down, + Direction::Down => Direction::Up, + Direction::Left => Direction::Right, + Direction::Right => Direction::Left, + } + } +} + pub enum CellType { Food, Snake, @@ -23,7 +49,15 @@ pub struct Cell { col: i32, ctype: CellType, } - +impl PartialEq for Cell { + fn eq(&self, other: &Cell) -> bool { + if (self.line == other.line) && (self.col == other.col) { + return true; + } else { + return false; + } + } +} impl Cell { pub fn new(l: i32, c: i32, t: CellType) -> Cell { Cell { @@ -113,17 +147,35 @@ impl Board { } pub fn eat_food(&mut self, snake: &mut Snake) { snake.grow(); - self.food.chtype(CellType::Empty); + // self.food.chtype(CellType::Empty); + self.spawn_food(snake); + } + pub fn spawn_food(&mut self, snake: &Snake) { + let mut food: Cell = Cell::random(self.maxlines, self.maxcols); + let mut spawned_food = false; + while spawned_food != true { + // check for colliosions with the snake body until a free spot is found and spawn the food there + spawned_food = true; + let mut snake_iter = snake.iter(); + for snake_cell in snake_iter.next() { + if *snake_cell == food { + // 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); + spawned_food = false; + break; + } + } + } + self.food = food; } - pub fn spawn_food() {} } pub struct Snake { head: Cell, - pub body: LinkedList, - // length: i32, - pub direction: Direction, - grow: bool, + body: LinkedList, + direction: Direction, + pub grow: bool, } impl Snake { pub fn new(head: Cell) -> Snake { @@ -140,15 +192,20 @@ impl Snake { pub fn posyx(&self) -> (i32, i32) { 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 let mut tail: Cell; - if self.grow { - tail = self.body.back().unwrap().clone(); + let direction: Direction; + if self.direction == _direction.opposite() { + direction = self.direction } else { - tail = self.body.pop_back().unwrap(); + direction = _direction + } + if self.grow == false { + tail = self.body.pop_back().unwrap(); + tail.chtype(CellType::Empty); + // self.grow = false; } - tail.ctype = CellType::Empty; let (dl, dc) = match direction { Direction::Up => (-1, 0), Direction::Down => (1, 0), @@ -158,11 +215,16 @@ impl Snake { self.direction = direction; self.head = Cell::new(self.head.line + dl, self.head.col + dc, CellType::Snake); self.body.push_front(self.head); + self.grow = false; } - pub fn tick(&mut self) { + pub fn tick(&mut self, time: Duration) { + sleep(time); self.smove(self.direction); } pub fn grow(&mut self) { self.grow = true; } + pub fn iter(&self) -> impl Iterator { + return self.body.iter(); + } } diff --git a/src/game/frontend.rs b/src/game/frontend.rs index da95e6d..7c7d1bd 100644 --- a/src/game/frontend.rs +++ b/src/game/frontend.rs @@ -1,7 +1,8 @@ // use ncurses::*; use crate::game::backend::{Board, Snake}; use ncurses::{ - box_, delwin, keypad, mvwaddstr, newwin, 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; @@ -29,17 +30,40 @@ pub fn destroy_window(win: WINDOW) { } pub fn draw_snake(snake: &Snake, game_win: WINDOW) { - let mut snake_iter = snake.body.iter(); - for snake_cell in snake_iter.next() { - wmove(game_win, 0, 0); - wclrtobot(game_win); - box_(game_win, 0, 0); + // 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, "x"); + mvwaddstr(game_win, snake_l, snake_c, "o"); } + wrefresh(game_win); } pub fn draw_board(board: &Board, game_win: WINDOW) { let (food_l, food_c): (i32, i32) = board.food_posyx(); mvwaddstr(game_win, food_l, food_c, "F"); } + +pub fn log(snake: &Snake, board: &Board) { + let (shl, shc): (i32, i32) = snake.posyx(); + let (bfl, bfc): (i32, i32) = board.food_posyx(); + mvwaddstr(stdscr(), 0, 0, &format!("snake:head: {} {} ", shl, shc)); + mvwaddstr(stdscr(), 1, 0, &format!("board:food: {} {} ", bfl, bfc)); + 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(), + // 2, + // 0, + // &format!("snake_size {}", snake.iter().size_hint().0), + // ); + if snake.grow { + mvwaddstr(stdscr(), 3, 0, &format!("snake:grew")); + } + wrefresh(stdscr()); +} diff --git a/src/game/mod.rs b/src/game/mod.rs index 8c32dc8..a02bcc8 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -6,19 +6,20 @@ use backend::{Board, Cell, Snake}; use ncurses::{ getmaxyx, nodelay, stdscr, wgetch, wrefresh, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_UP, WINDOW, }; -use std::thread::sleep; 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); getmaxyx(stdscr(), &mut mlines, &mut mcols); - game_win = frontend::game_window(mlines, mcols, 5, 10); + game_win = frontend::game_window(mlines, mcols, vmargin, hmargin); let mut snake = Snake::new(Cell::new(mlines / 2, mcols / 2, backend::CellType::Snake)); //Initialise snake in the middle of the screen - let mut board = Board::new(mlines, mcols); + let mut board = Board::new(mlines - vmargin * 2, mcols - hmargin * 2); nodelay(game_win, true); loop { frontend::draw_snake(&snake, game_win); frontend::draw_board(&board, game_win); + frontend::log(&snake, &board); if board.check_collision(&snake) { break; } @@ -47,8 +48,7 @@ pub fn start() { // 27 => break, _ => (), } - sleep(std::time::Duration::from_millis(100)); - snake.tick(); + snake.tick(std::time::Duration::from_millis(100)); } frontend::destroy_window(game_win); diff --git a/src/menu.rs b/src/menu.rs index e49ee24..b910376 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -87,7 +87,10 @@ pub fn main_menu_control() -> i8 { wattroff(menu_win, A_REVERSE()); wrefresh(menu_win); } - mvwaddstr(menu_win, 7, 1, " "); + // mvwaddstr(menu_win, 7, 1, " "); + wmove(menu_win, 7, 1); + wclrtoeol(menu_win); + box_(menu_win, 0, 0); mvwaddnstr(menu_win, 7, 1, &menu_desc[menu_highlight], 18); mvwaddstr(menu_win, 8, 1, &format!("{}", ch)); ch = wgetch(menu_win);