专栏首页LINUX阅码场80行C代码实现ncurses版贪吃蛇!

80行C代码实现ncurses版贪吃蛇!

事情是这样的,周末我在家打开电脑排查现网问题,安德森先生对这个电脑非常感兴趣,凑过来非要看看,我给他演示了sl小火车。小小和疯子也都在旁边看着。

我说这个sl小火车是一个现成的程序,然后就被小小和疯子鄙视了,她们以为这个小火车是我自己做的…搞了半天是下载的现成的东西…

我觉得我得自己做点可以玩的小东西,哪怕再简单的,只要看起来像回事就行,以挽回面子。

还是贪吃蛇最简单,这个东西以前我写过不止一版了: https://blog.csdn.net/dog250/article/details/5303351 https://blog.csdn.net/dog250/article/details/6787135 https://blog.csdn.net/dog250/article/details/6819996

不过代码都挺长的。这次我想来个简约风格的朴素版本,这次我用ncurses来实现,代码如下:

#include <ncurses.h>
#include <stdlib.h>
#include <string.h>

#define  LINES  30
#define  COLS  60

int start_x = 10, start_y = 10;
int main(int argc,char* argv[])
{
  int i, j, c, head_x, head_y, tail_x, tail_y, fx, fy;
  // 四个方向矩阵
  char dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
  int head_dir_index = 3, tail_dir_index = 3;
  char pad[LINES][COLS];

  initscr();
  noecho();
  keypad(stdscr, 1);
  nodelay(stdscr, 1);
  curs_set(0);

  memset(pad, 0, sizeof(pad));
  pad[start_y][start_x] = 1;
  head_x = tail_x = start_x;
  head_y = tail_y = start_y;
  srand(time(NULL));

  for (i = 0; i < LINES; i ++) {
    pad[i][0] = 1;
    pad[i][COLS - 1] = 1;
  }
  for (i = 0; i < COLS; i ++) {
    pad[0][i] = 1;
    pad[LINES - 1][i] = 1;
  }

  while (1) { // 外层循环表示一次吞食
    fx = rand()%COLS;
    fy = rand()%LINES;
    if (pad[fy][fx] == 1)
      continue;
    pad[fy][fx] = 2;

    while (c = getch()) { // 内层循环描绘吞食的过程
      // 获取蛇头的方向
      if (c == KEY_UP)
        head_dir_index = 0;
      else if (c == KEY_DOWN)
        head_dir_index = 1;
      else if (c == KEY_LEFT)
        head_dir_index = 2;
      else if (c == KEY_RIGHT)
        head_dir_index = 3;
      // 计算蛇头的位置
      head_y += dir[head_dir_index][0];
      head_x += dir[head_dir_index][1];
      if (head_y >= LINES - 1 || head_x >= COLS - 1 || head_x <= 0 || head_y <= 0 ||
        pad[head_y][head_x] == 1) {
        mvprintw(LINES/2, (COLS - 9)/2, "game over");
        refresh();
        sleep(2);
        endwin();
        exit(1);
      }
      // 吃到了食物
      if (pad[head_y][head_x] == 2) {
        pad[head_y][head_x] = 1;
        break;
      }
      pad[head_y][head_x] = 1; // 蛇头前进
      pad[tail_y][tail_x] = 0; // 蛇尾锁进

      // 获取蛇尾的方向
      if (tail_y - 1 > 0 && pad[tail_y - 1][tail_x] == 1)
        tail_dir_index = 0;
      else if (tail_y + 1 < LINES - 1 && pad[tail_y + 1][tail_x] == 1)
        tail_dir_index = 1;
      else if (tail_x - 1 > 0 && pad[tail_y][tail_x - 1] == 1)
        tail_dir_index = 2;
      else if (tail_x + 1 < COLS -1 && pad[tail_y][tail_x + 1] == 1)
        tail_dir_index = 3;
      // 计算蛇尾的位置
      tail_y += dir[tail_dir_index][0];
      tail_x += dir[tail_dir_index][1];
      // 绘制整蛇
      for (i = 0; i < LINES; i ++)
        for (j = 0; j < COLS; j ++)
          mvprintw(i, j, pad[i][j]?"#":" ");
      refresh();
      usleep(200000);
    }
  }

  return 0;
}

代码在:https://github.com/marywangran/GluttonousSnake

我喜欢这个风格,因为它只需要gcc和libncurses就能编译和执行,完全不依赖任何GUI:

[root@localhost test]# gcc test.c -lncurses

效果如下:

代码思路很简单,就是 把蛇尾拿开拼到蛇头前面 以模拟蛇移动,那么问题就剩下两个:

  • 如何知道蛇尾在哪里?
  • 如何知道蛇头在哪里?

于是我维护了两个方向:

  • 蛇头方向:取决于上一次按下的方向键。
  • 蛇尾方向:取决于蛇的连接矩阵。

非常简单的思路,没有链表,没有对象,什么都没有,简约,而且非常经理。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/dog250/article/details/107620992

本文分享自微信公众号 - Linux阅码场(LinuxDev),作者:dog250

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Linux实时补丁即将合并进Linux 5.3

    所谓实时,就是一个特定任务的执行时间必须是确定的,可预测的,并且在任何情况下都能保证任务的时限(最大执行时间限制)。实时又分软实时和硬实时,所谓软实时,就是对任...

    Linux阅码场
  • 黄东升: inotify学习笔记

    inotify是Linux中用于监控文件系统变化的一个框架,不同于前一个框架dnotify, inotify可以实现基于inode的文件监控。也就是说监...

    Linux阅码场
  • 从猫蛇之战看内核戏CPU

    小时候曾经目睹过猫与蛇战斗,面对昂首发威的毒蛇,小猫不慌不忙,挥舞前爪,沉着冷静,看准时机进攻,胆大心细。

    Linux阅码场
  • 当Kotlin遇见数据结构丨实现链式存储的二叉树中查找节点

    链式存储的二叉树中查找节点的方法可分为三种:前序查找、中序查找、后序查找,下面使用 Kotlin 语言编码实现查找函数,已创建的树结构、节点权如下图所示:

    码脑
  • 高分辨率256*256人脸生成效果介绍及代码

    众所周知,训练GAN非常困难. In order to train at 256 x 256 we utilize:

    用户1908973
  • JSP总结三(JSTL核心标签库的使用)

    爱撒谎的男孩
  • delete的奇怪行为

    F的实例拥有一个value属性,但不希望在new的时候就初始化属性值(因为这个值不一定用得到,而且计算成本比较高,或者new的时候还不一定能算出来),那么自然想...

    ayqy贾杰
  • 计算机网络自学笔记:多路复用与多路分解

    本文讨论传输层的多路复用与多路分解,也就是将网络层所提供的主机到主机交付服务扩展到为在主机上运行的应用程序所提供的进程到进程交付服务。

    云时之间
  • 微生物领域名言(5)物种的稀有性

    ‘rarity is the attribute of a vast number of species of all classes, in all coun...

    生物信息知识分享
  • Java基础--static关键字

    不管是平时阅读源代码,还是笔试、面试中,static关键字还是经常被问道,这篇文章主要来重新复习一下该关键字。

    河岸飞流

扫码关注云+社区

领取腾讯云代金券