]> git.cworth.org Git - wordgame/blob - grid.c
grid: Don't consider 2-letter words as valid.
[wordgame] / grid.c
1 /*
2  * Copyright © 2006 Carl Worth
3  *
4  * This program is free software; you can redistribute it and\/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA."
17  */
18
19 #include "word-game.h"
20
21 #include <string.h>
22 #include <ctype.h>
23 #include <sys/time.h>
24 #include <time.h>
25
26 char *cube_faces[16] = {
27     "aaeeng", "abbjoo", "achops", "affkps",
28     "aoottw", "cimotu", "deilrx", "delrvy",
29     "distty", "eeghnw", "eeinsu", "ehrtvw",
30     "eiosst", "elrtty", "himnqu", "hlnnrz"
31 };
32
33 typedef struct _board {
34     char letters[4][4];
35
36     /* Private, transient state used by enumerate */
37     dict_t *results;
38 } board_t;
39
40 static int
41 rand_within (int num_values)
42 {
43     return (int) ((double) num_values * (rand() / (RAND_MAX + 1.0)));
44 }
45
46 static void
47 shuffle (int *array, int length)
48 {
49     int i, r, tmp;
50
51     for (i = 0; i < length; i++)
52     {
53         r = i + rand_within (length - i);
54         tmp = array[i];
55         array[i] = array[r];
56         array[r] = tmp;
57     }
58 }
59
60 static void
61 board_init (board_t *board)
62 {
63     int i;
64     int cubes[16];
65
66     for (i = 0; i < 16; i++)
67         cubes[i] = i;
68     shuffle (cubes, 16);
69  
70     for (i = 0; i < 16; i++)
71         board->letters[i / 4][i % 4] = cube_faces[cubes[i]][rand_within(6)];
72 }
73
74 /* (  3 chars per cell
75  *  x 4 cells per row
76  *  + 1 newline per row
77  * ) x 4 rows per board
78  *   + 1 terminator character
79  * = 53
80  */
81 #define BOARD_STRING_MAX 53
82 static void
83 board_to_string (board_t        *board,
84                  char            board_string[BOARD_STRING_MAX])
85 {
86     char c;
87     int x, y;
88     char *s = &board_string[0];
89
90     for (y = 0; y < 4; y++) {
91         for (x = 0; x < 4; x++) {
92             c = board->letters[y][x];
93             *s++ = ' ';
94             *s++ = toupper (c);
95             if (c == 'q')
96                 *s++ = 'u';
97             else
98                 *s++ = ' ';
99         }
100         if (y != 3)
101             *s++ = '\n';
102     }
103     *s = '\0';
104 }
105
106 #define SEEN_BIT(x, y) (1 << (4*(y)+(x)))
107 static void
108 board_enumerate (board_t        *board,
109                  int             x,
110                  int             y,
111                  int16_t         seen,
112                  char           *word,
113                  dict_cursor_t   dict_cursor)
114 {
115     char c;
116     int dx, dy;
117
118     if (dict_cursor == DICT_CURSOR_NIL)
119         return;
120
121     if (x < 0 || x >= 4 ||
122         y < 0 || y >= 4 ||
123         seen & SEEN_BIT (x, y))
124     {
125         return;
126     }
127
128     seen |= SEEN_BIT (x, y);
129
130     c = board->letters[y][x];
131     word[strlen (word)] = c;
132     dict_cursor = dict_cursor_next (dict_cursor, c);
133
134     if (c == 'q') {
135         word[strlen (word)] = 'u';
136         dict_cursor = dict_cursor_next (dict_cursor, 'u');
137     }
138
139     if (strlen (word) > 2 &&
140         DICT_ENTRY_IS_WORD (dict_cursor_resolve (dict_cursor)))
141     {
142         dict_add_word (board->results, word);
143     }
144
145     for (dy = -1; dy <= 1; dy++)
146         for (dx = -1; dx <= 1; dx++)
147             board_enumerate (board, x + dx, y + dy, seen, word, dict_cursor);
148
149     if (c == 'q')
150         word [strlen (word) - 1] = '\0';
151     word [strlen (word) - 1] = '\0';
152 }
153
154 static void
155 board_solve (board_t *board, dict_t *dict, dict_t *solution)
156 {
157     int x, y;
158     int16_t seen = 0;
159     char word[18];
160
161     board->results = solution;
162
163     memset (word, '\0', 18);
164
165     for (y = 0; y < 4; y++)
166         for (x = 0; x < 4; x++)
167             board_enumerate (board, x, y, seen, word, dict_root (dict));
168 }
169
170 #define GAME_LENGTH (3 * 60)
171 int
172 main (void)
173 {
174     dict_t dict, solution;
175     board_t board;
176     char board_string[BOARD_STRING_MAX];
177     struct timeval tv;
178
179     gettimeofday (&tv, NULL);
180     srand (tv.tv_sec ^ tv.tv_usec);
181
182     dict_init (&dict);
183     dict_add_words_from_file (&dict, "words.txt");
184
185     board_init (&board);
186     board_to_string (&board, board_string);
187
188     dict_init (&solution);
189     board_solve (&board, &dict, &solution);
190
191     word_game_play (board_string, &dict, &solution, GAME_LENGTH);
192
193     dict_fini (&solution);
194     dict_fini (&dict);
195
196     return 0;
197 }