A PuzzleScript experiment

Controls:

  • Move: arrow keys.

  • Restart: R

  • Undo: Z

  • Quit: Q or Escape.


== title Simple Block Pushing Game
== author David Skinner
== homepage www.puzzlescript.net

========
OBJECTS
========

Background
LIGHTGREEN GREEN
11111
01111
11101
11111
10111


Target
DarkBlue
.....
.000.
.0.0.
.000.
.....

Wall
BROWN DARKBROWN
00010
11111
01000
11111
00010

Player
Black Orange White Blue
.000.
.111.
22222
.333.
.3.3.

Crate
Orange Yellow
00000
0...0
0...0
0...0
00000


=======
LEGEND
=======

. = Background
# = Wall
P = Player
* = Crate
@ = Crate and Target
O = Target
Thing = Player or Wall or Crate

======
RULES
======

[ > Player | Crate ] -> [ > Player | > Crate ]
[ > Thing | no Thing ] -> [ | Thing ]
win
[ Target no Crate ] unwin

=======
LEVELS
=======

####..
#.O#..
#..###
#@P..#
#..*.#
#..###
####..


######
#....#
#.#P.#
#.*@.#
#.O@.#
#....#
######
== Based on:
== title Simple Block Pushing Game
== author David Skinner
== homepage www.puzzlescript.net

== Sasquatch levels from  https://www.sourcecode.se/sokoban/levels

========
OBJECTS
========

Background
LIGHTGREEN GREEN
1111111111
1111111111
0111111111
1111111111
1111111011
1111111111
1111111111
1111111111
1101111111
1111111111


Target
DarkBlue
.....
.000.
.0.0.
.000.
.....

Wall
BROWN DARKBROWN
00000100
00000100
11111111
01000000
01000000
01000000
11111111
00000100

Player
Black Orange White Blue
....00000000....
....00000000....
....11111111....
...1110110111...
...1110110111...
....11111111....
......1111......
...2222222222...
.22222222222222.
222..222222..222
11...222222...11
....33333333....
....33333333....
....333..333....
....000..000....
...0000..0000...


Crate
Orange Yellow
00000
0...0
0...0
0...0
00000


=======
LEGEND
=======

# = Wall
@ = Player
$ = Crate
. = Target
* = Crate and Target
Thing = Player or Wall or Crate

======
RULES
======

[ > Player | Crate ] -> [ > Player | > Crate ]
[ > Thing | no Thing ] -> [ | Thing ]
win
[ Target no Crate ] unwin

=======
LEVELS
=======

   ###
  ## # ####
 ##  ###  #
## $      #
#   @$ #  #
### $###  #
  #  #..  #
 ## ##.# ##
 #      ##
 #     ##
 #######


 ## #####
## ## . #
# ## $. #
 ## $   #
## $@ ###
# $  ##
#.. ## ##
#   # ##
##### #


           #####
          ##   #
          #    #
    ####  # $ ##
    #  ####$ $#
    #     $ $ #
   ## ## $ $ $#
   #  .#  $ $ #
   #  .#      #
##### #########
#.... @  #
#....    #
##  ######
 ####


  ###########
 ##     #  @#
### $ $$#   #
# ##$    $$ #
#  #  $ #   #
###### ######
#.. ..$ #*##
# ..    ###
#  ..#####
#########


  ###########
 ##    #    ##
### $ $#$ $ ###
# #$ $ # $ $# #
# $  ..#..  $ #
#  $...#...$  #
# $ .. * .. $ #
###### @ ######
# $ ..   .. $ #
#  $...#...$  #
# $  ..#..  $ #
# #$ $ # $ $# #
### $ $#$ $ ###
 ##    #    ##
  ###########


  ###########
###.  .$.  .###
 ## $  $  $ ##
  ## ..$.. ##
   ##$#$#$##
    #.$ $.#
    #  @  #
    ### ###
   ## $ $ ##
   #.  $  .#
   ### . ###
     #####


           ######
    ####  ##    #
  ###  #  #  ## ###
###    #### #   $ #
#  $ @ ...*..  $  #
# $ $  ## ###   ###
### ###   # #####
 #      ###
 #   ####
 #####


    #######
    #     ##
##### ###  ##
#       #  ##
#@$***. ##$ #
#  #    ## .#
##  ##  # $ #
 ##  ####.$.#
  ##        #
   ######  ##
        ####


#########
#. .    #
#.$. .  #
## ###@ #
 #  $  ##
 # $$ ##
 #  $ #
 #  ###
 ####


      ######
      #    #
      # @  ###
####  #      #
#  ####..#.#$#####
# $ $ ##...      #
#     .....#$$   #
###### ##$## #####
     #  $    #
     #### ####
       #  #
       #  #####
     ### $    #
     #  $ $   #
     # #$# ####
     #     #
     #######


  ####
###  ####
#   @   ##
# #. .#.###
# $$$ $$$ #
###.#.#.# #
 ##       #
  ####  ###
     ####


              #####
              #   #
    #####     #   #######
    #   ##### #   ..... #
##### # ##  # #     # # #
# $ $ $ $ $ # ##   ## $ #
# # ##......#### ### $$ ###
#      ## * #    # #  $$  #
##########+$$   ## #      #
         #.$ $# #  ########
         #.##   #
         ########


   #######
 ###     ##
 #   ###  #
 #      # #
###$#@  # #
#   ##### #
#   #  *. #
##$$#  *.##
 #     *..#
 #### #...##
    # #$$$ #
    #   $  #
    #####  #
        ####


 #######
##     # #
#  *.$.#
#  *.#.###
# #$@$$  #
#   ## # #
######   #
     #####


   ####
   #@ #
  ##  #
  # .$#
  #$. #
###..$###
#  ..$  #
# $ $ # #
##### # #
    #   #
    #####


  ######
 ## #  ###
## #   # ##
# #   $.# #
##  $ $.# #
# #####. ##
#     $. @#
#     $. ####
### # #*# # ###
  #### .$     #
    #  .$     #
    ## .##### #
    # #.$ $  ##
    # #.$   # #
    ## #   # ##
     ###  # ##
       ######


    ###########
   ## . . . . ###
   #  $$ $ $ $  #
   #   ######## # #####
 #### ##  $     # #   #
 #    #  $ $ #  ### # #
##  # #   ####     $  #
#...  ##### $  #### ###
#... @     $     #    #
#...############ $  $ #
#####          #####  #
                   ####


    ####
#####  #
#      #
#$ $ $ #
#.*.*.*#
#*.*.*.#
# $ $ $#
#......#
#.*.*.*#
#$ $ $ #
# $ $ $#
#$ $ $ #
#      #
#@ #####
####


#####
#   #######
#  $      ##
## ######  ##
 # #    # # ########
 # # ##    $       ##
 # #.   #@###### $  ##
 # #.#  ###    ## $  ##
 # #.    #      ## $  ##
 # #.#   #  ##   ## $  ##
## #.#  ##  ###   ## $  #
#  #.#   #  #*##   ##   #
#   .# # #  ##*##   #####
######   #  ######
     #####


     ####
     #  #
######$.#
#   $ $.#
# $@$...#
# $$$..##
#  $ ..#
########


##### ########
#   ### . $  #
#   $ *.. #$ ##
## $# ..* $  @#
 #  $ . ###   #
 ######## #####


   ##### ####
   #@ .###  ###
####  $$ $    #
#   # . . ##  #
#  $ # . . ## #
## .  $ $$  # #
 # #  ###.  # #
 # #### ##### #
 #       #    #
 ####### # ####
       # .$ #
     ####   #
     ## #####
      ###


     #######
######     ######
#  . ..$#$.. .  #
#  $ $  .  $ $  #
###$####@####$###
#  $ $  .  $ $  #
#  . ..$#$.. .  #
######     ######
     #######


        ######
        #   ##
  ####### $  #
  # $ $ $ #$ #
  #   #. $   #
 ####.#.# $###
 #   ..... #
 #  $ ..##$#
### ## ..  #
#  $.#$ # $#
#   $   #  #
##@  #  ####
 ##  ####
  ####


         #####
     #####  #####
     #  .#$   $ #
     # #. $$$ @ ##
     #  .#$   $  #
     ###.#  $ $  #
       #.  ##$ ###
 #######*###.$ #
 # $    ....####
## #$#$$....#
#  $ $   #..#
#     $  #..#
#  ##########
#####


           ####
 ###########  #
 #  $ $ $ $   ##
 #  # # # # #$##
 ##. . . . . .#
  #$# # # # #$####
###. . . . . .   #
###$# # # # # @  #
  #   $ $ $ $  ###
  #  ###########
  ####


      ########
 ######      ##########
## $     ###          ##
# $ $ ## #  #########  #
#  $  #              # #
# $ $ # #  ######### # #
#  $  #  # #. . . .  # #
# $ $ # #    . . . .## #
#  $  # # # . . . . #  #
##$ $## #  #### # #   ##
 #   #@ #       #  ####
 ######  #####  #  #
      ##     #  #  #
       #####  ##  ##
           ##    ##
            ######


       ######
       #    ###
   ##### $ $  #
####   #.#    ##
#  $ #$#.##$#####
# $$. .#.$      ##
#  $.#.#.#####  ####
##  ....... @#     #
 ####$ #.### #$###$##
  ## $  .  #  $ $ $ #
   # $ ###          #
   #   # ############
   #####


####
#  #              ####
#  ######## #######  #
#         ###  ##  $ #
##.###### ...     #. #
 #.#      # .#   # $ #
 #$$$$#$$$ #.#   ##. #
 #.# $   $ #..      ##
 #.#  $  $   # #   ##
 #  #   $$ #   #####
 #.  ##$  ######
 #.   #  $.  #
##. @ ###.#$ #
#     # #    #
#    ## ######
######


     #####
     #   #
     #   #        ######
   ###  ## #####  #    ###
   #    #        ## #$$  #
  ##$   ########## $  $  #
###  ## ..........$  #$$@#
#    # $$# ####### $     #
#   $  #...#     ###  ####
#   #   $ ### ##   ####
########    #
       #    #
       #    #
       ######


       #########
       ###    ##  ####
#####  #    * ##  #  #
#   #### ****  ####$.##
# .$      *@*      $. #
##.$####  **** ####   #
 #  #  ## *    #  #####
 ####  ##    ###
       #########


                   #####
                   #   #
           ######### $ #
    ###### #   #   #   #
    #    # # $     $ #@#
  ### ## #### ### ## ###
  #   $  $     #   #   #
  #  $  $ # #$ # $$ $$ #
 ######  $  #  #   #   #
##    ## ###############
#  .#   $ #    #
#..    #  ######
#...####  #
#....# ####
#....#
######


   #######
  ##     ##
  #  ###  #
  # ## $  ####
  # # .#   $.####
  # # * *###.$  #
  # # *#   ### #####
  # # @ * *  # #   #
  # #  ### #*#  *  #
  # ## #  * *.# # #######
  # #  #     ....$  $   #
  # # ## $# $####$      #
###*   *     #    #######
#   ########## ####
#              #
##  ############
 ####


            #####
            # ..########
            # ......#  #
            #.. ##$$  $#
         #####.##   $  #
         #  ....# $  $$#
##### ## #  .. .#$  $  #
#   #    # ##.###  $$ $###
#   ###  # ## #  $  #    #
# @   #### #  # # ###$ # #
#             #  $    $  #
#   ####      ### ####$$##
#  ##  ####     #       #
#  #      ##    ######  #
####       ##     # # $ #
            ##    # #   #
             ###### #####


 #####
 #   #
## # #####
#    ##  #######
# #     $      ####
#   #### $  $$ #  #
#####  # $$$ $ #$ #
       # $  $ $ $ ######
     ###$   #$ $  $    #
     # $ $$      ### @ ##
     #  $ $$$$####...   #
     #  $     $ #. .#...#
     ### $$$$   ......  #
       #      ##..#.....#
       ###### ##.....####
            #   .....#   #
            ##########


               #####
   ####        #   ######
   #  #        # $    $ #
   #  ####     #  $##$  ###
   #     #########  # $ $ #
   #      ..........#   $ #
 ###### ##....@###  # $$  #
 #    # #####.## # ##   $ #
 #            #  #$  $$ $ #
#### #  ##### #  #  $  #  #
#    # #      #  ###   ####
#      #  #   #    #####
#   #     #####
#####     #
    #######


  #####       #########
  #   #       #       #
### #$### ##### # # # #####
# $. .  # #    . . . .    #
# # # #$### # # # # # # #$#
#  . . . .  $ $ $ $  . .  #
###$# # #$###########$# #$#
  #  . .  ##        #  .  #
  ###$# #$####### # #$# #$###
    #  . .$ $ $ #   #  . .  #
    #$# # # # # #####$# # # #
    #  . . . . .  $  . . .  #
    ### # # # # # # # # # # #
      # $ $. . .$ $ $ $ $ $ #
      ##### # # #############
          #  @  #
          #######


                      ####
  ####         ########  #
###@ ##        #      #  #
#     #        # ### $ $ #
# ....##########   #  #..#
# . #  ## $   $ $# #  #..#
### #     $  $$$ # # $ $ #
  # ...# $  $$   # #  #  #
  #  ..# $   $ $ # # ##  #
  ##...#  $ $$ $ #$# #####
   #   ## $  $ $   # #
   ### ######  ### # ###
   # .   ## #### .   . #
  ##   . #     # #.#.# #
  #  .   # # # #   #   #
  # . ####     #########
  #  ##
  ####


   ####           #####
   #  #######  ####   #
   # @  $   ####   $  #
   #  ###.#    #  $$  #
 ###.## $ #$ #    #  ##
 #  ..# $ ...# ###  ##
 # $ ...$##.##     ##
 ##.###$ $..   $$ ##
  #.  #. .### $ $ #
  #  $...## ## #  #
 ## ######   #   ##
##   ##      #####
# $$  #
#   $ #
### $ #
  #  ##
  ####


     #######
#### #     #
#  ### $$$ #
#  ....$  #####
#  ..# $  #  @#
###$##$#### # ######
 #.*....$  $  ###  #####
 # ..#####  ##   $ $   #
 #....*.... #  $$  # $ #
 ########## #$$ ## #   #
    # $.###        $  ##
    #       $###$# #  #
    #####   $    $ ####
        ####    ####
           ######


   #####
   #   #
 ###   ########
##  ***    # # #
 #  * *    ## # #####
##  ***   ## # ##   ##
 ###   #### # # #   #
   #   # # # ####$ $###
  ##   ## # ##  $...$ ##
   ##### # ##    .@.  #
        # # #   $...$ ##
         ########$ $###
                #   #
                #####


####
#  ######
#       ####
# $ $   #  #####
##### ###    $ #
 #  #   $  #   #
 #      ##$######
 # $###  # ...# #
 ## #@#$ ##.#.# #
 #    #   #...# #
 # $ ##$ $#...#####
 ### ##   #...    #
  #  #  $ $ $ # # #
  # $### ###### # #
  #             # #
  #############   #
              #####


   ####
  ##  #############
 ##    .......... #
##    #  ####$### ##
#      # #      #  ##
#     #  # $$$  # # #####
#####  # . .# ### . . . ##
    #   $. .#  # $$ $ $ @#
   ####### ### #   #######
   # $   $   # ## ###
   #    $  $ #  # ## # ####
   # $### ####  # # # ##  ####
   #  $ $$$  # ## #  ##      #
   ##        # ## #### $$$   #
    ## ####### .....     #####
    #  $         ######  #
    #   ######  ##    ####
    #####    ####


 #############
##       #   ###
#  $ $$$$$     #
### $   $  ### #
  # $ $ $### # #
  ##   $ ##  # ###
   ####   ####   #
     ###       # ###
   ####   ####     #
   #@ $   ###  #.# #####
   # $ $ ## #  ....    #
   # $$ ##  ####.....  #
  ## $  #     #..#.##  #
  # $ $ ##    #......  #
  #  $ $ #    # . ..# ##
  ##  $  #    ## ##.# #
   #    ##     #      #
   ######      ########


  ####      ########
  #  ##### ##   #  #
  #    $ ### $  $  #
  #  $ # ##    $   ####
  ###  #    # ###$##  #
#####  ###  ####   $  #
#   # $  $$## .. ##$  #
#  $$   # $          ##
##  # $##  #### # ####
### #  ##$ ###..#..#
#   ###..  #  .....###
#   #  *.### #  #..  #
##$$#  *.##@ #  #    #
 #     *. ####  ###  #
 ######   #  #       #
      #####  ##    ###
              #  ###
              ####


      #### ###################
  #####  ###            .$   #
###  $.       #####$####   # #
#    $.  #### #     .   ### .#
#  $ $.### ## # #### #  $.# $#
###  $.## # # # #  #  # $ #  #
  ###### # ## #$ $ ##   #. # #
        ##### #.#.  #  ### # #
 #####  #   # ### ###   #    #
 ##*##  #     .#  #   #$$*  ##
 #*### ### ## ## ## #  .#. ##
 ###*# #  .$ .# $.$.## ### #
 ##*## # #.####     # $.   ##
 #*### # $$   ### ###   ##  ##
 ###*# # #   . $@$  #######. #
 ##### # ### ####.#        $ #
       #     #  ###########  #
       #######            ####


#########
#       #    ######
#   $   ######    ###
# #$#$ $ $  # $     #
# $   $@$  $ $ $ $$ #
# $ $# $ #     $$$  #
#  $ $ #######   #####
##    ###....##### ..#
 ###$$# $$$$ #...* ..#
  #         ##   #.. #
  #  #  #$###....##*##
  #   ##..$. ....    #
  ### .*   .#....#   #
    ##################


   #### ####
  ##  # #  #  #######
###   ###$ ## #     ###
#  $      $ ###       #
# $ $ ###$   #  #     #
### ### #    #   #    #
#  $ #  ## ###    # ###
#    $   # #@        ##
# $# # ### ###   #   #
#  $ # # $ $ #  #  # #
##   #    $  # #.    #
 ##  # #   ## #..  ###
  ## # #  ## #... ##
 ### # #### #....##
 #          $.*.##
 ############..##
            ####


#########################
#  #  #  #  #  #  #  #  #
# $#$ # $#$ # $#$ # $#$ #
#  #  #  #  #  #  #  #  #
## # ### # ### # ### # ##
#  #  #  #  #  #  #  #  #
#     #     #     #     #
# ### # ### # ### # ### #
#  #  #  #  #  #  #  #  #
#  #     #  $  #     #  #
#  # ### # ### # ### #  #
#  . . .  . + .  . . .  #
#########################


  # # # # # # # # # # # #
 # # # # # # # # # # # # #
#   .$    . $.  . $   .$  #
 # $# #$# # # #$# # # #  #
#  .  .    $.  .  .$ .  . #
 # #$# # # # #$#$ $# #$# #
# .     .$ .$    . $.  .  #
 # $# # # # #@# # # # #$ #
#  .  .$ .    $. $.     . #
 # #$# #$ $#$# # # # #$# #
# .  . $.  .  .$    .  .  #
 #  # # # #$# # # #$# #$ #
#  $.   $ .  .$ .    $.   #
 # # # # # # # # # # # # #
  # # # # # # # # # # # #
== title Match 3 Block Push
== author Stephen Lavelle
== homepage www.puzzlescript.net

========
OBJECTS
========

Background
LIGHTGREEN GREEN
11111
01111
11101
11111
10111


Target
DarkBlue
.....
.000.
.0.0.
.000.
.....

Wall
BROWN DARKBROWN
00010
11111
01000
11111
00010

Player
Black Orange White Blue
.000.
.111.
22222
.333.
.3.3.

Crate
Orange Yellow
00000
0...0
0...0
0...0
00000


=======
LEGEND
=======

. = Background
# = Wall
P = Player
* = Crate
@ = Crate and Target
O = Target
Solid = Player or Wall or Crate

======
RULES
======

[ >  Player | Crate ] -> [  >  Player | > Crate  ]
[ > Solid | stationary solid ] -> [ Solid | Solid ]
[ > Solid | ] -> [ | Solid ]
[ Crate | Crate | Crate ] -> [ | | ]
win
[ Crate no Target ] unwin

=======
LEVELS
=======

#########
#.......#
#.*.*.@.#
#.P...O.#
#...*.*.#
#.......#
#########

.#######.
.#.....#.
.#O##..##
##.##.*.#
#.*..**.#
#.OOO.#.#
#.P.....#
#########
== title Block Faker
== author Droqen
== homepage www.droqen.com
== https://droqen.itch.io/block-faker

== require_player_movement
== key_repeat_interval 0.12

== background_color white
== text_color black

== color_palette c64

========
OBJECTS
========

Background
White

Grille
gray
0...0
.0.0.
..0..
.0.0.
0...0

EndPoint
Green

Player
Black
00000
00000
0.0.0
00000
00000

Wall
Gray

WallBlock
Black Grey
01111
01111
01111
01111
00001

BlueBlock
Blue
00000
00.00
0.0.0
00.00
00000

GreenBlock
LightGreen
00000
00000
00.00
00000
00000

PinkBlock
Red
00000
00.00
0...0
00.00
00000

PurpleBlock
Purple
00000
0...0
0.0.0
0...0
00000

OrangeBlock
Orange
00000
0.0.0
00000
0.0.0
00000


=======
LEGEND
=======

Block = PinkBlock or BlueBlock or PurpleBlock or OrangeBlock or GreenBlock
Moveable = Player or Block
Immovable = Wall or WallBlock

. = Background
# = Wall
@ = WallBlock
P = Player
B = BlueBlock
G = GreenBLock
K = PinkBlock
R = PurpleBlock
O = OrangeBlock
E = EndPoint
x = Grille
H = Grille and Player


== Player, Wall, WallBlock, PinkBlock, BlueBlock, PurpleBlock, OrangeBlock, GreenBlock

======
RULES
======

[ >  Moveable | Moveable ] -> [ > Moveable | > Moveable ]
[ > Block | Grille ] -> [ Block | Grille ]

[ > Moveable | Immovable ] -> [ Moveable | Immovable ]

[ > Moveable | no Moveable ] -> [ | Moveable ]

[ PinkBlock | PinkBlock | PinkBlock ] -> [ | | ]
[ BlueBlock | BlueBlock | BlueBlock ] -> [ | | ]
[ PurpleBlock | PurpleBlock | PurpleBlock ] -> [ | | ]
[ OrangeBlock | OrangeBlock | OrangeBlock ] -> [ | | ]
[ GreenBlock | GreenBlock | GreenBlock ] -> [ | | ]

[ player endpoint ] win

=======
LEVELS
=======

........########
################
########@@@@@###
####@@@@@...@###
###@..OO....@@##
##@..@@@@@....@#
##@.@..@@@..E@@#
#@..@.O...@@@@##
##@...@.P.######
####@.@@@@######
####@@##########
########........



##########
####R.R###
#x....#x##
#xO#O.OxE#
#xx##.#xx#
#####R####
#####P####
O#########



......#######...
.....##P.#####..
....###....####.
..#####O...#B..#
..#####.#.##BB.#
##EBB..O.O.....#
..#####.#.#....#
..######..#G.###
....####..#.OOx.
.....###.GG.#x..
......#######...


######xx######
######GG######
##xx#...#xEx##
##..O...#x..##
##..#...##O###
#..##.......##
xG....##....Gx
xG....##....Gx
##.......GG###
###G##...#xx##
##x..#...O.x##
##.P.#...#xx##
######GG######
######xx######



......##......
....######....
..##########..
..#.OG..kk.#..
.##OPO..Gkk##.
.##GOG..GGk##.
###...##...###
###...##...###
.##kkG##ROR##.
.##Gkk..OEO##.
..#.Gk..RO.#..
..##########..
....######....
......##......
== Based on:
== title Iterated Extended Rigid Body Test
== author Scott Hughes

=======
OBJECTS
=======

Background
white

Player
pink

Player2
pink

Box1
red

Box2
green

Wall
grey

Register
grey

======
LEGEND
======

. = Background
@ = Player
! = Player2
1 = Box1
2 = Box2
# = Wall
$ = Register

Box = Box1 or Box2
Thing = Box or Player or Player2

=====
RULES
=====

[ moving Player ] [ Register ] -> [ moving Player ] [ moving Register ]
[ > Player | Box ] -> [ > Player | > Box ]

[ moving Box1 | Box1 ] -> [ moving Box1 | moving Box1 ]
[ moving Box2 | Box2 ] -> [ moving Box2 | moving Box2 ]
[ > Box | Box ] -> [ > Box | > Box ]

[ moving Box1 | Box1 ] -> [ moving Box1 | moving Box1 ]
[ moving Box2 | Box2 ] -> [ moving Box2 | moving Box2 ]

[ > Thing | Wall ] -> [ Thing | Wall Halt ]

[ Halt ] [ moving Thing ] -> [ Halt ] [ Thing ]
[ Halt ] -> [ ]

[ > Thing | no Thing ] -> [ | Thing ]

[ > Register ] [ Player2 ] -> [ > Register ] [ > Player2 ]
[ > Player2 | Box ] -> [ > Player2 | > Box ]

[ moving Box1 | Box1 ] -> [ moving Box1 | moving Box1 ]
[ moving Box2 | Box2 ] -> [ moving Box2 | moving Box2 ]
[ > Box | Box ] -> [ > Box | > Box ]

[ moving Box1 | Box1 ] -> [ moving Box1 | moving Box1 ]
[ moving Box2 | Box2 ] -> [ moving Box2 | moving Box2 ]

[ > Thing | Wall ] -> [ Thing | Wall Halt ]

[ Halt ] [ moving Thing ] -> [ Halt ] [ Thing ]
[ Halt ] -> [ ]

[ > Thing | no Thing ] -> [ | Thing ]

======
LEVELS
======

###########
#....#....#
#.2..#....#
#.2..#.11.#
#....#..#.#
#....#.2..#
#.111#.22.#
##1..#..2.#
#....#....#
#.!..#..@.#
#....#...##
#....#....#
$##########

PuzzleScript is a game engine that gets incredible mileage from a simple two-dimensional search-and-replace operation. We build a crude clone that pushes its core concept further:

  • Instead of a move phase, we use ordinary patterns to describe movement.

  • This obivates the need for the late keyword, as we have full control over when movement occurs.

  • We can do without the collisionlayer section because we bring our own collision rules.

  • Instead of the dedicated wincondition sublanguage, we use ordinary patterns to describe them by making the win action set a flag indicating victory and an unwin action that clears this flag. (Perhaps win could take an integer argument describing the number of levels to skip, which would allow level branching.)

Controlling movements with ordinary rules allows extended rigid bodies and extended movements. For the latter, to jump exactly 4 tiles in the air, we can place a hidden object 4 tiles away from an obstacle. A rule starts the object moving when the player does, and another rule stops the player when the object does.

Converting PuzzleScript

Our simplistic parser is fussy. A comment is a line starting with an equals sign. Block comments are unsupported.

Whitespace is significant. Tokens in the rules section must be separated by at least one space.

There is no support for the prelude. Comment each of these lines. Also, messages are unimplemented; comment them out.

The order of the OBJECTS matters. The first object is always drawn; it acts as the default background. Later objects are drawn on top of earlier objects if both are present in the same square.

Sprites can be bigger or smaller than 5x5, but ought to be square.

Remove the SOUNDS section. The prototype lacks support for sounds.

Remove the COLLISIONLAYERS section. For each layer that matters to the game, define a new entry in the LEGEND section, replacing each comma with or.

Replace the WINCONDITIONS with rules in the RULES section.

Only 4 sections should remain: OBJECTS LEGEND RULES LEVELS.

Basic Example

The basic example contains the COLLISIONLAYERS:

Background
Target
Player, Wall, Crate

We add a LEGEND entry for the last of the layers. It’s the only one that affects gameplay, so we throw the rest away:

Thing = Player or Wall or Crate

We add a corresponding moving rule. A Thing moves if its destination contains no Thing:

[ > Thing | no Thing ] -> [ | Thing ]

We translate the win condition:

All Target on Crate

to the following rules:

win
[ Target no Crate ] unwin

In other words, we set the victory flag, but then unset it if we find a Target with no Crate on it.

To summarize, after the conversion, we have these rules:

[ > Player | Crate ] -> [ > Player | > Crate ]
[ > Thing | no Thing ] -> [ | Thing ]
win
[ Target no Crate ] unwin

Implementation

For a while, I’ve been seeking an excuse to use Gaussian integers to index a 2D grid. More recently, I’ve been seeking for tests for my Haskell compiler. PuzzleScript appeared on my radar at a perfect time!

My compiler worked well enough (amazingly, I only ran into one bug), though the generated code is slow.

The engine compiles in GHC with this wrapper:

{-# LANGUAGE CPP, BlockArguments, LambdaCase, TupleSections #-}
import Data.Char (chr, ord)
import Data.Foldable (asum)
import Control.Applicative (Alternative(..), liftA2)
import Data.Map ((!), Map, fromList, toAscList, insert)
import qualified Data.Map as M
mlookup = M.lookup

#define Ring Num
#include "zfc.hs"

[+] Show engine

The web frontend code mostly coordinates calls between JavaScript and wasm, though there is some code involving drawing sprites.

[+] Show web frontend


Ben Lynn blynn@cs.stanford.edu 💡