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 <windows.h>       /* required for all Windows applications */
53 #include <scrnsave.h>
54 #include <tchar.h>
55 #include <stdlib.h>
56 #include <commctrl.h>
57 #include <string.h>
58 #include <time.h>
59 #include "resource.h"
60 
61 #define APPNAME _T("Maze")
62 
63 LRESULT CALLBACK ScreenSaverProc(HWND hWnd, UINT message, WPARAM uParam, LPARAM lParam);
64 static int choose_door();
65 static long backup();
66 static void draw_wall();
67 static void draw_solid_square(int, int, int, HDC, HBRUSH);
68 static void enter_square(int, HDC, HBRUSH);
69 
70 extern HINSTANCE hMainInstance; /* current instance */
71 HBRUSH hBrushDead;
72 HBRUSH hBrushLiving;
73 HPEN   hPenWall;
74 HDC    hDC;
75 
76 static int solve_delay, pre_solve_delay, post_solve_delay, size;
77 
78 #define MAX_MAZE_SIZE_X    ((unsigned long) 1000) // Dynamic detection?
79 #define MAX_MAZE_SIZE_Y    ((unsigned long) 1000) // Dynamic detection?
80 
81 #define MOVE_LIST_SIZE  (MAX_MAZE_SIZE_X * MAX_MAZE_SIZE_Y)
82 
83 #define WALL_TOP    0x8000
84 #define WALL_RIGHT    0x4000
85 #define WALL_BOTTOM    0x2000
86 #define WALL_LEFT    0x1000
87 
88 #define DOOR_IN_TOP    0x800
89 #define DOOR_IN_RIGHT    0x400
90 #define DOOR_IN_BOTTOM    0x200
91 #define DOOR_IN_LEFT    0x100
92 #define DOOR_IN_ANY    0xF00
93 
94 #define DOOR_OUT_TOP    0x80
95 #define DOOR_OUT_RIGHT    0x40
96 #define DOOR_OUT_BOTTOM    0x20
97 #define DOOR_OUT_LEFT    0x10
98 
99 #define START_SQUARE    0x2
100 #define END_SQUARE    0x1
101 
102 #define    border_x        (0)
103 #define    border_y        (0)
104 
105 #define    get_random(x)    (rand() % (x))
106 
107 static unsigned short maze[MAX_MAZE_SIZE_X][MAX_MAZE_SIZE_Y];
108 
109 static struct {
110     unsigned int x;
111     unsigned int y;
112     unsigned int dir;
113 } move_list[MOVE_LIST_SIZE], save_path[MOVE_LIST_SIZE], path[MOVE_LIST_SIZE];
114 
115 static int maze_size_x, maze_size_y;
116 static long sqnum, path_length;
117 static int cur_sq_x, cur_sq_y;
118 static int start_x, start_y, start_dir, end_x, end_y, end_dir;
119 static int grid_width, grid_height;
120 static int bw;
121 static int state = 1, pathi = 0;
122 static LPCWSTR registryPath = _T("Software\\Microsoft\\ScreenSavers\\mazescr");
123 
SetDefaults()124 static void SetDefaults()
125 {
126     size = 10;
127     pre_solve_delay = 5000;
128     post_solve_delay = 5000;
129     solve_delay = 1;
130 }
131 
ReadRegistry()132 static void ReadRegistry()
133 {
134     LONG result;
135     HKEY skey;
136     DWORD valuetype, valuesize, val_size, val_presd, val_postsd, val_sd;
137 
138     SetDefaults();
139 
140     result = RegOpenKeyEx(HKEY_CURRENT_USER, registryPath, 0, KEY_READ, &skey);
141     if(result != ERROR_SUCCESS)
142         return;
143 
144     valuesize = sizeof(DWORD);
145 
146     result = RegQueryValueEx(skey, _T("size"), NULL, &valuetype, (LPBYTE)&val_size, &valuesize);
147     if(result == ERROR_SUCCESS)
148         size = val_size;
149     result = RegQueryValueEx(skey, _T("pre_solve_delay"), NULL, &valuetype, (LPBYTE)&val_presd, &valuesize);
150     if(result == ERROR_SUCCESS)
151         pre_solve_delay = val_presd;
152     result = RegQueryValueEx(skey, _T("post_solve_delay"), NULL, &valuetype, (LPBYTE)&val_postsd, &valuesize);
153     if(result == ERROR_SUCCESS)
154         post_solve_delay = val_postsd;
155     result = RegQueryValueEx(skey, _T("solve_delay"), NULL, &valuetype, (LPBYTE)&val_sd, &valuesize);
156     if(result == ERROR_SUCCESS)
157         solve_delay = val_sd;
158 
159     RegCloseKey(skey);
160 }
161 
WriteRegistry()162 static void WriteRegistry()
163 {
164     LONG result;
165     HKEY skey;
166     DWORD disp;
167 
168     result = RegCreateKeyEx(HKEY_CURRENT_USER, registryPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &skey, &disp);
169     if(result != ERROR_SUCCESS)
170         return;
171 
172     RegSetValueEx(skey, _T("size"), 0, REG_DWORD, (LPBYTE)&size, sizeof(size));
173     RegSetValueEx(skey, _T("pre_solve_delay"), 0, REG_DWORD, (LPBYTE)&pre_solve_delay, sizeof(pre_solve_delay));
174     RegSetValueEx(skey, _T("post_solve_delay"), 0, REG_DWORD, (LPBYTE)&post_solve_delay, sizeof(post_solve_delay));
175     RegSetValueEx(skey, _T("solve_delay"), 0, REG_DWORD, (LPBYTE)&solve_delay, sizeof(solve_delay));
176 
177     RegCloseKey(skey);
178 }
179 
set_maze_sizes(width,height)180 static void set_maze_sizes(width, height)
181 int width, height;
182 {
183     maze_size_x = (width -1)/ grid_width;
184     maze_size_y = (height-1) / grid_height;
185     if (maze_size_x > MAX_MAZE_SIZE_X)
186         maze_size_x = MAX_MAZE_SIZE_X;
187     if (maze_size_y > MAX_MAZE_SIZE_Y)
188         maze_size_y = MAX_MAZE_SIZE_Y;
189 }
190 
initialize_maze()191 static void initialize_maze()         /* draw the surrounding wall and start/end squares */
192 {
193     register int i, j, wall;
194 
195     /* initialize all squares */
196     for (i = 0; i < maze_size_x; i++) {
197         for (j = 0; j < maze_size_y; j++) {
198             maze[i][j] = 0;
199         }
200     }
201 
202     /* top wall */
203     for (i = 0; i < maze_size_x; i++) {
204         maze[i][0] |= WALL_TOP;
205     }
206 
207     /* right wall */
208     for (j = 0; j < maze_size_y; j++) {
209         maze[maze_size_x - 1][j] |= WALL_RIGHT;
210     }
211 
212     /* bottom wall */
213     for (i = 0; i < maze_size_x; i++) {
214         maze[i][maze_size_y - 1] |= WALL_BOTTOM;
215     }
216 
217     /* left wall */
218     for (j = 0; j < maze_size_y; j++) {
219         maze[0][j] |= WALL_LEFT;
220     }
221 
222     /* set start square */
223     wall = get_random(4);
224     switch (wall) {
225     case 0:
226         i = get_random(maze_size_x);
227         j = 0;
228         break;
229     case 1:
230         i = maze_size_x - 1;
231         j = get_random(maze_size_y);
232         break;
233     case 2:
234         i = get_random(maze_size_x);
235         j = maze_size_y - 1;
236         break;
237     case 3:
238         i = 0;
239         j = get_random(maze_size_y);
240         break;
241     }
242     maze[i][j] |= START_SQUARE;
243     maze[i][j] |= (DOOR_IN_TOP >> wall);
244     maze[i][j] &= ~(WALL_TOP >> wall);
245     cur_sq_x = i;
246     cur_sq_y = j;
247     start_x = i;
248     start_y = j;
249     start_dir = wall;
250     sqnum = 0;
251 
252     /* set end square */
253     wall = (wall + 2) % 4;
254     switch (wall) {
255     case 0:
256         i = get_random(maze_size_x);
257         j = 0;
258         break;
259     case 1:
260         i = maze_size_x - 1;
261         j = get_random(maze_size_y);
262         break;
263     case 2:
264         i = get_random(maze_size_x);
265         j = maze_size_y - 1;
266         break;
267     case 3:
268         i = 0;
269         j = get_random(maze_size_y);
270         break;
271     }
272     maze[i][j] |= END_SQUARE;
273     maze[i][j] |= (DOOR_OUT_TOP >> wall);
274     maze[i][j] &= ~(WALL_TOP >> wall);
275     end_x = i;
276     end_y = j;
277     end_dir = wall;
278 }
279 
create_maze(HWND hWnd)280 static void create_maze(HWND hWnd)             /* create a maze layout given the initialized maze */
281 {
282     register int i, newdoor = 0;
283 
284     do {
285         move_list[sqnum].x = cur_sq_x;
286         move_list[sqnum].y = cur_sq_y;
287         move_list[sqnum].dir = newdoor;
288         while ((newdoor = choose_door(hDC)) == -1) { /* pick a door */
289             if (backup() == -1) { /* no more doors ... backup */
290                 return; /* done ... return */
291             }
292         }
293 
294         /* mark the out door */
295         maze[cur_sq_x][cur_sq_y] |= (DOOR_OUT_TOP >> newdoor);
296 
297         switch (newdoor) {
298         case 0: cur_sq_y--;
299             break;
300         case 1: cur_sq_x++;
301             break;
302         case 2: cur_sq_y++;
303             break;
304         case 3: cur_sq_x--;
305             break;
306         }
307         sqnum++;
308 
309         /* mark the in door */
310         maze[cur_sq_x][cur_sq_y] |= (DOOR_IN_TOP >> ((newdoor + 2) % 4));
311 
312         /* if end square set path length and save path */
313         if (maze[cur_sq_x][cur_sq_y] & END_SQUARE) {
314             path_length = sqnum;
315             for (i = 0; i < path_length; i++) {
316                 save_path[i].x = move_list[i].x;
317                 save_path[i].y = move_list[i].y;
318                 save_path[i].dir = move_list[i].dir;
319             }
320         }
321     } while (1);
322 }
323 
choose_door(HDC hDC)324 static int choose_door(HDC hDC)                                    /* pick a new path */
325 {
326     int candidates[3];
327     register int num_candidates;
328 
329     num_candidates = 0;
330 
331     /* top wall */
332     if (maze[cur_sq_x][cur_sq_y] & DOOR_IN_TOP)
333         goto rightwall;
334     if (maze[cur_sq_x][cur_sq_y] & DOOR_OUT_TOP)
335         goto rightwall;
336     if (maze[cur_sq_x][cur_sq_y] & WALL_TOP)
337         goto rightwall;
338     if (maze[cur_sq_x][cur_sq_y - 1] & DOOR_IN_ANY) {
339         maze[cur_sq_x][cur_sq_y] |= WALL_TOP;
340         maze[cur_sq_x][cur_sq_y - 1] |= WALL_BOTTOM;
341         draw_wall(cur_sq_x, cur_sq_y, 0, hDC);
342         goto rightwall;
343     }
344     candidates[num_candidates++] = 0;
345 
346 rightwall:
347     /* right wall */
348     if (maze[cur_sq_x][cur_sq_y] & DOOR_IN_RIGHT)
349         goto bottomwall;
350     if (maze[cur_sq_x][cur_sq_y] & DOOR_OUT_RIGHT)
351         goto bottomwall;
352     if (maze[cur_sq_x][cur_sq_y] & WALL_RIGHT)
353         goto bottomwall;
354     if (maze[cur_sq_x + 1][cur_sq_y] & DOOR_IN_ANY) {
355         maze[cur_sq_x][cur_sq_y] |= WALL_RIGHT;
356         maze[cur_sq_x + 1][cur_sq_y] |= WALL_LEFT;
357         draw_wall(cur_sq_x, cur_sq_y, 1, hDC);
358         goto bottomwall;
359     }
360     candidates[num_candidates++] = 1;
361 
362 bottomwall:
363     /* bottom wall */
364     if (maze[cur_sq_x][cur_sq_y] & DOOR_IN_BOTTOM)
365         goto leftwall;
366     if (maze[cur_sq_x][cur_sq_y] & DOOR_OUT_BOTTOM)
367         goto leftwall;
368     if (maze[cur_sq_x][cur_sq_y] & WALL_BOTTOM)
369         goto leftwall;
370     if (maze[cur_sq_x][cur_sq_y + 1] & DOOR_IN_ANY) {
371         maze[cur_sq_x][cur_sq_y] |= WALL_BOTTOM;
372         maze[cur_sq_x][cur_sq_y + 1] |= WALL_TOP;
373         draw_wall(cur_sq_x, cur_sq_y, 2, hDC);
374         goto leftwall;
375     }
376     candidates[num_candidates++] = 2;
377 
378 leftwall:
379     /* left wall */
380     if (maze[cur_sq_x][cur_sq_y] & DOOR_IN_LEFT)
381         goto donewall;
382     if (maze[cur_sq_x][cur_sq_y] & DOOR_OUT_LEFT)
383         goto donewall;
384     if (maze[cur_sq_x][cur_sq_y] & WALL_LEFT)
385         goto donewall;
386     if (maze[cur_sq_x - 1][cur_sq_y] & DOOR_IN_ANY) {
387         maze[cur_sq_x][cur_sq_y] |= WALL_LEFT;
388         maze[cur_sq_x - 1][cur_sq_y] |= WALL_RIGHT;
389         draw_wall(cur_sq_x, cur_sq_y, 3, hDC);
390         goto donewall;
391     }
392     candidates[num_candidates++] = 3;
393 
394 donewall:
395     if (num_candidates == 0)
396         return -1;
397     if (num_candidates == 1)
398         return candidates[0];
399     return candidates[get_random(num_candidates)];
400 
401 }
402 
backup()403 static long backup()                                                  /* back up a move */
404 {
405     sqnum--;
406     if (0 <= sqnum) {
407         cur_sq_x = move_list[sqnum].x;
408         cur_sq_y = move_list[sqnum].y;
409     }
410     return sqnum;
411 }
412 
draw_solid_square(i,j,dir,hDC,hBrush)413 static void draw_solid_square(i, j, dir, hDC, hBrush)          /* draw a solid square in a square */
414 register int i, j, dir;
415 HDC hDC;
416 HBRUSH hBrush;
417 {
418     RECT rc;
419 
420     switch (dir) {
421     case 0:
422         rc.left = border_x + bw + grid_width * i;
423         rc.right = rc.left + grid_width - (bw + bw);
424         rc.top = border_y - bw + grid_height * j;
425         rc.bottom = rc.top + grid_height;
426         break;
427     case 1:
428         rc.left = border_x + bw + grid_width * i;
429         rc.right = rc.left + grid_width;
430         rc.top = border_y + bw + grid_height * j;
431         rc.bottom = rc.top + grid_height - (bw + bw);
432         break;
433     case 2:
434         rc.left = border_x + bw + grid_width * i;
435         rc.right = rc.left + grid_width - (bw + bw);
436         rc.top = border_y + bw + grid_height * j;
437         rc.bottom = rc.top + grid_height;
438         break;
439     case 3:
440         rc.left = border_x - bw + grid_width * i;
441         rc.right = rc.left + grid_width;
442         rc.top = border_y + bw + grid_height * j;
443         rc.bottom = rc.top + grid_height - (bw + bw);
444         break;
445     }
446     (void) FillRect(hDC, &rc, hBrush);
447 }
448 
draw_maze_border(HWND hWnd)449 static void draw_maze_border(HWND hWnd)    /* draw the maze outline */
450 {
451     register int i, j;
452     HBRUSH hBrush;
453 
454     SelectObject(hDC, hPenWall);
455 
456     for (i = 0; i < maze_size_x; i++) {
457         if (maze[i][0] & WALL_TOP) {
458             MoveToEx(hDC, border_x + grid_width * i, border_y, NULL);
459             (void) LineTo(hDC, border_x + grid_width * (i + 1) - 1, border_y);
460         }
461         if ((maze[i][maze_size_y - 1] & WALL_BOTTOM)) {
462             MoveToEx(hDC, border_x + grid_width * i, border_y + grid_height * (maze_size_y) -1, NULL);
463             (void) LineTo(hDC, border_x + grid_width * (i + 1) - 1, border_y + grid_height * (maze_size_y) -1);
464         }
465     }
466     for (j = 0; j < maze_size_y; j++) {
467         if (maze[maze_size_x - 1][j] & WALL_RIGHT) {
468             MoveToEx(hDC, border_x + grid_width * maze_size_x - 1, border_y + grid_height * j, NULL);
469             (void) LineTo(hDC, border_x + grid_width * maze_size_x - 1, border_y + grid_height * (j + 1) - 1);
470         }
471         if (maze[0][j] & WALL_LEFT) {
472             MoveToEx(hDC, border_x, border_y + grid_height * j, NULL);
473             (void) LineTo(hDC, border_x, border_y + grid_height * (j + 1) - 1);
474         }
475     }
476 
477     hBrush = GetStockObject(WHITE_BRUSH);
478     draw_solid_square(start_x, start_y, start_dir, hDC, hBrush);
479     draw_solid_square(end_x, end_y, end_dir, hDC, hBrush);
480 }
481 
draw_wall(i,j,dir,hDC)482 static void draw_wall(i, j, dir, hDC)                                   /* draw a single wall */
483 register int i, j, dir;
484 HDC hDC;
485 {
486     SelectObject(hDC, hPenWall);
487 
488     switch (dir) {
489     case 0:
490         MoveToEx(hDC, border_x + grid_width * i, border_y + grid_height * j, NULL);
491         (void) LineTo(hDC, border_x + grid_width * (i + 1), border_y + grid_height * j);
492         break;
493     case 1:
494         MoveToEx(hDC, border_x + grid_width * (i + 1), border_y + grid_height * j, NULL);
495         (void) LineTo(hDC, border_x + grid_width * (i + 1), border_y + grid_height * (j + 1));
496         break;
497     case 2:
498         MoveToEx(hDC, border_x + grid_width * i, border_y + grid_height * (j + 1), NULL);
499         (void) LineTo(hDC, border_x + grid_width * (i + 1), border_y + grid_height * (j + 1));
500         break;
501     case 3:
502         MoveToEx(hDC, border_x + grid_width * i, border_y + grid_height * j, NULL);
503         (void) LineTo(hDC, border_x + grid_width * i, border_y + grid_height * (j + 1));
504         break;
505     }
506 }
507 
begin_solve_maze(HWND hWnd)508 static void begin_solve_maze(HWND hWnd)                             /* solve it with graphical feedback */
509 {
510     /* plug up the surrounding wall */
511     maze[start_x][start_y] |= (WALL_TOP >> start_dir);
512     maze[end_x][end_y] |= (WALL_TOP >> end_dir);
513 
514     /* initialize search path */
515     pathi = 0;
516     path[pathi].x = end_x;
517     path[pathi].y = end_y;
518     path[pathi].dir = -1;
519 }
520 
solve_maze(HWND hWnd)521 static int solve_maze(HWND hWnd)                             /* solve it with graphical feedback */
522 {
523     int ret;
524     int action_done;
525 
526     do {
527         action_done = 1;
528         if (++path[pathi].dir >= 4) {
529             pathi--;
530             draw_solid_square((int) (path[pathi].x), (int) (path[pathi].y), (int) (path[pathi].dir), hDC, hBrushDead);
531             ret = 0;
532         }
533         else if (!(maze[path[pathi].x][path[pathi].y] & (WALL_TOP >> path[pathi].dir)) &&
534             ((pathi == 0) || ((path[pathi].dir != (int) (path[pathi - 1].dir + 2) % 4)))) {
535             enter_square(pathi, hDC, hBrushLiving);
536             pathi++;
537             if (maze[path[pathi].x][path[pathi].y] & START_SQUARE) {
538 
539                 ret = 1;
540             }
541             else {
542                 ret = 0;
543             }
544         }
545         else {
546             action_done = 0;
547         }
548     } while (!action_done);
549     return ret;
550 }
551 
enter_square(int n,HDC hDC,HBRUSH hBrush)552 static void enter_square(int n, HDC hDC, HBRUSH hBrush)  /* move into a neighboring square */
553 {
554     draw_solid_square((int) path[n].x, (int) path[n].y, (int) path[n].dir, hDC, hBrush);
555 
556     path[n + 1].dir = -1;
557     switch (path[n].dir) {
558     case 0: path[n + 1].x = path[n].x;
559         path[n + 1].y = path[n].y - 1;
560         break;
561     case 1: path[n + 1].x = path[n].x + 1;
562         path[n + 1].y = path[n].y;
563         break;
564     case 2: path[n + 1].x = path[n].x;
565         path[n + 1].y = path[n].y + 1;
566         break;
567     case 3: path[n + 1].x = path[n].x - 1;
568         path[n + 1].y = path[n].y;
569         break;
570     }
571 }
572 
start_timer(HWND hWnd,int iTimeout)573 static void start_timer(HWND hWnd, int iTimeout)
574 {
575     SetTimer(hWnd, 1, iTimeout, NULL);
576 }
577 
OnCreate(HWND hWnd,LPCREATESTRUCT lpCreateStruct)578 static BOOL OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
579 {
580     srand((unsigned) time(NULL));
581 
582     ReadRegistry();
583 
584     if (size < 2) {
585         size = 7 + (rand() % 30);
586     }
587     grid_width = grid_height = size;
588     bw = (size > 6 ? 3 : (size - 1) / 2);
589 
590 #if 0
591     /* FIXME Pattern brushes not yet implemented in ReactOS */
592     {
593         static long grayPattern [] = {
594             0x55555555,
595             0xaaaaaaaa,
596             0x55555555,
597             0xaaaaaaaa,
598             0x55555555,
599             0xaaaaaaaa,
600             0x55555555,
601             0xaaaaaaaa
602         };
603         static RGBQUAD argbq [] = {
604             { 0, 0, 255, 0 },
605             { 255, 255, 255, 0 }
606         };
607         BITMAPINFO *pbmi;
608 
609         pbmi = malloc(sizeof(BITMAPINFOHEADER) + sizeof(argbq) + sizeof(grayPattern));
610         pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
611         pbmi->bmiHeader.biWidth = 8;
612         pbmi->bmiHeader.biHeight = 8;
613         pbmi->bmiHeader.biPlanes = 1;
614         pbmi->bmiHeader.biBitCount = 1;
615         pbmi->bmiHeader.biCompression = BI_RGB;
616         (void) memcpy(pbmi->bmiColors, argbq, sizeof(argbq));
617         (void) memcpy(pbmi->bmiColors + 2, grayPattern, sizeof(grayPattern));
618         hBrushDead = CreateDIBPatternBrushPt(pbmi, DIB_RGB_COLORS);
619         //    hBrushDead = CreateHatchBrush(HS_DIAGCROSS, RGB(255, 0, 0));
620         free(pbmi);
621     }
622 #else
623     hBrushDead = CreateSolidBrush(RGB(255, 0, 0));
624 #endif
625     hBrushLiving = CreateSolidBrush(RGB(0, 255, 0));
626     hPenWall = CreatePen(PS_SOLID, 3, RGB(150, 150, 150));
627 
628     hDC = GetDC(hWnd);
629 
630     start_timer(hWnd, 1);
631 
632     return TRUE;
633 }
634 
AboutProc(HWND hWnd,UINT message,WPARAM wparam,LPARAM lparam)635 INT_PTR CALLBACK AboutProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
636 {
637     switch(message){
638     case WM_COMMAND:
639         switch(LOWORD(wparam)){
640         case IDOK:
641             EndDialog(hWnd, LOWORD(wparam));
642             return TRUE;
643         }
644     }
645     return FALSE;
646 }
647 
ReadSettings(HWND hWnd)648 static void ReadSettings(HWND hWnd)
649 {
650     size = SendDlgItemMessage(hWnd, IDC_SLIDER_SIZE, TBM_GETPOS, 0, 0);
651     SetDlgItemInt(hWnd, IDC_TEXT_SIZE, size, FALSE);
652 
653     pre_solve_delay = SendDlgItemMessage(hWnd, IDC_SLIDER_PRESD, TBM_GETPOS, 0, 0);
654     SetDlgItemInt(hWnd, IDC_TEXT_PRESD, pre_solve_delay, FALSE);
655 
656     post_solve_delay = SendDlgItemMessage(hWnd, IDC_SLIDER_POSTSD, TBM_GETPOS, 0, 0);
657     SetDlgItemInt(hWnd, IDC_TEXT_POSTSD, post_solve_delay, FALSE);
658 
659     solve_delay = SendDlgItemMessage(hWnd, IDC_SLIDER_SD, TBM_GETPOS, 0, 0);
660     SetDlgItemInt(hWnd, IDC_TEXT_SD, solve_delay, FALSE);
661 }
662 
ScreenSaverProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)663 LRESULT CALLBACK ScreenSaverProc(
664     HWND hWnd,         // window handle
665     UINT message,      // type of message
666     WPARAM wParam,     // additional information
667     LPARAM lParam)     // additional information
668 {
669     switch (message)
670     {
671     case WM_CREATE:
672         OnCreate(hWnd, (LPCREATESTRUCT) lParam);
673         break;
674     case WM_SIZE:
675         set_maze_sizes(LOWORD(lParam), HIWORD(lParam));
676         break;
677     case WM_TIMER:
678         switch (state)
679         {
680         case 2:
681             begin_solve_maze(hWnd);
682 
683             state = 3;
684 
685             start_timer(hWnd, solve_delay);
686             break;
687         case 3:
688             if (!solve_maze(hWnd))
689             {
690                 start_timer(hWnd, solve_delay);
691             }
692             else
693             {
694                 state = 1;
695                 start_timer(hWnd, post_solve_delay);
696             }
697             break;
698         default:
699             initialize_maze();
700 
701             SendMessage(hWnd, WM_ERASEBKGND, (WPARAM) hDC, (LPARAM) 0);
702             draw_maze_border(hWnd);
703 
704             create_maze(hWnd);
705 
706             state = 2;
707 
708             start_timer(hWnd, pre_solve_delay);
709             break;
710         }
711         break;
712     case WM_DESTROY:  // message: window being destroyed
713         DeleteObject(hBrushLiving);
714         DeleteObject(hBrushDead);
715         ReleaseDC(hWnd, hDC);
716         break;
717     default:          // Passes it on if unprocessed
718         return DefScreenSaverProc(hWnd, message, wParam, lParam);
719     }
720     return 0;
721 }
722 
ScreenSaverConfigureDialog(HWND hWnd,UINT message,WPARAM wparam,LPARAM lparam)723 BOOL WINAPI ScreenSaverConfigureDialog(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
724 {
725     switch (message)
726     {
727         case WM_INITDIALOG:
728             ReadRegistry();
729             //Set slider ranges
730             SendDlgItemMessage(hWnd, IDC_SLIDER_SIZE, TBM_SETRANGE, FALSE, MAKELPARAM(5, 64));
731             SendDlgItemMessage(hWnd, IDC_SLIDER_PRESD, TBM_SETRANGE, FALSE, MAKELPARAM(1, 10000));
732             SendDlgItemMessage(hWnd, IDC_SLIDER_POSTSD, TBM_SETRANGE, FALSE, MAKELPARAM(1, 10000));
733             SendDlgItemMessage(hWnd, IDC_SLIDER_SD, TBM_SETRANGE, FALSE, MAKELPARAM(1, 10000));
734             //Set current values to slider
735             SendDlgItemMessage(hWnd, IDC_SLIDER_SIZE, TBM_SETPOS, TRUE, size);
736             SendDlgItemMessage(hWnd, IDC_SLIDER_PRESD, TBM_SETPOS, TRUE, pre_solve_delay);
737             SendDlgItemMessage(hWnd, IDC_SLIDER_POSTSD, TBM_SETPOS, TRUE, post_solve_delay);
738             SendDlgItemMessage(hWnd, IDC_SLIDER_SD, TBM_SETPOS, TRUE, solve_delay);
739             //Set current values to texts
740             SetDlgItemInt(hWnd, IDC_TEXT_SIZE, size, FALSE);
741             SetDlgItemInt(hWnd, IDC_TEXT_PRESD, pre_solve_delay, FALSE);
742             SetDlgItemInt(hWnd, IDC_TEXT_POSTSD, post_solve_delay, FALSE);
743             SetDlgItemInt(hWnd, IDC_TEXT_SD, solve_delay, FALSE);
744             return TRUE;
745         case WM_COMMAND:
746             switch (LOWORD(wparam))
747             {
748                 case IDOK:
749                     WriteRegistry();
750                     EndDialog(hWnd, TRUE);
751                     return TRUE;
752                 case IDCANCEL:
753                     EndDialog(hWnd, TRUE);
754                     break;
755                 case IDABOUT:
756                     DialogBox(hMainInstance, MAKEINTRESOURCE(IDD_DLG_ABOUT), hWnd, AboutProc);
757                     break;
758             }
759         case WM_HSCROLL:
760             ReadSettings(hWnd);
761             return TRUE;
762     }
763     return FALSE;
764 }
765 
RegisterDialogClasses(HANDLE hmodule)766 BOOL WINAPI RegisterDialogClasses(HANDLE hmodule)
767 {
768     return TRUE;
769 }
770