Skip to content

Instantly share code, notes, and snippets.

@inclement
Last active June 4, 2025 22:34
Show Gist options
  • Select an option

  • Save inclement/458ac36579dda092d8760585f08da80c to your computer and use it in GitHub Desktop.

Select an option

Save inclement/458ac36579dda092d8760585f08da80c to your computer and use it in GitHub Desktop.
History of the Velsokomagnet (PuzzleScript Script)
Play this game by pasting the script in http://www.puzzlescript.net/editor.html
title History of the Velsokomagnet
author inclement
homepage https://inclem.net/
require_player_movement
key_repeat_interval 0.1
again_interval 0.04
run_rules_on_level_start
========
OBJECTS
========
Nothing
black
Background
#eeeeee #eeeeee
01000
01000
10011
00100
01000
Target
#c9c9c9 #eeeeee green
01010
10001
00200
10001
01010
PlayerTarget
#c9c9c9 darkgreen green
.0.0.
00000
.020.
00000
.0.0.
Wall
#a59aa5 #bb77bb
00000
00000
00000
00000
00000
WallBase
#a59aa5 #bb77bb #aa9daa
00000
00000
00000
00000
11111
Player
#0055ee #0044dd
.0.0.
01110
.101.
01110
.0.0.
Crate
#ee8822 #dd7711
0.0.0
.111.
00000
.111.
0.0.0
PlayerCrateRightMarker
#ee8822
....0
.....
....0
.....
....0
PlayerCrateAboveMarker
#ee8822
0.0.0
.....
.....
.....
.....
PlayerCrateLeftMarker
#ee8822
0....
.....
0....
.....
0....
PlayerCrateBelowMarker
#ee8822
.....
.....
.....
.....
0.0.0
CratePlayerRightMarker
#0055ee
.....
....0
.....
....0
.....
CratePlayerAboveMarker
#0055ee
.0.0.
.....
.....
.....
.....
CratePlayerLeftMarker
#0055ee
.....
0....
.....
0....
.....
CratePlayerBelowMarker
#0055ee
.....
.....
.....
.....
.0.0.
MovedCrateMarker
pink
00000
0...0
0...0
0...0
00000
CrateOnTargetMarker
lightgreen
.....
.....
..0..
.....
.....
PlayerOnTargetMarker
lightgreen
.....
.....
..0..
.....
.....
MovedPlayerMarker
red
JustMovedPlayerMarker
transparent
IntroCrate
#ee8822 #dd7711
.000.
01110
00000
01110
.000.
IntroCrateTarget
#c9c9c9 #eeeeee green
10001
00000
00200
00000
10001
IntroPlayerTarget
#c9c9c9 #eeeeee green
11111
11111
11211
11111
11111
IntroPlayerVisualMask
#0055ee #0044dd
00.00
0...0
.....
0...0
00.00
IntroPlayerTargetVisualMask
#c9c9c9
00.00
0...0
.....
0...0
00.00
VerticalForceMarker
#aaaaff
..0..
..0..
..0..
..0..
..0..
HorizontalForceMarker
#aaaaff
.....
.....
00000
.....
.....
=======
LEGEND
=======
. = Background
# = Wall
P = Player
* = Crate
@ = Crate and Target
O = Target
x = PlayerTarget
q = Player and PlayerTarget
z = Crate and PlayerTarget
N = Nothing
i = IntroCrate
j = IntroCrateTarget
=======
SOUNDS
=======
================
COLLISIONLAYERS
================
Background
Nothing
Target, PlayerTarget, IntroCrateTarget, IntroPlayerTarget
IntroPlayerTargetVisualMask
PlayerCrateRightMarker
PlayerCrateLeftMarker
PlayerCrateAboveMarker
PlayerCrateBelowMarker
CratePlayerRightMarker
CratePlayerAboveMarker
CratePlayerLeftMarker
CratePlayerBelowMarker
(Note these are the only actual physics objects for which we care about collision,
everything else is for game logic or prettiness)
Player, Wall, Crate, IntroCrate
WallBase ( Note WallBase drawn on top of Wall as it's just decoration )
MovedPlayerMarker
MovedCrateMarker
JustMovedPlayerMarker
IntroPlayerVisualMask
CrateOnTargetMarker, PlayerOnTargetMarker
HorizontalForceMarker
VerticalForceMarker
======
RULES
======
( Normal sokoban rules for the introductory level only. )
[ > Player | IntroCrate ] -> [ > Player | > IntroCrate ]
late [IntroCrate IntroCrateTarget no CrateOnTargetMarker] -> [IntroCrate IntroCrateTarget CrateOnTargetMarker ]
late [IntroCrate IntroCrateTarget no CrateOnTargetMarker] -> [IntroCrate IntroCrateTarget CrateOnTargetMarker ]
late [Player no IntroPlayerVisualMask] [IntroCrateTarget] -> [Player IntroPlayerVisualMask] [IntroCrateTarget]
late [IntroPlayerVisualMask no Player] -> [ ]
late [PlayerTarget no IntroPlayerTargetVisualMask] [IntroCrateTarget] -> [PlayerTarget IntroPlayerTargetVisualMask] [IntroCrateTarget]
( Velsokomagnet rules for other levels:)
(The player pushes crates when moving directly into them. Pushed crates
are marked with a MovedCrateMarker because we want to distinguish
crates the player directly pushed this way from those pushed from afar.)
[ > Player | Crate ] -> [ > Player | > Crate > MovedCrateMarker ]
[ ^ Player | Crate ] -> [ ^ Player | ^ Crate ^ MovedCrateMarker ]
[ < Player | Crate ] -> [ < Player | < Crate < MovedCrateMarker ]
[ v Player | Crate ] -> [ v Player | v Crate v MovedCrateMarker ]
(Crates can push other crates, but if the player is trying to directly
push a crate into a blockage then cancel the move. Note we can't just
rely on the collision layer logic because we're adding in rigid-body
logic for a Player that is velcroed to any crates; without these rules
the Player could move along the side of several adjacent crates against
a blockage)
[ > Crate | Crate ] -> [ > Crate | > Crate ]
(The following works because we only have up to 4 crates in a level.
This could be done in a maybe-better way using more objects carrying
collision logic, but doesn't seem worth worrying about given this is
simple enough.)
[ > MovedCrateMarker | Crate | Crate | Crate | Crate | Wall ] -> cancel
[ > MovedCrateMarker | Crate | Crate | Crate | Wall ] -> cancel
[ > MovedCrateMarker | Crate | Crate | Wall ] -> cancel
[ > MovedCrateMarker | Crate | Wall ] -> cancel
[ > MovedCrateMarker | Wall ] -> cancel
(We could run the repulsion logic in a single pass, but we use "again"
so that we can have a brief marker when the repulsion has been applied.
This hopefully reminds the player of the effect.)
[ > Player | ] -> [ > Player | JustMovedPlayerMarker ] again
(The Player will only be on top of a JustMovedPlayerMarker in the "again"
pass. These rules apply repulsion in that pass.)
[ Player JustMovedPlayerMarker | Crate ] -> [Player JustMovedPlayerMarker | Crate MovedCrateMarker ]
[ Player JustMovedPlayerMarker | ... | Crate no MovedCrateMarker ] -> [ Player JustMovedPlayerMarker | ... | > Crate ]
[Player JustMovedPlayerMarker] -> [Player]
(If any JustMovedPlayerMarker is present then we're in the first pass, so
draw repulsion lines to mark the logic being applied.)
horizontal [Crate no MovedCrateMarker |...| no HorizontalForceMarker |...| JustMovedPlayerMarker] -> [Crate |...| HorizontalForceMarker | ... | JustMovedPlayerMarker]
vertical [Crate no MovedCrateMarker| ... |no VerticalForceMarker|...| JustMovedPlayerMarker] -> [Crate |...| VerticalForceMarker | ... | JustMovedPlayerMarker]
(If we're drawing any nice markers for being velcroed, move these with the player.)
[> Player PlayerCrateRightMarker ] -> [> Player > PlayerCrateRightMarker ]
[> Player PlayerCrateLeftMarker ] -> [> Player > PlayerCrateLeftMarker ]
[> Player PlayerCrateAboveMarker ] -> [> Player > PlayerCrateAboveMarker ]
[> Player PlayerCrateBelowMarker ] -> [> Player > PlayerCrateBelowMarker ]
[> Crate CratePlayerRightMarker ] -> [> Crate > CratePlayerRightMarker ]
[> Crate CratePlayerLeftMarker ] -> [> Crate > CratePlayerLeftMarker ]
[> Crate CratePlayerAboveMarker ] -> [> Crate > CratePlayerAboveMarker ]
[> Crate CratePlayerBelowMarker ] -> [> Crate > CratePlayerBelowMarker ]
(If we have finished in the "again" pass, we can now remove the force markers.
Note because this is a "late" rule the player will have moved on top of
the marker on the first pass through.)
late [Player no JustMovedPlayerMarker] [HorizontalForceMarker] -> [Player] []
late [Player no JustMovedPlayerMarker] [VerticalForceMarker] -> [Player] []
(Clear up logic helper markers)
late [ MovedCrateMarker ] -> [ ]
(Draw an indicator when crates or the player are on their respective targets )
late [Player PlayerTarget no PlayerOnTargetMarker] -> [Player PlayerTarget PlayerOnTargetMarker]
late [PlayerOnTargetMarker no Player] -> [ ]
late [Crate Target no CrateOnTargetMarker] -> [Crate Target CrateOnTargetMarker]
late [CrateOnTargetMarker no Crate no IntroCrate] -> [ ]
(Draw cosmetic markers on some walls for visual variety)
late DOWN [ Wall | no Wall ] -> [WallBase Wall | ]
late Down [ WallBase | Wall ] -> [ | Wall ]
(If we're next to a crate but haven't yet drawn a cosmetic marker,
do that now)
late RIGHT [ Player no PlayerCrateRightMarker | Crate ] -> [ Player PlayerCrateRightMarker | Crate CratePlayerLeftMarker]
late UP [ Player no PlayerCrateAboveMarker | Crate ] -> [ Player PlayerCrateAboveMarker | Crate CratePlayerBelowMarker]
late LEFT [ Player no PlayerCrateLeftMarker | Crate ] -> [ Player PlayerCrateLeftMarker | Crate CratePlayerRightMarker ]
late DOWN [ Player no PlayerCrateBelowMarker | Crate ] -> [ Player PlayerCrateBelowMarker | Crate CratePlayerAboveMarker ]
==============
WINCONDITIONS
==============
(Note these are specified so as to work also in the intro level that has no Crates)
all Target on Crate
all Player on PlayerTarget
all IntroCrateTarget on IntroCrate
(Make sure win conditions only trigger at the end of the "again" pass)
no JustMovedPlayerMarker
=======
LEVELS
=======
(Normal sokoban introduction)
message (1 / 12) The original sokoban was invented when a global surplus of crates and targets necessitated a new form of warehouse management. PUSH the free crate to its target location.
nnnnn#####nnn
nnnnn#iii#nnn
######i..#nnn
####i....#nnn
#i.....#.#nnn
#ip.#i.#.###n
#i.....#.i##n
########.i##n
nnnn#.....i#n
nnnn#.j...x#n
nnnn#iii.###n
nnnn########n
message (2 / 12) Later advances in materials science introduced the sokomagnetic force that repelled the crates...
message (2 / 12) ...also the warehouse contents were covered in velcro for storage convenience, after an unfortunate incident involving the lead engineer's car keys.
message (2 / 12) The player now REPELS all crates with the same row or column...unless they're adjacent in which case it STICKS to them forever. Press "R" to restart if necessary.
(Basic introduction)
nnnnn#####nnn
nnnnn#...#nnn
######...#nnn
####.....#nnn
#......#.#nnn
#.p.#*.#.###n
#......#..##n
########..##n
nnnn#......#n
nnnn#.o...x#n
nnnn#....###n
nnnn########n
message (3 / 12) The resulting entity became known as...the VELSOKOMAGNET.
(Easy 3)
###########
#.........#
#.........#
#..*......#
#...o...x.#
#....o....#
#.....*.#.#
#.........#
#..p......#
###########
message (4 / 12) The velsokomagnet quickly became popular. Crate manipulation was easier than ever!
(Easy 2)
##########
#........#
#..#.....#
#..z..o..#
#.....#..#
#..*.....#
#..#.....#
#p.......#
###.o.####
###...####
##########
message (5 / 12) Using the velcro was considered quite gauche, but was not unknown.
(Velcro easy introduction)
nnnn#####nn
nnnn#...#nn
#####.#.#nn
###.#.#.#nn
##.o.*..#nn
#.ox#.#.###
##.......##
#.p###.#.##
#.#..*....#
#.........#
######.#..#
nnnnn#...##
nnnnn######
message (6 / 12) Still, the most high-profile designers generally felt the sokomagnetic interaction was more stimulating to the intellect.
(Easy 1)
##########
#p.....###
#........#
#.#*.#...#
#x#.O.#..#
#....*...#
#..#.#...#
#.O....#.#
##########
message (7 / 12) Attitudes steadily changed until the velcro was often a key part of the solution.
(Velcro easy 2)
nnn###########nnn
nnn####...####nnn
nnn#.........#nnn
####.........####
#..o....***...o.#
####.......p.####
nnn#....o....#nnn
nnn#####x#####nnn
nnn###########nnn
message (8 / 12) During its heights, the velsokomagnet's popularity eclipsed more traditional warehouse variants.
(Velcro easy 1)
nnnnn#######n
nnnnn#.....#n
nnnnn#.....#n
#######..#.#n
#.......*..#n
#...##..#..#n
#......###.##
####...###.o#
nnn#...###.x#
nnn#.*..##.##
nnn#.....#.#n
nnn#....p.o#n
nnn####....#n
nnnnnn###..#n
nnnnnnnn####n
message (9 / 12) For instance, the next warehouses are a duet of puzzles produced as part of Queen Elizabeth's Ruby Jubilee.
(Easy 4)
#########nnnnnn
##.....##nnnnnn
##.#...########
##......#.....#
##..#*..#...x.#
##............#
#.....*.......#
#.......#.....#
#.......#.opo.#
#.......#.....#
###############
message (10 / 12) The eventual downfall of the velsokomagnet was not due to disinterest, but economics.
(Easy 5)
#########nnnnnn
##.....##nnnnnn
##...#.##nnnnnn
##.#*..########
##......#.....#
##..#*..#...x.#
##............#
#.....*.......#
#.......#...o.#
#.......#.opo.#
#.......#.....#
###############
message (11 / 12) The materials used to create stable sokomagnetic monopoles became more valuable in other industries, making velsokomagnetic warehouses expensive to maintain.
(Medium? 1)
(I "fixed" an intended-logic break with the upper-left counter crate, but that's a bit
rubbish as nobody likes counters :< )
nnnnnnn######nn
########...##nn
#.o...*#.#.##nn
########.#..#nn
nnn##o##..#.###
nnn#o..x*#...##
nnn###o#......#
nnn###.#..*.#.#
nnn#.......##.#
nnn#...*..###.#
nnn#..p..####.#
nnn##...#####.#
nnn############
message (12 / 12) In the end velsokomagnetic warehouses were financially unsustainable. Public interest moved on, and the velsokomagnet is now mostly confined to the annals of history.
message (12 / 12) This last example was the winner of a public competition, demonstrated last year at the world warehouse design expo using one of the last remaining velsokomagnets.
(Medium 1 - not fully tested for simpler solutions )
###########
#.....p...#
#.o#..###.#
#.........#
#..#..#.#.#
#...#..*..#
##.....#..#
n#.#.*..#.#
n#..#.....#
n#..#*...x#
n#..o....o#
n#.o....#.#
n#....###*#
n##########
message That concludes this history of the velsokomagnetic era in sokoban warehouse arrangement. Any questions?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment