这段代码会发生内存泄漏,特此备注。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
没学到一个小小的贪吃蛇会有怎么多赞,当时想能有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,写代码也不容易
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("