java基础软件开发app之五子棋

Posted 醉画仙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java基础软件开发app之五子棋相关的知识,希望对你有一定的参考价值。

五子棋人机对战实践项目

总的任务和目标

完成一个人机对战的五子棋项目,基本效果如下:

   

第一部分 Java绘图原理

1.   基本概念

像素,坐标

第二部分 绘制棋盘

1.   基本思路

在一个JPanel上绘制一个背景,然后绘制水平和垂直的若干条线,使其构成等距离的格子,通常是15*15(条线)。

2.   代码实现

第三部分 绘制棋子

1.   基本思路

使用drawOval()可以绘制空心的圆,使用fillOval()可以填充实心的圆。

2.   坐标计算

由于格子是水平和垂直的有下标的,而绘制时需要使用实际的像素坐标,所以,需要进行行列下标到像素坐标的转换:

int x = col * GRID_WIDTH;

int y = row * GRID_WIDTH;

3.   代码实现

(1)     ChessPanel代码:

 

第四部分 鼠标下棋

1.   基本思路

需要处理鼠标单点事件,获取鼠标所在的位置,然后计算出应该绘制棋子的行列下标,并使用一个二维数组来全局存储棋子的位置。

2.   鼠标位置与行列下标计算

        int x = e.getX();

        int y = e.getY();

        int row = y / GRID_WIDTH;

     int col = x / GRID_WIDTH;

3.   代码实现

(1)      ChessPanel属性和构造方法代码:

 

(2)监听器类(内部类)代码:

 

(3)绘图代码:

 

第五部分 判断胜负

1.   基本思路

判断胜负是因为在当前位置(row, col)落子导致了胜负,所以,判断胜负其实是在当前落子位置为中心,横向搜索左边第4个位置开始到右边第4个位置(其余位置不需要考虑),或者从上到下,或者正向45度,或者反向45度位置。

2.   处理方法

处理方法有很多,可以采用计数的方式,也可以采用字符串连接的方式,此处采用了将从左边第4颗开始,到右边第4颗结束,将每颗的颜色表示成字符1(黑色)或者2(白色),只需要判断其中是否有连续的5个1或5个2,即“11111”或“22222”即可知道胜负。

3.   代码实现

(1)     监听器类(内部类)代码:

 

(2)checkWin判断胜负的代码:

/** 判断胜负

        * @param row      落子的行下标

        * @param col       落子的列下标

        * @return 是否获胜,true-是,false-否

        */

public boolean checkWin(int row, int col) {}

 

(3)重置游戏状态

 

【目前代码】

 

  1 package wuziqi;
  2 
  3 import java.awt.Color;
  4 import java.awt.Container;
  5 import java.awt.Graphics;
  6 import java.awt.event.MouseAdapter;
  7 import java.awt.event.MouseEvent;
  8 
  9 import javax.swing.JFrame;
 10 import javax.swing.JOptionPane;
 11 import javax.swing.JPanel;
 12 
 13 public class wuziqijiemianDemo {
 14     //创建窗口为主类的类部类并且继承自JFrame
 15     public class Myjframe extends JFrame {
 16         /**
 17          * 用一个构造方法创建窗口
 18          */
 19         public Myjframe() {
 20             this.setTitle("五子棋");
 21             this.setSize(620, 640);
 22             //获取内容面板
 23             Container cp = getContentPane();
 24             //创建一个面板JPanel
 25             JPanel jPanel = new MyJanel();
 26             cp.add(jPanel);
 27             //面板的背景颜色为黄色,便于下白棋与黑棋
 28             jPanel.setBackground(Color.yellow);
 29             this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
 30             //窗口默认设置为显示屏的正中间
 31             this.setLocationRelativeTo(null);
 32             //不可改变窗口的大小
 33             this.setResizable(false);
 34         }
 35     }
 36 /**
 37  * 创建一个面板继承自JPanel
 38  * @author Administrator
 39  *
 40  */
 41     public class MyJanel extends JPanel {
 42         //表示每个方格的大小
 43         private static final int GRID_WIDTh = 40;
 44         //棋盘的大小,代表棋盘的线的条数
 45         private static final int LINE_COUNT = 15;
 46         //设置黑棋子为1、白棋子为2、没有棋子为0(默认值)
 47         public static final int BLACK=1;
 48         public static final int WHITE=2;
 49         //定义一个棋盘大小的数组用来存放黑棋和白棋的位置
 50         int[][] chessItems=new int[LINE_COUNT][LINE_COUNT];
 51         //定义一个标志位,代表黑棋先下(黑棋和白棋轮流下棋)
 52         int flag=BLACK;
 53         /**
 54          * 构造方法用来画棋盘的棋子
 55          */
 56         public MyJanel(){
 57             /**
 58              * 为这个面板添加一个鼠标点击事件,鼠标每点击一次,就在棋盘上下一个棋子
 59              *使用适配器的方式添加鼠标点击事件    
 60              */
 61             this.addMouseListener(new MouseAdapter() {
 62                 public void mouseClicked(MouseEvent e){
 63                     /**
 64                      * 获取当前的鼠标点击的位置
 65                      */
 66                     int x=e.getX();
 67                     int y=e.getY();
 68                     /**
 69                      * 因为棋盘是用二维数组的方式表示的,所以最后表示为二维数组的行与列
 70                      */
 71                     int row=y/GRID_WIDTh;
 72                     int col=x/GRID_WIDTh;
 73                     //当前这个位置没有棋子(为零),可以下一个黑棋子
 74                     if(chessItems[row][col]==0){
 75                         if(flag==BLACK){
 76                             chessItems[row][col]=flag;
 77                             //下完黑棋下白棋
 78                             flag=WHITE;
 79                             //必须有,不然后面的白棋会覆盖黑棋
 80                         }
 81                         //当前这个位置没有棋子(为零),可以下一个白棋子
 82                         else{
 83                             chessItems[row][col]=flag;
 84                             //下完白棋下黑棋
 85                             flag=BLACK;
 86                         }
 87                     }
 88                     /**
 89                      * 每当下完一步棋之后便判断是否已经取胜
 90                      */
 91                     if(checkImage(row,col)){
 92                         //显示对话窗口
 93                         JOptionPane.showMessageDialog(null, "your win");
 94                         //清空棋盘
 95                         clear();
 96                     }
 97                     //System.out.println(chessItems[row][col]);
 98                 }
 99             });
100         }
101         /**
102          * 调用public void paintComponent(Graphics arg0){};方法画图
103          */
104         public void paintComponent(Graphics g) {
105             //系统调用
106             super.paintComponent(g);
107 //            g.setColor(Color.yellow);
108 //            g.fillRect(0, 0, jPanel.width(),jPanel.height());
109             /**
110              * 画横线,起始位置在窗口左上定点(GRID_WIDTh/2,GRID_WIDTh/2)
111              */
112             for (int i = 0; i < LINE_COUNT; i++) {
113                 int x1 = GRID_WIDTh / 2;
114                 int y1 = GRID_WIDTh / 2 + i * GRID_WIDTh;
115                 int x2 = x1 + (LINE_COUNT-1)* GRID_WIDTh;
116                 int y2 = y1;
117                 //画线
118                 g.drawLine(x1, y1, x2, y2);
119             }
120             /**
121              * 画竖线
122              */
123             for (int i = 0; i < LINE_COUNT; i++) {
124                 int x1 = GRID_WIDTh / 2 + i * GRID_WIDTh;
125                 int y1 = GRID_WIDTh / 2;
126                 int x2 = x1;
127                 int y2 = y1 + (LINE_COUNT-1) * GRID_WIDTh;
128                 //画线
129                 g.drawLine(x1, y1, x2, y2);
130             }
131             /**
132              * 遍历这个数组
133              */
134             for(int row=0;row<LINE_COUNT;row++){
135                 for(int col=0;col<LINE_COUNT;col++){
136                     //判断数组当前值,来画棋子
137                     switch (chessItems[row][col]) {
138                     case WHITE:chessItem(row, col, Color.WHITE, g);break;
139                     case BLACK:chessItem(row, col, Color.BLACK, g);break;
140                     }
141                     repaint();
142                 }
143             }
144         };
145         /**
146          * 清空数组,便于下次下棋
147          */
148         private void clear() {
149             for(int row=0;row<LINE_COUNT;row++){                    
150                 for(int col=0;col<LINE_COUNT;col++){
151                     //全部置为0
152                     chessItems[row][col]=0;
153                 }
154             }
155             //重画一遍棋盘
156             repaint();
157         }
158         /**
159          * 用于判断是否已经取胜
160          * @param row
161          * @param col
162          * @return
163          */
164         private boolean checkImage(int row, int col) {
165             /**
166              * 判断横行是否win
167              */
168             StringBuilder stringBuilder=new StringBuilder();
169             //记录当前存在字符串中的数据个数
170             int count=0;
171             for(int i=-4;i<=4;i++){
172                 int Newcol=col+i;
173                 if(Newcol>=0&&Newcol<LINE_COUNT){
174                     count++;
175                     stringBuilder.append(chessItems[row][Newcol]);
176                 }
177             }
178             if(stringBuilder.indexOf("11111")>=0||stringBuilder.indexOf("22222")>=0){
179                 return true;
180             }else {
181                 //如果当前不能赢,则清空字符串
182                 stringBuilder.delete(0, count);
183                 count=0;
184             }
185             /**
186              * 判断竖行是否win
187              */
188             for(int i=-4;i<=4;i++){
189                 int Newrow=row+i;
190                 if(Newrow>=0&&Newrow<LINE_COUNT){
191                     count++;
192                     stringBuilder.append(chessItems[Newrow][col]);
193                 }
194             }
195             if(stringBuilder.indexOf("11111")>=0||stringBuilder.indexOf("22222")>=0){
196                 return true;
197             }else {
198                 stringBuilder.delete(0, count);
199                 count=0;
200             }
201             /**
202              * 判断负45°是否win
203              */
204             for(int i=-4;i<=4;i++){
205                 int Newcol=col+i;
206                 int Newrow=row+i;
207                 if(Newcol>=0&&Newcol<LINE_COUNT&&Newrow>=0&&Newrow<LINE_COUNT){
208                     count++;
209                     stringBuilder.append(chessItems[Newrow][Newcol]);
210                 }
211             }
212             if(stringBuilder.indexOf("11111")>=0||stringBuilder.indexOf("22222")>=0){
213                 return true;
214             }else {
215                 stringBuilder.delete(0, count);
216                 count=0;
217             }
218             /**
219              * 判断正45°是否win
220              */
221             for(int i=-4;i<=4;i++){
222                 int Newcol=col+i;
223                 int Newrow=row-i;
224                 if(Newcol>=0&&Newcol<LINE_COUNT&&Newrow>=0&&Newrow<LINE_COUNT){
225                     count++;
226                     stringBuilder.append(chessItems[Newrow][Newcol]);
227                 }
228             }
229             if(stringBuilder.indexOf("11111")>=0||stringBuilder.indexOf("22222")>=0){
230                 return true;
231             }else {
232                 stringBuilder.delete(0, count);
233                 count=0;
234             }
235             return false;
236         }
237         //画棋子
238         public void chessItem(int row,int col,Color color,Graphics graphics){
239             //x与y分别代表在面板上的位置
240             int x=col*GRID_WIDTh;
241             int y=row*GRID_WIDTh;
242             graphics.setColor(color);
243             //画圆
244             graphics.fillOval(x, y, GRID_WIDTh,GRID_WIDTh);
245         }
246     }
247 
248     public static void main(String[] args) {
249         /**
250          * 使用一个java类来创建一个主类为wuziqijiemianDemo,其中的窗口与棋盘为该主类的内部类
251          */
252         //使用类部类的方式创建一个窗口引用对象(方式为 外部类名.内部类名 变量名=new 外部类名().new 内部类名();)
253         wuziqijiemianDemo.Myjframe myjframe = new wuziqijiemianDemo().new Myjframe();
254         //设置窗口可见
255         myjframe.setVisible(true);
256     }
257 
258 }

 

 

 

第六部分 人机对战

1.   基本思路

当人点了鼠标落子以后,轮到电脑下棋,电脑的基本思想就是,在棋盘的空白处的每个位置,进行判断,当前位置的进攻指数和防守指数分别为多少,在进攻指数和防守指数中取一个较大值作为当前位置的评估值,在整个棋盘的所有空白处找到一个最大值,最大值的那个位置即为应该落子的位置。

2.  代码实现

(1)监听器类(内部类)代码:

(2)电脑下棋的代码

(3)     评估关键参数代码:

 

(4) 评估方法代码:

【自己代码】

 

  1 package wuziqi;
  2 
  3 import java.awt.Color;
  4 import java.awt.Container;
  5 import java.awt.Graphics;
  6 import java.awt.Image;
  7 import java.awt.Point;
  8 import java.awt.event.MouseAdapter;
  9 import java.awt.event.MouseEvent;
 10 import java.io.File;
 11 import java.io.IOException;
 12 
 13 import javax.imageio.ImageIO;
 14 import javax.swing.JFrame;
 15 import javax.swing.JOptionPane;
 16 import javax.swing.JPanel;
 17 
 18 public class wuziqijiemianDemo {
 19     // 创建窗口为主类的类部类并且继承自JFrame
 20     public class Myjframe extends JFrame {
 21         /**
 22          * 用一个构造方法创建窗口
 23          */
 24         public Myjframe() {
 25             this.setTitle("五子棋");
 26             this.setSize(620, 640);
 27             // 获取内容面板
 28             Container cp = getContentPane();
 29             // 创建一个面板JPanel
 30             JPanel jPanel = new MyJanel();
 31             cp.add(jPanel);
 32             // 面板的背景颜色为黄色,便于下白棋与黑棋
 33             jPanel.setBackground(Color.yellow);
 34             this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
 35             // 窗口默认设置为显示屏的正中间
 36             this.setLocationRelativeTo(null);
 37             // 不可改变窗口的大小
 38             this.setResizable(false);
 39         }
 40     }
 41 
 42     /**
 43      * 创建一个面板继承自JPanel
 44      * 
 45      * @author Administrator
 46      * 
 47      */
 48     public class MyJanel extends JPanel {
 49         // 表示每个方格的大小
 50         private static final int GRID_WIDTh = 40;
 51         // 棋盘的大小,代表棋盘的线的条数
 52         private static final int LINE_COUNT = 15;
 53         // 设置黑棋子为1、白棋子为2、没有棋子为0(默认值)
 54         public static final int BLACK = 1;
 55         public static final int WHITE = 2;
 56         // 定义一个棋盘大小的数组用来存放黑棋和白棋的位置
 57         int[][] chessItems = new int[LINE_COUNT][LINE_COUNT];
 58         // 定义一个标志位,代表黑棋先下(黑棋和白棋轮流下棋)
 59         int flag = BLACK;
 60         //定义一个方框标记计算机下棋的棋子
 61         private Point lastpoint=new Point();
 62         //利用图片代表棋子
 63         Image blackImage=null;
 64         Image whiImage=null;
 65         //定义一个进攻的数组
 66         String[] defendstring={
 67             "11111","011110","11110","01111","11011",
 68             "10111","11101","01110","11100","00111",
 69             "0111","1110","1011","1101","111",
 70             "01100","00110","011","110","11"
 71         };
 72         //定义一个防守的数组
 73         String[] attackstring={
 74             "22222","022220","22220","02222","22022",
 75             "20222","22202","02220","22200","00222",
 76             "0222","2220","2022","2202","222",
 77             "02200","00220","022","220","22"
 78         };
 79         //定义一个防守与进攻对应的得分
 80         int[] score={
 81             100,90,80,80,80,
 82             80,80,70,60,60,
 83             50,50,50,50,40,
 84             30,30,20,20,10,
 85         };
 86         /**
 87          * 构造方法用来画棋盘的棋子
 88         

以上是关于java基础软件开发app之五子棋的主要内容,如果未能解决你的问题,请参考以下文章

iOS 符号化:基础与进阶

基于android的五子棋游戏app

java项目开发----五子棋

Java基础之方法的调用重载以及简单的递归

QT---实现舒尔特方格(零基础入门)

MyEclipse Java基础使用笔记