Java课程设计报告--Hannoi塔.doc_第1页
Java课程设计报告--Hannoi塔.doc_第2页
Java课程设计报告--Hannoi塔.doc_第3页
Java课程设计报告--Hannoi塔.doc_第4页
Java课程设计报告--Hannoi塔.doc_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

课 程 设 计 报 告 课程名称 Java程序设计 课题名称 Hannoi塔 专 业 计算机科学与技术 班 级 学 号 姓 名 指导教师 李远辉 2013 年 6月 27日湖南工程学院课 程 设 计 任 务 书课程名称 Java程序设计 课 题 Hannoi塔 专业班级 学生姓名 学 号 指导老师 李远辉 审 批 李远辉 任务书下达日期 2013 年 6 月20 日任务完成日期 2013 年 6 月 27 日目录1. 设计要求1 1.1 界面要求1 1.2 功能要求1 2. 总体设计 2 2.1 总体概述2 2.2 主要类功能设计33. 详细设计5 3.1 HannoiWindow类 5 3.2 Tower类 5 3.3 HandleMouse类 6 3.4 AutoMoveDisc类7 3.5 TimeCount类 84. 调试与结果分析9 4.1 初级游戏9 4.2 游戏界面属性设置10 4.3 游戏外观设置10 4.4 自动移动演示105. 设计总结与心得体会12附录 13 1 参考书13 2 源代码131 设计要求 1.1 界面要求 用户界面为GUI界面,其分为菜单栏以及游戏区两个部分。游戏区中分布有三座Hannoi塔,其名字分别为A、B、C。初始状态下A座有三个大小不等的盘子,其按照从大到小的顺序依次摆放在A座上。 1.2 功能要求 1.2.1 游戏规则 用户用鼠标选中盘子,然后通过拖动鼠标来移动盘子、释放鼠标来放置该盘子。其中主要的规则就是:(1) 移动盘子时,盘子上方必须无盘子(2) 放置盘子时,其位置必须在塔点处,而且盘子必须比下方盘子小(3) 游戏结束的条件是:所有的盘子均从A座移到B或C座 1.2.2 游戏设置功能 用户可以通过游戏-选项来设置游戏的一些基本的属性,如是否播放音乐、难度、盘子大小等等 1.2.3 游戏帮助功能 用户可以通过菜单栏中的帮助能过初步了解游戏的相关信息,以及如何操作。其中必须实现游戏的自动完成功能以指导用户如何操作。 1.2.4 游戏外观设置功能 用户可以通过游戏-外观可以设置游戏的背景颜色以及盘子的颜色2 总体设计 2.1 总体概述 在设计Hannoi塔时,需要编写9个Java源文件:AutoMoveDisc.java、Disc.java、GameMusic.java、GameSettingS.java、HandleMouse.java、HannoiWindow.java、TimeCount.java、Tower.java、TowerPoint.java。 Hannoi塔除了要编写的10个Java源文件所给出的类外,还需要Java系统提供的一些重要的类,如JMenuBar、JMenu、JMenuItem和JButton。Hannnoi塔所用的一些重要的类以及之间的组合关系如图2.1 所示:HannoiWindow TowerJMenuItemJMenuBarGameSettingSJMenuGameMusicAutoMoveDiscHandleMouseDiscTowerPointTimeCount图2.1 类之间的组合关系 2.2 主要类功能设计 2.2.1 HannoiWindow.java HannoiWindows类主要负责创建Hannoi塔的主窗口,该类包含main()方法,Hannoi塔从此类开始执行。HannoiWindows类的成员变量有五种重要类型对象以及一个char型数组。五种重要类型对象为:Tower、JMenuBar、JMenu、JMenuItem和GameSettings 对象。其效果图2.2如下: 图2.2 主界面 2.2.2 Tower.java Tower.java类是javax.swing.JPanel的子类,创建的容器被添HannoiWindow窗体的中心。Tower类主要的功能是设置游戏区的所有组件的位置等相关信息以及注册其中的监听器。 2.2.3 HandleMouse.java HandleMouse类主要负责的是鼠标移动游戏区组件所有的事件,其主要实现了 MouseListener,MouseMotionListener两个接口的方法。其所有的移动都必须遵守1.2.1的游戏规则。 2.2.4 AutoMoveDisc.java AutoMoveDisc类是javax.swing.JDialog类的子类,其主要的功能是弹出一个对话框在其中显示字符移动的全过程,与此同时移动游戏区的盘子直至游戏结束。其中包含的操作有开始、结束、继续、暂停、保存五大操作。 2.2.5 GameSettingS.java GameSettingS类是javax.swing.JFrame类的子类,其主要的功能是弹出一个界面,其中包含游戏的基本设置项目,通过此界面的操作来调整游戏区的相关信息。 3 详细设计 3.1 HannoiWindow类 其主要的方法是actionPerformed(ActionEvent e),其是ActionListenter接口的方法的实现。主要的功能就是监听JMenuItem对象如gStart等的监听。 其部分代码如下: else if(e.getSource()=gFColor)Tower.discsColor=JColorChooser.showDialog(this,请选择背景色 ,new Color(255,0,0);if(equalsColor()JOptionPane.showMessageDialog(null, 背景色与盘子颜色相同,设置无效);return;tower.putDiscOnTower(); 以上代码是监听到盘子设置菜单选择点击事件,系统弹出一个颜色的对话框,选择颜色后通过tower.putDiscOnTower()刷新游戏区。 3.2 Tower类 其UML图如下图3.1所示: Tower类中主要的功能就是确定塔、盘子的位置以及画图。其中最主要的是位置的确定。其关键代码如下: /设置塔点的x,yint vertialDistance=discHeight; for(int i=0;ipointA.length;i+) pointAi=new TowerPoint(maxDiscWidth-20,100+vertialDistance); pointBi=new TowerPoint(2*maxDiscWidth-20,100+vertialDistance); pointCi=new TowerPoint(3*maxDiscWidth-20,100+vertialDistance); vertialDistance=vertialDistance+discHeight; for(int i=0;ipointA.length;i+) pointAi.putDisc(discsi,this); 其中最主要的是知道Java图形界面的坐标系是采用的是倒坐标系,所以pointA或pointB数组中最后的一个TowerPoint对象就是A或B座最底下的一个盘子的坐标 3.3 HandMouse类 HandMouse的UML类图为图3.2 HandMouse类主要处理的是鼠标对盘子移动。其中主要涉及的是鼠标选中 盘子、鼠标拖动盘子、鼠标放置盘子,所以其中主要的方法有三个:(1) mousePressed(MouseEvent e)(2)mouseDragged(MouseEvent e)(3)mouseReleased(MouseEvent e) ,下面主要介绍一下mousePress(MouseEvent e)方法对鼠标选中盘子时判断是否可以移动时的处理,其主要代码如下: for(int i=0;i0&!pointAm-1.haveDisc)move_flag=true;break; 以上代码是判断选中的盘子是否是A座上的盘子同时判断是否可以移动?首先通过if(pointAi.equals(startPoint))判断是否相等,如果相等则继续判断盘子是否为最上方的盘子或者盘子的上方无盘子,如果仍成立,则将可移动标示设为true。 图3.1 Tower类图 图3.2 HandleMouse类图 3.4 AutoMoveDisc类 AutoMoveDisc类的UML图如图3.3所示 AutoMoveDisc类是javax.swing.JDialog的一个子类,其主要的功能可以参考总体设计中2.2主要类的功能设计。其中最主要的代码是计时器监听,代码大致结构如下: public void actionPerformed(ActionEvent e) if(e.getSource()=time)/移动信息输入对话框 /移动游戏区盘子else if(e.getSource()=btn_start)/迭代字符串求解time.start(); else if(e.getSource()=btn_stop)If(time.isRunning)time.stop(); 其设计巧妙的运用了javax.management.timer的相关性质。 图3.3 AutoMoveDisc类UML图 3.5 TimeCount类 TimeCount类继承了JLabel类,实现了Runnale接口。其中主要的方法是run()方法即线程体。其中通过取得系统时间与记录的游戏开始时间的差来刷新其组件上的内容。关键代码结构如下: public void run()if(flag) startDate=new Date(); flag=false; While(flag) Date currentDate=new Date(); /将currentDatr与startDate之差以为时:分:秒:毫秒:格式转为字符串str lab_time.setText(str); 其中通过flag来保证能够获得用户用鼠标移动第一个盘子的时间,其中主要涉及的问题是如何保证显示同步,相关内容在5 设计总结与心得体会有讲解。 本类主要用在HandleMouse类中,其中控制结构如下: /通过start_flag控制是否开始进程 public void mousePressed(MouseEvent e) if(start_flag)thread=new Thread(runThread);thread.start();start_flag=false; /匹配盘子及判断盘子是否可以移动 public void mouseReleased(MouseEvent e) /判断游戏是否结束,如果结束则停止计时线程 if(pointB0.getHaveDisc()|pointC0.getHaveDisc()end_flag=true;start_flag=true;runThread.flag=true;thread.stop();String str=runThread.getLabTime().getText();JOptionPane.showMessageDialog(null, YOU WINn+用时+str);Thread.currentThread().stop(); 以上代码核心为start_flag控制,其他相关控制在5设计总结和心得体会可以解答。4 调试与结果分析 4.1 初级游戏 图 4.1 初级游戏 上图是游戏难度为初级即盘子数量为3的Hannoi游戏。从图中可以看出实现了游戏的基本规则以及界面要求还有就是计时要求。 其中基本规则在初稿的时候有一个很大的Bug,情况如图4.2 图4.2 规则Bug 其中的现行条件是必须有一步是按规则玩的。 其bug出现的原因是因为在放置盘子后没有将move_flag修改为false. 4.2 游戏界面属性设置 游戏界面属性设置主要是采用Checkbox类设计,其布局管理器为GridBagLayout。鼠标点击游戏-选项即可出现如图4.3 图 4.3 选项 其中初稿主要的问题是由于GameSettingS类是JFrame的一个子类,其 与主窗口为不同的进程因此修改的属性值无法在主窗口中体现出来。后来将游戏区tower作为参数传入直接重绘。 4.3 外观设置 盘子与背景色的设置主要是通过JColorChooser.showDialog(component, title, initialColor)方法来设置的。鼠标点击游戏-外观-背景颜色,如图4.4选择颜色,其结果如图4.5 4.3 自动移动演示 如图4.5图4.4 背景色设置 图 4.5 自动移动演示5 设计总结和心得体会 本次课程由于老师已经将部分源代码分发以及星期一、二的上课,可以说对整个游戏的结构已经比较清晰了。其中主要的问题是数据传递问题以及线程问题。 数据传递问题在调试与结果分析 4.2游戏界面属性设置中已经提及了,接下来在详细的说明。由于GameSettingS与HannoiWindow两个类的实例是两个不同的SWI线程,所以其执行顺序不定,如果只是单纯的依赖方法传递参数则极有可能无法进行目标的数据交流,由于两者操作平台都是Tower的对象tower,所以可以将其作为两者的共享数据,通过此来进行数据交流,此为简单的线程间通信。 还有时间计数的问题,主要是如在正在游戏是突然间设置游戏属性,则时间计数可能不准确。如在游戏时中途设置游戏难度为中级,在初稿中则会出现计数器无法重新计数。其中最最要的问题是游戏未至结束阶段,所以时间计数线程仍就并发的执行,所以在设置难度时将时间计数线程重置即可。 本次课程设计中还有一个问题尚未解决,那就是盘子的大小改变时,如何同时以适当比率改变窗口大小等。二稿中用 ComponentAdapter监听窗口大小,以比率系数来改变盘子等的大小,但是其中比率系数以及坐标变化等难以确定故放弃。 总的来说,在本次课程设计中学到了很多,如StartUML软件的使用以及如何活用适配器以及监听接口、内部类等。 附录1 参考书籍 1 李刚. 疯狂Java讲义M. 第二版. 电子工业出版社, 2012-12. 2 辛云伟. Java程序设计M. 第二版. 清华大学出版社, 2012-3. 3 张广彬, 王小宁, 高静. Java课程设计案例精编M. 第2版. 清华大学出版社, 2011-6.2 源代码HannoiWindow类public class HannoiWindow extends JFrame implements ActionListenerprivate Tower tower;private char towerName=A,B,C;private JMenuBar bar_hannoi;private JMenugame,surface;private JMenuItem gStart,gSetting,gBColor,gFColor,gExit;private GameSettingS set;private JMenu help;private JMenuItem helpword,helpAuto;public HannoiWindow()/设置游戏界面tower=new Tower(towerName); tower.setMaxDiscWidth(120); tower.setMinDiscWidth(50); tower.setDiscHeight(16); tower.putDiscOnTower(); add(tower,BorderLayout.CENTER); /游戏下拉栏 bar_hannoi=new JMenuBar(); surface=new JMenu(外观); game=new JMenu(游戏); gStart=new JMenuItem(新游戏); gSetting=new JMenuItem(选项); gFColor=new JMenuItem(盘子颜色); gBColor=new JMenuItem(背景颜色); gExit=new JMenuItem(退出); surface.add(gFColor); surface.add(gBColor); game.add(gStart); game.add(gSetting); game.add(surface); game.add(gExit); bar_hannoi.add(game); gStart.addActionListener(this); gExit.addActionListener(this); gBColor.addActionListener(this); gFColor.addActionListener(this); gSetting.addActionListener(this); set=new GameSettingS(tower,this); /帮助下拉栏 help=new JMenu(帮助); helpword=new JMenuItem(关于Hannoi); helpAuto=new JMenuItem(Hannoi演示); help.add(helpword); help.add(helpAuto); bar_hannoi.add(help); helpword.addActionListener(this); helpAuto.addActionListener(this); setJMenuBar(bar_hannoi); setTitle(汉罗塔); setResizable(false); setVisible(true); setBounds(60,60,450,450); validate(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); /判断盘子颜色与背景颜色相同否private boolean equalsColor()Color back=Tower.towerColor;Color fron=Tower.discsColor;int i=back.getRGB();int k=fron.getRGB();if(back.getRGB()=fron.getRGB()return true;return false;Overridepublic void actionPerformed(ActionEvent e) if(e.getSource()=gStart)tower.getHandleMouse().setThreadField(); tower.putDiscOnTower();else if(e.getSource()=gExit)System.exit(0);else if(e.getSource()=gSetting)tower.getHandleMouse().setThreadField();set.setVisible(true);else if(e.getSource()=gBColor)Tower.towerColor=JColorChooser.showDialog(this,请选择背景色 ,new Color(255,0,0);if(equalsColor()JOptionPane.showMessageDialog(null, 背景色与盘子颜色相同,设置无效);return;tower.setBackground(Tower.towerColor);else if(e.getSource()=gFColor)Tower.discsColor=JColorChooser.showDialog(this,请选择背景色 ,new Color(255,0,0);if(equalsColor()JOptionPane.showMessageDialog(null, 背景色与盘子颜色相同,设置无效);return;tower.putDiscOnTower();else if(e.getSource()=helpword)tower.getHandleMouse().setThreadField();String help=游戏规则如下n下方盘子必须必上方盘子大n所有盘子从A移B或C则获胜;JOptionPane.showMessageDialog(null,help);else if(e.getSource()=helpAuto) tower.getHandleMouse().setThreadField(); tower.putDiscOnTower(); int x=this.getBounds().x+this.getBounds().width; int y=this.getBounds().y; /设置对话框位置 tower.getAutoMoveDisc().setLocation(x,y); tower.getAutoMoveDisc().setSize(400,this.getBounds().height); tower.getAutoMoveDisc().setVisible(true); public static void main(String args) HannoiWindow hannoi=new HannoiWindow();TowerPoint类import java.awt.*;import .hnie.HannoiV2.Disc;public class TowerPoint private int x,y;/坐标boolean haveDisc=false;/判断坐标点上是否有盘子Disc disc=null;public TowerPoint(int x,int y)this.x=x;this.y=y;public void setHaveDisc(boolean flag)haveDisc=flag;public boolean getHaveDisc()return this.haveDisc;public int getX()return x;public int getY()return y; /判断两个坐标点是否相等public boolean equals(TowerPoint p)if(p!=null)if(this.getX()=p.getX()&this.getY()=p.getY()return true;return false;/end_equalspublic void putDisc(Component com,Container con)disc=(Disc)com;con.setLayout(null);/获取disc的大小相关信息 int w=disc.getBounds().width; int h=disc.getBounds().height; disc.setBounds(x-w/2,y-h/2,w,h); con.add(disc); /记录属性 haveDisc=true; disc.setPoint(this); con.validate(); public Disc getDiscOnPoint() return disc; /移除盘子 public void removeDisc(Component com,Container con) if(com!=null) con.remove(com); con.validate(); Disc类import java.awt.Color;import javax.swing.JButton;public class Disc extends JButtonprivate int large;/盘子的大小 private TowerPoint point;/盘子的顶点大小public Disc()setBackground(Color.cyan);/Setter/Getter方法HandleMouse类import java.awt.*;import javax.swing.*;import .hnie.HannoiV2.TowerPoint;import .hnie.HannoiV2.Disc;public class HandleMouse implements MouseListener,MouseMotionListenerTowerPoint pointA,pointB,pointC; /柱子上的坐标信息TowerPoint startPoint,endPoint;/开始点以及结束点的位置信息int leftX,leftY,X0,Y0;/坐标boolean move_flag=false;Container cont;private Thread thread;private TimeCount runThread;private JPanel pan_time;private boolean start_flag=true;private boolean end_flag=false;public HandleMouse(Container cont)this.cont=cont;runThread=new TimeCount(cont);/PointA,PointB,PointC的Setter方法/* * 解决进程运行过程中由于难度重新选择的问题 * 将进程所有的相关两重新配置 * 进程重启 */public void setThreadField()/* * 判断是否是游戏是否为在计时 * 但是不为游戏状态 */if(thread!=null)end_flag=true;start_flag=true;runThread.flag=true;thread.stop();return;/鼠标事件处理/* * 鼠标在组件下按下(non-Javadoc) * 判断盘子是否可以移动 */public void mousePressed(MouseEvent e) if(start_flag)thread=new Thread(runThread);thread.start();start_flag=false;Disc disc=null;if(e.getSource().getClass()=Disc.class)disc=(Disc)e.getSource();startPoint=disc.getPoint();/* * 注意此处的赋值采用的是e.getX() * 而非startPoint的原因是此处要取得的是鼠标的坐标 * 如果改成startPoint.getX()则会出现鼠标位置与组件差距大 * 影响mouseDragged()方法的结果 */X0=e.getX();Y0=e.getY();int m=0;/* * 判断组件的坐标是否是A处的坐标 * 如果A处有相匹配的坐标 * 如果有则进一步判断该盘子上方是否有盘子,如无则move_flag置为true * 如果无则将move_flag置false */for(int i=0;i0&!pointAm-1.haveDisc)move_flag=true;break;/end_for(pointA)for(int i=0;i0&!pointBm-1.haveDisc)move_flag=true;break;/end_for(pointB)for(int i=0;i0&!pointCm-1.haveDisc)move_flag=true;break;/end_for(pointC)/end_mousePressed(MouseEvent e)/鼠标选中组件并拖动信息public void mouseDragged(MouseEvent e) Disc disc=null; disc=(Disc)e.getSource(); leftX=disc.getBounds().x; leftY=disc.getBounds().y; int x=e.getX(); int y=e.getY(); leftX=leftX+x; leftY=leftY+y; if(move_flag=true) disc.setLocation(leftX-X0,leftY-Y0); /end_mouseDragged(MouseEvent e)/判断盘子位置是否可以放置于此public void mouseReleased(MouseEvent e) Disc disc=null;if(e.getSource().getClass()=Disc.class)disc=(Disc)e.getSource();/获得组件范围,位置不确定Rectangle rect=disc.getBounds();int x=-1;int y=-1;/确定的塔点坐标boolean location=false;/* *判断是否可以放在此位置 *首先是判断拖到的终点坐标是否为A、B、C的上的一个塔点 *如果是,则判断其下方无盘子或下方盘子比上方的盘子大,条件成立则移动,否则将盘子放回原有的地点 *如果不是,则将盘子放回原有的坐标 */for(int i=0;ipointA.length;i+)x=pointAi.getX();y=pointAi.getY();/如果塔点坐标在此组件的边界之内if(rect.contains(x, y)endPoint=pointAi;/如果塔点坐标在最上方且无盘子if(i=pointA.length-1) & !pointAi.haveDisc)location=true;break;/如果塔点坐标不为最上方且无盘子 /下方有盘子且盘子的大小小于此盘子else if(ipointA.length-1 & !pointAi.haveDisc& pointAi+1.haveDisc & disc.getLarge()=pointAi+1.getDiscOnPoint().getLarge()location=true;break;/end_for(pointA)for(int i=0;ipointB.length;i+)if(location)break;x=pointBi.getX();y=pointBi.getY();/如果塔点坐标在此组件的边界之内if(rect.contains(x, y)endPoint=pointBi;/如果塔点坐标在最上方且无盘子if(i=pointB.length-1) & !pointBi.haveDisc)location=true;break;/如果塔点坐标不为最上方且无盘子 /下方有盘子且盘子的大小小于此盘子else if(ipointB.length-1 & !pointBi.haveDisc& pointBi+1.haveDisc & disc.getLarge()=pointBi+1.getDiscOnPoint().getLarge()location=true;break;/end_for(pointB)for(int i=0;ipointC.length;i+)if(location)break;x=pointCi.getX();y=pointCi.getY();/如果塔点坐标在此组件的边界之内if(rect.contains(x, y)endPoint=pointCi;/如果塔点坐标在最上方且无盘子if(i=pointC.length-1) & !pointCi.haveDisc)location=tru

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论