基本界面的实现
创建主窗体,为其添加五子棋基本功能的按钮:开始游戏,悔棋,认输,对战方式,并绘制棋盘,因为棋盘和棋子的参数是恒定的,我们定义一个接口
public interface GoBangInformation {
public static final int X=50,Y=100,SIZE=35,CHESS_SIZE=33,ROW=15,COLUMN=15;
}
然后让整个五子棋程序的所有文件实现该接口,接着绘制棋盘
private void drawTable(Graphics g) {
g.setColor(Color.BLACK);
for(int i=0;i<ROW;i++) {
g.drawLine(X, Y+SIZE*i, X+SIZE*(COLUMN-1), Y+SIZE*i);
}
for(int i=0;i<COLUMN;i++) {
g.drawLine(X+SIZE*i, Y ,X+SIZE*i, Y+SIZE*(ROW-1));
}
}
下棋数据的存储
1.首先为了存储整个棋盘的数据,我定义了一个二维数组public static int [][] chessTable=new int[ROW][COLUMN];来存储每个点上的棋子数据(例如:0-无棋子,1-黑棋,2-白棋)
2.为了实现悔棋功能,我们需要记录每一步的棋子位置,一个index代表第几步棋,
public static int []indxhistory=new int[500];
public static int []indyhistory=new int[500];
来记录每一步棋的横竖坐标.
绘制棋子:棋子颜色变更及棋子位置判断
颜色变更可以用一个flag来判定,每次画棋子变更一下,把棋子画在交叉处可以分两步来进行,先是根据鼠标点击位置判断在第几行第几列,然后在该交叉点画棋子,注意每次绘制要判断该位置是否已有棋子,有才绘制。
public static int getindexx(int tempX) {
if(tempX<X+SIZE/2) {
return 0;
}
else if(tempX>X+SIZE*(COLUMN-1)+SIZE/2) {
return COLUMN-1;
}
else {
return (tempX-X+SIZE/2)/SIZE+1;
}
}
//绘制棋子,若该位置有棋子则返回false
public static int getindexy(int tempY) {
if(tempY<Y+SIZE/2) {
return 0;
}
else if(tempY>Y+SIZE*(ROW-1)+SIZE/2) {
return ROW-1;
}
else {
return (tempY-Y+SIZE/2)/SIZE+1;
}
}
public static boolean drawOneChess(Graphics g,int indx,int indy,boolean flag) {
if(chessTable[indx][indy]==1) {
if(flag) {
chessTable[indx][indy]=2;
g.setColor(Color.BLACK);
}
else {
chessTable[indx][indy]=3;
g.setColor(Color.WHITE);
}
g.fillOval(X+(indx)*SIZE-CHESS_SIZE/2, Y+(indy)*SIZE-CHESS_SIZE/2, CHESS_SIZE, CHESS_SIZE);
return true;
}
return false;
}
悔棋功能的实现
1.根据棋子历史修改现有棋盘chessTable上每一个点上的棋子有无及颜色。
public void actionPerformed(ActionEvent e) {
String ac=e.getActionCommand();
//悔棋实现
if(ac.equals("悔棋")) {//在主界面用setActionCommand()为组件取名。
//人人对战的悔棋处理
if(gameStart==1&&gameType==0) {
setG();
if(index>0) {
index--;
chessTable[indxhistory[index]][indyhistory[index]]=1;
frame.paint(graphics);
}
else {
//如果还没开始下就什么都不做
}
}
//人机对战的悔棋处理,每次悔两步
if(gameStart==1&&gameType==1) {
setG();
if(index>0) {
index--;
chessTable[indxhistory[index]][indyhistory[index]]=1;
index--;
chessTable[indxhistory[index]][indyhistory[index]]=1;
frame.paint(graphics);
}
else {
//如果还没开始下就什么都不做
}
}
}
}
2.根据chessTable上的棋盘布局重绘棋盘
public void paint(Graphics g) {
super.paint(g);
drawTable(g);
if(test==1)//棋盘初始化
DrawChess.refreTable();
else
DrawChess.drawChess(g);
test++;
}
3.具体的重绘方法
public static void drawChess(Graphics g) {
for(int i=0;i<15;i++) {
for(int k=0;k<15;k++) {
if(chessTable[i][k]==2) {
g.setColor(Color.BLACK);
g.fillOval(X+i*SIZE-CHESS_SIZE/2, Y+k*SIZE-CHESS_SIZE/2, CHESS_SIZE, CHESS_SIZE);
}
else if(chessTable[i][k]==3) {
g.setColor(Color.WHITE);
g.fillOval(X+i*SIZE-CHESS_SIZE/2, Y+k*SIZE-CHESS_SIZE/2, CHESS_SIZE, CHESS_SIZE);
}
else {
}
}
}
}
输赢判断
判断输赢的方法是在每一次画完棋子后,分别判断横,竖,左斜,右斜四条线上是否有相邻的五颗棋子,若有,则输出胜利信号,结束游戏。
对横线的处理
private static boolean judgeRow(int indx,int indy) {
boolean result=false;
int flag=0;//记录相同棋子个数
for(int i=indx-1;i>0;i--) {
if(chessTable[i][indy]==chessTable[indx][indy]) {
flag++;
}
else {
break;
}
}
for(int i=indx+1;i<ROW;i++) {
if(chessTable[i][indy]==chessTable[indx][indy]) {
flag++;
}
else {
break;
}
}
if(flag>=4) {
result=true;
}
return result;
}
结束游戏的操作
if(flag) {//玩家为黑
winMessage="黑方赢了";
JOptionPane.showMessageDialog(null,winMessage, "游戏结束", JOptionPane.INFORMATION_MESSAGE);//弹窗提示
refresh();//清空棋盘并重绘
return true;//返回判断结果,若为false,则继续游戏
}
else {
winMessage="黑方输了";
JOptionPane.showMessageDialog(null,winMessage , "游戏结束", JOptionPane.INFORMATION_MESSAGE);
refresh();
return true;
}
private void refresh() {
gameStart=0;
flag=true;
DrawChess.refreTable();
if(graphics==null)
setG();
index=0;
frame.paint(graphics);
}