作业可直接源码五子运行实验(棋子设置游戏棋盘悔棋)「五子棋 源码」

Java程序设计大作业报告题目: 欢乐五子棋学院: 软件学院姓名:学号:专业班级:任课教师:截止时间: 2022年6月11日大作业要求:请根据本学期所学的Java和面向对象的思想实现一个完整的系统。
开发环境和工具不限,大作业题目和内容自定,代码总行数不低于800行(含注释)。
鼓励围绕这次疫情期间产生的学习、生活、工作的需求来开发相应程序。
具体要求如下:采用面向对象程序设计,要运用继承、多态等机制;代码规范需遵循Java编码规范要求;具备文件读写功能,程序中的数据要以文件方式保存;程序中要求具备异常处理;使用第三方类库或者插件需在报告和程序中注明来源和版权信息,并详细说明使用了该第三方类库或者插件哪部分功能。
要求具备菜单功能,根据用户的输入,执行相应的操作。
在菜单选项中,必须包含“关于”一项,该菜单项用来显示本作业的基本信息,包括程序名称、版本、完成时间,姓名、学号、班级等信息;程序要求做到界面友好,对于用户的输入操作要有明确的提示信息,并对输入的数据进行合法性和正确性的检查;每个文件、类、方法的前面都必须有规范的注释,注释中要说明作者是谁、主要功能、编写时间等信息。
变量、常量、关键语句等都必须有注释说明。
所有源程序代码(含注释)都要拷贝到大作业报告的【3.3 程序实现】中。
源代码为多文件项目,合理分配好各个源代码文件内容。
本报告文档是作业的一个重要内容,文档中的每个内容都必须认真按照要求撰写,否则扣分。
模板格式说明:正文模板中的红色文字部分为说明文字,请仔细阅读后撰写正式的内容。
排版要求:页面设置:上2.54cm,下2.54cm,左3.67cm,右2.67cm,页眉1.5cm,页脚1.75cm,行间距1.35倍。
全文中文字体采用宋体,英文字体采用Times New Roman字体,一级标题使用小三号字体,二级、三级标题均使用四号字体,正文内容采用小四号字体,代码字体大小为五号。
目 录一、需求分析11.1、开发环境11.2、功能需求1二、系统分析与设计12.1、本程序需解决的关键技术问题12.2、总体功能图12.3、类图22.4、程序流程图(至少画1个关键性功能的流程图)2三、程序设计与实现23.1、项目文件组织结构23.2、程序设计33.3、程序实现3四、系统测试3五、本程序高内聚低耦合的特点,易扩展、易维护3六、总结与体会4七、自评分4需求分析1.1、开发环境操作系统及版本:win 10开发工具及版本:IntelliJ IDEA Educational Edition 2021.3.21.2、功能需求欢乐五子棋设置程序只能在限定的棋盘上落子,开始游戏后,当鼠标在棋盘上点击时,绘制棋子完成五子棋的基本规则——任一方先在棋盘上形成横向、竖向、斜向的连续的相同颜色的五个(含五个以上)棋子的一方为胜,结束游戏。
设置倒计时功能,单位为分钟,令游戏更加合理设置悔棋功能,防止因一些客观原因落子失败设置认输功能设置历史对局功能,查看历史对局输赢情况设置退出功能系统分析与设计2.1、本程序需解决的关键技术问题1、如何令鼠标在限定的范围内落子而不越界2、如何实现黑子白子轮流进行落子3、如何实现任一种颜色棋子在任意方向上练成五个时判定某一方胜利4、如何令菜单上的功能在规定的点击范围内响应5、如何令棋子落在棋盘的网格线上且当两个棋子选择下在同一个网格上时,怎样解决上一个棋子被覆盖的问题6、怎样完成时间的设置,并且当使用者输入正整数和0以外的数字使不产生bug7、如何将对局输赢情况(包含时间线)存储在文件中不出现bug,以及如何将对局内容呈现在窗口中2.2、总体功能图2.3、类图2.4、程序流程图(至少画1个关键性功能的流程图)函数:paint函数,MyFrameChess函数,mousePressed函数,judge函数,run函数程序设计与实现3.1、项目文件组织结构3.2、程序设计mainmenu类:用于调用MyFrameChess类MyFrameChess类:用于构建棋盘,控制落子,判断胜负,设置时间等功能关键知识点:继承,封装,多态,多线程运行,JFrame和鼠标监听器的相关知识主要成员函数:MyFrameChess构造函数:初始化相关变量paint函数:用于设置界面,包括背景图片的导入,棋盘的绘制,落子方的提示信息。
mousePressed函数:设计意图:监听鼠标位置,实现棋盘上各项功能功能:获取x,y的坐标,根据由paint函数记录的数据绘制棋子,判断游戏是否结束。
实现“开始游戏”选项,点击重新开始,清空棋盘,开始游戏实现“倒计时”选项,以分钟为单位设置时间,输入数为0时,设置时间无限制实现“游戏说明”选项,点击游戏说明,弹出对话框以介绍游戏规则实现“关于”选项,点击关于,弹出对话框介绍游戏制作相关内容实现“悔棋”选项,点击悔棋,撤回上一步,但不可连续重复执行实现“认输”选项,点击认输,判断当前落子的人败北,游戏结束实现“历史对局”选项,点击显示历史对局的输赢情况实现“退出游戏”选项,点击退出,结束程序judge函数: 用于判断当前落子位置是否存在其余四个相同颜色棋子使当前一方连成五子run函数: 用于实现多线程运作3.3、程序实现paint函数:利用鼠标监听器获取棋盘的范围,再通过for循环划出棋盘,同时使用Graphics类对界面进行相应优化MyFrameChess构造函数:主要用于初始化各个变量mousePressed函数:使用if函数进行各类判断确定各类功能作用范围,利用JFrame的弹窗设置各类提示信息,显示时间maxtime本是正整数,运用一些方法设置为时分秒的形式,代码如下:if(maxTime > 0){bTime = maxTime/3600+":"+(maxTime/60-maxTime/360060)+":"+(maxTime-maxTime/6060);wTime = maxTime/3600+":"+(maxTime/60-maxTime/360060)+":"+(maxTime-maxTime/6060);悔棋选项利用记录最后落子坐标的方法进行撤回,代码如下://设置悔棋选项

作业可直接源码五子运行实验(棋子设置游戏棋盘悔棋)

//限定选项范围if(e.getX()>=505&&e.getX()<=598&&e.getY()>=280&&e.getY()<=320){//判断当前棋盘上是否有棋子if(allchess[finalx][finaly]!=0&&Goon==true){//弹出选择对话框,根据选项决定是否执行悔棋程序int result = JOptionPane.showConfirmDialog(this,"请问是否进行悔棋操作?");//若选择坚持执行悔棋程序,则进行以下操作if(result == 0){//将最后一步的棋子设置为无,即清除该点的棋子allchess[finalx][finaly] = 0;//返回到落子前的棋盘状态if(Black == true){//若悔棋时是黑子,则将棋子颜色设置为白色Black = false;//将游戏信息变换为对应的内容message = "轮到白方";}else{//若悔棋时是黑子,则将棋子颜色设置为黑色Black = true;//将游戏信息变换为对应的内容message = "轮到黑方";}//重绘棋盘this.repaint();}}else{//若棋盘上无棋子或连续执行悔棋操作,则弹出该窗口JOptionPane.showMessageDialog(this,"无效操作。

");}}judge函数:设置判断五子是否相连的方法若存在相同颜色的五个棋子任意方向相连,则返回true值该类的算法判断依据为:每落子一次便进行判定一次当判定当前棋子周围任意一个方向上有相同颜色棋子相连时则设置改棋子为最后落的棋子,将结束游戏条件设置为true部分代码如下://初始化为不相连boolean flag = false;//记录相同颜色棋子相连的数量int count = 1;//将本轮下的棋子颜色作为参考颜色int color = allchess[x][y];//用于判断横向是否有五个棋子相连int one = 1;//首先判断横向右方的棋子情况//防止向右越界异常处理while(x+one>=0&&x+one<=18&&y>=0&&y<=18&&color == allchess[x+one][y]){//若横向右方有相同颜色的棋子,则计数加一count++;//判断范围再往右前进一格one++;}//将判断范围初始化one = 1;//判断横向左方的棋子情况//防止向左越界异常处理while(x-one>=0&&x-one<=18&&y>=0&&y<=18&&color == allchess[x-one][y]){//若横向左方有相同颜色的棋子,则计数加一count++;//判断范围再往左前进一格one++;}//若相同连续的棋子计数达到五个,则更改flag的值if(count >= 5){//使上层判定游戏结束,其中一方获得胜利flag = true;}run函数:设置倒计时使黑方与白方时间各独立一个线程,当一方落子时,另一方的线程继续开始,设定每一秒时间某一方时间减一,当某一方时间为0时,停止计时,设置时间为-1,代表游戏结束代码如下:public void run() {//当设置时间大于0时,程序才会开始if(maxTime>0){//设置程序一直运行while(true){//设置黑方时间减少if(Black){//当黑方时间大于0时,设置黑方时间每秒减一if(BTime > 0){BTime--;}//黑方游戏时间耗尽时,判断游戏结束if(BTime == 0){JOptionPane.showMessageDialog(this,"黑方超时,游戏结束。

");Goon = false;//当黑方时间等于0时,设置时间为-1,防止倒计时继续运转BTime = -1;}}else{if(WTime > 0){//设置白方时间每秒减一WTime--;}if(WTime == 0){//白方游戏时间耗尽时,判断游戏结束JOptionPane.showMessageDialog(this,"白方超时,游戏结束。

");Goon = false;WTime = -1;}}//设置黑方显示时间为时分秒的显示形式bTime = BTime/3600+":"+(BTime/60-BTime/360060)+":"+(BTime-BTime/6060);//设置白方显示时间为时分秒的显示形式wTime = WTime/3600+":"+(WTime/60-WTime/360060)+":"+(WTime-WTime/6060);//重绘棋盘,刷新时间this.repaint();try {//设置停顿Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//System.out.println(BTime+"---"+WTime);}}}项目源代码如下:Mainmenu.java:package FiveChessGame;//项目名称:欢乐五子棋//期望分数:93//理由:界面设计合理,功能齐全,具有一定的创新性//该类用于调用MyFrameChess函数public class mainmenu {public static void main(String[] args) {//创建MyFrameChess类对象MyFrameChess zby = new MyFrameChess();}}MyFrameChess.java:package FiveChessGame;import javax.imageio.ImageIO;import javax.swing.;import java.awt.;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.awt.image.BufferedImage;import java.io.File;import java.io.IOException;import java.util.ArrayList;//MyFrameChess类//主要功能包括绘制棋盘,实现游戏各项功能,设置时间限制等//实现游戏主体功能public class MyFrameChess extends JFrame implements MouseListener,Runnable {//定义图片BufferedImage image = null;//定义x坐标,y坐标int x = 0;int y = 0;//记录步数int step = 0;//记录最后下的棋子的横坐标int finalx = 0;//记录最后下的棋子的纵坐标int finaly = 0;//创建菜单栏private JMenuBar menuBar;//添加系统private JMenu sysMenu;//添加开始选项private JMenuItem startMenuItem;//添加悔棋选项private JMenuItem backMenuItem;//添加退出选项private JMenuItem exitMenuItem;// //添加相关按钮// private JPanel toolBar;//// //添加开始按钮// private JButton startButton;//// //添加悔棋按钮// private JButton backButton;//// //添加退出按钮// private JButton exitButton;//保存之前下过棋子的全部坐标,0表示没有棋子,1表示黑子,2表示白子int[][] allchess = new int[19][19];//判断要下的棋子颜色boolean Black = true;//判断游戏是否需要进行boolean Goon = false;//提供一些必要的游戏提示信息String message = "黑方先行";//设置最大时间int maxTime = 0;//倒计时的线程类Thread time = new Thread(this);//设置黑方和白方的剩余时间int BTime = 0;int WTime = 0;//设置黑方和白方的剩余显示时间String bTime = "无限制";String wTime = "无限制";ResultManager resultManager = new ResultManager();//MyFrameChess类的构造方法//用于初始化棋盘,各类按键,设置背景图片,控制落子public MyFrameChess(){//取得屏幕的宽度int width = Toolkit.getDefaultToolkit().getScreenSize().width;//取得屏幕的高度int height = Toolkit.getDefaultToolkit().getScreenSize().height;// toolBar = new JPanel();//// startButton = new JButton();//// backButton = new JButton();//// exitButton = new JButton();//初始化菜单栏menuBar = new JMenuBar();//初始化系统sysMenu = new JMenu("系统");//初始化开始选项startMenuItem = new JMenuItem("开始游戏");//初始化悔棋选项backMenuItem = new JMenuItem("悔棋");//初始化退出选项exitMenuItem = new JMenuItem("退出");//将菜单栏添加到页面中this.setJMenuBar(menuBar);//将系统添加到菜单栏中menuBar.add(sysMenu);//将开始选项添加到系统中sysMenu.add(startMenuItem);//将悔棋选项添加到系统中sysMenu.add(backMenuItem);//将退出选项添加到系统中sysMenu.add(exitMenuItem);//设置标题this.setTitle("欢乐五子棋");//设置界面大小this.setSize(620,700);//设置界面出现在屏幕中间this.setLocation((width-500)/2,(height-500)/2);//设置为大小不可改变,以防止嵌入的图片出现问题this.setResizable(false);//设置关闭窗口后程序结束this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗口可见this.setVisible(true);//添加鼠标监听器this.addMouseListener(this);//设置线程设置time.start();//将线程暂时悬挂time.suspend();//解决黑屏的情况this.repaint();try {//导入图片image = ImageIO.read(new File("f:/Java大作业/background1.jpg"));// File background = new File("F:\\Java大作业\\background1.jpg");// System.out.println(background.getPath());// image = ImageIO.read(background);} catch (IOException e) {e.printStackTrace();}}//该类用于设置界面public void paint(Graphics show){//设置图片出现位置show.drawImage(image,0,30,null);//设置字体show.setFont(new Font("黑体",Font.BOLD,20));//在右上角设置落子方提示信息show.drawString(message,500,65);//重新设置字体,增加悔棋按键show.setFont(new Font("黑体",Font.BOLD,25));//在棋盘的右方增加悔棋按键show.drawString("悔棋",520,300);//重新设置字体show.setFont(new Font("宋体",0,20));//在棋盘的下方设置显示时间show.drawString("黑方时间:"+bTime,40,600);show.drawString("白方时间:"+wTime,260,600);//绘制悔棋按键的边框show.drawOval(510,265,70,50);//绘制棋盘for(int i = 0;i < 20;i++){//绘制横线show.drawLine(25,82+i25,499,82+i25);//绘制竖线show.drawLine(25+i25,82,25+i25,556);}//标注点位show.fillOval(98,155,5,5);show.fillOval(98,480,5,5);show.fillOval(424,155,5,5);show.fillOval(424,480,5,5);//标注中心点位show.fillOval(274,305,5,5);show.fillOval(274,480,5,5);show.fillOval(98,305,5,5);show.fillOval(424,305,5,5);show.fillOval(274,155,5,5);//控制棋盘的落子for(int i = 0;i < 19;i ++){for(int j = 0;j < 19;j ++){//读取二维数组中记录的各类棋子的位置if(1 == allchess[i][j]){//绘制黑子int X = i25+25;int Y = j25+82;//使棋子落在网格线的交叉处show.fillOval(X-7,Y-7,15,15);}if(2 == allchess[i][j]){int X = i25+25;int Y = j25+82;//将画笔颜色设置为白色show.setColor(Color.white);//绘制白色棋子show.fillOval(X-7,Y-7,15,15);show.setColor(Color.black);//绘制黑色边框show.drawOval(X-7,Y-7,15,15);}}}}@Overridepublic void mouseClicked(MouseEvent e) {}@Override//该类的功能主要通过监听实现,包括获取鼠标位置,绘制棋子,以及实现棋盘上的各类选项public void mousePressed(MouseEvent e) {//首先判定游戏是否在进行中if (Goon == true) {//获取鼠标位置信息x = e.getX();y = e.getY();//使棋子落在棋盘上if (x >= 25 && x <= 498 && y >= 82 && y <= 556) {//得到距离鼠标位置最近的网格交叉点的坐标x = (x - 25) / 25;y = (y - 82) / 25;//将当前所下的棋子的x坐标记录下来finalx = x;//将当前所下的棋子的y坐标记录下来finaly = y;//设置步数加一step++;//设置落子判断条件,防止棋子被覆盖if (allchess[x][y] == 0) {//若当前回合由黑方落子,则在棋盘相应位置绘制黑子if (Black == true) {//记录当前黑子的位置信息allchess[x][y] = 1;//转换棋子颜色Black = false;//更改回合提示信息message = "轮到白方";} else {//记录当前白子的位置信息allchess[x][y] = 2;//转换棋子颜色Black = true;//更改回合提示信息message = "轮到黑方";}//判断胜利条件,设置游戏不可运行boolean win = this.judge();//判断游戏胜利方//若win为true,则执行游戏结束//若win为false,则继续游戏if (win == true) {if (allchess[x][y] == 1) {JOptionPane.showMessageDialog(this, "游戏结束,黑方获胜");try {resultManager.writeResult("游戏结束,黑方获胜");} catch (IOException ioException) {ioException.printStackTrace();}//FileOutputStream fos2 = new FileOutputStream( new File(pathname:"1111\\fos.txt"));} else {JOptionPane.showMessageDialog(this, "游戏结束,白方获胜");try {resultManager.writeResult("游戏结束,白方获胜");} catch (IOException ioException) {ioException.printStackTrace();}}//设置游戏结束Goon = false;}//判断当前所下位置是否有棋子,防止棋子被覆盖} else {JOptionPane.showMessageDialog(this, "当前位置已有棋子,请重下");}//重绘棋盘this.repaint();}}//开始游戏选项//限定功能范围if(e.getX()>=505&&e.getX()<=598&&e.getY()>=75&&e.getY()<=125){int result = JOptionPane.showConfirmDialog(this,"是否重新开始游戏?");if(result == 0){Goon = true;//清空棋盘,回到初始状态for(int i = 0;i < 19;i++){for(int j = 0;j < 19;j++){allchess[i][j] = 0;}}//清空初始信息message = "黑方先行";Black = true;//重新设置游戏时间BTime = maxTime;WTime = maxTime;//将显示时间设置为时、分、秒的形式if(maxTime > 0){bTime = maxTime/3600+":"+(maxTime/60-maxTime/360060)+":"+(maxTime-maxTime/6060);wTime = maxTime/3600+":"+(maxTime/60-maxTime/360060)+":"+(maxTime-maxTime/6060);//重启线程time.resume();//当输入时间为0时设置时间为无限制}else if(maxTime == 0){bTime = "无限制";wTime = "无限制";}this.repaint();}}//设置游戏设置选项//限定选项作用范围if(e.getX()>=505&&e.getX()<=598&&e.getY()>=145&&e.getY()<=195){//获取最大游戏时长String timeSet = JOptionPane.showInputDialog("请输入游戏的最大时间(分钟):");try {//强制将timeSet转为int形式maxTime = Integer.parseInt(timeSet)60;//防止游戏时长输入为负数if(maxTime<0){JOptionPane.showMessageDialog(this,"请输入正确格式的信息。

");}//设置游戏时长无限制if(maxTime == 0) {int result = JOptionPane.showConfirmDialog(this, "设置完成,是否重新开始游戏?");//游戏时长设置后需重新开始游戏if (result == 0) {Goon = true;for (int i = 0; i < 19; i++) {for (int j = 0; j < 19; j++) {//清空棋盘allchess[i][j] = 0;}}//初始化信息message = "黑方先行";//重新加载剩余时间BTime = maxTime;WTime = maxTime;//重新加载显示时间bTime = "无限制";wTime = "无限制";//将该回合落子设定为黑子Black = true;//重绘棋盘this.repaint();}}//添加游戏时长大于0时的相关功能if(maxTime > 0){//重启游戏Goon = true;time.resume();for(int i = 0;i < 19;i++){for(int j = 0;j < 19;j++){allchess[i][j] = 0;}}message = "黑方先行";Black = true;//重新加载剩余时间BTime = maxTime;WTime = maxTime;//设置游戏时长显示格式bTime = maxTime/3600+":"+(maxTime/60-maxTime/360060)+":"+(maxTime-maxTime/6060);wTime = maxTime/3600+":"+(maxTime/60-maxTime/360060)+":"+(maxTime-maxTime/6060);//重绘棋盘this.repaint();}//异常处理,防止输入错误字符} catch (NumberFormatException numberFormatException) {JOptionPane.showMessageDialog(this,"请输入正确格式的信息。

");}}//设置游戏说明选项//限定选项作用范围if(e.getX()>=505&&e.getX()<=598&&e.getY()>=215&&e.getY()<=265){//介绍游戏的相关信息以及游戏玩法JOptionPane.showMessageDialog(this,"五子棋游戏。
\n" +"游戏规则:\n"+"黑白双方依次落子,由黑先下\n"+"任一方先在棋盘上形成横向、竖向、斜向的连续的相同颜色的五个(含五个以上)棋子的一方为胜。
\n"+"若在规定时间内都没有一方能够连成五个(或以上)棋子,则判定先用完时间的一方失败。
\n"+"开始游戏选项:\n"+"点击开始游戏选项以开始游戏,否则无法开始游戏。
\n"+"倒计时选项:\n"+"点击游戏设置选项以完成时间的设置.\n"+"时间设置单位为分钟,且仅支持输入0和正整数。
\n"+"当输入时间为0时,设置双方时间为无限制。
\n"+"时间设置完毕后若开始游戏,则会清空当前棋盘,请玩家留意。
\n"+"时间设置完毕后,会在棋盘下方显示剩余时间,双方起始剩余时间相同。
\n"+"游戏从黑方开始倒计时,若黑方落子,则开始扣除白方的剩余时间,反之亦然。
\n"+"认输选项:\n"+"点击认输选项会直接结束游戏,判定当前落子的一方败北。
\n"+"使用前还请认真考虑。
\n"+"关于选项:\n"+"点击关于选项会给出制作人员以及该程序的相关信息。
\n"+"退出选项:\n"+"点击退出选项会直接结束掉程序,使用前请认真考虑。
\n"+"历史对局选项:\n"+"点击查看历史对局结果。
\n"+"悔棋选项:\n"+"点击悔棋选项可以撤销上一回合的落子,且有该方重新落子。
\n"+"点击悔棋后时间不会回复到之前的状态,且悔棋选项不可以连续使用。
\n"+"若点击悔棋时棋盘上并未有落子,则会提示无效操作。
\n"+"悔棋选项可能会破坏游戏的公平性,使用前请慎重.\n");}//设置游戏认输选项//限定选项作用范围if(e.getX()>=505&&e.getX()<=598&&e.getY()>=335&&e.getY()<=385){//设置选择对话框int result = JOptionPane.showConfirmDialog(this,"请问您是否确定认输?");//根据判断结果决定是否判定认输if(result == 0) {//判断认输方if (Black == true) {//若该回合为黑方落子,则判定白方获胜JOptionPane.showMessageDialog(this, "黑方认输,白方获得胜利。

");//FileOutputStream his =new FileOutputStream( name: "黑方认输,白方获胜\\his.txt");// File file =new File( pathname:"黑方认输,白方获胜\\his.txt");// FileOutputStream fos2 =new FileOutputStream(file);try {resultManager.writeResult("黑方认输,白方获胜");} catch (IOException ioException) {ioException.printStackTrace();}} else {//若该回合为白方落子,则判定黑方获胜JOptionPane.showMessageDialog(this, "白方认输,黑方获得胜利。

");try {resultManager.writeResult("白方认输,黑方获胜");} catch (IOException ioException) {ioException.printStackTrace();}}//设置游戏结束Goon = false;}}//设置游戏关于选项//限定选项范围if(e.getX()>=505&&e.getX()<=598&&e.getY()>=410&&e.getY()<=455){//介绍作者以及游戏的相关信息JOptionPane.showMessageDialog(this,"程序名称:欢乐五子棋\n"+"版本信息:欢乐五子棋2.0\n"+"完成时间:2022.06.05\n" +"姓名:\n" +"学号:\n" +"班级:班\n");}//设置历史对局选项//限定选项范围if(e.getX()>=505&&e.getX()<=598&&e.getY()>=490&&e.getY()<=535){// 查看文件中的历史对局记录ArrayList resultList;String result = "";try {resultList = resultManager.readResult();for(Object obj : resultList){result += obj.toString();}} catch (IOException ioException) {ioException.printStackTrace();}//弹出游戏历史对局对话框JOptionPane.showMessageDialog(this,result);}//设置退出选项//限定选项范围if(e.getX()>=505&&e.getX()<=598&&e.getY()>=570&&e.getY()<=615){//弹出游戏结束对话框JOptionPane.showMessageDialog(this,"游戏结束。

");//退出程序System.exit(0);}//设置悔棋选项//限定选项范围if(e.getX()>=505&&e.getX()<=598&&e.getY()>=280&&e.getY()<=320){//判断当前棋盘上是否有棋子if(allchess[finalx][finaly]!=0&&Goon==true){//弹出选择对话框,根据选项决定是否执行悔棋程序int result = JOptionPane.showConfirmDialog(this,"请问是否进行悔棋操作?");//若选择坚持执行悔棋程序,则进行以下操作if(result == 0){//将最后一步的棋子设置为无,即清除该点的棋子allchess[finalx][finaly] = 0;//返回到落子前的棋盘状态if(Black == true){//若悔棋时是黑子,则将棋子颜色设置为白色Black = false;//将游戏信息变换为对应的内容message = "轮到白方";}else{//若悔棋时是白子,则将棋子颜色设置为黑色Black = true;//将游戏信息变换为对应的内容message = "轮到黑方";}//重绘棋盘this.repaint();}}else{//若棋盘上无棋子或连续执行悔棋操作,则弹出该窗口JOptionPane.showMessageDialog(this,"无效操作。

");}}}//设置判断五子是否相连的方法//若存在相同颜色的五个棋子任意方向相连,则返回true值//该类的算法判断依据为://每落子一次便进行判定一次//当判定当前棋子周围任意一个方向上有相同颜色棋子相连时//则设置改棋子为最后落的棋子,将结束游戏条件设置为trueprivate boolean judge(){//初始化为不相连boolean flag = false;//记录相同颜色棋子相连的数量int count = 1;//将本轮下的棋子颜色作为参考颜色int color = allchess[x][y];//用于判断横向是否有五个棋子相连int one = 1;//首先判断横向右方的棋子情况//防止向右越界异常处理while(x+one>=0&&x+one<=18&&y>=0&&y<=18&&color == allchess[x+one][y]){//若横向右方有相同颜色的棋子,则计数加一count++;//判断范围再往右前进一格one++;}//将判断范围初始化one = 1;//判断横向左方的棋子情况//防止向左越界异常处理while(x-one>=0&&x-one<=18&&y>=0&&y<=18&&color == allchess[x-one][y]){//若横向左方有相同颜色的棋子,则计数加一count++;//判断范围再往左前进一格one++;}//若相同连续的棋子计数达到五个,则更改flag的值if(count >= 5){//使上层判定游戏结束,其中一方获得胜利flag = true;}//初始化计数count = 1;//纵向判断范围初始化int two = 1;//判断纵向上方的棋子情况//防止向上越界异常处理while(x>=0&&x<=18&&y+two>=0&&y+two<=18&&color == allchess[x][y+two]){//若纵向上方有相同颜色的棋子,则计数加一count++;//判断范围向上前进一格two++;}//重置判断范围two = 1;//判断纵向下方的棋子情况//防止向下越界异常处理while(x>=0&&x<=18&&y-two>=0&&y-two<=18&&color == allchess[x][y-two]){//若纵向下方有相同颜色的棋子,则计数加一count++;//判断范围向下前进一格two++;}//若相同连续的棋子计数达到五个,则更改flag的值if(count >= 5){//判定条件改为trueflag = true;}//初始化计数count = 1;//左上、右下判断初始化int three = 1;//判断右下方的棋子情况//防止右下越界异常处理while(x+three>=0&&x+three<=18&&y+three>=0&&y+three<=18&&color == allchess[x+three][y+three]){//若右下方有相同颜色的棋子,则计数加一count++;//判断范围向右下前进一格three++;}//重置判断范围three = 1;//判断左上方的棋子情况//防止左上方越界异常处理while(x-three>=0&&x-three<=18&&y-three>=0&&y-three<=18&&color == allchess[x-three][y-three]){//若左上方有相同颜色的棋子,则计数加一count++;//判断范围向左上方前进一格three++;}//若相同连续的棋子计数达到五个,则更改flag的值if(count >= 5){flag = true;}//重置判断范围count = 1;//右上、左下判断初始化int four = 1;//判断右上方的棋子情况//防止右上方越界异常处理while(x+four>=0&&x+four<=18&&y-four>=0&&y-four<=18&&color == allchess[x+four][y-four]){//若右上方有相同颜色的棋子,则计数加一count++;//判断范围向右上方前进一格four++;}//重置判断范围four = 1;//判断左下方的棋子情况//防止左下方越界异常处理while(x-four>=0&&x-four<=18&&y+four>=0&&y+four<=18&&color == allchess[x-four][y+four]){//若左下方有相同颜色的棋子,则计数加一count++;//判断范围向左下方前进一格four++;}//若相同连续的棋子计数达到五个,则更改flag的值if(count >= 5){flag = true;}return flag;}@Overridepublic void mouseReleased(MouseEvent e) {}@Overridepublic void mouseEntered(MouseEvent e) {}@Overridepublic void mouseExited(MouseEvent e) {}@Override//倒计时设置public void run() {//当设置时间大于0时,程序才会开始if(maxTime>0){//设置程序一直运行while(true){//设置黑方时间减少if(Black){//当黑方时间大于0时,设置黑方时间每秒减一if(BTime > 0){BTime--;}//黑方游戏时间耗尽时,判断游戏结束if(BTime == 0){JOptionPane.showMessageDialog(this,"黑方超时,游戏结束。

");Goon = false;//当黑方时间等于0时,设置时间为-1,防止倒计时继续运转BTime = -1;}}else{if(WTime > 0){//设置白方时间每秒减一WTime--;}if(WTime == 0){//白方游戏时间耗尽时,判断游戏结束JOptionPane.showMessageDialog(this,"白方超时,游戏结束。

");Goon = false;WTime = -1;}}//设置黑方显示时间为时分秒的显示形式bTime = BTime/3600+":"+(BTime/60-BTime/360060)+":"+(BTime-BTime/6060);//设置白方显示时间为时分秒的显示形式wTime = WTime/3600+":"+(WTime/60-WTime/360060)+":"+(WTime-WTime/6060);//重绘棋盘,刷新时间this.repaint();try {//设置停顿Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//System.out.println(BTime+"---"+WTime);//测试内容}}}}ResultManager.classpackage FiveChessGame;import java.io.;import java.nio.charset.StandardCharsets;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.ArrayList;public class ResultManager {private String filePath ="result.txt";public void writeResult(String resultStr) throws IOException {OutputStream outputStream = new FileOutputStream(filePath,true);StringBuilder stringBuilder = new StringBuilder();LocalDateTime localDateTime = LocalDateTime.now();DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");//格式化String dateTime = formatter.format(localDateTime);// System.out.println(dateTime);stringBuilder.append(dateTime).append(" | " + resultStr).append("\n");String data = stringBuilder.toString();byte[] bytes = data.getBytes(StandardCharsets.UTF_8);try {outputStream.write(bytes);} catch (IOException e) {e.printStackTrace();} finally {outputStream.close();}}public ArrayList readResult() throws IOException {// InputStream inputStream = new FileInputStream("result.txt");InputStream inputStream = new FileInputStream(filePath);byte[] buf = new byte[1024];int byteRead = -1;ArrayList resultList = new ArrayList();while ((byteRead = inputStream.read(buf)) != -1) {String data = new String(buf, 0, byteRead, StandardCharsets.UTF_8);resultList.add(data);// System.out.println(data);}return resultList;}// @Test// public void testWriteResult() throws IOException {// writeResult("黑方认输,白方获胜");// ArrayList data = readResult();// String res = "";// for(Object obj : data){// res += obj.toString();//// System.out.println(obj);// }// System.out.println(res);// }}系统测试测试目的:减少使用bug,令五子棋程序流畅运行测试范围:边界问题,图片加载问题,倒计时问题,连子问题等测试工具:idea典型错误:1、当落子在棋盘边界时,编译器会不断报错原因:定义棋盘的数组发生越界行为2、程序刚运行时,图片会加载不出来原因:内容混乱,3、倒计时在为0后仍会往后倒数原因:run函数if语句判断有纰漏4、大于五个棋子相连时出现错误原因:judge判定未设想到该种情况测试手段:启动程序,任意进行一盘游戏,寻找可能的错误5.游戏功能测试游戏说明界面:关于界面:倒计时界面:正确运行:游戏输赢判断:认输:历史对局:本程序高内聚低耦合的特点,易扩展、易维护总结与体会此次Java大作业我的收获颇深。
一开始只是我想着做一个简单的欢乐五子棋小游戏,结果如何实现五子相连困扰了我很久。
一开始我的构想是遍历一遍棋盘,查看是否有五个棋子连在一起,但是这个方法后面证明既麻烦,又低效。
一遍遍的查找资料后,发现可以以当前落子的位置为参考点,来看周围是否有棋子与该落子的位置实现五子相连,这种方法不仅快速,而且占用内存小,同时又因为以每一次落子点为参考位置,不会出现漏洞。
悔棋的功能我构思了很久,本想放弃,但最后还是决定加上去。
一开始我毫无头绪,后面一遍又一遍翻看代码时,重新开始游戏算法中的重绘棋盘给了我启发,只需要利用之前定义的棋盘坐标,短短十几行代码便搞定了我苦思冥想半天的问题。
然后是加上倒计时。
多线程对于我来说是有点陌生的,当然,现在依旧称不上太熟悉,而且最困难的一点是,这部分的资料有些繁杂,不同的帖子用的方法和标准都不太一样,我一时间找不到突破口。
当然,既然我的程序用上了倒计时,最后我还是把它解决了,但是过程有一些痛苦。
首先是给黑白双方各设置一个线程,然后设置时间变量,当然,开始的时候因为变量设置太多把自己给绕进去了。
然后是写run函数,设置停顿,一点一点试错,最后拼凑出来。
剩下的部分就是倒计时的显示了,解决的方法让我有些出乎意料,只是简单的一个除法,加上计算机语言的特质就令我查阅许久。
最后是历史对局功能,我本来想着使用文件读写在弹窗出输赢的之后写入白方赢了,或者黑方赢了到文件中,然后再用窗口把他调用出来,但是这样会出现问题,也不能很好实现历史对局,后面经过反复观看文件读写相关视频才来了灵感。
上面三个功能,当我在查阅资料时,鲜有程序做到了这些,一开始我只是打算按教程去做项目,但后面随着一行行代码的敲下,我逐渐想要加上自己独属的内容。
此次大作业,让我发现,其实一些看似不可思议的操作实际上只是基本方法的熟练使用,比如五子连珠的判断,其实就是利用数组的特点,倒计时显示更是只用了四则运算,没有太多花里胡哨的东西,掌握好基础知识才是最重要的。
以及,变量的命名非常重要,好的命名方式可以节省不少时间,我再次在这次大作业中体会到了此点。
追风赶月莫停留,平芜尽处是春山,以后我们想继续深入学习Java或者其他语言,我认为基础内容和一些代码规范是非常重要的,一味追求算法反而容易忽略最本质的东西。
当然,定期练习项目,整合所学知识也非常重要。
多看,多听,多练,在计算机领域尤其适用。
自评分自评分:93自评语:本次大作业途中虽然遇到了很多困难,但我最终还是克服了这些困难,并在本次大作业中进行了创新,添加了倒计时,悔棋功能和查看历史对局功能,可以给游戏增加可玩性,不至于因为误触而影响游戏体验。

联系我们

在线咨询:点击这里给我发消息