Constantin Fürst
8 months ago
13 changed files with 30 additions and 503 deletions
-
35components/Point.cpp
-
6components/Point.h
-
17components/Snack.cpp
-
7components/Snack.h
-
163components/Snake.cpp
-
34components/Snake.h
-
74game/Controller.cpp
-
31game/Controller.h
-
64game/Game.cpp
-
27game/Game.h
-
32input-output/Player.cpp
-
21input-output/Player.h
-
22main.cpp
@ -1,17 +0,0 @@ |
|||
#include "Snack.h"
|
|||
|
|||
#include <random>
|
|||
|
|||
void generateSnack(Point* snack){ |
|||
std::random_device dev; |
|||
static std::mt19937 prng(dev()); |
|||
static std::uniform_int_distribution<uint32_t> distX(0, GAME_RIGHT_WALL_X); |
|||
static std::uniform_int_distribution<uint32_t> 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(); |
|||
} |
@ -1,7 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include "Point.h" |
|||
|
|||
static constexpr int SNACK_CHAR = '*'; |
|||
|
|||
void generateSnack(Point* snack); |
@ -1,163 +0,0 @@ |
|||
#include "Snake.h"
|
|||
|
|||
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; i++) { |
|||
snake_.push_back(Point{headY, headX + i, SNAKE_BODY_CHAR}); |
|||
} |
|||
} |
|||
|
|||
bool Snake::isBitten() const { |
|||
const Point& head = snake_.front(); |
|||
|
|||
// 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; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
bool Snake::hasBitSnack(uint32_t snackY, uint32_t snackX) const { |
|||
return snake_.front().getY() == snackY && snake_.front().getX() == snackX; |
|||
} |
|||
|
|||
bool Snake::hasCrashedWall() const { |
|||
const Point& head = snake_.front(); |
|||
|
|||
return (head.getY() < GAME_TOP_WALL_Y) || |
|||
(head.getY() > GAME_BOTTOM_WALL_Y) || |
|||
(head.getX() < GAME_LEFT_WALL_X) || |
|||
(head.getX() > GAME_RIGHT_WALL_X); |
|||
} |
|||
|
|||
uint32_t Snake::getSize() const { |
|||
return snake_.size(); |
|||
} |
|||
|
|||
void Snake::incSize(){ |
|||
const auto tail = std::prev(snake_.end()); |
|||
const uint32_t tailX = tail->getX(); |
|||
const uint32_t tailY = tail->getY(); |
|||
|
|||
const auto prev = std::prev(tail); |
|||
const uint32_t prevX = prev->getX(); |
|||
const uint32_t prevY = prev->getY(); |
|||
|
|||
if (prevY == tailY){ |
|||
// if the two last parts are on the same 'height' (horizontal tail direction)
|
|||
|
|||
if (prevX < tailX) { |
|||
// if the tail continues to the left:
|
|||
// add one part to the right of the tail
|
|||
snake_.push_back(Point{tailY, tailX + 1, SNAKE_BODY_CHAR}); |
|||
} |
|||
else { |
|||
// if the tail continues to the right:
|
|||
// add one part to the left of the tail
|
|||
snake_.push_back(Point{tailY, tailX - 1, SNAKE_BODY_CHAR}); |
|||
} |
|||
} |
|||
else { |
|||
// if the two last parts are on the same 'width' (vertical tail direction)
|
|||
|
|||
if (prevY < tailY) { |
|||
// if the tail continues to the upper side:
|
|||
// add one part facing down
|
|||
snake_.push_back(Point{tailY + 1, tailX, SNAKE_BODY_CHAR}); |
|||
} |
|||
else { |
|||
// if the tail continues to the lower side:
|
|||
// add one part facing up
|
|||
snake_.push_back(Point{tailY - 1, tailX, SNAKE_BODY_CHAR}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void Snake::updateHead(){ |
|||
switch (direction_) { |
|||
case UP: |
|||
snake_.front().moveUp(); |
|||
break; |
|||
|
|||
case DOWN: |
|||
snake_.front().moveDown(); |
|||
break; |
|||
|
|||
case LEFT: |
|||
snake_.front().moveLeft(); |
|||
break; |
|||
|
|||
case RIGHT: |
|||
snake_.front().moveRight(); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void Snake::printSnake() const { |
|||
//We print each element of the snake-list
|
|||
for (const Point& part : snake_){ |
|||
part.print(); |
|||
} |
|||
|
|||
Graphics::get().refreshScreen(); |
|||
} |
|||
|
|||
void Snake::move() { |
|||
auto head = snake_.begin(); |
|||
auto second = std::next(snake_.begin()); |
|||
|
|||
// clear the tail - overwrites with ' '
|
|||
snake_.back().clear(); |
|||
|
|||
// 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 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(); |
|||
|
|||
printSnake(); |
|||
} |
|||
|
|||
void Snake::moveUp(){ |
|||
snake_.front().setImg('v'); |
|||
direction_ = UP; |
|||
move(); |
|||
} |
|||
|
|||
void Snake::moveDown(){ |
|||
snake_.front().setImg('^'); |
|||
direction_ = DOWN; |
|||
move(); |
|||
} |
|||
|
|||
void Snake::moveLeft(){ |
|||
snake_.front().setImg('>'); |
|||
direction_ = LEFT; |
|||
move(); |
|||
} |
|||
|
|||
void Snake::moveRight(){ |
|||
snake_.front().setImg('<'); |
|||
direction_ = RIGHT; |
|||
move(); |
|||
} |
@ -1,34 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include <vector> |
|||
|
|||
#include "Point.h" |
|||
#include "Snack.h" |
|||
|
|||
static constexpr int SNAKE_BODY_CHAR = 'o'; |
|||
static constexpr uint32_t SNAKE_DEFAULT_SIZE = 4; |
|||
|
|||
class Snake{ |
|||
private: |
|||
std::vector<Point> snake_; |
|||
int direction_; |
|||
|
|||
void updateHead(); |
|||
void printSnake() const; |
|||
|
|||
public: |
|||
Snake(uint32_t headY = LINES/2, uint32_t headX = COLS/2); |
|||
|
|||
void moveUp(); |
|||
void moveDown(); |
|||
void moveLeft(); |
|||
void moveRight(); |
|||
void move(); |
|||
|
|||
bool isBitten() const; |
|||
bool hasBitSnack(uint32_t snackY, uint32_t snackX) const; |
|||
bool hasCrashedWall() const; |
|||
|
|||
uint32_t getSize() const; |
|||
void incSize(); |
|||
}; |
@ -1,74 +0,0 @@ |
|||
#include "Controller.h"
|
|||
|
|||
#include <string>
|
|||
#include <iostream>
|
|||
|
|||
Controller::Controller() |
|||
: input_{0}, score_{0}, snack_{Point(0,0,0)} |
|||
{ |
|||
generateSnack(&snack_); |
|||
} |
|||
|
|||
uint32_t Controller::getCurrScore() const { |
|||
return score_; |
|||
} |
|||
|
|||
void Controller::resetScore() { |
|||
score_ = 0; |
|||
} |
|||
|
|||
void Controller::printScore(uint32_t score) const { |
|||
const std::string str = "Score: " + std::to_string(score); |
|||
// locate message at (-1,-1) because otherwise it'll be printed inside the game box
|
|||
Graphics::get().printMsg(-1, -1, str); |
|||
} |
|||
|
|||
int Controller::act() { |
|||
if (snake_.hasBitSnack(snack_.getY(), snack_.getX())) { |
|||
score_ += 10; |
|||
snake_.incSize(); |
|||
|
|||
generateSnack(&snack_); |
|||
Graphics::get().advanceDifficulty(); |
|||
|
|||
printScore(score_); |
|||
} |
|||
|
|||
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(); |
|||
} |
|||
|
|||
Graphics::get().refreshScreen(); |
|||
|
|||
if (snake_.isBitten() || snake_.hasCrashedWall()) { |
|||
return DEFEAT; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
int Controller::readInput() { |
|||
input_ = Graphics::get().readInpt(); |
|||
return input_; |
|||
} |
|||
|
|||
bool Controller::wantsToQuit() const { |
|||
return input_ == EXIT_GAME; |
|||
} |
@ -1,31 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
|
|||
#include "../input-output/Graphics.h" |
|||
#include "../components/Snake.h" |
|||
#include "../components/Point.h" |
|||
|
|||
static constexpr int DEFEAT = -1; |
|||
|
|||
class Controller { |
|||
private: |
|||
Snake snake_; |
|||
Point snack_; |
|||
|
|||
int input_; |
|||
uint32_t score_; |
|||
|
|||
void printScore(uint32_t score) const; |
|||
|
|||
public: |
|||
Controller(); |
|||
|
|||
uint32_t getCurrScore() const; |
|||
|
|||
void resetScore(); |
|||
int readInput(); |
|||
int act(); |
|||
|
|||
bool wantsToQuit() const; |
|||
}; |
@ -1,64 +0,0 @@ |
|||
#include "Game.h"
|
|||
|
|||
#include <algorithm>
|
|||
#include <limits.h>
|
|||
|
|||
void SnakeGame::addPlayer(const std::string& name){ |
|||
players_.emplace_back(Player{name}); |
|||
} |
|||
|
|||
uint32_t SnakeGame::getHighScore() const { |
|||
return high_score_; |
|||
} |
|||
|
|||
const std::string& SnakeGame::getBestPlayer() const { |
|||
return best_player_; |
|||
} |
|||
|
|||
void SnakeGame::play(const std::string& 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)); |
|||
find = std::prev(players_.end()); |
|||
} |
|||
|
|||
Graphics::get().init(game_name_); |
|||
|
|||
find->play(); |
|||
|
|||
Graphics::get().finalize(); |
|||
|
|||
|
|||
if (find->getHighScore() > high_score_){ |
|||
high_score_ = find->getHighScore(); |
|||
best_player_ = find->getName(); |
|||
} |
|||
|
|||
std::cout << "Highscore: " << high_score_ << " by " << best_player_ << std::endl; |
|||
} |
|||
|
|||
void SnakeGame::play(){ |
|||
while(1) { |
|||
std::string name; |
|||
std::cout << "Who's playing: "; |
|||
std::cin >> name; |
|||
std::cout << std::endl; |
|||
|
|||
|
|||
play(name); |
|||
std::cin.clear(); |
|||
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); |
|||
std::cout << "Do you or someone else want to play again? (yes or no): "; |
|||
std::string ans; |
|||
|
|||
std::cin >> ans; |
|||
|
|||
if (ans != "yes") { |
|||
std::cout << "Exiting ..." << std::endl; |
|||
break; |
|||
} |
|||
|
|||
std::cout << "Perfect..." << std::endl; |
|||
} |
|||
} |
@ -1,27 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include <string> |
|||
#include <vector> |
|||
|
|||
#include "Controller.h" |
|||
#include "../components/Snake.h" |
|||
#include "../input-output/Player.h" |
|||
|
|||
class SnakeGame{ |
|||
private: |
|||
const std::string game_name_ = "Snake Game for C++ Course"; |
|||
std::vector<Player> players_; |
|||
|
|||
uint32_t high_score_ = 0; |
|||
std::string best_player_ = "None"; |
|||
|
|||
void play(const std::string& name); |
|||
void addPlayer(const std::string& name); |
|||
|
|||
public: |
|||
uint32_t getHighScore() const; |
|||
const std::string& getBestPlayer() const; |
|||
void printGameStatistics() const; |
|||
|
|||
void play(); |
|||
}; |
@ -1,32 +0,0 @@ |
|||
#include "Player.h"
|
|||
|
|||
Player::Player(std::string name) |
|||
: name_{name} |
|||
{} |
|||
|
|||
const std::string& Player::getName() const { |
|||
return name_; |
|||
} |
|||
|
|||
uint32_t Player::getHighScore() const { |
|||
return high_score_; |
|||
} |
|||
|
|||
void Player::play(){ |
|||
Controller controller; |
|||
|
|||
while (controller.wantsToQuit() == false) { |
|||
controller.readInput(); |
|||
|
|||
if (controller.act() == DEFEAT) { |
|||
break; |
|||
} |
|||
} |
|||
|
|||
const uint32_t score = controller.getCurrScore(); |
|||
controller.resetScore(); |
|||
|
|||
if (score > high_score_) { |
|||
high_score_ = score; |
|||
} |
|||
} |
@ -1,21 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include "../game/Controller.h" |
|||
|
|||
#include <iostream> |
|||
#include <string> |
|||
|
|||
class Player{ |
|||
private: |
|||
std::string name_; |
|||
uint32_t high_score_ = 0; |
|||
uint32_t timesPlayed_ = 0; |
|||
|
|||
public: |
|||
Player(std::string name); |
|||
|
|||
void play(); |
|||
|
|||
uint32_t getHighScore() const; |
|||
const std::string& getName() const; |
|||
}; |
@ -1,11 +1,23 @@ |
|||
|
|||
#include <ncurses.h>
|
|||
#include <iostream>
|
|||
#include <thread>
|
|||
#include <chrono>
|
|||
|
|||
#include "components/Point.h"
|
|||
#include "input-output/Graphics.h"
|
|||
|
|||
void mainL01() { |
|||
Graphics::get().init("Learners Helper"); |
|||
|
|||
Point p(10,10,'X'); |
|||
|
|||
std::this_thread::sleep_for(std::chrono::seconds(10)); |
|||
|
|||
Graphics::get().finalize(); |
|||
|
|||
#include "game/Game.h"
|
|||
std::cout << "Helper QUIT" << std::endl; |
|||
} |
|||
|
|||
int main() { |
|||
SnakeGame game; |
|||
game.play(); |
|||
mainL01(); |
|||
return 0; |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue