题目: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文件中。
一、算法设计
基本要求:在程序中随机生成4个1—13的随机数,用他们所代表的纸牌字符显示,然后用递归的方法找出4个数的所有排列,将每一组排列与4种运算符号的3个位置的所有排列组合的结合进行四则运算,得到结果为24就输出一组组合。
提高要求:在程序中随机生成4个1—13的随机数,用他们所代表的纸牌字符显示,输入四则运算,使用字符串转化成中缀表达式,再将中缀表达式转化成后缀表达式,对后缀表达式进行计算,输入过程的计时器可以用获取系统时间,标记输入开始和结束时间,对结果和输入时间进行判断,将成绩保存,循环以上过程,根据生命值判断结束。
二、算法设计
基本要求
class Cardcreate{
static String[] card={
"A","2","3","4","5","6","7","8","9","10","J","Q","K"
};
static char[] m= {'+','-','*','/'};
static int[] num=new int[4]; //随机数数组
static int count=0; //保存解法的个数
static int flag=0; //保存随机数排列的组数
void create() { //获取4个随机数
for(int i=0;i<4;i++) {
num[i]=(int)(1+Math.random()*(13-1+1));
System.out.print(card[num[i]-1]+" ");
}
}
public void sq(int k) { //对随机数进行递归全排列
if (k == num.length) {
flag++;
printResult(); //得到一组数的排列输出
}
for (int i = k; i < num.length; i++) {
{
int temp = num[k];
num[k] = num[i];
num[i] = temp;
}
sq(k + 1);
{
int temp = num[k];
num[k] = num[i];
num[i] = temp;
}
}
}
void printResult(){
char[] oper=new char[3];
int i,j,k;
for(i=0;i<4;i++) //对4种运算符的3个位置排列
for(j=0;j<4;j++)
for(k=0;k<4;k++){
oper[0]=m[i];
oper[1]=m[j];
oper[2]=m[k];
if(getResult(oper))
count++; //正确就计数一次
}
if(flag==24){
if(count!=0){
System.out.println("共"+count+"种解法");
}
else{
System.out.println("该情况无解\n");
}
}
}
boolean getResult(char oper[]) {
int a=num[0];
int b=num[1];
int c=num[2];
int d=num[3];
double t;
//穷举运算次序
//1.((A*B)*C)*D
t=0;
t=getValue(a,b,oper[0]);
t=getValue(t,c,oper[1]);
t=getValue(t,d,oper[2]);
if(Math.abs(t-24)<0.0001){
printAnswer(1,oper);
return true;
}
//2.(A*(B*C))*D
t=0;
t=getValue(b,c,oper[1]);
t=getValue(a,t,oper[0]);
t=getValue(t,d,oper[2]);
if(Math.abs(t-24)<0.0001){
printAnswer(2,oper);
return true;
}
//3.(A*B)*(C*D)
t=0;
t=getValue(getValue(a,b,oper[0]),getValue(c,d,oper[2]),oper[1]);
if(Math.abs(t-24)<0.0001) {
printAnswer(3,oper);
return true;
}
//4.A*(B*(C*D))
t=0;
t=getValue(c,d,oper[2]);
t=getValue(b,t,oper[1]);
t=getValue(a,t,oper[0]);
if(Math.abs(t-24)<0.0001){
printAnswer(4,oper);
return true;
}
//5.A*((B*C)*D)
t=0;
t=getValue(b,c,oper[1]);
t=getValue(t,d,oper[2]);
t=getValue(a,t,oper[0]);
if(Math.abs(t-24)<0.0001){
printAnswer(5,oper);
return true;
}
return false;
}
double getValue(double num1, double num2, char o) {
double result = 0;
switch(o){
case '+':
result=num1+num2;
break;
case '-':
result=num1-num2;
break;
case '*':
result=num1*num2;
break;
case '/':
result=num1/num2;
break;
default :
break;
}
return result;
}
void printAnswer(int flag,char oper[]){
String a=card[num[0]-1];
String b=card[num[1]-1];
String c=card[num[2]-1];
String d=card[num[3]-1];
switch(flag)
{
//1.((A*B)*C)*D
case 1:
System.out.println("(("+a+oper[0]+b+")"+oper[1]+c+")"+oper[2]+d);
break;
//2.(A*(B*C))*D
case 2:
System.out.println("("+a+oper[0]+"("+b+oper[1]+c+"))"+oper[2]+d);
break;
//3.(A*B)*(C*D)
case 3:
System.out.println("("+a+oper[0]+b+")"+oper[1]+"("+c+oper[2]+d+")");
break;
//4.A*(B*(C*D))
case 4:
System.out.println(a+oper[0]+"("+b+oper[1]+"("+c+oper[2]+d+"))");
break;
//5.A*((B*C)*D)
case 5:
System.out.println(a+oper[0]+"(("+b+oper[1]+c+")"+oper[2]+d+")");
break;
default:
break;
}
}
}
public class Card {
public static void main(String[] args) {
System.out.println("24点游戏");
System.out.println("随机生成纸牌:");
Cardcreate c=new Cardcreate();
c.create();
System.out.println("\n结果:");
c.sq(0);
}
}
提高要求
import java.io.*;
import java.util.*;
class LT {
String[] card={
"A","2","3","4","5","6","7","8","9","10","J","Q","K"
};
char[] op = {'+','-','*','/','(',')'};
String[] strOp = {"+","-","*","/","(",")"};
int[] num=new int[4];
int count=0;
int strength=3;
int score=0;
/**
* 生成随机纸牌
*/
void create() {
for(int i=0;i<4;i++) {
num[i]=(int)(1+Math.random()*(13-1+1));
System.out.print(card[num[i]-1]+" ");
}
}
boolean isNum(char c){
if(c>='0'&&c<='9'){
return true;
}
return false;
}
//符号判断重载
boolean isOp(char c){
for(int i=0;i<op.length;i++){
if(op[i]==c){
return true;
}
}
return false;
}
boolean isOp(String s){
for(int i=0;i<strOp.length;i++){
if(strOp[i].equals(s)){
return true;
}
}
return false;
}
/**
* 处理输入的计算式
* @param str
* @return
*/
List<String> work(String str){
List<String> list = new ArrayList<String>();
char c;
StringBuilder sb = new StringBuilder();
for(int i=0;i<str.length();i++){
c = str.charAt(i);
if(isNum(c)){
sb.append(c);
}
if(c=='A') {
list.add("1");
}else if(c=='J'){
list.add("11");
}else if(c=='Q') {
list.add("12");
}else if(c=='K') {
list.add("13");
}
if(isOp(c)){
if(sb.toString().length()>0){
list.add(sb.toString());
sb.delete(0, sb.toString().length());
}
list.add(c+"");
}
}
if(sb.toString().length()>0){
list.add(sb.toString());
sb.delete(0, sb.toString().length());
}
return list;
}
void printList(List<String> list){
for(String o:list){
System.out.print(o+" ");
}
}
/**
* 中缀表达式转化为后缀表达式
* 1,遇到数字输出
* 2,遇到高优先级的全部出栈
* 3,最后全部出栈
*/
List<String> InfixToPostfix(List<String> list){
List<String> Postfixlist = new ArrayList<String>();//存放后缀表达式
Stack<String> stack = new Stack<String>();//暂存操作符
//stack.push('#');
for(int i=0;i<list.size();i++){
String s = list.get(i);
if(s.equals("(")){
stack.push(s);
}else if(s.equals("*")||s.equals("/")){
stack.push(s);
}else if(s.equals("+")||s.equals("-")){
if(!stack.empty()){
while(!(stack.peek().equals("("))){
Postfixlist.add(stack.pop());
if(stack.empty()){
break;
}
}
stack.push(s);
}else{
stack.push(s);
}
}else if(s.equals(")")){
while(!(stack.peek().equals("("))){
Postfixlist.add(stack.pop());
}
stack.pop();
}else{
Postfixlist.add(s);
}
if(i==list.size()-1){
while(!stack.empty()){
Postfixlist.add(stack.pop());
}
}
}
return Postfixlist;
}
/**
* 后缀表达式计算
*/
int doCal(List<String> list){
Stack<Integer> stack = new Stack<Integer>();
for(int i=0;i<list.size();i++){
String s = list.get(i);
int t=0;
if(!isOp(s)){
t = Integer.parseInt(s);
stack.push(t);
}else{
if(s.equals("+")){
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2+a1;
stack.push(v);
}else if(s.equals("-")){
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2-a1;
stack.push(v);
}else if(s.equals("*")){
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2*a1;
stack.push(v);
}else if(s.equals("/")){
int a1 = stack.pop();
int a2 = stack.pop();
int v = a2/a1;
stack.push(v);
}
}
}
return stack.pop();
}
/**
* 保存局数,体力,分数
*/
void save() {
FileWriter result;
try {
result = new FileWriter("TopList.txt",true);
result.write("\r\n"+count+" "+strength+" "+score);
result.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Play {
public static void main(String[] args) {
LT lt = new LT();
System.out.println("24点游戏");
System.out.println("每局限时90秒");
boolean flag=false;
long startTime,endTime,usedTime;
while(!flag) {
System.out.println("---------------");
System.out.println("第"+ ++lt.count +"局");
System.out.println("用户生命值为"+lt.strength);
System.out.println("分数为"+lt.score);
System.out.println("随机生成纸牌:");
lt.create();
startTime = System.currentTimeMillis();//标记开始输入时间
System.out.println("\n请输入你的计算");
Scanner s=new Scanner(System.in);
String str = s.next();
endTime= System.currentTimeMillis();//标记结束输入时间
usedTime = (endTime-startTime)/1000;//用(结束时间-开始时间)/1000,得到秒级时间
System.out.println("用时为:"+usedTime+"秒");
List<String> list = lt.work(str); //将字符串转为中缀表达式
List<String> list2 = lt.InfixToPostfix(list);//中缀表达式转后缀表达式
int result=lt.doCal(list2); //后缀表达式计算结果
System.out.println("计算结果为:"+result);
if(usedTime<=90){
if(24==result) {
System.out.println("成功了");
lt.score++;
}else {
System.out.println("计算错误");
lt.strength--;
}
}else {
System.out.println("超时了");
lt.strength--;
}
lt.save();
if(lt.strength==0) {
flag=true;
System.out.println("游戏结束");
}
}
}
}
三、总结
这次的作业的基本要求采用了穷举法解决,但我没办法解决数据的完全不重复,虽然在显示的时候加上不同的括号位置,但按照正常的运算要求来说,次序和位置的不同也会是重复的,不过也只有这样才能列出所有的解决方法。
而提高要求利用的主要是栈的思想进行运算,Java有专为解决栈问题的方法,在这里运用了以前学到的中缀表达式和后缀表达式,也算是再次复习一遍,当然这次的计算也可以用中缀表达式直接求解来简化。