From 7640122fb0a55d190346e956775d02ce6e92bd39 Mon Sep 17 00:00:00 2001 From: Bill-77 Date: Sun, 13 Jul 2025 22:10:16 +0800 Subject: [PATCH 1/3] Create snake_std_with_cmt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为std版本添加注释详细,解释每行代码的实现,便于新手学习 --- GluttonousSnake/snake_std_with_cmt | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 GluttonousSnake/snake_std_with_cmt diff --git a/GluttonousSnake/snake_std_with_cmt b/GluttonousSnake/snake_std_with_cmt new file mode 100644 index 0000000..6e43fb2 --- /dev/null +++ b/GluttonousSnake/snake_std_with_cmt @@ -0,0 +1,38 @@ +#include // 引入conio.h库,用于控制台输入输出(如键盘检测和清屏) +#include +#include // 引入stdlib.h库,用于随机数生成和系统命令(如rand、system) +#include +#pragma warning(disable : 4996) // 禁用4996号警告,允许使用如_getch等被认为已弃用的函数 +#define W 30 // 定义游戏网格宽度为28 +#define H W // 定义游戏网格高度等于宽度(28) +#define S (W * H) // 定义网格总格子数(28 * 28 = 784) +int main() { + char o[S * 2 + W + 1], *c = o; // 定义显示缓冲区o(每个格子占2字符,W中行每行加换行符,再加终止符),c为指向缓冲区的指针 + int m[S + 1], q[S], l = 0, r = 4, d = 1, p, a, i; // m:一维数组(其实用二维数组更方便)标识地图格子状态(0=空,1=蛇身/墙),q:蛇身数组(预留蛇覆盖整个地图的空间),l:蛇尾尾索引,r:蛇头索引,d:方向(1=右),p:蛇头位置,a:苹果位置,i:循环变量 + for (i = l; i <= r; ++i) q[i] = S; // 初始化蛇身队列前5个元素为无效位置S(900),表示初始蛇长5 + for (i = 0; i < S; c += 2, ++i % W || (*c++ = '\n')) { // 循环遍历900个格子,初始化显示缓冲区和地图 + m[i] = !(i / W % (H - 1) && i % W % (W - 1)); // 设置地图数组状态m:边界(首行、末行、首列、末列)为1(墙),内部为0(空);具体逻辑:i / W 计算行号,i % W 计算列号。i / W % (H - 1) 检查是否为首行(0)或末行(29):行号除以29取余,若为0(行0或29),则为边界。i % W % (W - 1) 检查是否为首列(0)或末列(29):列号除以29取余,若为0,则为边界。 + m[i] ? (*c = '[', c[1] = ']') : (*c = c[1] = ' '); // 根据m[i]设置显示字符:墙为"[]",空为" " + } + p = W / 2 * (H + 1) - d, a = p + d, c[-1] = '\0'; // 设置蛇头位置p(第15行,第14列,接近中心),苹果位置a,缓冲区以空字符终止 + for (srand((unsigned)time(0)); i = 1; _sleep(100)) { // 使用当前时间初始化随机种子,进入帧率为10的主循环(每次循环画一次图即一帧(帧率也体现为速度)),这里开始i用于读入键盘输入(节约行数写在for里面) + if (_kbhit() && (i = _getch() & 95)) { // 检查键盘输入,获取输入字符并转为大写(A=65,D=68,W=87,S=83) + if (i == 'A' && d != 1) d = -1; // 按A且当前方向非右(禁止180度掉头),设置方向为左(-1) + else if (i == 'D' && d != -1) d = 1; // 按D且当前方向非左,设置方向为右(1) + else if (i == 'W' && d != W) d = -W; // 按W且当前方向非下,设置方向为上(-W) + else if (i == 'S' && d != -W) d = W; // 按S且当前方向非上,设置方向为下(W) + } + if (m[p += d] && p != q[l + 1] || i == 27) break; // 移动蛇头(p += d,这样是为了减少行数写在里面),若撞墙或蛇身(m[p]=1且非苹果)或按ESC(27),退出循环 + if (p == a) { // 若蛇头到达苹果位置 + for (a = rand() % S; m[a]; a = (a + 1) % S) {} // 一直随机生成新苹果位置,知道确保在空闲格子(m[a]=0)生成 + *(c = o + a * 2 + a / W) = '0', c[1] = '0'; // 在新苹果位置显示"00" + } else { // 若未吃到苹果 + m[i = q[l = (l + 1) % S]] = 0; // 清除蛇尾位置(m[i]=0),更新队列尾索引l,因为这一帧结束时蛇尾一定不在当前位置了,而蛇身不动 + *(c = o + i * 2 + i / W) = ' ', c[1] = ' '; // 在蛇尾位置显示空白" " + } + m[q[r] = p] = 1, r = (r + 1) % S; // 另外蛇头会更新位置,将新蛇头位置加入队列,标记地图m为1,更新队列头索引r + *(c = o + p * 2 + p / W) = '(', c[1] = ')'; // 在蛇头位置显示"()" + system("cls"), printf(o); // 清屏并打印整个游戏画面 + } + printf("\nGame over!\n"); // 游戏结束,打印提示信息 +} From 3b6ec8c9eeb7a5feeff176b72d86d20346e25fe0 Mon Sep 17 00:00:00 2001 From: Bill-77 Date: Sun, 13 Jul 2025 22:12:37 +0800 Subject: [PATCH 2/3] Create snake_std_fluent.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 解决缓冲区刷新鼠标乱飞的卡顿问题 --- GluttonousSnake/snake_std_fluent.c | 60 ++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 GluttonousSnake/snake_std_fluent.c diff --git a/GluttonousSnake/snake_std_fluent.c b/GluttonousSnake/snake_std_fluent.c new file mode 100644 index 0000000..9908183 --- /dev/null +++ b/GluttonousSnake/snake_std_fluent.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#pragma warning(disable : 4996) +#define W 28 +#define H W +#define S (W * H) + +void set_cursor(int x, int y) { + COORD pos = { (short)x, (short)y }; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); +} + +void print_at(int r, int c, const char *ch) { + set_cursor(c * 2, r); + printf("%s", ch); +} + +int main() { + char o[S * 2 + W + 3], *c = o; + int m[S + 1], q[S], l = 0, r = 4, d = 1, p, a, i; + for (i = l; i <= r; ++i) q[i] = S; + for (i = 0; i < S; c += 2, ++i % W || (*c++ = '\n')) { + m[i] = !(i / W % (H - 1) && i % W % (W - 1)); + m[i] ? (*c = '[', c[1] = ']') : (*c = c[1] = ' '); + } + p = W / 2 * (H + 1) - d, a = p + d, o[S * 2 + W + 2] = '\0'; + system("cls"); + printf("%s", o); + print_at(a / W, a % W, "00"); + for (srand((unsigned)time(0)); i = 1; _sleep(100)) { + if (_kbhit() && (i = _getch() & 95)) { + if (i == 'A' && d != 1) d = -1; + else if (i == 'D' && d != -1) d = 1; + else if (i == 'W' && d != W) d = -W; + else if (i == 'S' && d != -W) d = W; + } + int t = p; + p += d; + if (m[p] && p != q[l + 1] || i == 27) { + printf("Game over!\n"); + _sleep(1000); + break; + } + if (p == a) { + for (a = rand() % S; m[a]; a = (a + 1) % S) {} + print_at(a / W, a % W, "00"); + *(c = o + a * 2 + a / W) = '0', c[1] = '0'; + } else { + m[i = q[l = (l + 1) % S]] = 0; + print_at(i / W, i % W, " "); + *(c = o + i * 2 + i / W) = ' ', c[1] = ' '; + } + m[q[r] = p] = 1, r = (r + 1) % S; + print_at(p / W, p % W, "()"); + *(c = o + p * 2 + p / W) = '(', c[1] = ')'; + } +} From fa38f4085eb357e1a9b18ad121d1f4d203bb3ad3 Mon Sep 17 00:00:00 2001 From: Bill-77 Date: Sun, 13 Jul 2025 22:13:30 +0800 Subject: [PATCH 3/3] Rename snake_std_with_cmt to snake_std_with_cmt.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为std版本添加注释详细,解释每行代码的实现,便于新手学习 --- GluttonousSnake/{snake_std_with_cmt => snake_std_with_cmt.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename GluttonousSnake/{snake_std_with_cmt => snake_std_with_cmt.c} (100%) diff --git a/GluttonousSnake/snake_std_with_cmt b/GluttonousSnake/snake_std_with_cmt.c similarity index 100% rename from GluttonousSnake/snake_std_with_cmt rename to GluttonousSnake/snake_std_with_cmt.c