]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ncurses/test/hanoi.c
This commit was generated by cvs2svn to compensate for changes in r164146,
[FreeBSD/FreeBSD.git] / contrib / ncurses / test / hanoi.c
1 /*
2  *      Name: Towers of Hanoi.
3  *
4  *      Desc:
5  *              This is a playable copy of towers of hanoi.
6  *              Its sole purpose is to demonstrate my Amiga Curses package.
7  *              This program should compile on any system that has Curses.
8  *              'hanoi'         will give a manual game with 7 playing pieces.
9  *              'hanoi n'       will give a manual game with n playing pieces.
10  *              'hanoi n a' will give an auto solved game with n playing pieces.
11  *
12  *      Author: Simon J Raybould        (sie@fulcrum.bt.co.uk).
13  *      (This version has been slightly modified by the ncurses maintainers.)
14  *
15  *      Date: 05.Nov.90
16  *
17  * $Id: hanoi.c,v 1.23 2002/03/24 00:40:01 tom Exp $
18  */
19
20 #include <test.priv.h>
21
22 #define NPEGS                   3       /* This is not configurable !! */
23 #define MINTILES                3
24 #define MAXTILES                9
25 #define DEFAULTTILES            7
26 #define TOPLINE                 6
27 #define BASELINE                16
28 #define STATUSLINE              (LINES-3)
29 #define LEFTPEG                 19
30 #define MIDPEG                  39
31 #define RIGHTPEG                59
32
33 #define LENTOIND(x)             (((x)-1)/2)
34 #define OTHER(a,b)              (3-((a)+(b)))
35
36 struct Peg {
37     size_t Length[MAXTILES];
38     int Count;
39 };
40
41 static struct Peg Pegs[NPEGS];
42 static int PegPos[] =
43 {LEFTPEG, MIDPEG, RIGHTPEG};
44 static int TileColour[] =
45 {
46     COLOR_GREEN,                /* Length 3 */
47     COLOR_MAGENTA,              /* Length 5 */
48     COLOR_RED,                  /* Length 7 */
49     COLOR_BLUE,                 /* Length 9 */
50     COLOR_CYAN,                 /* Length 11 */
51     COLOR_YELLOW,               /* Length 13 */
52     COLOR_GREEN,                /* Length 15 */
53     COLOR_MAGENTA,              /* Length 17 */
54     COLOR_RED,                  /* Length 19 */
55 };
56 static int NMoves = 0;
57
58 static void InitTiles(int NTiles);
59 static void DisplayTiles(void);
60 static void MakeMove(int From, int To);
61 static void AutoMove(int From, int To, int Num);
62 static void Usage(void);
63 static int Solved(int NumTiles);
64 static int GetMove(int *From, int *To);
65 static int InvalidMove(int From, int To);
66
67 int
68 main(int argc, char **argv)
69 {
70     int NTiles, FromCol, ToCol;
71     bool AutoFlag = 0;
72
73     switch (argc) {
74     case 1:
75         NTiles = DEFAULTTILES;
76         break;
77     case 2:
78         NTiles = atoi(argv[1]);
79         if (NTiles > MAXTILES || NTiles < MINTILES) {
80             fprintf(stderr, "Range %d to %d\n", MINTILES, MAXTILES);
81             ExitProgram(EXIT_FAILURE);
82         }
83         break;
84     case 3:
85         if (strcmp(argv[2], "a")) {
86             Usage();
87             ExitProgram(EXIT_FAILURE);
88         }
89         NTiles = atoi(argv[1]);
90         if (NTiles > MAXTILES || NTiles < MINTILES) {
91             fprintf(stderr, "Range %d to %d\n", MINTILES, MAXTILES);
92             ExitProgram(EXIT_FAILURE);
93         }
94         AutoFlag = TRUE;
95         break;
96     default:
97         Usage();
98         ExitProgram(EXIT_FAILURE);
99     }
100 #ifdef TRACE
101     trace(TRACE_MAXIMUM);
102 #endif
103     initscr();
104     if (has_colors()) {
105         int i;
106         int bg = COLOR_BLACK;
107         start_color();
108 #if HAVE_USE_DEFAULT_COLORS
109         if (use_default_colors() == OK)
110             bg = -1;
111 #endif
112         for (i = 0; i < 9; i++)
113             init_pair(i + 1, bg, TileColour[i]);
114     }
115     cbreak();
116     if (LINES < 24) {
117         endwin();
118         fprintf(stderr, "Min screen length 24 lines\n");
119         ExitProgram(EXIT_FAILURE);
120     }
121     if (AutoFlag) {
122         curs_set(0);
123         leaveok(stdscr, TRUE);  /* Attempt to remove cursor */
124     }
125     InitTiles(NTiles);
126     DisplayTiles();
127     if (AutoFlag) {
128         do {
129             noecho();
130             AutoMove(0, 2, NTiles);
131         } while (!Solved(NTiles));
132         sleep(2);
133     } else {
134         echo();
135         for (;;) {
136             if (GetMove(&FromCol, &ToCol))
137                 break;
138             if (InvalidMove(FromCol, ToCol)) {
139                 mvaddstr(STATUSLINE, 0, "Invalid Move !!");
140                 refresh();
141                 beep();
142                 continue;
143             }
144             MakeMove(FromCol, ToCol);
145             if (Solved(NTiles)) {
146                 mvprintw(STATUSLINE, 0,
147                          "Well Done !! You did it in %d moves", NMoves);
148                 refresh();
149                 sleep(5);
150                 break;
151             }
152         }
153     }
154     endwin();
155     ExitProgram(EXIT_SUCCESS);
156 }
157
158 static int
159 InvalidMove(int From, int To)
160 {
161     if (From >= NPEGS)
162         return TRUE;
163     if (From < 0)
164         return TRUE;
165     if (To >= NPEGS)
166         return TRUE;
167     if (To < 0)
168         return TRUE;
169     if (From == To)
170         return TRUE;
171     if (!Pegs[From].Count)
172         return TRUE;
173     if (Pegs[To].Count &&
174         Pegs[From].Length[Pegs[From].Count - 1] >
175         Pegs[To].Length[Pegs[To].Count - 1])
176         return TRUE;
177     return FALSE;
178 }
179
180 static void
181 InitTiles(int NTiles)
182 {
183     int Size, SlotNo;
184
185     for (Size = NTiles * 2 + 1, SlotNo = 0; Size >= 3; Size -= 2)
186         Pegs[0].Length[SlotNo++] = Size;
187
188     Pegs[0].Count = NTiles;
189     Pegs[1].Count = 0;
190     Pegs[2].Count = 0;
191 }
192
193 static void
194 DisplayTiles(void)
195 {
196     int Line, peg, SlotNo;
197     char TileBuf[BUFSIZ];
198
199     erase();
200     mvaddstr(1, 24, "T O W E R S   O F   H A N O I");
201     mvaddstr(3, 34, "SJR 1990");
202     mvprintw(19, 5, "Moves : %d", NMoves);
203     attrset(A_REVERSE);
204     mvaddstr(BASELINE, 8,
205              "                                                               ");
206
207     for (Line = TOPLINE; Line < BASELINE; Line++) {
208         mvaddch(Line, LEFTPEG, ' ');
209         mvaddch(Line, MIDPEG, ' ');
210         mvaddch(Line, RIGHTPEG, ' ');
211     }
212     mvaddch(BASELINE, LEFTPEG, '1');
213     mvaddch(BASELINE, MIDPEG, '2');
214     mvaddch(BASELINE, RIGHTPEG, '3');
215     attrset(A_NORMAL);
216
217     /* Draw tiles */
218     for (peg = 0; peg < NPEGS; peg++) {
219         for (SlotNo = 0; SlotNo < Pegs[peg].Count; SlotNo++) {
220             memset(TileBuf, ' ', Pegs[peg].Length[SlotNo]);
221             TileBuf[Pegs[peg].Length[SlotNo]] = '\0';
222             if (has_colors())
223                 attrset(COLOR_PAIR(LENTOIND(Pegs[peg].Length[SlotNo])));
224             else
225                 attrset(A_REVERSE);
226             mvaddstr(BASELINE - (SlotNo + 1),
227                      (int) (PegPos[peg] - Pegs[peg].Length[SlotNo] / 2),
228                      TileBuf);
229         }
230     }
231     attrset(A_NORMAL);
232     refresh();
233 }
234
235 static int
236 GetMove(int *From, int *To)
237 {
238     mvaddstr(STATUSLINE, 0, "Next move ('q' to quit) from ");
239     clrtoeol();
240     refresh();
241     if ((*From = getch()) == 'q')
242         return TRUE;
243     *From -= ('0' + 1);
244     addstr(" to ");
245     clrtoeol();
246     refresh();
247
248     if ((*To = getch()) == 'q')
249         return TRUE;
250     *To -= ('0' + 1);
251     refresh();
252     napms(500);
253
254     move(STATUSLINE, 0);
255     clrtoeol();
256     refresh();
257     return FALSE;
258 }
259
260 static void
261 MakeMove(int From, int To)
262 {
263     Pegs[From].Count--;
264     Pegs[To].Length[Pegs[To].Count] = Pegs[From].Length[Pegs[From].Count];
265     Pegs[To].Count++;
266     NMoves++;
267     DisplayTiles();
268 }
269
270 static void
271 AutoMove(int From, int To, int Num)
272 {
273     if (Num == 1) {
274         MakeMove(From, To);
275         napms(500);
276         return;
277     }
278     AutoMove(From, OTHER(From, To), Num - 1);
279     MakeMove(From, To);
280     napms(500);
281     AutoMove(OTHER(From, To), To, Num - 1);
282 }
283
284 static int
285 Solved(int NumTiles)
286 {
287     int i;
288
289     for (i = 1; i < NPEGS; i++)
290         if (Pegs[i].Count == NumTiles)
291             return TRUE;
292     return FALSE;
293 }
294
295 static void
296 Usage(void)
297 {
298     fprintf(stderr, "Usage: hanoi [<No Of Tiles>] [a]\n");
299     fprintf(stderr,
300             "The 'a' option causes the tower to be solved automatically\n");
301 }