Added freeze/unfreeze grid functionality
[wordblah.git] / wordblox.h
1 #ifndef __WORDBLOX_H
2 #define __WORDBLOX_H
3
4 #include "constantstrings.h"
5
6 #define MAX_PUZZLE_SIZE 20
7 #define MAX_CLUE_LENGTH 150
8
9 /* Enum to define terminal colours */
10 enum COLOR {
11 BLACK = 0,
12 RED= 1,
13 GREEN=2,
14 YELLOW=3,
15 BLUE=4,
16 MAGENTA=5,
17 CYAN=6,
18 WHITE=7
19 };
20
21 typedef char String[MAX_CLUE_LENGTH];
22
23 /* The main puzzle struct type */
24 typedef struct {
25 char chars[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
26 int start_across_word[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
27 int start_down_word[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
28 String clue_across[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
29 String clue_down[MAX_PUZZLE_SIZE][MAX_PUZZLE_SIZE];
30 int grid_size;
31 bool grid_frozen;
32 } Puzzle;
33
34 int get_num ()
35 {
36 char s[5];
37 fgets (s, 5, stdin);
38 int n = atoi (s);
39 return n;
40 }
41
42 /* Set the terminal colour */
43 void set_color (enum COLOR fg, enum COLOR bg) {
44 printf ("\x1B[%d;%dm", fg+30, bg+40);
45 }
46
47 /* Reset the terminal colour */
48 void reset_color () {
49 printf ("\x1B[0m");
50 }
51
52 /* check if previous row is blank or not */
53 bool prev_row_blank (Puzzle *p, int r, int c)
54 {
55 if (r == 0) return true;
56 if (p->chars[r-1][c] == ' ' || p->chars[r-1][c] == '#') return true;
57 return false;
58 }
59 /* check if next row is blank or not */
60 bool next_row_blank (Puzzle *p, int r, int c)
61 {
62 if (r == p->grid_size - 1) return true;
63 if (p->chars[r+1][c] == ' ' || p->chars[r+1][c] == '#') return true;
64 return false;
65 }
66 /* check if previous col is blank or not */
67 bool prev_col_blank (Puzzle *p, int r, int c)
68 {
69 if (c == 0) return true;
70 if (p->chars[r][c-1] == ' ' || p->chars[r][c-1] == '#') return true;
71 return false;
72 }
73 /* check if the next col is blank or not */
74 bool next_col_blank (Puzzle *p, int r, int c)
75 {
76 if (c == p->grid_size -1) return true;
77 if (p->chars[r][c+1] == ' ' || p->chars[r][c+1] == '#') return true;
78 return false;
79 }
80
81 /* unfreeze the grid - mak editing possible to change words */
82 void unfreeze_puzzle (Puzzle *p)
83 {
84 for (int i = 0; i < p->grid_size; i ++)
85 {
86 for (int j = 0; j < p->grid_size; j ++)
87 {
88 if (p->chars[i][j] == '#')
89 p->chars[i][j] = ' ';
90
91 p->start_across_word[i][j] = -1;
92 p->start_down_word[i][j] = -1;
93 }
94 }
95 p->grid_frozen = false;
96 }
97
98 /* freeze the grid - make editing impossible because it finalizes the
99 across and down words in the grid */
100 void freeze_puzzle (Puzzle *p)
101 {
102 int word_num = 1;
103 bool across_word_start, down_word_start;
104 for (int i = 0; i < p->grid_size; i ++)
105 {
106 for (int j = 0; j < p->grid_size; j++)
107 {
108 across_word_start = false;
109 down_word_start = false;
110 /* if it is a blank cell - cover it with a block */
111 if (p->chars[i][j] == ' ')
112 p->chars[i][j] = '#';
113 /* it is not a blank cell - check all possibilities */
114 else
115 {
116 bool prev_row = prev_row_blank (p, i, j);
117 bool next_row = next_row_blank (p, i, j);
118 bool prev_col = prev_col_blank (p, i, j);
119 bool next_col = next_col_blank (p, i, j);
120 if (prev_row && ! next_row)
121 down_word_start = true;
122 if (prev_col && ! next_col)
123 across_word_start = true;
124 }
125
126 if (across_word_start == true)
127 p->start_across_word[i][j] = word_num;
128 else
129 p->start_across_word[i][j] = -1;
130 if (down_word_start == true)
131 p->start_down_word[i][j] = word_num;
132 else
133 p->start_down_word[i][j] = -1;
134 if (across_word_start == true || down_word_start == true)
135 word_num ++;
136 }
137 }
138 p->grid_frozen = true;
139 }
140
141 /* reset the entire grid */
142 void init_puzzle (Puzzle *p, int grid_size)
143 {
144 p->grid_size = grid_size;
145 p->grid_frozen = false;
146 for (int i = 0; i < p->grid_size; i ++)
147 {
148 for (int j = 0; j < p->grid_size; j ++)
149 {
150 p->chars[i][j] = ' ';
151 p->start_across_word[i][j] = -1;
152 p->start_down_word[i][j] = -1;
153 strcpy (p->clue_across[i][j], "");
154 strcpy (p->clue_down[i][j], "");
155 }
156 }
157 }
158
159 /* save the puzzle */
160 void save_puzzle (Puzzle *puzzle, const char* file) {
161 FILE *outfile;
162 outfile = fopen (file, "wb");
163 if (outfile == NULL)
164 {
165 fprintf (stderr, "%s\n", ERROR_WRITING_FILE);
166 exit (1);
167 }
168 fwrite (puzzle, sizeof (*puzzle), 1, outfile);
169 fclose (outfile);
170 }
171
172 /* read the puzzle */
173 Puzzle load_puzzle (const char* file) {
174 FILE *infile;
175 Puzzle p;
176 infile = fopen (file, "rb");
177 if (infile == NULL)
178 {
179 fprintf (stderr, "%s\n", ERROR_READING_FILE);
180 exit (1);
181 }
182 fread (&p, sizeof(p), 1, infile);
183 fclose (infile);
184 return p;
185 }
186
187 /* display the puzzle */
188 void print_puzzle (Puzzle *p)
189 {
190 printf ("\n");
191 set_color (WHITE, CYAN);
192 printf (" ");
193 for (int i = 0; i < p->grid_size; i ++)
194 printf ("%3d", i);
195 reset_color ();
196 printf("\n");
197 for (int i = 0; i < p->grid_size; i ++)
198 {
199 set_color (WHITE, CYAN);
200 printf ("%3d ", i);
201 for (int j = 0; j < p->grid_size; j ++)
202 {
203 if (p->chars[i][j] == '#') {
204 set_color (WHITE, BLACK);
205 printf (" ");
206 }
207 else
208 {
209 if (p->start_across_word[i][j] != -1 ||
210 p->start_down_word[i][j] != -1)
211 {
212 set_color (BLUE, WHITE);
213 if (p->start_across_word[i][j] != -1)
214 printf ("%-2d", p->start_across_word[i][j]);
215 else
216 printf ("%-2d", p->start_down_word[i][j]);
217 }
218 else
219 {
220 set_color (BLACK, WHITE);
221 printf (" ");
222 }
223
224 set_color (BLACK, WHITE);
225 printf ("%c", p->chars[i][j]);
226 }
227 reset_color ();
228 }
229 printf ("\n");
230 }
231 /* print the clues if set */
232 if (p->grid_frozen == true)
233 {
234 printf ("ACROSS - CLUES\n");
235 for (int i = 0; i < p->grid_size; i ++)
236 {
237 for (int j = 0; j < p->grid_size; j ++)
238 {
239 if (p->start_across_word[i][j] != -1)
240 {
241 printf ("%d - %s; ", p->start_across_word[i][j],
242 p->clue_across[i][j]);
243 }
244 }
245 }
246 printf ("\nDOWN - CLUES\n");
247 for (int i = 0; i < p->grid_size; i ++)
248 {
249 for (int j = 0; j < p->grid_size; j ++)
250 {
251 if (p->start_down_word[i][j] != -1)
252 {
253 printf ("%d - %s; ", p->start_down_word[i][j],
254 p->clue_down[i][j]);
255 }
256 }
257 }
258 printf ("\n");
259 }
260 }
261
262 /* function to check if a word is valid or not */
263 bool is_valid_word (const char *word)
264 {
265 for (int i = 0; i < strlen (word); i ++)
266 if (! isalpha (word[i]))
267 return false;
268
269 return true;
270 }
271
272 /* function set a clue for an across word */
273 bool set_across_clue (Puzzle *p, String clue, int index)
274 {
275 for (int i = 0; i < p->grid_size; i ++)
276 {
277 for (int j = 0; j < p->grid_size; j ++)
278 {
279 if (p->start_across_word[i][j] == index)
280 {
281 strcpy (p->clue_across[i][j], clue);
282 return true;
283 }
284 }
285 }
286 return false;
287 }
288
289 /* function to print a menu */
290 void print_menu (enum COLOR fg, enum COLOR bg, const char* title,
291 char **items, int num_items, int padding)
292 {
293 /* clear screen */
294 printf ("\e[1;1H\e[2J");
295 set_color (fg, bg);
296 printf ("\u2554");
297 for (int i = 0; i < padding; i ++)
298 printf ("\u2550");
299 printf ("\u2557");
300 reset_color (); printf ("\n");
301 set_color (fg, bg);
302 printf ("\u2551%-*s\u2551", padding, title);
303 reset_color (); printf ("\n");
304 set_color (fg, bg);
305 printf ("\u2560");
306 for (int i = 0; i < padding; i ++)
307 printf ("\u2550");
308 printf ("\u2563");
309 reset_color (); printf ("\n");
310 for (int i = 0; i < num_items; i ++)
311 {
312 set_color (fg, bg);
313 printf ("\u2551%-*s\u2551", padding, items[i]);
314 reset_color (); printf ("\n");
315 }
316 set_color (fg, bg);
317 printf ("\u255A");
318 for (int i = 0; i < padding; i ++)
319 printf ("\u2550");
320 printf ("\u255D");
321 reset_color (); printf ("\n");
322 }
323
324 #endif