From 7d2550b50df132072db57e8762bf247e51834aaa Mon Sep 17 00:00:00 2001 From: Tejas Protim Neog <92169576+tpncoder@users.noreply.github.com> Date: Sun, 19 Jul 2026 23:36:10 +0530 Subject: [PATCH] Add: Snake Game --- Snake-Game/README.md | 19 +++++++++ Snake-Game/main.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 Snake-Game/README.md create mode 100644 Snake-Game/main.cpp diff --git a/Snake-Game/README.md b/Snake-Game/README.md new file mode 100644 index 00000000..e4d862a2 --- /dev/null +++ b/Snake-Game/README.md @@ -0,0 +1,19 @@ +# Snake Game +A simple snake game written in C++
+ +## Installation +Make sure you have C++ installed on your system +
+```clang++ -O2 -std=c++17 main.cpp -o main.exe``` +
or
+```g++ -g main.cpp -o main.exe``` + +Execute the following to play
+```./main.exe``` + +## Keybindings +* ```W``` + ```Enter``` = Up +* ```A``` + ```Enter``` = Left +* ```S``` + ```Enter``` = Down +* ```D``` + ```Enter``` = Down +* ```Q``` + ```Enter``` = Quit \ No newline at end of file diff --git a/Snake-Game/main.cpp b/Snake-Game/main.cpp new file mode 100644 index 00000000..0c5de48b --- /dev/null +++ b/Snake-Game/main.cpp @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include + +constexpr int W = 20, H = 10; +enum Direction { LEFT, RIGHT, TOP, BOTTOM }; +struct Point { + int x; + int y; +}; +std::vector snake; +std::atomic dir(RIGHT); +bool game_over = false; + +void input_listener() { + while(!game_over) { + char c; + std::cin >> c; + c = tolower(c); + + // prevent 180 deg movement -> snake eating itself lol + if(c == 'q') game_over = true; // exit + if(c == 'w' && dir != BOTTOM) dir = TOP; + if(c == 's' && dir != TOP) dir = BOTTOM; + if(c == 'a' && dir != RIGHT) dir = LEFT; + if(c == 'd' && dir != LEFT) dir = RIGHT; + } +} + +Point generate_fruit() { + int fx, fy; + do { + fx = rand() % W; + fy = rand() % H; + } while (std::any_of(snake.begin(), snake.end(), [fx, fy](const Point& p) { + return p.x == fx && p.y == fy; + })); + + Point fruit = {fx, fy}; + return fruit; +} + +int main() { + snake = {{W/2, H/2}, {W/2-1, H/2}, {W/2-2, H/2}}; + + std::thread input_thread(input_listener); + Point fruit = generate_fruit(); + + // game loop + while(!game_over) { + Point new_head = snake.front(); + if(dir == TOP) { new_head.y--; } + if(dir == BOTTOM) { new_head.y++; } + if(dir == RIGHT) { new_head.x++; } + if(dir == LEFT) { new_head.x--; } + + // clip through walls + if(new_head.x < 0) { new_head.x = W - 1; } + if(new_head.x >= W) { new_head.x = 0; } + if(new_head.y < 0) { new_head.y = H - 1; } + if(new_head.y >= H) { new_head.y = 0; } + + // eating itself + for (const auto& s : snake) if (s.x == new_head.x && s.y == new_head.y) game_over = true; + + // create head for moving effect + snake.insert(snake.begin(), new_head); + + if (new_head.x == fruit.x && new_head.y == fruit.y) { fruit = generate_fruit(); } + else { snake.pop_back(); } + + system("cls"); + std::string frame = ""; + + // rendering + for(int i = 0; i < H; i++) { + for(int j = 0; j < W; j++) { + if(snake.front().x == j && snake.front().y == i) { frame += "O"; } + else if(std::any_of(snake.begin(), snake.end(), [i, j](const Point& p) { return p.x == j && p.y == i; })) { frame += "o"; } + else if(fruit.x == j && fruit.y == i) { frame += "X"; } + else { frame += "."; } + } + frame += "\n"; + } + std::cout << frame << std::flush; + + // 10 fps + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + input_thread.join(); + std::cout << "Game Over!\n"; + + return 0; +} \ No newline at end of file