]> git.cworth.org Git - wordgame/blob - grid.c
Move the main game logic from grid.c to new word-game.c
[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         *s++ = '\n';
101     }
102     *s = '\0';
103 }
104
105 #define SEEN_BIT(x, y) (1 << (4*(y)+(x)))
106 static void
107 board_enumerate (board_t        *board,
108                  int             x,
109                  int             y,
110                  int16_t         seen,
111                  char           *word,
112                  dict_cursor_t   dict_cursor)
113 {
114     char c;
115     int dx, dy;
116
117     if (dict_cursor == DICT_CURSOR_NIL)
118         return;
119
120     if (x < 0 || x >= 4 ||
121         y < 0 || y >= 4 ||
122         seen & SEEN_BIT (x, y))
123     {
124         return;
125     }
126
127     seen |= SEEN_BIT (x, y);
128
129     c = board->letters[y][x];
130     word[strlen (word)] = c;
131     dict_cursor = dict_cursor_next (dict_cursor, c);
132
133     if (c == 'q') {
134         word[strlen (word)] = 'u';
135         dict_cursor = dict_cursor_next (dict_cursor, 'u');
136     }
137
138     if (DICT_ENTRY_IS_WORD (dict_cursor_resolve (dict_cursor)))
139         dict_add_word (board->results, word);
140
141     for (dy = -1; dy <= 1; dy++)
142         for (dx = -1; dx <= 1; dx++)
143             board_enumerate (board, x + dx, y + dy, seen, word, dict_cursor);
144
145     if (c == 'q')
146         word [strlen (word) - 1] = '\0';
147     word [strlen (word) - 1] = '\0';
148 }
149
150 static void
151 board_solve (board_t *board, dict_t *dict, dict_t *solution)
152 {
153     int x, y;
154     int16_t seen = 0;
155     char word[18];
156
157     board->results = solution;
158
159     memset (word, '\0', 18);
160
161     for (y = 0; y < 4; y++)
162         for (x = 0; x < 4; x++)
163             board_enumerate (board, x, y, seen, word, dict_root (dict));
164 }
165
166 #define GAME_LENGTH (3 * 60)
167 int
168 main (void)
169 {
170     dict_t dict, solution;
171     board_t board;
172     char board_string[BOARD_STRING_MAX];
173     struct timeval tv;
174
175     gettimeofday (&tv, NULL);
176     srand (tv.tv_sec ^ tv.tv_usec);
177
178     dict_init (&dict);
179     dict_add_words_from_file (&dict, "words.txt");
180
181     board_init (&board);
182     board_to_string (&board, board_string);
183
184     dict_init (&solution);
185     board_solve (&board, &dict, &solution);
186
187     word_game_play (board_string, &dict, &solution, GAME_LENGTH);
188
189     dict_fini (&solution);
190     dict_fini (&dict);
191
192     return 0;
193 }