#include "Problem.h" #include #include #include 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; }