您的位置:首页 > 其它

XMOVE3.0手持终端——软件介绍(四):在2KB内存的单片机上实现的超精简五子棋对战算法(原创)

2012-06-20 19:53 561 查看

一. 综述

  这是我两年前完成的一个小项目,它基于我开发的XMOVE动作感应系统平台。五子棋算法网上随便一搜到处都是,不过值得自豪的是,我在2KB内存的单片机上不仅跑上了我自制的嵌入式OS,还能同时跑五子棋。这是界面截图:

其他模块的实现(仅供参考)

void DrawDesk()
{
u8 m;
Clear_Screen();
SetPaintMode(0,COLOR_Black);
Rectangle(23,28,205,210,1);
SetPaintMode(0,COLOR_Yellow);
Rectangle(20,25,202,207,1);
SetPaintMode(0,COLOR_Black);
for(m=0;m<15;m++)
Line(20,25+13*m,200,25+13*m);
for(m=0;m<15;m++)
Line(20+13*m,25,20+13*m,207);
//Lcd_disp(240,12,"五子棋");
//Lcd_disp(65,36,"赵一鸣之作");
}
void Drawchess(u8 x,u8 y, u8 mood)
{

if(mood==2)//黑方
{
SetPaintMode(0,COLOR_Black);
Circle(20+13*x,25+y*13,5,1);
}
//Rectangle(2+x*4,1+y*4,4+x*4,3+y*4,1);

else if(mood==1)
{

SetPaintMode(0,COLOR_White);
Circle(20+13*x,25+y*13,5,1);
SetPaintMode(0,COLOR_Black);
Circle(20+13*x,25+y*13,5,0);
}
}

void PushChess(u8 x,u8 y,u16  Data[29],u8 mood)
{
Drawchess(x,y,mood);
WriteData(x,y,Data,mood);

}
u8 DrawKuang(u8 *x,u8 *y,u16  Data[29])
{

u8 func_state=0;
u8 GyroKey,myKey;
while(func_state==0)
{
SetPaintMode(0,COLOR_Black);
Rectangle(14+*x*13,19+*y*13,26+*x*13,31+*y*13,0);
if(GyroControlEN==1&&back_light>1&&GyroMenuEN)
{

delay_ms(200);
L3G4200DReadData();
L3G4200DShowData();

delay_ms(200);
}

else
InputControl();

GyroKey=GyroKeyBoardInputMethod(0,0,300,300);

if(GyroKey!=KEYNULL)
myKey=GyroKey;
else
myKey=key_data;
GyroKey=KEYNULL;

SetPaintMode(0,COLOR_Yellow);
Rectangle(14+*x*13,19+*y*13,26+*x*13,31+*y*13,0);
SetPaintMode(0,COLOR_Black);

PutPixel(20+(*x)*13,19+(*y)*13);
PutPixel(20+(*x)*13,(*y)*13+31);
PutPixel(14+(*x)*13,(*y)*13+25);
PutPixel(26+(*x)*13,(*y)*13+25);
switch(myKey)
{

case KEYENTER_UP   :
if(ReadData(*x,*y,Data)==0)
func_state=1;
break;
case KEYCANCEL_UP    :
return 0;
default:
FourDirectionInputMethod(myKey,1,1,1,1,0,14,0,14,0,0, x,y);
}
myKey=KEYNULL;

}
return 1;
}


四. 算法主流程(简化版)

  流程因为很简单,所以就不画了。

while(OS_func_state==0)  //OS_func_state==0是正常的下棋状态
{
if(func_state==0)   //我方下棋
{
if(DrawKuang(&XAxi,&YAxi,TotalCheseData))
PushChess(XAxi,YAxi,TotalCheseData,2);
else
{
OS_func_state=10;  //跳出态
}
if(ResultCheck(TotalCheseData,2)==2)  //胜利,跳出到成功界面
{
OS_func_state=5;
}
else
func_state=1;  //让给对方下棋
}
else   //对方下棋
{
GameSatusInit(myGameSatus);
GameSatusInit(itGameSatus);
CalPushPosition(&XAxi,&YAxi,myGameSatus,itGameSatus,TotalCheseData);
PushChess(XAxi,YAxi,TotalCheseData,1);
if(ResultCheck(TotalCheseData,1)==1)
{
OS_func_state=5;
}
else
func_state=0;

}
}


五. 总结和改进

  实现五子棋的算法有很多选项,比如基于博弈树的剪枝算法,和我这种比较简化的靠遍历评分的算法。这个算法来自于网上,水平仅仅算是初级,缺点也很明显,    

只顾眼前利益,不能顾全大局,这就和许多五子棋初学者一样犯了“目光短浅”的毛病。要解决这个问题,我们引入‘今后几步预测法’,具体方法是这样的: 首先, 让电脑分析一个可能的点,
如果在这儿下子将会形成对手不得不防守的棋型(例如:‘冲四’、‘活三’);那么下一步对手就会照您的思路下子来防守您,如此一来便完成了第一步的预测。这时再调用模块4对预测后的棋进行盘面分析,如果出现了‘四三’、‘双三’或‘双四’等制胜点,那么己方就可以获胜了(当然对黑棋而言‘双三’、‘双四’是禁手,另当别论);否则照同样的方法向下分析,就可预测出第二步、第三步……

  不过,我做过实际的测试,加上两步迭代以后,计算时间变为原来的10倍左右(确实是指数级的),但此时内存是不够用的。考虑到是2KB内存的超低功耗单片机,实现更复杂的算法勉为其难,我也就没有在上面实现迭代,有兴趣的同学们可以尝试实现之,其实不难,用个好点的CPU,比如STM32,(用电脑就别用我这个算法了),稍微改改代码就可以。这种情况,电脑的水平在中级左右。

  系统没有随机性,换句话说,如果你每次下子的方式是一样的,那么系统演化的形式完全一致。

  顺便提一下,自从学习了C#编程以后,看了两年前写的C代码,真是不堪入目。不过,在单片机上实现的东西,效率比可读性和结构性更重要吧。

  有任何问题,欢迎随时交流。
  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐