~ubuntu-branches/ubuntu/saucy/ricochet/saucy-proposed

« back to all changes in this revision

Viewing changes to ricochet_0.1.orig/server-boards.5c

  • Committer: Package Import Robot
  • Author(s): Keith Packard
  • Date: 2012-06-11 13:37:57 UTC
  • Revision ID: package-import@ubuntu.com-20120611133757-zn0ukd22vz56ymto
Tags: 0.3
* Improve appearance of board
* Fix user list when removing/adding same user

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * $Id$
3
 
 *
4
 
 * Copyright © 2003 Keith Packard
5
 
 *
6
 
 * Permission to use, copy, modify, distribute, and sell this software and its
7
 
 * documentation for any purpose is hereby granted without fee, provided that
8
 
 * the above copyright notice appear in all copies and that both that
9
 
 * copyright notice and this permission notice appear in supporting
10
 
 * documentation, and that the name of Keith Packard not be used in
11
 
 * advertising or publicity pertaining to distribution of the software without
12
 
 * specific, written prior permission.  Keith Packard makes no
13
 
 * representations about the suitability of this software for any purpose.  It
14
 
 * is provided "as is" without express or implied warranty.
15
 
 *
16
 
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
 
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18
 
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19
 
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20
 
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21
 
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22
 
 * PERFORMANCE OF THIS SOFTWARE.
23
 
 */
24
 
 
25
 
autoload RR
26
 
autoload Server
27
 
autoload Shuffle
28
 
 
29
 
extend namespace Server {
30
 
    public namespace Boards {
31
 
        /*
32
 
         * Board layout; each section is named by the color of the triangle,
33
 
         * each section has two sides.  These are all layed out
34
 
         * in the "lower right" position with the center of the board at the
35
 
         * top left (0,0) coordinate.
36
 
         */
37
 
 
38
 
        TargetOrNone target (Shape s, Color c) {
39
 
            return (TargetOrNone.target) (Target) {
40
 
                color = c, shape = s, active = false
41
 
            };
42
 
        }
43
 
 
44
 
        RobotOrNone robot (Color c) {
45
 
            return (RobotOrNone.robot) (Robot) {
46
 
                color = c, active = false
47
 
            };
48
 
        }
49
 
        
50
 
        typedef enum { left, right, above, below } W;
51
 
 
52
 
        Walls walls (W w...) {
53
 
            Walls   
54
 
            walls = { 
55
 
                left = false, right = false, above = false, below = false
56
 
            };
57
 
            for (int i = 0; i < dim (w); i++)
58
 
                switch (w[i]) {
59
 
                case W.left: 
60
 
                    walls.left = true; break;
61
 
                case W.right: 
62
 
                    walls.right = true; break;
63
 
                case W.above: 
64
 
                    walls.above = true; break;
65
 
                case W.below: 
66
 
                    walls.below = true; break;
67
 
                }
68
 
            return 
69
 
            walls;
70
 
        }
71
 
 
72
 
        ObjectLoc[*]    red_tri1 = {
73
 
            { x = 0, y = 2, object = { robot = RobotOrNone.none,
74
 
                target = target (Shape.Square, Color.Yellow),
75
 
                walls = walls (W.right, W.below) }},
76
 
            { x = 1, y = 5, object = { robot = RobotOrNone.none,
77
 
                target = target (Shape.Circle, Color.Green),
78
 
                walls = walls (W.left, W.below) }},
79
 
            { x = 4, y = 7, object = { robot = RobotOrNone.none,
80
 
                target = TargetOrNone.none,
81
 
                walls = walls (W.left) }},
82
 
            { x = 5, y = 3, object = { robot = RobotOrNone.none,
83
 
                target = target (Shape.Octagon, Color.Blue),
84
 
                walls = walls (W.left, W.above) }},
85
 
            { x = 6, y = 6, object = { robot = RobotOrNone.none,
86
 
                target = target (Shape.Triangle, Color.Red),
87
 
                walls = walls (W.right, W.above) }},
88
 
            { x = 7, y = 2, object = { robot = RobotOrNone.none,
89
 
                target = TargetOrNone.none,
90
 
                walls = walls (W.above) }}
91
 
        };
92
 
        ObjectLoc[*]    red_tri2 = {
93
 
            { x = 0, y = 2, object = { robot = RobotOrNone.none, 
94
 
                target = target (Shape.Triangle, Color.Red), 
95
 
                walls = walls (W.above, W.right ) }},
96
 
            { x = 2, y = 5, object = { robot = RobotOrNone.none, 
97
 
                target = target (Shape.Octagon, Color.Blue), 
98
 
                walls = walls (W.above, W.left  ) }},
99
 
            { x = 4, y = 7, object = { robot = RobotOrNone.none, 
100
 
                target = TargetOrNone.none, 
101
 
                walls = walls (W.left  ) }},
102
 
            { x = 5, y = 2, object = { robot = RobotOrNone.none, 
103
 
                target = target (Shape.Circle, Color.Green), 
104
 
                walls = walls (W.left, W.below ) }},
105
 
            { x = 6, y = 0, object = { robot = RobotOrNone.none, 
106
 
                target = target (Shape.Square, Color.Yellow), 
107
 
                walls = walls (W.below, W.right ) }},
108
 
            { x = 7, y = 2, object = { robot = RobotOrNone.none, 
109
 
                target = TargetOrNone.none, 
110
 
                walls = walls (W.above ) }},
111
 
        };
112
 
 
113
 
        ObjectLoc[*]    yellow_tri1 = {
114
 
            { x = 0, y = 2, object = { robot = RobotOrNone.none, 
115
 
                target = target (Shape.Whirl, Color.Whirl), 
116
 
                walls = walls (W.left, W.above ) }},
117
 
            { x = 1, y = 6, object = { robot = RobotOrNone.none, 
118
 
                target = target (Shape.Circle, Color.Blue), 
119
 
                walls = walls (W.above, W.right ) }},
120
 
            { x = 2, y = 3, object = { robot = RobotOrNone.none, 
121
 
                target = target (Shape.Square, Color.Green), 
122
 
                walls = walls (W.below, W.right ) }},
123
 
            { x = 4, y = 7, object = { robot = RobotOrNone.none, 
124
 
                target = TargetOrNone.none, 
125
 
                walls = walls (W.left  ) }},
126
 
            { x = 5, y = 2, object = { robot = RobotOrNone.none, 
127
 
                target = target (Shape.Octagon, Color.Red), 
128
 
                walls = walls (W.left, W.above ) }},
129
 
            { x = 6, y = 4, object = { robot = RobotOrNone.none, 
130
 
                target = target (Shape.Triangle, Color.Yellow), 
131
 
                walls = walls (W.left, W.below ) }},
132
 
            { x = 7, y = 1, object = { robot = RobotOrNone.none, 
133
 
                target = TargetOrNone.none, 
134
 
                walls = walls (W.above ) }},
135
 
        };
136
 
 
137
 
        ObjectLoc[*]    yellow_tri2 = {
138
 
            { x = 1, y = 3, object = { robot = RobotOrNone.none, 
139
 
                target = target (Shape.Triangle, Color.Yellow), 
140
 
                walls = walls (W.below, W.right ) }},
141
 
            { x = 2, y = 1, object = { robot = RobotOrNone.none, 
142
 
                target = target (Shape.Circle, Color.Blue), 
143
 
                walls = walls (W.left, W.below ) }},
144
 
            { x = 3, y = 7, object = { robot = RobotOrNone.none, 
145
 
                target = TargetOrNone.none, 
146
 
                walls = walls (W.left  ) }},
147
 
            { x = 4, y = 0, object = { robot = RobotOrNone.none, 
148
 
                target = target (Shape.Whirl, Color.Whirl), 
149
 
                walls = walls (W.above, W.left  ) }},
150
 
            { x = 5, y = 6, object = { robot = RobotOrNone.none, 
151
 
                target = target (Shape.Octagon, Color.Red), 
152
 
                walls = walls (W.above, W.left  ) }},
153
 
            { x = 6, y = 4, object = { robot = RobotOrNone.none, 
154
 
                target = target (Shape.Square, Color.Green), 
155
 
                walls = walls (W.above, W.right ) }},
156
 
            { x = 7, y = 3, object = { robot = RobotOrNone.none, 
157
 
                target = TargetOrNone.none, 
158
 
                walls = walls (W.above ) }},
159
 
        };
160
 
 
161
 
        ObjectLoc[*]    green_tri1 = {
162
 
            { x = 1, y = 2, object = { robot = RobotOrNone.none, 
163
 
                target = target (Shape.Square, Color.Blue), 
164
 
                walls = walls (W.left, W.below ) }},
165
 
            { x = 1, y = 6, object = { robot = RobotOrNone.none, 
166
 
                target = target (Shape.Octagon, Color.Yellow), 
167
 
                walls = walls (W.above, W.left  ) }},
168
 
            { x = 3, y = 7, object = { robot = RobotOrNone.none, 
169
 
                target = TargetOrNone.none, 
170
 
                walls = walls (W.left  ) }},
171
 
            { x = 4, y = 1, object = { robot = RobotOrNone.none, 
172
 
                target = target (Shape.Circle, Color.Red), 
173
 
                walls = walls (W.above, W.right ) }},
174
 
            { x = 6, y = 5, object = { robot = RobotOrNone.none, 
175
 
                target = target (Shape.Triangle, Color.Green), 
176
 
                walls = walls (W.below, W.right ) }},
177
 
            { x = 7, y = 2, object = { robot = RobotOrNone.none, 
178
 
                target = TargetOrNone.none, 
179
 
                walls = walls (W.above ) }},
180
 
        };
181
 
 
182
 
        ObjectLoc[*]    green_tri2 = {
183
 
            { x = 1, y = 4, object = { robot = RobotOrNone.none, 
184
 
                target = target (Shape.Octagon, Color.Yellow), 
185
 
                walls = walls (W.left, W.above ) }},
186
 
            { x = 3, y = 6, object = { robot = RobotOrNone.none, 
187
 
                target = target (Shape.Circle, Color.Red), 
188
 
                walls = walls (W.below, W.right ) }},
189
 
            { x = 4, y = 1, object = { robot = RobotOrNone.none, 
190
 
                target = target (Shape.Square, Color.Blue), 
191
 
                walls = walls (W.above, W.right ) }},
192
 
            { x = 6, y = 5, object = { robot = RobotOrNone.none, 
193
 
                target = target (Shape.Triangle, Color.Green), 
194
 
                walls = walls (W.left, W.below ) }},
195
 
            { x = 6, y = 7, object = { robot = RobotOrNone.none, 
196
 
                target = TargetOrNone.none, 
197
 
                walls = walls (W.left  ) }},
198
 
            { x = 7, y = 2, object = { robot = RobotOrNone.none, 
199
 
                target = TargetOrNone.none, 
200
 
                walls = walls (W.above ) }},
201
 
        };
202
 
 
203
 
        ObjectLoc[*]    blue_tri1 = {
204
 
            { x = 1, y = 3, object = { robot = RobotOrNone.none, 
205
 
                target = target (Shape.Circle, Color.Yellow), 
206
 
                walls = walls (W.left, W.above ) }},
207
 
            { x = 2, y = 6, object = { robot = RobotOrNone.none, 
208
 
                target = target (Shape.Triangle, Color.Blue), 
209
 
                walls = walls (W.left, W.below ) }},
210
 
            { x = 4, y = 7, object = { robot = RobotOrNone.none, 
211
 
                target = TargetOrNone.none, 
212
 
                walls = walls (W.left  ) }},
213
 
            { x = 5, y = 1, object = { robot = RobotOrNone.none, 
214
 
                target = target (Shape.Octagon, Color.Green), 
215
 
                walls = walls (W.left, W.above ) }},
216
 
            { x = 6, y = 5, object = { robot = RobotOrNone.none, 
217
 
                target = target (Shape.Square, Color.Red), 
218
 
                walls = walls (W.above, W.right ) }},
219
 
            { x = 7, y = 4, object = { robot = RobotOrNone.none, 
220
 
                target = TargetOrNone.none, 
221
 
                walls = walls (W.above ) }},
222
 
        };
223
 
 
224
 
        ObjectLoc[*]    blue_tri2 = {
225
 
            { x = 1, y = 3, object = { robot = RobotOrNone.none, 
226
 
                target = target (Shape.Circle, Color.Yellow), 
227
 
                walls = walls (W.right, W.below ) }},
228
 
            { x = 2, y = 6, object = { robot = RobotOrNone.none, 
229
 
                target = target (Shape.Octagon, Color.Green), 
230
 
                walls = walls (W.above, W.left  ) }},
231
 
            { x = 4, y = 7, object = { robot = RobotOrNone.none, 
232
 
                target = TargetOrNone.none, 
233
 
                walls = walls (W.left  ) }},
234
 
            { x = 5, y = 1, object = { robot = RobotOrNone.none, 
235
 
                target = target (Shape.Triangle, Color.Blue), 
236
 
                walls = walls (W.left, W.below ) }},
237
 
            { x = 6, y = 5, object = { robot = RobotOrNone.none, 
238
 
                target = target (Shape.Square, Color.Red), 
239
 
                walls = walls (W.above, W.right ) }},
240
 
            { x = 7, y = 4, object = { robot = RobotOrNone.none, 
241
 
                target = TargetOrNone.none, 
242
 
                walls = walls (W.above ) }},
243
 
        };
244
 
 
245
 
        (&ObjectLoc[*])[4,2] Locations = {
246
 
            { &red_tri1, &red_tri2 },
247
 
            { &yellow_tri1, &yellow_tri2 },
248
 
            { &green_tri1, &green_tri2 },
249
 
            { &blue_tri1, &blue_tri2 },
250
 
        };
251
 
        /*
252
 
         * Rotate the one square 90 degrees counter clockwise,
253
 
         * all this really has to do is deal with the walls and
254
 
         * the position
255
 
         */
256
 
 
257
 
        ObjectLoc RotateLoc (ObjectLoc a, int rot)
258
 
        {
259
 
            while (rot-- > 0)
260
 
            {
261
 
                ObjectLoc   t;
262
 
 
263
 
                t.x = a.y;
264
 
                t.y = 7 - a.x;
265
 
                t.object.target = a.object.target;
266
 
                t.object.robot = a.object.robot;
267
 
                t.object.walls.below = a.object.walls.left;
268
 
                t.object.walls.above = a.object.walls.right;
269
 
                t.object.walls.left = a.object.walls.above;
270
 
                t.object.walls.right = a.object.walls.below;
271
 
                a = t;
272
 
            }
273
 
            return a;
274
 
        }
275
 
 
276
 
        typedef struct {
277
 
            int     rot, dx, dy;
278
 
        } Transform;
279
 
 
280
 
        ObjectLoc TransformLoc (ObjectLoc l, Transform t) {
281
 
            l = RotateLoc (l, t.rot);
282
 
            l.x += t.dx;
283
 
            l.y += t.dy;
284
 
            return l;
285
 
        }
286
 
        /*
287
 
         * Given the description of one square,
288
 
         * place it on the board.  Also, place the
289
 
         * "other" walls on adjacent squares as needed.
290
 
         * This duplicates all of the wall information,
291
 
         * but makes it easier to search for collisions
292
 
         */
293
 
        
294
 
        void
295
 
        PlaceObject (&Board         b,
296
 
                     ObjectLoc      l,
297
 
                     Transform      t)
298
 
        {
299
 
            l = TransformLoc (l, t);
300
 
            
301
 
            if (l.object.robot != RobotOrNone.none)
302
 
                b[l.x,l.y].robot = l.object.robot;
303
 
            if (l.object.target != TargetOrNone.none)
304
 
                b[l.x,l.y].target = l.object.target;
305
 
            
306
 
            if (l.object.walls.left) {
307
 
                b[l.x, l.y].walls.left = true;
308
 
                if (l.x > 0)
309
 
                    b[l.x-1, l.y].walls.right = true;
310
 
            }
311
 
            if (l.object.walls.right) {
312
 
                b[l.x, l.y].walls.right = true;
313
 
                if (l.x < Width - 1)
314
 
                    b[l.x+1, l.y].walls.left = true;
315
 
            }
316
 
            if (l.object.walls.above) {
317
 
                b[l.x, l.y].walls.above = true;
318
 
                if (l.y > 0)
319
 
                    b[l.x,  l.y - 1].walls.below = true;
320
 
            }
321
 
            if (l.object.walls.below) {
322
 
                b[l.x, l.y].walls.below = true;
323
 
                if (l.y < Height - 1)
324
 
                    b[l.x, l.y + 1].walls.above = true;
325
 
            }
326
 
        }
327
 
 
328
 
        void
329
 
        PlaceObjects (&Board        b,
330
 
                      &ObjectLoc[*] o,
331
 
                      Transform     t)
332
 
        {
333
 
            int         i;
334
 
 
335
 
            for (i = 0; i < dim(o); i++)
336
 
                PlaceObject (&b, o[i], t);
337
 
        }
338
 
 
339
 
        /*
340
 
         * Each quarter of the board is rotated and positioned
341
 
         * from the data structure above, here are the constants
342
 
         * used for that
343
 
         */
344
 
 
345
 
        Transform[4]  transforms = {
346
 
            { rot = 2, dx = 0, dy = 0 },
347
 
            { rot = 1, dx = 8, dy = 0 },
348
 
            { rot = 3, dx = 0, dy = 8 },
349
 
            { rot = 0, dx = 8, dy = 8 },
350
 
        };
351
 
 
352
 
        /*
353
 
         * Generate a random board and random robot locations
354
 
         */
355
 
 
356
 
        public Board
357
 
        random_board ()
358
 
        {
359
 
            Board   b;
360
 
            int     i, j;
361
 
 
362
 
            /* empty the board */
363
 
            for (j = 0; j < Height; j++)
364
 
                for (i = 0; i < Width; i++)
365
 
                    b[i, j] = (Object) { 
366
 
                        robot = RobotOrNone.none,
367
 
                        target = TargetOrNone.none,
368
 
                        walls = walls () };
369
 
            
370
 
            /*
371
 
             * Shuffle the board sections
372
 
             */
373
 
            int[4] board_order = { [i] = i };
374
 
            Shuffle::shuffle (&board_order);
375
 
            for (i = 0; i < 4; i++)
376
 
            {
377
 
 
378
 
                /* pick which side to use for this section */
379
 
                j = PRNG::randint (2);
380
 
                /* 
381
 
                 * Place all of the objects on this side on the board
382
 
                 */
383
 
                PlaceObjects (&b, Locations[board_order[i], j], transforms[i]);
384
 
                /*
385
 
                 * Add the center walls
386
 
                 */
387
 
                ObjectLoc   l = { 
388
 
                    x = 0, y = 0, object = {
389
 
                        target = TargetOrNone.none,
390
 
                        robot = RobotOrNone.none,
391
 
                        walls = walls (W.below, W.right) }};
392
 
                PlaceObject (&b, l, transforms[i]);
393
 
            }
394
 
 
395
 
            /*
396
 
             * Pick which quadrant each robot appears in
397
 
             */
398
 
            Object[4]  robot_order = {
399
 
                {   robot = robot (Color.Red), 
400
 
                    target = TargetOrNone.none, 
401
 
                    walls = walls ()
402
 
                },
403
 
                {   robot = robot (Color.Yellow), 
404
 
                    target = TargetOrNone.none, 
405
 
                    walls = walls ()
406
 
                },
407
 
                {   robot = robot (Color.Green), 
408
 
                    target = TargetOrNone.none, 
409
 
                    walls = walls ()
410
 
                },
411
 
                {   robot = robot (Color.Blue), 
412
 
                    target = TargetOrNone.none, 
413
 
                    walls = walls ()
414
 
                },
415
 
            };
416
 
            Shuffle::shuffle (&robot_order);
417
 
            for (i = 0; i < 4; i++)
418
 
            {
419
 
                ObjectLoc   l;
420
 
                int         loc;
421
 
 
422
 
                l.object = robot_order[i];
423
 
                /* avoid spot zero which is in the center */
424
 
                loc = PRNG::randint(63) + 1;
425
 
                l.x = loc % 8;
426
 
                l.y = loc // 8;
427
 
                PlaceObject (&b, l, transforms[i]);
428
 
            }
429
 
 
430
 
            /*
431
 
             * Now add walls all the way around the board
432
 
             */
433
 
            for (i = 0; i < Width; i++)
434
 
            {
435
 
                b[i, 0].walls.above = true;
436
 
                b[i, Height-1].walls.below = true;
437
 
                b[0, i].walls.left = true;
438
 
                b[Width-1, i].walls.right = true;
439
 
            }
440
 
            return b;
441
 
        }
442
 
 
443
 
        /*
444
 
         * Locate objects on the board, the predicate matching
445
 
         * function is used to test whether objects should be added
446
 
         * to the returned array
447
 
         */
448
 
        
449
 
        ObjectLoc[*] find (&Board b, bool (Object) match) {
450
 
            ObjectLoc[...]  ol = {};
451
 
            int             i = 0;
452
 
            for (int y = 0; y < Height; y++)
453
 
                for (int x = 0; x < Width; x++)
454
 
                    if (match (b[x,y]))
455
 
                        ol[i++] = (ObjectLoc) { x = x, y = y, object = b[x,y] };
456
 
            return ol;
457
 
        }
458
 
 
459
 
        public ObjectLoc[*] find_robots (&Board b, Color color)
460
 
        {
461
 
            bool match (Object o) {
462
 
                union switch (o.robot) {
463
 
                case robot r: 
464
 
                    if (r.color == color || color == Color.Whirl) 
465
 
                        return true;
466
 
                default:
467
 
                }
468
 
                return false;
469
 
            }
470
 
            return find (&b, match);
471
 
        }
472
 
 
473
 
        public exception invalid_robot (Color color);
474
 
 
475
 
        public ObjectLoc find_robot (&Board b, Color color) {
476
 
            ObjectLoc[*] ol = find_robots (&b, color);
477
 
            if (dim (ol) != 1)
478
 
                raise invalid_robot (color);
479
 
            return ol[0];
480
 
        }
481
 
        
482
 
        public ObjectLoc[*] find_active_robot (&Board b)
483
 
        {
484
 
            bool match (Object o) {
485
 
                union switch (o.robot) {
486
 
                case robot r: 
487
 
                    if (r.active)
488
 
                        return true;
489
 
                default:
490
 
                }
491
 
                return false;
492
 
            }
493
 
            return find (&b, match);
494
 
        }
495
 
 
496
 
        public ObjectLoc[*] find_targets (&Board b, Color color, Shape shape)
497
 
        {
498
 
            bool match (Object o) {
499
 
                union switch (o.target) {
500
 
                case target t: 
501
 
                    if (t.color == color && t.shape == shape) 
502
 
                        return true;
503
 
                default:
504
 
                }
505
 
                return false;
506
 
            }
507
 
            return find (&b, match);
508
 
        }
509
 
 
510
 
        public ObjectLoc[*] find_active_target (&Board b) {
511
 
            bool match (Object o) {
512
 
                union switch (o.target) {
513
 
                case target t: 
514
 
                    if (t.active)
515
 
                        return true;
516
 
                default:
517
 
                }
518
 
                return false;
519
 
            }
520
 
            return find (&b, match);
521
 
        }
522
 
 
523
 
        public void set_target (&Board b, Color color, Shape shape) {
524
 
            void    set_robot_active (ObjectLoc[*] ol, bool active) {
525
 
                for (int o = 0; o < dim (ol); o++)
526
 
                    b[ol[o].x, ol[o].y].robot.robot.active = active;
527
 
            }
528
 
            void    set_target_active (ObjectLoc[*] ol, bool active) {
529
 
                for (int o = 0; o < dim (ol); o++)
530
 
                    b[ol[o].x, ol[o].y].target.target.active = active;
531
 
            }
532
 
            set_robot_active (find_active_robot (&b), false);
533
 
            set_target_active (find_active_target (&b), false);
534
 
            
535
 
            set_robot_active (find_robots (&b, color), true);
536
 
            set_target_active (find_targets (&b, color, shape), true);
537
 
        }
538
 
 
539
 
        public void position_robot (&Board b, Color color, int x, int y) {
540
 
            ObjectLoc ol = find_robot (&b, color);
541
 
            b[ol.x, ol.y].robot = RobotOrNone.none;
542
 
            if (b[x, y].robot != RobotOrNone.none)
543
 
                raise invalid_robot (color);
544
 
            b[x, y].robot = ol.object.robot;
545
 
        }
546
 
 
547
 
        typedef struct {
548
 
            int dx;
549
 
            int dy;
550
 
        } Delta;
551
 
 
552
 
        bool blocked_wall (Direction direction, Walls walls) {
553
 
            switch (direction) {
554
 
            case Direction.North: return walls.above;
555
 
            case Direction.East:  return walls.right;
556
 
            case Direction.South: return walls.below;
557
 
            case Direction.West:  return walls.left;
558
 
            }
559
 
            return false;
560
 
        }
561
 
 
562
 
        bool blocked_robot (&Board b, int x, int y) {
563
 
            if (x < 0 || Width <= x) return true;
564
 
            if (y < 0 || Height <= y) return true;
565
 
            return b[x,y].robot != RobotOrNone.none;
566
 
        }
567
 
 
568
 
        Delta delta (Direction direction) {
569
 
            switch (direction) {
570
 
            case Direction.North: return (Delta) { dx =  0, dy = -1 };
571
 
            case Direction.East:  return (Delta) { dx =  1, dy =  0 };
572
 
            case Direction.South: return (Delta) { dx =  0, dy =  1 };
573
 
            case Direction.West:
574
 
            default:
575
 
            }
576
 
            return (Delta) { dx = -1, dy =  0 };
577
 
        }
578
 
 
579
 
        ObjectLoc find_dst (&Board b, int x, int y, Direction direction) {
580
 
            Delta   d = delta (direction);
581
 
            while (!blocked_wall (direction, b[x,y].walls) &&
582
 
                   !blocked_robot (&b, x + d.dx, y + d.dy))
583
 
            {
584
 
                x += d.dx;
585
 
                y += d.dy;
586
 
            }
587
 
            return (ObjectLoc) { x = x, y = y, object = b[x,y] };
588
 
        }
589
 
            
590
 
        public ObjectLoc move_robot (&Board b, Color color, Direction direction) {
591
 
            ObjectLoc   src = find_robot (&b, color);
592
 
            ObjectLoc   dst = find_dst (&b, src.x, src.y, direction);
593
 
            return dst;
594
 
        }
595
 
 
596
 
        public bool solved (&Board b) {
597
 
            ObjectLoc[*]    target = find_active_target (&b);
598
 
 
599
 
            if (dim(target) != 1)
600
 
                return false;
601
 
            union switch (target[0].object.robot) {
602
 
            case robot r:
603
 
                return r.active;
604
 
            default:
605
 
            }
606
 
            return false;
607
 
        }
608
 
    }
609
 
}