今天来分享一个Java五子棋。
所涉及到的知识
首先定义一个BorderSize的接口,用来设置棋盘和棋子的相关属性。凡是需要用到接口中相关属性的类都必须实现BorderSize接口。
public interface BorderSize {
int SIZE = 50;
int ROW = 19;
int COLUM = 19;
int X = 30;
int Y = 30;
int[][] chessArray = new int[ROW][COLUM];
int[][] weightArray = new int[ROW][COLUM];
}
棋盘界面类中主要定义了界面的样式以及重绘方法
public class ChessBorder extends JPanel implements BorderSize{
public void showBorder(){
JFrame frame = new JFrame();
frame.setTitle("我的五子棋");
frame.setSize(1100, 1000);
//设置窗体不可改变大小
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置棋盘背景图片
ImageIcon centerIcon = new ImageIcon("C:\\Users\\sunxiaona\\Desktop\\Java\\蓝杰\\Image\\4.jpg");
JLabel centerLabel = new JLabel(centerIcon);
this.add(centerLabel);
//设置容器为边框布局
frame.setLayout(new BorderLayout());
//this.setBackground(Color.LIGHT_GRAY);
frame.add(this, BorderLayout.CENTER);
//添加按钮面板并设置大小
JPanel eastPanel = new JPanel();
eastPanel.setBackground(Color.DARK_GRAY);
Dimension eastPsize = new Dimension(120,1000);
eastPanel.setPreferredSize(eastPsize);
frame.add(eastPanel, BorderLayout.EAST);
//添加标签,使按钮居中
JLabel label = new JLabel();
Dimension labelSize = new Dimension(110,300);
label.setPreferredSize(labelSize);
eastPanel.add(label);
//创建监听器对象
BorderListener BL = new BorderListener();
//添加鼠标监听器到棋盘面板
//this.addMouseListener(BL);
//设置按钮的大小
Dimension buttonSize = new Dimension(110,50);
String[] btn ={"开始新游戏","认输","悔棋"};
for(int i=0;i<btn.length;i++){
JButton button = new JButton(btn[i]);
button.setPreferredSize(buttonSize);
button.addActionListener(BL);
eastPanel.add(button);
}
String[] item = {"人人对战","人机对战"};
JComboBox<String> JCB = new JComboBox<String>(item);
JCB.setPreferredSize(buttonSize);
eastPanel.add(JCB);
JCB.addActionListener(BL);
//显示可见
frame.setVisible(true);
BL.setPanel(this);
BL.setJCB(JCB);
BL.setCHB(this);
}
public void paint(Graphics g){
super.paint(g);
for(int i=0;i<ROW;i++){
//画横线
g.drawLine(X,Y+SIZE*i,X+(ROW-1)*SIZE,Y+SIZE*i);
g.drawLine(X+SIZE*i, Y, X+SIZE*i,Y+SIZE*(COLUM-1));
}
//画棋子
for(int i=0;i<ROW;i++){
for(int j=0;j<COLUM;j++){
if(chessArray[i][j]==1){
g.setColor(Color.BLACK);
g.fillOval(X+i*SIZE-SIZE/2, Y+j*SIZE-SIZE/2, SIZE, SIZE);
}
if(chessArray[i][j]==2){
g.setColor(Color.WHITE);
g.fillOval(X+i*SIZE-SIZE/2, Y+j*SIZE-SIZE/2, SIZE, SIZE);
}
}
}
}
public static void main(String[] args){
ChessBorder CHB = new ChessBorder();
CHB.showBorder();
}
所有的逻辑实现全部在监听器类中,在本五子棋中有“人人对战”和“人机对战”两种对战模式,并且有开始新游戏、悔棋、认输等操作。所有的这些操作所产生的效果都在监听器类中定义了。细节之处见代码!
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class BorderListener implements BorderSize,MouseListener,ActionListener{
int x,y;
JPanel panel;
JComboBox JCB;
ChessBorder CHB;
int count = 0;
String fightType = "人人对战";
int huiX,huiY;
int max,row,colum; //人机大战需要用的数据
//获取画布
public void setPanel(JPanel panel){
this.panel = panel;
}
//传递JComboBox
public void setJCB(JComboBox JCB){
this.JCB = JCB;
}
//传递ChessBorder
public void setCHB(ChessBorder CHB){
this.CHB = CHB;
}
public void actionPerformed(ActionEvent e){
String action = e.getActionCommand();
if("开始新游戏".equals(action)){
//清空棋盘
for(int i=0;i<ROW;i++){
for(int j=0;j<COLUM;j++){
chessArray[i][j] = 0;
}
}
//设置JComboBox不可用
JCB.setEnabled(false);
panel.addMouseListener(this);
//画的时候获取画布(游戏重新开始后清空画板)
Graphics g = panel.getGraphics();
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
CHB.paint(g);
}else if("认输".equals(action)){
if(count==0){
JOptionPane.showMessageDialog(null, "白棋获胜!!!");
}else {
JOptionPane.showMessageDialog(null, "黑棋获胜!!!");
}
//黑棋先下
count = 0;
JCB.setEnabled(true);
panel.removeMouseListener(this);
}else if("悔棋".equals(action)){
chessArray[huiX][huiY] = 0;
Graphics g = panel.getGraphics();
//抗锯齿效果
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
if(count==0){
count = 1;
}else {
count = 0;
}
CHB.paint(g);
}else {
String s =(String)JCB.getSelectedItem();
fightType = s;
}
}
public void mouseReleased(MouseEvent e){
x = e.getX();
y = e.getY();
Result result = new Result();
if(panel!=null){
Graphics g = panel.getGraphics();
//抗锯齿处理 添加此行后,棋子边缘光滑
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
int index = 0;
int r,c;
for(int i=X;i<=(ROW-1)*SIZE;i=i+SIZE){
for(int j=Y;j<=(COLUM-1)*SIZE;j=j+SIZE){
if((x-i>-SIZE/2&&x-i<SIZE/2)&&(y-j>-SIZE/2&&y-j<SIZE/2)){
r = (i-X)/SIZE;
c = (j-Y)/SIZE;
//画黑棋
if(count==0 && chessArray[r][c]!=1 && chessArray[r][c]!=2){
chessArray[r][c] = 1;
g.setColor(Color.BLACK);
g.fillOval(i-SIZE/2, j-SIZE/2, SIZE, SIZE);
count++; //转换到白棋
result.r = r;
result.c = c;
//悔棋的棋子
huiX = r;
huiY = c;
}
//画白棋
if(count==1 && chessArray[r][c]!=1 && chessArray[r][c]!=2){
chessArray[r][c] = 2;
g.setColor(Color.WHITE);
g.fillOval(i-SIZE/2, j-SIZE/2, SIZE, SIZE);
count--; //转换到黑棋
result.r = r;
result.c = c;
//悔棋的棋子
huiX = r;
huiY = c;
}
}
}
}
//(人人对战判断黑白棋胜利)和(人机对战判断黑棋部分)
if(result.WinOrLoss()){
if(chessArray[result.r][result.c]==1){
JOptionPane.showMessageDialog(null, "黑棋获胜!");
}
if(chessArray[result.r][result.c]==2){
JOptionPane.showMessageDialog(null, "白棋胜利!");
}
//重新开始后黑棋先下
count = 0;
//游戏结束后设置下拉列表框为可用
JCB.setEnabled(true);
//游戏结束后不可继续下棋 (移除鼠标监听器)
panel.removeMouseListener(this);
}
//人机对战部分
if("人机对战".equals(fightType)){
AI ai = new AI();
ai.AIplay();
int max=0;
//寻找最大权重
for(int i=0;i<ROW;i++){
for(int j=0;j<COLUM;j++){
if(weightArray[i][j]>max){
max = weightArray[i][j];
row = i;
colum = j;
}
System.out.print(weightArray[i][j]+" ");
}
System.out.println();
}
System.out.println(max);
//人机对战中画电脑的棋子
if(count==1){
chessArray[row][colum] = 2;
g.setColor(Color.WHITE);
System.out.println(row+" "+colum);
g.fillOval(row*SIZE+X-SIZE/2,colum*SIZE+Y-SIZE/2 ,SIZE, SIZE);
count--;
}
result.r = row;
result.c = colum;
}
if(result.WinOrLoss()&&"人机对战".equals(fightType)){
if(chessArray[row][colum]==2){
JOptionPane.showMessageDialog(null, "白棋胜利!");
row = 0;
colum = 0;
}
//重新开始后黑棋先下
count = 0;
//游戏结束后设置下拉列表框为可用
JCB.setEnabled(true);
//游戏结束后不可继续下棋 (移除鼠标监听器)
panel.removeMouseListener(this);
}
}
}
public void mouseClicked(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
}
实现了上述内容之后,我们已经可以在棋盘上顺利下棋了,那么接下来当然是判断输赢了。判断输赢分别从4个方向上统计:水平、垂直、左斜、右斜。只要搞清楚原理即可,这部分的代码大同小异,基本上都是重复工作。
package goBang;
public class Result implements BorderSize{
boolean flag = false;
int r,c;
public boolean WinOrLoss(){
if(resultH(r,c)>=5||resultS(r,c)>=5||resultL(r,c)>=5||resultR(r,c)>=5){
return !flag;
}else {
return flag;
}
}
//横向判断
public int resultH(int r,int c){
int count=1;
//往左走
for(int i=c-1;i>=0;i--){
if(chessArray[r][c]==chessArray[r][i]&&chessArray[r][i]!=0){
count++;
}else {
break;
}
}
//往右走
for(int i=c+1;i<ROW;i++){
if(chessArray[r][c]==chessArray[r][i]&&chessArray[r][i]!=0){
count++;
}else {
break;
}
}
return count;
}
//竖向判断
public int resultS(int r,int c){
int count=1;
//往上走
for(int i=r-1;i>=0;i--){
if(chessArray[r][c]==chessArray[i][c]&&chessArray[i][c]!=0){
count++;
}else {
break;
}
}
//往下走
for(int i=r+1;i<ROW;i++){
if(chessArray[r][c]==chessArray[i][c]&&chessArray[i][c]!=0){
count++;
}else {
break;
}
}
return count;
}
//斜向判断(左上到右下)
public int resultL(int r,int c){
int count=1;
//往左走
for(int i=r-1,j=c-1;i>=0&&j>=0;i--,j--){
if(chessArray[i][j]==chessArray[r][c]&&chessArray[i][j]!=0){
count++;
}else{
break;
}
}
//往右走
for(int i=r+1,j=c+1;i<ROW&&j<COLUM;i++,j++){
if(chessArray[i][j]==chessArray[r][c]&&chessArray[i][j]!=0){
count++;
}else {
break;
}
}
return count;
}
//斜向判断(左下到右上)
public int resultR(int r,int c){
int count=1;
//往左走
for(int i=r+1,j=c-1;i<ROW&&j>=0;i++,j--){
if(chessArray[i][j]==chessArray[r][c]&&chessArray[i][j]!=0){
count++;
}else {
break;
}
}
//往右走
for(int i=r-1,j=c+1;i>=0&&j<ROW;i--,j++){
if(chessArray[i][j]==chessArray[r][c]&&chessArray[i][j]!=0){
count++;
}else {
break;
}
}
return count;
}
}
如果想为我们的五子棋增添一点点人工智能的色彩,就需要知道如何指挥电脑下棋了。想深入了解的小伙伴可以参考一下权值算法、博弈树…我用的是权值算法(下面内容,算法不是特别完善哈,你们可以参考参考自己写一个更厉害的AI)
package goBang;
import java.util.HashMap;
public class AI implements BorderSize{
static HashMap<String,Integer> map = new HashMap<String,Integer>();
static {
//防守
map.put("0", 1);
map.put("010",10);
map.put("021", 15);
map.put("0112",20);
map.put("0221",150);
map.put("02221",400);
map.put("01112",500);
map.put("0110", 800);
map.put("022221", 5000);
map.put("01110", 2000);
map.put("011112", 7000);
map.put("02020", 300);
map.put("02220", 5000);
map.put("020", 25);
map.put("0220",280);
map.put("022220",100000);
map.put("01111", 4000);
map.put("02", 5);
}
//判断每个点的权值
public void AIplay(){
for(int i=0;i<ROW;i++){
for(int j=0;j<COLUM;j++){
weightArray[i][j]=0;
}
}
for(int r=0;r<ROW;r++){
for(int c=0;c<COLUM;c++){
if(chessArray[r][c]==0){ //判断该位是否为空位
//水平方向
String code = "0"; //用来记录棋子相连的情况
int chess = 0; //记录第一次出现的棋子
int number = 0; //记录空位出现的次数
//水平向左统计
for(int i=c-1;i>=0;i--){
if(chessArray[r][i]==0){//判断是否为空位
if(c==i+1){
break; //如果有两个连续的空位,跳出
}else if(number==0){ //第一次出现空位
code = code +chessArray[r][i]; //记录棋子相连的情况
number++;
}else if(number==1){ //第二次出现空位
if(chessArray[r][i]==chessArray[r][i+1]){ //判断是否又为2个连续的空位
break;
}
code = code +chessArray[r][i];
number++;
}else if(number==2){ //第三次出现空位
if(chessArray[r][i]==chessArray[r][i+1]){ //空位连续
break;
}
}
}else{ //该位是棋子
if(chess==0){ //第一次出现棋子
chess =chessArray[r][i];
code = code +chessArray[r][i];
}else if(chess==chessArray[r][i]){
code = code +chessArray[r][i];
}else {
code = code +chessArray[r][i];
break;
}
}
}
System.out.print(code+" ");
Integer value0 = map.get(code); //Inter 整数类
if(value0!=null){
weightArray[r][c] += value0;
}
code = "0";
chess = 0;
number=0;
//水平向右统计
for(int i=c+1;i<COLUM;i++){
if(chessArray[r][i]==0){
if(c==i-1){
break; //相邻2空位,跳出
}else if(number==0){ //第一次出现空位
code = code +chessArray[r][i];
number++;
}else if(number==1){ ////第2次出现空位
if(chessArray[r][i]==chessArray[r][i-1]){
break; //连续2空位跳出
}else{
code = code + chessArray[r][i];
number++;
}
}else if(number==2){ //第3次出现空位
if(chessArray[r][i]==chessArray[r][i-1]){
break;
}
}
}else { //该位位棋子
if(chess==0){
chess = chessArray[r][i];
code = code +chessArray[r][i];
}else if(chess==chessArray[r][i]){
code = code +chessArray[r][i];
}else { //碰到不同颜色的棋子跳出循环
code = code +chessArray[r][i];
break;
}
}
}
System.out.print(code+" ");
Integer value1 = map.get(code); //Inter 整数类
if(value1!=null){
weightArray[r][c] += value1;
}
//垂直方向
code = "0";
chess = 0;
number=0;
//垂直向上
for(int i=r-1;i>=0;i--){
if(chessArray[i][c]==0){
if(r==i+1){
break; //连续2个空位跳出循环
}else if(number==0){ //第一次出现空位
code = code +chessArray[i][c];
number++;
}else if(number==1){//第2次出现空位
if(chessArray[i][c]==chessArray[i+1][c]){
break;
}else {
code = code +chessArray[i][c];
number++;
}
}else if(number==2){//第3次出现空位
if(chessArray[i][c]==chessArray[i+1][c]){
break;
}
}
}else {
if(chess==0){
chess = chessArray[i][c];
code = code +chessArray[i][c];
}else if(chess==chessArray[i][c]){
code = code +chessArray[i][c];
}else {
code = code +chessArray[i][c];
break;
}
}
}
System.out.print(code+" ");
Integer value2 = map.get(code); //Inter 整数类
if(value2!=null){
weightArray[r][c] += value2;
}
code = "0";
chess = 0;
number=0;
//垂直向下
for(int i=r+1;i<ROW;i++){
if(chessArray[i][c]==0){
if(r==i-1){
break;
}else if(number==0){
code = code +chessArray[i][c];
number++;
}else if(number==1){
if(chessArray[i][c]==chessArray[i-1][c]){
break;
}else {
code = code +chessArray[i][c];
}
}else if(number==2){
if(chessArray[i][c]==chessArray[i-1][c]){
break;
}
}
}else {
if(chess==0){
chess = chessArray[i][c];
code = code +chessArray[i][c];
}else if(chess==chessArray[i][c]){
code = code +chessArray[i][c];
}else {
code = code +chessArray[i][c];
break;
}
}
}
Integer value3 = map.get(code); //Inter 整数类
if(value3!=null){
weightArray[r][c] += value3;
// }
//左斜
code = "0";
chess = 0;
number=0;
//往左上
int i,j;
for(i=r-1,j=c-1;i>=0&&j>=0;i--,j--){
if(chessArray[i][j]==0){
if(r==i+1&&c==j+1){
break;
}else if(number==0){
code = code +chessArray[i][j];
number++;
}else if(number==1){
if(chessArray[i][j]==chessArray[i+1][j+1]){
break;
}else {
code = code +chessArray[i][j];
number++;
}
}else if(number==2){
if(chessArray[i][j]==chessArray[i+1][j+1]){
break;
}
}
}else {
if(chess==0){
chess=chessArray[i][j];
code = code +chessArray[i][j];
}else if(chess==chessArray[i][j]){
code = code +chessArray[i][j];
}else {
code = code +chessArray[i][j];
break;
}
}
}
System.out.println(code+" ");
Integer value4 = map.get(code); //Inter 整数类
if(value4!=null){
weightArray[r][c] += value4;
}
code = "0";
chess = 0;
number = 0;
//往右下
for(i=r+1,j=c+1;i<ROW&&j<COLUM;i++,j++){
if(chessArray[i][j]==0){
if(r==i-1&&c==j-1){
break;
}else if(number==0){
code = code +chessArray[i][j];
number++;
}else if(number==1){
if(chessArray[i][j]==chessArray[i-1][j-1]){
break;
}else {
code = code +chessArray[i][j];
number++;
}
}else if(number==2){
if(chessArray[i][j]==chessArray[i-1][j-1]){
break;
}
}
}else {
if(chess==0){
chess = chessArray[i][j];
code = code +chessArray[i][j];
}else if(chess==chessArray[i][j]){
code = code +chessArray[i][j];
}else {
code = code +chessArray[i][j];
break;
}
}
}
System.out.println(code+" ");
Integer value5 = map.get(code); //Inter 整数类
if(value5!=null){
weightArray[r][c] += value5;
}
//右斜
code = "0";
chess = 0;
number = 0;
//往左
for(i=r+1,j=c-1;i<ROW&&j>=0;i++,j--){
if(chessArray[i][j]==0){
if(r==i-1&&c==j+1){
break;
}else if(number==0){
code = code +chessArray[i][j];
number++;
}else if(number==1){
if(chessArray[i][j]==chessArray[i-1][j+1]){
break;
}else {
code = code +chessArray[i][j];
number++;
}
}else if(number==2){
if(chessArray[i][j]==chessArray[i-1][j+1]){
break;
}
}
}else {
if(chess==0){
chess=chessArray[i][j];
code = code +chessArray[i][j];
}else if(chess==chessArray[i][j]){
code = code +chessArray[i][j];
}else {
code = code +chessArray[i][j];
break;
}
}
}
System.out.println(code+" ");
Integer value6 = map.get(code); //Inter 整数类
if(value6!=null){
weightArray[r][c] += value6;
}
//往右
code = "0";
chess = 0;
number = 0;
for(i=r-1,j=c+1;i>=0&&j<COLUM;i--,j++){
if(chessArray[i][j]==0){
if(r==i+1&&c==j-1){
break;
}else if(number==0){
code = code +chessArray[i][j];
number++;
}else if(number==1){
if(chessArray[i][j]==chessArray[i+1][j-1]){
break;
}else {
code = code +chessArray[i][j];
number++;
}
}else if(number==2){
if(chessArray[i][j]==chessArray[i+1][j-1]){
break;
}
}
}else {
if(chess==0){
chess=chessArray[i][j];
code = code +chessArray[i][j];
}else if(chess==chessArray[i][j]){
code = code +chessArray[i][j];
}else {
code = code +chessArray[i][j];
break;
}
}
}
System.out.println(code+" ");
Integer value7 = map.get(code); //Inter 整数类
if(value7!=null){
weightArray[r][c] += value7;
}
}
}
}
}
}
}
可承接各种项目,有意者加QQ:1217898975