This small program generates random operands and operations and asks the user to perform the computation and input the result. I want to make it more C++ and remove any C-ness it might inappropriately contain. How to go about it?
/*
* https://artfulcode.wordpress.com/learn-you-a-hex/
* https://github.com/cmovz/
* License: Use it as you wish, just keep this notice.
*/
#include <iostream>
#include <string>
#include <random>
#include <cstdlib>
#include <limits>
enum Ops {
ADD, SUB, MUL, DIV, OPS_COUNT
};
static char const* ops_signs[] = {"+", "-", "*", "/", "?"};
static char const* bin_to_hex_table = "0123456789abcdef";
static char const hex_to_bin_table[256] = {
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x3,0x4,0x5,
0x6,0x7,0x8,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xA,0xB,0xC,0xD,0xE,0xF,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa,0xb,0xc,0xd,0xe,0xf,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0
};
std::string to_hex(unsigned long long hex)
{
std::string rev_s;
do {
rev_s.push_back(bin_to_hex_table[hex&0xf]);
} while(hex >>= 4);
std::string s = "0x";
s.insert(s.end(), rev_s.rbegin(), rev_s.rend());
return s;
}
long long hex_to_bin(std::string const& str)
{
long long bin = 0;
int shift = 0;
for(std::string::const_reverse_iterator ite = str.rbegin();
ite != str.rend();
++ite)
{
bin |= static_cast<long long>(
hex_to_bin_table[static_cast<unsigned char>(*ite)]
)
<< shift;
shift += 4;
}
return bin;
}
bool is_hex(std::string const& str)
{
for(std::string::const_iterator ite = str.begin();
ite != str.end();
++ite)
{
unsigned char c = *ite;
if('0' != c && !hex_to_bin_table[c]){
return false;
}
}
return true;
}
void bye()
{
std::cout << std::endl << "------------" << std::endl << std::endl
<< "Bye!" << std::endl;
std::exit(0);
}
int main()
{
std::random_device hw_rand;
unsigned int mask;
std::cout << "=============================" << std::endl
<< " Welcome to Learn You A Hex!" << std:: endl
<< "=============================" << std::endl
<< std::endl;
if(hw_rand.entropy() == 0){
std::cout << "INFO: Using software-generated random numbers"
<< std::endl;
}
else {
std::cout << "INFO: Using hardware-generated random numbers"
<< std::endl;
}
std::cout << std::endl;
while(true){
unsigned int digits;
std::cout << "How many digits you want? [1;8]" << std::endl;
std::cin >> digits;
if(!std::cin){
if(std::cin.eof()){
bye();
}
std::cout << "Error: bad input" << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
else
if(digits >= 1 && digits <= 8){
mask = 0;
while(digits--){
mask |= 0xf << (digits * 4);
}
break;
}
std::cout << "Range must be [1;8]" << std::endl;
}
do {
long long correct_answer;
long long user_answer;
unsigned int a = hw_rand() & mask;
unsigned int b = hw_rand() & mask;
unsigned int op = hw_rand() % OPS_COUNT;
std::string answer_str;
switch(op){
case ADD:
correct_answer = (long long)a + b;
break;
case SUB:
correct_answer = (long long)a - b;
break;
case MUL:
correct_answer = (long long)a * b;
break;
case DIV:
if(b == 0){
continue; // can't divide by 0
}
correct_answer = (long long)a / b;
break;
}
std::cout << "------------" << std::endl
<< to_hex(a) << " " << ops_signs[op] << " "
<< to_hex(b) << " = ?" << std::endl
<< "0x";
while(std::cin >> answer_str){
if(!is_hex(answer_str)){
std::cout << "Error: not hex, write only the hex digits"
<< std::endl;
}
else
if(answer_str.size() > sizeof(long long) * 2){
std::cout << "Error: input too long, hex number should not "
"exceed " << sizeof(long long) * 2 << " digits"
<< std::endl;
}
else {
user_answer = hex_to_bin(answer_str);
break;
}
std::cout << "0x";
}
if(!std::cin){
bye();
}
if(user_answer == correct_answer){
std::cout << "Correct!" << std::endl;
}
else {
std::cout << to_hex(correct_answer) << std::endl;
}
} while(true);
}
main
which could be moved into functions instead. This has nothing to do with C vs C++, but is there a particular reason behind your approach? \$\endgroup\$