一、题目分析
从扑克中每次取出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文件中。
二、关键算法构造
三、程序实现
#include<iostream>
#include<iomanip>
#include<cstdlib>
#include <stdlib.h>
#include <stdio.h>
#include<ctime>
#include <string>
#include <stack>
#include <fstream>
using namespace std;
int allnumber[13] = { 1,2,3,4,5,6,7,8,9,10,11,12,13 };
int score=0;
double result;
char card[] = { 'A','2','3','4','5','6','7','8','9','10','J','Q','K' };
char pai[4] = {'@','@','@','@'};//对牌初始化
double nums[4];
char ope[4] = { '+','-','*','/' };
void GetCards(int a[])
{
for(int i = 0; i < 4; i++) {
pai[i] = '@';
}
while(pai[0]=='0'||pai[0]=='@'||pai[1]=='0'||pai[1]=='@'||pai[2]=='0'||pai[2]=='@'||pai[3]=='0'||pai[3]=='@')//若牌没有输入,则重新输入
{
int i=0;
int j;
for (i = 0; i<4; i++)
{
j =a[i];
pai[i] = card[j];
}
for (i = 0; i<4; i++)
{
if (pai[i] == 'A') nums[i] = 1;
if (pai[i] == '2') nums[i] = 2;
if (pai[i] == '3') nums[i] = 3;
if (pai[i] == '4') nums[i] = 4;
if (pai[i] == '5') nums[i] = 5;
if (pai[i] == '6') nums[i] = 6;
if (pai[i] == '7') nums[i] = 7;
if (pai[i] == '8') nums[i] = 8;
if (pai[i] == '9') nums[i] = 9;
if (pai[i] == '10') nums[i] = 10;
if (pai[i] == 'J') nums[i] = 11;
if (pai[i] == 'Q') nums[i] = 12;
if (pai[i] == 'K') nums[i] = 13;
}
}
cout<<" 随机获得的4张牌为"<<pai[0]<<","<<pai[1]<<","<<pai[2]<<","<<pai[3]<<","<<endl;
}
double calculate(double a,double b,char op)
{
if(op == '+') return a + b;
if(op == '-') return a - b;
if(op == '*') return a * b;
if((op == '/')&&(b != 0)) return a/b;
}
void qiongju()
{
double temp[3], tem[2]; //第一个符号放置后,经过计算后相当于剩下三个数,这个数组用于存储这三个数
double sum; //求得的和
int judge = 0; //判断是否找到一个合理的解
for (int i = 0; i < 4; i++) //第一次放置的符号
{
for (int j = 0; j < 4; j++) //第二次放置的符号
{
for (int k = 0; k < 4; k++) //第三次放置的符号
{
for (int m = 0; m < 3; m++) //首先计算的两个相邻数字,共有3种情况,相当于括号的作用
{
if (nums[m + 1] == 0 && ope[i] == '/') break;
temp[m] = calculate(nums[m], nums[m + 1], ope[i]);
temp[(m + 1) % 3] = nums[(m + 2) % 4];
temp[(m + 2) % 3] = nums[(m + 3) % 4]; //先确定首先计算的两个数字,计算完成相当于剩下三个数,按顺序储存在temp数组中
for (int n = 0; n < 2; n++) //三个数字选出先计算的两个相邻数字,两种情况,相当于第二个括号
{
if (temp[n + 1] == 0 && ope[j] == '/') break;
tem[n] = calculate(temp[n], temp[n + 1], ope[j]);
tem[(n + 1) % 2] = temp[(n + 2) % 3]; //先确定首先计算的两个数字,计算完成相当于剩下两个数,按顺序储存在temp数组中
if (tem[1] == 0 && ope[k] == '/') break;
sum = calculate(tem[0], tem[1], ope[k]); //计算和
if (sum == 24) //若和为24
{
judge = 1; //判断符为1,表示已求得解
if (m == 0 && n == 0)
cout << "((" << nums[0] << ope[i] << nums[1] << ")" << ope[j] << nums[2] << ")" << ope[k] << nums[3] << "=" << sum << endl;
else if (m == 0 && n == 1)
cout << "(" << nums[0] << ope[i] << nums[1] << ")" << ope[k] << "(" << nums[2] << ope[j] << nums[3] << ")=" << sum << endl;
else if (m == 1 && n == 0)
cout << "(" << nums[0] << ope[j] << "(" << nums[1] << ope[i] << nums[2] << ")" << ope[k] << nums[3] << "=" << sum << endl;
else if (m == 1 && n == 1)
cout << nums[0] << ope[k] << "((" << nums[1] << ope[i] << nums[2] << ")" << ope[j] << nums[3] << ")=" << sum << endl;
else if (m == 2 && n == 0)
cout << "(" << nums[0] << ope[j] << nums[1] << ")" << ope[k] << "(" << nums[2] << ope[i] << nums[3] << ")=" << sum << endl;
else if (m == 2 && n == 0)
cout << nums[0] << ope[k] << "(" << nums[1] << ope[j] << "(" << nums[2] << ope[i] << nums[3] << "))=" << sum << endl; //m=0,1,2 n=0,1表示六种括号放置可能,并按照这六种可能输出相应的格式的计算式
}
}
}
}
}
}
if (judge == 0)
cout << " 这四张扑克牌无法找到一个合理的解" << endl; //如果没有找到结果,符号位为0
}
bool isone(char c){
return (c=='+' || c=='-');
}
bool istwo(char c){
return (c=='*' || c=='/');
}
string shorten(string m){
stack<char> s;
string sur;
int i;
char w;
sur;
for(i=0;i<m.size();i++){
if(isdigit(m[i]) || m[i]=='.'){
while(isdigit(m[i]) || m[i]=='.') sur += m[i++];
i--;
sur += '$';
}
else if(isone(m[i])){
while(s.size() && (isone(s.top()) || istwo(s.top()))){
sur+=s.top();
s.pop();
}
s.push(m[i]);
}
else if(m[i]==')'){
while(s.top()!='('){
sur+=s.top();
s.pop();
}
s.pop();
}
else if(istwo(m[i])){
while(s.size() && istwo(s.top())){
sur+=s.top();
s.pop();
}
s.push(m[i]);
}
else s.push(m[i]);
}
while(s.size()){
sur+=s.top();
s.pop();
}
return sur;
}
double tentimes(int n){
double res=1;
for(int i=0;i<n;i++){
res *= 10;
}
return res;
}
double str2double(string s){
double res=0;
char c;
int dec=0;
for(int i=1;i<=s.size();i++){
c=s[i-1];
if(c=='.') dec=i;
else if(!dec) res = res*10 + c-'0';
else res += (c-'0')/tentimes(i-dec);
}
return res;
}
//计算输入的表达式
double calculate(string s){
double res, t;
stack<double> num;
string temp;
int i;
for(i=0;i<s.size();i++){
temp="";
if(isdigit(s[i]) || s[i]=='.'){
while(isdigit(s[i]) || s[i]=='.') temp+=s[i++]; //如果最后一位是数字,这样做会出错
num.push(str2double(temp));
}
else{
switch (s[i]){
case '+': t=num.top(); num.pop(); t+=num.top();num.pop();num.push(t);break;
case '-': t=num.top(); num.pop(); t=num.top()-t;num.pop();num.push(t);break;
case '*': t=num.top(); num.pop(); t*=num.top();num.pop();num.push(t);break;
case '/': t=num.top(); num.pop(); t=num.top()/t;num.pop();num.push(t);break;
default: cerr << "输入表达书有误!" << endl; system("pause");break;
}
}
}
res=num.top();
return res;
}
void jisuan()
{
string mid, sur;
cin >> mid;
sur = shorten(mid);
result = calculate(sur);
}
int main()
{
srand((unsigned)time(0));//获取当前时间作为参数,生可以随时间变化的随机数
time_t begin,end;
double ret;
int choose;
int flag=1;
int life=3;
int arr[4];
//GetCards();
//jisuan();
//qiongju();
cout<<" 24点小游戏"<<endl;
cout<<" *---------------------*"<<endl;
cout<<" 1.开始游戏"<<endl;
cout<<" 2.结束游戏"<<endl;
cout<<" *---------------------*"<<endl;
cout<<" 请输入编号选择功能:";
cin>>choose;
switch(choose)
{
case 1:
{
while(flag)
{
cout<<" **剩余生命值为:"<<life<<endl;
cout<<" **当前所得分数为:"<<score<<endl;
for(int i=0;i<4;i++)
{
arr[i] = rand() % 13 ;
}
begin=clock();//开始计时
GetCards(arr);
jisuan();
end=clock();//结束计时
ret=double(end-begin)/CLOCKS_PER_SEC;
if(ret>60)
{
cout<<" 你已经超过60s了!"<<endl;
life = life - 1;
}
else
{
if(result == 24)
{
cout<<" 计算成功!"<<endl;
score = score + 10;
}
else
{
cout<<" 计算出错!"<<endl;
life = life - 1;
}
}
if(life==0)
{
flag = 0;
cout<<" 你已经用完了所有次数!"<<endl;
}
}
break;
}
case 2:
{
break;
}
default:
{
cout<<"请输入1~3的数字!";
}
}
cout<<" 共计获得分数为:"<<score<<endl;
return 0;
}
四、调试、测试及运行结果
1)计算成功
2)计算失败
3)计算失败至退出
4)超出规定时间
五、经验总结
1、加深了对随机数产生的相关知识,并且了解到了多次生成随机数的方法
2、学习到了对于算术表达式的计算,运用一个运算数栈和一个运算符栈对表达式进行运算得出表达式
3、学习了24点的穷举算法,先将两个随机数组合起来,将四个数转化为三个数,再将三个数转化为两个数,最后求出结果与24比较便可得出结果
4、复习了程序运行时间的相关知识,这次作业将运行时间作为判断条件使用