zoukankan      html  css  js  c++  java
  • C语言-黑白棋(人机对战)

      1 #include <stdio.h>
      2 #include <stdlib.h>
    3 /* 4 具体思路如下: 5 1.定义一个二维数组chessboard[8][8],用于保存黑白双方棋子的位置。如果数组元素为0,表示该单元格未落子;如果是-1,表示该单元格是黑子;如果是1,则表示该单元格是白子。 6 2.当一方下棋时,先检查是否有位置可下,如果有则己方下棋,如果没有就让对手下棋。 7 3.若玩家下,需要等待玩家输入棋子坐标,然后执行翻转对手棋子操作。 8 4.若计算机下,程序需对棋盘所有可以落子的位置进行判断,找出最佳的落子位置,然后执行翻转对手棋子操作
    9 5.重复步骤2~4,直到棋盘已满或双方都不能下子时结束。
     10 */
     11  
     12 void Output(char chessboard[][8]); //显示棋盘中的下子情况
     13 int Check(char chessboard[][8],int moves[][8],char player);//检查一方是否有位置下子
     14 void PlayStep(char chessboard[][8],int row,int col,char player);//在指定位置下棋
     15 void AutoPlayStep(char chessboard[][8],int moves[][8],char player);//计算机思考下子
     16 int GetMaxScore(char chessboard[][8],char player);//获取分数
     17 int BestPlay(char chessboard[][8],int moves[][8],char player);//最优下子位置 
     18 
     19 
     20 int main(){
     21     char chessboard[8][8];//保存棋盘中各单元格下子的状态
     22     int isDown[8][8] = {0};//保存棋盘中的各个位置是否可以下子,可以下的位置为1,其余为0 
     23     int row,col,x,y;
     24     int iCount = 0;//以下子的数量
     25     int player = 0;//下棋方
     26     int SkipPlay = 0;//重置下子的次数为0,若为2,则表示双方都不能下子
     27     int Score[2];//保存计算机和玩家的得分
     28     
     29     char select,ch;
     30     
     31     printf("黑白棋
    
    ");
     32     printf("玩家执黑子先行,计算机执白,按Enter开始
    ");
     33     
     34     
     35     scanf("%c",&select);
     36     
     37     do{
     38         
     39         if(player==0){
     40             player = 1;
     41         }else{
     42             player = 0;
     43         }
     44         
     45         for(row=0;row<8;row++){
     46             for(col=0;col<8;col++){
     47                 chessboard[row][col]=0;
     48             }
     49         }
     50         
     51         iCount = 4;//游戏开始的四颗棋子 
     52         chessboard[3][3] = chessboard[4][4] = 1;
     53         chessboard[3][4] = chessboard[4][3] = -1;
     54         
     55         printf("
    棋盘初始状态:
    ");
     56         Output(chessboard);
     57         
     58         //双方下棋 
     59         do{
     60             if(player==1){//玩家下棋(黑) 
     61                 player = 0;
     62                 if(Check(chessboard,isDown,2)){
     63                     while(1){
     64                         fflush(stdin);
     65                         printf("输入下子的位置(行,列):");
     66                         scanf("%d%c",&x,&ch);
     67                         x--;//因为数组是从0开始存的 
     68                         if(ch>='a'){
     69                             y = ch - 'a' + 1;
     70                         } else{
     71                             y = ch - 'A' + 1;
     72                         }
     73                         y--;
     74                         //判断是否越界、是否已有棋子 
     75                         if(x>=0&&x<8&&y>=0&&y<8&&isDown[x][y]){
     76                             PlayStep(chessboard,x,y,2);
     77                             iCount++;
     78                             break; 
     79                         }else{
     80                             printf("坐标输入有误,请重新输入。
    
    ");
     81                         }
     82                     }
     83                     
     84                     printf("
    你下子之后的状态:
    ");
     85                     Output(chessboard);
     86                     system("pause"); 
    87
    88
    }else if(++SkipPlay < 2){//无效下子的次数小于2 89 fflush(stdin); 90 printf("你没位置可下,按Enter让计算机下子"); 91 scanf("%c",&select); 92 } else{ 93 printf("双方都没位置下子,游戏结束! "); 94 } 95 }else{//计算机下棋(白) 96 97 player = 1; 98 if(Check(chessboard,isDown,1)) { 99 SkipPlay = 0;//清除无效下子次数 100 AutoPlayStep(chessboard,isDown,1); //下子 101 iCount++; 102 printf(" 计算机下子后的状态: "); 103 Output(chessboard); 104 }else if(++SkipPlay < 2){//无效下子的次数小于2 105 fflush(stdin); 106 printf("我没位置可下,你走 "); 107 scanf("%c",&select); 108 } else{ 109 printf("双方都没位置下子,游戏结束! "); 110 } 111 112 113 114 } 115 116 117 }while(iCount<64&&SkipPlay<2); 118 119 Output(chessboard); 120 Score[0] = Score[1] = 0;//清空几份变量 121 122 for(row=0;row<8;row++){ 123 for(col=0;col<8;col++){ 124 if(chessboard[row][col]==-1){ 125 Score[0]++;//统计黑子数量 126 } 127 if(chessboard[row][col]==1){ 128 Score[1]++;//统计白子数量 129 } 130 } 131 } 132 printf("最终成绩: "); 133 printf("玩家:%d 计算机:%d ",Score[0],Score[1]); 134 fflush(stdin); 135 printf("继续下一局(y/n)? "); 136 scanf("%c",&select); 137 138 }while(select=='y'||select=='Y'); 139 printf("游戏结束!"); 140 system("pause"); 141 return 0; 142 143 } 144 145 146 //显示棋盘中的下子情况 147 void Output(char chessboard[][8]){ 148 int row, col; 149 printf(" "); 150 for (col = 0; col < 8; col++) //输出列标号 151 printf(" %c", 'A' + col); 152 printf(" "); 153 printf(""); //输出顶部横线 154 for (col = 0; col < 7; col++) //输出一行 155 printf("—┬"); 156 printf("—┐ "); 157 for (row = 0; row < 8; row++) 158 { 159 printf("%2d|", row + 1); //输出行号 160 for (col = 0; col < 8; col++) //输出棋盘各单元格中棋子的状态 161 { 162 if (chessboard[row][col] == 1) //白棋 163 printf("○|"); 164 else if (chessboard[row][col] == -1) //黑棋 165 printf("●|"); 166 else //未下子处 167 printf(" |"); 168 } 169 printf(" "); 170 if (row < 8-1) 171 { 172 printf(""); //输出交叉线 173 for (col = 0; col < 8-1; col++) //输出一行 174 printf("—┼"); 175 printf("—┤ "); 176 } 177 } 178 printf(""); 179 for (col = 0; col < 8-1; col++) //最后一行的横线 180 printf("—┴"); 181 printf("—┘ "); 182 } 183 184 //检查一方是否有位置下子 185 int Check(char chessboard[][8], int isDown[][8], char player) 186 { 187 int rowdelta, coldelta, row, col, x, y = 0; 188 int iStep = 0;//可下的位置数量 189 char opponent = (player == 1) ? -1 : 1; //对方棋子 190 char myplayer = -1 *opponent;//我方棋子 191 for (row = 0; row < 8; row++) //将isDown数组全部清0 192 for (col = 0; col < 8; col++) 193 isDown[row][col] = 0; 194 for (row = 0; row < 8; row++) //循环判断棋盘中的哪些单元格可以下子 195 { 196 for (col = 0; col < 8; col++) 197 { 198 if (chessboard[row][col] != 0) //若棋盘上的对应位置不为空(表示已经有子) 199 continue; //继续处理下一个单元格 200 for (rowdelta = -1; rowdelta <= 1; rowdelta++) //循环检查上下行 201 { 202 for (coldelta = -1; coldelta <= 1; coldelta++) //循环检查左右列 203 { 204 if (row + rowdelta < 0 || row + rowdelta >= 8 || col + coldelta < 0 || col + coldelta >= 8|| (rowdelta == 0 && coldelta == 0))//若坐标超过棋盘或为当前单元格 205 continue; //继续循环 206 if (chessboard[row + rowdelta][col + coldelta] == opponent)//若(row,col)四周有对手下的子 207 { 208 x = row + rowdelta; //以对手的下子位置为坐标 209 y = col + coldelta; 210 while(1)//以对手的下子为起始点,沿着该方向查找自己方的棋子,以攻击对方棋子 211 { 212 x += rowdelta; //对手下子的四周坐标 213 y += coldelta; 214 if (x < 0 || x >= 8 || y < 0 || y >= 8) //超过棋盘 215 break; //退出循环 216 if (chessboard[x][y] == 0) //若对应位置为空 217 break; 218 if (chessboard[x][y] == myplayer) //若对应位置下的子是当前棋手的 219 { 220 //设置移动数组中对应位置为1 (该位置可下子,形成向对手进攻的棋形) 221 isDown[row][col] = 1; 222 iStep++; //加可下子的位置数量 223 break; 224 } 225 } 226 } 227 } 228 } 229 } 230 } 231 return iStep; //返回可下的位置数量(若返回值为0,表示没地方可下) 232 } 233 234 235 //在指定位置下子 236 void PlayStep(char chessboard[][8], int row, int col, char player) 237 { 238 int rowdelta = 0; 239 int coldelta = 0; 240 int x = 0; 241 int y = 0; 242 char opponent = (player == 1) ? -1 : 1; //对方棋子 243 char myplayer = -1 * opponent;//我方棋子 244 chessboard[row][col] = myplayer; //保存所下的棋子 245 for (rowdelta = -1; rowdelta <= 1; rowdelta++)//检查所下子四周的棋子 246 { 247 for (coldelta = -1; coldelta <= 1; coldelta++) 248 { 249 if (row + rowdelta < 0 || row + rowdelta >= 8 || col + coldelta < 0 || col + coldelta >= 8 || (rowdelta == 0 && coldelta == 0)) 250 //若坐标超过棋盘界限 251 continue; //继续下一位置 252 //若该位置是对手的棋子 253 if (chessboard[row + rowdelta][col + coldelta] == opponent) 254 { 255 x = row + rowdelta; //以对手的棋子作为坐标 256 y = col + coldelta; 257 while(1) //在对手棋子的四周寻找我方棋子 258 { 259 x += rowdelta; 260 y += coldelta; 261 if (x < 0 || x >= 8 || y < 0 || y >= 8) //若坐标超过棋盘 262 break; //退出循环 263 if (chessboard[x][y] == 0)//若对应位置为空 264 break; //退出循环 265 if (chessboard[x][y] == myplayer) //若对应位置是我方棋子 266 { 267 //循环处理 268 while (chessboard[x -= rowdelta][y -= coldelta] == opponent) 269 chessboard[x][y] = myplayer; //将中间的棋子都变成我方棋子 270 break; //退出循环 271 } 272 } 273 } 274 } 275 } 276 } 277 278 //计算机自动下子 279 void AutoPlayStep(char chessboard[][8], int isDown[][8], char player) 280 { 281 int row, col, row1, col1, i, j; 282 int Score = 0, MinScore = 100;//对方可下子得到的分数和最小分数 283 char chessboard1[8][8]; //临时数组,保存棋盘的下子位置 284 int isDown1[8][8]; //临时数组,保存可下子的位置 285 char opponent = (player == 1) ? -1 : 1; //对手下的棋子 286 for (row = 0; row < 8; row++) //循环检查棋盘的每个单元格 287 { 288 for (col = 0; col < 8; col++) 289 { 290 if (isDown[row][col] == 0) //若不可下子 291 continue; //继续下一个位置 292 for (i = 0; i < 8; i++)//将棋盘原来的棋子复制到临时数组中 293 for (j = 0; j < 8; j++) 294 chessboard1[i][j] = chessboard[i][j]; 295 PlayStep(chessboard1, row, col, player); 296 //试着在临时棋盘中的一个位置下子 297 Check(chessboard1, isDown1, opponent); //检查对手是否有地方可下子 298 Score = BestPlay(chessboard1, isDown1, opponent); 299 //获得临时棋盘中对方下子的得分情况 300 if (Score < MinScore) //保存对方得分最低的下法 301 { 302 MinScore = Score; 303 row1 = row; 304 col1 = col; 305 } 306 } 307 } 308 PlayStep(chessboard, row1, col1, player); //计算机按最优下法下子 309 } 310 311 //获取分数 312 int GetMaxScore(char chessboard[][8], char player) 313 { 314 int Score, row, col; 315 char opponent = (player == 1) ? -1 : 1; //对方棋子 316 char myplayer=-1*opponent; 317 for (row = 0; row < 8; row++) //循环 318 { 319 for (col = 0; col < 8; col++) 320 { 321 //如果棋盘对应位置是对手下的棋子,从总分中减1分 322 Score -= chessboard[row][col] == opponent; 323 //如果棋盘对应位置是我方的棋子,在总分中加1分 324 Score += chessboard[row][col] == myplayer; 325 } 326 } 327 return Score; //返回分数 328 } 329 330 //最优下子位置 331 int BestPlay(char chessboard[][8], int isDown[][8], char player) 332 { 333 int row, col, i, j; 334 char chessboard1[8][8] = { 0 }; //定义一个临时数组 335 int MaxScore = 0; //保存最高分 336 int Score = 0; 337 char opponent = (player == 1) ? -1 : 1;//对手下的棋子 338 for (row = 0; row < 8; row++) //循环检查每个单元格 339 { 340 for (col = 0; col < 8; col++) 341 { 342 if (!isDown[row][col]) //如果该位置不可下子 343 continue; //继续检查 344 for (i = 0; i < 8; i++) //复制棋盘各单元格下子的状态到临时数组 345 for (j = 0; j < 8; j++) 346 chessboard1[i][j] = chessboard[i][j]; 347 PlayStep(chessboard1, row, col, player); //在临时数组中的指定行列下子 348 Score = GetMaxScore(chessboard1, player); //获取下子后可得到的分数 349 if (MaxScore < Score) //若原方案得到的分数小于本次下子的分数 350 MaxScore = Score; //保存最高分 351 } 352 } 353 return MaxScore; //返回得到的最高分 354 }
    stdio
    如果有就让玩家或计算机下
  • 相关阅读:
    django项目部署服务器后无法发送邮箱 错误信息:Connection unexpectedly closed
    python
    python
    获取当前时间减去 xx时,xx分,xx秒
    Python之List和Tuple类型(入门3)
    AndroidProjects个人项目归纳
    Android面试问题收集总结
    Python变量和数据类型(入门2)
    Python简单介绍以及Python环境搭建(入门1)
    Andriod ADB Interface驱动安装失败Configure USB Debug for Android
  • 原文地址:https://www.cnblogs.com/xuecl/p/12366288.html
Copyright © 2011-2022 走看看