www.jupiter-ace.co.uk
|
Previous Page > Listings Index > SokoACE listing |
|
|
SokoAce
by
Ricardo Fernandes Lopes
|
( SokoACE ) ( Sokoban game for the Jupiter ACE ) ( (c) 2006 by Ricardo Fernandes Lopes ) ( under the GNU General Public License ) ( Load and play the game with: ) ( LOAD SOKOACE PLAY ) ( Graphic characters ) CREATE T 56 ALLOT : GR 8 * T + DUP 8 + SWAP DO I C! LOOP ; : SETGR 56 0 DO T I + C@ 10240 I + C! LOOP ; 16 BASE C! 00 00 00 00 00 00 00 00 00 GR ( Not used ) 00 00 00 18 18 00 00 00 01 GR ( Target ) 3C 42 81 FF 99 99 7E 3C 02 GR ( Soko ) 3C 42 BD FF BD 99 7E 3C 03 GR ( Soko + Target ) 00 7E 42 42 42 42 7E 00 04 GR ( Box ) 00 7E 42 5A 5A 42 7E 00 05 GR ( Box + Target ) FF AB D5 AB D5 AB D5 FF 06 GR ( Wall ) DECIMAL ( Screen elements) 01 CONSTANT TARGET ( 00 0001b ) 02 CONSTANT SOKO ( 00 0010b ) 04 CONSTANT BOX ( 00 0100b ) 06 CONSTANT WALL ( 00 0110b ) 32 CONSTANT BL ( 10 0000b ) : KEY ( -- c ,wait for keypress) BEGIN INKEY 0= UNTIL BEGIN INKEY ?DUP UNTIL ; : >UPPER ( c1 -- c2 ,convert to uppercase) DUP 96 > IF 223 AND THEN ; : IN? ( -- n , get number from user) QUERY NUMBER DUP IF 4181 = ( avoid float numbers) IF DROP 0 THEN THEN ; : +! ( n adr -- ) SWAP OVER @ + SWAP ! ; : INC ( a -- ) 1 SWAP +! ; : DEC ( a -- ) -1 SWAP +! ; 0 VARIABLE SOKO> ( holds SOKO screen address ) 0 VARIABLE #BOX ( number of boxes out of target ) 0 VARIABLE #STEP ( number of steps ) 0 VARIABLE #PUSH ( number of pushes ) ( Movement directions) -32 CONSTANT UP 32 CONSTANT DOWN -1 CONSTANT LEFT 1 CONSTANT RIGHT : STEP ( a1 -- , move SOKO one step) DUP C@ TARGET AND SOKO OR OVER C! ( place SOKO in new position ) SOKO> @ ( previous SOKO position ) DUP C@ TARGET AND ( check previous contents ) IF TARGET ELSE BL THEN ( Target or Blank ) SWAP C! ( remove SOKO from old position ) SOKO> ! #STEP INC ; : PUSH ( a1 a2 -- , push a BOX) OVER C@ TARGET AND IF #BOX INC THEN ( Box entered a target region) DUP C@ DUP TARGET AND IF #BOX DEC THEN ( Box exited a target area) TARGET AND BOX OR SWAP C! ( Move Box) STEP ( Move Soko) #STEP DEC ( Inc Pushes but not Steps) #PUSH INC ; : GO ( dir -- , try to move Soko in the specified direction) SOKO> @ OVER + ( next position ) DUP C@ WALL = IF DROP DROP ( if WALL, do nothing ) ELSE DUP C@ DUP BL = SWAP TARGET = OR IF STEP DROP ( if Blank or Target, do Step) ELSE SWAP OVER + ( over next position ) DUP C@ DUP BL = SWAP TARGET = OR IF PUSH ( if Blank or Target, do Push ) ELSE DROP DROP ( else, do nothing ) THEN THEN THEN ; : WALK ( c -- c, interpret key and move Soko ) DUP ASCII I = IF UP GO ELSE DUP ASCII K = IF DOWN GO ELSE DUP ASCII J = IF LEFT GO ELSE DUP ASCII L = IF RIGHT GO THEN THEN THEN THEN ; : .#### ( a -- , formatted score type) @ 0 <# # # # # #> TYPE ; : .SCORE ( update score ) 3 28 AT #BOX @ . 5 28 AT #STEP .#### 7 28 AT #PUSH .#### ; : .FRAME ( Draw screen ) CLS ." ______SokoACE_______ version 1.0" 3 22 AT ." BOXES ?" 5 22 AT ." STEPS" 7 21 AT ." PUSHES" 10 21 AT ." I Up" 11 21 AT ." K Down" 12 21 AT ." J Left" 13 21 AT ." L Right" 15 21 AT ." N Level + 1" 16 21 AT ." P Level - 1" 17 21 AT ." M Level ?" 18 21 AT ." R Restart" 20 21 AT ." Q Quit" 22 0 AT ." _by Ricardo F Lopes_ c 2006" ; : SCAN ( Scan screen map for Soko position and count boxes out of target) 0 #BOX ! ( reset number of boxes) 9920 9280 DO I C@ DUP SOKO = IF I SOKO> ! ELSE ( Search for SOKO start position) DUP BOX = IF #BOX INC ( Count Boxes out of target) THEN THEN DROP LOOP ; 20 21 * CONSTANT MAPSIZE ( Map size = 20x20 chars + 20 chars for map label line ) CREATE MAPS MAPSIZE 30 * ALLOT ( Room for 30 maps ) : MAP ( level -- a , return a map address) MAPSIZE * MAPS + ; : MAP>SCR ( level -- , copy level map to screen) MAP 22 1 DO I 0 AT DUP 20 TYPE CR 20 + LOOP DROP ; 0 VARIABLE LEVEL : INIT ( level -- , Initialize Level) 0 #STEP ! ( reset steps count ) 0 #PUSH ! ( reset pushes count ) .FRAME 0 MAX 29 MIN DUP LEVEL ! MAP>SCR SCAN ; : MAP? ( c -- c , Change level) DUP ASCII N = IF LEVEL @ 1+ INIT ELSE ( Next level) DUP ASCII P = IF LEVEL @ 1- INIT ELSE ( Previous level) DUP ASCII M = IF IN? INIT ELSE ( Entered level number) DUP ASCII R = IF LEVEL @ INIT ( Re-start same level) THEN THEN THEN THEN ; : PLAY ( Main code, run this to play SokoACE) SETGR ( initialize graphics ) 0 INIT ( start the first level ) BEGIN .SCORE ( Update Score) KEY >UPPER ( Get key pressed ) WALK ( Move SOKO ) MAP? ( Check for level request) 1 9 AT #BOX @ 0= ( No boxes left?) IF ." Done !" 100 50 BEEP 75 25 BEEP ( Level completed !) THEN ASCII Q = ( Quit?) UNTIL ." Quit." ; ( Before saving this program, populate the ) ( level slots with maps created with SokoED.) ( To do that, use: ) ( 0 MAP 0 BLOAD MAP1 ) ( 1 MAP 0 BLOAD MAP2 ) ( 2 MAP 0 BLOAD MAP3 ) ( etc..) ( Where 0, 1, 2,.. 29 are the available level numbers) ( and MAP1, MAP2, etc. are map files created with SokoED) |