From 352e7bb836a852c4df6810e6be58990f602cf7a1 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Sat, 23 Sep 2006 00:26:27 -0700 Subject: [PATCH] Move the main game logic from grid.c to new word-game.c The idea here is to make it very easy to have many games which are basically variations of the same theme. --- Makefile | 2 +- dict.c | 8 +-- dict.h | 4 ++ grid.c | 159 ++++++++++------------------------------------------ word-game.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++ word-game.h | 32 +++++++++++ 6 files changed, 226 insertions(+), 137 deletions(-) create mode 100644 word-game.c create mode 100644 word-game.h diff --git a/Makefile b/Makefile index 270b2ef..2e1e7e0 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ WGCFLAGS=-Wall -Wextra -Wmissing-prototypes -Wno-unused-parameter PROGRAMS=grid all: $(PROGRAMS) -LIBRARY=dict.o +LIBRARY=dict.o word-game.o grid: grid.o $(LIBRARY) $(CC) $(CFLAGS) $(WGCFLAGS) $(LDFLAGS) -lreadline -lm -o $@ $^ diff --git a/dict.c b/dict.c index cef51d4..a920293 100644 --- a/dict.c +++ b/dict.c @@ -16,16 +16,12 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." */ -/* Portably, schmortability. I want ease of programming. */ -#define _GNU_SOURCE -#include -#include +#include "dict.h" + #include #include #include -#include "dict.h" - typedef struct _string { size_t size; char *s; diff --git a/dict.h b/dict.h index d5aa1cd..af21015 100644 --- a/dict.h +++ b/dict.h @@ -19,6 +19,10 @@ #ifndef _DICT_H_ #define _DICT_H_ +/* Portably, schmortability. I want ease of programming. */ +#define _GNU_SOURCE +#include +#include #include #ifndef FALSE diff --git a/grid.c b/grid.c index 0ebd786..ed88df3 100644 --- a/grid.c +++ b/grid.c @@ -16,20 +16,12 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." */ -#include -#include +#include "word-game.h" + +#include #include #include #include -#include - -#include -#include - -#include "dict.h" - -/* Remember that dict reserves the 0th bit for IS_WORD */ -#define GRID_WORD_SEEN (1<<1) char *cube_faces[16] = { "aaeeng", "abbjoo", "achops", "affkps", @@ -79,22 +71,35 @@ board_init (board_t *board) board->letters[i / 4][i % 4] = cube_faces[cubes[i]][rand_within(6)]; } +/* ( 3 chars per cell + * x 4 cells per row + * + 1 newline per row + * ) x 4 rows per board + * + 1 terminator character + * = 53 + */ +#define BOARD_STRING_MAX 53 static void -board_print (board_t *board) +board_to_string (board_t *board, + char board_string[BOARD_STRING_MAX]) { - int x, y; char c; + int x, y; + char *s = &board_string[0]; - printf ("\n"); for (y = 0; y < 4; y++) { for (x = 0; x < 4; x++) { c = board->letters[y][x]; - printf (" %c%s", toupper (c), - c == 'q' ? "u" : " "); + *s++ = ' '; + *s++ = toupper (c); + if (c == 'q') + *s++ = 'u'; + else + *s++ = ' '; } - printf ("\n"); + *s++ = '\n'; } - printf ("\n"); + *s = '\0'; } #define SEEN_BIT(x, y) (1 << (4*(y)+(x))) @@ -158,136 +163,30 @@ board_solve (board_t *board, dict_t *dict, dict_t *solution) board_enumerate (board, x, y, seen, word, dict_root (dict)); } -static bool_t -seen_predicate (dict_entry_t entry) -{ - return entry & GRID_WORD_SEEN; -} - -static bool_t -unseen_predicate (dict_entry_t entry) -{ - return ! seen_predicate (entry); -} - -static void -_count_possible (dict_cursor_t cursor, - int depth, - int possible[17]) -{ - char c; - - if (cursor == DICT_CURSOR_NIL) - return; - - if (DICT_ENTRY_IS_WORD (dict_cursor_resolve (cursor))) - possible[depth]++; - - for (c = 'a'; c <= 'z'; c++) - _count_possible (dict_cursor_next (cursor, c), depth + 1, possible); -} - #define GAME_LENGTH (3 * 60) int main (void) { - int i; dict_t dict, solution; board_t board; - struct timeval tv, tv_stop; - int remaining, minutes, seconds; - /* 16 tiles + Qu on one tile = max 17 letters in one word. */ - int found[17], possible[17]; - int found_total, possible_total; - char prompt[7], *response; - bool_t just_saw_board; + char board_string[BOARD_STRING_MAX]; + struct timeval tv; gettimeofday (&tv, NULL); srand (tv.tv_sec ^ tv.tv_usec); dict_init (&dict); dict_add_words_from_file (&dict, "words.txt"); + board_init (&board); + board_to_string (&board, board_string); dict_init (&solution); board_solve (&board, &dict, &solution); - for (i=0; i < 17; i++) { - found[i] = 0; - possible[i] = 0; - } - _count_possible (dict_root (&solution), 0, possible); - found_total = 0; - possible_total = 0; - for (i=0; i < 17; i++) - possible_total += possible[i]; - - board_print (&board); - just_saw_board = TRUE; - - gettimeofday (&tv, NULL); - tv_stop = tv; - tv_stop.tv_sec += GAME_LENGTH; - remaining = GAME_LENGTH; - do { - minutes = remaining / 60; - seconds = remaining % 60; - sprintf (prompt, "%02d:%02d ", minutes, seconds); - response = readline (prompt); - add_history (response); - if (strlen (response) == 0) { - if (! just_saw_board) { - board_print (&board); - just_saw_board = TRUE; - } else { - for (i = 2; i <= 17; i++) - if (possible[i]) - printf ("%d: (%d/%d) ", i, found[i], possible[i]); - printf ("total: (%d/%d = %.2f%%)\n", - found_total, possible_total, - 100 * (double) found_total / possible_total); - } - } else { - dict_entry_t *entry; - just_saw_board = FALSE; - if (response[strlen (response) - 1] == '\n') - response[strlen (response) - 1] = '\0'; - entry = dict_lookup (&solution, response); - if (DICT_ENTRY_IS_WORD (entry)) { - if (*entry & GRID_WORD_SEEN) { - printf ("(repeat)\n"); - } else { - *entry |= GRID_WORD_SEEN; - found [strlen (response)]++; - found_total++; - } - } else { - entry = dict_lookup (&dict, response); - if (DICT_ENTRY_IS_WORD (entry)) - printf ("(a good word, but it's not in the puzzle)\n"); - else - printf ("*** %s is not a word\n", response); - } - } - free (response); - gettimeofday (&tv, NULL); - remaining = floor (0.5 + (tv_stop.tv_sec - tv.tv_sec) + (tv_stop.tv_usec - tv.tv_usec) / 1000000.0); - minutes = remaining / 60; - } while (remaining > 0); - - board_print (&board); - - printf ("Words you found:\n"); - dict_print_by_length_if (&solution, seen_predicate); - - printf ("\nWords you missed:\n"); - dict_print_by_length_if (&solution, unseen_predicate); - printf ("\n"); - - printf ("You found %d of %d words (%.2f%%)\n", - found_total, possible_total, - 100 * (double) found_total / possible_total); + word_game_play (board_string, &dict, &solution, GAME_LENGTH); + dict_fini (&solution); dict_fini (&dict); return 0; diff --git a/word-game.c b/word-game.c new file mode 100644 index 0000000..29cf01b --- /dev/null +++ b/word-game.c @@ -0,0 +1,158 @@ +/* + * Copyright © 2006 Carl Worth + * + * This program is free software; you can redistribute it and\/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." + */ + +#include "word-game.h" + +#include +#include +#include + +#include +#include + +/* Remember that dict reserves the 0th bit for IS_WORD */ +#define GAME_WORD_SEEN (1<<1) + +static bool_t +seen_predicate (dict_entry_t entry) +{ + return entry & GAME_WORD_SEEN; +} + +static bool_t +unseen_predicate (dict_entry_t entry) +{ + return ! seen_predicate (entry); +} + +static void +_count_possible (dict_cursor_t cursor, + int depth, + int possible[17]) +{ + char c; + + if (cursor == DICT_CURSOR_NIL) + return; + + if (DICT_ENTRY_IS_WORD (dict_cursor_resolve (cursor))) + possible[depth]++; + + for (c = 'a'; c <= 'z'; c++) + _count_possible (dict_cursor_next (cursor, c), depth + 1, possible); +} + +void +word_game_play (const char *puzzle, + dict_t *dict, + dict_t *answers, + int time_limit_seconds) +{ + int i; + struct timeval tv, tv_stop; + int remaining, minutes, seconds; + char prompt[7], *response; + bool_t just_saw_puzzle; + int found[WORD_GAME_MAX_WORD_LENGTH+1]; + int possible[WORD_GAME_MAX_WORD_LENGTH+1]; + int found_total, possible_total; + + for (i=0; i < WORD_GAME_MAX_WORD_LENGTH+1; i++) { + found[i] = 0; + possible[i] = 0; + } + _count_possible (dict_root (answers), 0, possible); + found_total = 0; + possible_total = 0; + for (i=0; i < 17; i++) + possible_total += possible[i]; + + printf ("%s\n", puzzle); + just_saw_puzzle = TRUE; + + remaining = time_limit_seconds; + if (time_limit_seconds) { + gettimeofday (&tv, NULL); + tv_stop = tv; + tv_stop.tv_sec += time_limit_seconds; + } else { + sprintf (prompt, "> "); + } + do { + if (time_limit_seconds) { + minutes = remaining / 60; + seconds = remaining % 60; + sprintf (prompt, "%02d:%02d ", minutes, seconds); + } + response = readline (prompt); + add_history (response); + if (strlen (response) == 0) { + if (! just_saw_puzzle) { + printf ("%s\n", puzzle); + just_saw_puzzle = TRUE; + } else { + for (i = 2; i <= 17; i++) + if (possible[i]) + printf ("%d:(%d/%d) ", i, found[i], possible[i]); + printf ("total:(%d/%d = %.2f%%)\n", + found_total, possible_total, + 100 * (double) found_total / possible_total); + } + } else { + dict_entry_t *entry; + just_saw_puzzle = FALSE; + if (response[strlen (response) - 1] == '\n') + response[strlen (response) - 1] = '\0'; + entry = dict_lookup (answers, response); + if (DICT_ENTRY_IS_WORD (entry)) { + if (*entry & GAME_WORD_SEEN) { + printf ("(repeat)\n"); + } else { + *entry |= GAME_WORD_SEEN; + found [strlen (response)]++; + found_total++; + } + } else { + entry = dict_lookup (dict, response); + if (DICT_ENTRY_IS_WORD (entry)) + printf ("(a good word, but it's not in the puzzle)\n"); + else + printf ("*** %s is not a word\n", response); + } + } + free (response); + if (time_limit_seconds) { + gettimeofday (&tv, NULL); + remaining = floor (0.5 + (tv_stop.tv_sec - tv.tv_sec) + (tv_stop.tv_usec - tv.tv_usec) / 1000000.0); + minutes = remaining / 60; + } + } while (remaining > 0); + + printf ("%s\n", puzzle); + + printf ("Words you found:\n"); + dict_print_by_length_if (answers, seen_predicate); + + printf ("\nWords you missed:\n"); + dict_print_by_length_if (answers, unseen_predicate); + printf ("\n"); + + printf ("You found %d of %d words (%.2f%%)\n", + found_total, possible_total, + 100 * (double) found_total / possible_total); +} diff --git a/word-game.h b/word-game.h new file mode 100644 index 0000000..063d299 --- /dev/null +++ b/word-game.h @@ -0,0 +1,32 @@ +/* + * Copyright © 2006 Carl Worth + * + * This program is free software; you can redistribute it and\/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA." + */ + +#ifndef _WORD_GAME_H_ +#define _WORD_GAME_H_ + +#include "dict.h" + +#define WORD_GAME_MAX_WORD_LENGTH 15 + +void +word_game_play (const char *puzzle, + dict_t *dict, + dict_t *answers, + int time_limit_seconds); + +#endif /* _WORD_GAME_H_ */ -- 2.43.0