Home > Previous Page >  Ace Mines
Archive Search  
Ace Mines
by Ricardo Lopes
Ace Mines by Ricardo Fernandes Lopes. (c) 2004 GNU General Public License.

The object of Ace Mines is to find all the mines possible without uncovering any of them.
If you find a mine, its all over! you lose.

Keys

I .. Move left
P .. Move right
A .. Move up
Z .. Move down

F .. to flag or mark a mine.
O .. to open or uncover the cell.

To Start a new game select,

B .. for Beginner
I .. for Intermediate
E .. for Expert

Move your cursor around the cells with keys I,P,A, and Z.
To uncover or open a cell press O, if you find a bomb its Game over!

If a number appears in the cell, it indicates how many mines are in the eight cells that surround the numbered one.

To mark a cell you suspect contains a mine, press f to flag it.
The listing below has a number of comments in it, give you a clear guide of what each AceForth word does.


( ACE Mines listing  )

CREATE TABLE 128 ALLOT  ( Graphics )
: GR 8 * TABLE + DUP 8 + SWAP DO I C! LOOP ;
16 BASE C!
00 00 00 00 00 00 00 00 00 GR
00 1C 08 08 08 08 18 00 01 GR
00 7E 40 7E 02 02 7E 00 02 GR
00 7E 02 02 3E 02 7E 00 03 GR
00 04 04 7E 44 44 40 00 04 GR
00 7E 02 02 7E 40 7E 00 05 GR
00 7E 42 7E 40 40 7E 00 06 GR
00 02 02 02 02 02 7E 00 07 GR
00 7E 42 42 7E 24 3C 00 08 GR
00 02 02 02 7E 42 7E 00 09 GR
00 3c 7e 7e 7e 3c 08 06 0A GR ( BOMB )
81 7E 5E 5E 42 42 7E 81 0B GR ( FLAG )
00 7E 7E 7E 7E 7E 7E 00 0C GR ( TILE )
FF 81 81 81 81 81 81 FF 0D GR ( not used)
7E FF BD C3 FF 99 DB 7E 0E GR ( SAD )
7E C3 81 FF 99 00 99 7E 0F GR ( SMILE )
DECIMAL
: SETGR 128 0 DO TABLE I + C@ 10240 I + C! LOOP ;

: 2DUP OVER OVER ;  ( x1 x2 -- x1 x2 x1 x2 )
: 2DROP DROP DROP ; ( x1 x2 -- )

: BLIP 100 50 BEEP 50 25 BEEP ;

: KEY ( -- c , wait for a keypress )
 BEGIN INKEY 0= UNTIL
 BEGIN INKEY ?DUP UNTIL 223 AND ;

( random number generator)
0 VARIABLE RND
: RANDOMIZE 15403 @ RND ! ;
: RANDOM ( n1 -- n2 , generate a random number from 0 to n1-1)
 RND @ 31421 * 6927 + DUP RND !
 U* SWAP DROP ;

: MENU ( -- n , Print menu and wait user option )
 CLS ." 2004       ACE  MINES       v1.0"
  5  3 AT ." Choose:  Beginner"
  7 12 AT ." Intermediate"
  9 12 AT ." Expert"
 11 12 AT ." Quit"
 19  0 AT ." 2004 (c) Ricardo Fernandes Lopes" CR
 ." - GNU General Public License -"
 KEY BLIP ;

8 VARIABLE XMAX
8 VARIABLE YMAX
10 VARIABLE BOMBS
: LEVEL! BOMBS ! YMAX ! XMAX ! ; ( bombs height width -- )
: BEGINNER  8  8 10 ;
: INTERMED 16 16 40 ;
: EXPERT   30 16 99 ;
: SETLEVEL
 DUP [ ASCII I ] LITERAL = IF INTERMED
 ELSE DUP [ ASCII E ] LITERAL = IF EXPERT ELSE BEGINNER THEN
 THEN LEVEL! DROP ;

10 CONSTANT BOMB
11 CONSTANT FLAG
12 CONSTANT TILE

0 VARIABLE X
0 VARIABLE Y
9216 CONSTANT SCREEN
CREATE BOARD 30 16 * ALLOT
: XY@ X @ Y @ ;                 (     -- x y , get cursor coord)
: XY>BOARD XMAX @ * + BOARD + ; ( x y -- adr , convert coord to board address)
: BOARD> XY@ XY>BOARD ;         (     -- adr , get current board address)
: XY>SCREEN 1+ 32 * 1+ + SCREEN + ;   ( x y -- adr , convert coord to screen address)
: SCREEN> XY@ XY>SCREEN ;       (     -- adr , get current screen address)
: CLRBOARD ( Clear Board)
 BOARD XMAX @ YMAX @ * + BOARD DO 0 I C! LOOP ;

: XY-OK? ( x y -- x y f , check for valid coord)
 2DUP
 OVER XMAX @ < OVER YMAX @ < AND
 SWAP 0< 0= AND SWAP 0< 0= AND ;

( Toogle screen cursor inverse/normal)
: .CURSOR SCREEN> DUP C@ 128 XOR SWAP C! ;

( Move coord)
: UP    ( x y -- x y-1)   1- ; 
: DOWN  ( x y -- x y+1)   1+ ; 
: LEFT  ( x y -- x-1 y)   SWAP 1- SWAP ; 
: RIGHT ( x y -- x+1 y)   SWAP 1+ SWAP ; 

: SHOW ( x y -- c , show coord contents)
 2DUP XY>SCREEN   ROT ROT XY>BOARD C@   DUP ROT C! ;

( Tracking winning condition)
0 VARIABLE CLOSED
: CLOSEALL XMAX @ YMAX @ * BOMBS @ - CLOSED ! ; ( Initialize count of closed tiles)
: WIN? CLOSED @ 0= ; ( -- f , Check winning condition)
: .WIN ( Win/Loose icon/tune)
 0 XMAX @ 2 / AT
 WIN?
 IF   201 100 BEEP 100 150 BEEP  50 200 BEEP 15
 ELSE  50 100 BEEP 100 150 BEEP 201 200 BEEP 14
 THEN EMIT ;

: OPENALL ( Open all tiles)
 YMAX @ 0 DO
  XMAX @ 0 DO
   I J XY>BOARD C@
   I J XY>SCREEN C!
  LOOP
 LOOP ;

: OPENXY ( x y -- x y , open tile at coord)
 XY-OK?
 IF
  2DUP XY>SCREEN C@
  DUP TILE = SWAP FLAG = OR
  IF
   CLOSED @ 1- CLOSED !
   2DUP SHOW 0=
   IF
    UP    OPENXY
    RIGHT OPENXY
    DOWN  OPENXY
    DOWN  OPENXY
    LEFT  OPENXY
    LEFT  OPENXY
    UP    OPENXY
    UP    OPENXY
    RIGHT DOWN
   THEN
  THEN
 THEN ;

: OPEN ( -- f , open tile and return true if BOMB )
 BLIP XY@ OPENXY   XY>BOARD C@ BOMB = ;

: FLAGIT ( Mark/Unmark tile with a flag)
 SCREEN> C@ DUP
 TILE = IF FLAG SCREEN> C! THEN
 FLAG = IF TILE SCREEN> C! THEN ;

: INC ( x y -- x y , Increment value of cell at coord)
 XY-OK?
 IF
  2DUP XY>BOARD DUP C@ BOMB =
  IF DROP
  ELSE DUP C@ 1+ SWAP C!
  THEN
 THEN ;

: BOMB! ( x y -- , Place Bomb at coord and increment neighbor)
 2DUP XY>BOARD BOMB SWAP C!
 UP    INC
 RIGHT INC
 DOWN  INC
 DOWN  INC
 LEFT  INC
 LEFT  INC
 UP    INC
 UP    INC
 2DROP ;

: BOMB? ( x y -- x y f , check if Bomb at coord)
 2DUP XY>BOARD C@ BOMB = ;

: SEED ( place Bombs at mine field)
 CLRBOARD
 BOMBS @ 0
 DO
  46 EMIT
  BEGIN
   XMAX @ RANDOM YMAX @ RANDOM BOMB?
  WHILE
   2DROP
  REPEAT
  BOMB!
 LOOP ;

( Draw board ) 
: HBAR XMAX @ 2+ 0 DO 160 EMIT LOOP ;
: DRAW
 CLS HBAR
 YMAX @ 1+ DUP 1
 DO
  I 0 AT 160 EMIT
  XMAX @ 0
  DO
   TILE EMIT
  LOOP
  160 EMIT
 LOOP
 0 AT HBAR
 19 0 AT
 ."    A move up      Z move down"  CR
 ."    I move left    P move right" CR
 ."    F place flag   O open"       CR
 ."    Q quit" ;

: INIT   0 X ! 0 Y !  SEED CLOSEALL DRAW ;

: XY! ( x y -- )
 XY-OK? IF Y ! X ! ELSE 2DROP THEN ;

: ACTION ( c -- f , execute key command, return true if end)
 DUP [ ASCII Q ] LITERAL = DUP 0=
 IF
  OVER [ ASCII I ] LITERAL = IF XY@ LEFT  XY! THEN
  OVER [ ASCII P ] LITERAL = IF XY@ RIGHT XY! THEN
  OVER [ ASCII A ] LITERAL = IF XY@ UP    XY! THEN
  OVER [ ASCII Z ] LITERAL = IF XY@ DOWN  XY! THEN
  OVER [ ASCII F ] LITERAL = IF FLAGIT THEN
  OVER [ ASCII O ] LITERAL = IF OPEN OR WIN? OR THEN
 THEN
 SWAP DROP ;

: GAME ( n -- , Play game at given level)
 CLS ." Wait" SETLEVEL INIT
 BEGIN .CURSOR KEY .CURSOR ACTION UNTIL
 .WIN OPENALL .CURSOR KEY DROP ;

(  Main code, run it to play ACE Mines)
: MINES
 SETGR RANDOMIZE
 BEGIN
  MENU DUP [ ASCII Q ] LITERAL = 0=
 WHILE
  GAME
 REPEAT
 DROP CLS ." Bye." ;