-
tanguy.cavagna authoredtanguy.cavagna authored
ui.c 9.60 KiB
#include "ui.h"
#include <curses.h>
#define MENU_MAX 4
#define TITLE_Y_OFFSET 2
#define MENU_CHOICE_Y_OFFSET 20
#define GAMEBOARD_Y_OFFSET 13
//==========================
// PRIVATE
//==========================
// Windows
WINDOW *ui_window = NULL;
WINDOW *help = NULL;
WINDOW *tool = NULL;
char main_title[8][64] = {"$$\\ $$\\ $$$$$$\\ $$$$$$$\\ $$$$$$$\\ $$\\ $$$$$$$$\\ ",
"$$ | $\\ $$ |$$ __$$\\ $$ __$$\\ $$ __$$\\ $$ | $$ _____|",
"$$ |$$$\\ $$ |$$ / $$ |$$ | $$ |$$ | $$ |$$ | $$ | ",
"$$ $$ $$\\$$ |$$ | $$ |$$$$$$$ |$$ | $$ |$$ | $$$$$\\ ",
"$$$$ _$$$$ |$$ | $$ |$$ __$$< $$ | $$ |$$ | $$ __| ",
"$$$ / \\$$$ |$$ | $$ |$$ | $$ |$$ | $$ |$$ | $$ | ",
"$$ / \\$$ | $$$$$$ |$$ | $$ |$$$$$$$ |$$$$$$$$\\ $$$$$$$$\\ ",
"\\__/ \\__| \\______/ \\__| \\__|\\_______/ \\________|\\________|"};
char mode_solo_title[8][40] = {" $$$$$$\\ $$$$$$\\ $$\\ $$$$$$\\ ", "$$ __$$\\ $$ __$$\\ $$ | $$ __$$\\ ",
"$$ / \\__|$$ / $$ |$$ | $$ / $$ |", "\\$$$$$$\\ $$ | $$ |$$ | $$ | $$ |",
" \\____$$\\ $$ | $$ |$$ | $$ | $$ |", "$$\\ $$ |$$ | $$ |$$ | $$ | $$ |",
"\\$$$$$$ | $$$$$$ |$$$$$$$$\\ $$$$$$ |", " \\______/ \\______/ \\________|\\______/ "};
char mode_1v1_title[8][54] = {
" $$\\ $$\\ $$\\ $$\\", "$$$$ | $$ | $$ | $$$$ |",
"\\_$$ | $$ | $$ | $$$$$$$\\ \\_$$ |", " $$ | \\$$\\ $$ |$$ _____| $$ |",
" $$ | \\$$\\$$ / \\$$$$$$\\ $$ |", " $$ | \\$$$ / \\____$$\\ $$ |",
" $$$$$$\\ \\$ / $$$$$$$ | $$$$$$\\", " \\______| \\_/ \\_______/ \\______|"};
char mode_computer_title[8][21] = {"$$$$$$\\ $$$$$$\\ ", "\\_$$ _|$$ __$$\\ ", " $$ | $$ / $$ |", " $$ | $$$$$$$$ |",
" $$ | $$ __$$ |", " $$ | $$ | $$ |", "$$$$$$\\ $$ | $$ |", "\\______|\\__| \\__|"};
/**
* @brief Set the color scheme of the programm
*
*/
void set_colors() {
init_pair(GREEN_PAIR, COLOR_GREEN, COLOR_BLACK);
init_pair(ORANGE_PAIR, COLOR_YELLOW, COLOR_BLACK);
init_pair(WHITE_PAIR, COLOR_WHITE, COLOR_BLACK);
init_pair(RED_PAIR, COLOR_RED, COLOR_BLACK);
}
/**
* @brief Is the window too small
*
* @return true
* @return false
*/
bool window_too_small() { return (LINES < MENU_CHOICE_Y_OFFSET + MENU_MAX + 10); }
/**
* @brief Modify the menu offset depending on the window size
*
* @return int
*/
int menu_offset_modifer() { return (window_too_small() ? 15 : 0); }
/**
* @brief Get the selected menu choice
*
* @return int
*/
void draw_menu(int menu_item) {
char menu_choices[MENU_MAX][20] = {" Solo ", " 1 Vs 1 ", " Computer ", " Quit "};
// Print of the menu choices
for (int i = 0; i < MENU_MAX; i++) {
if (i == menu_item)
attron(A_STANDOUT);
if (i == MENU_QUIT)
attron(COLOR_PAIR(RED_PAIR));
printw_center(menu_choices[i], MENU_CHOICE_Y_OFFSET + (i * 2) - menu_offset_modifer());
attroff(COLOR_PAIR(WHITE_PAIR));
attroff(A_STANDOUT);
}
}
/**
* @brief Hide the help subwindow
*/
void hide_help() {
wclear(ui_window);
delwin(help);
refresh();
help = NULL;
}
/**
* @brief Hide the tool subwindow
*/
void hide_tool() {
wclear(ui_window);
delwin(tool);
refresh();
tool = NULL;
}
//==========================
// PUBLIC
//==========================
void printw_center(char *foo, int line) { mvaddstr(line, TERM_MID_COLS - (strlen(foo) / 2), foo); }
void draw_title(int id) {
if (window_too_small())
return;
for (int i = 0; i < TITLES_LINE_COUNT; i++) {
switch (id) {
case MAIN_TITLE_ID:
printw_center(main_title[i], i + TITLE_Y_OFFSET);
break;
case SOLO_TITLE_ID:
printw_center(mode_solo_title[i], i + TITLE_Y_OFFSET);
break;
case ONE_V_ONE_TITLE_ID:
printw_center(mode_1v1_title[i], i + TITLE_Y_OFFSET);
break;
case COMPUTER_TITLE_ID:
printw_center(mode_computer_title[i], i + TITLE_Y_OFFSET);
break;
}
}
}
void show_answer(char *answer) { printw_center(answer, GAMEBOARD_Y_OFFSET + 15); }
void hide_answer() { printw_center(" ", GAMEBOARD_Y_OFFSET + 15); }
bool init_term() {
ui_window = initscr();
cbreak();
noecho();
curs_set(0);
keypad(stdscr, true);
if (ui_window == NULL)
return false;
start_color();
if (!has_colors() || !can_change_color()) {
printf("Warning. Your terminal can't handle this program.\n");
return false;
}
set_colors();
return true;
}
void cleanup_term() {
curs_set(1);
nocbreak();
delwin(tool);
delwin(help);
delwin(ui_window);
endwin();
refresh();
}
int show_menu() {
hide_help();
// Title print
if (!window_too_small())
draw_title(MAIN_TITLE_ID);
// Menu print
attron(COLOR_PAIR(GREEN_PAIR));
attron(A_BOLD);
printw_center("====== MENU ======", MENU_CHOICE_Y_OFFSET - 3 - menu_offset_modifer());
attroff(A_BOLD);
attron(COLOR_PAIR(WHITE_PAIR));
attron(A_DIM);
printw_center("Use arrow keys to move; Enter to chose", MENU_CHOICE_Y_OFFSET + 10 - menu_offset_modifer());
attroff(A_DIM);
// Menu choices handler
int key = 0, menu_item = 0;
do {
switch (key) {
case KEY_DOWN:
menu_item += 1;
if (menu_item > MENU_MAX - 1)
menu_item = 0;
break;
case KEY_UP:
menu_item -= 1;
if (menu_item < 0)
menu_item = MENU_MAX - 1;
break;
}
draw_menu(menu_item);
key = getch();
} while (key != '\n');
refresh();
return menu_item;
}
void toggle_help() {
// Delete existing instance of the subwindow
if (help != NULL) {
hide_help();
return;
}
// Create new instance of the subwindow
help = subwin(ui_window, 7, COLS - 2, LINES - 7, 1);
refresh();
if (help == NULL) {
cleanup_term();
exit(EXIT_FAILURE);
}
box(help, 0, 0);
mvwprintw(help, 0, 1, " Help "); // Title
// Content
// Keybindings
wattron(help, A_BOLD);
mvwprintw(help, 2, 2, "Ctrl+h");
mvwprintw(help, 3, 2, "Ctrl+t");
mvwprintw(help, 4, 2, "Ctrl+w");
wattroff(help, A_BOLD);
// Description
mvwprintw(help, 2, 10, "Show this page");
mvwprintw(help, 3, 10, "Toggle the assistance tool (only in Computer mode)");
mvwprintw(help, 4, 10, "Quit the game");
refresh();
wrefresh(help);
}
void show_tool() {
// Delete existing instance of the subwindow
if (tool != NULL) {
hide_tool();
return;
}
// Create new instance of the subwindow
tool = subwin(ui_window, LINES - 2, 30, 1, 1);
refresh();
if (tool == NULL) {
cleanup_term();
exit(EXIT_FAILURE);
}
refresh();
wrefresh(tool);
}
void update_tool(int count, char words[count][WORD_LENGHT + 1], double *entropies) {
wclear(tool);
box(tool, 0, 0);
mvwprintw(tool, 0, 1, " Tool "); // Title
mvwprintw(tool, 2, 2, " Mot \t\tEntropie");
for (int i = 0; i < (count > 30 ? 30 : count); i++)
mvwprintw(tool, 4 + i, 2, "%s\t\t%f", words[i], entropies[i]);
refresh();
wrefresh(tool);
}
void show_gameboard(int tries_count, int word_length, char **tries, Pattern **patterns, int* scores, Gamemode mode, bool p2_turn, int current_turn) {
for (int i = 0; i < tries_count; i++) {
// Draw current try letters
for (int j = 0; j < word_length; j++) {
// Placeholder
if (tries[i][j] == '\0') {
mvaddch(GAMEBOARD_Y_OFFSET + i - menu_offset_modifer() + 5, TERM_MID_COLS - word_length + (j * 2), '_');
continue;
}
// Letters
if (patterns[i][j] == MISPLACED)
attron(COLOR_PAIR(ORANGE_PAIR));
if (patterns[i][j] == CORRECT)
attron(COLOR_PAIR(GREEN_PAIR));
mvaddch(GAMEBOARD_Y_OFFSET + i - menu_offset_modifer() + 5, TERM_MID_COLS - word_length + (j * 2), tries[i][j]);
attroff(COLOR_PAIR(GREEN_PAIR));
attroff(COLOR_PAIR(ORANGE_PAIR));
}
}
if (mode == VERSUS) {
move(GAMEBOARD_Y_OFFSET, TERM_MID_COLS - word_length);
printw("Turn: %d/%d", current_turn, VERSUS_TURN_COUNT);
if (!p2_turn)
attron(COLOR_PAIR(GREEN_PAIR));
move(GAMEBOARD_Y_OFFSET - 2 - menu_offset_modifer() + 5, TERM_MID_COLS - word_length - 10);
printw("Score P1: %d", scores[0]);
attroff(COLOR_PAIR(GREEN_PAIR));
if (p2_turn)
attron(COLOR_PAIR(GREEN_PAIR));
move(GAMEBOARD_Y_OFFSET - 2 - menu_offset_modifer() + 5, TERM_MID_COLS - word_length + 8);
printw("Score P2: %d", scores[1]);
attroff(COLOR_PAIR(GREEN_PAIR));
}
else {
move(GAMEBOARD_Y_OFFSET - 2 - menu_offset_modifer() + 5, TERM_MID_COLS - word_length);
printw("Score: %d", scores[0]);
}
refresh();
}
void show_winner(bool p2_turn, int* scores) {
move(GAMEBOARD_Y_OFFSET + 15, TERM_MID_COLS - 13);
printw("Winner: %s with %d points !", p2_turn ? "P2" : "P1", p2_turn ? scores[1] : scores[0]);
}