java实现24点游戏

游戏规则

从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。

基本要求

  • 随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式
  • 列出表达式无重复
  • 用户初始生命值为一给定值(比如3),初始分数为0。随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。
  • 使用计时器要求用户在规定时间内输入表达式,如果规定时间内运算正确则加分,超时或运算错误则进入下一题并减少生命值(不扣分)。
  • 所有成绩均可记录在TopList.txt文件中。

解表达式基本思路

采用穷举法列举每一种存在的可能,接着判断是否值为24,如果等于24,则将表达式存入Set集合,最终遍历Set集合即可得到所有表达式。具体思路如下:

1.采用随机数生成4个符合要求的数据,假设四个数据为n1,n2,n3,n4 。
2.把数据相互组合可以得到如下组合:n1和n2 ,n1和n3,n1和n4,n2和n3,n2和n4,n3和n4
3.将上面的组合进行各种可能的运算例如:n1+n2,n1-n2,n2-n1,n1*n2,n1/n2,n2/n1等等。
4.把上面组合计算出来的结果存入进对应的数组中例如:组合相加的结果存入add数组,相减的结果存入sub数组……最终将这些数组存入一个list集合中,目的是为了方便通过循环遍历出每一种组合。
5.通过循环去遍历每一种组合,把这些组合在一起进行相加,相减等运算,记录结果为24的表达式。在这里需要注意的是,因为数组得值为两个数字的运算结果,所以需要根据当前循环变量的值和list集合以及数组存入数据的顺序去把表达式格式化成四个数字组成的表达式,否则表达式只有两个数字。

  • 需要注意的是:在遍历集合的过程中,由于集合中存入的数组的数据为两个数据组合的形式,所以遍历是只需要控制好下标,使的每一个表达式中只有n1,n2,n3,n4这四个数据,而不会出现类似于n1,n2,n1,n3 这种组合的方式。
  • 具体的流程图入下图所示:

玩家运算基本思路

在java中使用Timer和Canender即可实现定时的功能,而判断表达式是否正确,在java中使用Script引擎调用eval方法即可判断表达式的值是否正确,具体思路如下:

1.初始化生命值,和分数
2.由系统给出四个数字
3.玩家给出答案
4.判断给出的答案中的数字和系统给出的数字是否吻合,如果吻合进入5,否则,生命值减一。
5.借助Timer类的schedule()判断是否超时,如果没有超时,进入6,否则,生命值减一。
6.借助script引擎的eval()方法可以判断表达式是否正确,如果正确,分数加一,否则,生命值减一。
当生命值大于0时执行2,3,4,5,6操做,否则将当前分数写入文件。

流程图如下图所示

编码

Game类,主要实现由系统随机生成数据,并计算可能的表达式

为了避免除零异常采用了float类型的数组进行存储

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.util.Set;

/**
 *
 * Title: Test Description: 1. 采用随机数生成4个符合要求的数据,假设四个数据为n1,n2,n3,n4 。
 * 2.把数据相互组合可以得到如下组合:n1和n2 ,n1和n3,n1和n4,n2和n3,n2和n4。
 * 3.将上面的组合进行各种可能的运算例如:n1+n2,n1-n2,n2-n1,n1*n2,n1/n2,n2/n1等等。
 * 4.把上面组合计算出来的结果存入进对应的数组中例如:组合相加的结果存入add数组,相减的结果存入sub数组……最终将这些数组存入一个list集合中,目的是为了方便通过循环遍历出每一种组合。
 * 5.通过循环去遍历每一种组合,把这些组合在一起进行相加,相减等运算,记录结果为24的表达式
 * @author jianglei
 */
public class Game {
 static Set<String> set = new HashSet<String>();// 使用Set存储算式表达式可以避免有重复的结果
 float[] data = new float[4];// 存放数据的集合
 float[] add = new float[6];// 存放组合相加的结果的集合
 float[] sub1 = new float[6];// 存放相减的结果(两个数相减的结果存在两种可能)
 float[] sub2 = new float[6];// 存放相减的结果
 float[] mul = new float[6];// 存放相乘
 float[] div1 = new float[6];// 存放相除(两个数相除的结果存在两种可能)
 float[] div2 = new float[6];// 存放相除
 List<float[]> list = new ArrayList<float[]>();// 存放组合结果运算的集合

 /**
 *
 * Title: combine
 * </p>
 * Description: 该方法用来获取每两个数字的组合组合, 用1代表第一个数字,2代表第二个数字....共有六种组合方式,分别如下:
 * 1和2,1和3,1和 4,2和 3,2和 4,3和 4 在上面的组合中,每一种组合都对应着 加减乘除 这四种运算
 * 将上述的组合的每种计算结果存入上面声明的集合
 */
 public void conbine(float n1, float n2, float n3, float n4) {
 add[0] = n1 + n2;
 add[1] = n1 + n3;
 add[2] = n1 + n4;
 add[3] = n2 + n3;
 add[4] = n2 + n4;
 add[5] = n3 + n4;

 sub1[0] = n1 - n2;
 sub1[1] = n1 - n3;
 sub1[2] = n1 - n4;
 sub1[3] = n2 - n3;
 sub1[4] = n2 - n4;
 sub1[5] = n3 - n4;
 sub1[5] = n3 + n4;

 sub2[0] = n2 - n1;
 sub2[1] = n3 - n1;
 sub2[2] = n4 - n1;
 sub2[3] = n3 - n2;
 sub2[4] = n4 - n2;
 sub2[5] = n4 - n3;

 mul[0] = n2 * n1;
 mul[1] = n3 * n1;
 mul[2] = n4 * n1;
 mul[3] = n3 * n2;
 mul[4] = n4 * n2;
 mul[5] = n4 * n3;

 div1[0] = n1 / n2;
 div1[1] = n1 / n3;
 div1[2] = n1 / n4;
 div1[3] = n2 / n3;
 div1[4] = n2 / n4;
 div1[5] = n3 / n4;

 div2[0] = n2 / n1;
 div2[1] = n3 / n1;
 div2[2] = n4 / n1;
 div2[3] = n3 / n2;
 div2[4] = n4 / n2;
 div2[5] = n4 / n3;

 list.add(add);// 把各种组合加入到list集合中,方便通过循环来遍历每一种组合方式
 list.add(sub1);
 list.add(sub2);
 list.add(mul);
 list.add(div1);
 list.add(div2);
 }

 public void getData() {
 Random r = new Random();
 // 获取1——13的的数字的集合
 data[0] = r.nextInt(12) + 1;
 data[1] = r.nextInt(12) + 1;
 data[2] = r.nextInt(12) + 1;
 data[3] = r.nextInt(12) + 1;
 System.out.print("四个数字为:");
 for (float f : data)
 switch ((int) f) {// 将11,12,13,1变成J,Q,K,A
 case 1:
 System.out.print("A" + " ");
 break;
 case 11:
 System.out.print("J" + " ");
 break;
 case 12:
 System.out.print("O" + " ");
 break;
 case 13:
 System.out.print("K" + " ");
 break;
 default:
 System.out.print((int) f + " ");
 break;
 }
 System.out.println();
 boolean flag = false;// 通过该变量去判断是否存在表达式
 conbine(data[0], data[1], data[2], data[3]);
 for (int a = 0; a < 3; a++) {// 有种组合方式,分别遍历每一种组合方法
 for (int b = 0; b < 6; b++) {// 穷举每一个组合和他们之间的运算
 for (int c = 0; c < 6; c++) {// 判断每一种组合的每一种运算结果是否等于24
 if ((list.get(b)[a] + list.get(c)[5 - a]) == 24) {
 DataFormat.judge(a, b, c, data, "+", set);
 flag = true;
 }
 // 减法
 if ((list.get(b)[a] - list.get(c)[5 - a]) == 24) {
 DataFormat.judge(a, b, c, data, "-", set);
 }
 if ((list.get(b)[5 - a] - list.get(c)[a]) == 24) {
 DataFormat.judge(a, b, c, data, "-", set);
 flag = true;
 }
 // 乘法
 if ((list.get(b)[a] * list.get(c)[5 - a]) == 24) {
 DataFormat.judge(a, b, c, data, "*", set);
 flag = true;
 }
 // 除法
 if ((list.get(b)[a] / list.get(c)[5 - a]) == 24) {
 DataFormat.judge(a, b, c, data, "/", set);
 flag = true;
 }
 if ((list.get(b)[5 - a] / list.get(c)[a]) == 24) {
 DataFormat.judge(a, b, c, data, "/", set);
 flag = true;
 }
 }
 }
 }
 if (!flag)
 System.out.println("没有表达式满足条件");
 }

AutoGame类主要实现由系统给定数值,用户输入表达式来根据结过进行计分,并将分数写入文件

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class AutoGame {
 static boolean flag = true;//该变量标识是否超时
 static int life = 3;//初始化生命值
 static int score=0;//初始化分数

 /**
 *开始游戏的方法,该方法通过当前生命值判断是否结束
 */
 public void start() throws IOException {
 Calendar date = Calendar.getInstance();//实例化Calendar对象
 while(life>0) {//当生命值大于0才会进行
 flag=true;//初始化分数标记
 date.setTime(new Date());
 date.add(Calendar.SECOND, 20);//设置限定时间
 Timer timer = new Timer();
 //当达到限定时间将会执行run()方法,即把全局变量flag变为false
 timer.schedule(new RemindTask(), date.getTime());
 int answer = answer();
 switch(answer) {
 case -1:
 System.out.println("表达式错误!! 当前生命值为"+life+" 分数为:"+score);
 break;
 case -2:
 System.out.println("输入超时!! 当前生命值为"+life+" 分数为:"+score);
 break;
 case -3:
 System.out.println("结果错误!! 当前生命值为"+life+" 分数为:"+score);
 break;
 case 1:
 System.out.println("正确,得到1分奖励!! 当前生命值为"+life+" 分数为:"+score);
 break;
 }
 System.out.println("----------");
 }
 System.out.println("游戏结束……分数为: "+score);//循环结束也就是生命值为0,打印游戏结束
 saveScore(score);//将玩家当前分数存入文件
 return;
 }
/**
 *
 * Title: getData</p>
 * Description:给定任意的数据
 * @return
 */
 private float[] getData() {
 float[] data = new float[4];
 Random r = new Random();//随机生成四个数据存入数组中
 data[0] = r.nextInt(12) + 1;
 data[1] = r.nextInt(12) + 1;
 data[2] = r.nextInt(12) + 1;
 data[3] = r.nextInt(12) + 1;
 System.out.print("四个数字为:");
 for (float f : data)
 switch ((int) f) {
 case 1:
 System.out.print("A" + " ");
 break;
 case 11:
 System.out.print("J" + " ");
 break;
 case 12:
 System.out.print("O" + " ");
 break;
 case 13:
 System.out.print("K" + " ");
 break;
 default:
 System.out.print((int) f + " ");
 break;
 }
 System.out.println("请开始作答,时间20秒");
 return data;
 }

 /**
 *
 * Title: answer</p>
 * Description:根据用户输入返回false或true
 * 1.输入不含给定值,返回FALSE
 * 2.输入超时,返回false
 * 3.输入表达式的值不为24,返回false
 * 否则,返回true
 * @return -1代表输入的表达式与系统给出的数字不吻合
 * @return -2代表用户计算结果超时
 * @return -3代表结果错误
 * @return 1代表用户计算正确
 */
 public int answer() {
 Scanner sc = new Scanner(System.in);
 float[] data = getData();//获取给定的数据
 //获取script引擎,调用eval()方法来判断表达式是否正确
 ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
 ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("nashorn");
 String exper = sc.next();
 try {
 String res = String.valueOf(scriptEngine.eval(exper));
 for (int i = 0; i < data.length; i++)
 if (!exper.contains(data[i] + "")) {//输入的表达式不含给定的值
 life--;
 return -1;
 }
 if(!flag) {//判断超时
 life--;
 return -2;
 }
 if (res.equals("24")) {//回答正確并且没有超时
 score++;//分数加一
 return 1;
 }
 life--;
 } catch (ScriptException e) {
 System.out.println("表达式输入不合法");
 }
 return -3;

 }
 /**
 * Title: saveScore</p>
 * Description: 该方法表示将玩家当前分数存入TopList.txt文件
 * @param score 需要存入的分数
 * @throws IOException
 */
 public static void saveScore(int score) throws IOException {
 FileOutputStream fos = new FileOutputStream("e:/TopList.txt");
 BufferedOutputStream bos = new BufferedOutputStream(fos);
 bos.write((score+"").getBytes());//把分数写入文件
 bos.close();

 }
 public static void main(String[] args) throws IOException {
 saveScore(1);
 }
}
/**
 *
* Title: RemindTask
* Description:该TimerTask并且重写run()可以实现在指定的定时时间执行run方法的内容
* @author jianglei
 */
class RemindTask extends TimerTask {

 @Override
 public void run() {
 AutoGame.flag = false;//当超时会把全局变量flag变为false
 }

}

DataFormat类根据a b c是三个循环变量将两个组合数字的运算格式化成四个数字的表达式

由于代码比较长,在这里只留一种情况的,其余的情况与它类似

import java.util.Set;
/**
 *
* Title: GetFoamat
* Description: 该类通过在循环中的a b c的值判断出当前所参与运算的值与参加运算的符号,假设四个值为n0,n1,n2,n3
* 形参 a、b、c为循环变量,形参n数组为参与运算的四个数字,形参op表示当前进行的运算类型,形参set为存储结果的容器

 */
public class DataFormat {
 public static void judge(int a,int b,int c,float[]n,String op,Set<String> set) {
 StringBuilder sb = new StringBuilder();
 if(a==0) {//n0和n1 与n2和n3之间的运算
 if(b==0) {//n0+n1
 if(c==0) {//n2+n3
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("+").append(n[3]).append(")").append("=24");
 }if(c==1) {//n2-n3
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("-").append(n[3]).append(")").append("=24");
 }if(c==2) {//n3-n2
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[3]).append("-").append(n[2]).append(")").append("=24");
 }if(c==3) {// n2*n3
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("*").append(n[3]).append(")").append("=24");
 }if(c==4) {// n2/n3
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[2]).append("/").append(n[3]).append(")").append("=24");
 }if(c==5) {// n3/n2
 sb.append("(").append(n[0]).append("+").append(n[1]).append(")").append(op).append("(").append(n[3]).append("/").append(n[2]).append(")").append("=24");
 }
 //将运算表达式存入容器
 set.add(sb.toString());
 //将sb清空
 sb = new StringBuilder();
 }if(b==1) {//n0-n1
 //由于这种代码篇幅比较长,在这里省略了,思路和上面的一致
 }

测试

import java.io.IOException;
import java.util.Scanner;

public class Test {
 public static void main(String[] args) throws IOException {
 Scanner sc = new Scanner(System.in);
 Game t = new Game();
 System.out.println("----------");
 System.out.println("1.随机生成数判断");
 System.out.println("2.用户输入运算式");
 System.out.println("请选择");
 char op = sc.next().charAt(0);
 switch (op) {
 case '1':
 t.getData();
 for (String str : t.set) {
 System.out.println(str.replaceAll(".0", ""));
 }
 break;
 case '2':
 AutoGame a = new AutoGame();
 a.start();
 break;
 default:
 System.out.println("输入错误");
 }
 }
}

运行结果

以下用户输入表达式的运行结果

测试过程中在该情况下的测试数据是由自己给出的为1 1 12 12这四个数字

分数存入文件

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java实现Flappy Bird游戏源码

    本文实例为大家分享了Java实现Flappy Bird游戏的具体代码,供大家参考,具体内容如下 1.首先在mainActivity.xml中放置一个View,ID为viewDraw 2.开始编程,程序中自定义一个View类的子类,与viewDraw关联,程序除了放置如一个view控件,没有其他控件,程序上面的所有图片都是通过控制canvas画图实现 3.游戏是依据flappybird的游戏过程重新写的算法,功能与原版游戏相似,可能有些地方不足,完全是学习练习编程而已,做的不好见谅 4.原图片大小

  • java实现猜拳游戏

    本文实例为大家分享了java实现猜拳游戏的具体代码,供大家参考,具体内容如下 package com.farsight.session7; import java.util.Scanner; /** * 根据输入的数字,判断数组strs的值 然后进行逻辑判断 */ public class 猜拳 { public static void main(String[] args) { String[] strs = { "石头", "剪刀", "布"

  • Java版AI五子棋游戏

    本文实例为大家分享了java五子棋游戏的具体代码,供大家参考,具体内容如下 AI思路:通过判断棋盘上每个空位的分数,去分数最高的几个点,随机下棋 分数计算思路:能成5个说明能赢了,给最高分 不能成5个,对方能成5个,说明对方要赢了,给第二高分 能成活4,给第三高分 能成活3,给第四高分 能成冲4,给第五高分 能成冲3,给第六高分 能成活2,给第七高分 能成冲2,给第八高分 其他,给最低分 分数设定可自己定义. 因为是去年写的了,思路记得大概就是这样.最近根据书上写了个棋类游戏的设计框架,待完善后

  • java实现斗地主游戏

    感想: 第一次写博客,感觉编辑器挺复杂厉害的,感觉自己的内容挺简单的.有什么问题请多多指教! 思路: 1.创建一个扑克牌的实体类Poker,设置了四个参数:花色.数字.牌值(判断大小).是否地主牌,实现getset方法和构造方法: 2.创建一个玩家的实体类Player,设置了四个参数: 初始牌集合,排序后牌集合,牌值集合,是否地主,实现getset方法和构造方法: 3.洗牌:循环嵌套花色数组跟数字数组生成52个Poker,手动加入大小王Poker,放进map(int,Poker)里面,利用Col

  • java实现flappy Bird小游戏

    本文实例为大家分享了java实现flappy Bird游戏的具体代码,供大家参考,具体内容如下 整个游戏由3个类构成.Bird类,Pipe类,stage类 第一步:首先写一个Bird类 //鸟类 public class Bird { private int flyHeight;//飞行高度 private int xpos;//距离y轴(窗口左边缘)的位置, public static int Up=1;//向上飞 public static int Down=-1;//向下飞 public

  • Java实现的打地鼠小游戏完整示例【附源码下载】

    本文实例讲述了Java实现的打地鼠小游戏.分享给大家供大家参考,具体如下: 这里涉及到java线程和GUI的相关知识,一个简单的java小游戏打地鼠,有兴趣的朋友可以优化一下.先来看看运行效果: 具体代码: Mouse.java: import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt

  • java实现简单扫雷小游戏

    本文实例为大家分享了java实现扫雷游戏的具体代码,供大家参考,具体内容如下 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.GridLayout; import java.awt.Insets; import java.awt.Label; import java.awt.event.ActionEvent; import java.awt.event

  • java连连看游戏菜单设计

    本文实例为大家分享了java连连看游戏菜单的具体实现代码,供大家参考,具体内容如下 先写GUI. 首先初始化框架,菜单,按钮,需要把菜单和按钮都添加在框架中.注意添加的顺序,首先要设置菜单,再设置框架,再设置按钮,如果交换了设置菜单和框架的顺序,会导致菜单显示不出,被框架挡住.对菜单设置了三个选项,第一个选项有五个下拉按键,用循环添加,第二个和第三个选项的下拉按键直接添加. GUI代码如下: package gui; import java.awt.Font; import javax.swin

  • Java Swing实现扫雷小游戏

    swing设计扫雷心得,供大家参考,具体内容如下 最近学习swing学习之余做了一个小游戏:扫雷 1.前期设计 2.实现 其实完成这个游戏的核心就在于对数组的操纵,下面贴主要代码Main.java: package first; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GridLayout; import java.awt.Image; import java.

  • 小伙熬夜用Java重现经典超级马里奥代码实例

    说起Java,很多人都想问,Java这么火但是Java能干什么呢?Java主要是做企业级的应用开发,其实Java还可以做游戏开发,Java不仅开发过电脑端的游戏,手游也有开发过,经典的游戏有很多,比如<我的世界>.<吃豆>等等,今天小编来分享一个用Java开发超级马里奥. 游戏界面展示: 游戏代码如下: 以上所述是小编给大家介绍的Java重现经典超级马里奥详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的.在此也非常感谢大家对我们网站的支持!

随机推荐