用 C++ 类来写贪吃蛇:Snake 类管身体和移动,主函数管输入和渲染。顺便体会 deque 双端队列为什么天生适合当蛇身。
1. Snake 类与 deque
蛇身用 deque<Pos> 存,头在 front。移动 = 新头插前、吃到食物不弹尾就变长。方向用枚举防止"直接反向":
#include <iostream>
#include <deque>
using namespace std;
struct Pos { int x, y; };
enum Dir { UP, DOWN, LEFT, RIGHT };
class Snake {
deque<Pos> body;
Dir dir = RIGHT;
public:
Snake() { body.push_back({5, 5}); body.push_back({4, 5}); body.push_back({3, 5}); }
Pos head() const { return body.front(); }
void setDir(Dir d) {
if ((d == UP && dir != DOWN) || (d == DOWN && dir != UP) ||
(d == LEFT && dir != RIGHT) || (d == RIGHT && dir != LEFT)) dir = d;
}
void move(bool grow) {
Pos h = head(), n = h;
if (dir == UP) n.y--;
else if (dir == DOWN) n.y++;
else if (dir == LEFT) n.x--;
else n.x++;
body.push_front(n);
if (!grow) body.pop_back();
}
bool hits(const Pos &p) const {
for (auto &s : body) if (s.x == p.x && s.y == p.y) return true;
return false;
}
};
2. 食物与主循环
食物随机生成,避开蛇身。每步:读方向键 → 判断是否吃到食物 → 移动 → 检查撞墙/撞自己:
const int W = 20, H = 12;
Snake snake;
Pos food;
int score = 0;
void place_food() {
do { food = {rand() % W, rand() % H}; }
while (snake.hits(food));
}
int main() {
srand((unsigned)time(NULL));
place_food();
char key;
while (true) {
// 绘制 + 读键 + 移动 + 判定(见完整代码)
Pos nh = snake.head();
if (nh.x < 0 || nh.x >= W || nh.y < 0 || nh.y >= H) { cout << "撞墙!\n"; break; }
}
}
3. 完整代码
#include <iostream>
#include <deque>
#include <cstdlib>
#include <ctime>
using namespace std;
struct Pos { int x, y; };
enum Dir { UP, DOWN, LEFT, RIGHT };
class Snake {
deque<Pos> body;
Dir dir = RIGHT;
public:
Snake() { body.push_back({5, 5}); body.push_back({4, 5}); body.push_back({3, 5}); }
Pos head() const { return body.front(); }
void setDir(Dir d) {
if ((d == UP && dir != DOWN) || (d == DOWN && dir != UP) ||
(d == LEFT && dir != RIGHT) || (d == RIGHT && dir != LEFT)) dir = d;
}
void move(bool grow) {
Pos h = head(), n = h;
if (dir == UP) n.y--;
else if (dir == DOWN) n.y++;
else if (dir == LEFT) n.x--;
else n.x++;
body.push_front(n);
if (!grow) body.pop_back();
}
bool hits(const Pos &p) const {
for (auto &s : body) if (s.x == p.x && s.y == p.y) return true;
return false;
}
int len() const { return (int)body.size(); }
};
const int W = 20, H = 12;
Snake snake;
Pos food;
int score = 0;
void place_food() {
do { food = {rand() % W, rand() % H}; }
while (snake.hits(food));
}
void draw() {
system("clear"); // Windows: system("cls")
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
Pos p = {x, y};
if (p.x == food.x && p.y == food.y) cout << "F";
else if (snake.hits(p)) cout << "S";
else cout << ".";
}
cout << "\n";
}
cout << "分数 " << score << " wasd移动 q退出\n";
}
int main() {
srand((unsigned)time(NULL));
place_food();
char key;
while (true) {
draw();
cin >> key;
if (key == 'q') break;
if (key == 'w') snake.setDir(UP);
else if (key == 's') snake.setDir(DOWN);
else if (key == 'a') snake.setDir(LEFT);
else if (key == 'd') snake.setDir(RIGHT);
Pos h = snake.head();
bool grow = false;
snake.move(grow);
Pos nh = snake.head();
if (nh.x < 0 || nh.x >= W || nh.y < 0 || nh.y >= H) { cout << "撞墙,游戏结束\n"; break; }
if (snake.hits(nh) && !(nh.x == h.x && nh.y == h.y) && snake.len() > 1) {
cout << "咬到自己,游戏结束\n"; break;
}
if (nh.x == food.x && nh.y == food.y) {
snake.move(true); // 变长
score += 10;
place_food();
}
}
return 0;
}
4. 运行与常见问题
保存为 snake.cpp,g++ snake.cpp -o snake 后运行。常见问题:①吃食物没变长——先判断是否吃到,再 move(true) 补一次;②不能掉头——方向锁在 setDir 里判断;③自撞误判——新头与旧头重合时不算撞。
💡 改进方向:①自动下落(非阻塞输入);②障碍物关卡;③最高分存档;④穿墙模式;⑤道具。