📄 main.c
字号:
//如果当前移动的是"王"则暂时先将"王"移入新位置(更新王的位置)
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 + -