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 enum ORIENTATION current_movement
;
75 /* compute the hash of a password */
76 void digest_message(const unsigned char *message
,
77 size_t message_len
, unsigned char **digest
, unsigned int *digest_len
)
81 if((mdctx
= EVP_MD_CTX_new()) == NULL
)
84 if(1 != EVP_DigestInit_ex(mdctx
, EVP_sha256(), NULL
))
87 if(1 != EVP_DigestUpdate(mdctx
, message
, message_len
))
90 if((*digest
= (unsigned char *)
91 OPENSSL_malloc(EVP_MD_size(EVP_sha256()))) == NULL
)
94 if(1 != EVP_DigestFinal_ex(mdctx
, *digest
, digest_len
))
97 EVP_MD_CTX_free(mdctx
);
100 EVP_MD_CTX_free(mdctx
);
101 ERR_print_errors_fp(stderr
);
105 /* convert the hashed binary password to hexadecimal representation and
106 free the hashed binary password */
107 void to_hexadecimal (char *hex
, unsigned char *binary_pwd
, unsigned int len
)
110 /* keep reference to beginning of the hashed password */
111 unsigned char *binary_pw_begin
= binary_pwd
;
112 for (int i
= 0; i
< len
; i
++)
114 sprintf (buf
, "%02x", (*binary_pwd
)&0xff);
118 /* free the hashed password */
119 OPENSSL_free (binary_pw_begin
);
122 /* get a number from the user */
131 /* verify password */
132 bool verify_password (Puzzle
*p
, const char* password
)
134 /* no password set */
135 if (strcmp (p
->hashed_password
, "\0") == 0)
138 /* hash the user input password and compare it with the stored password */
139 unsigned char* hashed_password
;
141 digest_message ((const unsigned char *)password
, strlen(password
),
142 &hashed_password
, &len
);
143 char hashed_hex_pwd
[256] = { (char) NULL
};
144 to_hexadecimal (hashed_hex_pwd
, hashed_password
, len
);
146 if (strcmp (p
->hashed_password
, hashed_hex_pwd
) == 0)
152 /* Set or reset password for puzzle */
153 void set_puzzle_password (Puzzle
*p
, const char *password
)
155 /* if it is a null string, reset the password */
156 if (strcmp (password
, "\0") == 0)
158 strcpy (p
->hashed_password
, "\0");
159 strcpy (p
->salt
, "\0");
164 unsigned char* hashedpwd
;
166 digest_message ((const unsigned char *)password
, strlen(password
),
168 /* the hashedpwd contains binary data - we will convert it to
169 hexadecimal data and store in file */
171 to_hexadecimal (p
->hashed_password
, hashedpwd
, len
);
172 printf ("%s\n", p
->hashed_password
);
174 strcpy (p
->salt
, "\0");
179 /* Output the clues to text file */
180 void export_clues (Puzzle
*p
, const char *filename
)
182 FILE *outfile
= fopen (filename
, "w");
185 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
188 /* first the across clues */
189 fprintf (outfile
, "ACROSS CLUES\n");
190 for (int i
= 0; i
< p
->grid_size
; i
++)
192 for (int j
= 0; j
< p
->grid_size
; j
++)
194 if (p
->start_across_word
[i
][j
] != -1)
195 fprintf (outfile
, "%d - %s\n", p
->start_across_word
[i
][j
],
196 p
->clue_across
[i
][j
]);
199 /* now the down clues */
200 fprintf (outfile
, "DOWN CLUES\n");
201 for (int i
= 0; i
< p
->grid_size
; i
++)
203 for (int j
= 0; j
< p
->grid_size
; j
++)
205 if (p
->start_down_word
[i
][j
] != -1)
206 fprintf (outfile
, "%d - %s\n", p
->start_down_word
[i
][j
],
213 /* Output the grid to image - if answerkey is true export filled grid */
214 void export_grid_image (Puzzle
*p
, const char *filename
, bool answerkey
)
216 int img_size
= p
->grid_size
* GRID_PIXELS
;
217 FILE * outfile
= fopen (filename
, "wb");
220 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
224 gdImagePtr img
= gdImageCreate (img_size
, img_size
);
225 gdImageColorAllocate (img
, 255,255,255);
226 int black
= gdImageColorAllocate (img
, 0, 0, 0);
227 int blue
= gdImageColorAllocate (img
, 0, 0, 216);
228 gdFontPtr sm_fnt
= gdFontGetMediumBold ();
229 gdFontPtr lg_fnt
= gdFontGetGiant ();
231 for (int i
= 0; i
< p
->grid_size
; i
++)
233 for (int j
= 0; j
< p
->grid_size
; j
++)
235 /* if it is a block, draw the black square */
236 if (p
->chars
[i
][j
] == '#')
237 gdImageFilledRectangle (img
, j
*GRID_PIXELS
, i
*GRID_PIXELS
,
238 j
*GRID_PIXELS
+GRID_PIXELS
,
239 i
*GRID_PIXELS
+GRID_PIXELS
,black
);
242 /* draw a regular square */
243 gdImageRectangle (img
, j
*GRID_PIXELS
, i
*GRID_PIXELS
,
244 j
*GRID_PIXELS
+GRID_PIXELS
,
245 i
*GRID_PIXELS
+GRID_PIXELS
, black
);
247 /* print the numers, if it is either start across word or
249 if (p
->start_across_word
[i
][j
] != -1 ||
250 p
->start_down_word
[i
][j
] != -1)
252 if (p
->start_across_word
[i
][j
] != -1)
255 sprintf (str
, "%d", p
->start_across_word
[i
][j
]);
256 gdImageString (img
, sm_fnt
, j
*GRID_PIXELS
+2,
258 (unsigned char *)str
, blue
);
263 sprintf (str
, "%d", p
->start_down_word
[i
][j
]);
264 gdImageString (img
, sm_fnt
, j
*GRID_PIXELS
+2,
266 (unsigned char *)str
, blue
);
269 /* if answerkey is true, draw the character in the cell */
272 gdImageChar (img
, lg_fnt
, j
*GRID_PIXELS
+15,
273 i
*GRID_PIXELS
+10, p
->chars
[i
][j
], black
);
279 gdImagePng (img
, outfile
);
280 gdImageDestroy (img
);
284 /* Set the terminal colour */
285 void set_color (enum COLOR fg
, enum COLOR bg
, enum ATTR at
) {
286 printf ("\x1B[%d;%d;%dm", fg
+30, bg
+40, at
);
289 /* Reset the terminal colour */
290 void reset_color () {
294 /* check if the prev row has a block or not */
295 bool prev_row_block (Puzzle
*p
, int r
, int c
)
299 if (p
->chars
[r
-1][c
] == '#')
304 /* check if the next row has a block or not */
305 bool next_row_block (Puzzle
*p
, int r
, int c
)
307 if (r
== p
->grid_size
-1)
309 if (p
->chars
[r
+1][c
] == '#')
314 /* check if the prev col has a block or not */
315 bool prev_col_block (Puzzle
*p
, int r
, int c
)
319 if (p
->chars
[r
][c
-1] == '#')
324 /* check if the next col has a block or not */
325 bool next_col_block (Puzzle
*p
, int r
, int c
)
327 if (c
== p
->grid_size
- 1)
329 if (p
->chars
[r
][c
+1] == '#')
334 /* check if previous row is blank or not */
335 bool prev_row_blank (Puzzle
*p
, int r
, int c
)
337 if (r
== 0) return true;
338 if (p
->chars
[r
-1][c
] == ' ' || p
->chars
[r
-1][c
] == '#') return true;
341 /* check if next row is blank or not */
342 bool next_row_blank (Puzzle
*p
, int r
, int c
)
344 if (r
== p
->grid_size
- 1) return true;
345 if (p
->chars
[r
+1][c
] == ' ' || p
->chars
[r
+1][c
] == '#') return true;
348 /* check if previous col is blank or not */
349 bool prev_col_blank (Puzzle
*p
, int r
, int c
)
351 if (c
== 0) return true;
352 if (p
->chars
[r
][c
-1] == ' ' || p
->chars
[r
][c
-1] == '#') return true;
355 /* check if the next col is blank or not */
356 bool next_col_blank (Puzzle
*p
, int r
, int c
)
358 if (c
== p
->grid_size
-1) return true;
359 if (p
->chars
[r
][c
+1] == ' ' || p
->chars
[r
][c
+1] == '#') return true;
363 /* set the current row/col to the beginning of word index (across or down) */
364 void set_selection_to_word_start (MainPlayerData
*app_data
,
365 enum ORIENTATION orient
, int word_index
)
367 for (int i
= 0; i
< app_data
->puzzle
.grid_size
; i
++)
369 for (int j
= 0; j
< app_data
->puzzle
.grid_size
; j
++)
371 if (orient
== ACROSS
&&
372 app_data
->puzzle
.start_across_word
[i
][j
] == word_index
)
374 app_data
->current_movement
= ACROSS
;
375 app_data
->cur_row
= i
;
376 app_data
->cur_col
= j
;
379 else if (orient
== DOWN
&&
380 app_data
->puzzle
.start_down_word
[i
][j
] == word_index
)
382 app_data
->current_movement
= DOWN
;
383 app_data
->cur_row
= i
;
384 app_data
->cur_col
= j
;
391 /* unfreeze the grid - make editing possible to change words */
392 void unfreeze_puzzle (Puzzle
*p
)
394 for (int i
= 0; i
< p
->grid_size
; i
++)
396 for (int j
= 0; j
< p
->grid_size
; j
++)
398 if (p
->chars
[i
][j
] == '#')
399 p
->chars
[i
][j
] = ' ';
401 p
->start_across_word
[i
][j
] = -1;
402 p
->start_down_word
[i
][j
] = -1;
405 p
->grid_frozen
= false;
408 /* freeze the grid - make editing impossible because it finalizes the
409 across and down words in the grid */
410 void freeze_puzzle (Puzzle
*p
)
413 bool across_word_start
, down_word_start
;
414 for (int i
= 0; i
< p
->grid_size
; i
++)
416 for (int j
= 0; j
< p
->grid_size
; j
++)
418 across_word_start
= false;
419 down_word_start
= false;
420 /* if it is a blank cell - cover it with a block */
421 if (p
->chars
[i
][j
] == ' ' || p
->chars
[i
][j
] == '#')
422 p
->chars
[i
][j
] = '#';
423 /* it is not a blank cell - check all possibilities */
426 bool prev_row
= prev_row_blank (p
, i
, j
);
427 bool next_row
= next_row_blank (p
, i
, j
);
428 bool prev_col
= prev_col_blank (p
, i
, j
);
429 bool next_col
= next_col_blank (p
, i
, j
);
430 if (prev_row
&& ! next_row
)
431 down_word_start
= true;
432 if (prev_col
&& ! next_col
)
433 across_word_start
= true;
436 if (across_word_start
== true)
437 p
->start_across_word
[i
][j
] = word_num
;
439 p
->start_across_word
[i
][j
] = -1;
440 if (down_word_start
== true)
441 p
->start_down_word
[i
][j
] = word_num
;
443 p
->start_down_word
[i
][j
] = -1;
444 if (across_word_start
== true || down_word_start
== true)
448 p
->grid_frozen
= true;
451 /* reset the entire grid */
452 void init_puzzle (Puzzle
*p
, int grid_size
)
454 p
->grid_size
= grid_size
;
455 p
->grid_frozen
= false;
456 for (int i
= 0; i
< p
->grid_size
; i
++)
458 for (int j
= 0; j
< p
->grid_size
; j
++)
460 p
->chars
[i
][j
] = ' ';
461 p
->start_across_word
[i
][j
] = -1;
462 p
->start_down_word
[i
][j
] = -1;
463 strcpy (p
->clue_across
[i
][j
], "");
464 strcpy (p
->clue_down
[i
][j
], "");
467 strcpy (p
->hashed_password
, "\0");
468 strcpy (p
->salt
, "\0");
472 /* save the puzzle to a file */
473 void save_puzzle (Puzzle
*puzzle
, const char* file
) {
475 /* First output the uncompressed contents to a temp file */
476 outfile
= tmpfile ();
479 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
482 /* grid size is the first field */
483 fprintf (outfile
, "%d\n", puzzle
->grid_size
);
484 /* whether grid is frozen or not */
485 fprintf (outfile
, "%d\n", puzzle
->grid_frozen
);
486 /* the hashed password */
487 fprintf (outfile
, "%s\n", puzzle
->hashed_password
);
489 fprintf (outfile
, "%s\n", puzzle
->salt
);
491 /* First output the grid characters columns/rows */
492 for (int i
= 0; i
< puzzle
->grid_size
; i
++)
494 for (int j
= 0; j
< puzzle
->grid_size
; j
++)
495 fprintf (outfile
, "%c", puzzle
->chars
[i
][j
]);
496 fprintf (outfile
, "\n");
499 /* Next output the start across/down numbers */
500 for (int i
= 0; i
< puzzle
->grid_size
; i
++)
502 for (int j
= 0; j
< puzzle
->grid_size
; j
++)
504 fprintf (outfile
, "%d ", puzzle
->start_across_word
[i
][j
]);
505 fprintf (outfile
, "%d ", puzzle
->start_down_word
[i
][j
]);
507 fprintf (outfile
, "\n");
510 /* Output the across clues */
511 fprintf (outfile
, "ACROSS\n");
512 /* Search the grid for across words */
513 for (int i
= 0; i
< puzzle
->grid_size
; i
++)
515 for (int j
= 0; j
< puzzle
->grid_size
; j
++)
517 /* if it is an across word, then put the word index followed by
518 tab character (as separator) and the clue */
519 if (puzzle
->start_across_word
[i
][j
] != -1)
520 fprintf (outfile
, "%d\t%s\n", puzzle
->start_across_word
[i
][j
],
521 puzzle
->clue_across
[i
][j
]);
525 /* Output the down clues */
526 fprintf (outfile
, "DOWN\n");
527 /* Search the grid for down words */
528 for (int i
= 0; i
< puzzle
->grid_size
; i
++)
530 for (int j
= 0; j
< puzzle
->grid_size
; j
++)
532 /* same as across word, put the word index followed by the tab
533 character and then the clue */
534 if (puzzle
->start_down_word
[i
][j
] != -1)
535 fprintf (outfile
, "%d\t%s\n", puzzle
->start_down_word
[i
][j
],
536 puzzle
->clue_down
[i
][j
]);
540 /* Flush the buffer and rewind to beginning - to read and save into
541 gzip compressed file */
543 fseek (outfile
, 0, 0);
545 /* now compress the file and save it to destination file */
546 gzFile outdestfile
= gzopen (file
, "wb");
547 if (outdestfile
== NULL
)
549 fprintf (stderr
, "%s\n", ERROR_WRITING_FILE
);
554 int num
= fread (buf
, sizeof(char), sizeof(char)*128, outfile
);
557 int res
= gzwrite (outdestfile
, buf
, num
*sizeof(char) );
560 fprintf (stderr
, "%s %s\n", ERROR_WRITING_FILE
, COMPRESSED
);
564 num
= fread (buf
, sizeof(char), sizeof(char)*128, outfile
);
566 gzclose (outdestfile
);
571 /* read the puzzle from a file */
572 Puzzle
load_puzzle (const char* file
) {
573 /* First open the GZip file */
574 gzFile insourcefile
= gzopen (file
, "rb");
575 if (insourcefile
== NULL
)
577 fprintf (stderr
, "%s %s\n", ERROR_READING_FILE
, COMPRESSED
);
580 /* Open a temporary file to uncompress the contents */
581 FILE *infile
= tmpfile ();
584 fprintf (stderr
, "%s\n", ERROR_READING_FILE
);
587 /* Put the uncompressed content to the temp file */
590 num
= gzread (insourcefile
, buf
, 128);
593 int res
= fwrite (buf
, 1, num
, infile
);
596 fprintf (stderr
, "%s\n", ERROR_READING_FILE
);
598 gzclose (insourcefile
);
601 num
= gzread (insourcefile
, buf
, 128);
603 /* Close the gzip file */
604 gzclose (insourcefile
);
605 /* Flush the temp file buffer and rewind to beginning */
607 fseek (infile
, 0, 0);
609 /* Read the temporary file contents to the structure Puzzle */
611 char line
[MAX_CLUE_LENGTH
+10];
612 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
613 p
.grid_size
= atoi (line
);
614 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
615 p
.grid_frozen
= atoi (line
) == 0 ? false : true ;
616 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
617 if (strlen (line
) != 1)
618 strcpy (p
.hashed_password
, strtok (line
, "\n"));
620 strcpy (p
.hashed_password
, "\0");
621 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
622 if (strlen (line
) != 1)
623 strcpy (p
.salt
, strtok (line
, "\n"));
625 strcpy (p
.salt
, "\0");
627 /* read each character of the grid */
628 for (int i
= 0; i
< p
.grid_size
; i
++ )
630 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
631 for (int j
= 0; j
< p
.grid_size
; j
++)
632 p
.chars
[i
][j
] = line
[j
];
634 /* read the word numbers */
635 for (int i
= 0; i
< p
.grid_size
; i
++)
637 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
638 char *token
= strtok (line
, " ");
639 for (int j
= 0; j
< p
.grid_size
; j
++)
642 p
.start_across_word
[i
][j
] = atoi (token
);
643 token
= strtok (NULL
, " ");
645 p
.start_down_word
[i
][j
] = atoi (token
);
646 token
= strtok (NULL
, " ");
650 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
653 char clues
[100][MAX_CLUE_LENGTH
];
656 /* first read the across clues from file */
659 fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
);
660 /* if reached the end of across clues */
661 if (strcmp (line
, "DOWN\n") == 0)
663 word_num
[c
] = atoi (strtok (line
, "\t"));
664 char *cl
= strtok (NULL
, "\n");
666 strcpy (clues
[c
], cl
);
668 strcpy (clues
[c
], "\0");
671 /* set the clue to the correct cell in grid */
672 for (int i
= 0; i
< p
.grid_size
; i
++)
674 for (int j
= 0; j
< p
.grid_size
; j
++)
676 for (int r
= 0; r
< c
; r
++)
677 if (p
.start_across_word
[i
][j
] == word_num
[r
])
678 strcpy (p
.clue_across
[i
][j
], clues
[r
]);
684 while (fgets (line
, MAX_CLUE_LENGTH
+ 10, infile
))
686 word_num
[c
] = atoi (strtok (line
, "\t"));
687 char* cl
= strtok (NULL
, "\n");
689 strcpy (clues
[c
], cl
);
691 strcpy (clues
[c
], "\0");
694 for (int i
= 0; i
< p
.grid_size
; i
++)
696 for (int j
= 0; j
< p
.grid_size
; j
++)
698 for (int r
= 0; r
< c
; r
++)
699 if (p
.start_down_word
[i
][j
] == word_num
[r
])
700 strcpy (p
.clue_down
[i
][j
], clues
[r
]);
708 /* display the puzzle */
709 void print_puzzle (Puzzle
*p
)
712 set_color (WHITE
, CYAN
, NORMAL
);
714 for (int i
= 0; i
< p
->grid_size
; i
++)
718 for (int i
= 0; i
< p
->grid_size
; i
++)
720 set_color (WHITE
, CYAN
, NORMAL
);
722 for (int j
= 0; j
< p
->grid_size
; j
++)
724 if (p
->chars
[i
][j
] == '#') {
725 set_color (WHITE
, BLACK
, NORMAL
);
730 if (p
->start_across_word
[i
][j
] != -1 ||
731 p
->start_down_word
[i
][j
] != -1)
733 set_color (BLUE
, WHITE
, NORMAL
);
734 if (p
->start_across_word
[i
][j
] != -1)
735 printf ("%-2d", p
->start_across_word
[i
][j
]);
737 printf ("%-2d", p
->start_down_word
[i
][j
]);
741 set_color (BLACK
, WHITE
,NORMAL
);
745 set_color (BLACK
, WHITE
, BOLD
);
746 printf ("%c", p
->chars
[i
][j
]);
752 /* print the clues if set */
753 if (p
->grid_frozen
== true)
755 printf ("\x1B[1mACROSS - CLUES\x1B[0m\n");
756 for (int i
= 0; i
< p
->grid_size
; i
++)
758 for (int j
= 0; j
< p
->grid_size
; j
++)
760 if (p
->start_across_word
[i
][j
] != -1)
762 printf ("%d - %s; ", p
->start_across_word
[i
][j
],
763 p
->clue_across
[i
][j
]);
767 printf ("\n\x1B[1mDOWN - CLUES\x1B[0m\n");
768 for (int i
= 0; i
< p
->grid_size
; i
++)
770 for (int j
= 0; j
< p
->grid_size
; j
++)
772 if (p
->start_down_word
[i
][j
] != -1)
774 printf ("%d - %s; ", p
->start_down_word
[i
][j
],
783 /* function to check if a word is valid or not */
784 char* is_valid_word (char *word
)
786 if (word
== NULL
|| strlen(word
) == 0)
788 for (int i
= 0; i
< strlen (word
) - 1; i
++)
789 if (! isalpha (word
[i
]))
792 return strtok (word
, "\n");
796 /* function to set a clue for an across word */
797 bool set_clue (Puzzle
*p
, String clue
, int index
, enum ORIENTATION order
)
799 for (int i
= 0; i
< p
->grid_size
; i
++)
801 for (int j
= 0; j
< p
->grid_size
; j
++)
805 if (p
->start_across_word
[i
][j
] == index
)
807 strcpy (p
->clue_across
[i
][j
], clue
);
811 else if (order
== DOWN
)
813 if (p
->start_down_word
[i
][j
] == index
)
815 strcpy (p
->clue_down
[i
][j
], clue
);
824 /* function to print a menu */
825 void print_menu (enum COLOR fg
, enum COLOR bg
, const char* title
,
826 char **items
, int num_items
, int padding
)
829 printf ("\e[1;1H\e[2J");
830 set_color (fg
, bg
, NORMAL
);
832 for (int i
= 0; i
< padding
; i
++)
835 reset_color (); printf ("\n");
836 set_color (fg
, bg
, NORMAL
);
838 set_color (fg
, bg
, BOLD
);
839 printf ("%-*s", padding
, title
);
841 set_color (fg
, bg
, NORMAL
);
843 reset_color (); printf ("\n");
844 set_color (fg
, bg
, NORMAL
);
846 for (int i
= 0; i
< padding
; i
++)
849 reset_color (); printf ("\n");
850 for (int i
= 0; i
< num_items
; i
++)
852 set_color (fg
, bg
, NORMAL
);
853 printf ("\u2551%-*s\u2551", padding
, items
[i
]);
854 reset_color (); printf ("\n");
856 set_color (fg
, bg
, NORMAL
);
858 for (int i
= 0; i
< padding
; i
++)
861 reset_color (); printf ("\n");
864 /* reset the player data, from the new file */
865 void reset_player_data (MainPlayerData
*app_data
, const char *filename
)
867 app_data
->puzzle
= load_puzzle (filename
);
869 app_data
->is_loaded
= app_data
->puzzle
.grid_frozen
;
870 app_data
->cur_col
= -1;
871 app_data
->cur_row
= -1;
872 strcpy (app_data
->filename
, filename
);
873 /* reset the answer keys */
874 for (int i
= 0; i
< app_data
->puzzle
.grid_size
; i
++)
875 for (int j
= 0; j
< app_data
->puzzle
.grid_size
; j
++)
876 app_data
->char_ans
[i
][j
] = ' ';
880 /* in the player app, move the current selection index left or right */
881 void move_current_col (MainPlayerData
*app_data
, enum DIRECTION dir
)
883 int r
= app_data
->cur_row
;
884 int c
= app_data
->cur_col
;
885 if (dir
== DIR_FORWARD
)
888 while (c
< app_data
->puzzle
.grid_size
)
890 if (app_data
->puzzle
.chars
[r
][c
] == '#')
895 if (c
< app_data
->puzzle
.grid_size
)
896 app_data
->cur_col
= c
;
903 if (app_data
->puzzle
.chars
[r
][c
] == '#')
909 app_data
->cur_col
= c
;
913 /* in the player app move the current selection index up or down */
914 void move_current_row (MainPlayerData
*app_data
, enum DIRECTION dir
)
916 int r
= app_data
->cur_row
;
917 int c
= app_data
->cur_col
;
918 if (dir
== DIR_FORWARD
)
921 while (r
< app_data
->puzzle
.grid_size
)
923 if (app_data
->puzzle
.chars
[r
][c
] == '#')
928 if (r
< app_data
->puzzle
.grid_size
)
929 app_data
->cur_row
= r
;
936 if (app_data
->puzzle
.chars
[r
][c
] == '#')
942 app_data
->cur_row
= r
;