JAVA五子棋人人对战的实现
此程序只实现了五子棋的人人对战功能,人机对战功能待完善算法问题后补充
棋子类
package FiveChess;
import java.awt.Color;
//棋子
public class Chess{
private int x;
private int y;
private Color color;
public static final int R=30;
public Chess(int x,int y,Color color){
this.x=x;
this.y=y;
this.color=color;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public Color getColor(){
return color;
}
}
棋盘类
这里包括算法的核心,获取棋子索引,判断是否达成获胜条件(4个方向任意一个方向累加至五子)
package FiveChess;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
/**
* 五子棋--棋盘类
*/
public class ChessBoard extends JPanel implements MouseListener {
public static final int MARGIN=30;//边距
public static final int GRID_SPAN=35;//网格间距
public static final int ROWS=15;//棋盘行数
public static final int COLS=15;//棋盘列数
Chess[] chessList=new Chess[(ROWS+1)*(COLS+1)];
boolean isBlack=true;//默认开始是黑棋先
boolean gameOver=false;//游戏是否结束
int chessCount;//当前棋盘棋子的个数
int xIndex,yIndex;//当前刚下棋子的索引
Color colortemp;
public ChessBoard(){
setBackground(Color.white);
addMouseListener(this);
addMouseMotionListener(new MouseMotionListener(){
public void mouseDragged(MouseEvent e){
}
public void mouseMoved(MouseEvent e){
int x1=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
//将鼠标点击的坐标位置转成网格索引
int y1=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
//游戏已经结束不能下
//落在棋盘外不能下
//x,y位置已经有棋子存在,不能下
if(x1<0||x1>ROWS||y1<0||y1>COLS||gameOver||findChess(x1,y1))
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
//设置成默认状态
else setCursor(new Cursor(Cursor.HAND_CURSOR));
}
});
}
public void paintComponent(Graphics g){
super.paintComponent(g);//画棋盘
int FWidth=getWidth();
int FHeight=getHeight();
for(int i=0;i<=ROWS;i++){//画横线
g.drawLine(MARGIN, MARGIN+i*GRID_SPAN, MARGIN+COLS*GRID_SPAN, MARGIN+i*GRID_SPAN);
}
for(int i=0;i<=COLS;i++){//画竖线
g.drawLine(MARGIN+i*GRID_SPAN, MARGIN, MARGIN+i*GRID_SPAN, MARGIN+ROWS*GRID_SPAN);
}
//画棋子
for(int i=0;i<chessCount;i++){
//网格交叉点x,y坐标
int xPos=chessList[i].getX()*GRID_SPAN+MARGIN;
int yPos=chessList[i].getY()*GRID_SPAN+MARGIN;
g.setColor(chessList[i].getColor());//设置颜色
// g.fillOval(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2,
//Point.DIAMETER, Point.DIAMETER);
//g.drawImage(shadows, xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER, null);
colortemp=chessList[i].getColor();
if(colortemp==Color.black){
RadialGradientPaint paint = new RadialGradientPaint(xPos-Chess.R/2+25, yPos-Chess.R/2+10, 20, new float[]{0f, 1f}
, new Color[]{Color.WHITE, Color.BLACK});
((Graphics2D) g).setPaint(paint);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);
}
else if(colortemp==Color.white){
RadialGradientPaint Paint = new RadialGradientPaint(xPos-Chess.R/2+25, yPos-Chess.R/2+10, 70, new float[]{0f, 1f}
, new Color[]{Color.WHITE, Color.BLACK});
((Graphics2D) g).setPaint(Paint);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);
}
Ellipse2D e = new Ellipse2D.Float(xPos-Chess.R/2, yPos-Chess.R/2, 34, 35);
((Graphics2D) g).fill(e);
//标记最后一个棋子的红矩形框
if(i==chessCount-1){//如果是最后一个棋子
g.setColor(Color.red);
g.drawRect(xPos-Chess.R/2, yPos-Chess.R/2,
34, 35);
}
}
}
public void mousePressed(MouseEvent e){//鼠标在组件上按下时调用
//游戏结束时,不再能下
if(gameOver) return;
String colorName=isBlack?"黑棋":"白棋";
//将鼠标点击的坐标位置转换成网格索引
xIndex=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
yIndex=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
//落在棋盘外不能下
if(xIndex<0||xIndex>ROWS||yIndex<0||yIndex>COLS)
return;
//如果x,y位置已经有棋子存在,不能下
if(findChess(xIndex,yIndex))return;
//可以进行时的处理
Chess ch=new Chess(xIndex,yIndex,isBlack?Color.black:Color.white);
chessList[chessCount++]=ch;
repaint();//通知系统重新绘制
//如果胜出则给出提示信息,不能继续下棋
if(isWin()){
String msg=String.format("恭喜,%s赢了!", colorName);
JOptionPane.showMessageDialog(this, msg);
gameOver=true;
}
isBlack=!isBlack;
}
//覆盖mouseListener的方法
public void mouseClicked(MouseEvent e){
//鼠标按键在组件上单击时调用
}
public void mouseEntered(MouseEvent e){
//鼠标进入到组件上时调用
}
public void mouseExited(MouseEvent e){
//鼠标离开组件时调用
}
public void mouseReleased(MouseEvent e){
//鼠标按钮在组件上释放时调用
}
//在棋子数组中查找是否有索引为x,y的棋子存在
private boolean findChess(int x,int y){
for(Chess c:chessList){
if(c!=null&&c.getX()==x&&c.getY()==y)
return true;
}
return false;
}
private boolean isWin(){
int continueCount=1;//连续棋子的个数
//横向向西寻找
for(int x=xIndex-1;x>=0;x--){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,yIndex,c)!=null){
continueCount++;
}else
break;
}
//横向向东寻找
for(int x=xIndex+1;x<=COLS;x++){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,yIndex,c)!=null){
continueCount++;
}else
break;
}
if(continueCount>=5){
return true;
}else
continueCount=1;
//继续另一种搜索纵向
//向上搜索
for(int y=yIndex-1;y>=0;y--){
Color c=isBlack?Color.black:Color.white;
if(getChess(xIndex,y,c)!=null){
continueCount++;
}else
break;
}
//纵向向下寻找
for(int y=yIndex+1;y<=ROWS;y++){
Color c=isBlack?Color.black:Color.white;
if(getChess(xIndex,y,c)!=null)
continueCount++;
else
break;
}
if(continueCount>=5)
return true;
else
continueCount=1;
//继续另一种情况的搜索:斜向
//东北寻找
for(int x=xIndex+1,y=yIndex-1;y>=0&&x<=COLS;x++,y--){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,y,c)!=null){
continueCount++;
}
else break;
}
//西南寻找
for(int x=xIndex-1,y=yIndex+1;x>=0&&y<=ROWS;x--,y++){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,y,c)!=null){
continueCount++;
}
else break;
}
if(continueCount>=5)
return true;
else continueCount=1;
//继续另一种情况的搜索:斜向
//西北寻找
for(int x=xIndex-1,y=yIndex-1;x>=0&&y>=0;x--,y--){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,y,c)!=null)
continueCount++;
else break;
}
//东南寻找
for(int x=xIndex+1,y=yIndex+1;x<=COLS&&y<=ROWS;x++,y++){
Color c=isBlack?Color.black:Color.white;
if(getChess(x,y,c)!=null)
continueCount++;
else break;
}
if(continueCount>=5)
return true;
else continueCount=1;
return false;
}
private Chess getChess(int xIndex,int yIndex,Color color){
for(Chess p:chessList){
if(p!=null&&p.getX()==xIndex&&p.getY()==yIndex
&&p.getColor()==color)
return p;
}
return null;
}
public void restartGame(){
//清除棋子
for(int i=0;i<chessList.length;i++){
chessList[i]=null;
}
//恢复游戏相关的变量值
isBlack=true;
gameOver=false; //游戏是否结束
chessCount =0; //当前棋盘棋子个数
repaint();
}
//悔棋
public void goback(){
if(chessCount==0)
return ;
chessList[chessCount-1]=null;
chessCount--;
if(chessCount>0){
xIndex=chessList[chessCount-1].getX();
yIndex=chessList[chessCount-1].getY();
}
isBlack=!isBlack;
repaint();
}
//矩形Dimension
public Dimension getPreferredSize(){
return new Dimension(MARGIN*2+GRID_SPAN*COLS,MARGIN*2
+GRID_SPAN*ROWS);
}
}
界面类
package FiveChess;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
//五子棋主框架
public class ChessJFrame extends JFrame{
private ChessBoard chessboard;
private JPanel toolbar;//工具栏
private JButton button_start,button_back,button_exit;
private JMenuBar menubar;//菜单栏
private JMenu Menu;
private JMenuItem startItem,backItem,exitItem;//菜单项
public ChessJFrame(){
setTitle("五子棋");
chessboard=new ChessBoard();
menubar=new JMenuBar();
Menu=new JMenu("选项");
startItem=new JMenuItem("重新开始");
backItem=new JMenuItem("悔棋");
exitItem=new JMenuItem("退出");
Menu.add(startItem);
Menu.add(backItem);
Menu.add(exitItem);
//内部监听类
MyItemListener lis=new MyItemListener();
this.startItem.addActionListener(lis);
this.backItem.addActionListener(lis);
this.exitItem.addActionListener(lis);
menubar.add(Menu);
setJMenuBar(menubar);//设置菜单栏
toolbar=new JPanel();//工具面板实例化
button_start=new JButton("重新开始");
button_back=new JButton("悔棋");
button_exit=new JButton("退出");
toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));
toolbar.add(button_start);
toolbar.add(button_back);
toolbar.add(button_exit);
button_start.addActionListener(lis);
button_back.addActionListener(lis);
button_exit.addActionListener(lis);
add(toolbar,BorderLayout.SOUTH);
add(chessboard);//添加面板对象
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension dim=getToolkit().getScreenSize();
this.setLocation(520, 200);
pack();
}
private class MyItemListener implements ActionListener{
public void actionPerformed(ActionEvent e){
if(e.getSource()==startItem||e.getSource()==button_start){
System.out.println("重新开始");
chessboard.restartGame();
}
else if(e.getSource()==exitItem||e.getSource()==button_exit){
System.exit(0);
}
else if(e.getSource()==backItem||e.getSource()==button_back){
System.out.println("悔棋...");
chessboard.goback();
}
}
}
public static void main(String[] args) {
ChessJFrame j=new ChessJFrame();
j.setVisible(true);
}
}
总结
对棋子的绘制采用了awt的Ellipse2D功能使其更有3D感,菜单栏实现的功能和按键相同,下面附上程序图
人机对战要用到二叉树等数据结构问题,以后将进行更新