sokoban levels (#1269)

Three simple (demonstration) levels plus one serious challenge, `foresight.yaml`.

![image](https://github.com/swarm-game/swarm/assets/261693/f1f298e1-13ee-4f8d-b153-8c50f5d53ba8)
This commit is contained in:
Karl Ostmo 2023-05-19 12:28:17 -07:00 committed by GitHub
parent 2487737d1d
commit 39ae4ae40d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 612 additions and 1 deletions

View File

@ -13,3 +13,4 @@ wolf-goat-cabbage.yaml
friend.yaml friend.yaml
Mazes Mazes
Ranching Ranching
Sokoban

View File

@ -0,0 +1,3 @@
foresight.yaml
Simple
Gadgets

View File

@ -0,0 +1,2 @@
no-reverse.yaml
one-way.yaml

View File

@ -0,0 +1,3 @@
Taken from this paper:
"PushPush and Push-1 are NP-hard in 2D"
https://arxiv.org/abs/cs/0007021

View File

@ -0,0 +1,82 @@
version: 1
name: No-reverse gadget
author: Karl Ostmo
description: |
Once a robot passes from left to right, they cannot return they way they came.
creative: false
seed: 0
objectives:
- goal:
- Grab the flower.
condition: |
as base {
has "flower";
};
robots:
- name: base
dir: [0, -1]
display:
attr: gold
devices:
- branch predictor
- ADT calculator
- comparator
- compass
- dictionary
- dozer blade
- grabber
- keyboard
- lambda
- logger
- scanner
- strange loop
- treads
- workbench
solution: |
move;
move;
turn left;
move;
turn right;
move;
turn left;
move;
move;
turn left;
move;
turn left;
push;
turn right;
move;
move;
turn right;
push;
turn right;
push;
turn left;
move;
move;
grab;
entities:
- name: monolith
display:
char: '@'
description:
- Pushable rock
properties: [known, unwalkable, portable]
known: [mountain, water, flower]
world:
default: [grass, water]
upperleft: [-1, 1]
offset: false
palette:
'B': [grass, null, base]
'.': [grass]
'@': [grass, monolith]
'A': [grass, mountain]
'*': [grass, flower]
map: |
BA.@.A
.A.@.*
..@.AA
A...AA

View File

@ -0,0 +1,65 @@
version: 1
name: One-way gadget
author: Karl Ostmo
description: |
Initially permits passage only from left to right.
creative: false
seed: 0
objectives:
- goal:
- Grab the flower.
condition: |
as base {
has "flower";
};
robots:
- name: base
dir: [1, 0]
display:
attr: gold
devices:
- branch predictor
- ADT calculator
- comparator
- compass
- dictionary
- dozer blade
- grabber
- keyboard
- lambda
- logger
- scanner
- strange loop
- treads
- workbench
solution: |
move;
move;
push;
turn right;
move;
move;
grab;
entities:
- name: monolith
display:
char: '@'
description:
- Pushable rock
properties: [known, unwalkable, portable]
known: [mountain, water, flower]
world:
default: [grass, water]
upperleft: [-1, 1]
offset: false
palette:
'B': [grass, null, base]
'.': [grass]
'@': [grass, monolith]
'A': [grass, mountain]
'*': [grass, flower]
map: |
AAAAAA
B..@.A
AAA.AA
AAA*AA

View File

@ -0,0 +1 @@
trapdoor.yaml

View File

@ -0,0 +1,117 @@
version: 1
name: Trapdoor 1
author: Karl Ostmo
# NOTES: There is a way to push the blocks
# so that you cannot get back the way you
# came. This is the "trap door".
# But there is one other route that will allow
# you to go back.
description: |
Bring the flower back.
creative: false
seed: 0
objectives:
- goal:
- Place the flower on the target.
- You may have to start over if you get stuck.
condition: |
as base {
teleport self (0,0);
ishere "flower";
};
robots:
- name: base
dir: [1, 0]
display:
attr: gold
devices:
- branch predictor
- ADT calculator
- comparator
- compass
- dictionary
- dozer blade
- grabber
- keyboard
- lambda
- logger
- scanner
- strange loop
- treads
- workbench
solution: |
def doN = \n. \f. if (n > 0) {f; doN (n - 1) f} {}; end;
move;
turn right;
move;
turn left;
doN 2 move;
turn left;
move;
turn right;
move;
turn left;
move;
turn right;
doN 2 move;
turn right;
push;
turn back;
move;
turn left;
doN 2 move;
turn left;
move;
turn left;
push;
turn right;
move;
turn left;
doN 3 push;
turn left;
doN 2 move;
turn right;
doN 2 move;
f <- grab;
turn back;
doN 2 move;
turn left;
doN 2 move;
turn right;
doN 3 move;
turn right;
move;
turn left;
doN 2 move;
turn left;
move;
turn right;
doN 3 move;
turn right;
move;
place f;
entities:
- name: monolith
display:
char: '@'
description:
- Pushable rock
properties: [known, unwalkable, portable]
known: [mountain, water, flower]
world:
default: [grass, water]
upperleft: [-1, 1]
offset: false
palette:
'B': [ice, null, base]
'.': [grass]
'x': [dirt]
'@': [grass, monolith]
'A': [grass, mountain]
'*': [grass, flower]
map: |
xxxAA...A..*
xBxA..@@A...
xxx..A.....A

View File

@ -0,0 +1,198 @@
def doN = \n. \f. if (n > 0) {f; doN (n - 1) f} {}; end;
def moveUntilBlocked =
isBlocked <- blocked;
if isBlocked {} {
move;
moveUntilBlocked;
}
end;
def pushUntilBarrier =
try {
push;
pushUntilBarrier;
} {}
end;
def goAroundCell =
turn right;
move;
turn left;
doN 2 move;
turn left;
end;
def repositionFromMiddle =
turn right;
move;
turn left;
move;
turn right;
moveUntilBlocked;
end;
def childShared =
goAroundCell;
moveUntilBlocked;
end;
def childSharedPrep =
move;
turn back;
watch forward;
wait 200;
end;
def childSharedWait =
childSharedPrep;
pushUntilBarrier;
end;
def firstChild =
childShared;
turn right;
childSharedWait;
doN 4 (turn left; moveUntilBlocked);
repositionFromMiddle;
turn left;
childSharedWait;
end;
def secondChild =
childShared;
doN 1 (turn left; moveUntilBlocked);
turn right;
childSharedWait;
doN 3 (turn left; moveUntilBlocked);
repositionFromMiddle;
doN 1 (turn right; moveUntilBlocked);
turn left;
childSharedWait;
end;
def thirdChild =
childShared;
doN 2 (turn left; moveUntilBlocked);
turn right;
childSharedWait;
doN 2 (turn left; moveUntilBlocked);
repositionFromMiddle;
doN 2 (turn right; moveUntilBlocked);
turn left;
childSharedWait;
end;
def fourthChild =
childShared;
doN 3 (turn left; moveUntilBlocked);
turn right;
childSharedWait;
doN 1 (turn left; moveUntilBlocked);
repositionFromMiddle;
doN 3 (turn right; moveUntilBlocked);
turn left;
childSharedWait;
end;
def fifthChild =
childShared;
doN 4 (turn left; moveUntilBlocked);
turn right;
childSharedPrep;
doN 2 push;
repositionFromMiddle;
doN 4 (turn right; moveUntilBlocked);
turn left;
childSharedWait;
turn right;
move;
turn left;
move;
turn left;
doN 3 push;
end;
def firstLeg =
build {fifthChild};
build {fourthChild};
build {thirdChild};
build {secondChild};
build {firstChild};
wait 10;
push;
turn right;
move;
turn left;
move;
turn left;
pushUntilBarrier;
wait 4;
move;
doN 5 (turn left; moveUntilBlocked);
turn right;
move;
turn left;
doN 2 move;
turn left;
doN 2 move;
turn left;
move;
turn left;
doN 3 push;
end;
def getToCaveEntrance =
moveUntilBlocked;
turn right;
move;
turn left;
move;
turn right;
move;
turn left;
doN 2 move;
turn left;
move;
turn left;
push;
turn right;
doN 2 move;
turn right;
push;
turn right;
push;
turn left;
doN 3 move;
turn left;
doN 3 move;
x <- grab;
equip x;
doN 18 move;
turn left;
doN 5 move;
turn left;
move;
turn right;
doN 10 push;
end;
def go =
getToCaveEntrance;
firstLeg;
end;
go;

View File

@ -0,0 +1,133 @@
version: 1
name: Foresight
author: Karl Ostmo
description: |
Have assistants take their marks to execute the heist.
creative: false
seed: 0
attrs:
- name: barrier
fg: "#222222"
bg: "#111111"
- name: bluish
fg: "#bbbbff"
objectives:
- goal:
- Push a monolith onto the base's initial location.
condition: |
as base {
teleport self (0,0);
ishere "monolith";
};
- teaser: Pick flower
hidden: true
optional: true
goal:
- Grab the flower
condition: |
as base {
has "flower";
};
robots:
- name: base
display:
attr: bluish
dir: [0, 1]
devices:
- branch predictor
- ADT calculator
- comparator
- compass
- dictionary
- dozer blade
- grabber
- hourglass
- keyboard
- lambda
- logger
- net
- scanner
- strange loop
- treads
- welder
inventory:
- [5, dozer blade]
- [5, ADT calculator]
- [5, branch predictor]
- [5, hourglass]
- [5, comparator]
- [5, counter]
- [5, dictionary]
- [5, grabber]
- [5, lambda]
- [5, lodestone]
- [5, logger]
- [5, net]
- [5, rolex]
- [5, scanner]
- [5, solar panel]
- [5, string]
- [5, strange loop]
- [5, treads]
solution: |
run "scenarios/Challenges/Sokoban/_foresight/solution.sw"
entities:
- name: monolith
display:
char: '@'
attr: gold
description:
- Pushable rock
properties: [known, unwalkable, portable]
- name: crate
display:
attr: wood
char: '▪'
description:
- Pushable crate
properties: [known, portable, unwalkable]
- name: wall
display:
attr: barrier
char: '#'
description:
- Unmovable barrier
properties: [known, unwalkable]
known: [mountain, water, 3D printer, flower]
world:
default: [grass, water]
upperleft: [-21, 10]
offset: false
palette:
'B': [ice, null, base]
'.': [grass]
'*': [grass, flower]
'b': [grass, boat]
'3': [grass, 3D printer]
'@': [grass, monolith]
'c': [grass, crate]
'A': [grass, wall]
'w': [dirt, water]
'x': [stone]
'z': [dirt]
map: |
..................3...A.
.................AAAA.A*
.AAAAAAAAAAAAAAAAA.A..AA
.A.................Acc..
.AA.AAAAAAAAAAAAAA.A..c.
..A.AA.AAAAAAAAAAA.AAA..
.@A.AA...........A.....A
..A.AA.AAAAAAAA.AA....AA
..A.AA.AzzzA.AA.A.......
..A.AA.Azzz..AA.A...xxx.
..A.AA.AA..A.AA.A...xBx.
..A.A.....AA.AA.AAA.xxx.
..A.AAAAA.AA.AA.A.......
..A.AAAAAAAA.AA.A.......
..A...........A.A.......
..A.AAAAAAAAAAA.A.......
..AAAAAAAAAAAAA.A.......
................A.......
.AAAAAAAAAAAAAA.A.......
.............bAAA.......

View File

@ -49,7 +49,6 @@ entities:
description: description:
- Pushable crate - Pushable crate
properties: [known, portable, unwalkable] properties: [known, portable, unwalkable]
capabilities: [push]
known: [tree, flower, boulder, water] known: [tree, flower, boulder, water]
world: world:
default: [blank] default: [blank]

View File

@ -207,6 +207,13 @@ testScenarioSolution _ci _em =
[ testSolution Default "Challenges/Ranching/capture" [ testSolution Default "Challenges/Ranching/capture"
, testSolution (Sec 30) "Challenges/Ranching/gated-paddock" , testSolution (Sec 30) "Challenges/Ranching/gated-paddock"
] ]
, testGroup
"Sokoban"
[ testSolution Default "Challenges/Sokoban/foresight.yaml"
, testSolution Default "Challenges/Sokoban/Gadgets/no-reverse.yaml"
, testSolution Default "Challenges/Sokoban/Gadgets/one-way.yaml"
, testSolution Default "Challenges/Sokoban/Simple/trapdoor.yaml"
]
] ]
, testGroup , testGroup
"Regression tests" "Regression tests"