diff --git a/snake.cpp b/snake.cpp new file mode 100644 index 0000000..9cc4da2 --- /dev/null +++ b/snake.cpp @@ -0,0 +1,339 @@ +#include +#include +#include +#include + +using namespace std; + +const int WIDTH = 30; +const int HEIGHT = 15; +const int OBSTACLE_COUNT = 10; +const int NORMAL_FRUIT_SCORE = 10; +const int HIGH_SCORE_FRUIT_SCORE = 30; +const int WIN_SCORE = 500; + +bool gameover, paused, highScoreFruit; +int x, y, fruitX, fruitY, highScoreFruitX, highScoreFruitY, score; +int tailX[100], tailY[100], nTail; +int x2, y2, score2, tailX2[100], tailY2[100], nTail2; +int obstacles[OBSTACLE_COUNT][2]; +enum Direction { STOP = 0, LEFT, RIGHT, UP, DOWN }; +Direction dir, dir2; +bool twoSnakeMode = false; // 增加模式选择标志 + +void gotoxy(int x, int y) { + COORD coord; + coord.X = x; + coord.Y = y; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); +} + +void SetConsoleCursor(bool visible) { + CONSOLE_CURSOR_INFO cci; + cci.dwSize = 1; + cci.bVisible = visible ? TRUE : FALSE; + SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci); +} + +void InitializeObstacles() { + for (int i = 0; i < OBSTACLE_COUNT; ++i) { + do { + obstacles[i][0] = rand() % WIDTH; + obstacles[i][1] = rand() % HEIGHT; + } while ((obstacles[i][0] == x && obstacles[i][1] == y) || (twoSnakeMode && obstacles[i][0] == x2 && obstacles[i][1] == y2)); + } +} + +void GenerateFruit(int& fruitX, int& fruitY) { + int tt; + do { + tt = 0; + fruitX = rand() % (WIDTH - 2) + 1; + fruitY = rand() % (HEIGHT - 2) + 1; + for (int i = 0; i < nTail; ++i) + if (fruitX == tailX[i] && fruitY == tailY[i]) tt = 1; + for (int i = 0; i < OBSTACLE_COUNT; ++i) + if (fruitX == obstacles[i][0] && fruitY == obstacles[i][1]) tt = 1; + if (fruitX == x && fruitY == y) tt = 1; + if (twoSnakeMode && fruitX == x2 && fruitY == y2) tt = 1; + } while (tt == 1); +} + +void Setup() { + gameover = paused = highScoreFruit = false; + dir = dir2 = STOP; + x = WIDTH / 2; + y = HEIGHT / 2; + if (twoSnakeMode) { + x2 = WIDTH / 3; + y2 = HEIGHT / 3; + score2 = 0; + nTail2 = 0; + } + fruitX = rand() % WIDTH; + fruitY = rand() % HEIGHT; + score = 0; + nTail = 0; + InitializeObstacles(); +} + +void Draw() { + gotoxy(0, 0); // 将光标移动到控制台的左上角 + + for (int i = 0; i < WIDTH + 2; i++) + cout << "#"; + cout << endl; + + for (int i = 0; i < HEIGHT; i++) { + for (int j = 0; j < WIDTH; j++) { + if (j == 0) + cout << "#"; + + bool isObstacle = false; + for (int k = 0; k < OBSTACLE_COUNT; ++k) { + if (obstacles[k][0] == j && obstacles[k][1] == i) { + cout << "*"; + isObstacle = true; + break; + } + } + + if (!isObstacle) { + if (i == y && j == x) + cout << "O"; + else if (twoSnakeMode && i == y2 && j == x2) + cout << "X"; + else if (i == fruitY && j == fruitX) + cout << "F"; + else if (i == highScoreFruitY && j == highScoreFruitX && highScoreFruit) + cout << "H"; + else { + bool printTail = false; + for (int k = 0; k < nTail; k++) { + if (tailX[k] == j && tailY[k] == i) { + cout << "o"; + printTail = true; + break; + } + } + if (twoSnakeMode) { + for (int k = 0; k < nTail2; k++) { + if (tailX2[k] == j && tailY2[k] == i) { + cout << "x"; + printTail = true; + break; + } + } + } + if (!printTail) + cout << " "; + } + } + + if (j == WIDTH - 1) + cout << "#"; + } + cout << endl; + } + + for (int i = 0; i < WIDTH + 2; i++) + cout << "#"; + cout << endl; + cout << "Score1: " << score; + if (twoSnakeMode) cout << " Score2: " << score2; + cout << endl; + + if (paused) + cout << "Paused. Press 'R' to resume." << endl; + else + cout << " " << endl; +} + +void Input() { + if (_kbhit()) { + switch (_getch()) { + case 'a': + dir = LEFT; + break; + case 'd': + dir = RIGHT; + break; + case 'w': + dir = UP; + break; + case 's': + dir = DOWN; + break; + case 'j': + if (twoSnakeMode) dir2 = LEFT; + break; + case 'l': + if (twoSnakeMode) dir2 = RIGHT; + break; + case 'i': + if (twoSnakeMode) dir2 = UP; + break; + case 'k': + if (twoSnakeMode) dir2 = DOWN; + break; + case 'p': + paused = !paused; + break; + case 'q': + gameover = true; + break; + } + } +} + +void MoveSnake(int& x, int& y, int tailX[], int tailY[], int& nTail, Direction dir) { + 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; + default: + break; + } + + if (x >= WIDTH) x = 0; else if (x < 0) x = WIDTH - 1; + if (y >= HEIGHT) y = 1; else if (y <= 0) y = HEIGHT - 1; + + for (int i = 0; i < nTail; i++) + if (tailX[i] == x && tailY[i] == y) + gameover = true; + + for (int i = 0; i < OBSTACLE_COUNT; ++i) { + if (x == obstacles[i][0] && y == obstacles[i][1]) { + gameover = true; + } + } +} + +void Algorithm() { + if (!paused) { + MoveSnake(x, y, tailX, tailY, nTail, dir); + if (twoSnakeMode) { + MoveSnake(x2, y2, tailX2, tailY2, nTail2, dir2); + } + + static int timer = 0; + const int timerThreshold = 50; + + timer++; + if (timer == timerThreshold) { + timer = 0; + highScoreFruit = true; + GenerateFruit(highScoreFruitX, highScoreFruitY); + } + + if (x == highScoreFruitX && y == highScoreFruitY) { + score += HIGH_SCORE_FRUIT_SCORE; + highScoreFruit = false; + nTail += 2; + } + if (twoSnakeMode && x2 == highScoreFruitX && y2 == highScoreFruitY) { + score2 += HIGH_SCORE_FRUIT_SCORE; + highScoreFruit = false; + nTail2 += 2; + } + + if (x == fruitX && y == fruitY) { + score += NORMAL_FRUIT_SCORE; + nTail++; + GenerateFruit(fruitX, fruitY); + } + if (twoSnakeMode && x2 == fruitX && y2 == fruitY) { + score2 += NORMAL_FRUIT_SCORE; + nTail2++; + GenerateFruit(fruitX, fruitY); + } + + if (score >= WIN_SCORE) { + gameover = true; + gotoxy(0, HEIGHT + 3); + Draw(); + cout << "Player 1 wins!" << endl; + return; + } + + if (twoSnakeMode && score2 >= WIN_SCORE) { + gameover = true; + gotoxy(0, HEIGHT + 3); + Draw(); + cout << "Player 2 wins!" << endl; + return; + } + } +} + +void Index() { + cout << "Press 1 for single snake mode" << endl; + cout << "Press 9 for two snakes mode" << endl; + cout << "Press 2 to exit\nPress p to pause\nPress r to resume\nPress q to quit" << endl; + cout << "Rules:\nNormal fruit 'F' = 10 scores, increases length by 1;\nHigh-score fruit 'H' = 30 scores, increases length by 2;\nReach 500 scores to win!" << endl; +} + +int main() { + SetConsoleOutputCP(CP_UTF8); + srand(time(0)); + Index(); + while (true) { + int flag = 0; + switch (_getch()) { + case '1': + twoSnakeMode = false; + Setup(); + while (!gameover) { + Draw(); + Input(); + Algorithm(); + Sleep(100); + } + gotoxy(0, WIDTH + 1); + Index(); + break; + case '9': + twoSnakeMode = true; + Setup(); + while (!gameover) { + Draw(); + Input(); + Algorithm(); + Sleep(100); + } + gotoxy(0, WIDTH + 1); + Index(); + break; + case '2': + flag = 1; + break; + } + if (flag) break; + } + SetConsoleCursor(true); + return 0; +}