简单来说,这个项目由两大部分组成,第一部分是界面设置,第二部分是功能实现。
界面设置
界面主要由窗体和组件构成,细分可以分为整个窗体+按钮+棋盘格
界面的实现:
设置窗体标题大小和布局
setTitle("AIGoBang"+"V1.0");
setSize(900,750);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);//默认居中
setLayout(null);//修改布局为null,自定义组件的尺寸和位置
设置按钮颜色位置并加到窗体上
//String[] btnstrs= {"人人下棋","人机下棋","悔棋","回放","历史棋局","结束游戏"};
for(int i=0;i<btnstrs.length;i++) {
JButton btn=new JButton(btnstrs[i]);
btn.setBackground(Color.WHITE);
btn.setBounds(X + SIZE * COL + SIZE, Y + i * (SIZE + 10), 100, 35);
add(btn);
btn.addActionListener(gl);//加入监听器实现监听功能
btns[i]=btn;
}
3.界面可视化
setVisible(true);
4.设置一个画笔来绘制棋盘,为了防止窗体移动刷新导致棋子消失,重写paint方法,并把棋盘按钮和棋子重新绘制上去。chessArr[][]数组存储棋盘后面会提到。
//绘制棋盘格子
// 重写方法 paint 是窗体刷新时都会执行的方法
// g可以用来绘制 直线 矩形 圆 图片 字符串
@Override
public void paint(Graphics g){
drawBack (g);
rfBtn ();
drawChess (g);
}
public void rfBtn() {
//刷新按钮显示出来
for(int i=0;i<btns.length;i++) {
btns[i].repaint();
}
}
public void drawBack(Graphics g) {
//绘制棋盘
g.setColor(new Color(205, 243, 54, 255));
g.fillRect(0, 0, getWidth(),getHeight() );
//绘制网格线
g.setColor (Color.BLACK);
for(int i = 0; i <= ROW; i++){
g.drawLine (X, Y+i*SIZE, X + SIZE * COL, Y+i*SIZE);//横线
g.drawLine (X+i*SIZE, Y, X+i*SIZE, Y + ROW * SIZE);//竖线
}
}
public void drawChess(Graphics g) {
//遍历数组绘制棋子,防止刷新时棋子消失
for(int i = 0; i < chessArr.length; i++){
for(int j = 0; j < chessArr[i].length; j++){
int cnum = chessArr[i][j];
if(cnum!=0){
g.setColor (cnum==1?Color.BLACK:Color.WHITE);
// 根据行列值 还原 标准坐标
int cx = j * SIZE + X - SIZE / 2;
int cy = i * SIZE + Y - SIZE / 2;
g.fillOval (cx, cy, SIZE, SIZE);
}
}
}
}
以上就是整个界面ui的设置
功能实现
表面上看主要有"人人下棋","人机下棋","悔棋","回放","历史棋局","结束游戏"六大模块功能的实现,而实际上,要实现这六个功能,主要是由两个动作触发:按下按钮和按下鼠标,因此用到两个监听器接口:MouseListener, ActionListener。
怎么添加这两个监听器呢?
首先建一个类GoListener,让这个类实现这两个接口,然后在上面写的GoBangUI中创建GoListener对象,分别在按钮和整个窗体上调用方法实现监听。
public class GoListener implements MouseListener, ActionListener{}
public class GoBangUI extends JFrame implements GoData{
//初始化监听器
private GoListener gl=new GoListener();
btn.addActionListener(gl);
addMouseListener(gl);}
人人下棋
首先分析下棋的动作,开始下棋后,按下鼠标绘制棋子,这个时候需要画笔来画棋子,所以要在GoBangUI中可视化后用getGraphics()方法获取图形对象-画笔,然后将画笔传给GoListener。
怎么传呢?在GoListener中构建方法setG,然后在GoBangUI中调用这个方法,就可以在GoListener中使用画笔绘制棋子。
public class GoListener implements MouseListener, ActionListener, GoData{
private Graphics g=null;
public void setG(Graphics g) {
this.g=g;
}}
public GoBangUI() {
//前面设置窗体组件属性的代码省略
gl.setG (getGraphics ());// 在可视化之后 getGraphics 获取一个图形对象 - 画笔
}
轮流下棋需要切换颜色,使用一个标识在未开始游戏时,flag为0,开始游戏默认黑先行,flag为1,下完flag为2,表示下一个棋子为白色,白色下完后flag=1,重复这个轮流切换的过程直到一方胜出。
int chessFlag=0; //0:不能下棋 1 表示黑棋 2 表示白棋
if(btnstr.equals("人人下棋")){
chessFlag=1;}
//开始轮流下棋
if(chessFlag==1) {
g.setColor(Color.BLACK);//画笔为黑色
chessFlag=2;
}else if(chessFlag==2) {
g.setColor (Color.WHITE);//画笔为白色
chessFlag = 1;
}
使用chessArr[][]数组记下在几行几列是否有棋子,是什么颜色的棋子,主要通过赋值chessFlag实现。
记下整个棋盘后方便刷新棋盘以及判断输赢,也可以防止重复落子。
//校正坐标
//计算这个点属于第几行第几列,SIZE/2是为了将点校正至圆心
int c=(x-X+SIZE/2)/SIZE;
int r=(y-Y+SIZE/2)/SIZE;
if (chessArr[r][c]!=0){
msgFrame ("此处已有棋子!不能重复落子!");
return;
}
chessArr[r][c]=chessFlag;
// 根据行列值 还原 标准坐标
int cx = c * SIZE + X - SIZE / 2;
int cy = r * SIZE + Y - SIZE / 2;
// 绘制圆形
g.fillOval (cx, cy, SIZE, SIZE);
清屏的操作也是通过清空chessArr数组,然后重新刷新棋盘实现的,刷新棋盘用到GoBangUI对象的repaint方法,因此要在Golistener中创建GoBangUI对象,创建setUI方法,在GoBangUI中调用setUI方法,将这一ui对象传到GoListener中。
public class GoListener implements MouseListener, ActionListener, GoData{
private GoBangUI ui=null;
public void setUi(GoBangUI ui){
this.ui = ui;
}
}
private GoListener gl=new GoListener();
public GoBangUI() {
gl.setUi(this);
}
//清屏
for(int i=0;i<chessArr.length;i++) {
for(int j=0;j<chessArr[i].length;j++) {
chessArr[i][j]=0;
}
}
ui.repaint ();
输赢的判断,判断的时机在落子之后,无论黑白,落子后找到该棋子的行列坐标,在chessArr[][]数组中以chessArr[r][c]为原点,统计该棋子上、下、左、右,左上、右下,右上、左下八个方向,四个大方向上的连子情况,大于等于5胜利。
public class IsWin {
public static boolean isWin(int[][] chessArr,int r,int c) {
//水平方向
int counth1=findRightchess(chessArr,r,c);
int counth2=findLeftchess(chessArr,r,c);
//竖直方向
int countv1=findUpchess(chessArr,r,c);
int countv2=findDownchess(chessArr,r,c);
//左斜
int countb1=findLeftupchess(chessArr,r,c);
int countb2=findRightdownchess(chessArr,r,c);
//右斜
int counta1=findRightupchess(chessArr,r,c);
int counta2=findLeftdownchess(chessArr,r,c);
//
int count1=counth1+counth2-1;//因为两个方向都会把当前落子加入进去所以减一
int count2=countv1+countv2-1;
int count3=countb1+countb2-1;
int count4=counta1+counta2-1;
if(count1>=5||count2>=5||count3>=5||count4>=5) {
return true;
}
return false;
}
//落子后检查是否达到赢的标准,即连成五子,一共八个方向,以此时落子为中心在四个方向上统计该色棋子的总共数量
//找当前落子的右侧棋子数量(连续不间隔)
private static int findRightchess(int[][] chessArr,int r,int c) {
int count=0;
for(int i=c;i<chessArr[r].length;i++) {
if(chessArr[r][i]==chessArr[r][c]) {
count++;
}else {
break;
}
}
return count;
}
//找当前落子的左侧棋子数量(连续不间隔)
private static int findLeftchess(int[][] chessArr,int r,int c) {
int count=0;
for(int i=c;i>=0;i--) {
if(chessArr[r][i]==chessArr[r][c]) {
count++;
}else {
break;
}
}
return count;
}
//找当前落子的上方棋子数量(连续不间隔)
private static int findUpchess(int[][] chessArr,int r,int c) {
int count=0;
for(int i=r;i>=0;i--) {
if(chessArr[i][c]==chessArr[r][c]) {
count++;
}else {
break;
}
}
return count;
}
//找当前落子的下方棋子数量(连续不间隔)
private static int findDownchess(int[][] chessArr,int r,int c) {
int count=0;
for(int i=r;i<chessArr.length;i++) {
if(chessArr[i][c]==chessArr[r][c]) {
count++;
}else {
break;
}
}
return count;
}
//找当前落子的左上方棋子数量(连续不间隔)
private static int findLeftupchess(int[][] chessArr,int r,int c) {
int count=0;
int j=c;
for(int i=r;i>=0;i--) {
if(j>=0) {
if(chessArr[i][j]==chessArr[r][c]) {
count++;
j--;
}else {
break;
}
}
}
return count;
}
//找当前落子的右下方棋子数量(连续不间隔)
private static int findRightdownchess(int[][] chessArr,int r,int c) {
int count=0;
int j=c;
for(int i=r;i<chessArr.length;i++) {
if(j<chessArr[r].length) {
if(chessArr[i][j]==chessArr[r][c]) {
count++;
j++;
}else {
break;
}
}
}
return count;
}
//找当前落子的右上方棋子数量(连续不间隔)
private static int findRightupchess(int[][] chessArr,int r,int c) {
int count=0;
int j=c;
for(int i=r;i>=0;i--) {
if(j<chessArr[r].length) {
if(chessArr[i][j]==chessArr[r][c]) {
count++;
j++;
}else {
break;
}
}
}
return count;
}
//找当前落子的左下方棋子数量(连续不间隔)
private static int findLeftdownchess(int[][] chessArr,int r,int c) {
int count=0;
int j=c;
for(int i=r;i<chessArr.length;i++) {
if(j>=0) {
if(chessArr[i][j]==chessArr[r][c]) {
count++;
j--;
}else {
break;
}
}
}
return count;
}
}
完整代码在后续章节...