← index
Remember.Words/source/main.c
Source: Remember.Words/source/main.c
/*
 
 Remember Words, memory game
 
 I used to play this game with my speech therapist after being in a coma
 and having to learn how to speak again. Helps with memory recall
 so I decided to code it into a computer program.
 
 Hope this can help anyone
 
 - Jared
 
*/
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<time.h>
#include"remember.h"
#include "SDL.h"
#include "SDL_ttf.h"
#ifdef __EMSCRIPTEN__
#include<emscripten/emscripten.h>
#endif
TTF_Font *font = NULL;
int font_size = 24;
int width = 1920, height = 1080;
SDL_Renderer *ren = NULL;
int show_words = 0;
struct Remember rem;
unsigned int time_ticks = 0;
unsigned int timeout = 15;
int argc = 0;
char **argv = NULL; 

/* get path */
const char *get_path(const char *src) {
	static char buffer[1024];
#ifdef __EMSCRIPTEN__
	snprintf(buffer, 1023, "/data/%s", src);
#else
	snprintf(buffer, 1023, "s/%s", "./data",src);
#endif
	return buffer;
}

/* print text to the window */
void printtext(SDL_Renderer *ren, TTF_Font *font, const char *src, int x, int y,unsigned char r, unsigned char g, unsigned char b) {
    SDL_Color color = { r, g, b };
    SDL_Surface *surface = TTF_RenderText_Solid(font,src,color);

    if(!surface) {
        fprintf(stderr, "Error creating surface %s\n", TTF_GetError());
        return;
    }

    SDL_Texture *texture = SDL_CreateTextureFromSurface(ren, surface);

    if(!texture) {
        fprintf(stderr, "Error creating texture: %s\n", SDL_GetError());
        return;
    }

    SDL_Rect rc = { x, y, surface->w, surface->h };
    SDL_Rect rc_s = { 0, 0, surface->w, surface->h };
    SDL_RenderCopy(ren, texture, &rc_s, &rc);
    SDL_DestroyTexture(texture);
    SDL_FreeSurface(surface);
}
/* print text based on how wide the string is to wrap around */
void printtext_width(SDL_Renderer *ren, TTF_Font *font, int blink, const char *src, int x, int y, int w, unsigned char r, unsigned char g, unsigned char b) {
    static char (*buffer)[BUFFER_MAX] = NULL;
    if (!buffer) {
        buffer = (char (*)[BUFFER_MAX])malloc(255 * BUFFER_MAX);
        if (!buffer) {
            fprintf(stderr, "Memory allocation failed\n");
            return;
        }
    }
    int index = 0, pos = 0, offset = 0;
    int len = strlen(src);
    int width = x;
    int advance = 0;
    int minx,maxx,miny,maxy;
    int ypos = y;
    static int max_advance = 0;
    static int max_y = 0;
    while(pos < len) {
        if(TTF_GlyphMetrics(font,src[pos],&minx,&maxx,&miny,&maxy,&advance)==-1) {
            printf("%s\n",TTF_GetError());
            return;
        }
        else {
            if(maxy > max_y)
                max_y = maxy;
            if(advance > max_advance)
                max_advance = advance;

            if(width + max_advance > (w-25)) {
                width = x;
                buffer[index][offset] = 0;
                ++index;
                offset = 0;
                ypos += max_advance+max_y;
            } else {
                buffer[index][offset++] = src[pos++];
                width += advance;
            }
        }
        
    }
    buffer[index][offset] = 0;
    int yy = y;
    for (int i = 0; i <= index; ++i) {
        if(strlen(buffer[i]) > 0)
            printtext(ren, font, buffer[i], x, yy, r, g, b);
        yy += max_advance+max_y;
    }

    static int flash = 0;
    if(blink == 1 && ++flash > 15) {
        SDL_Rect rc = {width, ypos, 8, max_y+max_advance};
        SDL_SetRenderDrawColor(ren, 255, 255, 255, 255);
        SDL_RenderFillRect(ren, &rc);
        flash = 0;
    }
}

SDL_Event e;
int active = 1;
SDL_Window *main_window = NULL;

void cleanup_resources();

void procEvent() {
    if(!active) {
        cleanup_resources();
        emscripten_cancel_main_loop();
        return;
    }
    if(SDL_PollEvent(&e)) {
        switch(e.type) {
            case SDL_QUIT:
                active = 0;
                break;

            case SDL_TEXTINPUT: {
                if(show_words == 2) {
                    for(int i = 0; i < strlen(e.text.text); ++i) {
                        int keycode = e.text.text[i];
                        if(isalpha(keycode) || keycode == '\'' || keycode == '\"' || keycode == ' ') {
                                rem_addchar(&rem, keycode);
                        } 
                    }
                }
            }
                break;
        
            case SDL_KEYDOWN: {
                    if(e.key.keysym.sym == SDLK_ESCAPE) {
                        active = 0;
                        break;
                    }                   

                    if(show_words == 0) {
                        if(e.key.keysym.sym == SDLK_SPACE) {
                            show_words = 1;
                            time_ticks = SDL_GetTicks();
                            break;
                        }
                    break;
                    } else if(show_words == 3) {
                        if(e.key.keysym.sym == SDLK_SPACE) {
                            show_words = 0;
                            rem_restart(&rem);
                            rem_genwords(&rem);
                            timeout += 5;
                            break;
                        }
                        break;
                    } else if(show_words == 4) {
                        show_words = 0;
                        rem_restart(&rem);
                        rem.count = 1;
                        rem_genwords(&rem);
                        timeout = 15;
                        if(argc >= 2) 
                        timeout = atoi(argv[1]);
                        break;
                    } else if(show_words == 2) {
                    int keycode = e.key.keysym.sym;
                    if(keycode == SDLK_RETURN) {
                        if(rem_compare(&rem)) {
                                show_words = 3;
                        } else {
                                show_words = 4;
                            }
                    }
                    
                    if(keycode == SDLK_BACKSPACE) {
                        if(rem.pos > 0)
                            rem_delchar(&rem);
                    }
                }
            }
                break;
        }
    }
    SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
    SDL_RenderClear(ren);
    switch(show_words) {
        case 0: {
            char buffer[1024];
            sprintf(buffer, "Remember these %d words: (Press Space to Start)", rem.count-1);
            printtext(ren, font, buffer, 25, 25, 255, 0, 0);
            printtext_width(ren, font, 0, rem.match_buffer, 25, 60, width, 0, 255, 0);
        }
            break;
        case 1: {

            char buffer[1024];
            unsigned int cur_ticks = SDL_GetTicks();
            unsigned int diff_time = cur_ticks - time_ticks;
            static unsigned int num = 0;
            num += diff_time;
            int wait_ticks = timeout-(num/1000);
            time_ticks = cur_ticks;
            if(wait_ticks <= 0) {
                show_words = 2;
                num = 0;
            }
            sprintf(buffer, "Wait for %d Seconds then Retype the Text as you saw it...", wait_ticks);
            printtext(ren, font, buffer, 25, 25, 0, 0, 255);
        }
            break;
        case 2:
            printtext(ren, font, "Enter the words Exactly as you saw and press Enter", 25, 25, 255, 0, 255);
            printtext_width(ren, font, 1, rem.buffer, 25, 60, width, 255, 255, 255);
            break;
        case 3:
            printtext(ren, font, "You are Correct! Press Space to Continue....", 25, 25, 0, 255, 255);
            break;
        case 4:
            printtext(ren, font, "You are incorrect Press Space to Start Over...", 25, 25, 255, 255, 0);
        break;
    }
    SDL_RenderPresent(ren);
}
   
/* main function - entry point */
int main(int argc_x, char **argv_x) {
    argc = argc_x;
    argv = argv_x;
    srand((unsigned int)time(0));
    printf("Program Usage:\n%s: timeout words_list.txt font_size width height\n", argv[0]);
    if(SDL_Init(SDL_INIT_VIDEO) < 0) {
        fprintf(stderr, "Error: %s\n", SDL_GetError());
        return EXIT_FAILURE;
    }

    if(argc >= 4)
        font_size = atoi(argv[3]);

    if(argc >= 6) {
        width = atoi(argv[4]);
        height = atoi(argv[5]);
    }
    
    TTF_Init();

    main_window = SDL_CreateWindow("Remember Words", 0, 0, width, height, SDL_WINDOW_SHOWN);
    if(!main_window) {
        fprintf(stderr, "Error creating Window: %s", SDL_GetError());
        SDL_Quit();
        return EXIT_FAILURE;
    }

    font = TTF_OpenFont(get_path("font.ttf"), font_size);

    if(font == NULL) {
        fprintf(stderr, "Error loading font ./data/font.ttf %s\n", SDL_GetError());
        SDL_Quit();
        return EXIT_FAILURE;
    }
    
    ren = SDL_CreateRenderer(main_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    
    if(ren == NULL) {
	fprintf(stderr, "Error creating renderer: %s\n", SDL_GetError());
        SDL_Quit();
        return EXIT_FAILURE;
    }

    rem_init(&rem);
    
    if(argc >= 3)
        rem_buildlist(&rem, argv[2]);
    else
        rem_buildlist(&rem, get_path("list.txt"));

    rem_genwords(&rem);
    int active = 1;
    SDL_Event e;

    if(argc >= 2) {
        timeout = atoi(argv[1]);
    }

    SDL_StartTextInput();

#ifndef __EMSCRIPTEN__
    while(active == 1) {
        while(SDL_PollEvent(&e)) {
            switch(e.type) {
                case SDL_QUIT:
                    active = 0;
                    break;

                case SDL_TEXTINPUT: {
                    if(show_words == 2) {
                        for(int i = 0; i < strlen(e.text.text); ++i) {
                            int keycode = e.text.text[i];
                            if(isalpha(keycode) || keycode == ' ') {
                                    rem_addchar(&rem, keycode);
                            } 
                        }
                    }
                }
                    break;
          
                case SDL_KEYDOWN: {
                     if(e.key.keysym.sym == SDLK_ESCAPE) {
                         active = 0;
                         break;
                     }                   

                     if(show_words == 0) {
                         if(e.key.keysym.sym == SDLK_SPACE) {
                             show_words = 1;
                             time_ticks = SDL_GetTicks();
                             break;
                         }
                        break;
                     } else if(show_words == 3) {
                         if(e.key.keysym.sym == SDLK_SPACE) {
                             show_words = 0;
                             rem_restart(&rem);
                             rem_genwords(&rem);
                             timeout += 5;
                             break;
                         }
                         break;
                     } else if(show_words == 4) {
                         show_words = 0;
                         rem_restart(&rem);
                         rem.count = 1;
                         rem_genwords(&rem);
                         timeout = 15;
                         if(argc >= 2) 
                            timeout = atoi(argv[1]);
                         break;
                     } else if(show_words == 2) {
                        int keycode = e.key.keysym.sym;
                        if(keycode == SDLK_RETURN) {
                            if(rem_compare(&rem)) {
                                 show_words = 3;
                            } else {
                                 show_words = 4;
                             }
                        }
                       
                       if(keycode == SDLK_BACKSPACE) {
                            rem_delchar(&rem);
                        }
                    }
                }
                    break;
            }
        }
        SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
        SDL_RenderClear(ren);
        switch(show_words) {
            case 0: {
                char buffer[1024];
                sprintf(buffer, "Remember these %d words: (Press Space to Start)", rem.count-1);
                printtext(ren, font, buffer, 25, 25, 255, 0, 0);
                printtext_width(ren, font, 0, rem.match_buffer, 25, 60, width, 0, 255, 0);
            }
                break;
            case 1: {

                char buffer[1024];
                unsigned int cur_ticks = SDL_GetTicks();
                unsigned int diff_time = cur_ticks - time_ticks;
                static unsigned int num = 0;
                num += diff_time;
                int wait_ticks = timeout-(num/1000);
                time_ticks = cur_ticks;
                if(wait_ticks <= 0) {
                    show_words = 2;
                    num = 0;
                }
                sprintf(buffer, "Wait for %d Seconds then Retype the Text as you saw it...", wait_ticks);
                printtext(ren, font, buffer, 25, 25, 0, 0, 255);
            }
                break;
            case 2:
                printtext(ren, font, "Enter the words Exactly as you saw and press Enter", 25, 25, 255, 0, 255);
                printtext_width(ren, font, 1, rem.buffer, 25, 60, width, 255, 255, 255);
                break;
            case 3:
                printtext(ren, font, "You are Correct! Press Space to Continue....", 25, 25, 0, 255, 255);
                break;
            case 4:
                printtext(ren, font, "You are incorrect Press Space to Start Over...", 25, 25, 255, 255, 0);
            break;
        }
        SDL_RenderPresent(ren);
    }
#else
    emscripten_set_main_loop(procEvent, 0, 1);
#endif
    return 0;
}

void cleanup_resources() {
    SDL_DestroyRenderer(ren);
    SDL_DestroyWindow(main_window);
    TTF_CloseFont(font);
    TTF_Quit();
    rem_free(&rem);
    SDL_Quit();
}