打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
JAVA 井字棋

有时候我们可以用java编写一些小游戏,比如井字棋,这是一个很简单的程序,如图效果;

我们可以将它分为棋子,棋盘,框架启动类表示;

首先我们来编写棋子类,棋子类里有棋子的坐标和形状的表示,

用1表示圆圈,2表示方框

public class Chess {	private int x;	private int y;//棋子的索引	private int form;//棋子的形状,1是圆圈,2是方框	public Chess(int x,int y,int form) {//构造函数		this.x=x;		this.y=y;		this.form=form;	}	public int getX() {//get函数		return x;	}	public int getY() {		return y;	}	public int getForm() {		return form;	}}

接下来进行框架类的编写,创建一个类来继承JFrame类,用来启动游戏,放置面板对象,设置大小,设置标题,一个游戏少不了一些按钮,井字棋中有三个按钮,重新开始游戏按钮,悔棋按钮和退出游戏按钮,有按钮就有相应的事件处理,这时候我们需要一个类继承事件处理类,并将三个按钮和事件处理进行绑定;

import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.*;/* * 井字棋的主框架类 *  */public class ChessJFrame extends JFrame {	private Chessbord chessbord;//声明一个棋盘对象	private Button	restartgame;//声明一个重新开始按钮	private Button	backgame;//声明一个悔棋按钮	private Button	exitgame;//声明一个退出游戏按钮	private JPanel jp;//面板对象,存放按钮	public ChessJFrame() {//构造函数,对参数初始化		setTitle("井字棋");//设置表题名称		MyActLister ma=new MyActLister();//事件处理对象		chessbord=new Chessbord();//棋盘对象		restartgame=new Button("重新开始");//		backgame=new Button("悔棋");		exitgame=new Button("退出");//对三个按钮进行初始化		jp=new JPanel();//面板对象		jp.setLayout(new FlowLayout(FlowLayout.CENTER));//流式布局		jp.add(restartgame);//		jp.add(backgame);		jp.add(exitgame);//将三个按钮添加到面板中		add(jp,BorderLayout.SOUTH);//面板的位置		restartgame.addActionListener(ma);		backgame.addActionListener(ma);		exitgame.addActionListener(ma);//将三个按钮事件源进行监听		add(chessbord);//添加棋盘		pack();//框架大小的自适应			}		public static void main(String[] args) {		ChessJFrame jf=new ChessJFrame();//声明框架对象		jf.setVisible(true);//可见		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭方式		jf.setLocationRelativeTo(null);//将面板置中	}	private class MyActLister implements ActionListener{//事件监听内部类		@Override		public void actionPerformed(ActionEvent e) {			Object obj=e.getSource();//获取事件源			if(obj==restartgame) {//重新开始事件				System.out.println("重新开始");				chessbord.restartgame();			}			else if(obj==backgame) {//悔棋事件				System.out.println("悔棋");				chessbord.backgame();			}else if(obj==exitgame) {//退出游戏事件				System.exit(0);			}					}		} 	}

最后一个棋盘类是最复杂的,也是最重要的一个类,它继承的JTable类和两个鼠标事件接口,棋盘类里有画图函数,判单输赢函数和鼠标处理事件,

先说画图函数,它对棋盘进行画图,对棋子进行画图,要想弄清楚其中的关系,画一个九宫格自己比划比划,

画图函数调用的画直线函数方法,画圆圈方法,画方框方法;

protected void paintComponent(Graphics g) {//画棋盘和棋子		super.paintComponent(g);		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  ) {//画棋子			int form=chessList[i].getForm();//判断是什么形状			int xpos=chessList[i].getX()*GRID_SPAN MARGIN 20;//棋子的X的坐标			int ypos=chessList[i].getY()*GRID_SPAN MARGIN 20;//棋子的y的坐标			if(form==1) {//画圆圈				g.drawOval(xpos,ypos, GRID_SPAN/2, GRID_SPAN/2);			}else if(form==2) {//画方框				g.drawRect(xpos, ypos, GRID_SPAN/2, GRID_SPAN/2);			}		}	}

接下来就是鼠标事件,鼠标事件又分为鼠标移动事件和鼠标按下事件,

鼠标移动事件用来设置鼠标光标的,当光标在棋盘外,所在位置有棋子时或游戏结束时设置为默认形状;

代码如下;

​public void mouseMoved(MouseEvent e) {//鼠标移动事件		int x1=(e.getX()-MARGIN)/GRID_SPAN;//棋子x的坐标		int y1=(e.getY()-MARGIN)/GRID_SPAN;//棋子y的坐标		if(x1<0||x1>ROWS-1||y1<0||y1>COLS-1||findchess(x1,y1)||gameover) {//判断鼠标光标是否在棋盘外,是否所在位置有棋子,是否游戏结束			setCursor(new Cursor(Cursor.DEFAULT_CURSOR));//如果是,设置为默认形状		}else {//如果不是,则设置为手形			setCursor(new Cursor(Cursor.HAND_CURSOR));		}	}​

鼠标按下事件,是用来下棋子的,并判断棋子是否胜利,是否平局;

代码如下;

public void mousePressed(MouseEvent e) {//鼠标按下事件		if(gameover)//游戏结束不能下			return ;		int form=start?1:2;		int xindex=(e.getX()-MARGIN)/GRID_SPAN;		int yindex=(e.getY()-MARGIN)/GRID_SPAN;		if(xindex<0||xindex>ROWS-1||yindex<0||yindex>COLS-1||findchess(xindex, yindex)) {			return ;//在棋盘外,所在位置有棋子,不能下		}		Chess ch=new Chess(xindex,yindex,form);//棋子对象		chessList[chessCount  ]=ch;//存放在棋子对象数组里		repaint();//重画		if(win(xindex,yindex)) {//如果游戏胜利,输出以下信息			String msg=String.format("恭喜 %s赢了",start?"圆圈":"方框");			JOptionPane.showMessageDialog(this, msg);			gameover=true;		}else if(chessCount==ROWS*COLS&&gameover==false) {//如果棋子下满,并且没有胜利,输出以下信息			String msg=String.format("旗鼓相当,加油");			JOptionPane.showMessageDialog(this, msg);			gameover=true;		}		start=!start;//改变形状	}

最后是判断棋子是否胜利的代码,个人觉得这是最难的地方;

判断井字棋是否胜利时,当棋子个数小于5时不用判断棋子是否胜利,棋子数不够;

判断主对角线上的棋子时,根据棋子的坐标我们可以知道主对角线上的x坐标与y坐标是相等的;

接下来就是遍历棋子数组中的棋子是否有x坐标与Y坐标相等的;

有的话就判断是否和当前所下棋子是否相同,是的话,数目加一,当数目为三时,说明游戏中有棋子胜利;

根据这个关系写出可以下代码;

if(xindex==yindex) {//主对角线上的棋子		for(int i=0;i<chessCount;i  ) {			if(chessList[i].getX()==chessList[i].getY()) {				if(chessList[i].getForm()==x) {					Count  ;				}else					break;			}		}		if(Count==3) {//判断连续棋子个数是否为三			return true;		}else {			Count=0;		}

判断反对角线上的棋子,放对角线的棋子x坐标和y坐标相加等于同一个数;

判断反对角线上的棋子原理和主对角线上的原理差不多,这里就不多说了;

if(xindex yindex==2) {//反对角线上的棋子		for(int i=0;i<chessCount;i  ) {		if(chessList[i].getX() chessList[i].getY()==2) {				if(chessList[i].getForm()==x) {					Count  ;				}else					break;			}		}			if(Count==3) {//判断连续棋子数是否为三				return true;			}else {				Count=0;			}		}

接下来就是判断棋子所在行和列是否有相同连续的三个棋子;

根据坐标关系我们可知;同一列的坐标,它们的x坐标值相等,同一行的坐标,它们的y坐标相等;

以列为例,我们可以根据所下棋子的索引来对棋子所在的列进行遍历;

拿出当前所下棋子的x索引值,然后遍历棋子对象中有没有和当前棋子x索引相同的值,有的话说明该棋子是和所下棋子在同一列

然后进行判断,同一列有没有连续相同的三个棋子;有的话则当前棋子胜利;

行和列的判断代码如下;

for(int i=0;i<chessCount;i  ) {//判断所下棋子所在列有没有连续三个的棋子			if(xindex==chessList[i].getX()) {				if(chessList[i].getForm()==x) {					Count  ;				}else					break;			}		}				if(Count==3) {//判断连续棋子数是否为三					return true;				}else {					Count=0;					}		for(int i=0;i<chessCount;i  ) {//判断棋子所在行有没有连续的三个棋子		if(yindex==chessList[i].getY()) {			if(chessList[i].getForm()==x) {				Count  ;			}else				break;		}		}		if(Count==3) {//判断连续棋子数是否为三			return true;		}else {			Count=0;		}

棋盘类三个比较重要的部分已经说完了,接下来我会贴出完整的棋盘类代码,大家再接再厉;

​import java.awt.*;import java.awt.event.*;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.awt.event.MouseMotionListener;import javax.swing.*;/* * 井字棋的棋盘类 * 棋盘类继承了面板类和鼠标事件接口 */public class Chessbord extends JPanel implements MouseListener,MouseMotionListener{	private static int MARGIN=30;//面板与框架之间的间距	private static int ROWS=3;//行数	private static int COLS=3;//列数	private static int GRID_SPAN=80;//网格间距	Chess[] chessList=new Chess[ROWS*COLS];//棋子数组,存放棋子对象	int chessCount=0;//棋子个数	boolean start=true;//默认圆圈先下	boolean gameover=false;//游戏结束	public Chessbord() {//构造函数		setBackground(Color.GRAY);//设置背景颜色		addMouseListener(this);		addMouseMotionListener(this);//添加鼠标事件			}	@Override	protected void paintComponent(Graphics g) {//画棋盘和棋子		super.paintComponent(g);		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  ) {//画棋子			int form=chessList[i].getForm();//判断是什么形状			int xpos=chessList[i].getX()*GRID_SPAN MARGIN 20;//棋子的X的坐标			int ypos=chessList[i].getY()*GRID_SPAN MARGIN 20;//棋子的y的坐标			if(form==1) {//画圆圈				g.drawOval(xpos,ypos, GRID_SPAN/2, GRID_SPAN/2);			}else if(form==2) {//画方框				g.drawRect(xpos, ypos, GRID_SPAN/2, GRID_SPAN/2);			}		}	}	@Override	public void mouseDragged(MouseEvent e) {		// TODO Auto-generated method stub			}	@Override	public void mouseMoved(MouseEvent e) {//鼠标移动事件		int x1=(e.getX()-MARGIN)/GRID_SPAN;//棋子x的坐标		int y1=(e.getY()-MARGIN)/GRID_SPAN;//棋子y的坐标		if(x1<0||x1>ROWS-1||y1<0||y1>COLS-1||findchess(x1,y1)||gameover) {//判断鼠标光标是否在棋盘外,是否所在位置有棋子,是否游戏结束			setCursor(new Cursor(Cursor.DEFAULT_CURSOR));//如果是,设置为默认形状		}else {//如果不是,则设置为手形			setCursor(new Cursor(Cursor.HAND_CURSOR));		}	}	private boolean findchess(int x1, int y1) {//判断所在位置是否有棋子		for (Chess chess : chessList) {			if(chess!=null&&chess.getX()==x1&&chess.getY()==y1) {				return true;			}		}		return false;	}	@Override	public void mouseClicked(MouseEvent e) {		// TODO Auto-generated method stub			}	@Override	public void mousePressed(MouseEvent e) {//鼠标按下事件		if(gameover)//游戏结束不能下			return ;		int form=start?1:2;		int xindex=(e.getX()-MARGIN)/GRID_SPAN;		int yindex=(e.getY()-MARGIN)/GRID_SPAN;		if(xindex<0||xindex>ROWS-1||yindex<0||yindex>COLS-1||findchess(xindex, yindex)) {			return ;//在棋盘外,所在位置有棋子,不能下		}		Chess ch=new Chess(xindex,yindex,form);//棋子对象		chessList[chessCount  ]=ch;//存放在棋子对象数组里		repaint();//重画		if(win(xindex,yindex)) {//如果游戏胜利,输出以下信息			String msg=String.format("恭喜 %s赢了",start?"圆圈":"方框");			JOptionPane.showMessageDialog(this, msg);			gameover=true;		}else if(chessCount==ROWS*COLS&&gameover==false) {//如果棋子下满,并且没有胜利,输出以下信息			String msg=String.format("旗鼓相当,加油");			JOptionPane.showMessageDialog(this, msg);			gameover=true;		}		start=!start;//改变形状	}	private boolean win(int xindex,int yindex) {//判断游戏是否胜利		if(chessCount<5) {//当棋子小于5时不用判断			return false;		}		int x=start?1:2;//判断棋子形状		int Count=0;//统计连续棋子数		if(xindex==yindex) {//主对角线上的棋子		for(int i=0;i<chessCount;i  ) {			if(chessList[i].getX()==chessList[i].getY()) {				if(chessList[i].getForm()==x) {					Count  ;				}else					break;			}		}		if(Count==3) {//判断连续棋子个数是否为三			return true;		}else {			Count=0;		}		}		if(xindex yindex==2) {//反对角线上的棋子		for(int i=0;i<chessCount;i  ) {		if(chessList[i].getX() chessList[i].getY()==2) {				if(chessList[i].getForm()==x) {					Count  ;				}else					break;			}		}			if(Count==3) {//判断连续棋子数是否为三				return true;			}else {				Count=0;			}		}		for(int i=0;i<chessCount;i  ) {//判断所下棋子所在列有没有连续三个的棋子			if(xindex==chessList[i].getX()) {				if(chessList[i].getForm()==x) {					Count  ;				}else					break;			}		}				if(Count==3) {//判断连续棋子数是否为三					return true;				}else {					Count=0;					}		for(int i=0;i<chessCount;i  ) {//判断棋子所在行有没有连续的三个棋子		if(yindex==chessList[i].getY()) {			if(chessList[i].getForm()==x) {				Count  ;			}else				break;		}		}		if(Count==3) {//判断连续棋子数是否为三			return true;		}else {			Count=0;		}		     return false;//否则返回false			}	@Override	public void mouseReleased(MouseEvent e) {			}	@Override	public void mouseEntered(MouseEvent e) {			}	@Override	public void mouseExited(MouseEvent e) {		// TODO Auto-generated method stub			}		public void restartgame() {//重新开始函数		for (int i = 0; i < chessList.length; i  ) {			chessList[i]=null;		}		chessCount=0;		gameover=false;		start=true;//一切恢复为初始状态		repaint();//重画	}	public void backgame() {//悔棋函数		if(gameover) {//如果游戏结束,不能悔棋			return ;		}		if(chessCount==0) {//如果棋子个数为0,不能悔棋			return ;		}		chessList[chessCount-1]=null;		chessCount--;		start=!start;//改变形状		repaint();//重画	}		public Dimension getPreferredSize() {//画矩形面板		return new Dimension(MARGIN*2 ROWS*GRID_SPAN,MARGIN*2 COLS*GRID_SPAN);	}	}​

井字棋代码到此结束;

来源:http://www.icode9.com/content-1-135351.html
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
《“井”字棋·有趣的格子》微课实录
世界棋的种类
锻炼娃的思维能力,这些DIY棋类游戏不要错过
用 Python 跟自己下棋(续)
1个套装包含15种经典棋类游戏,只要68元,拓展数理思维,暑假和旅行必备
Python案例分析|井字棋(Tic Tac Toe)游戏
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服