提前bb:採用的ide是vc++ 6.0 ,並且是通過24點遊戲.cpp包含Judge.h、compute.h、menu.h3個文件
一、題目分析
24點遊戲是經典的紙牌益智遊戲。
遊戲規則:
從撲克中每次取出4張牌。使用加減乘除,第一個能得出24者爲贏。(其中,J代表11,Q代表12,K代表13,A代表1),按照要求編程解決24點遊戲。
要求(全部實現):
1.隨機生成4個代表撲克牌牌面的數字字母,程序自動列出所有可能算出24的表達式。
2.程序風格良好(使用自定義註釋模板)。
3.列出表達式無重複。
4.用戶初始生命值爲一給定值(比如3),初始分數44 CC爲0。隨機生成4個代表撲克牌牌面的數字或字母,由用戶輸入包含這4 個數字或字母的運算表達式(可包含括號),如果表達式計算結果爲24則代表用戶贏了此局。
5.使用計時器要求用戶在規定時間內輸入表達式,如果規定時間內運算正確則加分,超時或運算錯誤則進入下一題並減少生命值(不扣分)。
6.所有成績均可記錄在TopList.txt文件中。
二、算法分析
難難點在於表達式的計算,其實就是後綴表達式的計算~具體過程可見代碼或者其他教程。
計時可以用time_t類型的變量,設定一個time_begin,然後用當前已運行的時間減去起始時間,超過規定的時間則執行其他操作(此處我設定的是3s,覺得時間短了的可以改)。
三、流程圖
四、代碼實現
【24點遊戲.cpp】
//版本:1.1
//主要功能:系統隨機生成四個數字,遊戲玩家輸入由四個數字組成的四則運算表達式,使計算結果得24
//系統會檢查玩家輸入的四則運算表達式是否正確。並給出提示。同時系統會給出所有的表達式使得這四個
//數字的運算結果爲24
#include<iostream>
#include"menu.h"
#include"compute.h"
#include"Judge.h"
#include<math.h>
using namespace std;
int main()
{
int option;
int flag;
char a;
Menu();
do
{
cout<<"請輸入你的選項:";
cin>>option;
if(option>=1&&option<=3)
{
flag=1;
break;
}
else
{
flag=0;
cout<<"你的輸入有誤,請重新輸入!"<<endl;
}
}while(flag==0);
while(flag==1)
{
switch(option)
{
case 1: Compute();JudgeAnswer();lefts();break;
case 2: GameRule(); break;
case 3: exit(0); break;
default: break;
}
cout<<"是否要繼續(y or n):";
cin>>a;
if(a=='y')
{
flag=1;
system("cls");
Menu();
cout<<"請輸入你的選項:";
cin>>option;
}
else
exit(0);
}
}
【Judge.h】
//Judge.h
//中綴表達式的計算
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <conio.h>
#include <fstream>
#define SIZE 40
#define MaxSize 32
using namespace std;
int life=3; //生命值
int point=0; //得分
//定義結點,存放字符
struct node
{
char *base;
char *top; //頭指針
int size;
}m;
//數值結點定義
struct list
{
float *base;
float *top;
int size;
}n;
//將數值放入棧中的算法
void ValuePush(list& S,float e)
{
*S.top++=e;
}
//將運算符放入棧中
void CharPush(node& S,char e)
{
*S.top++=e;
}
//數值出棧
float ValuePop(list& S)
{
if(S.base==S.top) cout<<"整數棧爲空,不能輸出";
float x= *(--S.top);
return x;
}
//字符出棧
char CharPop(node& S)
{
if(S.base==S.top) cout<<"字符棧爲空,不能輸出";
char x= *(--S.top);
return x;
}
//初始化字符棧
void InitCharStack(node& S)
{
S.base=(char *)malloc(SIZE *sizeof(char)); //建立一個節
if(!S.base)
{
cout<<"errer abc"<<endl;
exit(1);
}
S.top=S.base;
S.size=20;
}
//初始化數值棧
void InitValueStack(list& S)
{
S.base=(float *)malloc(SIZE *sizeof(float)); //建立一個節點
if(!S.base)
{
cout<<"errer efg"<<endl;
exit(1);
}
S.top=S.base;
S.size=20;
}
//解決比較優先級的時候如何處理運算符的值的大小,進而進入下一步的運算
int Prior(char c)
{
//cout<<"要求棧內優先數的字符爲"<<c<<endl;
int r;
switch(c)
{
case ';':r=0;break;
case '(':r=1;break;
case '*':
case '/':r=5;break;
case '+':
case '-':r=3;break;
case ')':r=8;break;
default:cout<<"errer asdf"<<endl;
}
return r;
}
int Prior2(char c)
{
int w;
//cout<<"要求棧內優先數的字符爲"<<c<<endl;
switch(c)
{
case ';':w=0;break;
case '(':w=8;break;
case '*':
case '/':w=4;break;
case '+':
case '-':w=2;break;
case ')':w=1;break;
default:cout<<"errer sfd"<<endl;
}
return w;
}
float Compute(char* str)
{
int i=0;
float x;
CharPush(m,';'); //初始化字符棧,中只有一個元素';',整數棧爲空棧
while(str[i]&&i<SIZE-1) //處理中綴表達式循環
{
x=0;
if(str[i]==' ')
{
i++;
continue;
}
while(str[i]>=48&&str[i]<=57) //1到10的ASCII碼值
{
x=x*10+str[i]-48; //從屏幕上獲取的都是以字符的形式展現出來的,所以要ASCILL碼值都要減去48 ,這樣才能輸入多位數
i++;
}
if(x!=0) ValuePush(n,x); //如果x的值不等於 0那麼就進整數棧
else
{
int a=Prior2(str[i]); //處理棧外字符
int b=Prior(*(m.top-1)); //處理棧內字符,成員變量是字符棧中的棧頂元素
if(a>b) //棧外運算符優先級高於棧內運算符優先級
{
CharPush(m,str[i]);i++;} //將其插入到字符棧中
else
switch(CharPop(m)) //優先級相反,括號裏面的參數變量是字符棧內的首元素
{
case '+':x=ValuePop(n)+ValuePop(n); //從整數棧中拋出兩個數值,進行以上的運算
ValuePush(n,x); break;
case '-':x=ValuePop(n);
x=ValuePop(n)-x;
ValuePush(n,x);break;
case '*':x=ValuePop(n)*ValuePop(n);
ValuePush(n,x);break;
case '/':x=ValuePop(n);
if(x!=0.0)
{
x=ValuePop(n)/x;
ValuePush(n,x);
}
else {cout<<"零不能做除數"<<endl;i=SIZE-1;}
break;
case '(':i++;break;
case ';':i=SIZE-1;break;
default:cout<<"====輸入有誤===="<<endl;
}
}
}
x=ValuePop(n);
return x;
}
void JudgeAnswer()
{
ofstream f;
f.open("TopList.txt",ios::app);
if(!f){
cout<<"打開文件失敗!"<<endl;
exit(0);
}
char str[32];
char a[SIZE];
InitCharStack(m); //字符棧初始化
InitValueStack(n); //數值棧初始化
f<<"-------------------"<<endl;
f<<"這是新的一輪的記錄"<<endl;
cout<<"輸入24點表達式,以;結束:"<<endl;
cout<<"你一共有三秒的時間思考,超過時間視爲失敗"<<endl;
time_t timeBegin=time(0);
int n=0;
float z=0;
while(true){
if(kbhit()){
cin>>str;
z=Compute(str);
break;
}
//輸出倒計時
else if(time(0)-timeBegin>=3){
cout<<"時間到!你沒有輸入表達式!"<<endl;
n=0;
break;
}
}
cout<<"你的表達式的結果爲:"<<z<<endl;
if(24==(int)z)
{
point++;
f<<"當前得分爲:"<<point<<endl;
cout<<"你的回答是正確的!"<<endl;
cout<<"目前你的分數爲:"<<point<<endl;
cout<<"目前你的生命值爲:"<<life<<endl;
}
else
{
life--;
cout<<"你的回答是錯誤的!"<<endl;
f<<"當前得分爲:"<<point<<endl;
cout<<"目前你的分數爲:"<<point<<endl;
cout<<"目前你的生命值爲:"<<life<<endl;
if(life==0)
{
f<<"-------------------"<<endl;
f.close;
cout<<"沒有生命值!遊戲結束!"<<endl;
exit(0);
}
}
}
【compute.h】
//compute.h 計算24點的表達式
#include<iostream>
#include<string>
#include<time.h>
#include<math.h>
const double LING = 1E-6;
const int VALUE=24;
const int COUNT=4;
double number[COUNT];
string expression[COUNT];
string ShowAnswers[50];
int FINDNUM=0;
bool Judge=false;
int NUM=0;
using namespace std;
void Find(int n) //n爲運算數的個數,當n爲1時,達到遞歸的終止條件,此時第一位保存的就是運算結果
{
if(n==1) //n爲1時,給出相應的處理
{
if(fabs(number[0]-VALUE)<=LING) //判斷數值是否是24
{
ShowAnswers[FINDNUM]=expression[0];
Judge=true; //結果標識
NUM++;FINDNUM++;
}
}
for(int i=0;i<n;i++) //遞歸循環開始,使用窮盡的方法
{
for(int j=i+1;j<n;j++)
{
double a,b;
string expressiona,expressionb;//表示計算的表達式
a=number[i]; //把兩個隨機數賦給a和b,隨機數放在了數組中
b=number[j];
number[j]=number[n-1];//將後面的數轉移到選中的數,此時數組中的值的數量在減少
expressiona=expression[i];
expressionb=expression[j];
expression[j]=expression[n-1];
//對取出的數分別做+ - * / 運算,並將運算結果放入的原數組中,再次進行Find()運算
expression[i]='('+expressiona+'+'+expressionb+')';
number[i]=a+b;
Find(n-1);
expression[i]='('+expressiona+'-'+expressionb+')';
number[i]=a-b;
Find(n-1);
expression[i]='('+expressionb+'-'+expressiona+')';
number[i]=b-a;
Find(n-1);
expression[i]='('+expressiona+'*'+expressionb+')';
number[i]=a*b;
Find(n-1);
//討論除數爲0的狀況
if(b!=0)
{
expression[i]='('+expressiona+'/'+expressionb+')';
number[i]=a/b;
Find(n-1);
}
if(a!=0)
{
expression[i]='('+expressionb+'/'+expressiona+')';
number[i]=b/a;
Find(n-1);
}
number[i]=a;
number[j]=b;
expression[i]=expressiona;
expression[j]=expressionb;
}
}
}
void Compute()
{
srand(time(0));
for(int i=0;i<COUNT;i++)
{
char ch[20];
number[i]=rand()%13+1;
itoa(number[i],ch,10);
expression[i]=ch;
}
cout<<"系統自動爲你生成的遊戲數字是:"<<endl;
for(int j=0;j<COUNT;j++)
{
if(number[j]==1) cout<<"A"<<" ";
else if(number[j]==11) cout<<"J"<<" ";
else if(number[j]==12) cout<<"Q"<<" ";
else if(number[j]==13) cout<<"K"<<" ";
else cout<<number[j]<<" ";
}
cout<<endl;
}
void lefts()
{
char a;
cout<<"是否想看見全部解答?(y or n):";
cin>>a;
Find(COUNT);
if(a=='y')
{
if(Judge==true)
{
cout<<"\n以下是全部可能:"<<endl;
cout<<"總共的方法有:"<<NUM<<endl;
for(int i=0;i<NUM;i++)
{
cout<<ShowAnswers[i]<<endl;
}
}
else
cout<<"抱歉,該組數字無正確的解!"<<endl;
}
else
{};
}
【menu.h】
//Menu.h
#include<iostream>
using namespace std;
void Menu(void)
{
cout<<"**********歡迎使用24點遊戲程序**********\n";
cout<<" 1.開始遊戲\n";
cout<<" 2.遊戲規則\n";
cout<<" 3.退出遊戲\n";
cout<<"****************************************\n";
}
void GameRule()
{
cout<<"遊戲說明如下:"<<endl;
cout<<" 24點遊戲是一種使用撲克牌來進行的益智類遊戲,"<<endl;
cout<<"由於本程序在控制檯下完成,故使用具體的數字代替撲"<<endl;
cout<<"克牌.遊戲內容是:從一副撲克牌中抽去大小王剩下52張"<<endl;
cout<<",任意抽取4張牌,把牌面上的數(A代表1)運用加、減"<<endl;
cout<<"、乘、除和括號進行運算得出24。每張牌都必須使用一"<<endl;
cout<<"次,但不能重複使用。"<<endl;
}
五、運行結果
(調試截圖略)
六、經驗歸納
通過編寫程序發現我在編程過程中細心程度不夠,會出現小錯誤,在以後的學習過程中應該養成好的編程習慣。還有從最初的一個簡單的程序,通過自己的努力慢慢調試完善修改,得到最後成果,雖然還有不足,但是這個過程我享受到了收穫的感覺,是喜悅的。還有自己的知識還欠缺太多,希望自己加油努力學習更多的知識。