Initial commit: Console Snake game

This commit is contained in:
Sigismund Dijkstra 2025-07-08 21:50:28 -05:00
commit 3d79b8c199
13 changed files with 836 additions and 0 deletions

26
.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
# Build directories
build/
cmake-build-*/
# CMake files
CMakeCache.txt
CMakeFiles/
Makefile
cmake_install.cmake
build.ninja
rules.ninja
# Executables
Snake
*.exe
# IDE files
.idea/
.vscode/
*.user
# Testing
Testing/
# OS files
.DS_Store

22
CMakeLists.txt Normal file
View File

@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.10)
project(Snake)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Find SFML
find_package(SFML 2.5 COMPONENTS graphics window system REQUIRED)
# Add executable
add_executable(Snake
main.cpp
Game.cpp
Snake.cpp
Food.cpp
)
# Include headers
target_include_directories(Snake PRIVATE .)
# Link SFML libraries
target_link_libraries(Snake sfml-graphics sfml-window sfml-system)

6
Direction.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef DIRECTION_H
#define DIRECTION_H
enum class Direction { UP, DOWN, LEFT, RIGHT };
#endif //DIRECTION_H

20
Food.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "Food.h"
#include <random>
#include <algorithm>
void Food::generateNew(int maxX, int maxY, const std::vector<Point>& occupiedPositions)
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> disX(0, maxX - 1);
std::uniform_int_distribution<> disY(0, maxY - 1);
Point newPos;
do
{
newPos = Point(disX(gen), disY(gen));
} while (std::find(occupiedPositions.begin(), occupiedPositions.end(), newPos) != occupiedPositions.end());
position = newPos;
}

17
Food.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef FOOD_H
#define FOOD_H
#include "Point.h"
#include <vector>
class Food
{
Point position;
public:
Food() : position(0, 0) {}
void generateNew(int maxX, int maxY, const std::vector<Point>& occupiedPositions);
Point getPosition() const { return position; }
};
#endif //FOOD_H

492
Game.cpp Normal file
View File

@ -0,0 +1,492 @@
#include "Game.h"
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <cmath>
Game::Game()
: snake(Point(BOARD_WIDTH / 2, BOARD_HEIGHT / 2)),
score(0),
bestScore(0),
gameOver(false),
paused(false),
inMenu(true)
{
loadBestScore();
generateFood();
}
void Game::run()
{
sf::RenderWindow window(sf::VideoMode(BOARD_WIDTH * CELL_SIZE, BOARD_HEIGHT * CELL_SIZE + 60), "Snake Game");
sf::Clock clock;
float timer = 0.0f, delay = 0.15f;
// Menu buttons initialization
MenuButton startBtn, exitBtn, restartBtn, menuBtn;
startBtn.rect = sf::FloatRect(CELL_SIZE * BOARD_WIDTH / 2 - 110, 180, 220, 48);
startBtn.label = "Start";
startBtn.color = sf::Color(80, 180, 80);
startBtn.hoverColor = sf::Color(120, 220, 120);
exitBtn.rect = sf::FloatRect(BOARD_WIDTH * CELL_SIZE / 2 - 110, 250, 220, 40);
exitBtn.label = "Exit";
exitBtn.color = sf::Color(180, 80, 80);
exitBtn.hoverColor = sf::Color(220, 120, 120);
restartBtn.rect = sf::FloatRect(BOARD_WIDTH * CELL_SIZE / 2 - 110, 180, 220, 48);
restartBtn.label = "Restart";
restartBtn.color = sf::Color(80, 180, 80);
restartBtn.hoverColor = sf::Color(120, 220, 120);
menuBtn.rect = sf::FloatRect(BOARD_WIDTH * CELL_SIZE / 2 - 110, 250, 220, 40);
menuBtn.label = "Menu";
menuBtn.color = sf::Color(180, 80, 80);
menuBtn.hoverColor = sf::Color(220, 120, 120);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
processEvent(event, &window, &startBtn, &exitBtn, &restartBtn, &menuBtn);
}
if (!paused && !gameOver && !inMenu)
{
timer += clock.restart().asSeconds();
if (timer > delay)
{
update();
timer = 0;
}
}
else
{
clock.restart();
}
render(window, &startBtn, &exitBtn, &restartBtn, &menuBtn);
}
}
// Handles all events, including mouse support for menu buttons
void Game::processEvent(const sf::Event& event, sf::RenderWindow* window,
MenuButton* startBtn, MenuButton* exitBtn,
MenuButton* restartBtn, MenuButton* menuBtn)
{
sf::Vector2f mousePos;
if (window)
mousePos = window->mapPixelToCoords(sf::Mouse::getPosition(*window));
// Reset hover state for all buttons
if (startBtn) startBtn->hovered = false;
if (exitBtn) exitBtn->hovered = false;
if (restartBtn) restartBtn->hovered = false;
if (menuBtn) menuBtn->hovered = false;
if (inMenu)
{
if (startBtn && startBtn->rect.contains(mousePos))
startBtn->hovered = true;
if (exitBtn && exitBtn->rect.contains(mousePos))
exitBtn->hovered = true;
if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left)
{
if (startBtn && startBtn->rect.contains(mousePos))
{
inMenu = false;
gameOver = false;
paused = false;
reset();
return;
}
if (exitBtn && exitBtn->rect.contains(mousePos))
{
if (window) window->close();
return;
}
}
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Enter)
{
inMenu = false;
gameOver = false;
paused = false;
reset();
}
else if (event.key.code == sf::Keyboard::Escape)
{
if (window) window->close();
}
}
return;
}
if (gameOver)
{
if (restartBtn && restartBtn->rect.contains(mousePos))
restartBtn->hovered = true;
if (menuBtn && menuBtn->rect.contains(mousePos))
menuBtn->hovered = true;
if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left)
{
if (restartBtn && restartBtn->rect.contains(mousePos))
{
reset();
gameOver = false;
paused = false;
inMenu = false;
return;
}
if (menuBtn && menuBtn->rect.contains(mousePos))
{
inMenu = true;
return;
}
}
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Enter)
{
reset();
gameOver = false;
paused = false;
inMenu = false;
}
else if (event.key.code == sf::Keyboard::Escape)
{
inMenu = true;
}
}
return;
}
// Snake controls
if (event.type == sf::Event::KeyPressed)
{
switch (event.key.code)
{
case sf::Keyboard::W:
case sf::Keyboard::Up:
if (snake.getDirection() != Direction::DOWN)
snake.setDirection(Direction::UP);
paused = false;
break;
case sf::Keyboard::S:
case sf::Keyboard::Down:
if (snake.getDirection() != Direction::UP)
snake.setDirection(Direction::DOWN);
paused = false;
break;
case sf::Keyboard::A:
case sf::Keyboard::Left:
if (snake.getDirection() != Direction::RIGHT)
snake.setDirection(Direction::LEFT);
paused = false;
break;
case sf::Keyboard::D:
case sf::Keyboard::Right:
if (snake.getDirection() != Direction::LEFT)
snake.setDirection(Direction::RIGHT);
paused = false;
break;
case sf::Keyboard::Space:
paused = !paused;
break;
case sf::Keyboard::Q:
case sf::Keyboard::Escape:
inMenu = true;
break;
default:
break;
}
}
}
// Rendering with interactive menu buttons and centered text
void Game::render(sf::RenderWindow& window,
MenuButton* startBtn, MenuButton* exitBtn,
MenuButton* restartBtn, MenuButton* menuBtn)
{
// Draw gradient background
sf::VertexArray background(sf::Quads, 4);
background[0].position = sf::Vector2f(0, 0);
background[1].position = sf::Vector2f(window.getSize().x, 0);
background[2].position = sf::Vector2f(window.getSize().x, window.getSize().y);
background[3].position = sf::Vector2f(0, window.getSize().y);
background[0].color = sf::Color(40, 40, 60);
background[1].color = sf::Color(40, 40, 60);
background[2].color = sf::Color(20, 20, 30);
background[3].color = sf::Color(20, 20, 30);
window.draw(background);
// Draw game border
sf::RectangleShape border(sf::Vector2f(BOARD_WIDTH * CELL_SIZE, BOARD_HEIGHT * CELL_SIZE));
border.setPosition(0, 0);
border.setFillColor(sf::Color::Transparent);
border.setOutlineThickness(3);
border.setOutlineColor(sf::Color(180, 180, 220));
window.draw(border);
// Draw food with highlight
sf::CircleShape foodCircle(CELL_SIZE / 2 - 3);
foodCircle.setFillColor(sf::Color(255, 80, 80));
foodCircle.setOutlineThickness(2);
foodCircle.setOutlineColor(sf::Color(255, 180, 180));
foodCircle.setOrigin(foodCircle.getRadius(), foodCircle.getRadius());
foodCircle.setPosition(food.getPosition().x * CELL_SIZE + CELL_SIZE / 2, food.getPosition().y * CELL_SIZE + CELL_SIZE / 2);
window.draw(foodCircle);
// Draw snake
for (const auto& segment : snake.getBody())
{
sf::RectangleShape cell(sf::Vector2f(CELL_SIZE - 4, CELL_SIZE - 4));
cell.setPosition(segment.x * CELL_SIZE + 2, segment.y * CELL_SIZE + 2);
if (segment == snake.getHead()) {
cell.setFillColor(sf::Color(80, 255, 80));
cell.setOutlineThickness(2);
cell.setOutlineColor(sf::Color(40, 180, 40));
} else {
cell.setFillColor(sf::Color(100, 200, 100));
cell.setOutlineThickness(1);
cell.setOutlineColor(sf::Color(60, 120, 60));
}
window.draw(cell);
}
// Helper for drawing shadowed text
auto drawShadowedText = [&](sf::RenderTarget& target, const sf::Text& text, sf::Color shadowColor = sf::Color(0,0,0,120), float offset = 2.f) {
sf::Text shadow = text;
shadow.setFillColor(shadowColor);
shadow.move(offset, offset);
target.draw(shadow);
target.draw(text);
};
static sf::Font font;
static bool fontLoaded = false;
if (!fontLoaded) {
fontLoaded = font.loadFromFile("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf");
}
if (fontLoaded)
{
sf::Text text;
text.setFont(font);
text.setCharacterSize(22);
text.setFillColor(sf::Color::White);
if (inMenu)
{
// Title
text.setString("SNAKE GAME");
text.setCharacterSize(38);
text.setStyle(sf::Text::Bold);
sf::FloatRect titleRect = text.getLocalBounds();
text.setOrigin(titleRect.left + titleRect.width / 2.0f, titleRect.top + titleRect.height / 2.0f);
text.setPosition(BOARD_WIDTH * CELL_SIZE / 2.0f, 80);
drawShadowedText(window, text);
// Best score
text.setString("Best score: " + std::to_string(bestScore));
text.setCharacterSize(22);
text.setStyle(sf::Text::Regular);
sf::FloatRect bestRect = text.getLocalBounds();
text.setOrigin(bestRect.left + bestRect.width / 2.0f, bestRect.top + bestRect.height / 2.0f);
text.setPosition(BOARD_WIDTH * CELL_SIZE / 2.0f, 130);
drawShadowedText(window, text);
// Start button
sf::RectangleShape startShape(sf::Vector2f(startBtn->rect.width, startBtn->rect.height));
startShape.setPosition(startBtn->rect.left, startBtn->rect.top);
startShape.setFillColor(startBtn->hovered ? startBtn->hoverColor : startBtn->color);
startShape.setOutlineThickness(3);
startShape.setOutlineColor(sf::Color(40, 120, 40));
window.draw(startShape);
text.setString("Start");
text.setCharacterSize(24);
text.setFillColor(sf::Color::White);
sf::FloatRect startTextRect = text.getLocalBounds();
text.setOrigin(startTextRect.left + startTextRect.width / 2.0f, startTextRect.top + startTextRect.height / 2.0f);
text.setPosition(
startBtn->rect.left + startBtn->rect.width / 2.0f,
startBtn->rect.top + startBtn->rect.height / 2.0f
);
drawShadowedText(window, text);
// Exit button
sf::RectangleShape exitShape(sf::Vector2f(exitBtn->rect.width, exitBtn->rect.height));
exitShape.setPosition(exitBtn->rect.left, exitBtn->rect.top);
exitShape.setFillColor(exitBtn->hovered ? exitBtn->hoverColor : exitBtn->color);
exitShape.setOutlineThickness(3);
exitShape.setOutlineColor(sf::Color(120, 40, 40));
window.draw(exitShape);
text.setString("Exit");
text.setCharacterSize(22);
text.setFillColor(sf::Color::White);
sf::FloatRect exitTextRect = text.getLocalBounds();
text.setOrigin(exitTextRect.left + exitTextRect.width / 2.0f, exitTextRect.top + exitTextRect.height / 2.0f);
text.setPosition(
exitBtn->rect.left + exitBtn->rect.width / 2.0f,
exitBtn->rect.top + exitBtn->rect.height / 2.0f
);
drawShadowedText(window, text);
}
else if (gameOver)
{
// Game Over title
text.setString("GAME OVER");
text.setCharacterSize(38);
text.setStyle(sf::Text::Bold);
text.setFillColor(sf::Color(255, 80, 80));
sf::FloatRect overRect = text.getLocalBounds();
text.setOrigin(overRect.left + overRect.width / 2.0f, overRect.top + overRect.height / 2.0f);
text.setPosition(BOARD_WIDTH * CELL_SIZE / 2.0f, 80);
drawShadowedText(window, text, sf::Color(0,0,0,180), 3.f);
// Score info
text.setString("Score: " + std::to_string(score) + " Best: " + std::to_string(bestScore));
text.setCharacterSize(22);
text.setStyle(sf::Text::Regular);
text.setFillColor(sf::Color::White);
sf::FloatRect scoreRect = text.getLocalBounds();
text.setOrigin(scoreRect.left + scoreRect.width / 2.0f, scoreRect.top + scoreRect.height / 2.0f);
text.setPosition(BOARD_WIDTH * CELL_SIZE / 2.0f, 130);
drawShadowedText(window, text);
// Restart button
sf::RectangleShape restartShape(sf::Vector2f(restartBtn->rect.width, restartBtn->rect.height));
restartShape.setPosition(restartBtn->rect.left, restartBtn->rect.top);
restartShape.setFillColor(restartBtn->hovered ? restartBtn->hoverColor : restartBtn->color);
restartShape.setOutlineThickness(3);
restartShape.setOutlineColor(sf::Color(40, 120, 40));
window.draw(restartShape);
text.setString("Restart");
text.setCharacterSize(24);
text.setFillColor(sf::Color::White);
sf::FloatRect restartTextRect = text.getLocalBounds();
text.setOrigin(restartTextRect.left + restartTextRect.width / 2.0f, restartTextRect.top + restartTextRect.height / 2.0f);
text.setPosition(
restartBtn->rect.left + restartBtn->rect.width / 2.0f,
restartBtn->rect.top + restartBtn->rect.height / 2.0f
);
drawShadowedText(window, text);
// Menu button
sf::RectangleShape menuShape(sf::Vector2f(menuBtn->rect.width, menuBtn->rect.height));
menuShape.setPosition(menuBtn->rect.left, menuBtn->rect.top);
menuShape.setFillColor(menuBtn->hovered ? menuBtn->hoverColor : menuBtn->color);
menuShape.setOutlineThickness(3);
menuShape.setOutlineColor(sf::Color(120, 40, 40));
window.draw(menuShape);
text.setString("Menu");
text.setCharacterSize(22);
text.setFillColor(sf::Color::White);
sf::FloatRect menuTextRect = text.getLocalBounds();
text.setOrigin(menuTextRect.left + menuTextRect.width / 2.0f, menuTextRect.top + menuTextRect.height / 2.0f);
text.setPosition(
menuBtn->rect.left + menuBtn->rect.width / 2.0f,
menuBtn->rect.top + menuBtn->rect.height / 2.0f
);
drawShadowedText(window, text);
}
else
{
// Score bar
text.setString("Score: " + std::to_string(score) + " Best: " + std::to_string(bestScore) +
(paused ? " [PAUSED]" : ""));
text.setCharacterSize(22);
text.setFillColor(sf::Color::White);
text.setStyle(sf::Text::Regular);
text.setPosition(5, BOARD_HEIGHT * CELL_SIZE + 8);
drawShadowedText(window, text);
// Controls
text.setString("WASD / Arrows - Move SPACE - Pause ESC - Menu");
text.setCharacterSize(16);
text.setFillColor(sf::Color(180, 180, 220));
text.setPosition(5, BOARD_HEIGHT * CELL_SIZE + 36);
drawShadowedText(window, text, sf::Color(0,0,0,100), 1.5f);
}
}
window.display();
}
void Game::update()
{
snake.updateDirection();
Point newHead = getTeleportedHead();
if (snake.checkSelfCollision(newHead))
{
gameOver = true;
if (score > bestScore)
{
bestScore = score;
saveBestScore();
}
return;
}
if (newHead == food.getPosition())
{
snake.grow(newHead);
score += 10;
generateFood();
}
else
{
snake.move(newHead);
}
}
Point Game::getTeleportedHead() const
{
Point newHead = snake.getNextHeadPosition();
if (newHead.x < 0) newHead.x = BOARD_WIDTH - 1;
else if (newHead.x >= BOARD_WIDTH) newHead.x = 0;
if (newHead.y < 0) newHead.y = BOARD_HEIGHT - 1;
else if (newHead.y >= BOARD_HEIGHT) newHead.y = 0;
return newHead;
}
void Game::generateFood()
{
std::vector<Point> occupiedPositions(snake.getBody().begin(), snake.getBody().end());
food.generateNew(BOARD_WIDTH, BOARD_HEIGHT, occupiedPositions);
}
void Game::loadBestScore()
{
std::ifstream in(BEST_SCORE_FILE);
if (in)
in >> bestScore;
else
bestScore = 0;
}
void Game::saveBestScore()
{
std::ofstream out(BEST_SCORE_FILE);
if (out)
out << bestScore;
}
void Game::reset()
{
snake = Snake(Point(BOARD_WIDTH / 2, BOARD_HEIGHT / 2));
score = 0;
generateFood();
}

63
Game.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef GAME_H
#define GAME_H
#include "Snake.h"
#include "Food.h"
#include "Direction.h"
#include <SFML/Graphics.hpp>
#include <string>
#include <fstream>
class Game
{
Snake snake;
Food food;
int score;
int bestScore;
bool gameOver;
bool paused;
bool inMenu;
// Menu button struct
struct MenuButton {
sf::FloatRect rect;
std::string label;
sf::Color color;
sf::Color hoverColor;
bool hovered = false;
};
void generateFood();
Point getTeleportedHead() const;
void loadBestScore();
void saveBestScore();
void reset();
public:
static const int BOARD_WIDTH = 20;
static const int BOARD_HEIGHT = 20;
static const int CELL_SIZE = 24;
static constexpr const char* BEST_SCORE_FILE = "best_score.txt";
Game();
void run();
void processEvent(const sf::Event& event,
sf::RenderWindow* window = nullptr,
MenuButton* startBtn = nullptr,
MenuButton* exitBtn = nullptr,
MenuButton* restartBtn = nullptr,
MenuButton* menuBtn = nullptr);
void update();
void render(sf::RenderWindow& window,
MenuButton* startBtn = nullptr,
MenuButton* exitBtn = nullptr,
MenuButton* restartBtn = nullptr,
MenuButton* menuBtn = nullptr);
bool isGameOver() const { return gameOver; }
int getScore() const { return score; }
int getBestScore() const { return bestScore; }
};
#endif //GAME_H

17
Point.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef POINT_H
#define POINT_H
class Point
{
public:
int x, y;
explicit Point(int x = 0, int y = 0) : x(x), y(y){}
bool operator==(const Point& other) const
{
return x == other.x && y == other.y;
}
};
#endif //POINT_H

42
README.md Normal file
View File

@ -0,0 +1,42 @@
# 🐍 Snake Game
Classic Snake game implemented in C++ with a console interface.
## 📁 Project Structure
- `main.cpp` — Entry point
- `Game.*` — Game logic and rendering
- `Snake.*` — Snake class implementation
- `Food.*` — Food generation system
- `Point.h` — Coordinate structure
- `Direction.h` — Direction enumeration
- `best_score.txt` — High score storage
- `CMakeLists.txt` — Build configuration
## 🛠️ Requirements
- C++11 or higher
- CMake 3.10+
- Linux/Unix terminal
## 🎮 Features
- Console-based graphics
- WASD controls
- Food generation
- Collision detection
- Growing snake mechanics
- Score tracking
- Best score persistence
## 🎯 Controls
- W — Move up
- S — Move down
- A — Move left
- D — Move right
- Q — Quit game
## 📦 Build and Run
```bash
mkdir build && cd build
cmake ..
make
./Snake
```

70
Snake.cpp Normal file
View File

@ -0,0 +1,70 @@
#include "Snake.h"
// Constructor
Snake::Snake(Point startPos)
: currentDirection(Direction::RIGHT), nextDirection(Direction::RIGHT)
{
body.push_back(startPos);
}
// Set the movement direction
void Snake::setDirection(Direction dir)
{
if ((currentDirection == Direction::UP && dir == Direction::DOWN) ||
(currentDirection == Direction::DOWN && dir == Direction::UP) ||
(currentDirection == Direction::LEFT && dir == Direction::RIGHT) ||
(currentDirection == Direction::RIGHT && dir == Direction::LEFT))
return;
nextDirection = dir;
}
// Check if the snake's body contains the point pos
bool Snake::contains(Point pos) const
{
for (const Point& segment : body)
if (segment == pos)
return true;
return false;
}
// Move the snake (without growing)
void Snake::move(const Point& newHead)
{
body.push_front(newHead);
body.pop_back();
}
// Grow the snake (add a head)
void Snake::grow(const Point& newHead)
{
body.push_front(newHead);
}
// Update the current direction
void Snake::updateDirection()
{
currentDirection = nextDirection;
}
// Get the next head position
Point Snake::getNextHeadPosition() const
{
Point head = body.front();
switch (currentDirection)
{
case Direction::UP: return Point(head.x, head.y - 1);
case Direction::DOWN: return Point(head.x, head.y + 1);
case Direction::LEFT: return Point(head.x - 1, head.y);
case Direction::RIGHT: return Point(head.x + 1, head.y);
default: return head;
}
}
// Check for self-collision
bool Snake::checkSelfCollision(const Point& newHead) const
{
for (const Point& segment : body)
if (newHead == segment)
return true;
return false;
}

50
Snake.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef SNAKE_H
#define SNAKE_H
#include <vector>
#include <deque>
#include "Point.h"
#include "Direction.h"
class Snake
{
std::deque<Point> body; // The segments of the snake's body
Direction currentDirection; // The current direction of the snake
Direction nextDirection; // The next direction the snake will move towards
public:
// Constructor to initialize the snake's position
Snake(Point startPos);
// Set the snake's direction
void setDirection(Direction dir);
// Move the snake to a new head position
void move(const Point& newHead);
// Grow the snake by adding a new head segment
void grow(const Point& newHead);
// Update the snake's direction based on the next direction
void updateDirection();
// Get the position of the snake's next head
Point getNextHeadPosition() const;
// Check if moving to the new head position will cause the snake to collide with itself
bool checkSelfCollision(const Point& newHead) const;
// Get the current direction of the snake
Direction getDirection() const { return currentDirection; }
// Get the segments of the snake's body
const std::deque<Point>& getBody() const { return body; }
// Get the position of the snake's head
Point getHead() const { return body.front(); }
// Check if the snake's body contains a specific point
bool contains(Point pos) const;
};
#endif // SNAKE_H

2
best_score.txt Normal file
View File

@ -0,0 +1,2 @@
0

9
main.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "Game.h"
int main()
{
Game game;
game.run();
return 0;
}