[MAZE*]
[reactos.git] / rosapps / demos / maze / maze.c
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
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
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
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
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
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
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
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
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
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
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
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
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 ****************************************************************************/
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
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
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
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
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
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 }