24点

一、问题描述:
24点游戏是经典的纸牌益智游戏。
常见游戏规则:
从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求编程解决24点游戏。
基本要求:
随机生成4个代表扑克牌牌面的数字字母,程序自动列出所有可能算出24的表达式,用擅长的语言(C/C++/Java或其他均可)实现程序解决问题。
1.程序风格良好(使用自定义注释模板)
2.列出表达式无重复。
提高要求:
用户初始生命值为一给定值(比如3),初始分数为0。随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。
1. 程序风格良好(使用自定义注释模板)
2.使用计时器要求用户在规定时间内输入表达式,如果规定时间内运算正确则加分,超时或运算错误则进入下一题并减少生命值(不扣分)。
3.所有成绩均可记录在TopList.txt文件中。
二、分析:
对于基本要求,我可以通过random函数来生成随机数;把生成的四个随机数存储在数组中;然后对数组进行全排列;对于每一种排列,分别进行加减乘除运算;看运算的结果是否为24;如果为24直接把式子输出出来。

对于提高要求,我可以设计一个game类来进行游戏,先对用户输入的数据进行检查。用户输入的表达式用java自带的JavaScript引擎去把字符串转换从语句,然后执行,计算出结果。

三、具体设计:
程序流程图:

在这里插入图片描述

代码如下:

package com.lyq.point;

import java.util.Random;

public class Point24 {
   public  int[] cards = new int[4];  //存储四张牌的数组
   public char[] operators = new char[3]; //存放运算操作
   
   public Point24() {            
	   Random rd = new Random();    //随机产生四张牌
	   for(int i=0;i<4;i++) {
	   cards[i]=rd.nextInt(13)+1;
	   }
}
   public void show() {              //显示四张牌
	System.out.println("你有四张牌,他们对应的值为:");
	   for(int i=0;i<4;i++) {
		    System.out.print(cards[i]+" ");
		  
	   }
	   System.out.println("");
	   System.out.println("--------");
}
   
   public  void getOpertors(int[] Num){		  //把操作符放入operators	
		for(int i=0;i<3;i++){			
			int op=Num[i];			
			switch (op) {			
			case 0:				operators[i]='+';				break;		
			case 1:				operators[i]='-';				break;		
			case 2:				operators[i]='*';				break;		
			case 3:				operators[i]='/';				break;		
			default:				break;			
			}		
			}		
		}
   
public void Sort() {                      //对操作数进行全排序
     int[] temp = new int[4];
     for(int i=0;i<4;i++)
     {
    	 temp[i]=cards[i];
     }
     for(int i=0;i<4;i++) {
    	 cards[0]=cards[i];
    	 int j=(i+1)%4;
    	 for(int k=0;k<3;){
    		 if (j!=i) {
				cards[1]=temp[j];
				int e = (j+1)%4;
				for(int h=0;h<2;)
				{
					if (e!=j&&e!=i) {
						cards[2] = temp[e];
						cards[3] = temp[6-i-j-e];
						//System.out.println(cards[0]+" "+cards[1]+" "+cards[2]+" "+cards[3]);
						this.opertor();                     //排序完成后进行运算
						h++;
					}
				e = (e+1)%4;
				}
				k++;
				}
    		 j = (j+1)%4;
    	 }
     }
}
   
	public  void  opertor(){           //对数组中两两相邻元素进行运算
		double sum=0;
		for(int i=0;i<4;i++){			
			double sum1=count(cards[0],cards[1],i);			
			for(int j=0;j<4;j++){				
				double sum2=count(sum1,cards[2],j);				
				for(int k=0;k<4;k++){					
					sum=count(sum2,cards[3],k);					
					int[] symbolNum={i,j,k};		 //记录运算的操作符			
					getOpertors(symbolNum);			 				
					if(sum==24){											
						System.out.println("["+"("+cards[0]+" "+operators[0]+" "+cards[1]+")"+" "+operators[1]+" "+cards[2]+"]"+" "+operators[2]+" "+cards[3]+"==24");				
	
						}
				}
			}
		
		}
	}
	
	//对两个数据进行加减乘除运算
	public static double count(double num1,double num2,int num){	
		double sum=0.0;		
        switch (num) {
		case 0:
		sum = num1+num2;
			break;
		case 1:
		sum = num1-num2;
			break;
		case 2:
		sum = num1*num2;
			break;
		case 3:
		sum = num1/num2;
			break;
		}	
		return sum;	
		}

public void refresh() {
	   Random rd = new Random();    //随机产生四张牌
	   for(int i=0;i<4;i++) {
	   cards[i]=rd.nextInt(13)+1;
	   }
}
   
   //用main函数进行测试
   public static void main(String[] args) {
	 Point24 op  = new Point24();
	 op.show();
	 System.out.println("可以算出24的表达式如下:");
	 op.Sort();

}
}

Game类




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

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

public class Game {
   public int life = 3;
   public  int score = 0;
   
   public Game() {    //构造函数
	// TODO Auto-generated constructor stub
		 Point24 op  = new Point24();         
		 boolean flag = true;
		 while(flag)
		 {
			 System.out.println("当前你的生命值为:"+life+"  ");
			 System.out.println("当前你的分数为:  "+score+"  ");
			 op.show();
			 System.out.println("请输入表达式:(输入时间为一分钟)");
			 String input = null;
			 Scanner sc = new Scanner(System.in);
			 input = sc.nextLine();
			 if(check(input)) {
				 score+=10;
				 System.out.println("答案正确");
			 }else {
				 life--;
				 System.out.println("答案错误");
				 if (life==0) {
					 System.out.println("抱歉,你的生命值已经耗尽");
					 System.out.println("请问是否要存储你本次的分数:y/n");
					 if (sc.nextLine()=="y") {
					       write(score+" ");                    //写入文件
					}
					flag = false;
				}
			 }
			 sc.close();
			 op.refresh();
			 System.out.println("");
			 System.out.println("");
			 System.out.println("");
		 }
}
   
public void write(String str) {             //把分数写入文件
	BufferedWriter bd = null;
	try {
	  bd = new BufferedWriter(new FileWriter("/Student/src/com/lyq/point/TopList.txt"));
	  bd.write(str);
	} catch (IOException e) {
		e.printStackTrace();
	}finally {
		try {
			bd.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
   
public boolean check(String str) {        //判断输入表达式是否正确
	   boolean flag = false;
	   ScriptEngineManager manager = new ScriptEngineManager();
	   ScriptEngine engine = manager.getEngineByName("js");
	   try {
		Object result = engine.eval(str);
		if (result.equals(24)) {             //计算表达式是否等于24
			flag = true;
		}
	} catch (ScriptException e) {
		// TODO Auto-generated catch block
		System.out.println("输入错误");
	}
	 return  flag;
}
   


   public static void main(String[] args) {
	new Game();
}
   
   
   
}

四、调试与结果
在这里插入图片描述

在这里插入图片描述

五、总结
通过这次作业,我知道了如何对数组进行全排列,这是一个不是很简单的过程,我自己写的这个算法十分复杂,有三个for循环嵌套,而且有大量的变量来控制这一个过程。我也了解到还有一些其它算法
递归算法:
这里以A{a,b,c}为例,来说明全排列的生成方法,对于这个集合,其包含3个元素,所有的排列情况有3!=6种,对于每一种排列,其第一个元素有3种选择a,b,c,对于第一个元素为a的排列,其第二个元素有2种选择b,c;第一个元素为b的排列,第二个元素也有2种选择a,c,……,依次类推,我们可以将集合的全排列与一棵多叉树对应;在此树中,每一个从树根到叶子节点的路径,就对应了集合A的一个排列。通过递归算法,可以避免多叉树的构建过程,直接生成集合A的全排列。
字典序:
全排列生成算法的一个重要思路,就是将集合A中的元素的排列,与某种顺序建立一一映射的关系,按照这种顺序,将集合的所有排列全部输出。这种顺序需要保证,既可以输出全部的排列,又不能重复输出某种排列,或者循环输出一部分排列。字典序就是用此种思想输出全排列的一种方式。这里以A{1,2,3,4}来说明用字典序输出全排列的方法。
首先,对于集合A的某种排列所形成的序列,字典序是比较序列大小的一种方式。以A{1,2,3,4}为例,其所形成的排列1234<1243,比较的方法是从前到后依次比较两个序列的对应元素,如果当前位置对应元素相同,则继续比较下一个位置,直到第一个元素不同的位置为止,元素值大的元素在字典序中就大于元素值小的元素。上面的a1[1…4]=1234和a2[1…4]=1243,对于i=1,i=2,两序列的对应元素相等,但是当i=2时,有a1[2]=3<a2[2]=4,所以1234<1243。
使用字典序输出全排列的思路是,首先输出字典序最小的排列,然后输出字典序次小的排列,……,最后输出字典序最大的排列。这里就涉及到一个问题,对于一个已知排列,如何求出其字典序中的下一个排列。这里给出算法。
对于排列a[1…n],找到所有满足a[k]<ak+1的k的最大值,如果这样的k不存在,则说明当前排列已经是a的所有排列中字典序最大者,所有排列输出完毕。
在a[k+1…n]中,寻找满足这样条件的元素l,使得在所有a[l]>a[k]的元素中,a[l]取得最小值。也就是说a[l]>a[k],但是小于所有其他大于a[k]的元素。
交换a[l]与a[k].
对于a[k+1…n],反转该区间内元素的顺序。也就是说a[k+1]与a[n]交换,a[k+2]与a[n-1]交换,……,这样就得到了a[1…n]在字典序中的下一个排列。
这里我们以排列a[1…8]=13876542为例,来解释一下上述算法。首先我们发现,1(38)76542,括号位置是第一处满足a[k]<a[k+1]的位置,此时k=2。所以我们在a[3…8]的区间内寻找比a[2]=3大的最小元素,找到a[7]=4满足条件,交换a[2]和a[7]得到新排列14876532,对于此排列的3~8区间,反转该区间的元素,将a[3]-a[8],a[4]-a[7],a[5]-a[6]分别交换,就得到了13876542字典序的下一个元素14235678。
通过这次作业,我还了解到了,如何在java中运行JavaScript代码的;即通过使用javax.script下的JavaScript引擎,来把字符串转化成JavaScript代码,并运行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值