C++: 24 Game

Bjarne-stroustrup
 

The 24 Game tests one’s mental arithmetic.

Write a program that randomly chooses and displays four digits, each from one to nine, with repetitions allowed. The program should prompt for the player to enter an arithmetic expression using just those, and all of those four digits, used exactly once each. The program should check then evaluate the expression. The goal is for the player to enter an expression that evaluates to 24.

  • Only multiplication, division, addition, and subtraction operators/functions are allowed.
  • Division should use floating point or rational arithmetic, etc, to preserve remainders.
  • Brackets are allowed, if using an infix expression evaluator.
  • Forming multiple digit numbers from the supplied digits is disallowed. (So an answer of 12+12 when given 1, 2, 2, and 1 is wrong).
  • The order of the digits when given does not have to be preserved.

Note:

  • The type of expression evaluator used is not mandated. An RPN evaluator is equally acceptable for example.
  • The task is not for the program to generate the expression, or test whether an expression is even possible.

#include <random>
#include <iostream>
#include <stack>
#include <set>
#include <string>
#include <functional>
using namespace std;

class RPNParse
{
public:
	stack<double> stk;
	multiset<int> digits;

	void op(function<double(double,double)> f)
	{
		if(stk.size() < 2)
		throw "Improperly written expression";
		int b = stk.top(); stk.pop();
		int a = stk.top(); stk.pop();
		stk.push(f(a, b));
	}

	void parse(char c)
	{
		if(c >= '0' && c <= '9')
		{
			stk.push(c - '0');
			digits.insert(c - '0');
		}
		else if(c == '+')
		op([](double a, double b) {return a+b;});
		else if(c == '-')
		op([](double a, double b) {return a-b;});
		else if(c == '*')
		op([](double a, double b) {return a*b;});
		else if(c == '/')
		op([](double a, double b) {return a/b;});
	}

	void parse(string s)
	{
		for(int i = 0; i < s.size(); ++i)
		parse(s[i]);
	}

	double getResult()
	{
		if(stk.size() != 1)
		throw "Improperly written expression";
		return stk.top();
	}
};

int main()
{
	random_device seed;
	mt19937 engine(seed());
	uniform_int_distribution<> distribution(1, 9);
	auto rnd = bind(distribution, engine);

	multiset<int> digits;
	cout << "Make 24 with the digits: ";
	for(int i = 0; i < 4; ++i)
	{
		int n = rnd();
		cout << " " << n;
		digits.insert(n);
	}
	cout << endl;

	RPNParse parser;

	try
	{
		string input;
		getline(cin, input);
		parser.parse(input);

		if(digits != parser.digits)
		cout << "Error: Not using the given digits" << endl;
		else
		{
			double r = parser.getResult();
			cout << "Result: " << r << endl;

			if(r > 23.999 && r < 24.001)
			cout << "Good job!" << endl;
			else
			cout << "Try again." << endl;
		}
	}
	catch(char* e)
	{
		cout << "Error: " << e << endl;
	}
	return 0;
}

 

Output:
Enter an expression using the digits 8833 that evals to 24: (8/(3-(8/3)))
nice!
Enter an expression using the digits 8833 that evals to 24: (8/(3-(8/9)))
Extra goodies in expression: 9
Enter an expression using the digits 8833 that evals to 24: (8/(3-(8/8)))
You can only use the digits 8833 once each
Enter an expression using the digits 7155 that evals to 24: 7+1+5+5
That evaled to 18, not 24
Enter an expression using the digits 8332 that evals to 24: 8*3*(3-2)
nice!

SOURCE

Content is available under GNU Free Documentation License 1.2.