尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

C语言小结---2048游戏实现

C语言小结---2048游戏实现 游戏核心逻辑实现一行数字向左合并void merge_left(int *p) 71 { 72 int i0; 73 int j0; 74 for(i0;i4;i) 75 { 76 if(p[i]!0) 77 { 78 for(ji1;j4;j) 79 { 80 if(p[i]p[j]) //匹配相同值合并 81 { 82 p[i]*2; 83 p[j]0; 84 break; //合并一次退出避免双重合并 85 }else if(p[j]!0) //碰到非0且不相同值说明此数不可能合并退出循环避免跨数合并 86 { 87 break; 88 } //p【j】等于0j继续找 89 } 90 } 91 } 92 }从左边p[0]开始向右寻找与p[0]相同数字0值跳过遇到非0且不等的数说明此数无法合并直接退出后看p[1]依次查看下去一行数字向左移动94 void compress_left(int p[]) 95 { 96 int i0; 97 int j0; 98 for(i0;i4;i) 99 { 100 if(p[i]!0) 101 { 102 for(ji-1;j0;--j) 103 { 104 if(p[j]0) 105 { 106 p[j]p[i]; 107 p[i]0; 108 --i; 109 } 110 } 111 } 112 } 113 }通过i外层循环寻找非0数找到之后同过内层循环让非0数向左移动非0数左边是0的情况下通过--i让p[i]逐渐“冒泡”到左边通过ai获得一个更高效且符合规范的算法上述算法在循环内改变了条件值ivoid compress_left(int p[], int n) { int write 0; // 下一个非零元素要写入的位置 for (int read 0; read n; read) { if (p[read] ! 0) { p[write] p[read]; } } // 剩余位置补零 while (write n) { p[write] 0; } }此算法通过双指针寻找非0值和0位巧妙处在于即使p[0]有值也只是p[0]赋值给p[0]。write每次写入后自动1先用后加read只遍历一遍数组而且只赋值一次而不消除原处的数据所以write之后的数据需要清零数组向左移动115 void left_move(int p[][4]) 116 { 117 int i; 118 for(i0;i4;i) 119 { 120 merge_left(p[i][0]); 121 compress_left(p[i][0]); 122 } 123 }通过函数复用轻松完成了整个数组的左移数组向右移动易得将数组左右翻转之后向左移动再翻转可以获得向右移动的效果125 void reverse_row(int m[4]) 126 { 127 int row[4]{}; 128 int i0; 129 for(i0;i4;i) 130 { 131 row[i]m[3-i]; 132 } 133 for(i0;i4;i) 134 { 135 m[i]row[i]; 136 } 137 }翻转数组一行)void right_move(int p[][4]) 140 { 141 int i; 142 for(i0;i4;i) 143 { 144 reverse_row(p[i][0]); 145 merge_left(p[i][0]); 146 compress_left(p[i][0]); 147 reverse_row(p[i][0]); 148 } 149 }循环同样是对一行数据进行操作的所以通过翻转实现了右移重写向右合并与向右移动函数虽然已有前例对照但是实现代码的效率还是不如翻转好数组向上移动有了以上经验我们知道可以将数组改造成便于向左一行一行移动的结构即可151 void up_move(int p[][4]) 152 { 153 int colmn[4]; 154 int i,j; 155 for(i0;i4;i) 156 { 157 for(j0;j4;j) 158 { 159 colmn[j]p[j][i]; 160 } 161 merge_left(colmn); 162 compress_left(colmn); 163 for(j0;j4;j) 164 { 165 p[j][i]colmn[j]; 166 } 167 } 168 } 169通过外循环i内部的两次循环j一次外循环就将一列数据取出、移动然后填回数组向下移动170 void down_move(int p[][4]) 171 { 172 int colmn[4]; 173 int i,j; 174 for(i0;i4;i) 175 { 176 for(j0;j4;j) 177 { 178 colmn[j]p[j][i]; 179 } 180 reverse_row(colmn); 181 merge_left(colmn); 182 compress_left(colmn); 183 reverse_row(colmn); 184 for(j0;j4;j) 185 { 186 p[j][i]colmn[j]; 187 } 188 } 189 }与向上移动类型添加了两次翻转判断失败或者胜利void check_game_status(int p[][4]) 214 { 215 win0; 216 int i,j; 217 for(i0;i4;i) 218 { 219 for(j0;j4;j) 220 { 221 if(p[i][j]2048) 222 { 223 win1; 224 return; //游戏胜利 225 } 226 } 227 } 228 for(i0;i4;i) 229 { 230 for(j0;j4;j) 231 { 232 if(p[i][j]0) 233 { 234 return; //游戏继续 235 } 236 } 237 } 238 for(i0;i4;i) 239 { 240 for(j0;j4;j) 241 { 242 if(j3 i!3) 243 { 244 if(p[i][j]p[i1][j]) 245 { 246 return; //游戏继续 247 } 248 }else if(i3 j!3) 249 { 250 if(p[i][j]p[i][j1]) 251 { 252 return; //游戏继续 253 } 254 }else if(i!3 j!3) 255 { 256 if(p[i][j]p[i][j1]) 257 { 258 return; //游戏继续 259 } 260 if(p[i][j]p[i1][j]) 261 { 262 return; //游戏继续 263 } 264 } 265 266 } 267 } 268 game_over1; 269 }优先判断是否有2048胜利条件防止2048出现后游戏继续有空格直接判断游戏继续无空格则判断是否有相同且相邻的数有则继续无则结束我的判断相同相邻值算法略显复杂插入一个更优秀的算法for (int i 0; i 4; i) { for (int j 0; j 4; j) { // 检查右邻居j1 4 if (j 1 4 p[i][j] p[i][j 1]) return; // 检查下邻居i1 4 if (i 1 4 p[i][j] p[i 1][j]) return; } }算法原理相同我为了防止数组越界写的较为复杂这是一种更简易且易理解的算法对数组初始化37 void init(int (*p)[4]) 38 { 39 srand(time(NULL)); 40 int init_val1,init_val2; 41 memset(p,0,sizeof(int[4][4])); 42 if(rand()%101) 43 { 44 init_val14; 45 }else 46 { 47 init_val12; 48 } 49 if(rand()%101) 50 { 51 init_val24; 52 }else 53 { 54 init_val22; 55 } 56 p[rand()%4][rand()%4]init_val1; 57 int flage1; 58 while(flage) 59 { 60 int nrand()%4; 61 int mrand()%4; 62 if(p[n][m]0) 63 { 64 flage0; 65 p[n][m]init_val2; 66 } 67 } 68 }初始化一局游戏只需要一次所以这里顺便取出随机种子值种子值一次运行只能取一次否则时间戳相同第一个随机数也是相同的这里通过对10求余概率取得0~9十个结果所以初始值有10%的概率为490%的概率为2再通过flag检测是否两个初始值填入一个位置填入随机值10 void generate_random(int (*p)[4]) 11 { 12 int i,j; 13 int q[16][2]{}; 14 int t0; 15 for(i0;i4;i) 16 { 17 for(j0;j4;j) 18 { 19 if(p[i][j]0) 20 { 21 q[t][0]i; 22 q[t][1]j; 23 t; 24 } 25 } 26 } 27 if(t0) 28 return; 29 int rrand()%t; 30 if(rand()%107) 31 { 32 p[q[r][0]][q[r][1]]4; 33 }else 34 { 35 p[q[r][0]][q[r][1]]2; 36 } 37 }创建一个数组存储所有空白格的行列坐标从t个空白格随机选择一个以 30% 的概率生成 470% 的概率生成 2
返回列表