⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 单片机c语言程序设计100例--基于PIC+PROTEUS
💻 C
📖 第 1 页 / 共 2 页
字号:
   //如果当前移动的是"王"则暂时先将"王"移入新位置(更新王的位置)
   if ((p & 0x07) == KING) updatekingpos(to,(p & 0x08));
   //对待移入的目标位置信息进行备份,以便在尝试搜索所有合法移动及合法捕获后还原
   tmpdest = board[to[0]][to[1]];
   //将待移动棋子当前所在位置设为空
   board[from[0]][from[1]] = EMPTY;
   //在新位置放入当前棋子p
   board[to[0]][to[1]] = p;
   kingcapture = FALSE;//先设捕获为假
   //对8x8棋盘格子搜索对方的每一棋子对本方(虚拟移入)to位置的棋子的攻击情况
   //(未遇到对方棋子捕获已方的"王"时继续搜索)
   for (i = 0; (i < 8) && (!kingcapture); i++)    //扫描行(i) 
   {      
      for (j = 0; (j < 8) && (!kingcapture); j++) //扫描列(j)
      {         
         if (is_opp_piece(i,j,(p & 0x08)))
         {  //将对手棋子位置[i,j]放入位置变量opp_pos,棋子类型/角色放入opp_piece
            opp_pos[0] = i, opp_pos[1] = j, opp_piece = board[i][j];
            //搜索对手该棋子所有可能的合法移动与捕获掩码,结果保存到
            //validmovemask和capturemask,在遇到kingcapture为真时循环提前结束
            validate(piecetype(opp_piece),opp_pos,(opp_piece & 0x08));
         }
      }
   }
   //搜索与判断结束后,将尝试移动的棋子还原
   board[to[0]][to[1]] = tmpdest;
   board[from[0]][from[1]] = p;
   //将此前移入新位置的棋子也还原到原始位置
   if ((p & 0x07) == KING) updatekingpos(from,(p & 0x08));
   //返回在(from,to,p)的操作下,王是否被将,
   //被将时返回FALSE(表示此移动不可行),否则返回真(表示此移动可行)
   return (kingcapture) ? FALSE : TRUE;
}

//-----------------------------------------------------------------
// 对棋子的移动进行评估
// 根据棋子/移动类型/目标位置/后续可能遇到的风险计算出一次移动的相对价值
// 该函数进行的人为处理可提高单片机所执黑子的取胜能力
// 参数posrate的取值范围为0~8,标识了与棋盘中心的接近程度)
//-----------------------------------------------------------------
INT rate_move(PIECE piece, BYTE to[],BYTE posrate)
{
   BYTE tmp, value, rating;   
   //兵,车,马,象,后,王的权值分别定义为: 1,2,3,4,5,6
   //如果棋子是"王"则将其权值改为最小值0,
   value = ((piece & 0x07) == KING) ? 0 : (piece & 0x07); 
   //根据不同的移动类型得出不同的评估值(rate)
   switch (movetype)
   { 
      case NORMAL     : //在一般情况下优先移动低权值棋子
                        //"王"例外:王的权重值最高(value=6),改设为0后可优先移动
                        rating = 6 - value + posrate / 2;  break;
      case SAFE       : //权值较大且离中心[3,3]较近的棋子优先移动
                         //即:较好的棋子移向较好的位置
                        rating = value + ((8 - posrate));  break;
      case SAFECAPTURE: //如果为安全捕获(可吃对方,但对方不能吃自己)
                         //权重设为6+8=14(最大权重)
                        rating = 14;                       break;
      case CAPTURE    : //如果目标位置的白子优于本方黑子则设权重为12,否则设为4
                        rating = ((board[to[0]][to[1]] & 0x07) > value) ? 12 : 4;
                                                           break; 
      default         : rating = 0;                       break;
   }
   return rating;
 }

//-----------------------------------------------------------------
// 移动棋子(将原位棋子删除,在新位置重绘)
//-----------------------------------------------------------------
void draw_move(BYTE from[], BYTE to[],PIECE p)
{  
   BYTE *basemask,baserow;
   //根据当前棋子颜色获取其底线行的掩码
   basemask = (p & 0x08) ? &bl_base_cont : &wh_base_cont;
   //白子底线行号为0,黑子底线行号为7(棋子编码XXXX中的高位为颜色)
   baserow = (p & 0x08) ? 7 : 0; 
   if (piecetype(p) == KING)  //王移动
   {     
      updatekingpos(to,(p & 0x08));        //更新王的位置为to
      panel_draw(from[0],from[1],EMPTY);   //删除原位棋子(绘制空白棋子)
      panel_draw(to[0],to[1],p);           //在新位置绘制棋子p
      board[from[0]][from[1]] = EMPTY;     //board数组中原位置棋子设为空
      board[to[0]][to[1]] = p;             //board数组中新位置棋子设为p
      //如果"王"在横向走过不止一步(王/车易位)
      if (((to[1] - from[1]) != 1) && ((from[1] - to[1]) != 1))
      {  //通过&0x1F(00011111)检测底线左边的五位,如果结果为00010001(0x11)
         //则表示“王”与左边的“车”没有[后/马/象]的阻隔.
         //(注意不要误认为11111在右边而认为是检测右边的5位)
         if (((*basemask) & 0x1F) == 0x11)
         {  panel_draw(to[0],0,EMPTY);                //擦除左边的"车"
            panel_draw(to[0],3,((p & 0x08) | ROOK));  //"车"易位到该行第3格
            board[to[0]][0] = EMPTY;                  //这两行将board数组更新为
            board[to[0]][3] = ((p & 0x08) | ROOK);    //与棋盘棋子相同
            printf("Queenside Castle\n");             //长易位(放在"后"的位置)
         }
         //否则&0xF0(11110000)来检测右边的五位(同样要注意不要误认为1111在左边
         //而认为检测的是左边的4位),如果为10010000(0x90)则表示“王”与的右边的“车”
         //之间没有[象/马]的阻隔.
         else if (((*basemask) & 0xF0) == 0x90)
         {  panel_draw(to[0],7,EMPTY);                //擦除右边的"车"
            panel_draw(to[0],5,((p & 0x08) | ROOK));  //"车"易位到该行第5格
            board[to[0]][7] = EMPTY;                  //这两行将board数组更新为
            board[to[0]][5] = ((p & 0x08) | ROOK);    //与棋盘棋子相同
            printf("Kingside Castle\n");              //短易位(放在"王"旁边)
         }
       }
   }
   //如果p为“黑兵”且目标列为0,或p为“白兵”且目标列为第7列,由“兵”升变为“后”
   //实际上兵可升变为除王与兵以外的任何棋子,这里将其直接升变为威力最大的“后”
   else if (((p == 0x09) && (to[0] == 0)) || ((p == 0x01) && (to[0] == 7)))
   {
     panel_draw(from[0],from[1], EMPTY);         //删除原位棋子(绘制空白棋子)
     panel_draw(to[0],to[1], QUEEN|(p & 0x08));  //在目标新位置以p的颜色绘制"后"
     board[from[0]][from[1]] = EMPTY;            //board数组中原位置棋子设为空
     board[to[0]][to[1]]     = QUEEN|(p & 0x08); //board数组中新位置棋子为"后"(p的颜色) 
   }       
   else  //否则为正常移动
   {  
      panel_draw(from[0], from[1], EMPTY);       //删除原位棋子(绘制空白棋子)
      panel_draw(to[0], to[1], p);               //在目标位置绘制棋子p
      if (board[to[0]][to[1]] != EMPTY) sound_capture();//如果目标位置非空则输出捕获声音
      board[from[0]][from[1]] = EMPTY;           //棋盘原位置棋子移走(设空)
      board[to[0]][to[1]] = p;                   //该棋子移入新位置
   }
   //如果所移动棋子p是处于底行某列的,且底行掩码basemask标识该位置有棋子
   if ((from[0] == baserow) && ((*basemask) & (1 << from[1])))
   {  //则在移走处于该位置的棋子p以后,应随即更新底行掩码,将该位清为0,
      //(因为后续可能出现的"王车易位"操作需要满足"无子阻隔"的条件)
      (*basemask) &= ~(1 << from[1]);
   }
 }

//-----------------------------------------------------------------
// 更新“王”的位置记录
//-----------------------------------------------------------------
void updatekingpos(BYTE to[], BOOL piececolour)
{ 
   if (!piececolour)
   {  wh_king_pos[0] = to[0]; wh_king_pos[1] = to[1]; //白子"王"
   }
   else
   {  bl_king_pos[0] = to[0]; bl_king_pos[1] = to[1]; //黑子"王"
   }
}

//-----------------------------------------------------------------
// 棋盘棋子初始化
//-----------------------------------------------------------------
void init_board() 
{  
   COORD i, j;  panel_cls(); //清屏并重绘黑白交错的棋盘格子
   //在board第0行放置已方的白子:“车,马,象,后,王,象,马,车”
   board[0][0] = board[0][7] = WHITE|ROOK;   //两车(白子)
   board[0][1] = board[0][6] = WHITE|KNIGHT; //两马(白子)
   board[0][2] = board[0][5] = WHITE|BISHOP; //两象(白子)
   board[0][3] = WHITE|QUEEN;                //一后(白子)
   board[0][4] = WHITE|KING;                 //一王(白子)
   //在board第7行放置对方的黑子:“车,马,象,后,王,象,马,车”
   board[7][0] = board[7][7] = BLACK|ROOK;   //两车(黑子)
   board[7][1] = board[7][6] = BLACK|KNIGHT; //两马(黑子)
   board[7][2] = board[7][5] = BLACK|BISHOP; //两象(黑子)
   board[7][3] = BLACK|QUEEN;                //一后(黑子)
   board[7][4] = BLACK|KING;                 //一王(黑子)
   //3~6行为空
   for (i = 3; i < 6; ++i)
      for (j = 0; j < 8; ++j) board[i][j] = 0;
   //第board第1,6两行上的各放置8个兵(分别为黑子和白子)
   for (i = 0; i < 8; ++i)
   {  board[1][i] = WHITE|PAWN;//白兵
      board[6][i] = BLACK|PAWN;//黑兵
   }
   //在整个棋盘8x8=64个格子上绘制棋子图案(为空的格子跳过)
   for (i = 0; i < 8; ++i)
      for (j = 0; j < 8; ++j)
         if (board[i][j] != EMPTY) panel_draw(i, j, board[i][j]);   
   //初始设置王在8x8棋盘上的坐标位置
   wh_king_pos[0] = 0; //白子王的位置在(0,4)
   wh_king_pos[1] = 4; 
   bl_king_pos[0] = 7; //黑子王的位置在(7,4)
   bl_king_pos[1] = 4;  
   //双方底线行被全部占据
   wh_base_cont = bl_base_cont = 0xFF;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -