diff --git a/data/scenarios/Challenges/00-ORDER.txt b/data/scenarios/Challenges/00-ORDER.txt index 960f1498..51802de5 100644 --- a/data/scenarios/Challenges/00-ORDER.txt +++ b/data/scenarios/Challenges/00-ORDER.txt @@ -13,3 +13,4 @@ wolf-goat-cabbage.yaml friend.yaml Mazes Ranching +Sokoban diff --git a/data/scenarios/Challenges/Sokoban/00-ORDER.txt b/data/scenarios/Challenges/Sokoban/00-ORDER.txt new file mode 100644 index 00000000..beda0875 --- /dev/null +++ b/data/scenarios/Challenges/Sokoban/00-ORDER.txt @@ -0,0 +1,3 @@ +foresight.yaml +Simple +Gadgets diff --git a/data/scenarios/Challenges/Sokoban/Gadgets/00-ORDER.txt b/data/scenarios/Challenges/Sokoban/Gadgets/00-ORDER.txt new file mode 100644 index 00000000..5b501c91 --- /dev/null +++ b/data/scenarios/Challenges/Sokoban/Gadgets/00-ORDER.txt @@ -0,0 +1,2 @@ +no-reverse.yaml +one-way.yaml \ No newline at end of file diff --git a/data/scenarios/Challenges/Sokoban/Gadgets/README.md b/data/scenarios/Challenges/Sokoban/Gadgets/README.md new file mode 100644 index 00000000..4aef8471 --- /dev/null +++ b/data/scenarios/Challenges/Sokoban/Gadgets/README.md @@ -0,0 +1,3 @@ +Taken from this paper: +"PushPush and Push-1 are NP-hard in 2D" +https://arxiv.org/abs/cs/0007021 diff --git a/data/scenarios/Challenges/Sokoban/Gadgets/no-reverse.yaml b/data/scenarios/Challenges/Sokoban/Gadgets/no-reverse.yaml new file mode 100644 index 00000000..24440b62 --- /dev/null +++ b/data/scenarios/Challenges/Sokoban/Gadgets/no-reverse.yaml @@ -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 diff --git a/data/scenarios/Challenges/Sokoban/Gadgets/one-way.yaml b/data/scenarios/Challenges/Sokoban/Gadgets/one-way.yaml new file mode 100644 index 00000000..aea2cc6b --- /dev/null +++ b/data/scenarios/Challenges/Sokoban/Gadgets/one-way.yaml @@ -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 diff --git a/data/scenarios/Challenges/Sokoban/Simple/00-ORDER.txt b/data/scenarios/Challenges/Sokoban/Simple/00-ORDER.txt new file mode 100644 index 00000000..b22b1632 --- /dev/null +++ b/data/scenarios/Challenges/Sokoban/Simple/00-ORDER.txt @@ -0,0 +1 @@ +trapdoor.yaml diff --git a/data/scenarios/Challenges/Sokoban/Simple/trapdoor.yaml b/data/scenarios/Challenges/Sokoban/Simple/trapdoor.yaml new file mode 100644 index 00000000..8bd090ed --- /dev/null +++ b/data/scenarios/Challenges/Sokoban/Simple/trapdoor.yaml @@ -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 diff --git a/data/scenarios/Challenges/Sokoban/_foresight/solution.sw b/data/scenarios/Challenges/Sokoban/_foresight/solution.sw new file mode 100644 index 00000000..9f167392 --- /dev/null +++ b/data/scenarios/Challenges/Sokoban/_foresight/solution.sw @@ -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; diff --git a/data/scenarios/Challenges/Sokoban/foresight.yaml b/data/scenarios/Challenges/Sokoban/foresight.yaml new file mode 100644 index 00000000..5353838b --- /dev/null +++ b/data/scenarios/Challenges/Sokoban/foresight.yaml @@ -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....... diff --git a/data/scenarios/Testing/1234-push-command.yaml b/data/scenarios/Testing/1234-push-command.yaml index 46dfa2fd..de9a4935 100644 --- a/data/scenarios/Testing/1234-push-command.yaml +++ b/data/scenarios/Testing/1234-push-command.yaml @@ -49,7 +49,6 @@ entities: description: - Pushable crate properties: [known, portable, unwalkable] - capabilities: [push] known: [tree, flower, boulder, water] world: default: [blank] diff --git a/test/integration/Main.hs b/test/integration/Main.hs index ff7bf3d4..2d743f18 100644 --- a/test/integration/Main.hs +++ b/test/integration/Main.hs @@ -207,6 +207,13 @@ testScenarioSolution _ci _em = [ testSolution Default "Challenges/Ranching/capture" , 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 "Regression tests"