 


Task

Implement the Fifteen Puzzle Game.



The   15-puzzle   is also known as:

   Fifteen Puzzle
   Gem Puzzle
   Boss Puzzle
   Game of Fifteen
   Mystic Square
   14-15 Puzzle
   and some others.


Related Tasks

   15 Puzzle Solver
   16 Puzzle Game


 
( moves: 0 - up, 1 - down, 2 - left, 3 - right )
 
[ stack ]                            is 15.solver ( --> [ )
 
[ 0 swap find ]                      is find-empty ( board --> n )
 
[ over + dup -1 >
  over 4 < and iff
  [ nip true ] else
  [ drop false ] ] is try-nudge ( coord delta --> coord ? )
 
[ dip [ dup find-empty 4 /mod ]
  2 /mod 2 * 1 -
  swap iff try-nudge else
  [ dip swap
    try-nudge
    dip swap ]
  dip [ swap 4 * + ] ]               is try-move-target ( board move --> board target ? )
 
[ 2dup peek dip
  [ -1 unrot poke
    0 over find ]
  unrot poke
  0 swap -1 over find poke ]         is move-to ( board target --> board )
 
[ try-move-target
  iff [ move-to true ]
  else [ drop false ] ]              is try-move ( board move --> board ? )
 
[ [] 15 times
  [ i^ 1+ join ]
  0 join ]                  constant is <board> ( --> board )
 
[ <board>
  410 times ( 2 * the upper bound on the maximum moves required to solve )
  [ 4 random
    try-move drop ] ]                is <random-board> ( --> board )
 
[ peek dup iff
  [ number$
    dup size 1 =
    if [ space swap join ] ]
  else [ drop $ '  ' ]
  echo$ ]                            is echo-cell ( board n --> )
 
[ 4 * 4 times
  [ say '| '
    2dup i^ +
    echo-cell
    say ' ' ]
  say '|'
  2drop ]                            is echo-row ( board n --> )
 
[ 4 times
  [ say '+----+----+----+----+' cr
    dup i^ echo-row cr ]
  say '+----+----+----+----+' cr
  drop ]                             is echo-board ( board --> )
 
[ <board> = ]                        is solved? ( board --> ? )
 
[ $ 'Moves: ' input ]                is input-moves ( --> $ )
 
[ dup char w = iff
  [ drop 0 true ] done
  dup char s = iff
  [ drop 1 true ] done
  dup char a = iff
  [ drop 2 true ] done
  dup char d = iff
  [ drop 3 true ] done
  false ]                            is char-to-move ( c --> move true | c false )
 
[ input-moves witheach
  [ char-to-move
    if try-move
    drop ] ]                         is player-move ( board --> board )
 
[ ]'[ 15.solver put
  [ cr dup echo-board
    dup solved? not while
    15.solver share do
    again ]
  15.solver release drop ]           is 15-solve-with ( board 'solver --> board )
 
[ <random-board>
  15-solve-with player-move ]        is 15-puzzle ( --> )
 
15-puzzle
 