12 #include <openssl/conf.h>
13 #include <openssl/evp.h>
14 #include <openssl/err.h>
15 #include "constantstrings.h"
17 #define MAX_PUZZLE_SIZE 25
18 #define MAX_CLUE_LENGTH 150
19 #define GRID_PIXELS 37
21 /* Enum to define terminal colours */
43 /* for use with the player */
49 typedef char String
[MAX_CLUE_LENGTH
];
51 /* The main puzzle struct type */
53 char chars
[MAX_PUZZLE_SIZE
][MAX_PUZZLE_SIZE
];
54 int start_across_word
[MAX_PUZZLE_SIZE
][MAX_PUZZLE_SIZE
];
55 int start_down_word
[MAX_PUZZLE_SIZE
][MAX_PUZZLE_SIZE
];
56 String clue_across
[MAX_PUZZLE_SIZE
][MAX_PUZZLE_SIZE
];
57 String clue_down
[MAX_PUZZLE_SIZE
][MAX_PUZZLE_SIZE
];
60 char hashed_password
[256];
64 /* The player data struct type - for the player app */
69 char char_ans
[MAX_PUZZLE_SIZE
][MAX_PUZZLE_SIZE
];
72 bool solution_revealed
;
73 enum ORIENTATION current_movement
;
76 /* compute the hash of a password */
77 void digest_message(const unsigned char *message
,
78 size_t message_len
, unsigned char **digest
, unsigned int *digest_len
)
82 if((mdctx
= EVP_MD_CTX_new()) == NULL
)
85 if(1 != EVP_DigestInit_ex(mdctx
, EVP_sha256(), NULL
))
88 if(1 != EVP_DigestUpdate(mdctx
, message
, message_len
))
91 if((*digest
= (unsigned char *)
92 OPENSSL_malloc(EVP_MD_size(EVP_sha256()))) == NULL
)
95 if(1 != EVP_DigestFinal_ex(mdctx
, *digest
, digest_len
))
98 EVP_MD_CTX_free(mdctx
);
101 EVP_MD_CTX_free(mdctx
);
102 ERR_print_errors_fp(stderr
);
106 /* convert the hashed binary password to hexadecimal representation and
107 free the hashed binary password */
108 void to_hexadecimal (char *hex
, unsigned char *binary_pwd
, unsigned int len
)
111 /* keep reference to beginning of the hashed password */
112 unsigned char *binary_pw_begin
= binary_pwd
;
113 for (int i
= 0; i
< len
; i
++)
115 sprintf (buf
, "%02x", (*binary_pwd
)&0xff);
119 /* free the hashed password */
120 OPENSSL_free (binary_pw_begin
);
123 /* get a number from the user */
132 /* verify password */
133 bool verify_password (Puzzle
*p
, const char* password
)
135 /* no password set */
136 if (strcmp (p
->hashed_password
, "\0") == 0)
139 /* hash the user input password and compare it with the stored password */
140 unsigned char* hashed_password
;
142 digest_message ((const unsigned char *)password
, strlen(password
),
143 &hashed_password
, &len
);
144 char hashed_hex_pwd
[256] = { (char) NULL
};
145 to_hexadecimal (hashed_hex_pwd
, hashed_password
, len
);
147 if (strcmp (p
->hashed_password
, hashed_hex_pwd
) == 0)
153 /* Set or reset password for puzzle */
154 void set_puzzle_password (Puzzle
*p
, const char *password
)
156 /* if it is a null string, reset the password */
157 if (strcmp (password
, "\0") == 0)
159 strcpy (p
->hashed_password
, "\0");
160 strcpy (p
->salt
, "\0");
165 unsigned char* hashedpwd
;
167 digest_message ((const unsigned char *)password
, strlen(password
),
169 /* the hashedpwd contains binary data - we will convert it to
170 hexadecimal data and store in file */
172 to_hexadecimal (p
->hashed_password
, hashedpwd
, len
);
173 printf ("%s\n", p
->hashed_password
);
175 strcpy (p
->salt
, "\0");
180 /* Output the clues to text file */
181 void export_clues (Puzzle
*p
, const char *filename
)
183 FILE *outfile
= fopen (filename
, "w");
186 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
189 /* first the across clues */
190 fprintf (outfile
, "ACROSS CLUES\n");
191 for (int i
= 0; i
< p
->grid_size
; i
++)
193 for (int j
= 0; j
< p
->grid_size
; j
++)
195 if (p
->start_across_word
[i
][j
] != -1)
196 fprintf (outfile
, "%d - %s\n", p
->start_across_word
[i
][j
],
197 p
->clue_across
[i
][j
]);
200 /* now the down clues */
201 fprintf (outfile
, "DOWN CLUES\n");
202 for (int i
= 0; i
< p
->grid_size
; i
++)
204 for (int j
= 0; j
< p
->grid_size
; j
++)
206 if (p
->start_down_word
[i
][j
] != -1)
207 fprintf (outfile
, "%d - %s\n", p
->start_down_word
[i
][j
],
214 /* Output the grid to image - if answerkey is true export filled grid */
215 void export_grid_image (Puzzle
*p
, const char *filename
, bool answerkey
)
217 int img_size
= p
->grid_size
* GRID_PIXELS
;
218 FILE * outfile
= fopen (filename
, "wb");
221 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
225 gdImagePtr img
= gdImageCreate (img_size
, img_size
);
226 gdImageColorAllocate (img
, 255,255,255);
227 int black
= gdImageColorAllocate (img
, 0, 0, 0);
228 int blue
= gdImageColorAllocate (img
, 0, 0, 216);
229 gdFontPtr sm_fnt
= gdFontGetMediumBold ();
230 gdFontPtr lg_fnt
= gdFontGetGiant ();
232 for (int i
= 0; i
< p
->grid_size
; i
++)
234 for (int j
= 0; j
< p
->grid_size
; j
++)
236 /* if it is a block, draw the black square */
237 if (p
->chars
[i
][j
] == '#')
238 gdImageFilledRectangle (img
, j
*GRID_PIXELS
, i
*GRID_PIXELS
,
239 j
*GRID_PIXELS
+GRID_PIXELS
,
240 i
*GRID_PIXELS
+GRID_PIXELS
,black
);
243 /* draw a regular square */
244 gdImageRectangle (img
, j
*GRID_PIXELS
, i
*GRID_PIXELS
,
245 j
*GRID_PIXELS
+GRID_PIXELS
,
246 i
*GRID_PIXELS
+GRID_PIXELS
, black
);
248 /* print the numers, if it is either start across word or
250 if (p
->start_across_word
[i
][j
] != -1 ||
251 p
->start_down_word
[i
][j
] != -1)
253 if (p
->start_across_word
[i
][j
] != -1)
256 sprintf (str
, "%d", p
->start_across_word
[i
][j
]);
257 gdImageString (img
, sm_fnt
, j
*GRID_PIXELS
+2,
259 (unsigned char *)str
, blue
);
264 sprintf (str
, "%d", p
->start_down_word
[i
][j
]);
265 gdImageString (img
, sm_fnt
, j
*GRID_PIXELS
+2,
267 (unsigned char *)str
, blue
);
270 /* if answerkey is true, draw the character in the cell */
273 gdImageChar (img
, lg_fnt
, j
*GRID_PIXELS
+15,
274 i
*GRID_PIXELS
+10, p
->chars
[i
][j
], black
);
280 gdImagePng (img
, outfile
);
281 gdImageDestroy (img
);
285 /* Set the terminal colour */
286 void set_color (enum COLOR fg
, enum COLOR bg
, enum ATTR at
) {
287 printf ("\x1B[%d;%d;%dm", fg
+30, bg
+40, at
);
290 /* Reset the terminal colour */
291 void reset_color () {
295 /* check if the prev row has a block or not */
296 bool prev_row_block (Puzzle
*p
, int r
, int c
)
300 if (p
->chars
[r
-1][c
] == '#')
305 /* check if the next row has a block or not */
306 bool next_row_block (Puzzle
*p
, int r
, int c
)
308 if (r
== p
->grid_size
-1)
310 if (p
->chars
[r
+1][c
] == '#')
315 /* check if the prev col has a block or not */
316 bool prev_col_block (Puzzle
*p
, int r
, int c
)
320 if (p
->chars
[r
][c
-1] == '#')
325 /* check if the next col has a block or not */
326 bool next_col_block (Puzzle
*p
, int r
, int c
)
328 if (c
== p
->grid_size
- 1)
330 if (p
->chars
[r
][c
+1] == '#')
335 /* check if previous row is blank or not */
336 bool prev_row_blank (Puzzle
*p
, int r
, int c
)
338 if (r
== 0) return true;
339 if (p
->chars
[r
-1][c
] == ' ' || p
->chars
[r
-1][c
] == '#') return true;
342 /* check if next row is blank or not */
343 bool next_row_blank (Puzzle
*p
, int r
, int c
)
345 if (r
== p
->grid_size
- 1) return true;
346 if (p
->chars
[r
+1][c
] == ' ' || p
->chars
[r
+1][c
] == '#') return true;
349 /* check if previous col is blank or not */
350 bool prev_col_blank (Puzzle
*p
, int r
, int c
)
352 if (c
== 0) return true;
353 if (p
->chars
[r
][c
-1] == ' ' || p
->chars
[r
][c
-1] == '#') return true;
356 /* check if the next col is blank or not */
357 bool next_col_blank (Puzzle
*p
, int r
, int c
)
359 if (c
== p
->grid_size
-1) return true;
360 if (p
->chars
[r
][c
+1] == ' ' || p
->chars
[r
][c
+1] == '#') return true;
364 /* set the current row/col to the beginning of word index (across or down) */
365 void set_selection_to_word_start (MainPlayerData
*app_data
,
366 enum ORIENTATION orient
, int word_index
)
368 for (int i
= 0; i
< app_data
->puzzle
.grid_size
; i
++)
370 for (int j
= 0; j
< app_data
->puzzle
.grid_size
; j
++)
372 if (orient
== ACROSS
&&
373 app_data
->puzzle
.start_across_word
[i
][j
] == word_index
)
375 app_data
->current_movement
= ACROSS
;
376 app_data
->cur_row
= i
;
377 app_data
->cur_col
= j
;
380 else if (orient
== DOWN
&&
381 app_data
->puzzle
.start_down_word
[i
][j
] == word_index
)
383 app_data
->current_movement
= DOWN
;
384 app_data
->cur_row
= i
;
385 app_data
->cur_col
= j
;
392 /* unfreeze the grid - make editing possible to change words */
393 void unfreeze_puzzle (Puzzle
*p
)
395 for (int i
= 0; i
< p
->grid_size
; i
++)
397 for (int j
= 0; j
< p
->grid_size
; j
++)
399 if (p
->chars
[i
][j
] == '#')
400 p
->chars
[i
][j
] = ' ';
402 p
->start_across_word
[i
][j
] = -1;
403 p
->start_down_word
[i
][j
] = -1;
406 p
->grid_frozen
= false;
409 /* freeze the grid - make editing impossible because it finalizes the
410 across and down words in the grid */
411 void freeze_puzzle (Puzzle
*p
)
414 bool across_word_start
, down_word_start
;
415 for (int i
= 0; i
< p
->grid_size
; i
++)
417 for (int j
= 0; j
< p
->grid_size
; j
++)
419 across_word_start
= false;
420 down_word_start
= false;
421 /* if it is a blank cell - cover it with a block */
422 if (p
->chars
[i
][j
] == ' ' || p
->chars
[i
][j
] == '#')
423 p
->chars
[i
][j
] = '#';
424 /* it is not a blank cell - check all possibilities */
427 bool prev_row
= prev_row_blank (p
, i
, j
);
428 bool next_row
= next_row_blank (p
, i
, j
);
429 bool prev_col
= prev_col_blank (p
, i
, j
);
430 bool next_col
= next_col_blank (p
, i
, j
);
431 if (prev_row
&& ! next_row
)
432 down_word_start
= true;
433 if (prev_col
&& ! next_col
)
434 across_word_start
= true;
437 if (across_word_start
== true)
438 p
->start_across_word
[i
][j
] = word_num
;
440 p
->start_across_word
[i
][j
] = -1;
441 if (down_word_start
== true)
442 p
->start_down_word
[i
][j
] = word_num
;
444 p
->start_down_word
[i
][j
] = -1;
445 if (across_word_start
== true || down_word_start
== true)
449 p
->grid_frozen
= true;
452 /* reset the entire grid */
453 void init_puzzle (Puzzle
*p
, int grid_size
)
455 p
->grid_size
= grid_size
;
456 p
->grid_frozen
= false;
457 for (int i
= 0; i
< p
->grid_size
; i
++)
459 for (int j
= 0; j
< p
->grid_size
; j
++)
461 p
->chars
[i
][j
] = ' ';
462 p
->start_across_word
[i
][j
] = -1;
463 p
->start_down_word
[i
][j
] = -1;
464 strcpy (p
->clue_across
[i
][j
], "");
465 strcpy (p
->clue_down
[i
][j
], "");
468 strcpy (p
->hashed_password
, "\0");
469 strcpy (p
->salt
, "\0");
473 /* save the puzzle to a file */
474 void save_puzzle (Puzzle
*puzzle
, const char* file
) {
476 /* First output the uncompressed contents to a temp file */
477 outfile
= tmpfile ();
480 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
483 /* grid size is the first field */
484 fprintf (outfile
, "%d\n", puzzle
->grid_size
);
485 /* whether grid is frozen or not */
486 fprintf (outfile
, "%d\n", puzzle
->grid_frozen
);
487 /* the hashed password */
488 fprintf (outfile
, "%s\n", puzzle
->hashed_password
);
490 fprintf (outfile
, "%s\n", puzzle
->salt
);
492 /* First output the grid characters columns/rows */
493 for (int i
= 0; i
< puzzle
->grid_size
; i
++)
495 for (int j
= 0; j
< puzzle
->grid_size
; j
++)
496 fprintf (outfile
, "%c", puzzle
->chars
[i
][j
]);
497 fprintf (outfile
, "\n");
500 /* Next output the start across/down numbers */
501 for (int i
= 0; i
< puzzle
->grid_size
; i
++)
503 for (int j
= 0; j
< puzzle
->grid_size
; j
++)
505 fprintf (outfile
, "%d ", puzzle
->start_across_word
[i
][j
]);
506 fprintf (outfile
, "%d ", puzzle
->start_down_word
[i
][j
]);
508 fprintf (outfile
, "\n");
511 /* Output the across clues */
512 fprintf (outfile
, "ACROSS\n");
513 /* Search the grid for across words */
514 for (int i
= 0; i
< puzzle
->grid_size
; i
++)
516 for (int j
= 0; j
< puzzle
->grid_size
; j
++)
518 /* if it is an across word, then put the word index followed by
519 tab character (as separator) and the clue */
520 if (puzzle
->start_across_word
[i
][j
] != -1)
521 fprintf (outfile
, "%d\t%s\n", puzzle
->start_across_word
[i
][j
],
522 puzzle
->clue_across
[i
][j
]);
526 /* Output the down clues */
527 fprintf (outfile
, "DOWN\n");
528 /* Search the grid for down words */
529 for (int i
= 0; i
< puzzle
->grid_size
; i
++)
531 for (int j
= 0; j
< puzzle
->grid_size
; j
++)
533 /* same as across word, put the word index followed by the tab
534 character and then the clue */
535 if (puzzle
->start_down_word
[i
][j
] != -1)
536 fprintf (outfile
, "%d\t%s\n", puzzle
->start_down_word
[i
][j
],
537 puzzle
->clue_down
[i
][j
]);
541 /* Flush the buffer and rewind to beginning - to read and save into
542 gzip compressed file */
544 fseek (outfile
, 0, 0);
546 /* now compress the file and save it to destination file */
547 gzFile outdestfile
= gzopen (file
, "wb");
548 if (outdestfile
== NULL
)
550 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
555 int num
= fread (buf
, sizeof(char), sizeof(char)*128, outfile
);
558 int res
= gzwrite (outdestfile
, buf
, num
*sizeof(char) );
561 fprintf (stderr
, "%s %s\n", ERROR_WRITING_FILE
, COMPRESSED
);
565 num
= fread (buf
, sizeof(char), sizeof(char)*128, outfile
);
567 gzclose (outdestfile
);
572 /* read the puzzle from a file */
573 Puzzle
load_puzzle (const char* file
) {
574 /* First open the GZip file */
575 gzFile insourcefile
= gzopen (file
, "rb");
576 if (insourcefile
== NULL
)
578 fprintf (stderr
, "%s %s\n", ERROR_READING_FILE
, COMPRESSED
);
581 /* Open a temporary file to uncompress the contents */
582 FILE *infile
= tmpfile ();
585 fprintf (stderr
, "%s\n", ERROR_READING_FILE
);
588 /* Put the uncompressed content to the temp file */
591 num
= gzread (insourcefile
, buf
, 128);
594 int res
= fwrite (buf
, 1, num
, infile
);
597 fprintf (stderr
, "%s\n", ERROR_READING_FILE
);
599 gzclose (insourcefile
);
602 num
= gzread (insourcefile
, buf
, 128);
604 /* Close the gzip file */
605 gzclose (insourcefile
);
606 /* Flush the temp file buffer and rewind to beginning */
608 fseek (infile
, 0, 0);
610 /* Read the temporary file contents to the structure Puzzle */
612 char line
[MAX_CLUE_LENGTH
+10];
613 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
614 p
.grid_size
= atoi (line
);
615 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
616 p
.grid_frozen
= atoi (line
) == 0 ? false : true ;
617 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
618 if (strlen (line
) != 1)
619 strcpy (p
.hashed_password
, strtok (line
, "\n"));
621 strcpy (p
.hashed_password
, "\0");
622 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
623 if (strlen (line
) != 1)
624 strcpy (p
.salt
, strtok (line
, "\n"));
626 strcpy (p
.salt
, "\0");
628 /* read each character of the grid */
629 for (int i
= 0; i
< p
.grid_size
; i
++ )
631 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
632 for (int j
= 0; j
< p
.grid_size
; j
++)
633 p
.chars
[i
][j
] = line
[j
];
635 /* read the word numbers */
636 for (int i
= 0; i
< p
.grid_size
; i
++)
638 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
639 char *token
= strtok (line
, " ");
640 for (int j
= 0; j
< p
.grid_size
; j
++)
643 p
.start_across_word
[i
][j
] = atoi (token
);
644 token
= strtok (NULL
, " ");
646 p
.start_down_word
[i
][j
] = atoi (token
);
647 token
= strtok (NULL
, " ");
651 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
654 char clues
[100][MAX_CLUE_LENGTH
];
657 /* first read the across clues from file */
660 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
661 /* if reached the end of across clues */
662 if (strcmp (line
, "DOWN\n") == 0)
664 word_num
[c
] = atoi (strtok (line
, "\t"));
665 char *cl
= strtok (NULL
, "\n");
667 strcpy (clues
[c
], cl
);
669 strcpy (clues
[c
], "\0");
672 /* set the clue to the correct cell in grid */
673 for (int i
= 0; i
< p
.grid_size
; i
++)
675 for (int j
= 0; j
< p
.grid_size
; j
++)
677 for (int r
= 0; r
< c
; r
++)
678 if (p
.start_across_word
[i
][j
] == word_num
[r
])
679 strcpy (p
.clue_across
[i
][j
], clues
[r
]);
685 while (fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
))
687 word_num
[c
] = atoi (strtok (line
, "\t"));
688 char* cl
= strtok (NULL
, "\n");
690 strcpy (clues
[c
], cl
);
692 strcpy (clues
[c
], "\0");
695 for (int i
= 0; i
< p
.grid_size
; i
++)
697 for (int j
= 0; j
< p
.grid_size
; j
++)
699 for (int r
= 0; r
< c
; r
++)
700 if (p
.start_down_word
[i
][j
] == word_num
[r
])
701 strcpy (p
.clue_down
[i
][j
], clues
[r
]);
709 /* display the puzzle */
710 void print_puzzle (Puzzle
*p
)
713 set_color (WHITE
, CYAN
, NORMAL
);
715 for (int i
= 0; i
< p
->grid_size
; i
++)
719 for (int i
= 0; i
< p
->grid_size
; i
++)
721 set_color (WHITE
, CYAN
, NORMAL
);
723 for (int j
= 0; j
< p
->grid_size
; j
++)
725 if (p
->chars
[i
][j
] == '#') {
726 set_color (WHITE
, BLACK
, NORMAL
);
731 if (p
->start_across_word
[i
][j
] != -1 ||
732 p
->start_down_word
[i
][j
] != -1)
734 set_color (BLUE
, WHITE
, NORMAL
);
735 if (p
->start_across_word
[i
][j
] != -1)
736 printf ("%-2d", p
->start_across_word
[i
][j
]);
738 printf ("%-2d", p
->start_down_word
[i
][j
]);
742 set_color (BLACK
, WHITE
,NORMAL
);
746 set_color (BLACK
, WHITE
, BOLD
);
747 printf ("%c", p
->chars
[i
][j
]);
753 /* print the clues if set */
754 if (p
->grid_frozen
== true)
756 printf ("\x1B[1mACROSS - CLUES\x1B[0m\n");
757 for (int i
= 0; i
< p
->grid_size
; i
++)
759 for (int j
= 0; j
< p
->grid_size
; j
++)
761 if (p
->start_across_word
[i
][j
] != -1)
763 printf ("%d - %s; ", p
->start_across_word
[i
][j
],
764 p
->clue_across
[i
][j
]);
768 printf ("\n\x1B[1mDOWN - CLUES\x1B[0m\n");
769 for (int i
= 0; i
< p
->grid_size
; i
++)
771 for (int j
= 0; j
< p
->grid_size
; j
++)
773 if (p
->start_down_word
[i
][j
] != -1)
775 printf ("%d - %s; ", p
->start_down_word
[i
][j
],
784 /* function to check if a word is valid or not */
785 char* is_valid_word (char *word
)
787 if (word
== NULL
|| strlen(word
) == 0)
789 for (int i
= 0; i
< strlen (word
) - 1; i
++)
790 if (! isalpha (word
[i
]))
793 return strtok (word
, "\n");
797 /* function to set a clue for an across word */
798 bool set_clue (Puzzle
*p
, String clue
, int index
, enum ORIENTATION order
)
800 for (int i
= 0; i
< p
->grid_size
; i
++)
802 for (int j
= 0; j
< p
->grid_size
; j
++)
806 if (p
->start_across_word
[i
][j
] == index
)
808 strcpy (p
->clue_across
[i
][j
], clue
);
812 else if (order
== DOWN
)
814 if (p
->start_down_word
[i
][j
] == index
)
816 strcpy (p
->clue_down
[i
][j
], clue
);
825 /* function to print a menu */
826 void print_menu (enum COLOR fg
, enum COLOR bg
, const char* title
,
827 char **items
, int num_items
, int padding
)
830 printf ("\e[1;1H\e[2J");
831 set_color (fg
, bg
, NORMAL
);
833 for (int i
= 0; i
< padding
; i
++)
836 reset_color (); printf ("\n");
837 set_color (fg
, bg
, NORMAL
);
839 set_color (fg
, bg
, BOLD
);
840 printf ("%-*s", padding
, title
);
842 set_color (fg
, bg
, NORMAL
);
844 reset_color (); printf ("\n");
845 set_color (fg
, bg
, NORMAL
);
847 for (int i
= 0; i
< padding
; i
++)
850 reset_color (); printf ("\n");
851 for (int i
= 0; i
< num_items
; i
++)
853 set_color (fg
, bg
, NORMAL
);
854 printf ("\u2551%-*s\u2551", padding
, items
[i
]);
855 reset_color (); printf ("\n");
857 set_color (fg
, bg
, NORMAL
);
859 for (int i
= 0; i
< padding
; i
++)
862 reset_color (); printf ("\n");
865 /* reset the player data, loading from the puzzle file */
866 void reset_player_data (MainPlayerData
*app_data
, const char *filename
)
868 app_data
->puzzle
= load_puzzle (filename
);
870 app_data
->is_loaded
= app_data
->puzzle
.grid_frozen
;
871 app_data
->cur_col
= -1;
872 app_data
->cur_row
= -1;
873 app_data
->solution_revealed
= false;
874 strcpy (app_data
->filename
, filename
);
875 /* reset the answer keys */
876 for (int i
= 0; i
< app_data
->puzzle
.grid_size
; i
++)
877 for (int j
= 0; j
< app_data
->puzzle
.grid_size
; j
++)
878 app_data
->char_ans
[i
][j
] = ' ';
882 /* in the player app, move the current selection index left or right */
883 void move_current_col (MainPlayerData
*app_data
, enum DIRECTION dir
)
885 int r
= app_data
->cur_row
;
886 int c
= app_data
->cur_col
;
887 if (dir
== DIR_FORWARD
)
890 while (c
< app_data
->puzzle
.grid_size
)
892 if (app_data
->puzzle
.chars
[r
][c
] == '#')
897 if (c
< app_data
->puzzle
.grid_size
)
898 app_data
->cur_col
= c
;
905 if (app_data
->puzzle
.chars
[r
][c
] == '#')
911 app_data
->cur_col
= c
;
915 /* in the player app move the current selection index up or down */
916 void move_current_row (MainPlayerData
*app_data
, enum DIRECTION dir
)
918 int r
= app_data
->cur_row
;
919 int c
= app_data
->cur_col
;
920 if (dir
== DIR_FORWARD
)
923 while (r
< app_data
->puzzle
.grid_size
)
925 if (app_data
->puzzle
.chars
[r
][c
] == '#')
930 if (r
< app_data
->puzzle
.grid_size
)
931 app_data
->cur_row
= r
;
938 if (app_data
->puzzle
.chars
[r
][c
] == '#')
944 app_data
->cur_row
= r
;