diff --git a/components/Point.cpp b/components/Point.cpp index 934fc9f..778cc3b 100755 --- a/components/Point.cpp +++ b/components/Point.cpp @@ -45,6 +45,7 @@ void Point::print() const { Graphics::get().printChar(y_, x_, img_); } -void Point::clear(){ +void Point::clear() { img_ = ' '; + print(); } \ No newline at end of file diff --git a/components/Snack.cpp b/components/Snack.cpp index 865b08a..25002ac 100755 --- a/components/Snack.cpp +++ b/components/Snack.cpp @@ -5,12 +5,12 @@ void generateSnack(Point* snack){ std::random_device dev; static std::mt19937 prng(dev()); - static std::uniform_int_distribution distX(0, GAME_RIGHT_WALL_X); - static std::uniform_int_distribution distY(0, GAME_BOTTOM_WALL_Y); + static std::uniform_int_distribution distX(0, GAME_RIGHT_WALL_X); + static std::uniform_int_distribution distY(0, GAME_BOTTOM_WALL_Y); const uint32_t x = distX(prng); const uint32_t y = distY(prng); - + snack->setImg(SNACK_CHAR); snack->setPoint(y, x); snack->print(); diff --git a/components/Snake.cpp b/components/Snake.cpp index 4960388..7885465 100755 --- a/components/Snake.cpp +++ b/components/Snake.cpp @@ -1,13 +1,11 @@ #include "Snake.h" -#include - Snake::Snake(uint32_t headY, uint32_t headX) :direction_{LEFT} { snake_.push_back(Point{headY, headX, '>'}); - for (uint32_t i = 1; i <= SNAKE_DEFAULT_SIZE - 1; i++) { + for (uint32_t i = 1; i <= SNAKE_DEFAULT_SIZE; i++) { snake_.push_back(Point{headY, headX + i, SNAKE_BODY_CHAR}); } } @@ -15,8 +13,11 @@ Snake::Snake(uint32_t headY, uint32_t headX) bool Snake::isBitten() const { const Point& head = snake_.front(); - for (const Point& part : snake_) { - if (part.getX() == head.getX() && part.getY() == head.getY()) { + // use manual iterator loop instead of + // range-based for as we need to skip head + + for (auto it = std::next(snake_.begin()); it != snake_.end(); it++) { + if (it->getX() == head.getX() && it->getY() == head.getY()) { return true; } } @@ -109,27 +110,31 @@ void Snake::printSnake() const { Graphics::get().refreshScreen(); } -void Snake::move(){ - // updates the tail by clearing it since - // the snake moved forward (overwrites with ' ') - snake_.back().clear(); +void Snake::move() { + auto head = snake_.begin(); + auto second = std::next(snake_.begin()); - // iterate through the snake step by step - // using iterators so that we can get prev - // and iterate from back to front as we want to - // update each element with the value of the next - // and would otherwise overwrite the next before - // and not updating first as head is handled separately + // clear the tail - overwrites with ' ' + snake_.back().clear(); - for (auto it = std::prev(snake_.end()); it != snake_.begin(); it--) { - const auto prev = std::prev(it); - it->setPoint(prev->getY(), prev->getX()); + // update all nodes by iterating from the back + // and copying the previous nodes values in + // until the second-to-first one + auto iter = std::prev(snake_.end()); + while (iter != second) { + auto prev = std::prev(iter); + *iter = *prev; + iter = prev; } - // update the head depending on movement + // update the previous to head node + // by copying from head and setting + // the image to be body instead of head + *second = *head; + iter->setImg(SNAKE_BODY_CHAR); + updateHead(); - // print the updated snake printSnake(); } diff --git a/game/Controller.cpp b/game/Controller.cpp index c930cc4..efa527d 100755 --- a/game/Controller.cpp +++ b/game/Controller.cpp @@ -1,6 +1,7 @@ #include "Controller.h" #include +#include Controller::Controller() : input_{0}, score_{0}, snack_{Point(0,0,0)} @@ -26,7 +27,7 @@ int Controller::act() { if (snake_.hasBitSnack(snack_.getY(), snack_.getX())) { score_ += 10; snake_.incSize(); - + generateSnack(&snack_); Graphics::get().advanceDifficulty(); @@ -36,15 +37,19 @@ int Controller::act() { switch (input_) { case UP: snake_.moveUp(); + Graphics::get().setVertical(true); break; case DOWN: snake_.moveDown(); + Graphics::get().setVertical(true); break; case LEFT: snake_.moveLeft(); + Graphics::get().setVertical(false); break; case RIGHT: snake_.moveRight(); + Graphics::get().setVertical(false); break; default: snake_.move(); diff --git a/game/Game.cpp b/game/Game.cpp index 60ae342..c071fd4 100644 --- a/game/Game.cpp +++ b/game/Game.cpp @@ -16,7 +16,7 @@ const std::string& SnakeGame::getBestPlayer() const { } void SnakeGame::play(const std::string& name){ - auto find = std::find(players_.begin(), players_.end(), [&name](const Player& p){ return p.getName() == name; }); + auto find = std::find_if(players_.begin(), players_.end(), [&name](const Player& p){ return p.getName() == name; }); if (find == players_.end()) { players_.emplace_back(Player(name)); diff --git a/input-output/Graphics.cpp b/input-output/Graphics.cpp index abb91f9..5aae038 100755 --- a/input-output/Graphics.cpp +++ b/input-output/Graphics.cpp @@ -41,10 +41,10 @@ void Graphics::finalize() { } void Graphics::refreshScreen() { - using namespace std::this_thread; - using namespace std::chrono; - - sleep_for(nanoseconds(sleep_time_)); + const float window_factor = (static_cast(LINES) * 5.25f) / static_cast(COLS); + const uint32_t vertical_sleep_time = window_factor * sleep_time_; + + std::this_thread::sleep_for(std::chrono::microseconds(vertical_ ? vertical_sleep_time : sleep_time_)); refresh(); wrefresh(box_); @@ -81,12 +81,16 @@ int Graphics::readInpt() { } void Graphics::advanceDifficulty() { - if(sleep_time_ > 28000000) { - sleep_time_ -= 1000000; + if (sleep_time_ > DIFFICULTY_CAP) { + sleep_time_ -= DIFFICULTY_CHANGE; } } Graphics& Graphics::get() { static Graphics graphics; return graphics; +} + +void Graphics::setVertical(bool value) { + vertical_ = value; } \ No newline at end of file diff --git a/input-output/Graphics.h b/input-output/Graphics.h index 47b70aa..011168f 100755 --- a/input-output/Graphics.h +++ b/input-output/Graphics.h @@ -9,17 +9,22 @@ static constexpr int LEFT = KEY_LEFT; static constexpr int RIGHT = KEY_RIGHT; static constexpr int EXIT_GAME = 'q'; -static constexpr int GAME_TOP_WALL_Y = 1; -const int GAME_BOTTOM_WALL_Y = LINES - 4; -static constexpr int GAME_LEFT_WALL_X = 1; -const int GAME_RIGHT_WALL_X = COLS - 2; +static constexpr uint32_t GAME_TOP_WALL_Y = 1; +static constexpr uint32_t GAME_LEFT_WALL_X = 1; +#define GAME_BOTTOM_WALL_Y (LINES - 4) +#define GAME_RIGHT_WALL_X (COLS - 2) + +static constexpr uint32_t DIFFICULTY_BEGIN = 40000; +static constexpr uint32_t DIFFICULTY_CAP = 28000; +static constexpr uint32_t DIFFICULTY_CHANGE = 1000; class Graphics { private: - unsigned int sleep_time_ = 40000000; - WINDOW* box_ = NULL; + bool vertical_ = false; + uint32_t sleep_time_ = DIFFICULTY_BEGIN; + WINDOW* box_ = nullptr; - Graphics(); + Graphics() = default; void createBox(); void destroyBox(); @@ -35,5 +40,6 @@ public: int readInpt(); void advanceDifficulty(); + void setVertical(bool value); };