2019-03-31 18:40:37 -04:00
|
|
|
#include "Problem.h"
|
|
|
|
|
|
|
|
#include <cmath>
|
2019-04-01 15:48:20 -04:00
|
|
|
#include <locale.h>
|
2019-04-01 18:14:30 -04:00
|
|
|
#include <syslog.h>
|
2019-04-01 18:47:16 -04:00
|
|
|
#include <stdexcept>
|
2020-03-10 16:59:48 -04:00
|
|
|
#include <ctime>
|
2019-03-31 18:40:37 -04:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2020-03-10 16:59:48 -04:00
|
|
|
srand(std::time(NULL));
|
2019-04-01 15:48:20 -04:00
|
|
|
setlocale(LC_NUMERIC, ""); // apostrophe to enable thousands separator in printf statements.
|
2019-03-31 18:40:37 -04:00
|
|
|
seeded = true;
|
|
|
|
}
|
|
|
|
|
2019-04-01 18:47:16 -04:00
|
|
|
input = "";
|
|
|
|
|
2019-03-31 18:40:37 -04:00
|
|
|
GenerateNumbers(type, (max_digits > 5 ? 5 : max_digits));
|
|
|
|
|
|
|
|
GenerateWindow(win_x, win_y);
|
|
|
|
}
|
|
|
|
|
|
|
|
Problem::~Problem()
|
|
|
|
{
|
|
|
|
if(win)
|
|
|
|
delwin(win);
|
|
|
|
}
|
|
|
|
|
2019-04-03 09:36:08 -04:00
|
|
|
void Problem::Draw(bool selected, const INPUT_STYLE &input_style)
|
2019-03-31 18:40:37 -04:00
|
|
|
{
|
2019-04-01 09:08:41 -04:00
|
|
|
if(!win)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Draw the window:
|
|
|
|
if(selected)
|
2019-04-04 07:51:04 -04:00
|
|
|
box(win, '*', '*'); // 0, 0 gives default characters for the vertical and horizontal lines
|
|
|
|
else
|
|
|
|
wborder(win, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
|
2019-04-01 09:08:41 -04:00
|
|
|
|
2019-04-01 15:48:20 -04:00
|
|
|
mvwprintw(win, 2, 4, "%'6d", number_top);
|
|
|
|
mvwprintw(win, 3, 4, "%'6d", number_bottom);
|
2019-04-01 09:08:41 -04:00
|
|
|
switch(problem_type)
|
|
|
|
{
|
|
|
|
case EASY_ADDITION:
|
|
|
|
case HARD_ADDITION:
|
2019-04-01 15:48:20 -04:00
|
|
|
mvwprintw(win, 3, 2, "+");
|
2019-04-01 09:08:41 -04:00
|
|
|
break;
|
|
|
|
case EASY_SUBTRACTION:
|
|
|
|
case HARD_SUBTRACTION:
|
2019-04-01 15:48:20 -04:00
|
|
|
mvwprintw(win, 3, 2, "-");
|
2019-04-01 09:08:41 -04:00
|
|
|
break;
|
2020-03-10 15:52:49 -04:00
|
|
|
case EASY_MULTIPLICATION:
|
|
|
|
case HARD_MULTIPLICATION:
|
|
|
|
mvwprintw(win, 3, 2, "*");
|
|
|
|
break;
|
|
|
|
case EASY_DIVISION:
|
|
|
|
case HARD_DIVISION:
|
|
|
|
mvwprintw(win, 3, 2, "÷");
|
|
|
|
break;
|
2019-04-01 09:08:41 -04:00
|
|
|
};
|
2019-04-01 15:48:20 -04:00
|
|
|
mvwprintw(win, 4, 2, "========");
|
2019-04-04 07:51:04 -04:00
|
|
|
if(Input() > 999999)
|
|
|
|
mvwprintw(win, 5, 3, " FAILED");
|
2020-03-10 15:52:49 -04:00
|
|
|
else if(Input() != 0 || selected) // if it's not selected then the answer could have been zero
|
2019-04-04 07:51:04 -04:00
|
|
|
mvwprintw(win, 5, 3, "%'7d", Input());
|
2020-03-10 15:52:49 -04:00
|
|
|
else if(selected)
|
|
|
|
mvwprintw(win, 5, 3, " ");
|
2019-04-03 09:36:08 -04:00
|
|
|
|
|
|
|
// Place the cursor in the correct position!
|
|
|
|
int length = input.length() + ((input.length() - 1) / 3); // add commas, too!
|
|
|
|
if(input_style == INPUT_STYLE::INPUT_PREPEND)
|
|
|
|
mvwprintw(win, 5, 9 - length, "");
|
|
|
|
else
|
|
|
|
mvwprintw(win, 5, 10, "");
|
2019-04-01 09:08:41 -04:00
|
|
|
wrefresh(win);
|
2019-03-31 18:40:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void Problem::GenerateNumbers(PROBLEM_TYPE type, unsigned short max_digits)
|
|
|
|
{
|
|
|
|
// Determine how many digits long these numbers should be:
|
2019-04-01 09:08:41 -04:00
|
|
|
unsigned short digits = rand() % (max_digits) + 1; // at least one digit
|
|
|
|
number_top = 0;
|
|
|
|
number_bottom = 0;
|
2019-03-31 18:40:37 -04:00
|
|
|
|
|
|
|
switch(problem_type)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case EASY_ADDITION:
|
|
|
|
for(auto digit = 0; digit < digits; ++digit)
|
|
|
|
{
|
|
|
|
unsigned short temp_number_top = rand() % 10;
|
2019-04-01 09:08:41 -04:00
|
|
|
unsigned short temp_number_bottom;
|
|
|
|
if(temp_number_top == 9)
|
|
|
|
temp_number_bottom = 0;
|
|
|
|
else
|
|
|
|
temp_number_bottom = rand() % (10 - temp_number_top);
|
2019-03-31 18:40:37 -04:00
|
|
|
|
|
|
|
// 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;
|
2020-03-10 15:52:49 -04:00
|
|
|
case EASY_MULTIPLICATION:
|
|
|
|
number_top = rand() % 13;
|
|
|
|
number_bottom = rand() % 13;
|
|
|
|
break;
|
|
|
|
case EASY_DIVISION:
|
|
|
|
// TODO(dev):
|
|
|
|
number_top = 1;
|
|
|
|
number_bottom = 1;
|
|
|
|
break;
|
2019-04-01 18:14:30 -04:00
|
|
|
case HARD_ADDITION:
|
|
|
|
number_top = rand() % int(pow(10, digits));
|
|
|
|
number_bottom = rand() % int(pow(10, digits));
|
|
|
|
break;
|
2019-03-31 18:40:37 -04:00
|
|
|
case HARD_SUBTRACTION:
|
2019-04-01 18:14:30 -04:00
|
|
|
number_top = rand() % int(pow(10, digits));
|
|
|
|
number_bottom = rand() % int(pow(10, digits));
|
2019-03-31 18:40:37 -04:00
|
|
|
// NOTE(dev): don't allow negative numbers:
|
|
|
|
if(number_bottom > number_top)
|
2019-04-01 09:08:41 -04:00
|
|
|
{
|
|
|
|
if(number_top)
|
|
|
|
number_bottom %= number_top;
|
|
|
|
else
|
|
|
|
number_bottom = 0; // lol, 0 - 0 is hard?
|
|
|
|
}
|
2019-03-31 18:40:37 -04:00
|
|
|
break;
|
2020-03-10 15:52:49 -04:00
|
|
|
case HARD_MULTIPLICATION:
|
|
|
|
number_top = rand() % 130;
|
|
|
|
number_bottom = rand() % 130;
|
|
|
|
break;
|
|
|
|
case HARD_DIVISION:
|
|
|
|
// TODO(dev):
|
|
|
|
number_top = 10;
|
|
|
|
number_bottom = 10;
|
|
|
|
break;
|
2019-03-31 18:40:37 -04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2019-04-01 18:14:30 -04:00
|
|
|
|
|
|
|
int Problem::Input() const
|
|
|
|
{
|
2019-04-01 18:47:16 -04:00
|
|
|
return atoi(input.c_str());
|
|
|
|
// int rtn = 0;
|
|
|
|
// try {
|
|
|
|
// rtn = std::stoi(input.c_str());
|
|
|
|
// } catch (std::invalid_argument &e) {
|
|
|
|
// syslog(LOG_USER|LOG_DEBUG, "%s:%d:%s Invalid std::stoi: \"%s\".",
|
|
|
|
// __FILE__,__LINE__,__FUNCTION__,e.what());
|
|
|
|
// exit(-1); // INVALID INPUT!!!
|
|
|
|
// }
|
|
|
|
// return rtn;
|
2019-04-01 18:14:30 -04:00
|
|
|
}
|
|
|
|
|
2019-04-01 18:47:16 -04:00
|
|
|
void Problem::Input(const INPUT_STYLE input_style, char character)
|
2019-04-01 18:14:30 -04:00
|
|
|
{
|
2019-04-04 07:51:04 -04:00
|
|
|
if(input.length() > 6)
|
|
|
|
return;
|
2019-04-01 18:14:30 -04:00
|
|
|
// TODO(dev): ASSERT
|
|
|
|
if(character < '0' || character > '9')
|
|
|
|
exit(-1);
|
|
|
|
|
|
|
|
if(input_style == INPUT_STYLE::INPUT_PREPEND)
|
2019-04-01 18:47:16 -04:00
|
|
|
input = character + input;
|
2019-04-01 18:14:30 -04:00
|
|
|
else
|
2019-04-01 18:47:16 -04:00
|
|
|
input += character;
|
2019-04-01 18:14:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2020-03-10 15:52:49 -04:00
|
|
|
case EASY_MULTIPLICATION:
|
|
|
|
case HARD_MULTIPLICATION:
|
|
|
|
return number_top * number_bottom == Input();
|
|
|
|
break;
|
|
|
|
case EASY_DIVISION:
|
|
|
|
case HARD_DIVISION:
|
|
|
|
return number_top / number_bottom == Input();
|
|
|
|
break;
|
2019-04-01 18:14:30 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
// TODO(dev): Assert that all conditions are handled!
|
|
|
|
exit(-1);
|
|
|
|
return false;
|
|
|
|
}
|