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