从开始着手做五子棋,到现在已经有一段时间了。这个项目也算告一段落。 从开始做的网络版,再到加入人机元素, 可谓是耗尽精力。 人机水平达到了比较牛逼的程度,可以战胜大多数人(略显夸张。。) 大言不惭的说最好,也是不符合程序猿严谨的风格,在新手中看来这个程序应该是写的可以了。但大牛看来就是乱七八糟(被大牛吐槽过)。。人机写到这个程度感觉再要进一步很难了。所以就先把这个版本发出来。
先看下效果图吧。 还是很漂亮的吧。这个界面也花了我很久的时间。
登陆界面
人机界面
可以更换背景
网络人人版
可下棋聊天
然后说下 一些做的不好的地方吧
1.我做了两个版本 一个是客户端一个是服务端, 必须先启动服务端 然后用客户端去连接客户端。(我想做成就一个版本, 任意打开的两个可以互联,但是一直没成功,求大神指导思路)。
2.棋子直接用画布画的圆圈没有用图片,不太好看。
3.最新下的棋子没有加入闪烁效果,棋子多了 可能分不清对方是在哪里下子
总代码太长了 ,我就发下人机代码了 ,这是核心
电脑下棋思路: 15*15的五子棋盘一共有572种 成“5”组合。我们称这种组合为获胜组合。而保存这572种组合的表称为获胜表。每次下棋后,都要更新所以获胜组合情况(“5”中的棋子个数更改)。而电脑下棋前 扫描每个位置,看包含这个位置的所有组合,根据评估函数打分。分数有两个,一个是这个位置对电脑的得分,一个是对玩家的得分。。 电脑每次选取分数最高的地方下子。 五子棋人机思路及具体做法我做了个PPT ,大家可以下载看看,讲的很详细了。有什么不懂的地方欢迎留言。有什么可以改进的地方也欢迎留言指教!
package client;
import java.awt.Point;
public class ComputerNormal {
static Integer[][][] pTable; // 人的获胜表
static Integer[][][] cTable;// 机器的获胜表
//win[0][k]:表示玩家在第k个获胜组合往其方向有win[0][k]个连续的黑棋。
//win[0][k]取值为9则表示第k个获胜组合被封死了,没有成5的可能。
// win[1][k]:表示计算机在第k个获胜组合往其方向有win[1][k]个连续的白棋。
static Integer win[][];
static int row = 15;
static int col = 15;
public ComputerNormal() {
InitBoard();
}
public static Point cPutChess(Integer map[][])
{
//机器下子 判断机器分
int maxi = 0,maxj = 0;
int max=-999999;
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
if(map[i][j]!=0)
continue;
int t=GiveScore(1, i, j);
if(max<t)
{
max=t;
maxi=i;
maxj=j;
}
}
}
//机器下子 判断ren分
int mini = 0,minj = 0;
int min=0;
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
if(map[i][j]!=0)
continue;
int t=GiveScore(2, i, j);
if(min>t)
{
min=t;
mini=i;
minj=j;
}
}
}
int lastx=maxi,lasty=maxj;
if(max<=Math.abs(min))
{
lastx=mini;
lasty=minj;
}
Point p = new Point(lastx,lasty);
return p;
}
//人下子后的状态变化
public static void pboardModify( int x, int y )
{
for( int k=0; k<572; k++ ) //修改玩家下子后棋盘状态的变化
{
//如果[x][y]位置是玩家第k个"5"中的位置,且第k个"5"没有被封死
if( pTable[x][y][k]==1 && win[0][k]!=9 )
win[0][k]++;
//如果[x][y]位置是计算机第k个"5"中的位置,则玩家下子后第k个"5"被封死
if( cTable[x][y][k]==1 ) //○●○○○
{
cTable[x][y][k] = 0;
win[1][k] = 9;
}
}
}//pboard
//计算机下子后的状态变化
public static void cboardModify( int x, int y )
{
for( int k=0; k<572; k++ ) //修改计算机下子后,棋盘的变化状况
{
//如果[x][y]位置是计算机第k个"5"中的位置,且第k个"5"没有被封死
if( cTable[x][y][k]==1 && win[1][k]!=9 )
{
win[1][k]++;
}
//如果[x][y]位置是玩家第k个"5"中的位置,则计算机下子后第k个"5"被封死
if( pTable[x][y][k]==1 ) //●○●●●
{
pTable[x][y][k] =0;
win[0][k] = 9;
}
}
}//cboard
/**
* 估值
*/
static int GiveScore( int type, int x, int y )
{
int k, score = 0;
for( k=0; k<572; k++ )
{
if( type==1 ) //计算机下
{
if( cTable[x][y][k]==1 ) //[x][y]是第k个"5"上的一个位置
{
//第k个"5"中已经有win[1][k]个位置了
switch( win[1][k] )
{
case 1: score += 5; break;
case 2: score += 50; break;
case 3: score += 500; break;
case 4: score += 5000; break;
default: break;
}
}
}
else //玩家下
{
if( pTable[x][y][k] ==1) //[x][y]是第k个"5"上的一个位置
{
//第k个"5"中已经有win[0][k]个位置了
switch( win[0][k] )
{
case 1: score-=5; break;
case 2: score-=50; break;
case 3: score-=500; break;
case 4: score-=5000; break;
default: break;
}
}
}
}
return score;
}
public static void InitBoard() {
int i, j, k;
pTable=new Integer[15][15][572];
cTable=new Integer[15][15][572];
for (i = 0; i < row; i++){
pTable[i]=new Integer[15][572];
cTable[i]=new Integer[15][572];
for (j = 0; j < col; j++) {
pTable[i][j]=new Integer[572];
cTable[i][j]=new Integer[572];
for (k = 0; k < 572; k++) {
//pTable[i][j][k]=new Integer();
pTable[i][j][k] = 0;
cTable[i][j][k] = 0;
}
}
}
int count = 0;
int x,y;
// 横着的获胜组合
for (x= 0; x < 15; x++) {
for (y= 0; y < 11; y++) {
for (k = 0; k < 5; k++) {
pTable[x][y+ k][count] = 1;
cTable[x][y+ k][count] = 1;
}
count++;
}
}
//竖的获胜组合
for (y = 0;y < 15; y++) {
for (x = 0; x < 11; x++) {
for (k = 0; k < 5; k++) {
pTable[x+k][y][count] = 1;
cTable[x+k][y][count] = 1;
}
count++;
}
}
//主对角线
for( x = 0; x < 11; x++ )
{
for( y = 0; y < 11; y++ )
{
for( k = 0; k < 5; k++ )
{
pTable[x+k][y+k][count] = 1;
cTable[x+k][y+k][count] = 1;
}
count++;
}
}
//次对角线
for( x = 4; x < 15; x++ )
{
for( y = 0; y < 11; y++ )
{
for( k = 0; k < 5; k++ )
{
pTable[x-k][y+k][count] = 1;
cTable[x-k][y+k][count] = 1;
}
count++;
}
}
//初始化win
win=new Integer[2][572];
win[0]=new Integer[572];
win[1]=new Integer[572];
for( k = 0; k < 572; k++ ) //初始化win数组
{
win[0][k] = 0;
win[1][k] = 0;
}
//初始化结束
}//init 结束
}
自己也知道有很多做的不好的地方,很多需要改进的地方。
欢迎大牛指点!