Fork Copy #include #include #include #include #include using namespace std; const int n = 20; // kích thước sân chơi n x n enum Direction { STOP = 0, LEFT, RIGHT, UP, DOWN }; void gotoxy(int x, int y) { static HANDLE h = NULL; if (!h) h = GetStdHandle(STD_OUTPUT_HANDLE); COORD c = { (SHORT)x, (SHORT)y }; SetConsoleCursorPosition(h, c); } void hideCursor() { HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_CURSOR_INFO info; info.dwSize = 100; info.bVisible = FALSE; SetConsoleCursorInfo(consoleHandle, &info); } class Point { public: int x, y; Point(int x = 0, int y = 0) : x(x), y(y) {} bool operator==(const Point& other) const { return x == other.x && y == other.y; } }; class Apple { Point point; char display; public: Apple() { setDisplay('A'); } void spawn(const vector& snake) { while (true) { Point p(rand() % (n - 2) + 1, rand() % (n - 2) + 1); bool overlap = false; for (auto& s : snake) if (s == p) { overlap = true; break; } if (!overlap) { point = p; break; } } } bool checkEat(Point p) { return p == point; } Point getPoint() const { return point; } void setDisplay(char d) { display = d; } char getDisplay() const { return display; } }; class Snake { vector body; Direction dir; public: Snake() { dir = STOP; body.push_back(Point(n / 2, n / 2)); // đầu 'o' body.push_back(Point(n / 2, n / 2 + 1)); // thân '#' body.push_back(Point(n / 2, n / 2 + 2)); // đuôi 'O' } void setDirection(Direction d) { if ((d == LEFT && dir == RIGHT) || (d == RIGHT && dir == LEFT) || (d == UP && dir == DOWN) || (d == DOWN && dir == UP)) return; dir = d; } void move(bool grow) { Point newHead = body[0]; switch (dir) { case LEFT: newHead.y--; break; case RIGHT: newHead.y++; break; case UP: newHead.x--; break; case DOWN: newHead.x++; break; default: return; } body.insert(body.begin(), newHead); if (!grow) body.pop_back(); // Nếu không ăn táo thì bỏ đuôi } bool checkCollision() { Point head = body[0]; if (head.x <= 0 || head.y <= 0 || head.x >= n - 1 || head.y >= n - 1) return true; for (int i = 1; i < body.size(); i++) if (body[i] == head) return true; return false; } vector& getBody() { return body; } Point getHead() { return body[0]; } }; class Game { Snake snake; Apple apple; bool gameOver; int score; public: Game() { srand(time(NULL)); apple.spawn(snake.getBody()); gameOver = false; score = 0; } void Draw() { gotoxy(0, 0); // Vẽ sân for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { bool printed = false; // Tường if (i == 0 || j == 0 || i == n - 1 || j == n - 1) { cout << (i == n - 1 ? '-' : '|'); printed = true; } else if (Point(i, j) == apple.getPoint()) { cout << apple.getDisplay(); printed = true; } else { auto body = snake.getBody(); for (int k = 0; k < body.size(); k++) { if (body[k].x == i && body[k].y == j) { if (k == 0) cout << 'o'; // đầu else if (k == body.size() - 1) cout << 'O'; // đuôi else cout << '#'; // thân printed = true; break; } } } if (!printed) cout << ' '; } cout << "\n"; } cout << "Score: " << score << "\n"; } void Input() { if (_kbhit()) { char c = _getch(); switch (c) { case 'a': snake.setDirection(LEFT); break; case 'd': snake.setDirection(RIGHT); break; case 'w': snake.setDirection(UP); break; case 's': snake.setDirection(DOWN); break; case 'q': gameOver = true; break; } } } void Update() { bool grow = false; if (apple.checkEat(snake.getHead())) { score++; apple.spawn(snake.getBody()); grow = true; } snake.move(grow); if (snake.checkCollision()) gameOver = true; } void Run() { hideCursor(); while (!gameOver) { Input(); Update(); Draw(); Sleep(100); } gotoxy(0, n + 2); cout << "Game Over! Final Score: " << score << "\n"; } }; int main() { Game game; game.Run(); return 0; }