#include #include #include #include #include #define random_word get_random_word(words, word_count) enum { TYPED_COLOR = 1, UNTYPED_COLOR = 2, MISTAKE_COLOR = 3, }; typedef struct { char *data; int head; int tail; int cap; } CBuffer; CBuffer CBuffer_init(int size) { CBuffer cbuffer; cbuffer.data = malloc(size); cbuffer.cap = size; cbuffer.tail = -1; cbuffer.head = -1; return cbuffer; } bool CBuffer_is_empty(CBuffer buffer) { return buffer.tail == buffer.head; } int CBuffer_count(CBuffer buffer) { if (CBuffer_is_empty(buffer)) return 0; int count = 0, tail = buffer.tail; while (tail != buffer.head) { tail++; if (tail == buffer.cap) tail = 0; count++; } return count; } bool CBuffer_is_full(CBuffer buffer) { return CBuffer_count(buffer) == buffer.cap; } char * CBuffer_read(CBuffer *buffer, int count) { if (CBuffer_is_empty(*buffer)) return NULL; char *read; read = malloc(count+1); int i = 0; for (;itail != buffer->head; i++, buffer->tail++) { if (buffer->tail == buffer->cap) buffer->tail = 0; read[i] = buffer->data[i]; } return read; } char CBuffer_peak(CBuffer buffer) { return buffer.data[buffer.head == 0 ? buffer.cap-1 : buffer.head-1]; }; char CBuffer_bottom(CBuffer buffer) { return buffer.data[buffer.tail]; } char *CBuffer_bottom_n(CBuffer buffer, int n) { char *read = malloc(n+1); for (int t = buffer.tail, i = 0; ihead == -1) { buffer->head = 0; buffer->tail = 0; } while ((ch = data[i]) != '\0') { i++; buffer->data[buffer->head] = ch; buffer->head++; if (buffer->head == buffer->cap) { buffer->head = 0; } } return i; } void CBuffer_clear(CBuffer *buffer) { buffer->tail = -1; buffer->head = -1; } typedef struct { int pos; time_t start_time; time_t finish_time; int keystrokes_count; CBuffer type_tape; CBuffer tape; } Test; Test Test_init() { Test test = { 0, time(NULL), 0, 0, CBuffer_init(256), CBuffer_init(256) }; return test; } void Test_finish(Test *test) { time(&test->finish_time); } float Test_duration(Test test) { if (test.finish_time == 0) return time(NULL) - test.start_time; return test.finish_time - test.start_time; } float Test_wpm(Test test) { float wpm; time_t td = Test_duration(test); wpm = (((float)test.keystrokes_count / td) * 60) / 5; return wpm; } void Test_write(Test *test, char ch) { if (test->finish_time != 0) return; char tc = (char)CBuffer_bottom(test->tape); char ttc = (char)CBuffer_peak(test->type_tape); if (tc != ch) { return Test_finish(test); } test->keystrokes_count++; char cha[1]; cha[0] = ch; CBuffer_write(&test->type_tape, cha); CBuffer_read(&test->tape, 1); }; void Test_backspace(Test *test) { // NO BACKSPACO NOW return; if (test->finish_time != 0) return; if (test->tape.head == 0) { test->tape.head = test->tape.cap - 1; } else { test->tape.head = test->tape.head - 1; } } bool Test_is_running(Test test) { return test.finish_time == 0; } void Test_render(Test test) { char *read, *tread, s_wpm[6], s_time[10]; int cc = COLS / 2 + COLS % 2, mte = COLS - 2, mta = COLS / 2, ta = test.keystrokes_count < cc ? cc - test.keystrokes_count : 1, te = cc - 1, t; // while (CBuffer_count(test.tape) > cc) // CBuffer_read(&test.tape, 1); while (CBuffer_count(test.type_tape) > cc - 1 )//- (COLS%2)) CBuffer_read(&test.type_tape, 1); read = CBuffer_bottom_n(test.tape, cc - 1); tread = CBuffer_bottom_n(test.type_tape, te); attron(COLOR_PAIR(UNTYPED_COLOR)); mvaddstr(10, cc, read); attroff(COLOR_PAIR(UNTYPED_COLOR)); attron(COLOR_PAIR(TYPED_COLOR)); mvaddstr(10, ta, tread); attroff(COLOR_PAIR(TYPED_COLOR)); attron(A_REVERSE | A_BOLD ); if (!Test_is_running(test)) attron(COLOR_PAIR(MISTAKE_COLOR)); mvaddch(9, cc, '|'); mvaddch(10, cc, CBuffer_bottom(test.tape)); mvaddch(11, cc, '|'); if (!Test_is_running(test)) attroff(COLOR_PAIR(MISTAKE_COLOR)); attroff(A_REVERSE | A_BOLD); t = sprintf(s_wpm, "%.2f", Test_wpm(test)); sprintf(s_time, "%.2f", Test_duration(test)); mvaddstr(7, cc - t - 4, s_wpm); mvaddstr(7, cc + 1, s_time); } void Test_show_result(Test test) { clear(); int i, j, cc = COLS / 2 + COLS % 2, lc = LINES / 2 + LINES % 2; char s_wpm[6], s_time[10], s_keystrokes[6]; // box for (i=0; i