完成时间:2012年
目的和意义
机器人作为下棋一方和人对弈,机器人先手,按照五子棋规则,双方轮流落子,机器人根据棋局选择最佳落子点,系统能够判断胜负。通过此项目熟悉LEGO NXT编程、电机控制,搭建二维移动机构。基本原则:只使用LEGO8547模块和常见的LEGO零件,不使用LEGO 之外的特殊零件,一是符合LEGO 玩家DIY精神,二是便于其他玩家模仿和实现。
使用零件:LEGO8547马达三个,触碰传感器两个,颜色传感器一个,常用零件若干。
编程平台:ROBOTC for LEGO NXT(使用C语言)
主要模块及设计思路
棋盘、棋子
功能:模拟五子棋。
从下棋体验角度来说,应该选择真实的五子棋棋盘和棋子,实际并没有这么做。主要因为五子棋并非LEGO配件,五子棋的棋盘和棋子尺寸也没有统一的规格,不利于项目的标准化,也不利于大家的仿制。
我用LEGO 常用的plate零件搭了一个棋盘,棋子用的是比较容易买到的塑料小球,尺寸和LEGO中的足球、篮球零件基本相当, 稍小于两个LEGO单位。棋盘每一格是两个LEGO单位。 由于齿条数量和线缆长度的限制,只做了非标准的10*10格的棋盘(标准棋盘15*15格),棋盘尺寸不影响机功能和算法的实现,如果棋盘规模改变,调整程序中的相应参数即可。
移动模块
功能:机器人的平面移动机构,负责将棋子移动到棋盘的指定位置。
机器人的移动不难设计。 最简单的方案当然是水平和竖直方向上各由一个马达驱动。
关键问题是如何精确定位到棋盘中的每一格。虽然LEGO NXT中的电机自带角度传感器,不过精度不高,而且运行距离比较长和速度比较快的情况下,累计误差较大。
一种代替方案是利用两个颜色传感器识别棋盘格子线条实现定位,经过测试,这种方法精确度和速度都比较好,但8547中只有一个颜色传感器,还要用来识别棋子的颜色,所以不可行。
最终方案用了两个触碰传感器来实现X、Y轴方向上的定位,也就是在棋盘周围放置定位销(图1中标注所示)。这种方法的缺点是额外增加了结构,如果棋盘尺寸增加,定位销也要相应增加,而且不如采用颜色传感器的方法精度高,好在落子位置对精度要求不是很高,只要不影响棋子的落点和对棋子颜色的识别即可。
落子模块
功能:保存一定数量的棋子,每次释放一个棋子。
落子装置不是机器人的核心部分,但这个模块反复设计和修改多次,从装小球的容器到释放小球动作试验了好多方案。
第一个问题是装小球的空间不能太小,因为小球比真实的棋子要厚,如果只是简单地垂直放一列,5个小球摞在一起就达到10个LEGO单位了。我的做法是设计一个漏斗形状的空间,漏斗下端可以并排容纳两个小球,漏斗上部可以并排放下4个小球,从宽端到窄端的连接部分做一个斜面。这样大约可以容纳15个棋子。如果棋子用尽,可以手动添加。另一个设计方案(没有实现,不过应该不难):在起始位置放置一个大容量的小球存储装置,每次归位的时候,可以从中添加小球,如图2所示。
比起容量限制,更棘手的问题是如何保证释放小球的稳定性,每次操作做到必须释放一个小球,常见的问题是挤在一起的小球会卡住,下面的小球已经放出去了,上面的小球因为相互挤在一起掉不下去。我采用的结构是容器的出口放置一个可旋转的十字扇叶机构(图3)。扇叶旋转90度释放一个小球,同时起到搅拌小球防止卡住的作用。
计算模块
功能:根据棋局状态,计算落子点,并判定胜负。
这部分相对简单,只要实现五子棋算法即可,在计算落子点的时候没有采用特别复杂的算法,只用了最简单的回溯算法,毕竟NXT的处理器能力有限,而且本项目的重点不在“棋力”上。
输入模块
功能:识别棋盘状态。
最初的想法是通过电脑连接摄像头识别棋局,优点是可以“看到”棋盘状态,不过最终没有采用。一是因为有人已经实现该方案,再重复没什么意思;二是机器人将变得复杂,和电脑、摄像头耦合在一起,增加了系统复杂度;第三,也是更重要的,利用电脑进行识别运算,NXT的主控模块就成为单纯的执行控制机构,成了一个有头无脑的纯机械了,NXT内置的处理器和存储空间应该可以完成更高级的工作。
NXT中包含一个颜色传感器,在只有一个颜色传感器的情况下,只能一格一格地扫描棋盘来找到新的落子。这种方式相比摄像头图像识别,肯定要慢得多。不过也有一定的优化空间,比如在正常情况下,有些格子不可能是落子点,也就是可以预判对手的落子点,优先扫描这些可能的落子点,一旦发现新棋子就可以结束扫描过程。剩下的问题就是在程序中存储棋局状态,具体实现可以参看代码部分。
NXT端代码
#pragma config(Sensor, S1, humanPort, sensorTouch)
#pragma config(Sensor, S2, colorPort, sensorCOLORFULL)
#pragma config(Sensor, S3, touchPortX, sensorTouch)
#pragma config(Sensor, S4, touchPortY, sensorTouch)
#pragma platform(NXT)
///////////////////////////////////////////////////////////////////////////////////////
//---------------------------------------------------------
// system configuration
//
//---------------------------------------------------------
const byte motorX=motorA; // control move in X Axle
const byte motorY=motorB;
const byte motorChess=motorC; // control drop chessman
const byte positiveDirection=1;
const byte negativeDirection=-1;
//-----------------------------------
// system function
void initSystem();
void waitMotorMoveFinish();
void waitDropChessFinish();
//---------------------------------------------------------
// chess configuration and fuction
//
//---------------------------------------------------------
const byte noChessman=0;
const byte PlayerRobot=REDCOLOR;
const byte playerHuman=GREENCOLOR;
const byte chessBoardDimension=10;
const byte withdrawGrids=3;
typedef struct
{
byte X;
byte Y;
} Point;
Point latestHumanChessPoint;
Point latestRobotChessPoint;
Point robotBestDropPoint;
Point humanBestDropPoint;
byte motorXPower=-90;
byte motorXCalibrationPower=-30;
byte motorYPower=90;
byte motorYCalibrationPower=30;
byte lastXDireciton=1;
byte lastYDireciton=1;
// the lengh of chess board in X Axle
//int chessBoardYDimension=10;
// the lengh of chess board in Y Axle
byte colorSensorRelativeX=1;
byte colorSensorRelativeY=0;
byte currentX;
byte currentY;
byte targetX;
byte targetY;
int dropOneChessmanEncoder=350;
byte dropChessmanMotorPower=40;
//---------------------------------
void initChess();
bool confirmChessmanReady();
void dropOneChessman();
void lockChessman();
void dropOneChessmanAt(byte X, byte Y);
byte checkChessmanColor(byte X , byte Y); // check the color of chessman in certain position
//bool findHumanChessmanInRange(byte XStart , byte YStart , byte XEnd, byte YEnd);
bool findChessman(byte x,byte y); // find human's chessman
bool searchHumanChessman();
void moveTo(byte x , byte y);
bool moveOneXGrid(byte direction);
void calibrateXMove(byte direction);
bool moveOneYGrid(byte direction);
void calibrateYMove(byte direction);
void withdraw();
void waitHumanDrop();
//---------------------------------------------------------
// chess algorithm
//---------------------------------------------------------
/*
chessBoard, 0 no chessman, 1 Red color robot, 2 others color human
the index [0][0] of this array means out of chessboard.
*/
byte chessBoard[chessBoardDimension+1][chessBoardDimension+1];
byte data1[chessBoardDimension+1][chessBoardDimension+1];
byte data2[chessBoardDimension+1][chessBoardDimension+1];
byte data3[chessBoardDimension+1][chessBoardDimension+1];
byte data4[chessBoardDimension+1][chessBoardDimension+1];
byte data5[chessBoardDimension+1][chessBoardDimension+1];
byte data6[chessBoardDimension+1][chessBoardDimension+1];
byte data7[chessBoardDimension+1][chessBoardDimension+1];
byte data8[chessBoardDimension+1][chessBoardDimension+1];
byte topBorder=1;
byte bottomBorder=chessBoardDimension;
byte leftBorder=chessBoardDimension;
byte rightBorder=1;
byte getChessAtBoard(byte x,byte y);
bool checkChessResult(byte player) ;
void CalGameSatus(byte player);
void GetBestDropPoint();
void getChessmanBorder();
void test();
//-----------------------------------------------------------
//sub task for robot move
//-----------------------------------------------------------
/*
move robot in X axle.
*/
task moveX( ){
byte dist;
while(true){
NXTDisplayTextLine(3,"cur x: %d", currentX);//debug
dist=targetX-currentX;
if(dist!=0){// should move
byte d=dist/abs(dist); //direction
for(byte i=0;i<abs(dist);){
if( moveOneXGrid(positiveDirection*d) ){
if( SensorValue(touchPortX)==0 ){
PlaySound(soundBeepBeep);//debug
//calibrateXMove(positiveDirection*d);
}
currentX=currentX+d;
i++;
PlaySound(soundBlip); //debug
}else{
}
}
}
//wait1Msec(50);
}
}
/*
move robot in Y axle.
*/
task moveY(){
while(true){
byte dist=targetY-currentY;
if(dist!=0){
byte d=dist/abs(dist); //direction
for(byte i=0;i<abs(dist);){
if ( moveOneYGrid(positiveDirection*d) ){
if( SensorValue(touchPortY)==0 ){
PlaySound(soundBeepBeep);
//calibrateYMove(positiveDirection*d);
}
currentY=currentY+d;
i++;
PlaySound(soundBlip); //debug
}else{
}
}
}
//wait1Msec(50);
}//while
}
//---------------------------------------------------------
// main task
//---------------------------------------------------------
task
main ()
{
initSystem();
initChess();
StartTask(moveX);
StartTask(moveY);
//test();
int k=1;
while(false){
for(;k<6;k++){
moveTo(k,0);
wait1Msec(200);
}
wait1Msec(100);
if(k==6) k=1;
wait1Msec(100);
}
dropOneChessmanAt(5,5);
withdraw();
while(true){
NXTDisplayTextLine(3,"x: %d", currentX);
NXTDisplayTextLine(4,"Y: %d", currentY);
wait1Msec(500);
PlaySound(soundShortBlip);
waitHumanDrop();
if( searchHumanChessman()){
}else{
};
if( checkChessResult(playerHuman)==true ){ // human win?
PlaySound(soundDownwardTones);
moveTo(1,0);
StopAllTasks();
}
GetBestDropPoint(); // compute drop point for robot
dropOneChessmanAt(robotBestDropPoint.X,robotBestDropPoint.Y);
if( checkChessResult(playerRobot)==true ){ // robot win?
PlaySound(soundDownwardTones);
moveTo(1,0);
StopAllTasks();
}
withdraw();
}
}
void test(){
chessBoard[5][3]=PlayerRobot;
chessBoard[5][2]=playerHuman;
searchHumanChessman();
}
//---------------------------------------------------------
// system function
//---------------------------------------------------------
void initSystem(){
nNXTButtonTask = -2; // Grab control of the buttons.
nNXTExitClicks = 3; // Triple clicking EXIT button will terminate program
nMotorPIDSpeedCtrl[motorA] = mtrSpeedReg;
nMotorPIDSpeedCtrl[motorB] = mtrSpeedReg;
// nMotorPIDSpeedCtrl[motorC] = mtrSpeedReg;
bFloatDuringInactiveMotorPWM = false; // brake when no power
}
void waitDropChessFinish( ){
while( nMotorRunState[motorChess] == runStateRunning ){
//wait1Msec(50);
//playsound(soundBlip); // debug
}
return;
}
//---------------------------------------------------------
// chess function
//---------------------------------------------------------
void initChess(){
// init chess board, no chessman on chessboard.
for(int m=1;m<chessBoardDimension;m++){
for(int n=1;n<chessBoardDimension;n++){
chessBoard[m][n]=noChessman;
}
}
//start
currentX=1;
targetX=1;
currentY=0;
targetY=0;
//check x y touch in border.
while(sensorValue(touchPortX)!=1 ){
PlaySound(soundException);
wait1Msec(3000);
}
//wait1Msec(1000);
while(sensorValue(touchPortY)!=1){
PlaySound(soundLowBuzz);
wait1Msec(3000);
}
lockChessman(); // set in lock status.
// confirmChessmanReady(); // put chessman in loader.
}
void moveTo(byte x , byte y){
targetX=x;
targetY=y;
while(currentX!=targetX || currentY!=targetY){
wait1Msec(600);
//wait
}
return;
//waitMotorMoveFinish();
}
/*
move motor in X Axle. direction is based on the chessboard.
the direction can be reserve via setting motorX and motorY power.
Note!!!!, this function is blocked. it should be called in a task() in unblocked circumstance.
*/
bool moveOneXGrid(byte direction){
bool inGrid=false;
if(SensorValue(touchPortX) == 1 ){ // on grid border flag.
while(true){
motor[motorX]=motorXPower*direction;
if(!inGrid && SensorValue(touchPortX)==0){ // in grid
inGrid=true;
}
if(inGrid && SensorValue(touchPortX) == 1 ){ // reach the next border flag.
motor[motorX]=0;
inGrid=false;
lastXDireciton=direction;
break;
}
}////while();
return true;
// wait1Msec(50);
// check whether on border flag, if not, calibration, avoiding move too fast to pass border
}else{
calibrateXMove(lastXDireciton);
return false;
}
}///////////////////////////////////////
/*
refer moveOneXGrid(int direction)
*/
bool moveOneYGrid(byte direction){
bool inGrid=false;
if(SensorValue(touchPortY) == 1 ){ // on grid border flag.
while(true){
motor[motorY]=motorYPower*direction;
if(!inGrid && SensorValue(touchPortY)==0){ // in grid
inGrid=true;
}
if(inGrid && SensorValue(touchPortY) == 1 ){ // reach the next border flag.
inGrid=false;
lastYDireciton=direction;
motor[motorY]=0; // stop
break;
}
//wait1Msec(100);
}////while();
return true;
}else{
calibrateYMove(lastYDireciton);
return false;
}
}///////////////////////////////////////
void calibrateXMove(byte direction){
PlaySound(soundException); // debug
motor[motorX]=-motorXCalibrationPower*direction; // go back
while(SensorValue(touchPortX) == 0){ // until go back to grid flag
}
motor[motorX]=0;
}
void calibrateYMove(byte direction){
PlaySound(soundException); // debug
motor[motorY]=-motorYCalibrationPower*direction; // go back
while(SensorValue(touchPortY) == 0){ // until go back to grid flag
}
motor[motorY]=0;
}
/*
After dropping chess, robot goes back. it is not definitely necessay to go to start point,
just leaveing enough space for human's dropping.
*/
void withdraw()
{
int withdrawX=0;
byte withdrawY=0;
byte findX;
byte findY;
getChessmanBorder();
if( bottomBorder- withdrawGrids<0){
withdrawY=0;
}else{
withdrawY=bottomBorder-withdrawGrids;
}
if( bottomBorder- 2<1){
findY=1;
}else{
findY=bottomBorder-2;
}
if( findY%2==1){
if(leftBorder-2<1){
withdrawX=1;
}else{
withdrawX=leftBorder-2;
}
}else{
if(rightBorder+2>chessBoardDimension){
withdrawX=chessBoardDimension;
}else{
withdrawX=rightBorder+2;
}
}
moveTo(withdrawX+colorSensorRelativeX,withdrawY+colorSensorRelativeY);
}//function end
/*
alarm user put chessman in loader.
*/
bool confirmChessmanReady(){
bool status=false;
while(nNXTButtonPressed!=kEnterButton){
NXTDisplayCenteredTextLine(1, "press Enter if ");
NXTDisplayCenteredTextLine(3, "chessman loaded");
PlaySound(soundBeepBeep);
wait1Msec(1000);
}
status=true;
return status;
}
/*
Drop one chessman. the chessman position depends on current position.
*/
void dropOneChessman(){
nMotorEncoderTarget(motorChess)=dropOneChessmanEncoder;
motor[motorChess]=dropChessmanMotorPower; //drop one chessman
wait1Msec(300);
waitDropChessFinish( );
lockChessman();
wait1Msec(300);
waitDropChessFinish( );
//update board status
chessBoard[currentX][currentY]=PlayerRobot;
latestRobotChessPoint.X=currentX;
latestRobotChessPoint.Y=currentY;
}
void dropOneChessmanAt(byte X, byte Y){
moveTo(X,Y);
dropOneChessman();
}
/*
close loader,avoiding chessman unexpected dropping
*/
void lockChessman(){
nMotorEncoderTarget(motorChess)=-dropOneChessmanEncoder; // lock loader
motor[motorChess]=-dropChessmanMotorPower;
waitDropChessFinish( );
}
/*
check chessman color at (x,y)position.
Beucase color sensor is aside dropped chessman, the axel has to be revised.
In other words, snesor positive is relative to drop position.
*/
byte checkChessmanColor(byte X , byte Y){
moveTo(X+colorsensorRelativeX,Y+colorsensorRelativeY);
return (byte)SensorValue[colorPort] ;
}
/*
scan color in certain range.
*/
bool findHumanChessmanInRange(byte XStart , byte YStart , byte XEnd, byte YEnd){
for(byte m=YStart;m<=YEnd;m++){
if(m%2==1){ // in odd row
for(byte n=XStart;n<=XEnd;n++){
byte color = checkChessmanColor(n,m);
if ( color==playerHuman && chessBoard[n][m]==noChessman){ // find new human chessman
PlaySound(soundBeepBeep);//debug
chessBoard[n][m]=playerHuman; //update chessboard status
latestHumanChessPoint.X=n;
latestHumanChessPoint.Y=m;
return true;
}
}
}
if(m%2==0){ // in even row
for(byte n=XEnd;n>=XStart;n--){
byte color = checkChessmanColor(n,m);
if ( color==playerHuman && chessBoard[n][m]==noChessman ){ // find new human chessman
PlaySound(soundBeepBeep);//debug
chessBoard[n][m]=playerHuman; //update chessboard status
latestHumanChessPoint.X=n;
latestHumanChessPoint.Y=m;
return true;
}
}
}
}// each row
return false;
}
void getChessmanBorder(){
for(int y=1;y<=chessBoardDimension;y++){
for(int x=1;x<=chessBoardDimension;x++){
if(chessBoard[x][y]!=noChessman){
if(leftBorder>x){
leftBorder=x;
}
if(rightBorder<x){
rightBorder=x;
}
if(topBorder<y){
topBorder=y;
}
if(bottomBorder>y){
bottomBorder=y;
}
}
}
}
}
bool findChessman(byte x, byte y){
byte color = checkChessmanColor(x,y);
if ( color==playerHuman && chessBoard[x][y]==noChessman){ // find new human chessman
PlaySound(soundBeepBeep);//debug
chessBoard[x][y]=playerHuman; //update chessboard status
latestHumanChessPoint.X=x;
latestHumanChessPoint.Y=y;
return true;
}
return false;
}
/*
Find the latest chessman dropped by human. Just search the possible position where human maybe
drop.
*/
bool searchHumanChessman( ){
for(int y=1;y<=chessBoardDimension;y++){
if(y%2==1){
for(int x=1;x<=chessBoardDimension;x++){
if(chessBoard[x][y]==noChessman){
for(byte d=-2;d<=2;d++){
if(x+d>chessBoardDimension || x+d<1){
}else{
}
if(y+d>chessBoardDimension || y+d<1){
}else{
}
if(getChessAtBoard(x+d,y)!=noChessman ||
getChessAtBoard(x,y+d)!=noChessman ||
getChessAtBoard(x+d,y+d)!=noChessman ||
getChessAtBoard(x-d,y+d)!=noChessman){
if(findChessman(x,y)){
return true;
}
}
}///d
}// no chessman
}// each x
}//////////////
if(y%2==0){
for(int x=chessBoardDimension;x>=1;x--){
if(chessBoard[x][y]==noChessman){
for(byte d=-2;d<=2;d++){
if(x+d>chessBoardDimension || x+d<1){
}else{
}
if(y+d>chessBoardDimension || y+d<1){
}else{
}
if(getChessAtBoard(x+d,y)!=noChessman ||
getChessAtBoard(x,y+d)!=noChessman ||
getChessAtBoard(x+d,y+d)!=noChessman ||
getChessAtBoard(x-d,y+d)!=noChessman){
if(findChessman(x,y)){
return true;
}
}
}///d
}// no chessman
}
}
}
return false;
}
bool findHumanChessman2( ){
byte top=0;
byte bottom=0;
byte right=0;
byte left=0;
getChessmanBorder();
if(topBorder+2>chessBoardDimension){
top=chessBoardDimension;
}else{
top=topBorder+2;
}
if(rightBorder+2>chessBoardDimension){
right=chessBoardDimension;
}else{
right=rightBorder+2;
}
if(leftBorder-2<1){
left=1;
}else{
left=leftBorder-2;
}
if(bottomBorder-2<1){
bottom=1 ;
}else{
bottom=bottomBorder-2;
}
return findHumanChessmanInRange(left,bottom,right,top);
}
//---------------------------------------------------------
// chess algorithm
//---------------------------------------------------------
/*
retrieve chessman at chessboard, avoid index out at array.
*/
byte getChessAtBoard(byte x,byte y){
byte iX=x,iY=y;
if(x>chessBoardDimension){
iX=chessBoardDimension;
}
if(y>chessBoardDimension){
iY=chessBoardDimension;
}
if(x<1){
iX=1;
}
if(y<1){
iY=1;
}
return chessBoard[iX][iY];
}
/*
check whether the player is winner.
*/
bool checkChessResult(byte player)
{
int x, y;
// hori
for ( y = 1; y <=chessBoardDimension; y++ )
{
for ( x = 1; x <= chessBoardDimension-4; x++ )
{
if ( player ==chessBoard[x][y] &&
player ==chessBoard[x+1][y] &&
player ==chessBoard[x+2][y] &&
player ==chessBoard[x+3][y] &&
player ==chessBoard[x+4][y] )
return true;
}
}
// vertical direction
for ( y = 1; y <= chessBoardDimension-4; y++ )
{
for ( x = 1; x <= chessBoardDimension; x++ )
{
if ( player ==chessBoard[x][y] &&
player ==chessBoard[x][y+1] &&
player ==chessBoard[x][y+2] &&
player ==chessBoard[x][y+3] &&
player ==chessBoard[x][y+4] )
return true;
}
}
// "\" direction
for ( y = 1; y <= chessBoardDimension-4; y++ )
{
for ( x = 1; x <= chessBoardDimension-4; x++ )
{
if ( player ==chessBoard[x][y]&&
player ==chessBoard[x+1][y+1] &&
player ==chessBoard[x+2][y+2]&&
player ==chessBoard[x+3][y+4]&&
player ==chessBoard[x+4][y+4] )
return true;
}
}
// "/" direction
for ( y = 1; y <= chessBoardDimension-4; y++ )
{
for ( x = 4; x <= chessBoardDimension; x++ )
{
if ( player ==chessBoard[x][y] &&
player ==chessBoard[x-1][y+1] &&
player ==chessBoard[x-2][y+2] &&
player ==chessBoard[x-3][y+3] &&
player ==chessBoard[x-4][y+4] )
return true;
}
}
return false;
}
/*
calculate status for one player according to dropped chessman.
*/
void CalGameSatus(byte player)
{
byte a,b,c,d;
for(a=1;a<=chessBoardDimension;a++)
{
for(b=1;b<=chessBoardDimension;b++)
{
if(chessBoard[a][b]==noChessman)
{
d=0;
for(c=1;c<5;c++)
{
if(a-c<=0) // left border
break;
if(chessBoard[a-c][b]!=player)//left
break;
else
d++;
}
for(c=1;c<5;c++)
{
if( a+c>chessBoardDimension)
break;
if(chessBoard[a+c][b]!=player) //right
break;
else
d++;
}
data1[a][b]=d%4; // save in horizon data
data2[a][b]=d/4;
d=0;
for(c=1;c<5;c++)
{
if(b-c<=0)
break;
if(chessBoard[a][b-c]!=player) //top
break;
else
d++;
}
for(c=1;c<5;c++)
{
if(b+c>chessBoardDimension)
break;
if(chessBoard[a][b+c]!=player)
break;
else
d++;
}
data3[a][b]=d%4; // vertical
data4[a][b]=d/4;
d=0;
for(c=1;c<5;c++)
{
if( b-c==0||a-c==0)
break;
if(chessBoard[a-c][b-c] !=player) //left top
break;
else
d++;
}
for(c=1;c<5;c++)
{
if(b+c>chessBoardDimension||a+c>chessBoardDimension)
break;
if( chessBoard [a+c][b+c]!=player )
break;
else
d++;
}
data5[a][b]=d%4; // "\"
data6[a][b]=d/4;
d=0;
for(c=1;c<5;c++)
{
if( a-c<=0 || b+c>chessBoardDimension)
break;
if(chessBoard[a-c][b+c]!=player ) //left bottom
break;
else
d++;
}
for(c=1;c<5;c++)
{
if( a+c>chessBoardDimension || b-c<=0)
break;
if(chessBoard[a+c][b-c]!=player) //right bottom
break;
else
d++;
}
data7[a][b]=d%4; // "/"
data8[a][b]=d/4;
}
}
}
}
/*
get the best drop point
*/
void GetBestDropPoint( )
{
long totalMark,maxMark=0;
long markTransform[5]={0,100,400,2000,10000};
byte m,n,p;
int mark;
long humanMaxMark=0;
long robotMaxMark=0;
CalGameSatus(PlayerRobot);
for(m=1;m<=chessBoardDimension;m++)
{
for(n=1;n<=chessBoardDimension;n++)
{
totalMark=0;
mark = data1[m][n]+4*data2[m][n];
totalMark+= markTransform[mark];
mark = data3[m][n]+4*data4[m][n];
totalMark+= markTransform[mark];
mark = data5[m][n]+4*data6[m][n];
totalMark+= markTransform[mark];
mark = data7[m][n]+4*data8[m][n];
totalMark+= markTransform[mark];
if(totalMark>maxMark)
{
robotBestDropPoint.X=m;
robotBestDropPoint.Y=n;
maxMark=totalMark;
robotMaxMark=maxMark;
}
}
}// robot player
// for humnan player
CalGameSatus(playerHuman);
for(m=1;m<=chessBoardDimension;m++)
{
for(n=1;n<=chessBoardDimension;n++)
{
totalMark=0;
mark = data1[m][n]+4*data2[m][n];
totalMark+= markTransform[mark];
mark = data3[m][n]+4*data4[m][n];
totalMark+= markTransform[mark];
mark = data5[m][n]+4*data6[m][n];
totalMark+= markTransform[mark];
mark = data7[m][n]+4*data8[m][n];
totalMark+= markTransform[mark];
if(totalMark>maxMark)
{
humanBestDropPoint.X=m;
humanBestDropPoint.Y=n;
maxMark=totalMark;
humanMaxMark=maxMark;
}
}
}// human player
if(humanMaxMark>robotMaxMark){ // defense or attack according to each maxMark
robotBestDropPoint.X=humanBestDropPoint.X;
robotBestDropPoint.Y=humanBestDropPoint.Y;
}
}////////////////////////////////////////////
/*
wait human drop, when has dropped, human should press touch to tell robot.
*/
void waitHumanDrop(){
while( SensorValue(humanPort) == 0 ){
wait1Msec(200);
}
PlaySound(soundBeepBeep);
return ;
}
近期评论