24点游戏

一、题目描述

用户初始生命值为一给定值(比如3),初始分数为0。随机生成4个代表扑克牌牌面的数字或字母,由用户输入包含这4个数字或字母的运算表达式(可包含括号),如果表达式计算结果为24则代表用户赢了此局。

二、问题分析

题目的难点有两个,一个是对用户输入的带括号的运算式进行计算,一个是计时器控制输入的进行。

三、算法设计

24点游戏

四、代码实现

头文件:

#pragma once
#include<iostream>
#include <stdlib.h>
#include<time.h>
#include<string>
#include<thread>
#include <windows.h>
using namespace std;

class Game {
public:
	int score = 0;
	int hp = 3;
	int a[4];
	string s[4];
	void Game_Start();
	void Generate();
	int culmulate(string);
	void control();
	int flag = 2;
private:
	thread t1;
};

主函数:

int main()
{
	Game g;
	thread t1(&Game::control, &g);//创建线程
	while (g.hp > 0)
	{
		g.flag = 2;
		t1.joinable();//线程开始
		g.Game_Start();
		g.flag = 1;//通过flag这个变量控制计时器线程的运行
	}
	system("pause");
}

函数实现:

void Game::Game_Start()//进行一次猜数
{
	string in;
	Generate();
	cout << "生命值:" << hp << "\t分数:" << score << endl;
	for (int i = 0; i < 4; i++)
		cout << s[i] << '\t';
	cout << "请输入计算式" << endl;
	cin >> in;
	if (in == "00") cout<<"跳过当前的题目"<<endl;
	else if (in == "0");
	else if (culmulate(in) == 24) { cout << culmulate(in); score += 1; cout << "分数+1" << endl; }
	else { cout << culmulate(in); hp--; cout << "生命值-1" << endl; }
}

void Game::Generate()//生成随机数
{
	srand((unsigned)time(NULL));
	for (int i = 0; i < 4; i++)
	{
		a[i] = (rand() % 13) + 1;
		if (a[i] < 10)
			s[i] = a[i] + 48;
		else switch (a[i])
		{
		case 10:s[i] = "10";
		case 11:s[i] = "J";
		case 12:s[i] = "Q";
		case 13:s[i] = "K";
		default:
			break;
		}
	}
}

int Game::culmulate(string s)//计算输入的字符串
{
	int a, b;
	int c = 0, d = 0, e = 0;
	string st = "";
	for (int i = 0; s[i] != '\0'; i++)
	{
		if (s[i] == 40) a = i;
	}
	for (int i = s.length(); i>-1; i--)
	{
		if (s[i] == 41) b = i;
	}
	for (int i = a+1; ; i++)
	{
		if (s[i + 1] < 58 && s[i + 1]>48)    c = (s[i++] - 48) * 10 + s[i++] - 48;
		else c = s[i++] - 48;
		i+=1;
		if (s[i + 1] < 58 && s[i + 1]>48)    d = (s[i] - 48) * 10 + s[i+1] - 48;
		else d = s[i] - 48;
		i--;
		switch (s[i])
		{
		case 43:e = c + d; break;//'+'=43
		case 45:e = c - d; break;//'-'=45
		case 42:e = c * d; break;//'*'=42
		case 47:e = c / d; break;//'/'=47
		default:
			break;
		}
		break;
	}
	for (int i = 0; i < a; i++)
		st += s[i];
	for (;;)
	{
		if(e / 10 == 0)
		{
			st += (e + 48);
			break;
		}
		else
		{
			st += ((e / 10) + 48);
			st += ((e % 10) + 48);
			break;
		}
	}
	for (int i = b+1; i < s.length(); i++)
		st += s[i];
	if (!(a == 0 && b == s.length() - 1))
		e=culmulate(st);
	return e;
}

void Game::control()//计时器
{
	int a;
	while (hp)
	{
		a = 0;
		for (int i = 0; i < 20000; i++)
		{
			Sleep(1);
			if (flag == 1)
			{
				a = 1;
				break;
			}
		}
		if (a == 0)
		{
			hp--;
			while (1)
			{
				while (flag == 1);
				cin.ignore();//清空缓冲区
				cout << "计时结束,生命值-1,现为"<<hp<<"连续输入两个0以继续" << endl;
				cin >> a;//用一个待输入的变量暂停计时器
				flag = 2;
				break;
			}
		}
	}
}

五、调试和运行结果

调试截图:
24点游戏
运行结果:
24点游戏

六、心得总结

线程之间的相互控制较为困难,容易形成复杂的数据关系。想要让一个结束运行的线程在循环之中重新启动似乎也是不可行的。同时,计时器计时结束时,若还在算式输入的过程中,会出现显示的混乱。