基于JAVA实现的21点游戏

Juvenile

发布日期: 2018-12-21 13:22:11 浏览量: 3502
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

1 需求分析

本系统主要提供人机对玩21点牌游戏,实现系统自动判断输赢,计算玩家金钱,并保存用户名称,金钱,头像等信息。另附带在玩游戏时提供背景音乐欣赏。

21点游戏基本规则为:每个人最多可拿5张牌,牌的点数在21内(包括21点),玩家点数大的赢,点数相同时庄家赢,玩家点数大于21时不管庄家的点数是什么,玩家都输。A牌可以当1点或11点。当玩家的点数为21点是,其输或着赢的金钱都为点数的双倍。

1.1 功能需求描述

本系统要求采用Java GUI程序实现一个21点游戏,主要包括如下功能:

  • 系统发牌:游戏初始时又系统给电脑方发牌,并给用户初始发2张牌

  • 用户发牌:用户点击发牌按钮,只要用户的牌的点数和小于21就可以获取一张由系统从整副牌剩下的牌中产生的一张随机的牌

  • 开牌:当用户点击开牌按钮后,系统自动计算电脑方和游戏玩家方的牌的点数,判断输赢,计算赌注,游戏金钱出入

  • 用户信息设置:游戏玩家可以从菜单中打开用户设置,初始化游戏金钱,设置昵称,头像等信息

  • 用户信息保存:各玩家的姓名,游戏金钱,头像图片等信息都保存在一个xml文件中,游戏开始时有系统自动读取,游戏中数据变更时有系统自动保存,并在游戏中更新

  • 游戏背景音乐:游戏中,用户可以从菜单中选择开启或关闭游戏背景音乐

1.2 开发环境

  • JKD 1.6

  • Eclipse

2 总体设计

2.1 系统类设计与算法描述

2.1.1 系统类图

2.1.2 游戏中主要算法

发牌算法

  • 创建一副牌

  • 给电脑发牌,只要牌的总点数小于16,牌的张数小于5就继续为电脑发牌,每张牌都是有i中创建的整副牌中随即获取

  • 从i中创建好的牌中删除发出去的牌

  • 给玩家发2张牌,并从删除这2张牌

点数计算算法

  • 计算出玩家手中的非A的牌的点数和count1,并统计A牌的个数countA

  • 如果A的牌的数量大于0,并且count1+11+countA-1小于等于21则取这个结尾为本步骤的结果;否则取count1+countA为本步骤结果

  • 算法结束

2.2 系统功能模块设计

2.3 界面设计

3 系统主函数程序设计

  1. public static void main(String[] args){
  2. //创建game,及相关参数创建及初始化(略)
  3. /*--------------界面创建(略)---------------*/
  4. /*--------------------关键事件处理(其余事件处理略)------------*/
  5. //菜单栏按钮事件
  6. //音乐开按钮事件
  7. musicOn.addActionListener(new ActionListener() {
  8. public void actionPerformed(ActionEvent arg0) {
  9. game.soundPlay();
  10. }
  11. });
  12. //音乐关按钮事件
  13. musicOff.addActionListener(new ActionListener() {
  14. public void actionPerformed(ActionEvent arg0) {
  15. game.soundStop();
  16. }
  17. });
  18. // 工具栏按钮事件处理
  19. //发牌按钮事件
  20. b_dealCard.addActionListener(new ActionListener() {
  21. public void actionPerformed(ActionEvent arg0) {
  22. game.countCardsValue(1);
  23. if(game.getUserCards().size() < 5 && game.getCardsValue(1)< 21){
  24. game.addCard(1);
  25. game.countCardsValue(1);
  26. game.getUserCardsPanel().removeAll();
  27. game.getUserCardsPanel().updateUI();
  28. }
  29. else if(game.getUserCards().size() < 5 && game.getCardsValue(1) == 21){
  30. String message = "<html><p>你21点啊,还不开牌...</p></html>";
  31. JOptionPane.showMessageDialog(game,message );
  32. }
  33. else if(game.getUserCards().size() < 5){
  34. String message = "<html><p>不好意思!你的点数大于21</p><p>你挂了... -_-</p></html>";
  35. JOptionPane.showMessageDialog(game,message );
  36. }
  37. else{
  38. String message = "<html><p>已经发了5张牌了,不能再发了</p></html>";
  39. JOptionPane.showMessageDialog(game,message );
  40. }
  41. }
  42. });
  43. //重新开局按钮事件
  44. b_newGame.addActionListener(new ActionListener() {
  45. public void actionPerformed(ActionEvent arg0) {
  46. //发牌按钮可用
  47. b_dealCard.setEnabled(true);
  48. //开牌按钮可用
  49. b_chechout.setEnabled(true);
  50. //重新初始化游戏
  51. game.gameStart();
  52. //更新空间
  53. game.getComputerCardsPanel(false).removeAll();
  54. game.getComputerCardsPanel(false).updateUI();
  55. game.getUserCardsPanel().removeAll();
  56. game.getUserCardsPanel().updateUI();
  57. //重新设置部分空间显示
  58. l_userValue.setText("");
  59. l_computerValue.setText("");
  60. l_win.setVisible(false);
  61. }
  62. });
  63. //开牌按钮事件
  64. b_chechout.addActionListener(new ActionListener() {
  65. public void actionPerformed(ActionEvent arg0) {
  66. //将电脑方牌正面显示
  67. game.getComputerCardsPanel(false).removeAll();
  68. game.getComputerCardsPanel(true).updateUI();
  69. game.countCardsValue(0);
  70. game.countCardsValue(1);
  71. //发牌按钮不可用
  72. b_dealCard.setEnabled(false);
  73. b_chechout.setEnabled(false);
  74. //显示玩家得点
  75. l_userValue.setText(game.getCardsValue(1) + "");
  76. l_computerValue.setText(game.getCardsValue(0) + "");
  77. //设置赌注
  78. game.setGameMoney(Integer.parseInt(T_gameMoney.getText()));
  79. //判断输赢
  80. if(
  81. (game.getCardsValue(1) < 21 && game.getCardsValue(0) < game.getCardsValue(1))
  82. ||
  83. (game.getCardsValue(1) < 21 && game.getCardsValue(0) > 21)
  84. ){
  85. //玩家赢单倍
  86. l_win.setBounds(470, 340, 33, 44);
  87. gameUser.setUserMoney(gameUser.getUserMoney() + game.getGameMoney());
  88. computerUser.setUserMoney(computerUser.getUserMoney() - game.getGameMoney());
  89. }
  90. else if(game.getCardsValue(0) == 21 ){
  91. //庄家得双倍
  92. l_win.setBounds(470, 220, 33, 44);
  93. computerUser.setUserMoney(computerUser.getUserMoney() + 2 * game.getGameMoney());
  94. gameUser.setUserMoney(gameUser.getUserMoney() + game.getGameMoney());
  95. }
  96. else if(game.getCardsValue(1) == 21 && game.getCardsValue(0) != 21){
  97. //玩家赢双倍
  98. l_win.setBounds(470, 340, 33, 44);
  99. gameUser.setUserMoney(gameUser.getUserMoney() + 2 * game.getGameMoney());
  100. computerUser.setUserMoney(computerUser.getUserMoney() - 2 * game.getGameMoney());
  101. }
  102. else{
  103. //庄家赢单倍
  104. l_win.setBounds(470, 220, 33, 44);
  105. computerUser.setUserMoney(computerUser.getUserMoney() + 2 * game.getGameMoney());
  106. gameUser.setUserMoney(gameUser.getUserMoney() - game.getGameMoney());
  107. }
  108. l_computerMoney.setText(computerUser.getUserMoney() + "");
  109. l_userMoney.setText(gameUser.getUserMoney() + "");
  110. l_win.setVisible(true);
  111. gameUser.save();
  112. computerUser.save();
  113. }
  114. });
  115. //赌注输入事件处理
  116. T_gameMoney.addKeyListener(new KeyAdapter() {
  117. public void keyReleased(KeyEvent arg0) {
  118. int tempMoney = Integer.parseInt(T_gameMoney.getText());
  119. if( tempMoney < 10){
  120. T_gameMoney.setText("10");
  121. }
  122. else if(tempMoney < gameUser.getUserMoney() && tempMoney < computerUser.getUserMoney() ){
  123. game.setGameMoney(tempMoney);
  124. T_gameMoney.setText(tempMoney + "");
  125. }
  126. else if(tempMoney > gameUser.getUserMoney() || tempMoney > computerUser.getUserMoney()){
  127. T_gameMoney.setText(Math.min(gameUser.getUserMoney(),computerUser.getUserMoney()) + "");
  128. }
  129. game.setGameMoney(Integer.parseInt(T_gameMoney.getText()));
  130. }
  131. });
  132. //赌注加事件
  133. b_moneyAdd.addActionListener(new ActionListener() {
  134. public void actionPerformed(ActionEvent arg0) {
  135. if((Integer.parseInt(T_gameMoney.getText()) + 10) < computerUser.getUserMoney() &&
  136. (Integer.parseInt(T_gameMoney.getText()) + 10) < gameUser.getUserMoney()){
  137. T_gameMoney.setText(Integer.parseInt(T_gameMoney.getText()) + 10 + "");
  138. game.setGameMoney(Integer.parseInt(T_gameMoney.getText()));
  139. }
  140. }
  141. });
  142. //赌注减事件
  143. b_moneySub.addActionListener(new ActionListener() {
  144. public void actionPerformed(ActionEvent arg0) {
  145. if((Integer.parseInt(T_gameMoney.getText()) - 10) > 0)
  146. T_gameMoney.setText(Integer.parseInt(T_gameMoney.getText()) - 10 + "");
  147. else
  148. T_gameMoney.setText("10");
  149. game.setGameMoney(Integer.parseInt(T_gameMoney.getText()));
  150. }
  151. });
  152. game.setVisible(true);
  153. }

4 小结

这个游戏系统比较难及复杂的地方在于游戏过程中的逻辑处理和和解决这些逻辑问题的有效的算法步骤。通过整个程序的代码量的分布也体现了这一点。其基础的几个类Card,Cards,User都只有少量的代码,大量的代码分布在发牌,开局,重新开局等事件处理上。界面的实现也费用了很多代码。而通过实现这个程序,我也发现了自己在逻辑问题处理上的弱势。比如在处理A牌改当1点算,还是当11点算时,我花费了很长时间来理清这个思路。而事实上这个逻辑处理比较简单。

整个系统的结构设计没有抽象好。GameMain这个类在这里是游戏功能的主要类的实现,但是跟mian函数写在一起,又跟界面混在一起,逻辑没有跟界面脱离好。导致这个类的文件代码过长,方法过多,容易产生紊乱,给维护修改带来困难。应该从中抽象出一个专门处理游戏业务逻辑的类,把界面完全分离出来。让系统更灵活些。

Java里的DOM不是完全是基于W3C规范的DOM。Java里的对XML的操作如果用DOM来实现的话,需要另外格式化数据,不然容易出现一些错误的假象,在未格式化的XML Document对象中,换行也会当作一个节点来处理。这让我一贯浏览器端Javascript中的DOM思维变得很无奈,通过断点,逐步查看变量的值才发现换行是个节点。这与规范的DOM不相符合,不过Java里一般会通过自有的方法先格式化XML Document,写入时也要将它格式化再写入磁盘文件。

User类的设计缺乏对xml数据写入的考虑。开始时只想到要从xml文件中取数据,而没有考虑到写入操作,所以User类中的方法很多都是私有的,读取数据的方法。在做写入操作是由creatDoc 方法创建了,Document而getUserNode 方法操作的是另外一个Document,导致数据不一致,所以调用写入方法就毫无意义了。而如果保存了全部数据的话又会导致游戏中创建的用户得不到数据的重新初始化。应该设一个Document私有属性来达到这个类内部的Document数据统一。

上传的附件 cloud_download 基于JAVA实现的21点游戏.7z ( 995.63kb, 146次下载 )
error_outline 下载需要11点积分

发送私信

我依旧深信时间是良药虽苦口,但有效

16
文章数
20
评论数
最近文章
eject