diff --git a/data/scenarios/Challenges/00-ORDER.txt b/data/scenarios/Challenges/00-ORDER.txt index c538cb710..9833e50a1 100644 --- a/data/scenarios/Challenges/00-ORDER.txt +++ b/data/scenarios/Challenges/00-ORDER.txt @@ -7,6 +7,7 @@ teleport.yaml word-search.yaml gopher.yaml ice-cream.yaml +combo-lock.yaml hanoi.yaml hackman.yaml lights-out.yaml diff --git a/data/scenarios/Challenges/_combo-lock/setup.sw b/data/scenarios/Challenges/_combo-lock/setup.sw new file mode 100644 index 000000000..7a1bd6756 --- /dev/null +++ b/data/scenarios/Challenges/_combo-lock/setup.sw @@ -0,0 +1,85 @@ +def elif = \t. \then. \else. {if t then else} end +def else = \t. t end +def doN = \n. \f. if (n > 0) {f; doN (n - 1) f} {}; end; + +def colorFromIndex = \i. + if (i == 0) {"R"} + $ elif (i == 1) {"G"} + $ else {"B"}; + end; + +def pixelFromColor = \c. + "dial (" ++ c ++ ")"; + end; + +def checkCombo = \noMismatchYet. \stepsTaken. \colorString. + + let remainingCount = chars colorString in + if (remainingCount > 0) { + + let splitted = split 1 colorString in + let nextLetter = fst splitted in + let remainingLetters = snd splitted in + let expectedPixel = pixelFromColor nextLetter in + + move; + isExpectedHere <- ishere expectedPixel; + checkCombo (isExpectedHere && noMismatchYet) (stepsTaken + 1) remainingLetters; + } { + turn back; + + // Replace the cell watches + doN stepsTaken (watch down; move); + turn back; + return noMismatchYet; + }; + end; + +def unlockGate = \n. + move; + turn right; + move; + turn left; + doN n (grab; move); + return () + end; + +def doUntilCorrect = \colorString. + isCorrect <- checkCombo true 0 colorString; + if isCorrect { + let remainingCount = chars colorString in + unlockGate remainingCount; + return true; + } { + wait 1000; + doUntilCorrect colorString; + }; + end; + +def createCombo = \colorString. + // Scenario map starts with red pixels to + // mark the combo sequence + redPixelHere <- ishere $ pixelFromColor "R"; + + if redPixelHere { + r <- random 3; + let newColor = colorFromIndex r in + watch down; + move; + createCombo $ newColor ++ colorString; + } { + turn back; + return colorString; + }; + end; + +def go = + comboString <- instant ( + move; + createCombo ""; + ); + // say comboString; + instant $ doUntilCorrect comboString; + end; + +go; diff --git a/data/scenarios/Challenges/_combo-lock/solution.sw b/data/scenarios/Challenges/_combo-lock/solution.sw new file mode 100644 index 000000000..a51af436a --- /dev/null +++ b/data/scenarios/Challenges/_combo-lock/solution.sw @@ -0,0 +1,65 @@ +def moveToLock = + emptyHere <- isempty; + if emptyHere {move; moveToLock} {}; + end; + +def cycleCombos = \n. + wait 1; + entityNorth <- scan north; + let hasGate = case entityNorth (\_. false) (\x. x == "gate") in + if hasGate { + if (n > 0) { + drill down; + maybeNextEnt <- scan east; + case maybeNextEnt return (\_. turn east; move; cycleCombos 3); + cycleCombos $ n - 1; + } { + turn west; + move; + }; + } {} + end; + +def moveUntilBlocked = + isblocked <- blocked; + if isblocked {} { + move; + moveUntilBlocked; + }; + end; + +def toLeftEdge = + turn north; + move; + turn left; + moveUntilBlocked; + turn north; + end; + +def goUp = + toLeftEdge; + move; move; move; + end; + +def grabBitcoin = + move; move; + turn right; + move; move; + grab; + end; + +def go = + moveToLock; + cycleCombos 3; + goUp; + cycleCombos 3; + goUp; + cycleCombos 3; + goUp; + cycleCombos 3; + + toLeftEdge; + grabBitcoin; + end; + +go; diff --git a/data/scenarios/Challenges/combo-lock.yaml b/data/scenarios/Challenges/combo-lock.yaml new file mode 100644 index 000000000..b1beec2d0 --- /dev/null +++ b/data/scenarios/Challenges/combo-lock.yaml @@ -0,0 +1,135 @@ +version: 1 +name: Combination locks +author: Karl Ostmo +description: | + Unlock the gates +creative: false +seed: 4 +objectives: + - goal: + - | + Several combination-locked gates lie between you + and treasure. + - | + Each "dial" can be one of three colors. + `drill` a dial to cycle to its next color. + The adjacent `gate`{=entity} opens when the correct + combination is set. + - | + Unlock all of the combination locks and `grab` + the `bitcoin`{=entity}. + condition: | + as base {has "bitcoin"}; +robots: + - name: base + dir: [1, 0] + display: + invisible: false + devices: + - ADT calculator + - branch predictor + - hourglass + - comparator + - compass + - dictionary + - drill + - grabber + - lambda + - lodestone + - logger + - keyboard + - net + - scanner + - strange loop + - treads + - name: lockbot + system: true + dir: [1, 0] + display: + invisible: true + program: | + run "scenarios/Challenges/_combo-lock/setup.sw" +solution: | + run "scenarios/Challenges/_combo-lock/solution.sw" +entities: + - name: gate + display: + char: '#' + description: + - A locked door + properties: [known, unwalkable] + - name: "dial (R)" + display: + char: '•' + attr: red + description: + - A red dial + properties: [known] + - name: "dial (G)" + display: + char: '•' + attr: green + description: + - A green dial + properties: [known] + - name: "dial (B)" + display: + char: '•' + attr: blue + description: + - A blue dial + properties: [known] +recipes: + - in: + - [1, "dial (R)"] + out: + - [1, "dial (G)"] + required: + - [1, drill] + time: 0 + - in: + - [1, "dial (G)"] + out: + - [1, "dial (B)"] + required: + - [1, drill] + time: 0 + - in: + - [1, "dial (B)"] + out: + - [1, "dial (R)"] + required: + - [1, drill] + time: 0 +known: [boulder, water, bitcoin] +world: + dsl: | + {water} + upperleft: [-1, -1] + offset: false + palette: + '.': [grass, erase] + '$': [grass, bitcoin] + '@': [grass, boulder] + '#': [grass, gate] + 'B': [grass, erase, base] + 'c': [grass, dial (R)] + 'a': [grass, erase, lockbot] + map: | + .......$...... + @@@@@......@@@ + ....@######@.. + ....acccccc... + .............. + @@@@@.....@@@@ + ....@#####@... + ....accccc.... + .............. + @@@@@....@@@@@ + ....@####@.... + ....acccc..... + .............. + @@@@@...@@@@@@ + ....@###@..... + ..B.accc...... + .............. diff --git a/test/integration/Main.hs b/test/integration/Main.hs index 5993b547a..416cf0294 100644 --- a/test/integration/Main.hs +++ b/test/integration/Main.hs @@ -216,6 +216,7 @@ testScenarioSolutions rs ui = , testSolution (Sec 3) "Challenges/word-search" , testSolution (Sec 10) "Challenges/bridge-building" , testSolution (Sec 5) "Challenges/ice-cream" + , testSolution (Sec 10) "Challenges/combo-lock" , testSolution (Sec 15) "Challenges/wave" , testSolution (Sec 3) "Challenges/arbitrage" , testSolution (Sec 10) "Challenges/gopher" @@ -293,7 +294,7 @@ testScenarioSolutions rs ui = , testSolution Default "Testing/479-atomic-race" , testSolution (Sec 5) "Testing/479-atomic" , testSolution Default "Testing/555-teleport-location" - , testSolution Default "Testing/562-lodestone" + , testSolution (Sec 2) "Testing/562-lodestone" , testSolution Default "Testing/378-objectives" , testSolution Default "Testing/684-swap" , testSolution Default "Testing/699-movement-fail/699-move-blocked"