百科问答小站 logo
百科问答小站 font logo



用C语言,能在100行之内实现贪吃蛇吗? 第1页

  

user avatar   dm2-91 网友的相关建议: 
      

这段代码会发生内存泄漏,特此备注。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

没学到一个小小的贪吃蛇会有怎么多赞,当时想能有100个赞已经很不错了,这个完全超出我的预期啊,啊啊啊~飘了飘了~

小声bb:其实这个代码写得不咋地,有些函数为了能用 return 语句,故意写了一个返回值,但是返回值没有用到,还有就是 Run 这个函数本来不应该接受一个参数,但是为了省一行的代码,把init写进去,才出此下策。这样写的后果就是代码不符合我的预期,不这样写的话又不符合题主的要求,两难啊。所以我才会比较郁闷,说了点脏话,实在抱歉 。(可能自己水平不够,代码还有很多优化空间,我看别的答主根本就用不到100行)

继续努力吧 ~

~~~~~~~~~~~~原答案~~~~~~~~~~~

我本来怀着很好的心情来写这个100的贪吃蛇的,不过写到后面就出口成脏了。

mmp,写到后面很是郁闷。有图为证。

刚刚好一百行代码,我去,这是那我之前写的350多行代码压缩的得到的。

写得很垃圾,有些东西就是乱写一通,就为了压缩一两行逻辑代码。

然后UI部分,这个也没办法压缩,能压缩的都在核心代码上面了。

尽量体现出来格式,但是难受啊

贪吃蛇的核心代码就在这个switch里面了,10行。也就是占比 1/10。其实还可以...

最后的效果图是这个


直接贴代码吧。

       #include <Windows.h> #include <stdio.h> #include <conio.h> #include <time.h> #define PANIC(err) (fprintf(stderr,"PANIC Line %d : %s",__LINE__,err),exit(-1),1) #define PANICIFNULL(EXP) ((EXP)==NULL && PANIC("NULL")) typedef enum { EMPTY=0, WALL, BODY, FOOD } MAP; typedef int POSITION; struct { int color; const char* shape; } UI[] = {  {2,"■"},{4,"□"},{6,"★"},{4,"●"} }; struct {  int WIDTH, HEIGHT, direction, delay;  MAP* map;  POSITION* body, head, tail, len; } C; void initConsole(int width, int height) {  char cmd[100];  sprintf_s(cmd,100, "mode con cols=%d lines=%d && title C语言贪吃蛇 By dreamer2q %s", width, height,__DATE__);  system(cmd);  HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);  CONSOLE_CURSOR_INFO cur_info;  GetConsoleCursorInfo(handle, &cur_info);  cur_info.bVisible = FALSE;  SetConsoleCursorInfo(handle, &cur_info); } void updatePosition(POSITION pos) {  HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);  COORD coord = { (pos % (C.WIDTH)) * 2 ,pos / (C.WIDTH) };  SetConsoleCursorPosition(handle, coord);  SetConsoleTextAttribute(handle, UI[C.map[pos]].color);  printf("%s", UI[C.map[pos]].shape); } MAP food(int t) {  POSITION pos = (rand() % ((C.WIDTH - 2) * (C.HEIGHT - 2))) + C.WIDTH + 1;  if (C.map[pos]) return food(t);  else return  (C.map[pos] = FOOD) ? updatePosition(pos), BODY : BODY; } int init() {  C.WIDTH = C.HEIGHT = 30;  initConsole(C.WIDTH * 2, C.HEIGHT);  PANICIFNULL(C.map = (MAP*)malloc((C.WIDTH) * (C.HEIGHT) * sizeof(MAP)));  PANICIFNULL(C.body = (POSITION*)malloc(C.WIDTH * C.HEIGHT * sizeof(POSITION)));  C.head = (C.len = 3) - 1;  C.direction = (C.tail = 0) + 1;  C.delay = -150;  memset(C.map, EMPTY, (C.WIDTH) * (C.HEIGHT) * sizeof(MAP));  for (int i = 0; i < (C.WIDTH) * (C.HEIGHT); i++) {   i < C.WIDTH && (C.map[i] = C.map[C.WIDTH * (C.HEIGHT - 1) + i] = WALL);   i < C.HEIGHT && (C.map[C.WIDTH * i] = C.map[C.WIDTH * i + C.WIDTH - 1] = WALL);   i < C.len && (C.map[C.body[i] = C.WIDTH * C.HEIGHT / 2 + C.WIDTH / 2 - 1 + i] = BODY);   updatePosition(i);  }  srand(time(NULL));  return food(0); } int Run(int shit) {  int prv = 77;  while (1) {   if (_kbhit()) {    int t = _getch();    if ((prv + t) == 152)continue;    switch (t) {    case 72:C.direction = -C.WIDTH; break;    case 80:C.direction = C.WIDTH; break;    case 75:C.direction = -1; break;    case 77:C.direction = 1; break;    case ' ':C.delay = -C.delay; break;    default:continue;    }    prv = t;   } #define INC(p) (((p)+1)%(C.WIDTH*C.HEIGHT))   if (C.delay > 0) Sleep(C.delay);   else continue;   switch (C.map[C.body[INC(C.head)] = C.body[C.head] + C.direction]) {   case FOOD:food(C.len = -C.len - 1);   case EMPTY:    C.map[C.body[C.head = INC(C.head)]] = BODY;    updatePosition(C.body[C.head]);    if (C.len > 0) updatePosition((C.map[C.body[C.tail]] = EMPTY) ? BODY : C.body[C.tail]), C.tail = INC(C.tail);    else C.len = -C.len;    break;   case WALL:case BODY:    return -1;//dead   }  } } int main() {  while (1) {   initConsole(25, 10);   printf("
	C语言贪吃蛇

    1. 开始游戏
    2. 关于
    q. 退出
%");   switch (_getch()) {   case 'q':return 0;   case '2':MessageBoxA(GetConsoleWindow(), "100行代码?", "有病吧你?", MB_OK|MB_ICONASTERISK); continue;   case '1':Run(init());    MessageBoxA(GetConsoleWindow(), "你死了。有病去看看吧", "SHIT", MB_OK | MB_ICONERROR);   }  } }     


觉得还行就thumbup,写代码也不容易


user avatar    网友的相关建议: 
      

UPD 20191229

重写了一个C89兼容的…大概吧…

总之在VC6下能跑起来了(对stdafx.h的依赖不会去除不是我的问题哦)…

然后…诸位…

快换一个完整支持C99的编译器吧!!!

不过代码又变脏了好多…对不起我已经不纯洁了嘤嘤嘤…

恰好100,如下

       #include <Windows.h> #define MAX_WIDTH (30) #define MAX_HEIGHT (30) #define MAX_SIZE (MAX_WIDTH*MAX_HEIGHT) #define inc(x) (x=(x+1)%MAX_SIZE) #define cmppos(left, right) (left.X == right.X && left.Y == right.Y) #define isborder(pos) (pos.X >= MAX_WIDTH+1 || pos.X <= 0 || pos.Y >= MAX_HEIGHT+1 || pos.Y <= 0) COORD snake[MAX_SIZE] = { {MAX_WIDTH / 2,MAX_HEIGHT / 2} }; COORD food = { MAX_WIDTH + 1, MAX_HEIGHT + 1 }, head = { MAX_WIDTH / 2, MAX_HEIGHT / 2 }; unsigned int QueueHead = 1, QueueTail = 0, movement = 2; const signed int MoveHints[4] = { 0 + 1 * 3,1 + 0 * 3,2 + 1 * 3,1 + 2 * 3 }; DWORD retdword; int IsSnake(COORD chk) {  unsigned int ptr = QueueTail;  while (ptr != QueueHead)  {   if (cmppos(snake[ptr], chk) == 1)    return 1;   inc(ptr);  }  return cmppos(snake[ptr], chk); } void genfood() {  do  {   food.X = rand() % MAX_WIDTH + 1;   food.Y = rand() % MAX_HEIGHT + 1;  }  while (IsSnake(food));  WriteConsoleOutputCharacterA(GetStdHandle(STD_OUTPUT_HANDLE), "o", 1, food, &retdword); } void cls(int mode) {  COORD pos={0,0};  for(pos.X=0;pos.X<MAX_WIDTH+2;pos.X++)   for(pos.Y=0;pos.Y<MAX_HEIGHT+2;pos.Y++)    if((mode==1) && isborder(pos))     WriteConsoleOutputCharacterA(GetStdHandle(STD_OUTPUT_HANDLE), "#", 1, pos, &retdword);    else     WriteConsoleOutputCharacterA(GetStdHandle(STD_OUTPUT_HANDLE), " ", 1, pos, &retdword); } void go(COORD pos) {  if (isborder(pos) || IsSnake(pos))  {   char tmp[256];   cls(0);   COORD pos = { 0, 0 };   wsprintfA(tmp, "Die! Total Score:%d", (QueueHead + MAX_SIZE - QueueTail) % MAX_SIZE);   WriteConsoleOutputCharacterA(GetStdHandle(STD_OUTPUT_HANDLE), tmp, strlen(tmp), pos, &retdword);   Sleep(3000);   exit(0);  }  snake[QueueHead] = pos;  inc(QueueHead);  WriteConsoleOutputCharacterA(GetStdHandle(STD_OUTPUT_HANDLE), "x", 1, pos, &retdword); } void removetail() {  WriteConsoleOutputCharacterA(GetStdHandle(STD_OUTPUT_HANDLE), " ", 1, snake[QueueTail], &retdword);  inc(QueueTail); } void ChkKey() {  while (1)  {   INPUT_RECORD ir;   PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &retdword);   if (retdword == 0)    break;   ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &retdword);   if (ir.EventType != KEY_EVENT || !ir.Event.KeyEvent.bKeyDown || ir.Event.KeyEvent.wVirtualKeyCode<VK_LEFT || ir.Event.KeyEvent.wVirtualKeyCode>VK_DOWN)    continue;   if ((((ir.Event.KeyEvent.wVirtualKeyCode - VK_LEFT) ^ movement) & 1) == 0)    continue;   movement = ir.Event.KeyEvent.wVirtualKeyCode - VK_LEFT;  } } int main() {  if (FALSE == GetStdHandle(STD_OUTPUT_HANDLE))   AllocConsole();  SMALL_RECT rect = { 0,0,MAX_WIDTH + 1,MAX_HEIGHT + 1 };  SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &rect);  SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),food);  srand(GetTickCount());  cls(1);  genfood();  while (1)  {   ChkKey();   head.X += (SHORT)(MoveHints[movement] % 3 - 1);   head.Y += (SHORT)(MoveHints[movement] / 3 - 1);   (cmppos(food, head)) ? genfood() : removetail();   go(head);   Sleep(500);  } }     

能…

试着写了一下…总之我的原则是尽量避免不规范表达,然后在100行内尽量保证可读性…

不过毕竟为了压到100行的话…写了点比较脏的东西…

如果发现这里有不规范的用法的话…请务必提醒我…多谢了…


       #include <stdio.h> #include <Windows.h> #define MAX_WIDTH (30) #define MAX_HEIGHT (30) #define MAX_SIZE (MAX_WIDTH*MAX_HEIGHT) typedef struct POS {  signed int x;  signed int y; }POS; const signed int MoveHints[4] = { 0+1*3,1+0*3,2+1*3,1+2*3 }; POS snake[MAX_SIZE] = { {MAX_WIDTH / 2,MAX_HEIGHT / 2} }, food; unsigned int QueueHead = 0, QueueTail = 0, movement = 2; void inc(unsigned int* pint) {  if (++(*pint) == MAX_SIZE)   *pint = 0; } #define cmppos(left, right) ((left.x == right.x && left.y == right.y) ? 1 : 0) int IsSnake(POS chk) {  unsigned int ptr = QueueTail;  while (ptr != QueueHead)  {   if (cmppos(snake[ptr], chk) == 1)    return 1;   inc(&ptr);  }  return cmppos(snake[ptr], chk); } void genfood() {  do  {   food.x = rand() % MAX_WIDTH;   food.y = rand() % MAX_HEIGHT;  }while (IsSnake(food));  printf("33[%d;%dHo33[%d;%dH", food.y,food.x,MAX_HEIGHT,MAX_WIDTH); } void cls(int mode) {  for (int i = 0; i <= MAX_HEIGHT; i++)   for (int j = 0; j <= MAX_WIDTH; j++)    if(mode==1 && (i==MAX_HEIGHT||j==MAX_WIDTH))     printf("33[%d;%dH#", i, j);    else     printf("33[%d;%dH ", i, j); } void go(POS p) {  if (p.x >= MAX_WIDTH || p.x <= 0 || p.y >= MAX_HEIGHT || p.y <= 0 || IsSnake(p))  {   cls(0);   printf("33[0;0HDIE!
Score:%d
",(QueueHead+MAX_SIZE-QueueTail)%MAX_SIZE);   exit(0);  }  inc(&QueueHead);  snake[QueueHead] = p;  printf("33[%d;%dHx33[%d;%dH", p.y, p.x,MAX_HEIGHT,MAX_WIDTH); } void removetail() {  printf("33[%d;%dH 33[%d;%dH", snake[QueueTail].y, snake[QueueTail].x,MAX_HEIGHT,MAX_WIDTH);  inc(&QueueTail); } void ChkKey() {  while (1)  {   INPUT_RECORD ir;   DWORD dw;   PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &dw);   if (dw==0)    break;   ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &dw);   if (ir.EventType != KEY_EVENT || !ir.Event.KeyEvent.bKeyDown || ir.Event.KeyEvent.wVirtualKeyCode<VK_LEFT || ir.Event.KeyEvent.wVirtualKeyCode>VK_DOWN)    continue;   if ((((ir.Event.KeyEvent.wVirtualKeyCode -VK_LEFT)^movement)&1)==0)    continue;   movement = ir.Event.KeyEvent.wVirtualKeyCode - VK_LEFT;  } } int main() {  srand(GetTickCount());  cls(1);  genfood();  while (1)  {   ChkKey();   POS t = (POS){    .x = snake[QueueHead].x + MoveHints[movement] % 3 - 1,    .y = snake[QueueHead].y + MoveHints[movement] / 3 - 1   };   go(t);   (cmppos(food, t)) ? genfood() : removetail();   Sleep(500);  } }     


user avatar   jing-wei-zhang-huai-39 网友的相关建议: 
      

问100行内能不能实现?那当然能实现,而且远远用不到100行。

写了一下,大概30行:

       #include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> #include <unistd.h> int main() {     char board[33][62];     strcpy(&board[0][0],"26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26
");     for(int i=1;i<30;i++) strcpy(&board[i][0],"26                                                           26
");     strcpy(&board[30][0],"26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26
w:up s:down a:left d:right
");     int snake_num=6,dir='a',snake[29*29]={16,30,16,32,16,34},food[2]={rand()%29+1,(rand()%29+1)*2};     for(int i=0;i<snake_num;i+=2) board[snake[i]][snake[i+1]]='26';     board[food[0]][food[1]]=1;     while(memmove(snake+2,snake,snake_num*sizeof(int)))     {         if(kbhit()) dir=getch();         snake[1]=snake[3]+((dir=='a')?-2:(dir=='d')?2:0);         snake[0]=snake[2]+((dir=='w')?-1:(dir=='s')?1:0);         if(board[snake[0]][snake[1]]==1)         {             snake_num+=2;             do{food[0]=rand()%29+1;food[1]=(rand()%29+1)*2;}while(board[food[0]][food[1]]!=' ');             board[food[0]][food[1]]=1;         }         else if(board[snake[0]][snake[1]]=='26') return printf("game over!
");         else board[snake[snake_num]][snake[snake_num+1]]=' ';         board[snake[0]][snake[1]]='26';         system("clear");         sprintf(((char *)board)+1949,"score: %d
",(snake_num-6)*50);         printf("%s",board);         usleep(((500-snake_num>200)?(500-snake_num):200)*1000);     } }     

效果:




  

相关话题

  C语言中后缀自加i++表达式的值到底是谁的值? 
  怎么看待 公办学院使用的部分c语言书籍存在 描述 main不可被其他函数调用但是实际操作 可以? 
  现在快2022年了,c++为什么还要实现(.cpp)和声明(.h)分开? 
  请问这段C++代码是未定义行为吗? 
  c语言遇到点小困难?想知道包含标准输入输出是什么意思? 
  同样用pow()表示10^2,为什么分别用字面量和变量作参数会返回不同的值? 
  个人或者小团队选择C语言还是c++? 
  在内存特定位置填数据后,placement new 是否完全等价与cast? 
  c语言如何用for语句求1+11+111+1111? 
  为何void类型指针不能解引用,却可以参与强制类型转换? 

前一个讨论
如何评价《王者荣耀》「绝悟」AI?
下一个讨论
计算机系如何写出优雅的实验报告?





© 2024-12-22 - tinynew.org. All Rights Reserved.
© 2024-12-22 - tinynew.org. 保留所有权利