bd286e3b2ba5207c20f030db7b1a18f78df18adc
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 clues to text file */
57 void export_clues (Puzzle
*p
, const char *filename
)
59 FILE *outfile
= fopen (filename
, "w");
62 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
65 /* first the across clues */
66 fprintf (outfile
, "ACROSS CLUES\n");
67 for (int i
= 0; i
< p
->grid_size
; i
++)
69 for (int j
= 0; j
< p
->grid_size
; j
++)
71 if (p
->start_across_word
[i
][j
] != -1)
72 fprintf (outfile
, "%d - %s\n", p
->start_across_word
[i
][j
],
73 p
->clue_across
[i
][j
]);
76 /* now the down clues */
77 fprintf (outfile
, "DOWN CLUES\n");
78 for (int i
= 0; i
< p
->grid_size
; i
++)
80 for (int j
= 0; j
< p
->grid_size
; j
++)
82 if (p
->start_down_word
[i
][j
] != -1)
83 fprintf (outfile
, "%d - %s\n", p
->start_down_word
[i
][j
],
90 /* Output the grid to image - if answerkey is true export filled grid */
91 void export_grid_image (Puzzle
*p
, const char *filename
, bool answerkey
)
93 int img_size
= p
->grid_size
* 40;
94 FILE * outfile
= fopen (filename
, "wb");
97 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
101 gdImagePtr img
= gdImageCreate (img_size
, img_size
);
102 int white
= gdImageColorAllocate (img
, 255,255,255);
103 int black
= gdImageColorAllocate (img
, 0, 0, 0);
104 int blue
= gdImageColorAllocate (img
, 0, 0, 216);
105 gdFontPtr sm_fnt
= gdFontGetMediumBold ();
106 gdFontPtr lg_fnt
= gdFontGetGiant ();
108 for (int i
= 0; i
< p
->grid_size
; i
++)
110 for (int j
= 0; j
< p
->grid_size
; j
++)
112 /* if it is a block, draw the black square */
113 if (p
->chars
[i
][j
] == '#')
114 gdImageFilledRectangle (img
, j
*40, i
*40, j
*40+40,
118 /* draw a regular square */
119 gdImageRectangle (img
, j
*40, i
*40, j
*40+40,
122 /* print the numers, if it is either start across word or
124 if (p
->start_across_word
[i
][j
] != -1 ||
125 p
->start_down_word
[i
][j
] != -1)
127 if (p
->start_across_word
[i
][j
] != -1)
130 sprintf (str
, "%d", p
->start_across_word
[i
][j
]);
131 gdImageString (img
, sm_fnt
, j
*40+2, i
*40+2,
132 (unsigned char *)str
, blue
);
137 sprintf (str
, "%d", p
->start_down_word
[i
][j
]);
138 gdImageString (img
, sm_fnt
, j
*40+2, i
*40+2,
139 (unsigned char *)str
, blue
);
142 /* if answerkey is true, draw the character in the cell */
145 gdImageChar (img
, lg_fnt
, j
*40+15, i
*40+15,
146 p
->chars
[i
][j
], black
);
152 gdImagePng (img
, outfile
);
153 gdImageDestroy (img
);
157 /* Set the terminal colour */
158 void set_color (enum COLOR fg
, enum COLOR bg
, enum ATTR at
) {
159 printf ("\x1B[%d;%d;%dm", fg
+30, bg
+40, at
);
162 /* Reset the terminal colour */
163 void reset_color () {
167 /* check if previous row is blank or not */
168 bool prev_row_blank (Puzzle
*p
, int r
, int c
)
170 if (r
== 0) return true;
171 if (p
->chars
[r
-1][c
] == ' ' || p
->chars
[r
-1][c
] == '#') return true;
174 /* check if next row is blank or not */
175 bool next_row_blank (Puzzle
*p
, int r
, int c
)
177 if (r
== p
->grid_size
- 1) return true;
178 if (p
->chars
[r
+1][c
] == ' ' || p
->chars
[r
+1][c
] == '#') return true;
181 /* check if previous col is blank or not */
182 bool prev_col_blank (Puzzle
*p
, int r
, int c
)
184 if (c
== 0) return true;
185 if (p
->chars
[r
][c
-1] == ' ' || p
->chars
[r
][c
-1] == '#') return true;
188 /* check if the next col is blank or not */
189 bool next_col_blank (Puzzle
*p
, int r
, int c
)
191 if (c
== p
->grid_size
-1) return true;
192 if (p
->chars
[r
][c
+1] == ' ' || p
->chars
[r
][c
+1] == '#') return true;
196 /* unfreeze the grid - mak editing possible to change words */
197 void unfreeze_puzzle (Puzzle
*p
)
199 for (int i
= 0; i
< p
->grid_size
; i
++)
201 for (int j
= 0; j
< p
->grid_size
; j
++)
203 if (p
->chars
[i
][j
] == '#')
204 p
->chars
[i
][j
] = ' ';
206 p
->start_across_word
[i
][j
] = -1;
207 p
->start_down_word
[i
][j
] = -1;
210 p
->grid_frozen
= false;
213 /* freeze the grid - make editing impossible because it finalizes the
214 across and down words in the grid */
215 void freeze_puzzle (Puzzle
*p
)
218 bool across_word_start
, down_word_start
;
219 for (int i
= 0; i
< p
->grid_size
; i
++)
221 for (int j
= 0; j
< p
->grid_size
; j
++)
223 across_word_start
= false;
224 down_word_start
= false;
225 /* if it is a blank cell - cover it with a block */
226 if (p
->chars
[i
][j
] == ' ')
227 p
->chars
[i
][j
] = '#';
228 /* it is not a blank cell - check all possibilities */
231 bool prev_row
= prev_row_blank (p
, i
, j
);
232 bool next_row
= next_row_blank (p
, i
, j
);
233 bool prev_col
= prev_col_blank (p
, i
, j
);
234 bool next_col
= next_col_blank (p
, i
, j
);
235 if (prev_row
&& ! next_row
)
236 down_word_start
= true;
237 if (prev_col
&& ! next_col
)
238 across_word_start
= true;
241 if (across_word_start
== true)
242 p
->start_across_word
[i
][j
] = word_num
;
244 p
->start_across_word
[i
][j
] = -1;
245 if (down_word_start
== true)
246 p
->start_down_word
[i
][j
] = word_num
;
248 p
->start_down_word
[i
][j
] = -1;
249 if (across_word_start
== true || down_word_start
== true)
253 p
->grid_frozen
= true;
256 /* reset the entire grid */
257 void init_puzzle (Puzzle
*p
, int grid_size
)
259 p
->grid_size
= grid_size
;
260 p
->grid_frozen
= false;
261 for (int i
= 0; i
< p
->grid_size
; i
++)
263 for (int j
= 0; j
< p
->grid_size
; j
++)
265 p
->chars
[i
][j
] = ' ';
266 p
->start_across_word
[i
][j
] = -1;
267 p
->start_down_word
[i
][j
] = -1;
268 strcpy (p
->clue_across
[i
][j
], "");
269 strcpy (p
->clue_down
[i
][j
], "");
274 /* save the puzzle */
275 void save_puzzle (Puzzle
*puzzle
, const char* file
) {
277 outfile
= fopen (file
, "wb");
280 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
283 fwrite (puzzle
, sizeof (*puzzle
), 1, outfile
);
287 /* read the puzzle */
288 Puzzle
load_puzzle (const char* file
) {
291 infile
= fopen (file
, "rb");
294 fprintf (stderr
, "%s\n", ERROR_READING_FILE
);
297 fread (&p
, sizeof(p
), 1, infile
);
302 /* display the puzzle */
303 void print_puzzle (Puzzle
*p
)
306 set_color (WHITE
, CYAN
, NORMAL
);
308 for (int i
= 0; i
< p
->grid_size
; i
++)
312 for (int i
= 0; i
< p
->grid_size
; i
++)
314 set_color (WHITE
, CYAN
, NORMAL
);
316 for (int j
= 0; j
< p
->grid_size
; j
++)
318 if (p
->chars
[i
][j
] == '#') {
319 set_color (WHITE
, BLACK
, NORMAL
);
324 if (p
->start_across_word
[i
][j
] != -1 ||
325 p
->start_down_word
[i
][j
] != -1)
327 set_color (BLUE
, WHITE
, NORMAL
);
328 if (p
->start_across_word
[i
][j
] != -1)
329 printf ("%-2d", p
->start_across_word
[i
][j
]);
331 printf ("%-2d", p
->start_down_word
[i
][j
]);
335 set_color (BLACK
, WHITE
,NORMAL
);
339 set_color (BLACK
, WHITE
, BOLD
);
340 printf ("%c", p
->chars
[i
][j
]);
346 /* print the clues if set */
347 if (p
->grid_frozen
== true)
349 printf ("\x1B[1mACROSS - CLUES\x1B[0m\n");
350 for (int i
= 0; i
< p
->grid_size
; i
++)
352 for (int j
= 0; j
< p
->grid_size
; j
++)
354 if (p
->start_across_word
[i
][j
] != -1)
356 printf ("%d - %s; ", p
->start_across_word
[i
][j
],
357 p
->clue_across
[i
][j
]);
361 printf ("\n\x1B[1mDOWN - CLUES\x1B[0m\n");
362 for (int i
= 0; i
< p
->grid_size
; i
++)
364 for (int j
= 0; j
< p
->grid_size
; j
++)
366 if (p
->start_down_word
[i
][j
] != -1)
368 printf ("%d - %s; ", p
->start_down_word
[i
][j
],
377 /* function to check if a word is valid or not */
378 char* is_valid_word (char *word
)
380 if (word
== NULL
|| strlen(word
) == 0)
382 for (int i
= 0; i
< strlen (word
) - 1; i
++)
383 if (! isalpha (word
[i
]))
386 return strtok (word
, "\n");
390 /* function to set a clue for an across word */
391 bool set_clue (Puzzle
*p
, String clue
, int index
, enum ORIENTATION order
)
393 for (int i
= 0; i
< p
->grid_size
; i
++)
395 for (int j
= 0; j
< p
->grid_size
; j
++)
399 if (p
->start_across_word
[i
][j
] == index
)
401 strcpy (p
->clue_across
[i
][j
], clue
);
405 else if (order
== DOWN
)
407 if (p
->start_down_word
[i
][j
] == index
)
409 strcpy (p
->clue_down
[i
][j
], clue
);
418 /* function to print a menu */
419 void print_menu (enum COLOR fg
, enum COLOR bg
, const char* title
,
420 char **items
, int num_items
, int padding
)
423 printf ("\e[1;1H\e[2J");
424 set_color (fg
, bg
, NORMAL
);
426 for (int i
= 0; i
< padding
; i
++)
429 reset_color (); printf ("\n");
431 set_color (fg
, bg
, BOLD
);
432 printf ("%-*s", padding
, title
);
434 set_color (fg
, bg
, NORMAL
);
436 reset_color (); printf ("\n");
437 set_color (fg
, bg
, NORMAL
);
439 for (int i
= 0; i
< padding
; i
++)
442 reset_color (); printf ("\n");
443 for (int i
= 0; i
< num_items
; i
++)
445 set_color (fg
, bg
, NORMAL
);
446 printf ("\u2551%-*s\u2551", padding
, items
[i
]);
447 reset_color (); printf ("\n");
449 set_color (fg
, bg
, NORMAL
);
451 for (int i
= 0; i
< padding
; i
++)
454 reset_color (); printf ("\n");