📄 main.c
字号:
//-----------------------------------------------------------------
// 名称: 用PIC18与触摸屏设计的国际象棋游戏程序
//-----------------------------------------------------------------
// 说明: 本例棋盘下半部分白子为用户方,上半部分黑子为CPU方.
// 案例运行时,用户可通过点击LCD(触摸LCD)与CPU对弈.
// 在每次轮到CPU控制行棋时,其搜索过程会通过虚拟终端显示.
// CPU将选择最佳方式来操作.
//
//-----------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include "chess.h"
//全局变量
ZPAGE BOARD board; //棋盘中当前各棋子信息[位置,棋子类型/颜色]
ZPAGE MASK validmovemask; //有效移动掩码
ZPAGE MASK capturemask; //捕获掩码
ZPAGE INT movecount; //移动计数
ZPAGE BYTE movetype; //移动类型NO_MOVE,NORMAL,SAFE,SAFECAPTURE,CAPTURE
ZPAGE BYTE rate; //移动权重评估值
ZPAGE BYTE piecerate; //当前棋子的移动方案权重评估
ZPAGE BYTE lastmove; //上次移动的棋子(用于避免某些棋子连续移动)
//将军与将死
ZPAGE BYTE wh_king_pos[2]; //白方王的位置
ZPAGE BYTE bl_king_pos[2]; //黑方王的位置
ZPAGE BYTE opp_king_pos[2];//对方王的位置
ZPAGE BOOL kingcapture; //王被将
//王车易位
ZPAGE BYTE wh_base_cont; //白子底线掩码
ZPAGE BYTE bl_base_cont; //黑子底线掩码
ZPAGE MASK currcapturemask;//当前捕获掩码
ZPAGE MASK currmovemask; //当前移动掩码
extern void sleep(int);
//-----------------------------------------------------------------
// 搜索棋子p从当前位置from开始的所有的合法移动
// 搜索结果保存于validmovemask和capturemask
// 两数组分别为该棋子的当前所有可能的移动掩码及捕获掩码
// 该函数所调用的各类棋子的合法移动搜索函数编写在validate.c中
//-----------------------------------------------------------------
void validate(BYTE p,BYTE from[],BOOL piececolour)
{
switch (p)
{
}
}
//-----------------------------------------------------------------
// 主程序
//-----------------------------------------------------------------
void main()
{
}
//-----------------------------------------------------------------
// 与CPU对弈的象棋游戏
//-----------------------------------------------------------------
void cpuplay()
{
LOC from, to, cpufrom, cputo; PIECE p;
BYTE i = 0, j = 0, movefrom, moveto, bestfrom, bestto, illegal = FALSE;
while(1)
{
//-----------------------------------------------------------
// 已方移动(已方执白,偶数次由已方移动)
//-----------------------------------------------------------
if (((movecount + 1) & 0x01) == 0)
{
}
//-----------------------------------------------------------
// 对方移动(由单片机控制棋子移动,单片机执黑,奇数次由单片机移动)
// 该移动所涉及的算法是本例程序算法中最复杂的,它需要搜索所有
// 黑子的所有可能的移动方式,并找出可能最佳的移动方案.
//-----------------------------------------------------------
else if (((movecount + 1) & 0x01) == 1)
{
}
}
}
//-----------------------------------------------------------------
// 本函数专用于为“黑子”p找出从from位置出发的最佳目标位置序号(0~63)
//-----------------------------------------------------------------
INT getbestpiecemove(BYTE from[])
{
BYTE i,j,k,tmp,to[2],move,bestmove,curr_pos_rate;
bestmove = NO_MOVE;
piecerate = tmp = 0;
//当前两个掩码数组validmovemask,capturemask内容为本方信息(这里指黑子),
//在开始搜索对手移动捕获信息时,先将其备份到currmovemask与currcapturemask
//再将validmovemask,capturemask数组中的掩码字节清0
for (i = 0; i < 8; i++)
{ currmovemask[i] = validmovemask[i];
currcapturemask[i] = capturemask[i];
validmovemask[i] = 0x00;
capturemask[i] = 0x00;
}
//通过双重for循环扫描处理“黑子”可能移入的每行(i)中的每个格子(j)
//评估移入[i,j]格子后的状况:
//包括NO_MOVE,NORMAL,CAPTURE,SAFE,SAFECAPTURE以及对应的权重值
for (i = 0; i < 8; i++)
{ //从掩码字节currmovemask[i]的第0位开始逐位判断
for (j = 0; j < 8; j++)
{
//如果棋盘格式[i,j]可移入黑子p(从掩码低位开始判断)
if (currmovemask[i] & 0x01)
{
//则开始对黑子p由from位置到[i,j]位置的移动进行评估------
to[0] = i; to[1] = j;
//下面的test_singlemove函数对p由from到to的单次移动进行检测
//test_simglemove针对假定已处于to位置的黑子p,搜索全盘中的白子,
//看是否出现"王"被捕获.可能被对方将军时返回FALSE,否则返回TRUE.
//返回值为TRUE是表示该移动可行(但不代表最优,因为还要对该移动进行评估)
if (test_singlemove(from,to,board[from[0]][from[1]]))
{ //当前p由from到to(即[i,j])的移动可行时,再进一步对移动进行权重评估
//getindex得到目标格子是0~63中的第几个格子(t[0]*8 + t[1])
move = getindex(to[0],to[1]);
//移动类型初始设为NORMAL
movetype = NORMAL;
//注意:本函数中每调用一次test_singlemove后,validmovemask与capturemask中
//所保存的都是对方“白子”的掩码,通过该掩码可知道对方的可移入位置.
//当前循环中黑子是处于位置from的,如果白子掩码中from位置恰好标识
//白子可移入的黑子所在的from位置,则表示黑子可被白子吃掉
if ((validmovemask[from[0]] >> from[1]) & 0x01)
{ //故加大该移动的权重,使其有可能避免被白子吃掉
//(所加的权重为棋子自身权重的1/2)
tmp = (board[from[0]][from[1]] & 0x07) / 2;
}
//如果白子不能捕获将移入[i,j]位置的黑子p,而黑子p可捕获[i,j]位置的白子,
//将移动类型设为SAFECAPTURE(可安全捕获)
if((!((capturemask[i] >> j) & 0x01)) &&
((currcapturemask[i] >> j) & 0x01)) movetype = SAFECAPTURE;
//否则如果仅仅是黑子可捕获[i,j]位置的白子(白子也能捕获移入[i,j]的黑子)
//则将移动类型设为CAPTURE(可捕获)
else if ((currcapturemask[i] >> j) & 0x01) movetype = CAPTURE;
//否则如果白子不能捕获将移入[i,j]位置的黑子(黑子亦不能捕获[i,j]位置白子)
//则将移动类型设为SAFE(是安全的)
else if (!((capturemask[i] >> j) & 0x01)) movetype = SAFE;
//根据目标位置to(即[i,j])与指定的理想位置[3,3]的距离(水平+垂直格子数)
//计算出移到目标位置to的权重值curr_pos_rate
curr_pos_rate = ((to[0] > 3) ? to[0] - 3 : 3 - to[0]) +
((to[1] > 3) ? to[1] - 3 : 3 - to[1]);
//对黑子p由from到to的移动进行进一步评估,累加评估返回权重
//函数rate_move综合考虑的3项因素分别是:
//(1) movetype (2) 棋子的价值(棋子符号常量定义) (3) 由from到[3,3]的距离
tmp += rate_move((board[from[0]][from[1]]),to,curr_pos_rate);
//如果评估值大于前一移动尝试的评估值piecerate
if (tmp > piecerate)
{ //则更新当前棋子可能更佳的移动方式
//piecerate保存新的权重,bestmove保存新的目标格子序号(0~63)
piecerate = tmp; bestmove = move;
}
tmp = 0;
}
//清空掩码字节
for (k = 0; k < 8; k++) validmovemask[k] = capturemask[k] = 0;
}
//取得第i行掩码中的下一位(即第j位掩码)
currmovemask[i] = currmovemask[i] >> 1;
}
}
if (bestmove != NO_MOVE) //显示可能找到的最佳移动路径
printf("bm : %d,from : %d,%d, rate: %d movetype : %d\n",
bestmove,from[0],from[1],piecerate,movetype);
return bestmove; //返回目标格子序号(0~63)
}
//-----------------------------------------------------------------
// test_singlemove(BYTE from[],BYTE to[],PIECE p)
// 该函数对棋子p由from到to位置的一次移动进行检测
// 检查假设棋子p(白子或黑子)由from位置移入to位置时,在不与规则
// 冲突的情况下,"王"是否被将,被将时返回FALSE(表示移动不可行),
// 未被将时返回TRUE(表示移动可行).
// 另外:调用该函数以后validmovemask与capturemask两个掩码数组中保存的
// 全部是对手的掩码信息.(无论返回值如何,该函数最终并不改动棋盘当前格局)
//-----------------------------------------------------------------
BOOL test_singlemove(BYTE from[],BYTE to[],PIECE p)
{ INT i = 0,j = 0;
BYTE opp_pos[2];
PIECE opp_piece,tmpdest;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -