ncurses 6.0 - patch 20151226
[ncurses.git] / test / knight.c
1 /****************************************************************************
2  * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28 /*
29  * Knight's Tour - a brain game
30  *
31  * The original of this game was anonymous.  It had an unbelievably bogus
32  * interface, you actually had to enter square coordinates!  Redesign by
33  * Eric S. Raymond <esr@snark.thyrsus.com> July 22 1995.  Mouse support
34  * added September 20th 1995.
35  *
36  * $Id: knight.c,v 1.36 2013/02/16 19:53:08 tom Exp $
37  */
38
39 #include <test.priv.h>
40
41 /* board size */
42 #define BDEPTH  8
43 #define BWIDTH  8
44
45 /* where to start the instructions */
46 #define INSTRY  2
47 #define INSTRX  35
48
49 /* corner of board */
50 #define BOARDY  2
51 #define BOARDX  0
52
53 /* notification line */
54 #define NOTIFYY 21
55
56 /* virtual color values */
57 #define TRAIL_COLOR     1
58 #define PLUS_COLOR      2
59 #define MINUS_COLOR     3
60
61 #define CX(x)           (2 + 4 * (x))
62 #define CY(y)           (1 + 2 * (y))
63 #define cellmove(y, x)  wmove(boardwin, CY(y), CX(x))
64 #define CXINV(x)        (((x) - 1) / 4)
65 #define CYINV(y)        (((y) - 2) / 2)
66
67 typedef struct {
68     short x, y;
69 } cell;
70
71 static WINDOW *boardwin;        /* the board window */
72 static WINDOW *helpwin;         /* the help window */
73 static WINDOW *msgwin;          /* the message window */
74 static cell history[BDEPTH * BWIDTH + 1];       /* choice history */
75 static chtype minus = '-';      /* possible-move character */
76 static chtype oldch;
77 static chtype plus = '+';       /* cursor hot-spot character */
78 static chtype trail = '#';      /* trail character */
79 static int movecount;           /* count of moves so far */
80 static int trialcount;          /* count of trials so far */
81 static short board[BDEPTH][BWIDTH];     /* the squares */
82 /* *INDENT-OFF* */
83 static const struct {
84     int y;
85     int x;
86 } offsets[] = {
87     {  2,  1 },
88     {  1,  2 },
89     { -1,  2 },
90     { -2,  1 },
91     { -2, -1 },
92     { -1, -2 },
93     {  1, -2 },
94     {  2, -1 },
95 };
96 /* *INDENT-ON* */
97
98 static void
99 init_program(void)
100 {
101     setlocale(LC_ALL, "");
102
103     srand((unsigned) getpid());
104     initscr();
105     cbreak();                   /* immediate char return */
106     noecho();                   /* no immediate echo */
107     boardwin = newwin(BDEPTH * 2 + 1, BWIDTH * 4 + 1, BOARDY, BOARDX);
108     helpwin = newwin(0, 0, INSTRY, INSTRX);
109     msgwin = newwin(1, INSTRX - 1, NOTIFYY, 0);
110     scrollok(msgwin, TRUE);
111     keypad(boardwin, TRUE);
112
113     if (has_colors()) {
114         int bg = COLOR_BLACK;
115
116         start_color();
117 #if HAVE_USE_DEFAULT_COLORS
118         if (use_default_colors() == OK)
119             bg = -1;
120 #endif
121
122         (void) init_pair(TRAIL_COLOR, (short) COLOR_CYAN, (short) bg);
123         (void) init_pair(PLUS_COLOR, (short) COLOR_RED, (short) bg);
124         (void) init_pair(MINUS_COLOR, (short) COLOR_GREEN, (short) bg);
125
126         trail |= (chtype) COLOR_PAIR(TRAIL_COLOR);
127         plus |= (chtype) COLOR_PAIR(PLUS_COLOR);
128         minus |= (chtype) COLOR_PAIR(MINUS_COLOR);
129     }
130 #ifdef NCURSES_MOUSE_VERSION
131     (void) mousemask(BUTTON1_CLICKED, (mmask_t *) NULL);
132 #endif /* NCURSES_MOUSE_VERSION */
133 #if defined(PDCURSES)
134     mouse_set(BUTTON1_RELEASED);
135 #endif
136
137     oldch = minus;
138 }
139
140 static void
141 help1(void)
142 /* game explanation -- initial help screen */
143 {
144     (void) waddstr(helpwin, "Knight's move is a solitaire puzzle.  Your\n");
145     (void) waddstr(helpwin, "objective is to visit each square of the  \n");
146     (void) waddstr(helpwin, "chessboard exactly once by making knight's\n");
147     (void) waddstr(helpwin, "moves (one square right or left followed  \n");
148     (void) waddstr(helpwin, "by two squares up or down, or two squares \n");
149     (void) waddstr(helpwin, "right or left followed by one square up or\n");
150     (void) waddstr(helpwin, "down).  You may start anywhere.\n\n");
151
152     (void) waddstr(helpwin, "Use arrow keys to move the cursor around.\n");
153     (void) waddstr(helpwin, "When you want to move your knight to the \n");
154     (void) waddstr(helpwin, "cursor location, press <space> or Enter.\n");
155     (void) waddstr(helpwin, "Illegal moves will be rejected with an  \n");
156     (void) waddstr(helpwin, "audible beep.\n\n");
157     (void) waddstr(helpwin, "The program will detect if you solve the\n");
158     (void) waddstr(helpwin, "puzzle; also inform you when you run out\n");
159     (void) waddstr(helpwin, "of legal moves.\n\n");
160
161     MvWAddStr(helpwin, NOTIFYY - INSTRY, 0,
162               "Press `?' to go to keystroke help.");
163 }
164
165 static void
166 help2(void)
167 /* keystroke help screen */
168 {
169     (void) waddstr(helpwin, "Possible moves are shown with `-'.\n\n");
170
171     (void) waddstr(helpwin, "You can move around with the arrow keys or\n");
172     (void) waddstr(helpwin, "with the rogue/hack movement keys.  Other\n");
173     (void) waddstr(helpwin, "commands allow you to undo moves or redraw.\n");
174     (void) waddstr(helpwin, "Your mouse may work; try left-button to\n");
175     (void) waddstr(helpwin, "move to the square under the pointer.\n\n");
176
177     (void) waddstr(helpwin, "x,q -- exit             y k u    7 8 9\n");
178     (void) waddstr(helpwin, "r -- redraw screen       \\|/      \\|/ \n");
179     (void) waddstr(helpwin, "bksp -- undo move       h-+-l    4-+-6\n");
180     (void) waddstr(helpwin, "a -- autojump            /|\\      /|\\ \n");
181     (void) waddstr(helpwin, "                        b j n    1 2 3\n");
182
183     (void) waddstr(helpwin, "\nYou can place your knight on the selected\n");
184     (void) waddstr(helpwin, "square with spacebar, Enter, or the keypad\n");
185     (void) waddstr(helpwin, "center key.  Use F/B to review the path.\n");
186
187     MvWAddStr(helpwin, NOTIFYY - INSTRY, 0,
188               "Press `?' to go to game explanation");
189 }
190
191 static void
192 show_help(bool * keyhelp)
193 {
194     werase(helpwin);
195     if (*keyhelp) {
196         help1();
197         *keyhelp = FALSE;
198     } else {
199         help2();
200         *keyhelp = TRUE;
201     }
202     wrefresh(helpwin);
203 }
204
205 static bool
206 chksqr(int r1, int c1)
207 {
208     if ((r1 < 0) || (r1 > BDEPTH - 1))
209         return (FALSE);
210     if ((c1 < 0) || (c1 > BWIDTH - 1))
211         return (FALSE);
212     return ((!board[r1][c1]) ? TRUE : FALSE);
213 }
214
215 static bool
216 chkmoves(int rw, int col)
217 /* check to see if valid moves are available */
218 {
219     unsigned n;
220
221     for (n = 0; n < SIZEOF(offsets); n++)
222         if (chksqr(rw + offsets[n].y, col + offsets[n].x))
223             return (TRUE);
224     return (FALSE);
225 }
226
227 static void
228 dosquares(void)
229 {
230     int i, j;
231
232     MvAddStr(0, 20, "KNIGHT'S MOVE -- a logical solitaire");
233
234     move(BOARDY, BOARDX);
235     waddch(boardwin, ACS_ULCORNER);
236     for (j = 0; j < 7; j++) {
237         waddch(boardwin, ACS_HLINE);
238         waddch(boardwin, ACS_HLINE);
239         waddch(boardwin, ACS_HLINE);
240         waddch(boardwin, ACS_TTEE);
241     }
242     waddch(boardwin, ACS_HLINE);
243     waddch(boardwin, ACS_HLINE);
244     waddch(boardwin, ACS_HLINE);
245     waddch(boardwin, ACS_URCORNER);
246
247     for (i = 1; i < BDEPTH; i++) {
248         move(BOARDY + i * 2 - 1, BOARDX);
249         waddch(boardwin, ACS_VLINE);
250         for (j = 0; j < BWIDTH; j++) {
251             waddch(boardwin, ' ');
252             waddch(boardwin, ' ');
253             waddch(boardwin, ' ');
254             waddch(boardwin, ACS_VLINE);
255         }
256         move(BOARDY + i * 2, BOARDX);
257         waddch(boardwin, ACS_LTEE);
258         for (j = 0; j < BWIDTH - 1; j++) {
259             waddch(boardwin, ACS_HLINE);
260             waddch(boardwin, ACS_HLINE);
261             waddch(boardwin, ACS_HLINE);
262             waddch(boardwin, ACS_PLUS);
263         }
264         waddch(boardwin, ACS_HLINE);
265         waddch(boardwin, ACS_HLINE);
266         waddch(boardwin, ACS_HLINE);
267         waddch(boardwin, ACS_RTEE);
268     }
269
270     move(BOARDY + i * 2 - 1, BOARDX);
271     waddch(boardwin, ACS_VLINE);
272     for (j = 0; j < BWIDTH; j++) {
273         waddch(boardwin, ' ');
274         waddch(boardwin, ' ');
275         waddch(boardwin, ' ');
276         waddch(boardwin, ACS_VLINE);
277     }
278
279     move(BOARDY + i * 2, BOARDX);
280     waddch(boardwin, ACS_LLCORNER);
281     for (j = 0; j < BWIDTH - 1; j++) {
282         waddch(boardwin, ACS_HLINE);
283         waddch(boardwin, ACS_HLINE);
284         waddch(boardwin, ACS_HLINE);
285         waddch(boardwin, ACS_BTEE);
286     }
287     waddch(boardwin, ACS_HLINE);
288     waddch(boardwin, ACS_HLINE);
289     waddch(boardwin, ACS_HLINE);
290     waddch(boardwin, ACS_LRCORNER);
291 }
292
293 static void
294 mark_possibles(int prow, int pcol, chtype mark)
295 {
296     unsigned n;
297
298     for (n = 0; n < SIZEOF(offsets); n++) {
299         if (chksqr(prow + offsets[n].y, pcol + offsets[n].x)) {
300             cellmove(prow + offsets[n].y, pcol + offsets[n].x);
301             waddch(boardwin, mark);
302         }
303     }
304 }
305
306 static bool
307 find_next_move(int *y, int *x)
308 {
309     unsigned j, k;
310     int found = -1;
311     int first = -1;
312     int next = -1;
313     int oldy, oldx;
314     int newy, newx;
315     bool result = FALSE;
316
317     if (movecount > 1) {
318         oldy = history[movecount - 1].y;
319         oldx = history[movecount - 1].x;
320         for (j = 0; j < SIZEOF(offsets) * 2; j++) {
321             k = j % SIZEOF(offsets);
322             newy = oldy + offsets[k].y;
323             newx = oldx + offsets[k].x;
324             if (chksqr(newy, newx)) {
325                 if (first < 0)
326                     first = (int) k;
327                 if (newy == *y
328                     && newx == *x) {
329                     found = (int) k;
330                 } else if (found >= 0) {
331                     next = (int) k;
332                     break;
333                 }
334             }
335         }
336         if (found < 0)
337             next = first;
338         if (next >= 0) {
339             *y = oldy + offsets[next].y;
340             *x = oldx + offsets[next].x;
341         }
342         result = TRUE;
343     }
344     return result;
345 }
346
347 static void
348 count_next_moves(int y, int x)
349 {
350     int count = 0;
351     unsigned j;
352
353     wprintw(msgwin, "\nMove %d", movecount);
354     for (j = 0; j < SIZEOF(offsets); j++) {
355         int newy = y + offsets[j].y;
356         int newx = x + offsets[j].x;
357         if (chksqr(newy, newx)) {
358             ++count;
359         }
360     }
361     wprintw(msgwin, ", gives %d choices", count);
362     wclrtoeol(msgwin);
363 }
364
365 static void
366 unmarkcell(int row, int column)
367 {
368     cellmove(row, column);
369     waddch(boardwin, '\b');
370     waddch(boardwin, ' ');
371     waddch(boardwin, minus);
372     waddch(boardwin, ' ');
373 }
374
375 static void
376 markcell(chtype tchar, int row, int column)
377 {
378     cellmove(row, column);
379     waddch(boardwin, '\b');
380     waddch(boardwin, tchar);
381     waddch(boardwin, tchar);
382     waddch(boardwin, tchar);
383 }
384
385 static void
386 drawmove(chtype tchar, int oldy, int oldx, int row, int column)
387 /* place the stars, update board & currents */
388 {
389     if (movecount <= 1) {
390         int i, j;
391
392         for (i = 0; i < BDEPTH; i++) {
393             for (j = 0; j < BWIDTH; j++) {
394                 if (movecount == 0) {
395                     unmarkcell(i, j);
396                 } else {
397                     cellmove(i, j);
398                     if (winch(boardwin) == minus)
399                         waddch(boardwin, movecount ? ' ' : minus);
400                 }
401             }
402         }
403     } else {
404         markcell(tchar, oldy, oldx);
405         mark_possibles(oldy, oldx, ' ');
406     }
407
408     if (row >= 0 && column >= 0) {
409         markcell(trail, row, column);
410         mark_possibles(row, column, minus);
411         board[row][column] = TRUE;
412     }
413
414     wprintw(msgwin, "\nMove %d", movecount);
415     if (trialcount != movecount)
416         wprintw(msgwin, " (%d tries)", trialcount);
417     wclrtoeol(msgwin);
418 }
419
420 static int
421 iabs(int num)
422 {
423     if (num < 0)
424         return (-num);
425     else
426         return (num);
427 }
428
429 static bool
430 evalmove(int row, int column)
431 /* evaluate move */
432 {
433     if (movecount == 1)
434         return (TRUE);
435     else if (board[row][column] == TRUE) {
436         waddstr(msgwin, "\nYou've already been there.");
437         return (FALSE);
438     } else {
439         int rdif = iabs(row - history[movecount - 1].y);
440         int cdif = iabs(column - history[movecount - 1].x);
441
442         if (!((rdif == 1) && (cdif == 2)) && !((rdif == 2) && (cdif == 1))) {
443             waddstr(msgwin, "\nThat's not a legal knight's move.");
444             return (FALSE);
445         }
446     }
447
448     return (TRUE);
449 }
450
451 static int
452 completed(void)
453 {
454     int i, j, count = 0;
455
456     for (i = 0; i < BDEPTH; i++)
457         for (j = 0; j < BWIDTH; j++)
458             if (board[i][j] != 0)
459                 count += 1;
460     return (count == (BWIDTH * BDEPTH) ? -1 : count);
461 }
462
463 static void
464 no_previous_move(void)
465 {
466     waddstr(msgwin, "\nNo previous move.");
467     beep();
468 }
469
470 static void
471 play(void)
472 /* play the game */
473 {
474     bool keyhelp;               /* TRUE if keystroke help is up */
475     int i, j, count;
476     int lastcol = 0;            /* last location visited */
477     int lastrow = 0;
478     int ny = 0, nx = 0;
479     int review = 0;             /* review history */
480     int rw = 0, col = 0;        /* current row and column */
481
482     do {
483         /* clear screen and draw board */
484         werase(boardwin);
485         werase(helpwin);
486         werase(msgwin);
487         dosquares();
488         help1();
489         wnoutrefresh(stdscr);
490         wnoutrefresh(helpwin);
491         wnoutrefresh(msgwin);
492         wnoutrefresh(boardwin);
493         doupdate();
494
495         movecount = 0;
496         for (i = 0; i < BDEPTH; i++) {
497             for (j = 0; j < BWIDTH; j++) {
498                 board[i][j] = FALSE;
499                 unmarkcell(i, j);
500             }
501         }
502         memset(history, 0, sizeof(history));
503         history[0].y = history[0].x = -1;
504         history[1].y = history[1].x = -1;
505         lastrow = lastcol = -2;
506         movecount = 1;
507         trialcount = 1;
508         keyhelp = FALSE;
509         show_help(&keyhelp);
510
511         for (;;) {
512             if (rw != lastrow || col != lastcol) {
513                 if (lastrow >= 0 && lastcol >= 0) {
514                     cellmove(lastrow, lastcol);
515                     if (board[lastrow][lastcol])
516                         waddch(boardwin, trail);
517                     else
518                         waddch(boardwin, oldch);
519                 }
520
521                 cellmove(rw, col);
522                 oldch = winch(boardwin);
523
524                 lastrow = rw;
525                 lastcol = col;
526             }
527             cellmove(rw, col);
528             waddch(boardwin, plus);
529             cellmove(rw, col);
530
531             wrefresh(msgwin);
532
533             switch (wgetch(boardwin)) {
534             case 'k':
535             case '8':
536             case KEY_UP:
537                 ny = rw + BDEPTH - 1;
538                 nx = col;
539                 break;
540             case 'j':
541             case '2':
542             case KEY_DOWN:
543                 ny = rw + 1;
544                 nx = col;
545                 break;
546             case 'h':
547             case '4':
548             case KEY_LEFT:
549                 ny = rw;
550                 nx = col + BWIDTH - 1;
551                 break;
552             case 'l':
553             case '6':
554             case KEY_RIGHT:
555                 ny = rw;
556                 nx = col + 1;
557                 break;
558             case 'y':
559             case '7':
560             case KEY_A1:
561                 ny = rw + BDEPTH - 1;
562                 nx = col + BWIDTH - 1;
563                 break;
564             case 'b':
565             case '1':
566             case KEY_C1:
567                 ny = rw + 1;
568                 nx = col + BWIDTH - 1;
569                 break;
570             case 'u':
571             case '9':
572             case KEY_A3:
573                 ny = rw + BDEPTH - 1;
574                 nx = col + 1;
575                 break;
576             case 'n':
577             case '3':
578             case KEY_C3:
579                 ny = rw + 1;
580                 nx = col + 1;
581                 break;
582
583 #ifdef KEY_MOUSE
584             case KEY_MOUSE:
585 #ifdef NCURSES_MOUSE_VERSION
586                 {
587                     MEVENT myevent;
588
589                     getmouse(&myevent);
590                     if (myevent.y >= CY(0) && myevent.y <= CY(BDEPTH)
591                         && myevent.x >= CX(0) && myevent.x <= CX(BWIDTH)) {
592                         nx = CXINV(myevent.x);
593                         ny = CYINV(myevent.y);
594                         ungetch('\n');
595                         break;
596                     } else {
597                         beep();
598                         continue;
599                     }
600                 }
601 #endif /* NCURSES_MOUSE_VERSION */
602 #ifdef PDCURSES
603                 {
604                     int test_y, test_x;
605                     request_mouse_pos();
606                     test_y = MOUSE_Y_POS + 0;
607                     test_x = MOUSE_X_POS + 1;
608                     if (test_y >= CY(0) && test_y <= CY(BDEPTH)
609                         && test_x >= CX(0) && test_x <= CX(BWIDTH)) {
610                         ny = CYINV(test_y);
611                         nx = CXINV(test_x);
612                         wmove(helpwin, 0, 0);
613                         wrefresh(helpwin);
614                         ungetch('\n');
615                     }
616                     break;
617                 }
618 #endif /* PDCURSES */
619 #endif /* KEY_MOUSE */
620
621             case KEY_B2:
622             case '\n':
623             case ' ':
624                 review = 0;
625                 if (evalmove(rw, col)) {
626                     drawmove(trail,
627                              history[movecount - 1].y,
628                              history[movecount - 1].x,
629                              rw, col);
630                     history[movecount].y = (short) rw;
631                     history[movecount].x = (short) col;
632                     movecount++;
633                     trialcount++;
634
635                     if (!chkmoves(rw, col)) {
636                         if (completed() < 0) {
637                             waddstr(msgwin, "\nYou won.");
638                         } else {
639                             waddstr(msgwin,
640                                     "\nNo further moves are possible.");
641                         }
642                     }
643                 } else {
644                     beep();
645                 }
646                 break;
647
648             case KEY_UNDO:
649             case KEY_BACKSPACE:
650             case '\b':
651                 review = 0;
652                 if (movecount <= 0) {
653                     no_previous_move();
654                 } else if (movecount <= 1) {
655                     ny = history[movecount].y;
656                     nx = history[movecount].x;
657                     if (nx < 0 || ny < 0) {
658                         ny = (lastrow >= 0) ? lastrow : 0;
659                         nx = (lastcol >= 0) ? lastcol : 0;
660                     }
661                     movecount = 0;
662                     board[ny][nx] = FALSE;
663                     oldch = minus;
664                     drawmove(' ', ny, nx, -1, -1);
665                     movecount = 1;
666                     trialcount = 1;
667                     no_previous_move();
668                 } else {
669                     int oldy = history[movecount - 1].y;
670                     int oldx = history[movecount - 1].x;
671
672                     if (!board[rw][col]) {
673                         cellmove(rw, col);
674                         waddch(boardwin, ' ');
675                     }
676
677                     board[oldy][oldx] = FALSE;
678                     --movecount;
679                     ny = history[movecount - 1].y;
680                     nx = history[movecount - 1].x;
681                     if (nx < 0 || ny < 0) {
682                         ny = oldy;
683                         nx = oldx;
684                     }
685                     drawmove(' ', oldy, oldx, ny, nx);
686
687                     /* avoid problems if we just changed the current cell */
688                     cellmove(lastrow, lastcol);
689                     oldch = winch(boardwin);
690                 }
691                 break;
692
693             case 'a':
694                 nx = col;
695                 ny = rw;
696                 if (find_next_move(&ny, &nx))
697                     count_next_moves(ny, nx);
698                 else
699                     beep();
700                 break;
701
702             case 'F':
703                 if (review > 0) {
704                     review--;
705                     ny = history[movecount - review - 1].y;
706                     nx = history[movecount - review - 1].x;
707                 } else {
708                     beep();
709                 }
710                 break;
711
712             case 'B':
713                 if (review < movecount - 2) {
714                     review++;
715                     ny = history[movecount - review - 1].y;
716                     nx = history[movecount - review - 1].x;
717                 } else {
718                     beep();
719                 }
720                 break;
721
722             case KEY_REDO:
723             case '\f':
724             case 'r':
725                 clearok(curscr, TRUE);
726                 wnoutrefresh(stdscr);
727                 wnoutrefresh(boardwin);
728                 wnoutrefresh(msgwin);
729                 wnoutrefresh(helpwin);
730                 doupdate();
731                 break;
732
733             case 'q':
734             case 'x':
735                 goto dropout;
736
737             case '?':
738                 show_help(&keyhelp);
739                 break;
740
741             default:
742                 beep();
743                 break;
744             }
745
746             col = nx % BWIDTH;
747             rw = ny % BDEPTH;
748         }
749
750       dropout:
751         if ((count = completed()) < 0)
752             wprintw(msgwin, "\nYou won.  Care to try again? ");
753         else
754             wprintw(msgwin, "\n%d squares filled.  Try again? ", count);
755         wclrtoeol(msgwin);
756     } while
757         (tolower(wgetch(msgwin)) == 'y');
758 }
759
760 int
761 main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
762 {
763     init_program();
764
765     play();
766
767     endwin();
768     ExitProgram(EXIT_SUCCESS);
769 }
770
771 /* knight.c ends here */