Skip to content

Instantly share code, notes, and snippets.

@viennadd
Last active June 19, 2016 13:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save viennadd/a67047dd21cf74fe2d034cd44a43fa31 to your computer and use it in GitHub Desktop.
Save viennadd/a67047dd21cf74fe2d034cd44a43fa31 to your computer and use it in GitHub Desktop.
#include <deque>
#include <iostream>
#include <thread>
#include <chrono>
#include <random>
using namespace std;
class Snake;
class SnakeGame;
class Board;
class GameSprite;
typedef struct
{
int x;
int y;
} Point;
enum class Direction { Up = 'w', Down = 's', Left = 'a', Right = 'd' };
class GameSprite {
public:
virtual void drawOn(Board &board) = 0;
};
class Snake : public GameSprite {
deque<Point> points;
Direction currentDirection;
public:
Snake();
void move(Board &board);
void drawOn(Board &board);
Point getNextPoint();
Direction& getCurrentDirection();
};
Snake::Snake()
{
for (int l = 8; l >= 2; l--)
points.push_back(Point{l, 1});
currentDirection = Direction::Right;
}
Direction& Snake::getCurrentDirection()
{
return currentDirection;
}
Point Snake::getNextPoint()
{
const Point &head = points.front();
Point p = head;
switch (currentDirection) {
case Direction::Up:
p.y--;
break;
case Direction::Down:
p.y++;
break;
case Direction::Left:
p.x--;
break;
case Direction::Right:
p.x++;
break;
}
return p;
}
class Board
{
unsigned int boardWidth;
unsigned int boardHeight;
char buffer[25][80];
public:
Board();
Board(int width, int height);
void setPixel(Point &p, char c);
char getPixel(Point &p);
unsigned int getWidth() { return boardWidth; }
unsigned int getHeight() { return boardHeight; }
friend ostream& operator<<(ostream &out, const Board &board);
private:
void InitBoard();
};
char Board::getPixel(Point &p)
{
return buffer[p.y][p.x];
}
void Board::InitBoard()
{
for (int r = 0; r < boardHeight; ++r) {
for (int c = 0; c < boardWidth; ++c) {
buffer[r][c] = '.';
}
buffer[r][boardWidth] = '\0';
}
}
Board::Board() : boardWidth(70), boardHeight(22)
{
InitBoard();
}
Board::Board(int width, int height) : boardWidth(width), boardHeight(height)
{
InitBoard();
}
void Board::setPixel(Point &p, char c)
{
buffer[p.y][p.x] = c;
}
void Snake::drawOn(Board &board)
{
for (auto &p : points) {
board.setPixel(p, '#');
}
}
ostream& operator<<(ostream &out, const Board &board)
{
for (int r = 0; r < board.boardHeight; ++r) {
out << board.buffer[r] << endl;
}
return out;
}
/*
* ===========================
*
*/
class SnakeGame
{
enum class GameState { Running, Stop };
GameState gameState;
Board board;
Snake snake;
public:
SnakeGame();
void start();
static void gameLoop(Board &board, Snake &snake);
static bool isGameEnd(Board &board, Snake &snake);
static void newFood(Board &board);
static void KeyboardHandler(SnakeGame &game, Snake &snake);
};
SnakeGame::SnakeGame() : gameState(GameState::Stop)
{
}
void SnakeGame::KeyboardHandler(SnakeGame &game, Snake &snake)
{
char c;
Direction &direction = snake.getCurrentDirection();
while ((c = getchar()) != EOF && game.gameState != GameState::Stop) {
// current up or down, then left or right will accept
// current left or right, then up or down will accept
if (
((direction == Direction::Left || direction == Direction::Right) && (c == 'w' || c == 's')) ||
((direction == Direction::Up || direction == Direction::Down) && (c == 'a' || c == 'd')))
{
direction = (Direction)c;
cout << "current dir is " << c << endl;
}
}
}
bool SnakeGame::isGameEnd(Board &board, Snake &snake)
{
Point head = snake.getNextPoint();
if (head.x < 0
|| head.y < 0
|| head.x >= board.getWidth()
|| head.y >= board.getHeight()
|| board.getPixel(head) == '#')
return true;
else
return false;
};
void SnakeGame::gameLoop(Board &board, Snake &snake)
{
auto Sleep = [](int milliseconds) {
this_thread::sleep_for(chrono::milliseconds(milliseconds));
};
while (!isGameEnd(board, snake)) {
snake.move(board);
system("clear");
cout << board;
Sleep(100);
}
}
void SnakeGame::newFood(Board &board)
{
random_device rd;
Point p;
do {
p.x = rd() % board.getWidth();
p.y = rd() % board.getHeight();
} while (board.getPixel(p) != '.');
board.setPixel(p, '*');
}
void Snake::move(Board &board)
{
Point nextPoint = getNextPoint();
if (board.getPixel(nextPoint) == '*') {
SnakeGame::newFood(board);
} else {
Point lastPoint = points.back();
board.setPixel(lastPoint, '.');
points.pop_back();
}
points.push_front(nextPoint);
board.setPixel(nextPoint, '#');
}
void SnakeGame::start()
{
gameState = GameState::Running;
snake.drawOn(board);
SnakeGame::newFood(board);
thread thGameLoop(gameLoop, ref(board), ref(snake));
thread thKeyboardHandler(KeyboardHandler, ref(*this), ref(snake));
thGameLoop.join();
gameState = GameState::Stop;
cout << "Game Over." << endl;
thKeyboardHandler.join();
}
int main()
{
SnakeGame game;
game.start();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment