53c522b848ea505391742d373a75c935bedc33f6
7 #include "constantstrings.h"
9 #define MAX_PUZZLE_SIZE 20
10 #define MAX_CLUE_LENGTH 150
12 /* Enum to define terminal colours */
34 typedef char String
[MAX_CLUE_LENGTH
];
36 /* The main puzzle struct type */
38 char chars
[MAX_PUZZLE_SIZE
][MAX_PUZZLE_SIZE
];
39 int start_across_word
[MAX_PUZZLE_SIZE
][MAX_PUZZLE_SIZE
];
40 int start_down_word
[MAX_PUZZLE_SIZE
][MAX_PUZZLE_SIZE
];
41 String clue_across
[MAX_PUZZLE_SIZE
][MAX_PUZZLE_SIZE
];
42 String clue_down
[MAX_PUZZLE_SIZE
][MAX_PUZZLE_SIZE
];
47 /* get a number from the user */
56 /* Output the grid to image - if answerkey is true export filled grid */
57 void export_grid_image (Puzzle
*p
, const char *filename
, bool answerkey
)
59 int img_size
= p
->grid_size
* 40;
60 FILE * outfile
= fopen (filename
, "wb");
63 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
67 gdImagePtr img
= gdImageCreate (img_size
, img_size
);
68 int white
= gdImageColorAllocate (img
, 255,255,255);
69 int black
= gdImageColorAllocate (img
, 0, 0, 0);
70 int blue
= gdImageColorAllocate (img
, 0, 0, 216);
71 gdFontPtr sm_fnt
= gdFontGetMediumBold ();
72 gdFontPtr lg_fnt
= gdFontGetGiant ();
74 for (int i
= 0; i
< p
->grid_size
; i
++)
76 for (int j
= 0; j
< p
->grid_size
; j
++)
78 /* if it is a block, draw the black square */
79 if (p
->chars
[i
][j
] == '#')
80 gdImageFilledRectangle (img
, j
*40, i
*40, j
*40+40,
84 /* draw a regular square */
85 gdImageRectangle (img
, j
*40, i
*40, j
*40+40,
88 /* print the numers, if it is either start across word or
90 if (p
->start_across_word
[i
][j
] != -1 ||
91 p
->start_down_word
[i
][j
] != -1)
93 if (p
->start_across_word
[i
][j
] != -1)
96 sprintf (str
, "%d", p
->start_across_word
[i
][j
]);
97 gdImageString (img
, sm_fnt
, j
*40+2, i
*40+2,
98 (unsigned char *)str
, blue
);
103 sprintf (str
, "%d", p
->start_down_word
[i
][j
]);
104 gdImageString (img
, sm_fnt
, j
*40+2, i
*40+2,
105 (unsigned char *)str
, blue
);
108 /* if answerkey is true, draw the character in the cell */
111 gdImageChar (img
, lg_fnt
, j
*40+15, i
*40+15,
112 p
->chars
[i
][j
], black
);
118 gdImagePng (img
, outfile
);
119 gdImageDestroy (img
);
123 /* Set the terminal colour */
124 void set_color (enum COLOR fg
, enum COLOR bg
, enum ATTR at
) {
125 printf ("\x1B[%d;%d;%dm", fg
+30, bg
+40, at
);
128 /* Reset the terminal colour */
129 void reset_color () {
133 /* check if previous row is blank or not */
134 bool prev_row_blank (Puzzle
*p
, int r
, int c
)
136 if (r
== 0) return true;
137 if (p
->chars
[r
-1][c
] == ' ' || p
->chars
[r
-1][c
] == '#') return true;
140 /* check if next row is blank or not */
141 bool next_row_blank (Puzzle
*p
, int r
, int c
)
143 if (r
== p
->grid_size
- 1) return true;
144 if (p
->chars
[r
+1][c
] == ' ' || p
->chars
[r
+1][c
] == '#') return true;
147 /* check if previous col is blank or not */
148 bool prev_col_blank (Puzzle
*p
, int r
, int c
)
150 if (c
== 0) return true;
151 if (p
->chars
[r
][c
-1] == ' ' || p
->chars
[r
][c
-1] == '#') return true;
154 /* check if the next col is blank or not */
155 bool next_col_blank (Puzzle
*p
, int r
, int c
)
157 if (c
== p
->grid_size
-1) return true;
158 if (p
->chars
[r
][c
+1] == ' ' || p
->chars
[r
][c
+1] == '#') return true;
162 /* unfreeze the grid - mak editing possible to change words */
163 void unfreeze_puzzle (Puzzle
*p
)
165 for (int i
= 0; i
< p
->grid_size
; i
++)
167 for (int j
= 0; j
< p
->grid_size
; j
++)
169 if (p
->chars
[i
][j
] == '#')
170 p
->chars
[i
][j
] = ' ';
172 p
->start_across_word
[i
][j
] = -1;
173 p
->start_down_word
[i
][j
] = -1;
176 p
->grid_frozen
= false;
179 /* freeze the grid - make editing impossible because it finalizes the
180 across and down words in the grid */
181 void freeze_puzzle (Puzzle
*p
)
184 bool across_word_start
, down_word_start
;
185 for (int i
= 0; i
< p
->grid_size
; i
++)
187 for (int j
= 0; j
< p
->grid_size
; j
++)
189 across_word_start
= false;
190 down_word_start
= false;
191 /* if it is a blank cell - cover it with a block */
192 if (p
->chars
[i
][j
] == ' ')
193 p
->chars
[i
][j
] = '#';
194 /* it is not a blank cell - check all possibilities */
197 bool prev_row
= prev_row_blank (p
, i
, j
);
198 bool next_row
= next_row_blank (p
, i
, j
);
199 bool prev_col
= prev_col_blank (p
, i
, j
);
200 bool next_col
= next_col_blank (p
, i
, j
);
201 if (prev_row
&& ! next_row
)
202 down_word_start
= true;
203 if (prev_col
&& ! next_col
)
204 across_word_start
= true;
207 if (across_word_start
== true)
208 p
->start_across_word
[i
][j
] = word_num
;
210 p
->start_across_word
[i
][j
] = -1;
211 if (down_word_start
== true)
212 p
->start_down_word
[i
][j
] = word_num
;
214 p
->start_down_word
[i
][j
] = -1;
215 if (across_word_start
== true || down_word_start
== true)
219 p
->grid_frozen
= true;
222 /* reset the entire grid */
223 void init_puzzle (Puzzle
*p
, int grid_size
)
225 p
->grid_size
= grid_size
;
226 p
->grid_frozen
= false;
227 for (int i
= 0; i
< p
->grid_size
; i
++)
229 for (int j
= 0; j
< p
->grid_size
; j
++)
231 p
->chars
[i
][j
] = ' ';
232 p
->start_across_word
[i
][j
] = -1;
233 p
->start_down_word
[i
][j
] = -1;
234 strcpy (p
->clue_across
[i
][j
], "");
235 strcpy (p
->clue_down
[i
][j
], "");
240 /* save the puzzle */
241 void save_puzzle (Puzzle
*puzzle
, const char* file
) {
243 outfile
= fopen (file
, "wb");
246 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
249 fwrite (puzzle
, sizeof (*puzzle
), 1, outfile
);
253 /* read the puzzle */
254 Puzzle
load_puzzle (const char* file
) {
257 infile
= fopen (file
, "rb");
260 fprintf (stderr
, "%s\n", ERROR_READING_FILE
);
263 fread (&p
, sizeof(p
), 1, infile
);
268 /* display the puzzle */
269 void print_puzzle (Puzzle
*p
)
272 set_color (WHITE
, CYAN
, NORMAL
);
274 for (int i
= 0; i
< p
->grid_size
; i
++)
278 for (int i
= 0; i
< p
->grid_size
; i
++)
280 set_color (WHITE
, CYAN
, NORMAL
);
282 for (int j
= 0; j
< p
->grid_size
; j
++)
284 if (p
->chars
[i
][j
] == '#') {
285 set_color (WHITE
, BLACK
, NORMAL
);
290 if (p
->start_across_word
[i
][j
] != -1 ||
291 p
->start_down_word
[i
][j
] != -1)
293 set_color (BLUE
, WHITE
, NORMAL
);
294 if (p
->start_across_word
[i
][j
] != -1)
295 printf ("%-2d", p
->start_across_word
[i
][j
]);
297 printf ("%-2d", p
->start_down_word
[i
][j
]);
301 set_color (BLACK
, WHITE
,NORMAL
);
305 set_color (BLACK
, WHITE
, BOLD
);
306 printf ("%c", p
->chars
[i
][j
]);
312 /* print the clues if set */
313 if (p
->grid_frozen
== true)
315 printf ("\x1B[1mACROSS - CLUES\x1B[0m\n");
316 for (int i
= 0; i
< p
->grid_size
; i
++)
318 for (int j
= 0; j
< p
->grid_size
; j
++)
320 if (p
->start_across_word
[i
][j
] != -1)
322 printf ("%d - %s; ", p
->start_across_word
[i
][j
],
323 p
->clue_across
[i
][j
]);
327 printf ("\n\x1B[1mDOWN - CLUES\x1B[0m\n");
328 for (int i
= 0; i
< p
->grid_size
; i
++)
330 for (int j
= 0; j
< p
->grid_size
; j
++)
332 if (p
->start_down_word
[i
][j
] != -1)
334 printf ("%d - %s; ", p
->start_down_word
[i
][j
],
343 /* function to check if a word is valid or not */
344 bool is_valid_word (const char *word
)
346 for (int i
= 0; i
< strlen (word
); i
++)
347 if (! isalpha (word
[i
]))
354 /* function to set a clue for an across word */
355 bool set_clue (Puzzle
*p
, String clue
, int index
, enum ORIENTATION order
)
357 for (int i
= 0; i
< p
->grid_size
; i
++)
359 for (int j
= 0; j
< p
->grid_size
; j
++)
363 if (p
->start_across_word
[i
][j
] == index
)
365 strcpy (p
->clue_across
[i
][j
], clue
);
369 else if (order
== DOWN
)
371 if (p
->start_down_word
[i
][j
] == index
)
373 strcpy (p
->clue_down
[i
][j
], clue
);
382 /* function to print a menu */
383 void print_menu (enum COLOR fg
, enum COLOR bg
, const char* title
,
384 char **items
, int num_items
, int padding
)
387 printf ("\e[1;1H\e[2J");
388 set_color (fg
, bg
, NORMAL
);
390 for (int i
= 0; i
< padding
; i
++)
393 reset_color (); printf ("\n");
394 set_color (fg
, bg
, BOLD
);
395 printf ("\u2551%-*s\u2551", padding
, title
);
396 reset_color (); printf ("\n");
397 set_color (fg
, bg
, NORMAL
);
399 for (int i
= 0; i
< padding
; i
++)
402 reset_color (); printf ("\n");
403 for (int i
= 0; i
< num_items
; i
++)
405 set_color (fg
, bg
, NORMAL
);
406 printf ("\u2551%-*s\u2551", padding
, items
[i
]);
407 reset_color (); printf ("\n");
409 set_color (fg
, bg
, NORMAL
);
411 for (int i
= 0; i
< padding
; i
++)
414 reset_color (); printf ("\n");