五子棋实现功能:
1、黑白棋交替下,进行正常的五子棋的输赢判断;
2、实现重新开始游戏清屏、悔棋(不限步数)、认输、人机对战、人人对战(手动交替下黑白棋)
五子棋实现效果:
棋盘界面五子棋设计简述
ps: 类分少了可能代码可读性有些差
“两个类 一个接口”
先说接口:
这个接口的使用其实就是将一些常用的变量定义,之后在改变的时候方便改变值,使用时只要implements这个接口即可。上图可能更明显。
主要谈谈类
一、界面类(含主函数)
里面有4个方法:
1、main方法 :初始化一个对象,调用对象的 initUI()函数。
2、public void initUI()方法:显示界面,Jframe上放两块画布,一块画棋盘(继承JPanel得): 横竖线,一块安各种操作按钮(new):重新开始,悔棋等等。
3、public void paint (Graphics g)方法:重绘功能,调用super.paint()就是为了除了绘制你需要定制的line之外,还要保证绘制这个组件自身的其它元素!因为在刷新、覆盖等操作中,这个组件需要被重新绘制。
paint()方法的调用是awt线程来控制的,jvm提供了这样一个线程来管理组件的各种工作。一旦这个组件被某个其它窗口覆盖之后,或者最小化最大化的过程中,组件本身都会接到awt的重绘事件申请,组件便调用paint()方法来绘制自身和add到组件之上的各种对象。
也就是说一旦发生变化,自动调用paint()进行重绘!
因为以上原理,所以我们需要在这个函数里重绘:窗体+棋盘(横竖线)+棋子(是否下棋用二维数组形式存储)
4、private void drawChessTable(Graphics g) 方法:循环画横竖线
二、监听类(核心操作部分)
在对棋盘上落子鼠标释放、在对”重新开始“”认输“等按钮点击操作等都进行监听处理。
三大部分:
1、在对”重新开始“”认输“等按钮点击棋盘上落子鼠标释放
2、棋盘上落子鼠标释放棋盘上落子鼠标释放
3、判断人机对战算法——权值法(基础、理论是好的,要设计出合适的有效的 a little difficult)
1、在对”重新开始“”认输“等按钮点击棋盘上落子鼠标释放方法
name = e.getActionCommand();得到按钮上的字符串,然后嘞,就根据name内容不同,利用if...else...结构进行不同的x处理。值得注意的是里面y需要调用paint()方法,方法是通过对象调用的,所以记得要把界面类中的对象传来,不能在此类直接新建一个对象来调用。
悔棋利用了数组队列存储点,可以进行不限步数的悔棋,重绘界面更新等。
2、棋盘上落子鼠标释放棋盘上落子鼠标释放
分人人对战与人机对战两部分,详细说下人人对战
黑白子交替下,其中有两个难点:1、下棋,棋子要下在棋盘的十字交叉处;2、要做好存储,不能重复下,要交替下。针对1,则是需要计算找出要下的地方的坐标,填充个圆形那个出来,画的时候,不同的设置画笔颜色白黑交替设置。针对2,利用二维数组存储,黑子存1,白子存-1。
每下完一个棋就要判断该位置,横,竖,斜右、斜左4个方向上有没有连成5个一样的,若果有,就游戏结束。
3、判断人机对战算法——权值法
权值法,设置一定的规则,计算可以下的位置的权值,找出权值最大的位置下棋。
我这个权值法还是雏形,有点笨,还待更新。
对每个位置的8个方向进行检索,每个方向得到的棋盘情况可以对应规则得到一个value值,所有valueh值加就是这个位置的最终权值。用一个chessValue[][]存储权值,遍历找到最大权值处,在此位置上下棋。
五子棋实现详情(代码注释ing)
Config.java(接口)
package Chesses;
public interface Config {
public static final int X0=100; //表格左上角起点的x值
public static final int Y0=100; //表格左上角起点的y值
public static final int ROWS=11; //横向线条数
public static final int COLUMNS=11; //纵向线条数
public static final int CHESS_SIZE=80; //棋子直径
public static final int SIZE=100; //单元格的大小
}
FiveChessUI.java(界面类)
package Chesses;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import Draw.shape;
public class FiveChessUI extends JPanel implements Config {
private int chesses[][]= new int[ROWS][COLUMNS];
static FiveChessUI fcUI=new FiveChessUI();
//主函数
public static void main(String args[]) {
fcUI.initUI();
}
//
public void initUI() {
ChessListener cl=new ChessListener();
JFrame jf=new JFrame();
jf.setTitle("五子棋");
jf.setSize(1500, 1400);
jf.setDefaultCloseOperation(3);
jf.setVisible(true);
//棋盘的画布
//Graphics g = this.getGraphics();
this.setBackground(Color.orange);
this.setPreferredSize(new Dimension(1000,400));
//安操作按钮的jp
JPanel jp=new JPanel();
jp.setBackground(Color.gray);
jp.setPreferredSize(new Dimension(300,400));
String st[]= {"重新开始","认输","悔棋"};
for(int i=0;i<st.length;i++) {
JButton jb= new JButton(st[i]);
jb.setFont(new Font("宋体", Font.BOLD, 20));
jb.setPreferredSize(new Dimension(200,100));
jp.add(jb);
jb.addActionListener(cl);
}
JComboBox jcb = new JComboBox();
jcb.setPreferredSize(new Dimension(200,100));
jcb.setFont(new Font("宋体", Font.BOLD, 25));
//jcb.set
jcb.addItem("人人对战");
jcb.addItem("人机对战");
jp.add(jcb);
jcb.addActionListener(cl);
jf.add(this,BorderLayout.CENTER);
jf.add(jp,BorderLayout.EAST);
jf.setVisible(true);
//监听器
Graphics g = this.getGraphics(); //画笔在界面可见后获取
cl.setg(g);
cl.setc(chesses);
cl.sets(fcUI);
cl.setj(jcb);
this.addMouseListener(cl);
}
public void paint (Graphics g)
{ //重绘窗体
super.paint(g);
//重绘窗体同时绘制棋盘
drawChessTable(g);
//重绘棋子
for(int j=0;j< ROWS;j++) {
for(int i=0;i< COLUMNS;i++) {
if(chesses[i][j]==1) {
g.setColor(Color.BLACK);
int x= X0+ SIZE*i; //横坐标
int y= Y0+ SIZE*(j); //纵坐标
g.fillOval(x-CHESS_SIZE/2,y-CHESS_SIZE/2,CHESS_SIZE,CHESS_SIZE);
}else if(chesses[i][j]==-1) {
g.setColor(Color.white);
int x= X0+ SIZE*i; //横坐标
int y= Y0+ SIZE*(j); //纵坐标
g.fillOval(x-CHESS_SIZE/2,y-CHESS_SIZE/2,CHESS_SIZE,CHESS_SIZE);
}
}
}
}
private void drawChessTable(Graphics g) {
//画棋盘横线
for(int i=0;i< ROWS;i++) {
g.drawLine( X0, Y0+i* SIZE, X0+( COLUMNS-1)* SIZE, Y0+i* SIZE);
}
//画棋盘竖线
for(int j=0;j< COLUMNS;j++) {
g.drawLine( X0+j* SIZE, Y0, X0+j* SIZE, Y0+( ROWS-1)* SIZE);
}
}
}
ChessListener.java(监听类)
package Chesses;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
public class ChessListener extends MouseAdapter implements Config, ActionListener {
private String name = null, name1 = "人人对战";
private boolean game = true;
private Graphics g;
private int count = 0, r = 0, l = 0, max = 0;
private int[][] chesses;
private int[][] chessValue = new int[ROWS][COLUMNS];
FiveChessUI fc = new FiveChessUI();
private JComboBox jcb;
int num = 0;
ArrayList<Point> list = new ArrayList<Point>();
HashMap<String, Integer> hm = new HashMap<String, Integer>();
public void hash() {
hm.put("1", 20);
hm.put("11", 200);
hm.put("111", 2000);
hm.put("1111", 3000);
hm.put("1-1", 10);
hm.put("11-1", 100);
hm.put("111-1", 1000);
hm.put("1111-1", 2000);
}
//传参
public void setg(Graphics g) {
this.g = g;
}
public void setc(int[][] chesses) {
this.chesses = chesses;
}
public void sets(FiveChessUI fc) {
this.fc = fc;
}
public void setj(JComboBox jcb) {
this.jcb = jcb;
}
public void mouseReleased(MouseEvent e) {
if ("人人对战".equals(name1)) {
// 得到鼠标事件发生时光标的位置
int x1 = e.getX();
int y1 = e.getY();
// 按行遍历棋盘,坐标(i,j)
for (int j = 0; j < ROWS; j++) {
for (int i = 0; i < COLUMNS; i++) {
// 得到交叉点的坐标
int x = X0 + SIZE * i; // 横坐标
int y = Y0 + SIZE * j; // 纵坐标
// 得到交叉点的行列
// 与圆心的误差为size/3
if (x1 > x - SIZE / 2 && x1 < x + SIZE / 2 && y1 > y - SIZE / 2 && y1 < y + SIZE / 2 && game) {
if (chesses[i][j] == 0) {
if (count == 0) {
chesses[i][j] = 1; // 黑子为1
Point p=new Point();
p.setLocation(i, j);
list.add(p);
g.setColor(Color.black);
count++;
} else {
chesses[i][j] = -1; // 白子为-1
Point p=new Point();
p.setLocation(i, j);
list.add(p);
g.setColor(Color.white);
count--;
}
// 画棋子
g.fillOval(x - CHESS_SIZE / 2, y - CHESS_SIZE / 2, CHESS_SIZE, CHESS_SIZE);
this.win(i, j);
}
}
}
}
} else if ("人机对战".equals(name1)) {
// 得到鼠标事件发生时光标的位置
int x1 = e.getX();
int y1 = e.getY();
// 按行遍历棋盘,坐标(i,j)
for (int j = 0; j < ROWS; j++) {
for (int i = 0; i < COLUMNS; i++) {
// 得到交叉点的坐标
int x = X0 + SIZE * i; // 横坐标
int y = Y0 + SIZE * j; // 纵坐标
// 得到交叉点的行列
// 与圆心的误差为size/3
if (x1 > x - SIZE / 2 && x1 < x + SIZE / 2 && y1 > y - SIZE / 2 && y1 < y + SIZE / 2 && game) {
if (chesses[i][j] == 0) {
// 人下黑棋子
if (count == 0) {
chesses[i][j] = 1; // 黑子为1
Point p=new Point();
p.setLocation(i, j);
list.add(p);
g.setColor(Color.black);
count++;
}
// 画棋子
g.fillOval(x - CHESS_SIZE / 2, y - CHESS_SIZE / 2, CHESS_SIZE, CHESS_SIZE);
this.win(i, j);
}
}
}
}
////////////////////////////////////////////////////////////
// 机器画白棋子
// 找到value最大的位置的i j
// while(true) {
if (game) {
this.count();
for (int j = 0; j < ROWS; j++) {
for (int i = 0; i < COLUMNS; i++) {
if (chessValue[i][j] > max) {
max = chessValue[i][j];
r = i;
l = j;
}
}
}
// System.out.println(r + " "+l);
// for(int i=0;i<11;i++)
// for(int j=0;j<11;j++) {
// System.out.print(chessValue[i][j]+" ");
// num++;
// if(num==11) {
// System.out.println(" ");
// num=0;
// }
// }
// 清空
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLUMNS; j++)
chessValue[i][j] = 0;
}
max = 0;
// 最大位置是(r,l)
if (count == 1) {
g.setColor(Color.white);
Point p=new Point();
p.setLocation(r, l);
list.add(p);
chesses[r][l] = -1; // 机器下白子
count--;
}
g.fillOval(X0 + SIZE * r - CHESS_SIZE / 2, Y0 + SIZE * l - CHESS_SIZE / 2, CHESS_SIZE, CHESS_SIZE);
this.win(r, l);
}
// }
} // 人机
}// 释放
public void count() {
for (int i = 0; i < chesses.length; i++) {
for (int j = 0; j < chesses[i].length; j++) {
// 判断当前是否为空
if (chesses[i][j] == 0) {
// 搜索该空位八个方向上棋局情况,并计算value值
// 定义两个变量分别保存棋局,以及颜色
String code = "";
int color = 0;
// 向下方向
for (int k = i + 1; k < ROWS; k++) {
if (chesses[k][j] == 0) { // 下一个为空就停止匹配
break;
} else {
if (color == 0) { // 下面的第1颗棋子
color = chesses[k][j]; // 保存颜色
code += chesses[k][j]; // 保存棋局
} else if (chesses[k][j] == color) { // 下边第2/3/4...同颜色棋子
code += chesses[k][j]; // 保存棋局
} else { // 下边第2/3/4....不同颜色
code += chesses[k][j]; // 保存棋局
break;
}
}
}
// 根据code取出hm对应的权值
Integer value = hm.get(code);
if (value != null) {
chessValue[i][j] += value; // 权值
}
code = "";
color = 0;
// 向上方向
for (int k = i - 1; k >= 0; k--) {
if (chesses[k][j] == 0) { // 下一个为空就停止匹配
break;
} else {
if (color == 0) { // 下面的第1颗棋子
color = chesses[k][j]; // 保存颜色
code += chesses[k][j]; // 保存棋局
} else if (chesses[k][j] == color) { // 右边第2/3/4...同颜色棋子
code += chesses[k][j]; // 保存棋局
} else { // 下边第2/3/4....不同颜色
code += chesses[k][j]; // 保存棋局
break;
}
}
}
// 根据code取出hm对应的权值
Integer value1 = hm.get(code);
if (value1 != null) {
chessValue[i][j] += value1; // 权值
}
code = "";
color = 0;
// 向右方向
for (int k = j + 1; k < COLUMNS; k++) {
if (chesses[i][k] == 0) { // 下一个为空就停止匹配
break;
} else {
if (color == 0) { // 下面的第1颗棋子
color = chesses[i][k]; // 保存颜色
code += chesses[i][k]; // 保存棋局
} else if (chesses[i][k] == color) { // 右边第2/3/4...同颜色棋子
code += chesses[i][k]; // 保存棋局
} else { // 下边第2/3/4....不同颜色
code += chesses[i][k]; // 保存棋局
break;
}
}
}
// 根据code取出hm对应的权值
Integer value2 = hm.get(code);
if (value2 != null) {
chessValue[i][j] += value2; // 权值
}
code = "";
color = 0;
// 向左方向
for (int k = j - 1; k >= 0; k--) {
if (chesses[i][k] == 0) { // 下一个为空就停止匹配
break;
} else {
if (color == 0) { // 下面的第1颗棋子
color = chesses[i][k]; // 保存颜色
code += chesses[i][k]; // 保存棋局
} else if (chesses[i][k] == color) { // 右边第2/3/4...同颜色棋子
code += chesses[i][k]; // 保存棋局
} else { // 下边第2/3/4....不同颜色
code += chesses[i][k]; // 保存棋局
break;
}
}
}
// 根据code取出hm对应的权值
Integer value3 = hm.get(code);
if (value3 != null) {
chessValue[i][j] += value3; // 权值
}
code = "";
color = 0;
// 向左上方向
for (int k = j - 1, l = i - 1; k >= 0 && l >= 0; k--, l--) {
if (chesses[l][k] == 0) { // 下一个为空就停止匹配
break;
} else {
if (color == 0) { // 下面的第1颗棋子
color = chesses[l][k]; // 保存颜色
code += chesses[l][k]; // 保存棋局
} else if (chesses[l][k] == color) { // 右边第2/3/4...同颜色棋子
code += chesses[l][k]; // 保存棋局
} else { // 下边第2/3/4....不同颜色
code += chesses[l][k]; // 保存棋局
break;
}
}
}
// 根据code取出hm对应的权值
Integer value4 = hm.get(code);
if (value4 != null) {
chessValue[i][j] += value4; // 权值
}
code = "";
color = 0;
// 向左下方向
for (int k = j - 1, l = i + 1; k >= 0 && l < ROWS; k--, l++) {
if (chesses[l][k] == 0) { // 下一个为空就停止匹配
break;
} else {
if (color == 0) { // 下面的第1颗棋子
color = chesses[l][k]; // 保存颜色
code += chesses[l][k]; // 保存棋局
} else if (chesses[l][k] == color) { // 右边第2/3/4...同颜色棋子
code += chesses[l][k]; // 保存棋局
} else { // 下边第2/3/4....不同颜色
code += chesses[l][k]; // 保存棋局
break;
}
}
}
// 根据code取出hm对应的权值
Integer value5 = hm.get(code);
if (value5 != null) {
chessValue[i][j] += value5; // 权值
}
code = "";
color = 0;
// 向右下方向
for (int k = j + 1, l = i + 1; k < COLUMNS && l < ROWS; k++, l++) {
if (chesses[l][k] == 0) { // 下一个为空就停止匹配
break;
} else {
if (color == 0) { // 下面的第1颗棋子
color = chesses[l][k]; // 保存颜色
code += chesses[l][k]; // 保存棋局
} else if (chesses[l][k] == color) { // 右边第2/3/4...同颜色棋子
code += chesses[l][k]; // 保存棋局
} else { // 下边第2/3/4....不同颜色
code += chesses[l][k]; // 保存棋局
break;
}
}
}
// 根据code取出hm对应的权值
Integer value6 = hm.get(code);
if (value6 != null) {
chessValue[i][j] += value6; // 权值
}
code = "";
color = 0;
// 向右上方向
for (int k = j + 1, l = i - 1; k < COLUMNS && l >= 0; k++, l--) {
if (chesses[l][k] == 0) { // 下一个为空就停止匹配
break;
} else {
if (color == 0) { // 下面的第1颗棋子
color = chesses[l][k]; // 保存颜色
code += chesses[l][k]; // 保存棋局
} else if (chesses[l][k] == color) { // 右边第2/3/4...同颜色棋子
code += chesses[l][k]; // 保存棋局
} else { // 下边第2/3/4....不同颜色
code += chesses[l][k]; // 保存棋局
break;
}
}
}
// 根据code取出hm对应的权值
Integer value7 = hm.get(code);
if (value7 != null) {
chessValue[i][j] += value7; // 权值
}
code = "";
color = 0;
}
}
}
}
private void win(int i, int j) {
if (this.checkRow(i, j) >= 5 || this.checkColumn(i, j) >= 5 || this.checkL_R(i, j) >= 5
|| this.checkR_L(i, j) >= 5) {
if (count == 1) {
System.out.println("黑方赢了"); // 如何停止游戏
game = false;
JOptionPane.showMessageDialog(null, "不好意思,黑方赢了");
}
else if (count == 0) {
System.out.println("白方赢了");
game = false;
JOptionPane.showMessageDialog(null, "不好意思,白方赢了");
}
}
}
// 斜向左下检查
private int checkR_L(int x, int y) {
// TODO Auto-generated method stub
int count = 0;
for (int i = x - 1, j = y + 1; i >= 0 && j < ROWS; i--, j++) { // 纵向向下检测
if (chesses[i][j] == chesses[x][y]) {
count++;
} else
break;
}
for (int i = x, j = y; i < COLUMNS && j >= 0; i++, j--) // 向上
{
if (chesses[i][j] == chesses[x][y]) {
count++;
} else
break;
}
return count;
}
// 斜向右下检查
private int checkL_R(int x, int y) {
// TODO Auto-generated method stub
int count = 0;
for (int i = x + 1, j = y + 1; i < COLUMNS && j < ROWS; i++, j++) { // 纵向向下检测
if (chesses[i][j] == chesses[x][y]) {
count++;
} else
break;
}
for (int i = x, j = y; i >= 0 && j >= 0; i--, j--) // 向上
{
if (chesses[i][j] == chesses[x][y]) {
count++;
} else
break;
}
return count;
}
// 纵向检测
private int checkColumn(int x, int y) {
// TODO Auto-generated method stub
int count = 0;
for (int i = y + 1; i < ROWS; i++) { // 纵向向下检测
if (chesses[x][i] == chesses[x][y]) {
count++;
} else
break;
}
for (int i = y; i >= 0; i--) // 向上
{
if (chesses[x][i] == chesses[x][y]) {
count++;
} else
break;
}
return count;
}
// 横向检测
private int checkRow(int x, int y) {
// TODO Auto-generated method stub
int count = 0;
for (int i = x + 1; i < COLUMNS; i++) { // 横向向右检测
if (chesses[x][y] == chesses[i][y]) {
count++;
} else
break;
}
for (int i = x; i >= 0; i--) {
if (chesses[x][y] == chesses[i][y]) {
count++;
} else
break;
}
return count;
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
name = e.getActionCommand();
//按钮判断
if("重新开始".equals(name)) {
for(int m=0;m< ROWS;m++) {
for(int n=0;n< COLUMNS;n++) {
chesses[m][n] = 0;
//System.out.println( chesses[m][n]);
}
}
fc.paint(g);
name=null;
count=0;
game=true;
}
else if("认输".equals(name)&&game) {
if(count==1) {
JOptionPane.showMessageDialog(null, "白方认输");
}else if(count==0) {
JOptionPane.showMessageDialog(null, "黑方认输");
}
game=false;
}
else if("悔棋".equals(name)&&game) {
if(list.size()>0) {
Point p=new Point();
p= list.remove(list.size()-1);
chesses[(int)p.getX()][(int)p.getY()]=0;
fc.paint(g);
if(count==1) count--;
else if(count==0) count++;
}
}
else {
name1=(String)jcb.getSelectedItem();
if("人机对战".equals(name1)) {
this.hash();
}else if("人人对战".equals(name1)) {
game=true;
}
}
}
}