#include "Problem.h" #include #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; } input = ""; GenerateNumbers(type, (max_digits > 5 ? 5 : max_digits)); GenerateWindow(win_x, win_y); } Problem::~Problem() { if(win) delwin(win); } void Problem::Draw(bool selected, const INPUT_STYLE &input_style) { if(!win) return; // Draw the window: if(selected) box(win, '*', '*'); // 0, 0 gives default characters for the vertical and horizontal lines else wborder(win, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); 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; case EASY_MULTIPLICATION: case HARD_MULTIPLICATION: mvwprintw(win, 3, 2, "*"); break; case EASY_DIVISION: case HARD_DIVISION: mvwprintw(win, 3, 2, "รท"); break; }; mvwprintw(win, 4, 2, "========"); if(Input() > 999999) mvwprintw(win, 5, 3, " FAILED"); else if(Input() != 0 || selected) // if it's not selected then the answer could have been zero mvwprintw(win, 5, 3, "%'7d", Input()); else if(selected) mvwprintw(win, 5, 3, " "); // 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, ""); 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 EASY_MULTIPLICATION: number_top = rand() % 13; number_bottom = rand() % 13; break; case EASY_DIVISION: // TODO(dev): number_top = 1; number_bottom = 1; 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; case HARD_MULTIPLICATION: number_top = rand() % 130; number_bottom = rand() % 130; break; case HARD_DIVISION: // TODO(dev): number_top = 10; number_bottom = 10; 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 { 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; } void Problem::Input(const INPUT_STYLE input_style, char character) { if(input.length() > 6) return; // TODO(dev): ASSERT if(character < '0' || character > '9') exit(-1); if(input_style == INPUT_STYLE::INPUT_PREPEND) input = character + input; else input += 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; 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; }; // TODO(dev): Assert that all conditions are handled! exit(-1); return false; }