一、需求分析
1、画一个15x15的棋盘版面
2、功能按钮:开始游戏,悔棋,认输
3、单选按钮:人人对战、人机对战
4、要求:在棋盘上下棋子,棋子必须要在交叉点上;同一个位置上不能有再下棋子;棋子不能消失;判断输赢。
二、设计思路
1、图形界面(棋盘版面)
通过JFrame与JPanel 窗体实现,将JFrame分为2个部分,一部分用于绘制棋盘,另一部分用于放置功能按钮等。 并且添加监听。
(1)创建窗体
public void showUI(){
JFrame frame=new JFrame(); //创建窗体 frameframe.setTitle("五子棋 "); //设置窗体的标题frame.setSize(750,650);//设置大小frame.setResizable(false);//大小不可变frame.setLocationRelativeTo(null);//窗体居中frame.setDefaultCloseOperation(3);//退出时关闭进程cl=new ChessListener(this);// 实例化事件处理类的对象,将棋盘面板作为参数传递过去centerPanel(frame); //在窗体frame上添加中间面板 ---棋盘eastPanel(frame);//窗体frame上添加东边面板 ---功能按钮
frame.setVisible(true);//设置窗体可见cl.setExist(exist);//将棋子数组传入到事件监听类中
}
(2)创建两个面板---中间面板(绘制棋盘)、东边面板(放置功能按钮)
/*** 往窗体上添加中间面板的方法* @param frame 窗体*/
public void centerPanel(JFrame frame){
this.setBackground(Color.ORANGE);
frame.add(this);
}
/*** 往窗体上添加东边面板的方法 ---用于放置功能按钮* @param frame窗体*/
public void eastPanel(JFrame frame){
JPanel epanel=new JPanel();//创建一个面板对象epanel.setBackground(Color.GRAY);//背景颜色设置为grayepanel.setPreferredSize(new Dimension(150,600)); //设置大小epanel.setLayout(new FlowLayout());//默认也是流式布局String[] buttonArray={"开始游戏","悔棋","认输"}; //数组存储 功能按钮命令for(int i=0;i
String[] radioArray={"人人对战","人机对战"};//数组存储 单选按钮命令ButtonGroup bg=new ButtonGroup();//实例化一个按钮组的对象for(int i=0;i
}
epanel.add(radioButton);//在面板上添加单选按钮radioButton.addActionListener(cl);//加监听器}
frame.add(epanel,BorderLayout.EAST);//为窗体(边框布局)添加面板---放置在东侧}
(3)新建一个接口,用于保存棋盘的各种参数(常量)
public interface Config {
public static final int X0=20;
//棋盘起点坐标x0public static final int Y0=30; //棋盘起点坐标y0public static final int ROWS=15; //行数public static final int COLUMNS =15; //列数public static final int CHESS_SIZE=40; //棋子的大小public static final int SIZE=40; //棋盘行与行 列与列之间的距离}
(4)绘制棋盘
/*** 绘制棋盘的方法* @param g 传入画笔*/
public void drawChessTable(Graphics g){
for(int r=0;r
}
for(int c=0;c
}
}
(5)棋子重绘
我们下棋的时候并不希望因为最大化或最小化窗体而导致棋子消失,因为组件具有重绘的方法,不需要我们重绘,但是对于棋子来说,我们必须将棋子重新画出。
这里我们考虑用一个exist[][] 二维数组存储棋子的颜色与位置,值为0时表示没有棋子,值为1时表示黑色棋子,值为-1 时表示该位置有白色的棋子。
/*** 棋子重绘的方法* @param g*/
public void reDrawChess(Graphics g){
Graphics2D g2d=(Graphics2D) g;//转为Graphics2D 后面要为画笔设置颜色g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for(int r=0;r
g2d.fillOval(Config.X0+c*Config.SIZE-Config.CHESS_SIZE/2,Config.Y0+r*Config.SIZE-Config.CHESS_SIZE/2 , Config.CHESS_SIZE, Config.CHESS_SIZE);
}else if(exist[r][c]==-1){ //该位置是白子g2d.setColor(Color.WHITE);
g2d.fillOval(Config.X0+c*Config.SIZE-Config.CHESS_SIZE/2,Config.Y0+r*Config.SIZE-Config.CHESS_SIZE/2 , Config.CHESS_SIZE, Config.CHESS_SIZE);
}
}
}
}
}(5)重写面板的paint() 方法,完成重绘
因为我们的主类(fiveChess) 继承了JPanel类,在中间面板的方法里,直接向窗体添加的面板就是主类面板。即:
/*** 往窗体上添加中间面板的方法* @param frame 窗体*/
public void centerPanel(JFrame frame){
this.setBackground(Color.ORANGE);
frame.add(this);
}
所以在主类里直接从写JPanel的paint()方法即可:
public void paint(Graphics g){
super.paint(g);
drawChessTable(g);
reDrawChess(g);
}
注:主类的完整代码
package com.xs.chessAI;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
/*** 五子棋* @author Administrator**/
public class FiveChess extends JPanel{ //继承JPanel类 使FiveChess作为一个面板private int[][] exist=new int[Config.ROWS][Config.COLUMNS]; //创建一个棋子数组 用于保存棋盘上哪个位置有哪个颜色的棋子private ChessListener cl; //声明事件处理类型的 变量/*** 图像界面的显示方法*/
public void showUI(){
JFrame frame=new JFrame(); //创建窗体 frameframe.setTitle("五子棋 "); //设置窗体的标题frame.setSize(750,650);//设置大小frame.setResizable(false);//大小不可变frame.setLocationRelativeTo(null);//窗体居中frame.setDefaultCloseOperation(3);//退出时关闭进程cl=new ChessListener(this);// 实例化事件处理类的对象,将棋盘面板作为参数传递过去centerPanel(frame); //在窗体frame上添加中间面板 ---棋盘eastPanel(frame);//窗体frame上添加东边面板 ---功能按钮
frame.setVisible(true);//设置窗体可见cl.setExist(exist);//将棋子数组传入到事件监听类中
}
/*** 重写面板重绘的方法*/
public void paint(Graphics g){
super.paint(g);
drawChessTable(g);
reDrawChess(g);
}
/*** 往窗体上添加中间面板* @param frame 窗体*/
public void centerPanel(JFrame frame){
this.setBackground(Color.ORANGE);
frame.add(this);
}
/*** 往窗体上添加东边面板 ---用于放置功能按钮* @param frame窗体*/
public void eastPanel(JFrame frame){
JPanel epanel=new JPanel();//创建一个面板对象epanel.setBackground(Color.GRAY);//背景颜色设置为grayepanel.setPreferredSize(new Dimension(150,600)); //设置大小epanel.setLayout(new FlowLayout());//默认也是流式布局String[] buttonArray={"开始游戏","悔棋","认输"}; //数组存储 功能按钮命令for(int i=0;i
String[] radioArray={"人人对战","人机对战"};//数组存储 单选按钮命令ButtonGroup bg=new ButtonGroup();//实例化一个按钮组的对象for(int i=0;i
}
epanel.add(radioButton);//在面板上添加单选按钮radioButton.addActionListener(cl);//加监听器}
frame.add(epanel,BorderLayout.EAST);//为窗体(边框布局)添加面板---放置在东侧}
/*** 绘制棋盘的方法* @param g 传入画笔*/
public void drawChessTable(Graphics g){
for(int r=0;r
}
for(int c=0;c
}
}
/*** 棋子重绘的方法* @param g*/
public void reDrawChess(Graphics g){
Graphics2D g2d=(Graphics2D) g;//转为Graphics2D 后面要为画笔设置颜色g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for(int r=0;r
g2d.fillOval(Config.X0+c*Config.SIZE-Config.CHESS_SIZE/2,Config.Y0+r*Config.SIZE-Config.CHESS_SIZE/2 , Config.CHESS_SIZE, Config.CHESS_SIZE);
}else if(exist[r][c]==-1){ //该位置是白子g2d.setColor(Color.WHITE);
g2d.fillOval(Config.X0+c*Config.SIZE-Config.CHESS_SIZE/2,Config.Y0+r*Config.SIZE-Config.CHESS_SIZE/2 , Config.CHESS_SIZE, Config.CHESS_SIZE);
}
}
}
}
}
public static void main(String[] args) {
FiveC