- 浏览: 51259 次
- 性别:
- 来自: 上海
最新评论
五子棋算法注释非常详细,供大家开发时候参考。此源码是收集的网上最流行也是免费的五子棋源码。
private Dot to4B(int player)
{//活四 棋型的实现
if(playerCounter[player] < 3)//如果该方下的棋子小于3,则不进行检测
return null;
Dot dot = null;
int maxGain = 0;//对某位置进行评分
for(int r = 1; r < boardSize - 1; r++)
{
for(int c = 1; c < boardSize - 1; c++)
if(table[r][c] == 0)//如果该位置为空白,则检测是否实现“活四”
{
int cd[] = connectedIn8D(player, r, c);//检测同类棋子在8个方向上的连续数目
int ed[] = expandedIn8D(player, r, c);//检测同类棋子和空白在8个方向上的连续数目
for(int i = 0; i < 4; i++)
if(ed[i] > cd[i] && ed[i + 4] > cd[i + 4] && cd[i] + cd[i + 4] + 1 >= 4)
{//如果活四
int gain = gainAt(r, c);//计算在该位置的得分,及对己方的有利程度
if(gain > maxGain || gain > 0 && gain == maxGain && randomTrue())
{
maxGain = gain;//保留最大分值的点,如果得分相同则随机选着
dot = new Dot(r, c);
}
}
}
}
return dot;
}
private Dot toSingle4S_3B_2N1B(int player)
{
if(playerCounter[player] < 2)
return null;
Dot dot = null;
for(int r = 0; r < boardSize; r++)
{
for(int c = 0; c < boardSize; c++)
{
if(table[r][c] != 0 || find4S_3B_2N1BAt(r, c, player, -1) == -1)
continue;
dot = new Dot(r, c);
break;
}
if(dot != null)
break;
}
return dot;
}
private Dot toDouble4S_3B_2N1B(int player, boolean only4S)
{
if(playerCounter[player] < 4)
return null;
Dot dot = null;
for(int rTest = 0; rTest < boardSize; rTest++)
{
for(int cTest = 0; cTest < boardSize; cTest++)
{
if(table[rTest][cTest] != 0)
continue;
int cd[] = connectedIn8D(player, rTest, cTest);
if(cd[0] + cd[1] + cd[2] + cd[3] + cd[4] + cd[5] + cd[6] + cd[7] <= 0)
continue;
triedDot.setRowCol(rTest, cTest);
table[rTest][cTest] = player;
boolean found = false;
int dFirst = find4S_3B_2N1B(player, -1, rTest, cTest, only4S);
if(dFirst != -1 && find4S_3B_2N1B(player, dFirst, rTest, cTest, false) != -1)
found = true;
table[rTest][cTest] = 0;
triedDot.setRowCol(-1, -1);
if(!found)
continue;
dot = new Dot(rTest, cTest);
break;
}
if(dot != null)
break;
}
return dot;
}
private int find4SAt(int row, int col, int player, int exceptDirection)
{
int dFond = -1;
int cd[] = connectedIn8D(player, row, col);
int ed[] = expandedIn8D(player, row, col);
for(int d = 0; d < 4; d++)
{
if(d == exceptDirection || table[row][col] != player)
continue;
int nConnect = cd[d] + cd[d + 4] + 1;
int nFree1 = ed[d] - cd[d];
int nFree2 = ed[d + 4] - cd[d + 4];
boolean b4S = nConnect >= 4 && (nFree1 >= 1 || nFree2 >= 1);
if(!b4S)
continue;
dFond = d;
break;
}
return dFond;
}
private int find4S_3B_2N1BAt(int row, int col, int player, int exceptDirection)
{
int dFond = -1;
int cd[] = connectedIn8D(player, row, col);
int ed[] = expandedIn8D(player, row, col);
for(int d = 0; d < 4; d++)
{
if(d == exceptDirection)
continue;
if(table[row][col] == player)
{
int nConnect = cd[d] + cd[d + 4] + 1;
int nFree1 = ed[d] - cd[d];
int nFree2 = ed[d + 4] - cd[d + 4];
boolean b4S = nConnect >= 4 && (nFree1 >= 1 || nFree2 >= 1);
boolean b3B = nConnect >= 3 && nFree1 >= 1 && nFree2 >= 1;
if(b4S || b3B)
{
dFond = d;
break;
}
}
if(table[row][col] != 0)
continue;
int nFree1 = ed[d] - cd[d];
int nFree2 = ed[d + 4] - cd[d + 4];
boolean b2N1 = cd[d] >= 2 && cd[d + 4] >= 1 || cd[d] >= 1 && cd[d + 4] >= 2;
boolean bSFree = nFree1 >= 1 && nFree2 >= 1;
if(!b2N1 || !bSFree)
continue;
dFond = d;
break;
}
return dFond;
}
private int find4S_3B_2N1B(int player, int exceptDirection, int rTest, int cTest, boolean only4S)
{
int dFond = -1;
int rMin = rTest - 3;
if(rMin < 0)
rMin = 0;
int rMax = rTest + 3;
if(rMax > boardSize)
rMax = boardSize;
int cMin = cTest - 3;
if(cMin < 0)
cMin = 0;
int cMax = cTest + 3;
if(cMax > boardSize)
cMax = boardSize;
for(int r = rMin; r < rMax; r++)
{
for(int c = cMin; c < cMax; c++)
{
if(table[r][c] != player && table[r][c] != 0)
continue;
if(only4S)
dFond = find4SAt(r, c, player, exceptDirection);
else
dFond = find4S_3B_2N1BAt(r, c, player, exceptDirection);
if(dFond != -1)
break;
}
if(dFond != -1)
break;
}
return dFond;
}
private Dot to5L(int player)
{/*
*to5L方法将根据指定一方,在棋盘上搜索能实现连五得点,如果该方下了4步以下的棋,则不进行检测
*,在检测过程中,如果检测到多个点能实现连五则比较to5LAt()返回的整数值(该数值有两部分组成,
*每个连五得32分,可能实现连五则得2分,各个方向上得分相加),如果两点的分相同,则随机选择
*
*/
if(playerCounter[player] < 4)//如果该方只下了4步以下的棋,则不进行检测
return null;
int maxGain = 0;//得分
Dot dot = null;
for(int r = 0; r < boardSize; r++)//遍历行
{
for(int c = 0; c < boardSize; c++)//遍历列
{
int gain = to5LAt(player, r, c);//对某点的连五情况进行评分
if(gain > maxGain || gain > 0 && gain == maxGain && randomTrue())//按照评分选择落子
{
maxGain = gain;
dot = new Dot(r, c);
}
}
}
return dot;//返回落子
}
/*
* to5LAt方法在指定的位置检测是否能够完成“连五”,检测方法为统计8个方向的同类棋子数目,如果在直线上同类棋子能够超过5颗,
* 既能实现“连五”
*/
private int to5LAt(int player, int row, int col)
{
int lines = 0;
int otherGain = 0;//走该步棋的增益,衡量该步棋对己方的有利程度
if(table[row][col] == 0)
{
int cd[] = connectedIn8D(player, row, col);//检测同类棋子在8个方向上的连续数目
int ed[] = expandedIn8D(player, row, col);
for(int i = 0; i < 4; i++)
if(ed[i] + ed[i + 4] + 1 >= 5)//在某一直线上同类棋子和空白数量超过5
{
int l = cd[i] + cd[i + 4] + 1;
if(l >= 5)//判断是否出现“连五”
lines++;
else
otherGain += 2 ^ l;//该方向利于己方,增加评分
}
}
return lines > 0 ? lines * 32 + otherGain : 0;//如果存在连五则返回真
}
private int[] expandedIn8D(int player, int row, int col)
{
int ed[] = new int[8];
for(int d = 0; d < 8; d++)
ed[d] = expandedIn1D(player, row, col, d);//对指定方向进行检测
return ed;//返回检测结果
}
private int expandedIn1D(int player, int row, int col, int direction)
{/*
*对指定方向进行检测,检测的内容是同类棋子或空白区域,其中空白区域不超过4,如果棋子超出棋盘或者
*遇见对手棋子则终止检测
*/
int n = 0;//检测计数器
int cn = 0;//循环计数器
Dot d = new Dot(row, col);//根据指定位置创建棋子
while(cn < 4)
{
d.copyFrom(moveOneStep(d, direction));//将棋子朝指定的方向移动
if(!d.isInBoard(boardSize))//如果棋子超出棋盘则终止检测
break;
int p = table[d.row][d.col];//获取棋盘在该位置的状态
if(p == 0)//如果棋盘在该位置是空白
cn++;//循环计数器计数
if(p != player && p != 0)//如果遇见对手棋子则终止检测
break;
n++;//计数
}
return n;//返回检测结果
}
private Dot maxGainedDot()
{
Dot dotWithMaxGain = null;
int maxGain = 0;
for(int r = 0; r < boardSize; r++)
{
for(int c = 0; c < boardSize; c++)
{
int gain = gainAt(r, c);
if(gain > maxGain || gain > 0 && gain == maxGain && randomTrue())
{
maxGain = gain;
dotWithMaxGain = new Dot(r, c);
}
}
}
return dotWithMaxGain;
}
private int gainAt(int row, int col)
{
if(table[row][col] == 0)
{
int gain = 0;
for(int d = 0; d < 8; d++)
{
int gd = gainAtDirection(row, col, d);
if(gd == 0)
gain >>= 2;
else
gain += gd;
}
if(gain < 1)
gain = 1;
return gain;
} else
{
return 0;
}
}
private int gainAtDirection(int row, int col, int direction)
{/*
*计算指定位置在某个方向上的得分,该评分是针对计算机方有效的。
*从某个位置向某个方向逐步移动,如果遇见玩家棋子则终止检测循环
*,在移动过程中发现计算机棋子得分权重为5,遇见空白区域得分权重为1,
*该位置的得分还与移动步长有关,离出发位置越远其影响力越小,因此步长的计算公式
*为gain=(boardSize-step)/2,其中boardsize为棋盘大小,step为移动步长,计算某个方向上
*得分代码如下
*/
int gain = 0;
Dot d = new Dot(row, col);
int step = 0;
do
{
d.copyFrom(moveOneStep(d, direction));//朝指定方向上移动一个位置
step++;//步长加一
if(!d.isInBoard(boardSize))//判断该位置是否是在棋盘中,即是否合法
break;
int player = table[d.row][d.col];//获得该位置的落子状态
if(player == 2)//如果该位置玩家已经落子,则终止循环
break;
int gainByStone = player == 1 ? 5 : 1;//设置权重,机方落子权重为5,空白区域落子权重为1
gain += gainByStep(step) * gainByStone;//计算机评分
} while(true);
return gain;//返回在指定位置落子朝指定方向上得分
}
private int gainByStep(int step)
{
int gain = (boardSize - step) / 2;//计算步长得分
if(gain < 1)
gain = 1;//得分最小为1
return gain;//返回移动步长得出的分数
}
private int exist2N1(int row, int col, int player, int exceptDirection)
{
int cd[] = connectedIn8D(player, row, col);
int ed[] = expandedIn8D(player, row, col);
int existDirection = -1;
for(int i = 0; i < 4; i++)
{
if(i == exceptDirection || (cd[i] < 2 || cd[i + 4] < 1) && (cd[i] < 1 || cd[i + 4] < 2) || (ed[i] - cd[i]) + (ed[i + 4] - cd[i + 4]) <= 0)
continue;
existDirection = i;
break;
}
return existDirection;
}
private int checkFiveInRow(int row, int col, int n, int exceptDirection)
{
int player = table[row][col];//获取该位置的落子状态
int cd[] = connectedIn8D(player, row, col);//检测8个方向上同类棋子的落子数目
int ed[] = expandedIn8D(player, row, col);//检测8个方向上同类棋子及空白的落子个数
int existDirection = -1;//检测出的连珠方向
for(int i = 0; i < 4; i++)
{
if(i == exceptDirection || cd[i] + cd[i + 4] + 1 < n || (ed[i] - cd[i]) + (ed[i + 4] - cd[i + 4]) < 0)
continue;
existDirection = i;//存在五子连珠情况
break;//终止循环
}
return existDirection;//返回检测出的方向
}
private int[] connectedIn8D(int player, int row, int col)
{
/*
*connectedIn8D对8个方向上都进行检测并用整形数组记录
*
*/
int cd[] = new int[8];//用来记录8个方向同类棋子情况的数组
for(int d = 0; d < 8; d++)
cd[d] = connectedIn1D(player, row, col, d);//对指定方向进行检测
return cd;
}
private int connectedIn1D(int player, int row, int col, int direction)
{
/*
* connectedIn1D方法用于检测棋盘上任意一点在指定的方向上的同类棋子相连的个数,传入落子
* 方标志(区分计算机还是玩家),检测位置的行列坐标和检测方向,返回在该方向上相连棋子的个数
* (若检测到对方棋子或者空白棋面则停止检测)。
*/
int n = 0;
Dot d = new Dot(row, col);//在当前位置创建棋子
do
{
d.copyFrom(moveOneStep(d, direction));//返回在指定方向上移动后的棋子
if(d.isInBoard(boardSize) && table[d.row][d.col] == player)
//移动后依然在棋盘上并有同类棋子
n++;//计数器加一
else
return n;//当棋子超出棋盘或者检测到对方棋子或空白区域时停止检测
} while(true);
}
private Dot moveOneStep(Dot d, int direction)//朝8个方向移动一步的moveOneStep方法,传入当前棋子和移动方向,返回移动之后的棋子
{
int r = d.row;
int c = d.col;
switch(direction)
{
case 0: //右方
c++;
break;
case 1: //右上方
r--;
c++;
break;
case 2: //上方
r--;
break;
case 3: //左上方
r--;
c--;
break;
case 4: //左方
c--;
break;
case 5: //左下方
r++;
c--;
break;
case 6: //下方
r++;
break;
case 7: //右下方
r++;
c++;
break;
}
return new Dot(r, c);//返回移动后的棋子
}
private boolean randomTrue()
{
return rndNum.nextInt() % 2 == 0;//返回随机的布尔值
}
电脑每次下棋,按照顺序(能连成五子,能连成四子、三子)检测落子位置,
如果那些方法没找到合适的落子位置,根据点的分数落子,然后判断是否赢了,
然后该人下了
选择性参考一下
//构造函数(画布,棋盘大小,谁先落子,难度)
public FIRLogic(FIRCanvas canvas, int boardSize, boolean isComputerFirst, int degree)
//落子(行,列,哪方落)
private void goAt(int row, int col, int player)
//悔棋
public boolean undo()
//某一点在特定方向的同类棋子的个数(哪一方,行,列,方向)
connectedIn1D(int player, int row, int col, int direction)
//某一点在八个方向上的同类棋子的个数的数组
private int[] connectedIn8D(int player, int row, int col)
//某一点在特定方向的同类棋子或空位的个数(哪一方,行,列,方向)
expandedIn1D(int player, int row, int col, int direction)
//某一点在特定方向的同类棋子或空位的个数的数组(哪一方,行,列,方向)
private int[] expandedIn8D(int player, int row, int col)
//判断胜利的方法,是否五子相连
private int checkFiveInRow(int row, int col, int n, int exceptDirection)
//某一方某个点(row,col)能否实现连五
private int to5LAt(int player, int row, int col)
//根据to5LAt()返回其中一个可以实现连五的点
private Dot to5L(int player)
//在direction方向上对点进行评分(当条件相同时,以分数来决定落子)
gainAtDirection(int row, int col, int direction)
//对某点的分数进行汇总(gainAtDirection()遍历)
gainAt(int row, int col)
//寻找活四的点(活四:有两个点可以形成连五的状态)
to4B(int player)
//寻找能冲四、活三的点
toSingle4S_3B_2N1B(int player)
//#%*$^*^*&(&&--------- ^.^
toDouble4S_3B_2N1B(int player, boolean only4S)
//只找冲四的点。能形成五子相連的四子叫 活四或冲四(活四:有两个点可形成五子相连 。冲四:只有一个点)
find4SAt(int row, int col, int player, int exceptDirection)
//某点某方向是否存在冲四、活三的可能
find4S_3B_2N1BAt(int row, int col, int player,int exceptDirection)
//寻找一个点,满足find4S_3B_2N1BAt()方法
find4S_3B_2N1B(int player, int exceptDirection, int rTest,
int cTest, boolean only4S)
//最佳落子点(有得分计算出来)
maxGainedDot()
private Dot to4B(int player)
{//活四 棋型的实现
if(playerCounter[player] < 3)//如果该方下的棋子小于3,则不进行检测
return null;
Dot dot = null;
int maxGain = 0;//对某位置进行评分
for(int r = 1; r < boardSize - 1; r++)
{
for(int c = 1; c < boardSize - 1; c++)
if(table[r][c] == 0)//如果该位置为空白,则检测是否实现“活四”
{
int cd[] = connectedIn8D(player, r, c);//检测同类棋子在8个方向上的连续数目
int ed[] = expandedIn8D(player, r, c);//检测同类棋子和空白在8个方向上的连续数目
for(int i = 0; i < 4; i++)
if(ed[i] > cd[i] && ed[i + 4] > cd[i + 4] && cd[i] + cd[i + 4] + 1 >= 4)
{//如果活四
int gain = gainAt(r, c);//计算在该位置的得分,及对己方的有利程度
if(gain > maxGain || gain > 0 && gain == maxGain && randomTrue())
{
maxGain = gain;//保留最大分值的点,如果得分相同则随机选着
dot = new Dot(r, c);
}
}
}
}
return dot;
}
private Dot toSingle4S_3B_2N1B(int player)
{
if(playerCounter[player] < 2)
return null;
Dot dot = null;
for(int r = 0; r < boardSize; r++)
{
for(int c = 0; c < boardSize; c++)
{
if(table[r][c] != 0 || find4S_3B_2N1BAt(r, c, player, -1) == -1)
continue;
dot = new Dot(r, c);
break;
}
if(dot != null)
break;
}
return dot;
}
private Dot toDouble4S_3B_2N1B(int player, boolean only4S)
{
if(playerCounter[player] < 4)
return null;
Dot dot = null;
for(int rTest = 0; rTest < boardSize; rTest++)
{
for(int cTest = 0; cTest < boardSize; cTest++)
{
if(table[rTest][cTest] != 0)
continue;
int cd[] = connectedIn8D(player, rTest, cTest);
if(cd[0] + cd[1] + cd[2] + cd[3] + cd[4] + cd[5] + cd[6] + cd[7] <= 0)
continue;
triedDot.setRowCol(rTest, cTest);
table[rTest][cTest] = player;
boolean found = false;
int dFirst = find4S_3B_2N1B(player, -1, rTest, cTest, only4S);
if(dFirst != -1 && find4S_3B_2N1B(player, dFirst, rTest, cTest, false) != -1)
found = true;
table[rTest][cTest] = 0;
triedDot.setRowCol(-1, -1);
if(!found)
continue;
dot = new Dot(rTest, cTest);
break;
}
if(dot != null)
break;
}
return dot;
}
private int find4SAt(int row, int col, int player, int exceptDirection)
{
int dFond = -1;
int cd[] = connectedIn8D(player, row, col);
int ed[] = expandedIn8D(player, row, col);
for(int d = 0; d < 4; d++)
{
if(d == exceptDirection || table[row][col] != player)
continue;
int nConnect = cd[d] + cd[d + 4] + 1;
int nFree1 = ed[d] - cd[d];
int nFree2 = ed[d + 4] - cd[d + 4];
boolean b4S = nConnect >= 4 && (nFree1 >= 1 || nFree2 >= 1);
if(!b4S)
continue;
dFond = d;
break;
}
return dFond;
}
private int find4S_3B_2N1BAt(int row, int col, int player, int exceptDirection)
{
int dFond = -1;
int cd[] = connectedIn8D(player, row, col);
int ed[] = expandedIn8D(player, row, col);
for(int d = 0; d < 4; d++)
{
if(d == exceptDirection)
continue;
if(table[row][col] == player)
{
int nConnect = cd[d] + cd[d + 4] + 1;
int nFree1 = ed[d] - cd[d];
int nFree2 = ed[d + 4] - cd[d + 4];
boolean b4S = nConnect >= 4 && (nFree1 >= 1 || nFree2 >= 1);
boolean b3B = nConnect >= 3 && nFree1 >= 1 && nFree2 >= 1;
if(b4S || b3B)
{
dFond = d;
break;
}
}
if(table[row][col] != 0)
continue;
int nFree1 = ed[d] - cd[d];
int nFree2 = ed[d + 4] - cd[d + 4];
boolean b2N1 = cd[d] >= 2 && cd[d + 4] >= 1 || cd[d] >= 1 && cd[d + 4] >= 2;
boolean bSFree = nFree1 >= 1 && nFree2 >= 1;
if(!b2N1 || !bSFree)
continue;
dFond = d;
break;
}
return dFond;
}
private int find4S_3B_2N1B(int player, int exceptDirection, int rTest, int cTest, boolean only4S)
{
int dFond = -1;
int rMin = rTest - 3;
if(rMin < 0)
rMin = 0;
int rMax = rTest + 3;
if(rMax > boardSize)
rMax = boardSize;
int cMin = cTest - 3;
if(cMin < 0)
cMin = 0;
int cMax = cTest + 3;
if(cMax > boardSize)
cMax = boardSize;
for(int r = rMin; r < rMax; r++)
{
for(int c = cMin; c < cMax; c++)
{
if(table[r][c] != player && table[r][c] != 0)
continue;
if(only4S)
dFond = find4SAt(r, c, player, exceptDirection);
else
dFond = find4S_3B_2N1BAt(r, c, player, exceptDirection);
if(dFond != -1)
break;
}
if(dFond != -1)
break;
}
return dFond;
}
private Dot to5L(int player)
{/*
*to5L方法将根据指定一方,在棋盘上搜索能实现连五得点,如果该方下了4步以下的棋,则不进行检测
*,在检测过程中,如果检测到多个点能实现连五则比较to5LAt()返回的整数值(该数值有两部分组成,
*每个连五得32分,可能实现连五则得2分,各个方向上得分相加),如果两点的分相同,则随机选择
*
*/
if(playerCounter[player] < 4)//如果该方只下了4步以下的棋,则不进行检测
return null;
int maxGain = 0;//得分
Dot dot = null;
for(int r = 0; r < boardSize; r++)//遍历行
{
for(int c = 0; c < boardSize; c++)//遍历列
{
int gain = to5LAt(player, r, c);//对某点的连五情况进行评分
if(gain > maxGain || gain > 0 && gain == maxGain && randomTrue())//按照评分选择落子
{
maxGain = gain;
dot = new Dot(r, c);
}
}
}
return dot;//返回落子
}
/*
* to5LAt方法在指定的位置检测是否能够完成“连五”,检测方法为统计8个方向的同类棋子数目,如果在直线上同类棋子能够超过5颗,
* 既能实现“连五”
*/
private int to5LAt(int player, int row, int col)
{
int lines = 0;
int otherGain = 0;//走该步棋的增益,衡量该步棋对己方的有利程度
if(table[row][col] == 0)
{
int cd[] = connectedIn8D(player, row, col);//检测同类棋子在8个方向上的连续数目
int ed[] = expandedIn8D(player, row, col);
for(int i = 0; i < 4; i++)
if(ed[i] + ed[i + 4] + 1 >= 5)//在某一直线上同类棋子和空白数量超过5
{
int l = cd[i] + cd[i + 4] + 1;
if(l >= 5)//判断是否出现“连五”
lines++;
else
otherGain += 2 ^ l;//该方向利于己方,增加评分
}
}
return lines > 0 ? lines * 32 + otherGain : 0;//如果存在连五则返回真
}
private int[] expandedIn8D(int player, int row, int col)
{
int ed[] = new int[8];
for(int d = 0; d < 8; d++)
ed[d] = expandedIn1D(player, row, col, d);//对指定方向进行检测
return ed;//返回检测结果
}
private int expandedIn1D(int player, int row, int col, int direction)
{/*
*对指定方向进行检测,检测的内容是同类棋子或空白区域,其中空白区域不超过4,如果棋子超出棋盘或者
*遇见对手棋子则终止检测
*/
int n = 0;//检测计数器
int cn = 0;//循环计数器
Dot d = new Dot(row, col);//根据指定位置创建棋子
while(cn < 4)
{
d.copyFrom(moveOneStep(d, direction));//将棋子朝指定的方向移动
if(!d.isInBoard(boardSize))//如果棋子超出棋盘则终止检测
break;
int p = table[d.row][d.col];//获取棋盘在该位置的状态
if(p == 0)//如果棋盘在该位置是空白
cn++;//循环计数器计数
if(p != player && p != 0)//如果遇见对手棋子则终止检测
break;
n++;//计数
}
return n;//返回检测结果
}
private Dot maxGainedDot()
{
Dot dotWithMaxGain = null;
int maxGain = 0;
for(int r = 0; r < boardSize; r++)
{
for(int c = 0; c < boardSize; c++)
{
int gain = gainAt(r, c);
if(gain > maxGain || gain > 0 && gain == maxGain && randomTrue())
{
maxGain = gain;
dotWithMaxGain = new Dot(r, c);
}
}
}
return dotWithMaxGain;
}
private int gainAt(int row, int col)
{
if(table[row][col] == 0)
{
int gain = 0;
for(int d = 0; d < 8; d++)
{
int gd = gainAtDirection(row, col, d);
if(gd == 0)
gain >>= 2;
else
gain += gd;
}
if(gain < 1)
gain = 1;
return gain;
} else
{
return 0;
}
}
private int gainAtDirection(int row, int col, int direction)
{/*
*计算指定位置在某个方向上的得分,该评分是针对计算机方有效的。
*从某个位置向某个方向逐步移动,如果遇见玩家棋子则终止检测循环
*,在移动过程中发现计算机棋子得分权重为5,遇见空白区域得分权重为1,
*该位置的得分还与移动步长有关,离出发位置越远其影响力越小,因此步长的计算公式
*为gain=(boardSize-step)/2,其中boardsize为棋盘大小,step为移动步长,计算某个方向上
*得分代码如下
*/
int gain = 0;
Dot d = new Dot(row, col);
int step = 0;
do
{
d.copyFrom(moveOneStep(d, direction));//朝指定方向上移动一个位置
step++;//步长加一
if(!d.isInBoard(boardSize))//判断该位置是否是在棋盘中,即是否合法
break;
int player = table[d.row][d.col];//获得该位置的落子状态
if(player == 2)//如果该位置玩家已经落子,则终止循环
break;
int gainByStone = player == 1 ? 5 : 1;//设置权重,机方落子权重为5,空白区域落子权重为1
gain += gainByStep(step) * gainByStone;//计算机评分
} while(true);
return gain;//返回在指定位置落子朝指定方向上得分
}
private int gainByStep(int step)
{
int gain = (boardSize - step) / 2;//计算步长得分
if(gain < 1)
gain = 1;//得分最小为1
return gain;//返回移动步长得出的分数
}
private int exist2N1(int row, int col, int player, int exceptDirection)
{
int cd[] = connectedIn8D(player, row, col);
int ed[] = expandedIn8D(player, row, col);
int existDirection = -1;
for(int i = 0; i < 4; i++)
{
if(i == exceptDirection || (cd[i] < 2 || cd[i + 4] < 1) && (cd[i] < 1 || cd[i + 4] < 2) || (ed[i] - cd[i]) + (ed[i + 4] - cd[i + 4]) <= 0)
continue;
existDirection = i;
break;
}
return existDirection;
}
private int checkFiveInRow(int row, int col, int n, int exceptDirection)
{
int player = table[row][col];//获取该位置的落子状态
int cd[] = connectedIn8D(player, row, col);//检测8个方向上同类棋子的落子数目
int ed[] = expandedIn8D(player, row, col);//检测8个方向上同类棋子及空白的落子个数
int existDirection = -1;//检测出的连珠方向
for(int i = 0; i < 4; i++)
{
if(i == exceptDirection || cd[i] + cd[i + 4] + 1 < n || (ed[i] - cd[i]) + (ed[i + 4] - cd[i + 4]) < 0)
continue;
existDirection = i;//存在五子连珠情况
break;//终止循环
}
return existDirection;//返回检测出的方向
}
private int[] connectedIn8D(int player, int row, int col)
{
/*
*connectedIn8D对8个方向上都进行检测并用整形数组记录
*
*/
int cd[] = new int[8];//用来记录8个方向同类棋子情况的数组
for(int d = 0; d < 8; d++)
cd[d] = connectedIn1D(player, row, col, d);//对指定方向进行检测
return cd;
}
private int connectedIn1D(int player, int row, int col, int direction)
{
/*
* connectedIn1D方法用于检测棋盘上任意一点在指定的方向上的同类棋子相连的个数,传入落子
* 方标志(区分计算机还是玩家),检测位置的行列坐标和检测方向,返回在该方向上相连棋子的个数
* (若检测到对方棋子或者空白棋面则停止检测)。
*/
int n = 0;
Dot d = new Dot(row, col);//在当前位置创建棋子
do
{
d.copyFrom(moveOneStep(d, direction));//返回在指定方向上移动后的棋子
if(d.isInBoard(boardSize) && table[d.row][d.col] == player)
//移动后依然在棋盘上并有同类棋子
n++;//计数器加一
else
return n;//当棋子超出棋盘或者检测到对方棋子或空白区域时停止检测
} while(true);
}
private Dot moveOneStep(Dot d, int direction)//朝8个方向移动一步的moveOneStep方法,传入当前棋子和移动方向,返回移动之后的棋子
{
int r = d.row;
int c = d.col;
switch(direction)
{
case 0: //右方
c++;
break;
case 1: //右上方
r--;
c++;
break;
case 2: //上方
r--;
break;
case 3: //左上方
r--;
c--;
break;
case 4: //左方
c--;
break;
case 5: //左下方
r++;
c--;
break;
case 6: //下方
r++;
break;
case 7: //右下方
r++;
c++;
break;
}
return new Dot(r, c);//返回移动后的棋子
}
private boolean randomTrue()
{
return rndNum.nextInt() % 2 == 0;//返回随机的布尔值
}
电脑每次下棋,按照顺序(能连成五子,能连成四子、三子)检测落子位置,
如果那些方法没找到合适的落子位置,根据点的分数落子,然后判断是否赢了,
然后该人下了
选择性参考一下
//构造函数(画布,棋盘大小,谁先落子,难度)
public FIRLogic(FIRCanvas canvas, int boardSize, boolean isComputerFirst, int degree)
//落子(行,列,哪方落)
private void goAt(int row, int col, int player)
//悔棋
public boolean undo()
//某一点在特定方向的同类棋子的个数(哪一方,行,列,方向)
connectedIn1D(int player, int row, int col, int direction)
//某一点在八个方向上的同类棋子的个数的数组
private int[] connectedIn8D(int player, int row, int col)
//某一点在特定方向的同类棋子或空位的个数(哪一方,行,列,方向)
expandedIn1D(int player, int row, int col, int direction)
//某一点在特定方向的同类棋子或空位的个数的数组(哪一方,行,列,方向)
private int[] expandedIn8D(int player, int row, int col)
//判断胜利的方法,是否五子相连
private int checkFiveInRow(int row, int col, int n, int exceptDirection)
//某一方某个点(row,col)能否实现连五
private int to5LAt(int player, int row, int col)
//根据to5LAt()返回其中一个可以实现连五的点
private Dot to5L(int player)
//在direction方向上对点进行评分(当条件相同时,以分数来决定落子)
gainAtDirection(int row, int col, int direction)
//对某点的分数进行汇总(gainAtDirection()遍历)
gainAt(int row, int col)
//寻找活四的点(活四:有两个点可以形成连五的状态)
to4B(int player)
//寻找能冲四、活三的点
toSingle4S_3B_2N1B(int player)
//#%*$^*^*&(&&--------- ^.^
toDouble4S_3B_2N1B(int player, boolean only4S)
//只找冲四的点。能形成五子相連的四子叫 活四或冲四(活四:有两个点可形成五子相连 。冲四:只有一个点)
find4SAt(int row, int col, int player, int exceptDirection)
//某点某方向是否存在冲四、活三的可能
find4S_3B_2N1BAt(int row, int col, int player,int exceptDirection)
//寻找一个点,满足find4S_3B_2N1BAt()方法
find4S_3B_2N1B(int player, int exceptDirection, int rTest,
int cTest, boolean only4S)
//最佳落子点(有得分计算出来)
maxGainedDot()
发表评论
-
如何解决J2ME中文的乱码问题
2010-11-02 09:54 957Java的中文问题通常会困扰很多开发者,你可能在开发Web应用 ... -
g.setClip()使用方法
2010-10-14 16:29 1807为了降低文件的大小,经常要把小图片合并成一个大图片,在屏 ... -
java.io.IOException SymbianOS error = -11
2010-10-11 09:49 998public void myFunct() { ... -
JSP,J2ME,JAVA常用源代码共享区
2010-10-08 16:53 691一个Applet(JApplet)访问数据库的例子 http: ... -
Java连接各种数据库的实例
2010-10-08 16:51 625此文中的代码主要列出连接数据库的关键代码,其他访问数据库代码省 ...
相关推荐
【J2ME五子棋源码(AI)】是一个基于Java Micro Edition (J2ME) 平台开发的五子棋游戏项目。J2ME是Java的一种轻量级版本,常用于移动设备和嵌入式系统的应用程序开发。在这个项目中,开发者已经实现了一个具有人工...
本文将深入探讨"j2me五子棋搜索算法"这一主题,它涉及到如何让计算机在五子棋游戏中展现出智能,与玩家进行对弈。五子棋是一种两人对战的策略游戏,目标是先连成五子直线(横、竖或斜)的一方获胜。在这个背景下,...
【J2ME五子棋游戏源码】是一个基于Java 2 Micro Edition(J2ME)平台开发的五子棋游戏项目。J2ME是Java的一个版本,主要用于移动设备和嵌入式系统的应用程序开发,如手机、智能手表和电视等。这款五子棋游戏的源码...
总的来说,J2ME五子棋游戏开发涵盖了移动游戏设计的多个方面,包括图形编程、事件处理、算法设计、音频处理、UI设计和性能优化等。通过这个项目,开发者可以深入理解J2ME平台并提升游戏开发技能。在"实验七"中,可能...
《J2ME五子棋游戏开发详解》 在IT领域,Java 2 Micro Edition(J2ME)是一种广泛应用于移动设备和嵌入式系统的Java平台。它为开发小型应用程序,尤其是手机游戏,提供了便利。本篇文章将深入探讨一个基于J2ME的...
【标题】"j2me五子棋源码"所涉及的知识点主要集中在Java ME(J2ME)平台上的游戏开发,特别是五子棋游戏的实现。J2ME是Java的一个子集,主要用于移动设备和嵌入式设备的编程,如手机、智能手表等。以下是对这些知识...
请通知我,我会尽快更正并在注释中将你的名字加入作者的行列(当然这一点会征求你的同意,毕竟有些人是非常低调的) 各位如果有空的话可以去看看我的开源博客www.dataozi.com,里面也许会有些你想要的东西
在J2ME五子棋项目中,AI部分可能是基于一些简单的搜索算法,如深度优先搜索(DFS)或最小最大搜索(Minimax)加上Alpha-Beta剪枝优化。这些算法模拟对手的思考过程,预测每一步的可能结果,以选择最优的走法。AI的...
j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋j2me五子棋...
【J2ME五子棋游戏源码解析】 J2ME,全称为Java 2 Micro Edition,是Java平台的一个子集,主要用于开发移动设备、嵌入式设备上的应用程序。这款五子棋游戏源码是一个典型的J2ME应用实例,它为我们揭示了如何在小型...
总的来说,这个J2ME五子棋源码项目是一个很好的学习资源,它涵盖了J2ME的基础知识、图形编程、游戏逻辑实现以及用户交互设计等多个方面。通过深入研究和实践,初学者不仅可以掌握J2ME开发技能,还能理解游戏开发的...
J2ME五子棋游戏源码提供了一个在小型设备上实现五子棋游戏的实例,对于学习J2ME编程以及游戏开发的初学者来说,这是一个非常有价值的资源。 首先,源码中的主要知识点包括: 1. **用户界面设计**:J2ME通常使用WML...
【J2ME五子棋游戏带AI源码】是一个基于Java Micro Edition(J2ME)技术开发的五子棋游戏项目。J2ME是Java平台的一个子集,主要用于嵌入式设备和移动设备上的应用程序开发,如手机和PDA。这个项目的特色在于它包含了...
总的来说,J2ME五子棋游戏源码的实现涉及了图形用户界面的设计,游戏逻辑的编程,事件处理,数据存储,性能优化,错误处理等多个方面。学习这些技术不仅可以加深对J2ME的理解,也有助于培养游戏开发和移动应用开发的...
这个压缩包包含三个不同编程语言实现的五子棋源码:C++版本、J2ME(Java Micro Edition)单机版以及JAVA版的网络对战版。下面将分别探讨这三个版本的特点和可能涉及的技术点。 1. **C++五子棋源码** C++是一种通用...
【J2ME五子棋源代码详解】 J2ME,全称Java 2 Micro Edition,是Java平台的一个轻量级版本,主要用于移动设备、嵌入式设备和智能卡等资源有限的环境。J2ME五子棋源代码是用Java语言编写的,专为移动设备设计,提供了...
【标题】: "未标题j2me游戏源码.rar" 是一个包含J2ME游戏源代码的压缩包,其中蕴含了丰富的Java编程和游戏开发知识。 【描述】中提到的"未标题j2me游戏源码"揭示了该资源的核心内容,即基于Java 2 Micro Edition...
在这个标题为“经典的J2me五子棋游戏有源码 java source five”的资源中,我们可以找到一个基于Java ME实现的五子棋游戏的完整源代码。这个项目对于学习Java ME编程、游戏开发以及了解移动设备上应用程序的实现机制...
【标题】"wuziqi.rar_J2ME 五子棋_j2me"指的是一个基于J2ME(Java 2 Micro Edition)平台开发的手机五子棋游戏。J2ME是Java的一种轻量级版本,专门用于嵌入式设备,如早期的智能手机和平板电脑,它提供了在这些设备...