Math-Practice/main.cpp
2020-03-10 16:15:13 -04:00

208 lines
5.4 KiB
C++

// TODO(dev): use 'halfdelay()' to parse input for pi menu choice 'secret.'
// NOTE(dev): Gonna need this:
// mvwprintw(win, y, x, string); /* Move to (y, x) relative to window */
// /* co-ordinates and then print */
#include <ncurses.h>
#include "Problem.h"
#include <vector>
#include <chrono>
#define PROMPT " > "
std::vector<Problem*> GenerateProblems(bool addition, bool subtraction,
bool multiplication, bool division);
char MainMenu();
int main(int argc, char *argv[])
{
initscr();
noecho(); // don't show user input
cbreak(); // handle user input immediately (i.e. don't wait for the user to press enter)
keypad(stdscr, true); // enable the numpad, F1-F12 keys, arrow keys, etc.
while(true)
{
// game boolean flags:
bool addition = false;
bool subtraction = false;
bool multiplication = false;
bool division = false;
// Main Menu:
char menu_action = MainMenu();
if(menu_action == 'q')
break;
else if(menu_action == '1')
addition = true;
else if(menu_action == '2')
subtraction = true;
else if(menu_action == '3')
addition = subtraction = true;
else if(menu_action == '4')
multiplication = true;
else if(menu_action == '5')
division = true;
else if(menu_action == '6')
multiplication = division = true;
else
continue; // restart loop
clear();
wrefresh(stdscr);
std::vector<Problem*> problems = GenerateProblems(addition, subtraction,
multiplication, division);
std::vector<Problem*>::iterator selected = problems.begin();
INPUT_STYLE input_style = INPUT_STYLE::INPUT_APPEND;
for(auto *problem : problems)
if(problem)
problem->Draw(problem == *selected, input_style);
// Keep track of time:
auto start_time = std::chrono::steady_clock::now();
unsigned int input = 'q';
while(selected != problems.end() && *selected)
{
Problem *current_problem = *selected;
current_problem->Draw(true, input_style); // refresh with new input
input = getch();
if(input == 'q') // early exit
break;
switch(input)
{
case KEY_LEFT:
input_style = INPUT_STYLE::INPUT_PREPEND;
break;
case KEY_RIGHT:
input_style = INPUT_STYLE::INPUT_APPEND;
break;
case KEY_BACKSPACE:
current_problem->ClearInput();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
current_problem->Input(input_style, input);
break;
};
// NOTE(dev): If the answer is zero and they hit backspace to clear input, it treated it
// as if they had entered zero themselves.
if(input != KEY_BACKSPACE && current_problem->Correct())
++selected;
current_problem->Draw(current_problem == *selected, input_style); // refresh with new input
}
if(input != 'q') // if you didn't quit
{
// Keep track of time:
auto end_time = std::chrono::steady_clock::now();
auto elapsed_time = std::chrono::duration_cast<std::chrono::seconds>(end_time - start_time);
int middle_h = COLS / 2;
int middle_v = LINES / 2;
clear();
mvprintw(middle_v - 1, middle_h - 10,
"Time Elapsed: %02dm %02ds\n",
elapsed_time / 60, elapsed_time % 60);
mvprintw(middle_v + 1, middle_h - 8,
"Press Q to quit.");
wrefresh(stdscr);
while(!(getch() == 'q'))
;
}
for(auto *problem : problems)
if(problem)
delete problem;
}
endwin();
return 0;
}
char MainMenu()
{
int middle_h = COLS / 2;
int middle_v = LINES / 2;
clear();
mvprintw(middle_v - 6, middle_h - 20, "\n");
mvprintw(middle_v - 5, middle_h - 20, " Welcome to Math Practice.\n");
mvprintw(middle_v - 4, middle_h - 20, " Please choose from the following menu:\n");
mvprintw(middle_v - 3, middle_h - 20, " 1. Addition\n");
mvprintw(middle_v - 2, middle_h - 20, " 2. Subtraction\n");
mvprintw(middle_v - 1, middle_h - 20, " 3. Both / Mixed\n");
mvprintw(middle_v - 0, middle_h - 20, " 4. Multiplication\n");
mvprintw(middle_v + 1, middle_h - 20, " 5. Division\n");
mvprintw(middle_v + 2, middle_h - 20, " 6. Both / Mixed\n");
mvprintw(middle_v + 3, middle_h - 20, " q. Quit\n");
mvprintw(middle_v + 4, middle_h - 20, "\n");
mvprintw(middle_v + 5, middle_h - 20, PROMPT);
refresh();
return getch();
}
std::vector<Problem*> GenerateProblems(bool addition, bool subtraction,
bool multiplication, bool division)
{
std::vector<Problem*> rtn;
for(auto y = 1; y < LINES - 10; y += 9)
{
for(auto x = 2; x < COLS - 16; x += 15)
{
Problem *test = nullptr;
if(addition || subtraction)
{
if(addition != subtraction)
{
if(addition)
test = new Problem(EASY_ADDITION, 3, x, y);
if(subtraction)
test = new Problem(EASY_SUBTRACTION, 3, x, y);
}
else
{
if(rand() % 2)
test = new Problem(HARD_ADDITION, 5, x, y);
else
test = new Problem(HARD_SUBTRACTION, 5, x, y);
}
rtn.push_back(test);
}
if(multiplication || division)
{
if(multiplication && !division)
test = new Problem(EASY_MULTIPLICATION, 2, x, y);
else if(division && !multiplication)
test = new Problem(EASY_DIVISION, 2, x, y);
else
{
// TODO(dev): Add hard problems
if(rand() % 2)
test = new Problem(HARD_MULTIPLICATION, 3, x, y);
else
test = new Problem(HARD_DIVISION, 3, x, y);
}
rtn.push_back(test);
}
}
}
return rtn;
}