【C++】24點遊戲

 

       提前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;
}

 

五、運行結果

(調試截圖略)

 

六、經驗歸納

       通過編寫程序發現我在編程過程中細心程度不夠,會出現小錯誤,在以後的學習過程中應該養成好的編程習慣。還有從最初的一個簡單的程序,通過自己的努力慢慢調試完善修改,得到最後成果,雖然還有不足,但是這個過程我享受到了收穫的感覺,是喜悅的。還有自己的知識還欠缺太多,希望自己加油努力學習更多的知識。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章