注意,编译前源文件字符编码必须为GB2312/GBK。否则填充字符█
会出现异常。
编译时需要指定按C++11标准编译,为了支持结构体字面量的语法。
g++ -std=c++11 -o gluttonous-snake.exe ./source.cpp
代码
#include <cstdlib>
#include <conio.h>
#include <deque>
#include <iostream>
#include <time.h>
#include <windows.h>
//定义一次步进
typedef struct {
//是否纵向移动
bool virticle = false;
//移动步长
int offset = 0;
}Step;
//定义'成长礼包'类型
enum GiftType {
//礼物,增加长度
GIFT_GIFT = FOREGROUND_GREEN,
//陷阱,减少长度
GIFT_TRAP = FOREGROUND_GREEN | FOREGROUND_BLUE,
//利剑,直接死亡
GIFT_SWORD = FOREGROUND_RED
};
//定义移动区域。窗口宽度应为width的两倍,因为ansi字符宽度仅高度的1/2。
#define FACTORY_WIDTH 64
#define FACTORY_HEIGHT 36
//定义蛇身颜色
#define SNAKE_BODY_COLOR (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
using namespace std;
//控制台输出句柄
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//蛇身数据容器。
deque<COORD> snakeBody;
//死亡标记
bool dead = false;
//'成长礼包'
COORD gift, trap, sword;
//判定点是否在蛇身上
bool inSnake(COORD point) {
if (snakeBody.size() == 0)
return false;
deque<COORD>::iterator iter = snakeBody.begin();
while (iter != snakeBody.end()) {
if (point.X == (*iter).X && point.Y == (*iter).Y)
return true;
++iter;
}
return false;
}
//生成'成长礼包'
COORD createGift(GiftType color) {
//统计递归调用次数
static int count = 0;
++count;
COORD point;
srand(rand());
point.X = rand() % FACTORY_WIDTH * 2;
srand(rand());
point.Y = rand() % FACTORY_HEIGHT;
if (inSnake(point)) {
return createGift(color);
}
else {
SetConsoleCursorPosition(hOutput, point);
SetConsoleTextAttribute(hOutput, color);
cout << "█";
SetConsoleTextAttribute(hOutput, SNAKE_BODY_COLOR);
dead = count > 12 ? true : false;
count = 0;
return point;
}//连礼包都没地方放了,死了算了
}
//初始化
void init() {
system("cls");
snakeBody.clear();
srand(time(NULL));
snakeBody.push_front({ 0, 0 });
snakeBody.push_front({ 2, 0 });
snakeBody.push_front({ 4, 0 });
deque<COORD>::iterator iter = snakeBody.begin();
while (iter != snakeBody.end()) {
SetConsoleCursorPosition(hOutput, *iter);
cout << "█";
++iter;
}
sword = createGift(GIFT_SWORD);
trap = createGift(GIFT_TRAP);
gift = createGift(GIFT_GIFT);
}
//步进
void stepOnece(Step step) {
COORD head = snakeBody.front();
(step.virticle ? head.Y : head.X) += step.offset;
//死亡
if (inSnake(head)
|| snakeBody.size() == 0
|| (head.X == sword.X && head.Y == sword.Y)
|| head.X < 0 || head.X >= FACTORY_WIDTH * 2
|| head.Y < 0 || head.Y >= FACTORY_HEIGHT) {
dead = true;
return;
}
snakeBody.push_front(head);
SetConsoleCursorPosition(hOutput, head);
cout << "█";
int count;
if (head.X == trap.X && head.Y == trap.Y) {
count = 2;
trap = createGift(GIFT_TRAP);
}//陷阱,变短
else if (head.X == gift.X && head.Y == gift.Y) {
count = 0;
gift = createGift(GIFT_GIFT);
}//礼物,增长
else
count = 1;
for (int i = 0; i < count; i++) {
COORD back = snakeBody.back();
SetConsoleCursorPosition(hOutput, back);
printf(" ");
snakeBody.pop_back();
if (snakeBody.size() == 0) {
dead = true;
break;
}
}
}
//控制循环
void gameLoop() {
Step curStep = { false, 2 };
Step step = curStep;
while (!dead) {
for (int i = 0; i < 200; i++) {
Sleep(1);
if (!_kbhit())
continue;
char cmd;
bool breakdown = true;
cmd = _getch();
switch (cmd) {
case 'w':
step.virticle = true;
step.offset = -1;
break;
case 's':
step.virticle = true;
step.offset = 1;
break;
case 'a':
step.virticle = false;
step.offset = -2;
break;
case 'd':
step.virticle = false;
step.offset = 2;
break;
default:
breakdown = false;
break;
}
//禁止当前方向反方向步进
if (step.virticle == curStep.virticle && step.offset * curStep.offset < 0)
continue;
else
curStep = step;
if (breakdown)
break;
}
stepOnece(curStep);
}
}
int main() {
//设置缓冲区大小
SMALL_RECT rect = { 0, 0, 10, 10 };
SetConsoleWindowInfo(hOutput, true, &rect);
SetConsoleScreenBufferSize(hOutput, { FACTORY_WIDTH * 2, FACTORY_HEIGHT });
//设置窗口大小
rect = { 0, 0, FACTORY_WIDTH * 2 - 1, FACTORY_HEIGHT - 1 };
SetConsoleWindowInfo(hOutput, true, &rect);
//设置窗口样式
SetConsoleTextAttribute(hOutput, SNAKE_BODY_COLOR);
CONSOLE_CURSOR_INFO cursorInfo = { 1, false };
SetConsoleCursorInfo(hOutput, &cursorInfo);
//规则介绍
cout << "使用W、S、A、D控制方向,吃到绿色礼包长度增加,吃到黄色礼包时长度减短,"\
"吃到红色礼包直接死亡。您也可以按CTRL + C退出游戏。按任意键开始游戏。" << endl;
system("pause");
//开始游戏
while (true) {
init();
gameLoop();
system("cls");
SetConsoleCursorPosition(hOutput, { 0, 0 });
printf("You has dead! Retry? (y/n)");
char cmd;
cin >> cmd;
if (cmd != 'y')
break;
else
dead = false;
}
}