/* * Created by Gregory Gauthier on 06/10/2025. */ /* main.c - Entry point and main game loop */ /* Compile with: gcc -std=c90 -o cordle src\/\*.c -Iinclude -lncurses */ #include #include #include #include #include "../include/platform.h" #include "../include/game.h" #include "../include/words.h" #include "../include/ui.h" /* Parse command line arguments */ static void parse_arguments(int argc, char **argv, char *filename, char *difficulty) { int i; /* Default values */ strcpy(filename, "default.txt"); strcpy(difficulty, "DEFAULT"); for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--easy") == 0) { strcpy(filename, "easy.txt"); strcpy(difficulty, "EASY"); } else if (strcmp(argv[i], "--medium") == 0) { strcpy(filename, "medium.txt"); strcpy(difficulty, "MEDIUM"); } else if (strcmp(argv[i], "--hard") == 0) { strcpy(filename, "hard.txt"); strcpy(difficulty, "HARD"); } else if (strcmp(argv[i], "--techy") == 0) { strcpy(filename, "techy.txt"); strcpy(difficulty, "TECHNICAL"); } else if (strcmp(argv[i], "--literary") == 0) { strcpy(filename, "literary.txt"); strcpy(difficulty, "LITERARY"); } else if (strcmp(argv[i], "--cultural") == 0) { strcpy(filename, "cultural.txt"); strcpy(difficulty, "CULTURAL"); } else if (strcmp(argv[i], "--full") == 0) { strcpy(filename, "full.txt"); strcpy(difficulty, "FULL"); } else if (strcmp(argv[i], "--wordlist") == 0 && i + 1 < argc) { strcpy(filename, argv[i + 1]); strcpy(difficulty, "CUSTOM"); i++; /* Skip next argument */ } } } /* Main game loop */ static int main_game_loop(int argc, char *argv[]) { WINDOW *stdscr; static GameState game; /* static to avoid stack overflow on DOS */ char filename[MAX_FILENAME]; char difficulty[32]; char message[MAX_MESSAGE] = ""; int message_color = COLOR_DEFAULT; int height, y_pos; int key; char temp_guess[WORD_LENGTH + 1]; char win_message[MAX_MESSAGE]; /* Get command line arguments */ parse_arguments(argc, argv, filename, difficulty); #ifdef PLATFORM_DOS /* DEBUG: Print progress before curses takes over */ printf("DEBUG: Parsed args, file=%s\n", filename); printf("DEBUG: Calling initscr()...\n"); #endif /* Initialize ncurses */ stdscr = initscr(); #ifdef PLATFORM_DOS /* DEBUG: If we get here, initscr worked */ mvaddstr(0, 0, "DEBUG: initscr() OK"); refresh(); #endif noecho(); /* Don't echo typed characters */ cbreak(); /* Disable line buffering */ curs_set(0); #ifdef PLATFORM_DOS /* PDCurses on DOS: disable keypad to avoid escape sequence delays */ keypad(stdscr, FALSE); /* Allow Ctrl+Break to work properly */ raw(); mvaddstr(1, 0, "DEBUG: curses init OK, loading words..."); refresh(); #else keypad(stdscr, TRUE); /* Enable special key detection */ #endif clear(); /* Initialize colors */ start_color(); init_pair(COLOR_DEFAULT, COLOR_WWHITE, COLOR_BLACK); init_pair(COLOR_CORRECT, COLOR_BLACK, COLOR_GREEN); init_pair(COLOR_PRESENT, COLOR_BLACK, COLOR_YELLOW); init_pair(COLOR_ABSENT, COLOR_WWHITE, COLOR_RED); init_pair(COLOR_WWHITE, COLOR_WWHITE, COLOR_BLACK); init_pair(COLOR_UNUSED, COLOR_WWHITE, COLOR_BLACK); /* Initialize game */ init_game(&game); #ifdef PLATFORM_DOS mvaddstr(0, 0, "DEBUG: Loading words..."); refresh(); #endif if (!load_words(&game, filename)) { /* Try fallback */ if (strcmp(filename, "default.txt") != 0 && load_words(&game, "default.txt")) { strcpy(difficulty, "DEFAULT"); } else { mvaddstr(0, 0, "Error: Could not load word list"); mvaddstr(1, 0, "Press any key to exit..."); getch(); endwin(); return 1; } } /* Main game loop */ while (1) { clear(); getmaxyx(stdscr, height, y_pos); y_pos = 1; /* Draw components */ draw_title(stdscr, y_pos, difficulty); y_pos += 2; draw_board(stdscr, &game, y_pos); y_pos += MAX_GUESSES * 2 + 1; draw_keyboard(stdscr, &game, y_pos); y_pos += 4; /* Draw message if exists */ if (strlen(message) > 0) { draw_message(stdscr, message, y_pos, message_color); y_pos += 2; } /* Draw instructions */ if (y_pos + 6 < height) { draw_instructions(stdscr, y_pos); } /* Handle game over */ if (game.game_over) { y_pos = (height > 20) ? height - 3 : y_pos; if (game.won) { sprintf(win_message, "Congratulations! You won in %d guesses!", game.guess_count); draw_message(stdscr, win_message, y_pos, COLOR_CORRECT); } else { sprintf(win_message, "Game Over! The word was: %s", game.target_word); draw_message(stdscr, win_message, y_pos, COLOR_ABSENT); } draw_message(stdscr, "Press 'N' for new game or 'Q' to quit", y_pos + 1, COLOR_DEFAULT); refresh(); key = getch(); if (key == 'n' || key == 'N') { /* Start new game */ init_game(&game); load_words(&game, filename); strcpy(message, ""); continue; } else if (key == 'q' || key == 'Q' || key == 27) { break; } continue; } refresh(); /* Get input */ key = getch(); /* Handle input */ if (key == 27) { /* ESC */ break; } else if (key == KEY_UP || key == KEY_DOWN || key == KEY_LEFT || key == KEY_RIGHT) { /* Ignore arrow keys to prevent crashes */ continue; } else if (key == '\n' || key == '\r' || key == KEY_ENTER) { if (game.current_guess_length == WORD_LENGTH) { strcpy(temp_guess, game.current_guess); if (make_guess(&game, temp_guess)) { game.current_guess[0] = '\0'; game.current_guess_length = 0; strcpy(message, ""); } else { /* Validation failed in make_guess or is_valid_word */ strcpy(message, "Not in word list!"); message_color = COLOR_ABSENT; } } else { sprintf(message, "Word must be %d letters!", WORD_LENGTH); message_color = COLOR_ABSENT; } } else if (key == KEY_BACKSPACE || key == 127 || key == '\b') { if (game.current_guess_length > 0) { game.current_guess_length--; game.current_guess[game.current_guess_length] = '\0'; strcpy(message, ""); } } else if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) { if (game.current_guess_length < WORD_LENGTH) { game.current_guess[game.current_guess_length] = toupper((unsigned char)key); game.current_guess_length++; game.current_guess[game.current_guess_length] = '\0'; strcpy(message, ""); } } } endwin(); return 0; } /* Main entry point */ int main(int argc, char *argv[]) { int i; /* Handle help */ for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { printf("cordle - C90 Wordle Game\n\n"); printf("Usage: %s [OPTIONS]\n\n", argv[0]); printf("Difficulty Levels:\n"); printf(" --easy Common everyday words (default)\n"); printf(" --medium Standard vocabulary\n"); printf(" --hard Challenging words\n\n"); printf("Word Categories:\n"); printf(" --techy Technical and scientific terms\n"); printf(" --literary Literary and archaic terms\n"); printf(" --cultural Cultural and international terms\n"); printf(" --full Complete dictionary\n\n"); printf("Custom:\n"); printf(" --wordlist FILE Use custom word list\n\n"); printf("Examples:\n"); printf(" %s --easy\n", argv[0]); printf(" %s --techy\n", argv[0]); printf(" %s --wordlist mywords.txt\n", argv[0]); return 0; } } return main_game_loop(argc, argv); }