From 7fd468078a7fb379c424f2b8fb8130b627f89c2f Mon Sep 17 00:00:00 2001 From: MerajDerafshi Date: Tue, 23 Sep 2025 00:42:24 +0330 Subject: [PATCH 1/9] feat(game): implement base functions and board rendering --- snake.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 snake.cpp diff --git a/snake.cpp b/snake.cpp new file mode 100644 index 0000000..d8f9f0e --- /dev/null +++ b/snake.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include + +using namespace std; + +bool gameOver; +const int width = 40; +const int height = 40; +int x, y, fruitX, fruitY, score; +enum eDirection { STOP = 0, LEFT, RIGHT, UP, DOWN }; +eDirection dir; + +void setup() { + gameOver = false; + dir = STOP; + x = width / 2; + y = height / 2; + fruitX = rand() % width; + fruitY = rand() % height; + score = 0; +} + +void draw() { + system("cls"); + for(int i = 0; i < width + 2; i++) cout << "#"; + cout << "\n"; + for(int i = 0; i < height; i++) { + for(int j = 0; j < width; j++ ) { + if(j == 0) cout << "#"; + cout << " "; + if(j == width - 1) cout << "#"; + } + cout << "\n"; + } + for(int i = 0; i < width + 2; i++) cout << "#"; + cout << "\n"; + +} + +void input() { + +} + +void logic() { + +} + +int main() { + setup(); + while(!gameOver){ + draw(); + input(); + logic(); + } +} \ No newline at end of file -- 2.54.0 From 9031d42ee4e809b1af7ec80fcf44813e99fd7033 Mon Sep 17 00:00:00 2001 From: MerajDerafshi Date: Tue, 23 Sep 2025 02:38:07 +0330 Subject: [PATCH 2/9] feat(game): complete full game logic implementation --- snake.cpp | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/snake.cpp b/snake.cpp index d8f9f0e..fbd71f6 100644 --- a/snake.cpp +++ b/snake.cpp @@ -1,14 +1,16 @@ #include #include -#include #include +#include using namespace std; bool gameOver; const int width = 40; -const int height = 40; +const int height = 20; int x, y, fruitX, fruitY, score; +int tailX[100], tailY[100]; +int ntail; enum eDirection { STOP = 0, LEFT, RIGHT, UP, DOWN }; eDirection dir; @@ -29,22 +31,100 @@ void draw() { for(int i = 0; i < height; i++) { for(int j = 0; j < width; j++ ) { if(j == 0) cout << "#"; - cout << " "; + if(i == y && j == x) cout << "O"; + else if(i == fruitY && j == fruitX) cout << "F"; + else { + bool print = false; + for (int k = 0; k < ntail; k++) { + if (tailX[k] == j && tailY[k] == i) { + cout << "o"; + print = true; + } + } + if(!print) cout << " "; + } if(j == width - 1) cout << "#"; } cout << "\n"; } for(int i = 0; i < width + 2; i++) cout << "#"; cout << "\n"; + cout << "score:" << score << "\n"; } void input() { + if(kbhit()) { + char userInput = getch(); + switch(toupper(userInput)) { + case 'A': + case 75: + dir = LEFT; + break; + case 'D': + case 77: + dir = RIGHT; + break; + case 'W': + case 72: + dir = UP; + break; + case 'S': + case 80: + dir = DOWN; + break; + case 27: + break; + } + } } void logic() { + int prevX = tailX[0]; + int prevY = tailY[0]; + int prev2X, prev2Y; + tailX[0] = x; + tailY[0] = y; + for(int i = 1; i < ntail; i++) { + prev2X = tailX[i]; + prev2Y = tailY[i]; + tailX[i] = prevX; + tailY[i] = prevY; + prevX = prev2X; + prevY = prev2Y; + } + + switch(dir){ + case LEFT: + x--; + break; + case RIGHT: + x++; + break; + case UP: + y--; + break; + case DOWN: + y++; + break; + } + + if(x >= width) x = 0; + else if(x < 0) x = width - 1; + if(y >= height) y = 0; + else if(y < 0) y = height - 1; + for(int i = 0; i < ntail; i++) + if(tailX[i] == x && tailY[i] == y) + gameOver = true; + if(x == fruitX && y == fruitY) { + score += 10; + fruitX = rand() % width; + fruitY = rand() % height; + ntail++; + } + } int main() { @@ -53,5 +133,7 @@ int main() { draw(); input(); logic(); + Sleep(100); } + return 0; } \ No newline at end of file -- 2.54.0 From 6d101c9730050798b116b5fe8cc91fb891599578 Mon Sep 17 00:00:00 2001 From: MerajDerafshi Date: Tue, 23 Sep 2025 02:54:45 +0330 Subject: [PATCH 3/9] fix(game): resolve flickering issue in game display --- snake.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snake.cpp b/snake.cpp index fbd71f6..d9b18ce 100644 --- a/snake.cpp +++ b/snake.cpp @@ -25,7 +25,7 @@ void setup() { } void draw() { - system("cls"); + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), {0,0}); for(int i = 0; i < width + 2; i++) cout << "#"; cout << "\n"; for(int i = 0; i < height; i++) { @@ -128,6 +128,7 @@ void logic() { } int main() { + system("cls"); setup(); while(!gameOver){ draw(); -- 2.54.0 From 1ea3f01414d3666beb9a7e3f8fe91a2c1749a482 Mon Sep 17 00:00:00 2001 From: MerajDerafshi Date: Tue, 23 Sep 2025 03:08:34 +0330 Subject: [PATCH 4/9] feat(game): add timer functionality to gameplay --- snake.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/snake.cpp b/snake.cpp index d9b18ce..284e720 100644 --- a/snake.cpp +++ b/snake.cpp @@ -11,6 +11,7 @@ const int height = 20; int x, y, fruitX, fruitY, score; int tailX[100], tailY[100]; int ntail; +int timer; // Variable to store elapsed time in seconds enum eDirection { STOP = 0, LEFT, RIGHT, UP, DOWN }; eDirection dir; @@ -22,6 +23,7 @@ void setup() { fruitX = rand() % width; fruitY = rand() % height; score = 0; + timer = 0; // Initialize timer } void draw() { @@ -50,6 +52,7 @@ void draw() { for(int i = 0; i < width + 2; i++) cout << "#"; cout << "\n"; cout << "score:" << score << "\n"; + cout << "Time: " << timer << "s\n"; // Display timer } @@ -93,7 +96,7 @@ void logic() { tailX[i] = prevX; tailY[i] = prevY; prevX = prev2X; - prevY = prev2Y; + prevY = prev2Y; } switch(dir){ @@ -130,11 +133,18 @@ void logic() { int main() { system("cls"); setup(); + int tickCounter = 0; while(!gameOver){ draw(); input(); logic(); Sleep(100); + + tickCounter++; + if (tickCounter == 10){ + timer++; + tickCounter = 0; + } } return 0; } \ No newline at end of file -- 2.54.0 From 1a14c7ff11ba2a4ab02693cc2dc56a0eddd4d05a Mon Sep 17 00:00:00 2001 From: MerajDerafshi Date: Tue, 23 Sep 2025 03:25:48 +0330 Subject: [PATCH 5/9] style(game): redesign game board UI --- snake.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/snake.cpp b/snake.cpp index 284e720..a9845c7 100644 --- a/snake.cpp +++ b/snake.cpp @@ -7,7 +7,7 @@ using namespace std; bool gameOver; const int width = 40; -const int height = 20; +const int height = 40; int x, y, fruitX, fruitY, score; int tailX[100], tailY[100]; int ntail; @@ -28,29 +28,31 @@ void setup() { void draw() { SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), {0,0}); - for(int i = 0; i < width + 2; i++) cout << "#"; - cout << "\n"; + cout << "┌"; + for(int i = 1; i < width + 1; i++) cout << "─"; + cout << "┐\n"; for(int i = 0; i < height; i++) { for(int j = 0; j < width; j++ ) { - if(j == 0) cout << "#"; + if(j == 0) cout << "│"; if(i == y && j == x) cout << "O"; else if(i == fruitY && j == fruitX) cout << "F"; else { bool print = false; for (int k = 0; k < ntail; k++) { if (tailX[k] == j && tailY[k] == i) { - cout << "o"; + cout << "@"; print = true; } } if(!print) cout << " "; } - if(j == width - 1) cout << "#"; + if(j == width - 1) cout << "│"; } cout << "\n"; } - for(int i = 0; i < width + 2; i++) cout << "#"; - cout << "\n"; + cout << "└"; + for(int i = 1; i < width + 1; i++) cout << "─"; + cout << "┘\n"; cout << "score:" << score << "\n"; cout << "Time: " << timer << "s\n"; // Display timer -- 2.54.0 From acb96cb7b07ec0474b55451eb41430d82cd5913d Mon Sep 17 00:00:00 2001 From: MerajDerafshi Date: Tue, 23 Sep 2025 05:27:48 +0330 Subject: [PATCH 6/9] #include --- snake.cpp | 377 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 335 insertions(+), 42 deletions(-) diff --git a/snake.cpp b/snake.cpp index a9845c7..6703872 100644 --- a/snake.cpp +++ b/snake.cpp @@ -1,13 +1,34 @@ -#include #include +#include +#include +#include +#include +#include +#include #include #include using namespace std; +using namespace chrono; +#define PURPLE "\033[35m" +#define AMETHYSTINE "\033[1;35m" +#define TURQUOISE "\033[1;36m" +#define COBALTBLUE "\033[36m" +#define GRAY "\033[1;90m" +#define RED "\033[1;31m" +#define BLUE "\033[1;34m" +#define YELLOW "\033[1;33m" +#define GREEN "\033[1;92m" +#define LIGHT_GREEN "\033[38;5;118m" +#define SILVER "\033[1;97m" +#define BRONZE "\033[0;33m" +#define RESET "\033[0m" + +// --- Game Variables --- bool gameOver; const int width = 40; -const int height = 40; +const int height = 20; // Adjusted height for better screen fit with menu/leaderboard int x, y, fruitX, fruitY, score; int tailX[100], tailY[100]; int ntail; @@ -15,6 +36,261 @@ int timer; // Variable to store elapsed time in seconds enum eDirection { STOP = 0, LEFT, RIGHT, UP, DOWN }; eDirection dir; +// --- Leaderboard Structure & Globals --- +struct Player { + string name; + int score = 0; + int time = 0; +}; + +string playerName; +Player players[100]; +int NumOfPlayers = 0; + +// --- Function Prototypes --- +// Utility +void clearScreen(); +void pauseForMilliseconds(int milliseconds); +void gotoxy(int x, int y); +void showConsoleCursor(bool showFlag); + +// Menu and Game Flow +int showMenu(); +void getPlayerName(); +void mainGame(); + +// Leaderboard +void leaderboard(); +void sortLeaderboard(); +void loadData(); +void saveData(string name, int score, int time); +void saveInfo(); + +// Original Snake Game Functions +void setup(); +void draw(); +void input(); +void logic(); + + +// --- Main Control Flow --- + +int main() { + #ifdef _WIN32 + SetConsoleOutputCP(CP_UTF8); + #endif + + while (true) { + int choice = showMenu(); + + switch (choice) { + case 0: + mainGame(); + break; + + case 1: + leaderboard(); + cout << GRAY << "\nPress Enter to return to the menu..." << RESET; + getch(); + break; + + case 2: + cout << RED << "\nExiting game. Goodbye!\n" << RESET; + pauseForMilliseconds(1500); + return 0; + } + } + return 0; +} + + +// --- Snake Game Logic (Wrapped) --- + +void mainGame() { + getPlayerName(); + setup(); + int tickCounter = 0; + while (!gameOver) { + draw(); + input(); + logic(); + Sleep(100); // Game speed + + tickCounter++; + if (tickCounter == 10) { // 10 * 100ms = 1 second + timer++; + tickCounter = 0; + } + } + // After game over + saveData(playerName, score, timer); + cout << RED << "GAME OVER!" << RESET << endl; + cout << YELLOW << "Press Enter to return to the menu..." << RESET; + getch(); +} + +// --- Menu & Player Input --- + +void getPlayerName() { + clearScreen(); + cout << "\033[1;37;46m" << "\nEnter your name: " << RESET << " "; + cin >> playerName; +} + +int showMenu() { + + showConsoleCursor(false); + clearScreen(); + cout << "\n\n"; + cout << GREEN << R"( _ + ___ _ __ __ _| | _____ +/ __| '_ \ / _` | |/ / _ \ +\__ \ | | | (_| | < __/ +|___/_| |_|\__,_|_|\_\___|)" << RESET << "\n\n"; + + + string menuItems[] = { "New Game", "Leaderboard", "Exit" }; + int selectedOption = 0; + char key; + + while (true) { + for (int i = 0; i < 3; i++) { + int y_pos = 8 + i * 2; + string textColor = (i == selectedOption) ? GREEN : AMETHYSTINE; + + gotoxy(6, y_pos); + if(selectedOption == i) cout << textColor << "> " << menuItems[i] << " <" << RESET; + else cout << textColor << " " << menuItems[i] << " " << RESET; + } + + key = getch(); + switch (toupper(key)) { + case 'W': + case 72: // Up arrow + selectedOption = (selectedOption > 0) ? selectedOption - 1 : 2; + break; + case 'S': + case 80: // Down arrow + selectedOption = (selectedOption < 2) ? selectedOption + 1 : 0; + break; + case 13: // Enter + showConsoleCursor(true); + return selectedOption; + } + } +} + +// --- Leaderboard Functions --- + +void leaderboard() { + clearScreen(); + loadData(); + sortLeaderboard(); + + cout << TURQUOISE << " _ _ _ _ \n"; + cout << "| | ___ __ _ __| | ___ _ __| |__ ___ __ _ _ __ __| |\n"; + cout << "| |/ _ \\/ _` |/ _` |/ _ \\ '__| '_ \\ / _ \\ / _` | '__/ _` |\n" << RESET; + cout << AMETHYSTINE << "| | __/ (_| | (_| | __/ | | |_) | (_) | (_| | | | (_| |\n"; + cout << "|_|\\___|\\__,_|\\__,_|\\___|_| |_.__/ \\___/ \\__,_|_| \\__,_|\n" << "\n" << RESET; + pauseForMilliseconds(1000); + + + cout << SILVER << setw(20) << left << "Name" + << setw(15) << "Score" + << setw(10) << "Time (s)" << RESET << "\n"; + cout << PURPLE << string(45, '_') << RESET << "\n\n"; + + // Print each player's data + for (int i = 0; i < NumOfPlayers; i++) { + string color; + if (i == 0) color = YELLOW; + else if (i == 1) color = GRAY; + else if (i == 2) color = BRONZE; + else color = RESET; + + cout << color << setw(20) << left << players[i].name + << setw(15) << players[i].score + << setw(10) << players[i].time << RESET << "\n"; + } +} + +void loadData() { + ifstream file("leaderboard.txt"); + if (file.is_open()) { + NumOfPlayers = 0; + while (NumOfPlayers < 100 && file >> players[NumOfPlayers].name >> players[NumOfPlayers].score >> players[NumOfPlayers].time) { + NumOfPlayers++; + } + } + file.close(); +} + +void sortLeaderboard() { + // Sorts players with a two-tiered priority: Score, then Time. + for (int i = 0; i < NumOfPlayers - 1; i++) { + for (int j = i + 1; j < NumOfPlayers; j++) { + bool shouldSwap = false; + + // Priority 1: Score (higher is better) + if (players[j].score > players[i].score) { + shouldSwap = true; + } + // Priority 2: Time (lower is better, used for ties in score) + else if (players[j].score == players[i].score) { + if (players[j].time < players[i].time) { + shouldSwap = true; + } + } + + if (shouldSwap) { + Player temp = players[i]; + players[i] = players[j]; + players[j] = temp; + } + } + } +} + +void saveInfo() { + ofstream file("snake_leaderboard.txt", ios::trunc); + if (file.is_open()) { + for (int i = 0; i < NumOfPlayers; i++) { + file << players[i].name << " " << players[i].score << " " << players[i].time << "\n"; + } + } + file.close(); +} + +void saveData(string name, int score, int time) { + loadData(); + + bool playerFound = false; + for (int i = 0; i < NumOfPlayers; i++) { + if (players[i].name == name) { + playerFound = true; + // Update record only if the new score is higher, + // or if scores are equal and the new time is lower. + if (score > players[i].score || (score == players[i].score && time < players[i].time)) { + players[i].score = score; + players[i].time = time; + } + break; + } + } + + if (!playerFound && NumOfPlayers < 100) { + players[NumOfPlayers].name = name; + players[NumOfPlayers].score = score; + players[NumOfPlayers].time = time; + NumOfPlayers++; + } + + saveInfo(); +} + + +// --- Original Snake Functions (Unchanged Core Logic) --- + void setup() { gameOver = false; dir = STOP; @@ -23,39 +299,39 @@ void setup() { fruitX = rand() % width; fruitY = rand() % height; score = 0; + ntail = 0; // Start with 0 tail length timer = 0; // Initialize timer } void draw() { SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), {0,0}); - cout << "┌"; + cout << AMETHYSTINE << "┌"; for(int i = 1; i < width + 1; i++) cout << "─"; - cout << "┐\n"; + cout << "┐\n" << RESET; for(int i = 0; i < height; i++) { for(int j = 0; j < width; j++ ) { - if(j == 0) cout << "│"; - if(i == y && j == x) cout << "O"; - else if(i == fruitY && j == fruitX) cout << "F"; + if(j == 0) cout << AMETHYSTINE << "│" << RESET; + if(i == y && j == x) cout << BLUE << "O" << RESET; // Snake Head + else if(i == fruitY && j == fruitX) cout << RED << "F" << RESET; // Fruit else { bool print = false; for (int k = 0; k < ntail; k++) { if (tailX[k] == j && tailY[k] == i) { - cout << "@"; + cout << TURQUOISE << "o" << RESET; // Snake Tail print = true; } } if(!print) cout << " "; } - if(j == width - 1) cout << "│"; + if(j == width - 1) cout << AMETHYSTINE << "│" << RESET; } cout << "\n"; } - cout << "└"; + cout << AMETHYSTINE << "└"; for(int i = 1; i < width + 1; i++) cout << "─"; - cout << "┘\n"; - cout << "score:" << score << "\n"; - cout << "Time: " << timer << "s\n"; // Display timer - + cout << "┘\n" << RESET; + cout << GREEN << "Score: " << score << RESET << "\n"; + cout << YELLOW << "Time: " << timer << "s" << RESET << "\n"; } void input() { @@ -63,30 +339,29 @@ void input() { char userInput = getch(); switch(toupper(userInput)) { case 'A': - case 75: - dir = LEFT; + case 75: // Left Arrow + if (dir != RIGHT) dir = LEFT; break; case 'D': - case 77: - dir = RIGHT; + case 77: // Right Arrow + if (dir != LEFT) dir = RIGHT; break; case 'W': - case 72: - dir = UP; + case 72: // Up Arrow + if (dir != DOWN) dir = UP; break; case 'S': - case 80: - dir = DOWN; + case 80: // Down Arrow + if (dir != UP) dir = DOWN; break; - case 27: + case 27: // ESC key + gameOver = true; break; - } } } void logic() { - int prevX = tailX[0]; int prevY = tailY[0]; int prev2X, prev2Y; @@ -114,39 +389,57 @@ void logic() { case DOWN: y++; break; + default: + break; } + // Wall collision (wrap around) if(x >= width) x = 0; else if(x < 0) x = width - 1; if(y >= height) y = 0; else if(y < 0) y = height - 1; + + // Tail collision for(int i = 0; i < ntail; i++) if(tailX[i] == x && tailY[i] == y) gameOver = true; + + // Fruit collision if(x == fruitX && y == fruitY) { score += 10; fruitX = rand() % width; fruitY = rand() % height; ntail++; } - } -int main() { - system("cls"); - setup(); - int tickCounter = 0; - while(!gameOver){ - draw(); - input(); - logic(); - Sleep(100); +// --- Utility Functions --- - tickCounter++; - if (tickCounter == 10){ - timer++; - tickCounter = 0; - } - } - return 0; +void clearScreen() { + #ifdef _WIN32 + system("cls"); + #else + system("clear"); + #endif +} + +void pauseForMilliseconds(int milliseconds) { + this_thread::sleep_for(chrono::milliseconds(milliseconds)); +} + +void gotoxy(int x, int y) { + #ifdef _WIN32 + COORD coord = { (SHORT)x, (SHORT)y }; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); + #endif +} + +void showConsoleCursor(bool showFlag) { + #ifdef _WIN32 + HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_CURSOR_INFO cursorInfo; + GetConsoleCursorInfo(out, &cursorInfo); + cursorInfo.bVisible = showFlag; + SetConsoleCursorInfo(out, &cursorInfo); + #endif } \ No newline at end of file -- 2.54.0 From 2d55962f5b6def145c79b454cad1dbc86ce5f6f7 Mon Sep 17 00:00:00 2001 From: MerajDerafshi Date: Tue, 23 Sep 2025 05:35:51 +0330 Subject: [PATCH 7/9] feat(project):complete full implementation of all features --- snake.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snake.cpp b/snake.cpp index 6703872..668291e 100644 --- a/snake.cpp +++ b/snake.cpp @@ -139,7 +139,7 @@ void getPlayerName() { int showMenu() { - showConsoleCursor(false); + showConsoleCursor(false); clearScreen(); cout << "\n\n"; cout << GREEN << R"( _ -- 2.54.0 From d1c58b50e8dc1c911c557d4d4834273ebe15b956 Mon Sep 17 00:00:00 2001 From: MerajDerafshi Date: Tue, 23 Sep 2025 05:51:07 +0330 Subject: [PATCH 8/9] add leaderboard file and sample data --- leaderboard.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 leaderboard.txt diff --git a/leaderboard.txt b/leaderboard.txt new file mode 100644 index 0000000..05767dc --- /dev/null +++ b/leaderboard.txt @@ -0,0 +1,4 @@ +Sam 370 139 +Mehrad 370 141 +navid 200 80 +Meraj 120 40 -- 2.54.0 From ddba3d661894ba47325cbfcac196796068ac63cf Mon Sep 17 00:00:00 2001 From: MerajDerafshi Date: Tue, 23 Sep 2025 06:07:39 +0330 Subject: [PATCH 9/9] add README file and images --- README.md | 90 ++++++++++++++++++++++++++++++++++++++++++ image/Game.png | Bin 0 -> 5464 bytes image/Menu.png | Bin 0 -> 4587 bytes image/leaderboard.png | Bin 0 -> 11701 bytes 4 files changed, 90 insertions(+) create mode 100644 README.md create mode 100644 image/Game.png create mode 100644 image/Menu.png create mode 100644 image/leaderboard.png diff --git a/README.md b/README.md new file mode 100644 index 0000000..0b6e52b --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +# 🐍 Snake Game (C++ Console Edition) + +A colorful and modern **Snake Game** built entirely in **C++** for the terminal. +This version includes a **menu system, persistent leaderboard, scoring with time tracking, smooth controls, and a retro ASCII-art UI** that makes the classic snake experience both fun and polished. + +--- + +## 🎮 Features + +- 🏠 **Main Menu:** Start a new game, view the leaderboard, or exit. +- 👤 **Player Names:** Each player enters their name before starting, and their performance is tracked. +- 🎯 **Scoring System:** + - +10 points for each fruit collected + - Timer shows how long you survived + - Score combined with time for leaderboard ranking +- 🏆 **Leaderboard:** Sorted by **score** (higher is better), with **time** used as a tiebreaker. +- 🐍 **Snake Mechanics:** Grow longer each time you eat fruit, but avoid running into your own tail! +- 🔄 **Wrap-Around Walls:** When hitting borders, snake reappears on the opposite side. +- ⏱ **Time Tracking:** Total game duration is displayed alongside your score. +- 🎨 **Colorful Console Graphics:** Snake, fruits, borders, and leaderboard are all highlighted with ANSI colors. +- 💾 **Persistent Save:** Player data is stored in `leaderboard.txt` so you can keep competing across sessions. +- ⚡ **Fast and Simple UI:** Runs directly in terminal — no extra dependencies. + +--- + +## 📷 Screenshots + +### 🏠 Main Menu +![Menu](./image/Menu.png) + +--- + +### 🏆 Leaderboard +![Leaderboard](./image/leaderboard.png) + +--- + +### 🎮 In-Game +![Gameplay](./image/Game.png) + +--- + +## ⚙️ Setup & Run + +### ✅ Requirements +- A C++ compiler (e.g., g++, MSVC) +- Windows OS (project uses `conio.h` and `windows.h`) +- Console with UTF-8 and ANSI color support + +### 📦 Build & Run + +#### On Windows: +```bash +g++ -o snake snake.cpp -std=c++11 +snake.exe +``` + +#### On Linux/macOS: +> ⚠️ This version relies on Windows-specific libraries. For Linux/macOS, small adjustments are required (replace `conio.h` and `windows.h` with platform-specific functions). + +--- + +## 🕹️ Controls + +- `W` or **Up Arrow** → Move Up +- `S` or **Down Arrow** → Move Down +- `A` or **Left Arrow** → Move Left +- `D` or **Right Arrow** → Move Right +- `ESC` → End the game immediately + +--- + +## 📁 Project Files + +- `snake.cpp` → Main source code +- `leaderboard.txt` → Stores player leaderboard data + + +--- + +## 👤 Creator + +> **Name:** _[Meraj Derafshi]_ +> **Contact/Portfolio:** _[https://github.com/MerajDerafshi]_ + +--- + +## 📜 License + +This project is open-source. Feel free to use, modify, or expand it for learning or fun. Attribution is appreciated. diff --git a/image/Game.png b/image/Game.png new file mode 100644 index 0000000000000000000000000000000000000000..b1c608c3bd7fa8265a2523c792b876bb9a4b8822 GIT binary patch literal 5464 zcmeHLdpy+n*B_>Nvu##*pT`&=btXo25T!)#|rbV%G7lzg)!jNki zw4!X7+;bbbHO&mB=E^WL&zE}j+VF#TH5p^NJ_nNgQ%KayIlsm8o0-=>WuKHd(8|WK= z3Q~eyLMw$S!L-$t!hw5~`o>Dv;K<*uj~>_iqVZXOeeDu8;Sl*01ln`c@}#L6q;6Y$zLyiMwxNDn6FwrXzF5=YmW5Ig^Jm zAk5IM*!ymM+m2qT5>x9eu$k4gKRm8DA7p+<;_iwmmkS%MNUakeh#L2!F!D>1Us}7lq*)oMyPi`cH3V+ z&eJfq9+3~WYrH!86t!}WTyQ`6iTS3^jH!a6DjRYG>uLQ$&avDeudz3aiN_a0T9b-; zGk^4Dq@dn@pF;|23)?A{g`V{rP@s5I@-NXAqc33}DA=HjJHUhEZ5Ma0hs8ALQsepK zZaCK3(bOfL7eV}%Ev(@i5EEqQYey9Z&n@hbZnyZ#m!+{M?$Y(AKb1%;|#pqlkFgJG1?6%|O8ZKAJu= z)+)^<7%`Bpv+37NomTX@pE-C|8t~$E-Yi`7R%drX%#rUzdonG>%{Q`X8UzTEz6#2< zlV$(V{ltFV;%fY}7ohyK;nu&)optlOEm~#JO>H|6f6lFwhq7LZxuVYQ4WNP4e4;%O29fu8o;K0u-4FU*aGWrk+DQ>q$hu$ z+y3uF%io4GVpxpS)nasOoga@#)U?sZEU{`RAL)hd2~lVQSUUg+1uUn&coH(D<=-gC zp^&*dwr-75^>5%%Q#eKk_`SO}-(I)XBfs|2cLarw_&5w5vK7#`nW|x;=4Vi^*{b~ESO^Cb z&zo0iQSomK89^}zAvB|#*AGb6yiY1YurTovAFq=WT@2ce@BUoxUkdf_arb{IJnP*N zCp9S-*jz>Gwne2CLr$PjV-2rIDGzMwG17HQcj!$@^87Rct^6uA8#TIb>ajj=LDzWo z4QW(GWTFR*)igyDIfz%FX)x zj(cM`(b5}rnDH-{x3b~i=gIrp!5?> z-pB&&Lj4~n|KGy(JfyICE|oHj5cW+ZnsG|Gp!e}6mGV4K-kU*t%1yeE*8S2tbO^T@ z*j{I+zmP-~$NRi6g!f`j&TF#3mD#^{a6|KrGflUIOe$~6D3>p$4!v53L@l7-Pf;!U;E)o;HUu&E!`&I#HxwY`mF97G} z834#Uy~)%AfOY0qSUU{>l;yVi{htYNV@CQ~2Y+GDza0EOv*T_TA-Ql1;4s|T^qK78=Y&a$vmne}^Sc2hfSs^|r@?VAL)U;<#IvS&;?o!z+Jv#gma?%?4y%CcZ4Ty>5Iw8*D0;14&J;zxc#IGZVSCqy>Lm&KvHO=>voxWXR?Me-m}%_-tCvh z6V{1yiM|N($n;WV@JFh^i_Q+W$5d+4#~0}%Jy>`e5}$&smuHfnM1`yktgSWnviyd7 z@bj}Pey|lk3;a<~U1)V$1`Is{sk$_fn{A zk>6Mv<}1i$Vjj{L=u=(z>E9y{Jz&tBTx_l8h@0;vQ`COBVo>6wibs%BkL}-JdhOsyM2kqHPMCjMuMdD0FL-!M&$~Z=BlG*F7xb+yM{5hiU!{lS}w6LNr zh;2q}(;Lfi?taI}!r^x=Cz<)7!~@8DJNgfCX{D#=mUdh5wzcYM0bRyOHt(LZdoZU< zn2f_JVHMo6S)0yj;M8RavDvtBRh&3v3JjR-!D`B2=-7mgTM?O_AM1J@^&c{EhVzTl zt=@j6GDe?nuhp(x6_l(goEiw#5yxQjWP9-CGSdC(pcs03k2EDt$FYDw8^!ziDU*qrAuL0k5rht#V^ z7QZ>gg+KMN0}J|ACHhPwE2lnS$t52&piw#&fy8CnR=jBql0~@JlF;WTrY%vlSp?Lc z%Tf>p5ncXvkb9%M?Zr;0k=i7ddxs*3SD|@>4qIzU4uID*BAvN?QE0=&##s&(3YCS} z>Rri6w#8$Y1_s8dSO*U`Rxpp+MO?sfKr�$=U}GsHGN(=|V_M-`}J>nY3hyGv;U& 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 bU65ztLx&!T%@KH!i0GNJwo=v8=db@4%yXdF literal 0 HcmV?d00001 -- 2.54.0