Math-Practice/Problem.cpp

187 lines
4.3 KiB
C++

#include "Problem.h"
#include <cmath>
#include <locale.h>
#include <syslog.h>
bool Problem::seeded = false;
Problem::Problem(PROBLEM_TYPE type, unsigned short max_digits, unsigned win_x, unsigned win_y)
: problem_type(type), window_x(win_x), window_y(win_y)
{
// NOTE(dev): Only ever seed rand ONCE!
// TODO(dev): Should this be in main.cpp?
if(!seeded)
{
// srand(time());
srand(0);
setlocale(LC_NUMERIC, ""); // apostrophe to enable thousands separator in printf statements.
seeded = true;
}
GenerateNumbers(type, (max_digits > 5 ? 5 : max_digits));
GenerateWindow(win_x, win_y);
}
Problem::~Problem()
{
if(win)
delwin(win);
}
void Problem::Draw(bool selected)
{
if(!win)
return;
// Draw the window:
if(selected)
box(win, '?', '?');
else
box(win, 0, 0); // 0, 0 gives default characters for the vertical and horizontal lines
mvwprintw(win, 2, 4, "%'6d", number_top);
mvwprintw(win, 3, 4, "%'6d", number_bottom);
switch(problem_type)
{
case EASY_ADDITION:
case HARD_ADDITION:
mvwprintw(win, 3, 2, "+");
break;
case EASY_SUBTRACTION:
case HARD_SUBTRACTION:
mvwprintw(win, 3, 2, "-");
break;
};
mvwprintw(win, 4, 2, "========");
mvwprintw(win, 5, 9, "");
wrefresh(win);
}
void Problem::GenerateNumbers(PROBLEM_TYPE type, unsigned short max_digits)
{
// Determine how many digits long these numbers should be:
unsigned short digits = rand() % (max_digits) + 1; // at least one digit
number_top = 0;
number_bottom = 0;
switch(problem_type)
{
default:
case EASY_ADDITION:
for(auto digit = 0; digit < digits; ++digit)
{
unsigned short temp_number_top = rand() % 10;
unsigned short temp_number_bottom;
if(temp_number_top == 9)
temp_number_bottom = 0;
else
temp_number_bottom = rand() % (10 - temp_number_top);
// Place into correct digit posititon:
number_top += temp_number_top * (pow(10, digit));
number_bottom += temp_number_bottom * (pow(10, digit));
}
break;
case EASY_SUBTRACTION:
for(auto digit = 0; digit < digits; ++digit)
{
unsigned short temp_number_bottom = rand() % 10;
// NOTE(dev): top number must be higher than bottom number
unsigned short temp_number_top;
if(temp_number_bottom == 9)
temp_number_top = 9; // can't mod by zero
else
temp_number_top = 9 - (rand() % (9 - temp_number_bottom));
// Place into correct digit posititon:
number_top += temp_number_top * (pow(10, digit));
number_bottom += temp_number_bottom * (pow(10, digit));
}
break;
case HARD_ADDITION:
number_top = rand() % int(pow(10, digits));
number_bottom = rand() % int(pow(10, digits));
break;
case HARD_SUBTRACTION:
number_top = rand() % int(pow(10, digits));
number_bottom = rand() % int(pow(10, digits));
// NOTE(dev): don't allow negative numbers:
if(number_bottom > number_top)
{
if(number_top)
number_bottom %= number_top;
else
number_bottom = 0; // lol, 0 - 0 is hard?
}
break;
};
}
void Problem::GenerateWindow(unsigned win_x, unsigned win_y)
{
// NOTE(dev): Max problem dimensions:
// Width: 13 characters
// Height: 8 characters
// +-----------+
// | |
// | 12,345 |
// | + 99,999 |
// | ======== |
// | 112,344 |
// | |
// +-----------+
auto height = 8;
auto width = 13;
win = newwin(height, width, win_y, win_x);
if(!win)
return;
}
int Problem::Input() const
{
int rtn = 0;
try {
rtn = std::stoi(input.c_str());
} catch (const std::exception &e) {
syslog(LOG_USER|LOG_DEBUG, "%s:%d:%s Invalid std::stoi: %s",
__FILE__,__LINE__,__PRETTY_FUNCTION__,e.what());
exit(-1); // INVALID INPUT!!!
}
return rtn;
}
void Problem::Input(char character)
{
// TODO(dev): ASSERT
if(character < '0' || character > '9')
exit(-1);
if(input_style == INPUT_STYLE::INPUT_PREPEND)
input = std::to_string(character) + input;
else
input += std::to_string(character);
}
bool Problem::Correct() const
{
// NOTE(dev): I know I don't need "break;", but it just makes me happier knowing they're there.
switch(problem_type)
{
case EASY_ADDITION:
case HARD_ADDITION:
return number_top + number_bottom == Input();
break;
case EASY_SUBTRACTION:
case HARD_SUBTRACTION:
return number_top - number_bottom == Input();
break;
};
// TODO(dev): Assert that all conditions are handled!
exit(-1);
return false;
}