1
2=head1 NAME
3
4Mines::Field - A minesweeper field
5
6=head1 SYNOPSIS
7
8    # setup field properties
9    $P0 = new 'Hash'
10    $P0['width']  = 40
11    $P0['height'] = 28
12    $P0['mines']  = 0.1075
13    $P0['level']  = 123
14    $P0['screen'] = screen
15    $P0['debug']  = debug
16
17    # create the field
18    field = new "Mines::Field", $P0
19
20    # draw the field
21    field.'draw'()
22
23=head1 DESCRIPTION
24
25This is an implementation of a Minesweeper game field.
26It draws the field onto a SDL surface.
27
28=head1 METHODS
29
30An Mines::Field object has the following methods:
31
32=over 4
33
34=cut
35
36.include "iterator.pasm"
37.loadlib 'math_ops'
38.namespace ["Mines::Field"]
39
40# size of a single mine field, in pixels
41.const int FIELD_WIDTH  = 16
42.const int FIELD_HEIGHT = 16
43
44# mine field values
45.const int VAL_INVALID            = -1
46.const int VAL_FREE               =  0
47.const int VAL_1                  =  1
48.const int VAL_2                  =  2
49.const int VAL_3                  =  3
50.const int VAL_4                  =  4
51.const int VAL_5                  =  5
52.const int VAL_6                  =  6
53.const int VAL_7                  =  7
54.const int VAL_8                  =  8
55.const int VAL_MINE_EXPLODED      =  9
56.const int VAL_NO_MINE            = 10
57.const int VAL_MINE               = 11
58.const int VAL_FLAG_NO_MINE       = 12
59.const int VAL_FLAG_MINE          = 13
60.const int VAL_UNSURE_NO_MINE     = 14
61.const int VAL_UNSURE_MINE        = 15
62.const int VAL_UNEXPLORED_NO_MINE = 16
63.const int VAL_UNEXPLORED_MINE    = 17
64.const int VAL_MARK_NO_MINE       = 18
65.const int VAL_MARK_MINE          = 19
66
67# game status
68.const int STATUS_PLAYING  = 0
69.const int STATUS_CHOOSING = 1
70.const int STATUS_LOST     = 2
71.const int STATUS_SLEEPING = 3
72.const int STATUS_WON      = 4
73
74
75=item __init( hash )
76
77The constructor. You have to pass a hash filled with
78the following values:
79
80=over 4
81
82=item width
83
84Number of horizontal units the field should have.
85
86=item height
87
88Number of vertical units the field should have.
89
90=item level
91
92Initial seed for the PRNG that is used to calculate the field.
93
94=item mines
95
96The amount of mines. 0.0 means no mines, 1.0 means mines everywhere.
97
98=item screen
99
100SDL surface to use for drawing.
101
102=item debug
103
1040 = normal mode
1051 = use debug image (position of mines are visible)
106
107=back
108
109=cut
110
111.sub __init :method
112    .param pmc args
113    .local pmc field
114    .local pmc screen
115    .local pmc cache
116    .local int width
117    .local int height
118    .local int level
119    .local num mines
120    .local int val
121    .local int debug
122    .local pmc lcd
123    .local pmc watch
124
125    # get the arguments
126    width  = args['width']
127    height = args['height']
128    level  = args['level']
129    mines  = args['mines']
130    screen = args['screen']
131    debug  = args['debug']
132    field  = new 'ResizablePMCArray'
133    cache  = new 'ResizablePMCArray'
134
135    watch = new ['SDL'; 'StopWatch'], screen
136    watch.'xpos'( 515 )
137    watch.'ypos'( 5 )
138
139    lcd = new ['SDL'; 'LCD']
140    # This seems to call __init() with too many parameters
141    # lcd = 0
142    lcd.'_digits'( 4 )
143    lcd.'xpos'( 5 )
144    lcd.'ypos'( 5 )
145
146    setattribute self, 'field', field
147    setattribute self, 'cache', cache
148    setattribute self, 'screen', screen
149    setattribute self, 'mines_lcd', lcd
150    setattribute self, 'watch', watch
151
152    $P0 = new 'Integer'
153    $P0 = width
154    setattribute self, 'width', $P0
155
156    $P0 = new 'Integer'
157    $P0 = height
158    setattribute self, 'height', $P0
159
160    $P0 = new 'Float'
161    $P0 = mines
162    setattribute self, 'mines', $P0
163
164    $P0 = new 'Integer'
165    $P0 = -1
166    setattribute self, 'markpos', $P0
167
168    $P0 = new 'Integer'
169    $P0 = debug
170    setattribute self, 'debug', $P0
171
172    # button
173    $P0 = new 'String'
174    $P0 = "examples/sdl/minesweeper/smiley.png"
175    $P0 = new ['SDL'; 'Button'], $P0
176    $P0.'states'( 5 )
177    $P0.'pos'( 305, 2 )
178    $P0.'size'( 30, 30 )
179
180    $P1 = get_hll_global [ 'Mines::Field' ], '_button_clicked'
181    $P0.'setAction'( STATUS_PLAYING, $P1 )
182    $P0.'setAction'( STATUS_WON, $P1 )
183    $P0.'setAction'( STATUS_LOST, $P1 )
184
185    setattribute self, 'status_button', $P0
186
187    self.'newLevel'( level )
188.end
189
190=item newLevel( level )
191
192Creates a new level, with the given number as initial seed for the PRNG.
193
194=cut
195
196.sub newLevel :method
197    .param int level
198    .local pmc field
199    .local pmc cache
200    .local int size
201    .local int width
202    .local int height
203    .local int val
204    .local num mines
205
206    field  = getattribute self, 'field'
207    cache  = getattribute self, 'cache'
208
209    $P0    = getattribute self, 'witdh'
210    width  = $P0
211
212    $P0    = getattribute self, 'height'
213    height = $P0
214
215    $P0    = getattribute self, 'mines'
216    mines  = $P0
217
218    size   = width * height
219
220    field  = 0
221    cache  = 0
222
223    # fill the field
224LOOP:
225    level += size
226
227    $I0 = level
228    shl $I0, 13
229    $I0 = or $I0, level
230
231    $I1 = $I0 * $I0
232    $I1 *= 15731
233    $I1 += 789221
234
235    $I1 *= $I0
236    $I1 += 1376312589
237
238    $N0 = $I1
239    $N0 = $N0 / 1073741824.0
240    $N0 = 100.0 + $N0
241    $N0 *= 100.0
242    $I0 = $N0
243    $N0 = $N0 - $I0
244    level += $I0
245
246    val = VAL_UNEXPLORED_NO_MINE
247    ge $N0, mines, NO_MINE
248    val = VAL_UNEXPLORED_MINE
249NO_MINE:
250
251    push field, val
252    push cache, VAL_INVALID
253
254    dec size
255    if size <= 0 goto END
256    branch LOOP
257END:
258    # set the game status
259    self.'setStatus'( STATUS_PLAYING )
260    # reset the watch
261    $P0 = getattribute self, "Mines::Field\x0watch"
262    $P0.'reset'()
263.end
264
265=item draw()
266
267Draws the field, then the LCDs and the smiley button.
268
269=cut
270
271.sub draw :method
272    .local pmc screen
273    .local pmc image
274    .local pmc dest_rect
275    .local pmc src_rect
276    .local int width
277    .local int height
278    .local int size
279    .local int i
280    .local pmc field
281    .local pmc cache
282    .local pmc cacheit
283    .local int debug
284    .local int minx
285    .local int miny
286    .local int maxx
287    .local int maxy
288    .local pmc mines_lcd
289    .local pmc watch
290    .local pmc status
291
292    getattribute field, self, 'field'
293    field   = iter field
294    field   = .ITERATE_FROM_START
295
296    cache   = getattribute self, 'cache'
297    cacheit = iter cache
298    cacheit = .ITERATE_FROM_START
299
300    screen  = getattribute self, 'screen'
301
302    $P0     = getattribute self, 'width'
303    width   = $P0
304
305    $P0     = getattribute self, 'height'
306    height  = $P0
307
308    $P0     = getattribute self, 'debug'
309    debug   = $P0
310
311    minx    = width  * FIELD_WIDTH
312    miny    = height * FIELD_HEIGHT
313    maxx    = 0
314    maxy    = 0
315
316    if debug goto DEBUG
317    image = get_hll_global [ "Mines::Field" ], "field"
318    branch IMAGE_OK
319DEBUG:
320    image = get_hll_global [ "Mines::Field" ], "field_debug"
321IMAGE_OK:
322    $P0 = new 'Hash'
323    $P0['x'] = 0
324    $P0['y'] = 0
325    $P0['width']  = 0
326    $P0['height'] = 0
327    dest_rect = new ['SDL'; 'Rect'], $P0
328    $P0['width']  = FIELD_WIDTH
329    $P0['height'] = FIELD_HEIGHT
330    src_rect = new ['SDL'; 'Rect'], $P0
331
332    set size, width
333    mul size, height
334
335    i = 0
336LOOP:
337    if i >= size goto END
338
339    $P0 = shift field
340    $I0 = $P0
341    $P0 = shift cacheit
342    $I1 = $P0
343
344    # current field already drawn?
345    if $I0 == $I1 goto NEXT
346
347    cache[i] = $I0
348
349    $I1 = cmod i, width
350    $I2 = div i, width
351
352    mul $I1, FIELD_WIDTH
353    mul $I2, FIELD_HEIGHT
354
355    add $I1, 0
356    add $I2, 32
357
358    dest_rect.'x'( $I1 )
359    dest_rect.'y'( $I2 )
360
361    if $I1 > minx goto SKIP1
362    minx = $I1
363SKIP1:
364
365    if $I2 > miny goto SKIP2
366    miny = $I2
367SKIP2:
368
369    if $I1 < maxx goto SKIP3
370    maxx = $I1
371SKIP3:
372
373    if $I2 < maxy goto SKIP4
374    maxy = $I2
375SKIP4:
376
377    $I1 = cmod $I0, 5
378    $I2 = div $I0, 5
379
380    mul $I1, FIELD_WIDTH
381    mul $I2, FIELD_HEIGHT
382
383    src_rect.'x'( $I1 )
384    src_rect.'y'( $I2 )
385
386    screen.'blit'( image, src_rect, dest_rect )
387NEXT:
388    inc i
389    branch LOOP
390END:
391
392    add maxx, FIELD_WIDTH
393    add maxy, FIELD_HEIGHT
394
395    if maxx <= minx goto NO_SCREEN_UPDATE
396    if maxy <= miny goto NO_SCREEN_UPDATE
397
398    dest_rect.'x'( minx )
399    dest_rect.'y'( miny )
400    $I0 = maxx - minx
401    dest_rect.'width'( $I0 )
402    $I0 = maxy - miny
403    dest_rect.'height'( $I0 )
404
405    screen.'update_rect'( dest_rect )
406NO_SCREEN_UPDATE:
407
408    # update the LCDs
409    self.'update_stats'()
410
411    $P0 = getattribute self, "Mines::Field\x0mines_lcd"
412    $P0.'draw'( screen )
413
414    $P0 = getattribute self, "Mines::Field\x0watch"
415    $P0.'draw'( screen )
416
417    $P0 = getattribute self, "Mines::Field\x0status_button"
418    $P0.'draw'( screen )
419.end
420
421=item reveal( x, y )
422
423Reveals the field at the specified location.
424
425Returns 1 if successful, 0 otherwise.
426
427=cut
428
429.sub reveal :method
430    .param int x
431    .param int y
432    .local int width
433    .local int height
434    .local pmc watch
435
436    self."undo_mark"()
437
438    $P0    = getattribute self, 'width'
439    width  = $P0
440
441    $P0    = getattribute self, 'height'
442    height = $P0
443
444    watch  = getattribute self, 'watch'
445
446    $P0    = getattribute self, 'status'
447    if $P0 > STATUS_CHOOSING goto END
448
449    x -= 0
450    y -= 32
451
452    if x < 0 goto END
453    if y < 0 goto END
454
455    x /= FIELD_WIDTH
456    y /= FIELD_HEIGHT
457
458    watch.'start'()
459    self.'reveal_recursive'( x, y, width, height )
460    self.'check_end'()
461    self.'draw'()
462
463    .return (1)
464
465END:
466    .return (0)
467.end
468
469=item setFlag( x, y )
470
471Sets a flag at the specified location.
472
473Returns 1 if successful, 0 otherwise.
474
475=cut
476
477.sub setFlag :method
478    .param int x
479    .param int y
480    .local int width
481    .local pmc field
482    .local pmc watch
483    .local int pos
484    .local int v
485
486    self."undo_mark"()
487
488    $P0   = getattribute self, 'field'
489    field = $P0
490
491    $P0   = getattribute self, 'width'
492    width = $P0
493
494    watch = getattribute self, 'watch'
495
496    $P0   = getattribute self, 'status'
497    if $P0 > STATUS_CHOOSING goto END
498
499    x -= 0
500    y -= 32
501
502    if x < 0 goto END
503    if y < 0 goto END
504
505    x /= FIELD_WIDTH
506    y /= FIELD_HEIGHT
507
508    pos = y * width
509    pos += x
510
511    v = field[pos]
512
513    if v == VAL_FLAG_NO_MINE       goto PLUS2
514    if v == VAL_FLAG_MINE          goto PLUS2
515    if v == VAL_UNSURE_NO_MINE     goto PLUS2
516    if v == VAL_UNSURE_MINE        goto PLUS2
517    if v == VAL_UNEXPLORED_NO_MINE goto MINUS4
518    if v == VAL_UNEXPLORED_MINE    goto MINUS4
519    branch END
520
521PLUS2:
522    v += 2
523    branch DRAW
524
525MINUS4:
526    v -= 4
527
528DRAW:
529    field[pos] = v
530
531    watch.'start'()
532    self."check_end"()
533    self."draw"()
534
535    .return (1)
536
537END:
538    .return (0)
539.end
540
541=item undo_mark( i ) B<(internal)>
542
543Removes the field mark.
544
545Parameters:
546
547=over 4
548
549=item i
550
551Optional. The value does not matter. If you pass an integer value,
552the game status is not set. If you pass no integer, the game status
553will be set.
554
555Just do not pass an integer, it is for internal use only.
556(C<setStatus()> calls undo_mark, which in turn calls setStatus; this
557argument is used to avoid recursion)
558
559=back
560
561This method returns nothing.
562
563=cut
564
565.sub undo_mark :method
566    .param int i      :optional
567    .param int has_i  :opt_flag
568
569    .local pmc markpos
570    .local pmc field
571    .local pmc status
572
573    $P0     = getattribute self, 'field'
574    field   = $P0
575
576    markpos = getattribute self, 'markpos'
577    status  = getattribute self, 'status'
578
579    $I0     = markpos
580
581    if $I0 == -1 goto UNDO_DONE
582    $I1 = field[$I0]
583    $I1 -= 2
584    field[$I0] = $I1
585UNDO_DONE:
586    markpos = -1
587
588    if has_i goto END
589    if status != STATUS_CHOOSING goto END
590    self."setStatus"( STATUS_PLAYING )
591END:
592.end
593
594=item mark( x, y )
595
596Sets a mark on the specified field.
597This is used to give feedback which field will be revealed.
598Only one field is marked at any time, a previous mark will be
599removed if you call this method.
600
601=cut
602
603.sub mark :method
604    .param int x
605    .param int y
606    .local int width
607    .local pmc markpos
608    .local pmc field
609    .local pmc watch
610    .local int pos
611    .local int v
612
613    self."undo_mark"()
614
615    $P0     = getattribute self, 'field'
616    field   = $P0
617
618    $P0     = getattribute self, 'width'
619    width   = $P0
620
621    markpos = getattribute self, 'markpos'
622
623    x -= 0
624    y -= 32
625
626    watch = getattribute self, 'watch'
627
628    $P0   = getattribute self, 'status'
629    if $P0 >= STATUS_CHOOSING goto END
630
631    if x < 0 goto END
632    if y < 0 goto END
633
634    x /= FIELD_WIDTH
635    y /= FIELD_HEIGHT
636
637    pos = y * width
638    pos += x
639
640    v = field[pos]
641
642    if v == VAL_UNEXPLORED_NO_MINE goto MARK
643    if v == VAL_UNEXPLORED_MINE goto MARK
644    branch END
645MARK:
646    self."setStatus"( STATUS_CHOOSING )
647    markpos = pos
648    v += 2
649    field[pos] = v
650DRAW:
651    watch.'start'()
652    self."check_end"()
653    self."draw"()
654
655    .return (1)
656
657END:
658    .return (0)
659.end
660
661=item click( x, y, b )
662
663This method is used to send mouse click events to the smiley button.
664
665Parameters:
666
667=over 4
668
669=item x
670
671The vertical mouse position.
672
673=item y
674
675The horizontal mouse position.
676
677=item b
678
6790 = mouse button not pressed
680
6811 = mouse button pressed
682
683=back
684
685=cut
686
687.sub click :method
688    .param int x
689    .param int y
690    .param int b
691
692    if y > 32 goto END
693
694    $P0 = getattribute self, 'status_button'
695    $I0 = $P0.'click'( x, y, b, self )
696    unless $I0 goto END
697
698    $P1 = getattribute self, 'screen'
699
700    $P0."draw"( $P1 )
701END:
702
703.end
704
705=item reveal_recursive( x, y, width, height ) B<(internal)>
706
707Reveals the specified field recursively.
708
709The width and height are the dimensions of the board, they
710have to be specified for performance reasons.
711
712=cut
713
714.sub reveal_recursive :method
715    .param int x
716    .param int y
717    .param int width
718    .param int height
719    .local pmc field
720    .local int pos
721
722    if x < 0 goto END
723    if y < 0 goto END
724    if x >= width goto END
725    if y >= height goto END
726
727    pos = y * width
728    pos += x
729
730    $P0   = getattribute self, 'field'
731    field = $P0
732
733    $I0 = field[pos]
734    if $I0 == VAL_FREE goto END
735    if $I0 == VAL_UNEXPLORED_NO_MINE goto UNEXPLORED
736    if $I0 == VAL_UNEXPLORED_MINE goto UNEXPLORED_MINE
737    branch END
738
739UNEXPLORED:
740    $I0 = _mines_near( field, x, y, width, height )
741    field[pos] = $I0
742    if $I0 != 0 goto END
743
744    dec y
745    dec x
746    self.'reveal_recursive'( x, y, width, height )
747    inc x
748    self.'reveal_recursive'( x, y, width, height )
749    inc x
750    self.'reveal_recursive'( x, y, width, height )
751
752    inc y
753    dec x
754    dec x
755    self.'reveal_recursive'( x, y, width, height )
756    inc x
757    self.'reveal_recursive'( x, y, width, height )
758    inc x
759    self.'reveal_recursive'( x, y, width, height )
760
761    inc y
762    dec x
763    dec x
764    self.'reveal_recursive'( x, y, width, height )
765    inc x
766    self.'reveal_recursive'( x, y, width, height )
767    inc x
768    self.'reveal_recursive'( x, y, width, height )
769    branch END
770
771UNEXPLORED_MINE:
772    field[pos] = VAL_MINE_EXPLODED
773    self.'lost'()
774
775END:
776    .return ()
777.end
778
779=item lost()
780
781Called if a mine is revealed.
782Shows the position of all mines on the field.
783
784=cut
785
786.sub lost :method
787    .local pmc field
788    .local int i
789    .local int max
790
791    self."setStatus"( STATUS_LOST )
792
793    field = getattribute self, 'field'
794    max   = field
795    i     = 0
796
797LOOP:
798    if i >= max goto END
799
800    $I1 = field[i]
801
802    if $I1 == VAL_UNEXPLORED_MINE goto MINE
803    if $I1 == VAL_UNSURE_MINE goto MINE
804    if $I1 == VAL_FLAG_NO_MINE goto NO_MINE
805    branch NEXT
806
807MINE:
808    $I1 = VAL_MINE
809    branch NEXT
810
811NO_MINE:
812    $I1 = VAL_NO_MINE
813    branch NEXT
814
815NEXT:
816    field[i] = $I1
817    inc i
818    branch LOOP
819END:
820.end
821
822=item won()
823
824Called when you have won.
825
826=cut
827
828.sub won :method
829    self."setStatus"( STATUS_WON )
830.end
831
832=item check_end()
833
834Checks if you have won.
835
836=cut
837
838.sub check_end :method
839    .local pmc field
840
841    field = getattribute self, 'field'
842    field = iter field
843    field = .ITERATE_FROM_START
844LOOP:
845    unless field goto WON
846
847    $I0 = shift field
848
849    if $I0 <= 8 goto LOOP
850
851    if $I0 == VAL_MINE goto END
852    if $I0 == VAL_MINE_EXPLODED goto END
853    if $I0 == VAL_UNSURE_MINE goto END
854    if $I0 == VAL_FLAG_NO_MINE goto END
855    if $I0 == VAL_UNEXPLORED_MINE goto END
856
857    branch LOOP
858
859WON:
860    self."won"()
861    .return (1)
862END:
863    .return (0)
864.end
865
866=item setStatus( newStatus )
867
868Sets a new game status.
869
870=cut
871
872.sub setStatus :method
873    .param int s
874    .local pmc screen
875    .local pmc watch
876    .local pmc status
877
878    screen = getattribute self, 'screen'
879    watch  = getattribute self, 'watch'
880    status = getattribute self, 'status'
881
882    if s == STATUS_PLAYING goto OK
883    if s == STATUS_CHOOSING goto OK
884
885    # not playing at the moment, stop the watch
886    watch.'stop'()
887OK:
888    # no need to start the watch here
889
890    status = s
891    self."undo_mark"( 1 )
892    watch.'draw'( screen )
893
894DONE:
895.end
896
897=item update_stats()
898
899Counts the unrevealed mines and updates the LCD.
900
901=cut
902
903.sub update_stats :method
904    .local pmc field
905    .local int size
906    .local pmc count
907    .local pmc mines_lcd
908
909    field     = getattribute self, 'field'
910    mines_lcd = getattribute self, 'mines_lcd'
911
912    size  = field
913    field = iter field
914    field = .ITERATE_FROM_START
915    count = new 'ResizablePMCArray'
916
917LOOP:
918    unless field goto END
919    $I0 = shift field
920    $I1 = count[$I0]
921    inc $I1
922    count[$I0] = $I1
923    branch LOOP
924END:
925
926    $I0 = count[VAL_UNEXPLORED_MINE]
927    $I1 = count[VAL_UNSURE_MINE]
928    $I2 = count[VAL_FLAG_NO_MINE]
929    $I3 = count[VAL_MINE]
930    $I4 = count[VAL_MINE_EXPLODED]
931    $I5 = count[VAL_MARK_MINE]
932
933    $I0 += $I1
934    $I0 -= $I2
935    $I0 += $I3
936    $I0 += $I4
937    $I0 += $I5
938    mines_lcd = $I0
939.end
940
941=back
942
943=head1 INTERNAL FUNCTIONS
944
945=over 4
946
947=item __onload()
948
949Loads necessary modules and creates the B<Mines::Field> class.
950This method is called automatically when this module is loaded.
951
952=cut
953
954.sub __onload :load
955    .local pmc class
956    class = get_class "Mines::Field"
957    unless null class goto END
958
959    .local pmc tmp
960    .local pmc size
961    .local pmc size_rect
962    .local pmc prop
963
964    .local pmc from_rect
965    .local pmc image
966    .local int rect_type
967    .local int surface_type
968
969    load_bytecode "examples/sdl/minesweeper/eventhandler.pir"
970    load_bytecode "SDL/Button.pir"
971    load_bytecode "SDL/StopWatch.pir"
972    load_bytecode "SDL/Image.pir"
973
974    # XXX: remove
975    load_bytecode "Data/Dumper.pir"
976
977    $P0 = new 'String'
978    $P0 = "examples/sdl/minesweeper/mines.png"
979    image = new ['SDL'; 'Image'], $P0
980    set_hll_global [ "Mines::Field" ], "field", image
981
982    $P0 = new 'String'
983    $P0 = "examples/sdl/minesweeper/mines_debug.png"
984    image = new ['SDL'; 'Image'], $P0
985    set_hll_global [ "Mines::Field" ], "field_debug", image
986
987    newclass $P0, "Mines::Field"
988    addattribute $P0, 'field'
989    addattribute $P0, 'cache'
990    addattribute $P0, 'screen'
991    addattribute $P0, 'width'
992    addattribute $P0, 'height'
993    addattribute $P0, 'mines'
994    addattribute $P0, 'markpos'
995    addattribute $P0, 'debug'
996    addattribute $P0, 'mines_lcd'
997    addattribute $P0, 'watch'
998    addattribute $P0, 'status_button'
999END:
1000.end
1001
1002=item _mines_near( field, x, y, width, height )
1003
1004Returns the number of mines in the neighbourhood
1005of the field at the specified location.
1006
1007The width and height are the dimensions of the board.
1008
1009=cut
1010
1011.sub _mines_near
1012    .param pmc field
1013    .param int x
1014    .param int y
1015    .param int width
1016    .param int height
1017    .local int mines
1018    .local int i
1019    .local int i1
1020    .local int i2
1021    .local int j
1022    .local int j2
1023    .local int pos
1024
1025    mines = 0
1026
1027    set i1, x
1028    dec i1
1029    set i2, x
1030    inc i2
1031
1032    set j, y
1033    dec j
1034    set j2, y
1035    inc j2
1036
1037LOOPj:
1038    i = i1
1039LOOPi:
1040    if i > i2 goto ENDi
1041    if j < 0 goto ENDi
1042    if j >= height goto ENDi
1043    if i < 0 goto NEXTi
1044    if i >= width goto NEXTi
1045
1046    pos = j * width
1047    pos += i
1048
1049    $I0 = _mine_at( field, pos )
1050    unless $I0 goto NEXTi
1051
1052    inc mines
1053
1054NEXTi:
1055    inc i
1056    branch LOOPi
1057ENDi:
1058    inc j
1059    if j <= j2 goto LOOPj
1060
1061    .return (mines)
1062.end
1063
1064=item _mine_at( field, pos )
1065
1066Returns 1 if a mine is in the given field
1067at the specified position, 0 otherwise.
1068
1069=cut
1070
1071.sub _mine_at
1072    .param pmc field
1073    .param int pos
1074    .local int v
1075
1076    v = field[pos]
1077    if v == VAL_MINE goto MINE
1078    if v == VAL_MINE_EXPLODED goto MINE
1079    if v == VAL_FLAG_MINE goto MINE
1080    if v == VAL_UNSURE_MINE goto MINE
1081    if v == VAL_UNEXPLORED_MINE goto MINE
1082    if v == VAL_MARK_MINE goto MINE
1083    .return (0)
1084MINE:
1085    .return (1)
1086.end
1087
1088=item _button_clicked( onField )
1089
1090Called if you click the smiley button.
1091It starts a new level.
1092
1093=cut
1094
1095.sub _button_clicked
1096    .param pmc field
1097
1098    $I0 = time
1099    field.'newLevel'( $I0 )
1100    field.'draw'()
1101.end
1102
1103=back
1104
1105=head1 AUTHOR
1106
1107Jens Rieks E<lt>parrot at jensbeimsurfen dot deE<gt> is the author
1108and maintainer.
1109Please send patches and suggestions to the Perl 6 Internals mailing list.
1110
1111=head1 COPYRIGHT
1112
1113Copyright (C) 2004-2008, Parrot Foundation.
1114
1115=cut
1116
1117# Local Variables:
1118#   mode: pir
1119#   fill-column: 100
1120# End:
1121# vim: expandtab shiftwidth=4 ft=pir:
1122