用C挑战无准备写2048
程序员文章站
2023-02-25 11:09:44
下午在刷题过程中,忽然想写2048了,以弥补以前写的那个千多行的,所以简单思考了一下准备采取的数据结构就开始了,本以为一个小时能搞定,结果后面改bug还是多花了些时间。因为在医院,所以声音不敢太大,如果看,建议耳机+声音最大,可以考虑倍速。个人感觉用C写这些东西的意义在于,你去掉了一些花里胡哨的东西 ......
下午在刷题过程中,忽然想写2048了,以弥补以前写的那个千多行的,所以简单思考了一下准备采取的数据结构就开始了,本以为一个小时能搞定,结果后面改bug还是多花了些时间。因为在医院,所以声音不敢太大,如果看,建议耳机+声音最大,可以考虑倍速。个人感觉用c写这些东西的意义在于,你去掉了一些花里胡哨的东西,而真的用你的逻辑思考出了这个东西怎么写,并写出来了。乱花渐欲迷人眼,难的是坚守本心!明白学一个东西的意义,有时候比学习它更重要!嗯就这样。下面贴上代码和录制的视频链接。
//2019年3月16日 17:29:07 //2048 //1、地图数据结构 2、合并和移动? 3、判断胜负 #include<stdio.h> #include<stdlib.h> #include<windows.h> #include<conio.h> #include<time.h> #include<string.h> #define n 5//地图大小 #define m 13//table表的长度 #define winflag 11 char map[n][n];//地图 int table[m];//查表使用 void init(); void run(); void print(); int win(); void lose(); int islose(); int up(int *ischange); int down(int *ischange); int left(int *ischange); int right(int *ischange); void generator(int dir); void gotoxy(int x, int y); //将光标调整到(x,y)的位置 //光标隐藏 void hidecursor() ; //隐藏光标显示 int main(void) { srand((unsigned)time(null)); hidecursor(); init(); run(); return 0; } void generator(int dir) { //按下右,就按列扫,从左往右随机选一个数生成 //按下上,就按行扫,从下网上随机选一个数生成 // int begin; // int end; // int mul;//增量 // for(int i = begin;i != end;i += mul) // for(int i = 0;i < n;++i) // for(j = n-1;j >= 0;--j) int flag = 0; int i1 = -1,i2 = -1; if(dir == 1 || dir == 2) { int begin,end,mul; dir == 1?begin = 0,end = n,mul = 1:begin = n-1,end = -1,mul = -1; for(int i = 0;i < n;++i) for(int j = begin;j != end;j += mul) { //保证选一个数,然后其他的随机 if(map[i][j] == 0)//选到了一个数 { if(flag == 0)//之前没选到过 { i1 = i; i2 = j; flag = 1; } else { if(rand()%3 < 2) { i1 = i; i2 = j; } } } } } else if(dir == 3 || dir == 4) { int begin,end,mul; dir == 3?begin = 0,end = n,mul = 1:begin = n-1,end = -1,mul = -1; for(int j = begin;j != end;j += mul) for(int i = 0;i < n;++i) { //保证选一个数,然后其他的随机 if(map[i][j] == 0)//选到了一个数 { if(flag == 0)//之前没选到过 { i1 = i; i2 = j; flag = 1; } else { if(rand()%3 < 2) { i1 = i; i2 = j; } } } } } if(i1 == i2 && i2 == -1) return; map[i1][i2] = 1; } int up(int *ischange) { //往上,所以是从上往下扫描 //一列一列的算 for(int j = 0;j < n;++j) { int k = 0; for(int i = 1;i < n;++i) { if(map[i][j] != 0)//当前处理的这一位是有数字的 { //只要是非0,且没有合并,则相加 //这里保证map[i][j]是有数字的 if(map[i][j] == map[k][j]) { //与那个数字进行交互。合并操作 map[k][j] += 1; map[i][j] = 0; if(map[k][j] == 12) return 5; *ischange = 1; } else if(map[k][j] == 0)//我们是说k是第一个非零的,但初始的时候我们为了好运算,是没做判断的 { //把当前位置上的数移过去 特判的移动操作 map[k][j] = map[i][j]; map[i][j] = 0; *ischange = 1; } else if(k+1 != i)//移动操作 { map[k+1][j] = map[i][j];//2 0 0 4 2 4 0 0 map[i][j] = 0;//4 2 0 0 ++k; *ischange = 1; } else//没有合并,且不是特判的 ++k; } } } return 1; } int down(int *ischange) { for(int j = 0;j < n;++j) { int k = n-1; for(int i = n-2;i >= 0;--i) { if(map[i][j] != 0)//当前处理的这一位是有数字的 { //只要是非0,且没有合并,则相加 //这里保证map[i][j]是有数字的 if(map[i][j] == map[k][j]) { //与那个数字进行交互。合并操作 map[k][j] += 1; map[i][j] = 0; if(map[k][j] == 12) return 5; *ischange = 1; } else if(map[k][j] == 0)//我们是说k是第一个非零的,但初始的时候我们为了好运算,是没做判断的 { //把当前位置上的数移过去 特判的移动操作 map[k][j] = map[i][j]; map[i][j] = 0; *ischange = 1; } else if(k-1 != i)//移动操作 { map[k-1][j] = map[i][j];//2 0 0 4 2 4 0 0 map[i][j] = 0;//4 2 0 0 --k; *ischange = 1; } else//没有合并,且不是特判的 --k; } } } return 2; } int left(int *ischange) { //合并?什么情况下合并?什么情况下移动? //一行一行处理 //从左往右处理 //这个有数字,我们才需要处理,没数字不用管 2 0 4 8 2 4 0 8 2 4 8 0 for(int i = 0;i < n;++i) { int k = 0; for(int j = 1;j < n;++j) { if(map[i][j] != 0)//当前处理的这一位是有数字的 { //这里保证map[i][j]是有数字的 if(map[i][j] == map[i][k]) { //与那个数字进行交互。合并操作 map[i][k] += 1; map[i][j] = 0; if(map[i][k] == 12) return 5; *ischange = 1; } else if(map[i][k] == 0)//我们是说k是第一个非零的,但初始的时候我们为了好运算,是没做判断的 { //把当前位置上的数移过去 特判的移动操作 map[i][k] = map[i][j]; map[i][j] = 0; *ischange = 1; } else if(k+1 != j)//移动操作 { map[i][k+1] = map[i][j];//2 0 0 4 2 4 0 0 map[i][j] = 0;//4 2 0 0 ++k; *ischange = 1; } else ++k; } } } return 3; } int right(int *ischange) { //从右至左 for(int i = 0;i < n;++i) { int k = n-1; for(int j = n-2;j >= 0;--j) { if(map[i][j] != 0)//当前处理的这一位是有数字的 { //这里保证map[i][j]是有数字的 if(map[i][j] == map[i][k]) { //与那个数字进行交互。合并操作 map[i][k] += 1; map[i][j] = 0; if(map[i][k] == 12) return 5; *ischange = 1; } else if(map[i][k] == 0)//我们是说k是第一个非零的,但初始的时候我们为了好运算,是没做判断的 { map[i][k] = map[i][j]; map[i][j] = 0; *ischange = 1; } else if(k-1 != j)//移动操作 { map[i][k-1] = map[i][j]; map[i][j] = 0; --k; *ischange = 1; } else --k; } } } return 4; } void init() { int n = 16;//随机地图的数目 //先求table table[0] = 1; for(int i = 1;i < m;++i) table[i] = table[i-1]<<1;//等同于*2 // for(int i = 0;i < m;++i) // printf("%5d",table[i]); //及时测试,验证正确性,免得日后找bug麻烦 //随机地图 随机生成3个2? memset(map,0,sizeof(map)); for(int i = 0;i < n;++i) { int i1 = rand()%n; int i2 = rand()%n; //随机一组下标,让地图那个位置变成1 map[i1][i2] = 1; //这个1代表2的一次,最终展现的是2 } } void run() { int ischange = 0;//检测是否发生了变化 int flag = 0; while(1) { print(); ischange = 0; switch(getch()) { case 'w':flag = up(&ischange);break; case 's':flag = down(&ischange);break; case 'a':flag = left(&ischange);break; case 'd':flag = right(&ischange);break; } if(flag != 5 && ischange) generator(flag); if(flag == 5) { win(); break; } else if(islose()) { print(); lose(); break; } } } void print() { gotoxy(0,0); for(int i = 0;i < n;++i) { for(int j = 0;j < n;++j) if(map[i][j] != 0) printf("%3d ",table[map[i][j]]); else printf(" "); putchar('\n'); } } int win() { printf("you are winner!\n"); } void lose() { printf("you are loser!\n"); } int islose() { //判断是否还具备可操作空间 for(int i = 0;i < n;++i) for(int j = 0;j < n-1;++j) { if(map[i][j] == map[i][j+1]) return 0; else if(map[i][j]*map[i][j+1] == 0) return 0; } for(int j = 0;j < n;++j) for(int i = 0;i < n-1;++i) { if(map[i][j] == map[i+1][j]) return 0; else if(map[i][j]*map[i+1][j] == 0) return 0; } print(); return 1; } //光标跳转 void gotoxy(int x, int y) //将光标调整到(x,y)的位置 { handle handle = getstdhandle(std_output_handle); coord pos; pos.x = x; pos.y = y; setconsolecursorposition(handle, pos); } //光标隐藏 void hidecursor() //隐藏光标显示 { console_cursor_info cursor_info = { 1, 0 }; setconsolecursorinfo(getstdhandle(std_output_handle), &cursor_info); }
哔哩哔哩配套视频链接: