xref: /reactos/modules/rosapps/demos/maze/maze.c (revision c2c66aff)
1 /******************************************************************************
2  * [ maze ] ...
3  *
4  * modified:  [ 03-08-15 ] Ge van Geldorp <ge@gse.nl>
5  *		ported to ReactOS
6  * modified:  [ 94-10-8 ] Ge van Geldorp <Ge.vanGeldorp@lr.tudelft.nl>
7  *		ported to MS Windows
8  * modified:  [ 3-7-93 ]  Jamie Zawinski <jwz@lucid.com>
9  *		added the XRoger logo, cleaned up resources, made
10  *		grid size a parameter.
11  * modified:  [ 3-3-93 ]  Jim Randell <jmr@mddjmr.fc.hp.com>
12  *		Added the colour stuff and integrated it with jwz's
13  *		screenhack stuff.  There's still some work that could
14  *		be done on this, particularly allowing a resource to
15  *		specify how big the squares are.
16  * modified:  [ 10-4-88 ]  Richard Hess    ...!uunet!cimshop!rhess
17  *              [ Revised primary execution loop within main()...
18  *              [ Extended X event handler, check_events()...
19  * modified:  [ 1-29-88 ]  Dave Lemke      lemke@sun.com
20  *              [ Hacked for X11...
21  *              [  Note the word "hacked" -- this is extremely ugly, but at
22  *              [   least it does the job.  NOT a good programming example
23  *              [   for X.
24  * original:  [ 6/21/85 ]  Martin Weiss    Sun Microsystems  [ SunView ]
25  *
26  ******************************************************************************
27  Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA.
28 
29  All Rights Reserved
30 
31  Permission to use, copy, modify, and distribute this software and its
32  documentation for any purpose and without fee is hereby granted,
33  provided that the above copyright notice appear in all copies and that
34  both that copyright notice and this permission notice appear in
35  supporting documentation, and that the names of Sun or MIT not be
36  used in advertising or publicity pertaining to distribution of the
37  software without specific prior written permission. Sun and M.I.T.
38  make no representations about the suitability of this software for
39  any purpose. It is provided "as is" without any express or implied warranty.
40 
41  SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
42  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43  PURPOSE. IN NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT
44  OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
45  OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
46  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
47  OR PERFORMANCE OF THIS SOFTWARE.
48  *****************************************************************************/
49 
50 #define STRICT
51 
52 #include <stdlib.h>
53 #include <string.h>
54 #include <time.h>
55 #include <windows.h>   	/* required for all Windows applications */
56 
57 #if !defined (APIENTRY) /* Windows NT defines APIENTRY, but 3.x doesn't */
58 #define APIENTRY far pascal
59 #endif
60 
61 #if !defined(WIN32)		/* Windows 3.x uses a FARPROC for dialogs */
62 #define DLGPROC FARPROC
63 #endif
64 
65 static BOOL InitApplication(HINSTANCE hInstance);
66 static BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
67 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM uParam,
68                          LPARAM lParam);
69 
70 HINSTANCE hInst;          	/* current instance */
71 HWND      hWnd; 			/* Main window handle.*/
72 HBRUSH hBrushDead;
73 HBRUSH hBrushLiving;
74 HDC    hDC;
75 static BOOL waiting;
76 
77 
78 char szAppName[] = "Maze";  /* The name of this application */
79 char szTitle[]   = "Maze"; 	/* The title bar text */
80 
81 static int solve_delay, pre_solve_delay, post_solve_delay;
82 
83 #define MAX_MAZE_SIZE_X	((unsigned long) 250)
84 #define MAX_MAZE_SIZE_Y	((unsigned long) 250)
85 
86 #define MOVE_LIST_SIZE  (MAX_MAZE_SIZE_X * MAX_MAZE_SIZE_Y)
87 
88 #define WALL_TOP	0x8000
89 #define WALL_RIGHT	0x4000
90 #define WALL_BOTTOM	0x2000
91 #define WALL_LEFT	0x1000
92 
93 #define DOOR_IN_TOP	0x800
94 #define DOOR_IN_RIGHT	0x400
95 #define DOOR_IN_BOTTOM	0x200
96 #define DOOR_IN_LEFT	0x100
97 #define DOOR_IN_ANY	0xF00
98 
99 #define DOOR_OUT_TOP	0x80
100 #define DOOR_OUT_RIGHT	0x40
101 #define DOOR_OUT_BOTTOM	0x20
102 #define DOOR_OUT_LEFT	0x10
103 
104 #define START_SQUARE	0x2
105 #define END_SQUARE	0x1
106 
107 #define	border_x        (0)
108 #define	border_y        (0)
109 
110 #define	get_random(x)	(rand() % (x))
111 
112 static unsigned short maze[MAX_MAZE_SIZE_X][MAX_MAZE_SIZE_Y];
113 
114 static struct {
115   unsigned char x;
116   unsigned char y;
117   unsigned char dir;
118   unsigned char dummy;
119 } move_list[MOVE_LIST_SIZE], save_path[MOVE_LIST_SIZE], path[MOVE_LIST_SIZE];
120 
121 static int maze_size_x, maze_size_y;
122 static long sqnum, path_length;
123 static int cur_sq_x, cur_sq_y;
124 static int start_x, start_y, start_dir, end_x, end_y, end_dir;
125 static int grid_width, grid_height;
126 
127 static int state = 1, pathi = 0;
128 
129 static void
set_maze_sizes(width,height)130 set_maze_sizes (width, height)
131      int width, height;
132 {
133   maze_size_x = width / grid_width;
134   maze_size_y = height / grid_height;
135 }
136 
137 
138 static void
initialize_maze()139 initialize_maze()         /* draw the surrounding wall and start/end squares */
140 {
141   register int i, j, wall;
142 
143   /* initialize all squares */
144   for ( i=0; i<maze_size_x; i++) {
145     for ( j=0; j<maze_size_y; j++) {
146       maze[i][j] = 0;
147     }
148   }
149 
150   /* top wall */
151   for ( i=0; i<maze_size_x; i++ ) {
152     maze[i][0] |= WALL_TOP;
153   }
154 
155   /* right wall */
156   for ( j=0; j<maze_size_y; j++ ) {
157     maze[maze_size_x-1][j] |= WALL_RIGHT;
158   }
159 
160   /* bottom wall */
161   for ( i=0; i<maze_size_x; i++ ) {
162     maze[i][maze_size_y-1] |= WALL_BOTTOM;
163   }
164 
165   /* left wall */
166   for ( j=0; j<maze_size_y; j++ ) {
167     maze[0][j] |= WALL_LEFT;
168   }
169 
170   /* set start square */
171   wall = get_random(4);
172   switch (wall) {
173   case 0:
174     i = get_random(maze_size_x);
175     j = 0;
176     break;
177   case 1:
178     i = maze_size_x - 1;
179     j = get_random(maze_size_y);
180     break;
181   case 2:
182     i = get_random(maze_size_x);
183     j = maze_size_y - 1;
184     break;
185   case 3:
186     i = 0;
187     j = get_random(maze_size_y);
188     break;
189   }
190   maze[i][j] |= START_SQUARE;
191   maze[i][j] |= ( DOOR_IN_TOP >> wall );
192   maze[i][j] &= ~( WALL_TOP >> wall );
193   cur_sq_x = i;
194   cur_sq_y = j;
195   start_x = i;
196   start_y = j;
197   start_dir = wall;
198   sqnum = 0;
199 
200   /* set end square */
201   wall = (wall + 2)%4;
202   switch (wall) {
203   case 0:
204     i = get_random(maze_size_x);
205     j = 0;
206     break;
207   case 1:
208     i = maze_size_x - 1;
209     j = get_random(maze_size_y);
210     break;
211   case 2:
212     i = get_random(maze_size_x);
213     j = maze_size_y - 1;
214     break;
215   case 3:
216     i = 0;
217     j = get_random(maze_size_y);
218     break;
219   }
220   maze[i][j] |= END_SQUARE;
221   maze[i][j] |= ( DOOR_OUT_TOP >> wall );
222   maze[i][j] &= ~( WALL_TOP >> wall );
223   end_x = i;
224   end_y = j;
225   end_dir = wall;
226 }
227 
228 static int choose_door ();
229 static long backup ();
230 static void draw_wall ();
231 static void draw_solid_square(int, int, int, HDC, HBRUSH);
232 static void enter_square(int, HDC, HBRUSH);
233 
234 static void
create_maze()235 create_maze()             /* create a maze layout given the intiialized maze */
236 {
237   register int i, newdoor = 0;
238   HDC hDC;
239 
240   hDC = GetDC(hWnd);
241   do {
242     move_list[sqnum].x = cur_sq_x;
243     move_list[sqnum].y = cur_sq_y;
244     move_list[sqnum].dir = newdoor;
245     while ( ( newdoor = choose_door(hDC) ) == -1 ) { /* pick a door */
246       if ( backup() == -1 ) { /* no more doors ... backup */
247 	    ReleaseDC(hWnd, hDC);
248 		return; /* done ... return */
249       }
250     }
251 
252     /* mark the out door */
253     maze[cur_sq_x][cur_sq_y] |= ( DOOR_OUT_TOP >> newdoor );
254 
255     switch (newdoor) {
256     case 0: cur_sq_y--;
257       break;
258     case 1: cur_sq_x++;
259       break;
260     case 2: cur_sq_y++;
261       break;
262     case 3: cur_sq_x--;
263       break;
264     }
265     sqnum++;
266 
267     /* mark the in door */
268     maze[cur_sq_x][cur_sq_y] |= ( DOOR_IN_TOP >> ((newdoor+2)%4) );
269 
270     /* if end square set path length and save path */
271     if ( maze[cur_sq_x][cur_sq_y] & END_SQUARE ) {
272       path_length = sqnum;
273       for ( i=0; i<path_length; i++) {
274 	save_path[i].x = move_list[i].x;
275 	save_path[i].y = move_list[i].y;
276 	save_path[i].dir = move_list[i].dir;
277       }
278     }
279 
280   } while (1);
281 
282 }
283 
284 
285 static int
choose_door(HDC hDC)286 choose_door(HDC hDC)                                    /* pick a new path */
287 {
288   int candidates[3];
289   register int num_candidates;
290 
291   num_candidates = 0;
292 
293   /* top wall */
294   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_TOP )
295     goto rightwall;
296   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_TOP )
297     goto rightwall;
298   if ( maze[cur_sq_x][cur_sq_y] & WALL_TOP )
299     goto rightwall;
300   if ( maze[cur_sq_x][cur_sq_y - 1] & DOOR_IN_ANY ) {
301     maze[cur_sq_x][cur_sq_y] |= WALL_TOP;
302     maze[cur_sq_x][cur_sq_y - 1] |= WALL_BOTTOM;
303     draw_wall(cur_sq_x, cur_sq_y, 0, hDC);
304     goto rightwall;
305   }
306   candidates[num_candidates++] = 0;
307 
308  rightwall:
309   /* right wall */
310   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_RIGHT )
311     goto bottomwall;
312   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_RIGHT )
313     goto bottomwall;
314   if ( maze[cur_sq_x][cur_sq_y] & WALL_RIGHT )
315     goto bottomwall;
316   if ( maze[cur_sq_x + 1][cur_sq_y] & DOOR_IN_ANY ) {
317     maze[cur_sq_x][cur_sq_y] |= WALL_RIGHT;
318     maze[cur_sq_x + 1][cur_sq_y] |= WALL_LEFT;
319     draw_wall(cur_sq_x, cur_sq_y, 1, hDC);
320     goto bottomwall;
321   }
322   candidates[num_candidates++] = 1;
323 
324  bottomwall:
325   /* bottom wall */
326   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_BOTTOM )
327     goto leftwall;
328   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_BOTTOM )
329     goto leftwall;
330   if ( maze[cur_sq_x][cur_sq_y] & WALL_BOTTOM )
331     goto leftwall;
332   if ( maze[cur_sq_x][cur_sq_y + 1] & DOOR_IN_ANY ) {
333     maze[cur_sq_x][cur_sq_y] |= WALL_BOTTOM;
334     maze[cur_sq_x][cur_sq_y + 1] |= WALL_TOP;
335     draw_wall(cur_sq_x, cur_sq_y, 2, hDC);
336     goto leftwall;
337   }
338   candidates[num_candidates++] = 2;
339 
340  leftwall:
341   /* left wall */
342   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_LEFT )
343     goto donewall;
344   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_LEFT )
345     goto donewall;
346   if ( maze[cur_sq_x][cur_sq_y] & WALL_LEFT )
347     goto donewall;
348   if ( maze[cur_sq_x - 1][cur_sq_y] & DOOR_IN_ANY ) {
349     maze[cur_sq_x][cur_sq_y] |= WALL_LEFT;
350     maze[cur_sq_x - 1][cur_sq_y] |= WALL_RIGHT;
351     draw_wall(cur_sq_x, cur_sq_y, 3, hDC);
352     goto donewall;
353   }
354   candidates[num_candidates++] = 3;
355 
356  donewall:
357   if (num_candidates == 0)
358     return ( -1 );
359   if (num_candidates == 1)
360     return ( candidates[0] );
361   return ( candidates[ get_random(num_candidates) ] );
362 
363 }
364 
365 
366 static long
backup()367 backup()                                                  /* back up a move */
368 {
369   sqnum--;
370   if (0 <= sqnum) {
371   	cur_sq_x = move_list[sqnum].x;
372   	cur_sq_y = move_list[sqnum].y;
373   }
374   return ( sqnum );
375 }
376 
377 int bw;
378 
379 static void
draw_solid_square(i,j,dir,hDC,hBrush)380 draw_solid_square(i, j, dir, hDC, hBrush)          /* draw a solid square in a square */
381      register int i, j, dir;
382      HDC hDC;
383 	 HBRUSH hBrush;
384 {
385   RECT rc;
386 
387   switch (dir) {
388   case 0:
389     rc.left = border_x + bw + grid_width * i;
390 	rc.right = rc.left + grid_width - (bw + bw);
391 	rc.top = border_y - bw + grid_height * j;
392 	rc.bottom = rc.top + grid_height;
393     break;
394   case 1:
395 	rc.left = border_x + bw + grid_width * i;
396 	rc.right = rc.left + grid_width;
397 	rc.top = border_y + bw + grid_height * j;
398 	rc.bottom = rc.top + grid_height - (bw + bw);
399     break;
400   case 2:
401     rc.left = border_x + bw + grid_width * i;
402 	rc.right = rc.left + grid_width - (bw + bw);
403 	rc.top = border_y + bw + grid_height * j;
404 	rc.bottom = rc.top + grid_height;
405     break;
406   case 3:
407   	rc.left = border_x - bw + grid_width * i;
408 	rc.right = rc.left + grid_width;
409 	rc.top = border_y + bw + grid_height * j;
410 	rc.bottom = rc.top + grid_height - (bw + bw);
411     break;
412   }
413   (void) FillRect(hDC, &rc, hBrush);
414 }
415 
416 static void
draw_maze_border(HWND hWnd,HDC hDC)417 draw_maze_border(HWND hWnd, HDC hDC)	/* draw the maze outline */
418 {
419   register int i, j;
420   HBRUSH hBrush;
421 
422 
423   for ( i=0; i<maze_size_x; i++) {
424     if ( maze[i][0] & WALL_TOP ) {
425 	  MoveToEx(hDC, border_x + grid_width * i, border_y, NULL);
426 	  (void) LineTo(hDC, border_x + grid_width * (i + 1) - 1, border_y);
427     }
428     if ((maze[i][maze_size_y - 1] & WALL_BOTTOM)) {
429 	  MoveToEx(hDC, border_x + grid_width * i,
430 	           border_y + grid_height * (maze_size_y) - 1, NULL);
431 	  (void) LineTo(hDC, border_x + grid_width * (i+1) - 1,
432 		            border_y + grid_height * (maze_size_y) - 1);
433     }
434   }
435   for ( j=0; j<maze_size_y; j++) {
436     if ( maze[maze_size_x - 1][j] & WALL_RIGHT ) {
437 	  MoveToEx(hDC, border_x + grid_width * maze_size_x - 1,
438 		       border_y + grid_height * j, NULL);
439 	  (void) LineTo(hDC, border_x + grid_width * maze_size_x - 1,
440 		            border_y + grid_height * (j+1) - 1);
441     }
442     if ( maze[0][j] & WALL_LEFT ) {
443 	  MoveToEx(hDC, border_x, border_y + grid_height * j, NULL);
444 	  (void) LineTo(hDC, border_x, border_y + grid_height * (j+1) - 1);
445     }
446   }
447 
448   hBrush = GetStockObject(BLACK_BRUSH);
449   draw_solid_square (start_x, start_y, start_dir, hDC, hBrush);
450   draw_solid_square (end_x, end_y, end_dir, hDC, hBrush);
451 }
452 
453 
454 static void
draw_wall(i,j,dir,hDC)455 draw_wall(i, j, dir, hDC)                                   /* draw a single wall */
456      int i, j, dir;
457 	 HDC hDC;
458 {
459   switch (dir) {
460   case 0:
461   	MoveToEx(hDC, border_x + grid_width * i, border_y + grid_height * j, NULL);
462 	(void) LineTo(hDC, border_x + grid_width * (i+1),
463 	              border_y + grid_height * j);
464     break;
465   case 1:
466 	MoveToEx(hDC, border_x + grid_width * (i+1), border_y + grid_height * j,
467 	         NULL);
468 	(void) LineTo(hDC, border_x + grid_width * (i+1),
469 	              border_y + grid_height * (j+1));
470     break;
471   case 2:
472 	MoveToEx(hDC, border_x + grid_width * i, border_y + grid_height * (j+1),
473 	         NULL);
474 	(void) LineTo(hDC, border_x + grid_width * (i+1),
475 	              border_y + grid_height * (j+1));
476     break;
477   case 3:
478 	MoveToEx(hDC, border_x + grid_width * i, border_y + grid_height * j,
479 	         NULL);
480 	(void) LineTo(hDC, border_x + grid_width * i,
481 	              border_y + grid_height * (j+1));
482     break;
483   }
484 }
485 
486 static void
begin_solve_maze()487 begin_solve_maze()                             /* solve it with graphical feedback */
488 {
489   static long grayPattern[] = {
490 	0x55555555,
491 	0xaaaaaaaa,
492 	0x55555555,
493 	0xaaaaaaaa,
494 	0x55555555,
495 	0xaaaaaaaa,
496 	0x55555555,
497 	0xaaaaaaaa
498   };
499   static RGBQUAD argbq[] = {
500   	{ 0, 0, 255, 0 },
501 	{ 255, 255, 255, 0 }
502   };
503   BITMAPINFO *pbmi;
504 
505   hDC = GetDC(hWnd);
506   pbmi = malloc(sizeof(BITMAPINFOHEADER) + sizeof(argbq) + sizeof(grayPattern));
507   pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
508   pbmi->bmiHeader.biWidth = 8;
509   pbmi->bmiHeader.biHeight = 8;
510   pbmi->bmiHeader.biPlanes = 1;
511   pbmi->bmiHeader.biBitCount = 1;
512   pbmi->bmiHeader.biCompression = BI_RGB;
513   (void) memcpy(pbmi->bmiColors, argbq, sizeof(argbq));
514   (void) memcpy(pbmi->bmiColors + 2, grayPattern, sizeof(grayPattern));
515 #if 0
516   /* FIXME Pattern brushes not yet implemented in ReactOS */
517   hBrushDead = CreateDIBPatternBrushPt(pbmi, DIB_RGB_COLORS);
518 #else
519   hBrushDead = CreateSolidBrush(RGB(255, 0, 0));
520 #endif
521 //  hBrushDead = CreateHatchBrush(HS_DIAGCROSS, RGB(255, 0, 0));
522   free(pbmi);
523   hBrushLiving = CreateSolidBrush(RGB(0, 255, 0));
524 
525   /* plug up the surrounding wall */
526   maze[start_x][start_y] |= (WALL_TOP >> start_dir);
527   maze[end_x][end_y] |= (WALL_TOP >> end_dir);
528 
529   /* initialize search path */
530   pathi = 0;
531   path[pathi].x = end_x;
532   path[pathi].y = end_y;
533   path[pathi].dir = -1;
534 }
535 
536 static int
solve_maze()537 solve_maze()                             /* solve it with graphical feedback */
538 {
539   int ret;
540   int action_done;
541 
542   do {
543     action_done = 1;
544     if ( ++path[pathi].dir >= 4 ) {
545       pathi--;
546       draw_solid_square( (int)(path[pathi].x), (int)(path[pathi].y),
547 	  	       (int)(path[pathi].dir), hDC, hBrushDead);
548       ret = 0;
549     }
550     else if ( ! (maze[path[pathi].x][path[pathi].y] &
551 	  	(WALL_TOP >> path[pathi].dir))  &&
552 	     ( (pathi == 0) || ( (path[pathi].dir !=
553 		  	    (int)(path[pathi-1].dir+2)%4) ) ) ) {
554       enter_square(pathi, hDC, hBrushLiving);
555       pathi++;
556       if ( maze[path[pathi].x][path[pathi].y] & START_SQUARE ) {
557 	    DeleteObject(hBrushLiving);
558 	    DeleteObject(hBrushDead);
559 	    ReleaseDC(hWnd, hDC);
560           ret = 1;
561       } else {
562         ret = 0;
563       }
564     } else {
565       action_done = 0;
566     }
567   } while (! action_done);
568 
569   return ret;
570 }
571 
572 
573 static void
enter_square(int n,HDC hDC,HBRUSH hBrush)574 enter_square(int n, HDC hDC, HBRUSH hBrush)  /* move into a neighboring square */
575 {
576   draw_solid_square( (int)path[n].x, (int)path[n].y,
577 		    (int)path[n].dir, hDC, hBrush);
578 
579   path[n+1].dir = -1;
580   switch (path[n].dir) {
581   case 0: path[n+1].x = path[n].x;
582     path[n+1].y = path[n].y - 1;
583     break;
584   case 1: path[n+1].x = path[n].x + 1;
585     path[n+1].y = path[n].y;
586     break;
587   case 2: path[n+1].x = path[n].x;
588     path[n+1].y = path[n].y + 1;
589     break;
590   case 3: path[n+1].x = path[n].x - 1;
591     path[n+1].y = path[n].y;
592     break;
593   }
594 }
595 
596 static void
start_timer(HWND hWnd,int iTimeout)597 start_timer(HWND hWnd, int iTimeout)
598 {
599 	waiting = TRUE;
600 	SetTimer(hWnd, 1, iTimeout, NULL);
601 }
602 
603 /****************************************************************************
604 
605 	FUNCTION: WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
606 
607 	PURPOSE: calls initialization function, processes message loop
608 
609 	COMMENTS:
610 
611 		Windows recognizes this function by name as the initial entry point
612 		for the program.  This function calls the application initialization
613 		routine, if no other instance of the program is running, and always
614 		calls the instance initialization routine.  It then executes a message
615 		retrieval and dispatch loop that is the top-level control structure
616 		for the remainder of execution.  The loop is terminated when a WM_QUIT
617 		message is received, at which time this function exits the application
618 		instance by returning the value passed by PostQuitMessage().
619 
620 		If this function must abort before entering the message loop, it
621 		returns the conventional value NULL.
622 
623 ****************************************************************************/
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)624 int APIENTRY WinMain(
625 	HINSTANCE hInstance,
626     HINSTANCE hPrevInstance,
627 	LPSTR lpCmdLine,
628 	int nCmdShow)
629 {
630 	MSG msg;
631 	HDC hDC;
632 
633 	if (!hPrevInstance) {       	/* Other instances of app running? */
634 			if (!InitApplication(hInstance)) { /* Initialize shared things */
635 			return (FALSE);     	/* Exits if unable to initialize */
636 		}
637 	}
638 
639 	/* Perform initializations that apply to a specific instance */
640 
641 	if (!InitInstance(hInstance, nCmdShow)) {
642 		return (FALSE);
643 	}
644 
645 	waiting = FALSE;
646 	state = 1;
647 
648 	/* Acquire and dispatch messages until a WM_QUIT message is received. */
649 
650 	while (0 != state) {
651 		if (waiting) {
652 			(void) WaitMessage();
653 		}
654 		while (0 != state && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
655 			if (WM_QUIT == msg.message) {
656 				state = 0;
657 			} else {
658 				DispatchMessage(&msg); /* Dispatches message to window */
659 			}
660 		}
661     		switch (state) {
662     		case 1:
663       			initialize_maze();
664 			state = 2;
665       			break;
666 	    	case 2:
667 			hDC = GetDC(hWnd);
668 			SendMessage(hWnd, WM_ERASEBKGND, (WPARAM) hDC, (LPARAM) 0);
669 			draw_maze_border(hWnd, hDC);
670 			ReleaseDC(hWnd, hDC);
671 			state = 3;
672       			break;
673 	    	case 3:
674 			create_maze();
675 			state = 4;
676 			break;
677 	    	case 4:
678 			start_timer(hWnd, pre_solve_delay);
679 			state = 5;
680 			break;
681 		case 5:
682 			if (! waiting) {
683 				state = 6;
684 			}
685 			break;
686     		case 6:
687 			begin_solve_maze();
688 			if (0 != solve_delay) {
689 				start_timer(hWnd, solve_delay);
690 				state = 7;
691 			} else {
692 				state = 8;
693 			}
694 			break;
695 		case 7:
696 			if (! waiting) {
697 				state = 8;
698 			}
699 			break;
700 		case 8:
701 			if (! solve_maze()) {
702 				if (0 != solve_delay) {
703 					start_timer(hWnd, solve_delay);
704 					state = 7;
705 				}
706 			} else {
707 				state = 9;
708 			}
709 			break;
710 		case 9:
711 			start_timer(hWnd, post_solve_delay);
712 			state = 10;
713 			break;
714 		case 10:
715 			if (! waiting) {
716 				state = 11;
717 			}
718 			break;
719 		case 11:
720 			state = 1;
721 			break;
722 		}
723 	}
724 
725 	return (msg.wParam); /* Returns the value from PostQuitMessage */
726 }
727 
728 
729 /****************************************************************************
730 
731 	FUNCTION: InitApplication(HINSTANCE)
732 
733 	PURPOSE: Initializes window data and registers window class
734 
735 	COMMENTS:
736 
737 		This function is called at initialization time only if no other
738 		instances of the application are running.  This function performs
739 		initialization tasks that can be done once for any number of running
740 		instances.
741 
742 		In this case, we initialize a window class by filling out a data
743 		structure of type WNDCLASS and calling the Windows RegisterClass()
744 		function.  Since all instances of this application use the same window
745 		class, we only need to do this when the first instance is initialized.
746 
747 
748 ****************************************************************************/
749 
InitApplication(HINSTANCE hInstance)750 static BOOL InitApplication(HINSTANCE hInstance)
751 {
752 	WNDCLASS  wc;
753 
754 	// Fill in window class structure with parameters that describe the
755 	// main window.
756 
757 	wc.style         = CS_HREDRAW | CS_VREDRAW;// Class style(s).
758 	wc.lpfnWndProc   = (WNDPROC)WndProc;       // Window Procedure
759 	wc.cbClsExtra    = 0;                      // No per-class extra data.
760 	wc.cbWndExtra    = 0;                      // No per-window extra data.
761 	wc.hInstance     = hInstance;              // Owner of this class
762 	wc.hIcon         = LoadIcon (hInstance, szAppName); // Icon name from .RC
763 	wc.hCursor       = LoadCursor(NULL, (LPCTSTR) IDC_ARROW);// Cursor
764 	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);// Default color
765 	wc.lpszMenuName  = NULL;                    // No menu
766 	wc.lpszClassName = szAppName;              // Name to register as
767 
768 	// Register the window class and return success/failure code.
769 	return (RegisterClass(&wc));
770 }
771 
772 
773 /****************************************************************************
774 
775 	FUNCTION:  InitInstance(HINSTANCE, int)
776 
777 	PURPOSE:  Saves instance handle and creates main window
778 
779 	COMMENTS:
780 
781 		This function is called at initialization time for every instance of
782 		this application.  This function performs initialization tasks that
783 		cannot be shared by multiple instances.
784 
785 		In this case, we save the instance handle in a static variable and
786 		create and display the main program window.
787 
788 ****************************************************************************/
789 
InitInstance(HINSTANCE hInstance,int nCmdShow)790 static BOOL InitInstance(
791 	HINSTANCE          hInstance,
792 	int             nCmdShow)
793 {
794 	/* Save the instance handle in static variable, which will be used in
795 	   many subsequence calls from this application to Windows. */
796 
797 	hInst = hInstance; /* Store instance handle in our global variable */
798 
799 	/* Create a main window for this application instance. */
800 
801 	hWnd = CreateWindow(
802 		szAppName,	     	/* See RegisterClass() call. */
803 		szTitle,	     	/* Text for window title bar. */
804 		WS_OVERLAPPEDWINDOW,/* Window style. */
805 		0, 0, CW_USEDEFAULT, CW_USEDEFAULT, /* Use default positioning */
806 		NULL,		     	/* Overlapped windows have no parent. */
807 		NULL,		     	/* Use the window class menu. */
808 		hInstance,	     	/* This instance owns this window. */
809 		NULL		     	/* We don't use any data in our WM_CREATE */
810 	);
811 
812 	// If window could not be created, return "failure"
813 	if (!hWnd) {
814 		return (FALSE);
815 	}
816 
817 	// Make the window visible; update its client area; and return "success"
818 	ShowWindow(hWnd, nCmdShow); // Show the window
819 	UpdateWindow(hWnd);         // Sends WM_PAINT message
820 
821 	return (TRUE);              // We succeeded...
822 
823 }
824 
825 static BOOL
OnCreate(HWND hWnd,LPCREATESTRUCT lpCreateStruct)826 OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
827 {
828 	RECT rc;
829 	int size;
830 
831 	srand((unsigned) time(NULL));
832 
833 	size = GetPrivateProfileIntA("maze", "gridsize", 10, "maze.ini");
834 	pre_solve_delay = GetPrivateProfileIntA("maze", "predelay", 5000, "maze.ini");
835 	post_solve_delay = GetPrivateProfileIntA("maze", "postdelay", 5000, "maze.ini");
836 	solve_delay = GetPrivateProfileIntA("maze", "solvedelay", 1, "maze.ini");
837 
838   	if (size < 2) {
839   		size = 7 + (rand() % 30);
840 	}
841   	grid_width = grid_height = size;
842     bw = (size > 6 ? 3 : (size-1)/2);
843 
844 	GetClientRect(hWnd, &rc);
845 	set_maze_sizes(rc.right - rc.left, rc.bottom - rc.top);
846 
847 	return TRUE;
848 }
849 
OnTimer(HWND hwnd,UINT id)850 void OnTimer(HWND hwnd, UINT id)
851 {
852 	waiting = FALSE;
853 }
854 
855 /****************************************************************************
856 
857 	FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
858 
859 	PURPOSE:  Processes messages
860 
861 	MESSAGES:
862 
863 	WM_DESTROY    - destroy window
864 
865 	COMMENTS:
866 
867 ****************************************************************************/
868 
WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)869 LRESULT CALLBACK WndProc(
870 		HWND hWnd,         // window handle
871 		UINT message,      // type of message
872 		WPARAM wParam,     // additional information
873 		LPARAM lParam)     // additional information
874 {
875 	PAINTSTRUCT ps;
876 
877 	switch (message) {
878 		case WM_CREATE:
879 			OnCreate(hWnd, (LPCREATESTRUCT) lParam);
880 			break;
881 		case WM_PAINT:
882 			BeginPaint(hWnd, &ps);
883 			state = 1;
884 			EndPaint(hWnd, &ps);
885 		case WM_TIMER:
886 			OnTimer(hWnd, wParam);
887 			break;
888 		case WM_DESTROY:  // message: window being destroyed
889 			PostQuitMessage(0);
890 			break;
891 
892 		default:          // Passes it on if unproccessed
893 			return (DefWindowProc(hWnd, message, wParam, lParam));
894 	}
895 	return (0);
896 }
897