diff --git a/.gitignore b/.gitignore index d4fb281..544f547 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# VS Code settings +.vscode/ + # Prerequisites *.d @@ -38,4 +41,4 @@ *.app # debug information files -*.dwo +*.dwo \ No newline at end of file diff --git a/snake.h b/snake.h index ebe1192..df6f923 100644 --- a/snake.h +++ b/snake.h @@ -4,54 +4,82 @@ #include #include #include -#include // for system clear +#include #include #include #include +#include + using namespace std; using std::chrono::system_clock; using namespace std::this_thread; char direction='r'; +vector top_scores; +bool paused = false; +void load_top_scores() { + ifstream infile("top_scores.txt"); + int s; + top_scores.clear(); + while (infile >> s) { + top_scores.push_back(s); + } + infile.close(); + sort(top_scores.rbegin(), top_scores.rend()); + if (top_scores.size() > 10) top_scores.resize(10); +} +void save_top_scores() { + ofstream outfile("top_scores.txt"); + for (int s : top_scores) { + outfile << s << endl; + } + outfile.close(); +} void input_handler(){ - // change terminal settings struct termios oldt, newt; tcgetattr(STDIN_FILENO, &oldt); newt = oldt; - // turn off canonical mode and echo newt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newt); - map keymap = {{'d', 'r'}, {'a', 'l'}, {'w', 'u'}, {'s', 'd'}, {'q', 'q'}}; + map keymap = {{'d', 'r'}, {'a', 'l'}, {'w', 'u'}, {'s', 'd'}}; + + while (true) { char input = getchar(); if (keymap.find(input) != keymap.end()) { - // This now correctly modifies the single, shared 'direction' variable direction = keymap[input]; - }else if (input == 'q'){ + }else if(input == 'p') { + paused = !paused; + } + else if (input == 'q'){ exit(0); } - // You could add an exit condition here, e.g., if (input == 'q') break; } tcsetattr(STDIN_FILENO, TCSANOW, &oldt); } -void render_game(int size, deque> &snake, pair food){ - for(size_t i=0;i> &snake, pair food, pair poison) { + for (size_t i = 0; i < size; i++) { + for (size_t j = 0; j < size; j++) { + if (i == food.first && j == food.second) { + cout << "🍎"; + } else if (i == poison.first && j == poison.second) { + cout << "☠️"; + } else if (find(snake.begin(), snake.end(), make_pair(int(i), int(j))) != snake.end()) { cout << "🐍"; - }else{ + } else { cout << "⬜"; } + } + cout << endl; } - cout << endl; -} } + + + pair get_next_head(pair current, char direction){ pair next; if(direction =='r'){ @@ -68,34 +96,111 @@ pair get_next_head(pair current, char direction){ } +pair generate_food(int size, const deque> &snake) { + pair food; + do { + food = make_pair(rand() % size, rand() % size); + } while (find(snake.begin(), snake.end(), food) != snake.end()); + return food; +} +pair generate_poison(int size, const deque> &snake, pair food) { + pair poison; + do { + poison = make_pair(rand() % size, rand() % size); + } while ( + find(snake.begin(), snake.end(), poison) != snake.end() || poison == food + ); + return poison; +} + +void game_play() { + load_top_scores(); -void game_play(){ system("clear"); deque> snake; - snake.push_back(make_pair(0,0)); - - pair food = make_pair(rand() % 10, rand() % 10); - for(pair head=make_pair(0,1);; head = get_next_head(head, direction)){ - // send the cursor to the top - cout << "\033[H"; - // check self collision - if (find(snake.begin(), snake.end(), head) != snake.end()) { - system("clear"); - cout << "Game Over" << endl; - exit(0); - }else if (head.first == food.first && head.second == food.second) { - // grow snake - food = make_pair(rand() % 10, rand() % 10); - snake.push_back(head); - }else{ - // move snake - snake.push_back(head); - snake.pop_front(); + snake.push_back(make_pair(0, 0)); + + pair food = generate_food(10, snake); + pair poison = generate_poison(10, snake, food); + + + int food_eaten = 0; + int speed = 500; + int score = 0; + int poison_timer = 0; + +pair head = make_pair(0, 1); +while (true) { + cout << "\033[H"; + + while (paused) { + system("clear"); + render_game(10, snake, food, poison); + cout << "=== PAUSED ===" << endl; + cout << "Press 'p' to resume..." << endl; + sleep_for(std::chrono::milliseconds(200)); + system("clear"); + } + + head = get_next_head(head, direction); + + if (find(snake.begin(), snake.end(), head) != snake.end()) { + system("clear"); + + top_scores.push_back(score); + sort(top_scores.rbegin(), top_scores.rend()); + if (top_scores.size() > 10) top_scores.resize(10); + save_top_scores(); + + cout << "Game Over! Snake hit itself." << endl; + cout << "Top 10 Scores:" << endl; + for (int s : top_scores) cout << s << endl; + + exit(0); +} +else if (head == poison) { + system("clear"); + + // Update top scores and save + top_scores.push_back(score); + sort(top_scores.rbegin(), top_scores.rend()); + if (top_scores.size() > 10) top_scores.resize(10); + save_top_scores(); + + cout << "Game Over! Snake ate poison ☠️." << endl; + cout << "Top 10 Scores:" << endl; + for (int s : top_scores) cout << s << endl; + + exit(0); +} + + + else if (head.first == food.first && head.second == food.second) { + food = generate_food(10, snake); + snake.push_back(head); + food_eaten++; + score += 10; + + if (food_eaten % 10 == 0 && speed > 100) { + speed += 50; } - render_game(10, snake, food); - cout << "length of snake: " << snake.size() << endl; - - sleep_for(500ms); + } else { + snake.push_back(head); + snake.pop_front(); + } + + poison_timer += speed; // add time passed in this loop + if (poison_timer >= 5000) { + poison = generate_poison(10, snake, food); + poison_timer = 0; } + + render_game(10, snake, food, poison); + cout << "length of snake: " << snake.size() << endl; + cout << "Score: " << score << endl; + cout << "food eaten: " << food_eaten << " | current speed: " << speed << "ms" << endl; + + sleep_for(std::chrono::milliseconds(speed)); } +} \ No newline at end of file diff --git a/top_scores.txt b/top_scores.txt new file mode 100644 index 0000000..cf8ba84 --- /dev/null +++ b/top_scores.txt @@ -0,0 +1,3 @@ +20 +20 +0 \ No newline at end of file