From 02eecba832c13355bcd45489832e0c2217b0cb91 Mon Sep 17 00:00:00 2001 From: Karl Ostmo Date: Fri, 15 Mar 2024 07:34:26 -0700 Subject: [PATCH 1/2] fix watch wakeup test (#1791) This improves the test introduced in #1736 in a few ways: * Place the system robot's code inline in the `program` field * even though the system bot had been using `instant`, the `run` command itself incurs a delay. So this ensures the system robot is ready to monitor the cell immediately * System robot uses exclusively `Intangible` commands in its monitoring loop * This allows removal of the `instant` command. * `Surveil`, which does not appear in any scenario yet, is made `Intangible`. * Remove the initial `wait 2` in the player robot's solution. Tested to ensure that this still exercises the problem that #1736 set out to solve, by commenting out this line (causing the scenario to fail). https://github.com/swarm-game/swarm/blob/01ae0e45d75c30619af76ae2438dc1b92ef61e08/src/swarm-engine/Swarm/Game/State/Robot.hs#L396 ## Demo scripts/play.sh -i data/scenarios/Testing/1598-detect-entity-change.yaml --autoplay --speed 1 --- .../Testing/1598-detect-entity-change.yaml | 19 +++++++++++++++++-- .../_1598-detect-entity-change/setup.sw | 17 ----------------- src/swarm-lang/Swarm/Language/Syntax.hs | 10 +++++++--- 3 files changed, 24 insertions(+), 22 deletions(-) delete mode 100644 data/scenarios/Testing/_1598-detect-entity-change/setup.sw diff --git a/data/scenarios/Testing/1598-detect-entity-change.yaml b/data/scenarios/Testing/1598-detect-entity-change.yaml index 604a48b8c..bddcdefe8 100644 --- a/data/scenarios/Testing/1598-detect-entity-change.yaml +++ b/data/scenarios/Testing/1598-detect-entity-change.yaml @@ -50,11 +50,26 @@ robots: invisible: true dir: [1, 0] program: | - run "scenarios/Testing/_1598-detect-entity-change/setup.sw" + def doUntilCorrect = + herenow <- ishere "dial (G)"; + if herenow { + give base "flower"; + } { + loc <- whereami; + surveil loc; + wait 1000; + doUntilCorrect; + } + end; + + def go = + doUntilCorrect; + end; + + go; inventory: - [1, flower] solution: | - wait 2; move; move; swap "dial (G)"; diff --git a/data/scenarios/Testing/_1598-detect-entity-change/setup.sw b/data/scenarios/Testing/_1598-detect-entity-change/setup.sw deleted file mode 100644 index 21b1aa3f6..000000000 --- a/data/scenarios/Testing/_1598-detect-entity-change/setup.sw +++ /dev/null @@ -1,17 +0,0 @@ -def doUntilCorrect = - herenow <- ishere "dial (G)"; - if herenow { - give base "flower"; - } { - watch down; - wait 1000; - doUntilCorrect; - } - end; - -def go = - instant $ - doUntilCorrect; - end; - -go; diff --git a/src/swarm-lang/Swarm/Language/Syntax.hs b/src/swarm-lang/Swarm/Language/Syntax.hs index 3e799a4c5..57c58ca57 100644 --- a/src/swarm-lang/Swarm/Language/Syntax.hs +++ b/src/swarm-lang/Swarm/Language/Syntax.hs @@ -827,9 +827,13 @@ constInfo c = case c of , "Any change to entities at the monitored locations will cause the robot to wake up before the `wait` timeout." ] Surveil -> - command 1 short . doc (Set.singleton $ Query $ Sensing EntitySensing) "Interrupt `wait` upon (remote) location changes." $ - [ "Like `watch`, but with no restriction on distance." - ] + command 1 Intangible $ + doc + (Set.singleton $ Query $ Sensing EntitySensing) + "Interrupt `wait` upon (remote) location changes." + [ "Like `watch`, but instantaneous and with no restriction on distance." + , "Supply absolute coordinates." + ] Heading -> command 0 Intangible $ shortDoc (Set.singleton $ Query $ Sensing RobotSensing) "Get the current heading." Blocked -> command 0 Intangible $ shortDoc (Set.singleton $ Query $ Sensing EntitySensing) "See if the robot can move forward." Scan -> From 55271c0003ba9fc246d6f0e1c2226bc8793b6aff Mon Sep 17 00:00:00 2001 From: Karl Ostmo Date: Fri, 15 Mar 2024 08:06:49 -0700 Subject: [PATCH 2/2] refactor word search using structure recognition (#1792) Makes use of rotation-aware structure recognition (#1678) to simplify goal checking for word search (#999). ![Screenshot from 2024-03-13 18-48-53](https://github.com/swarm-game/swarm/assets/261693/6fc9e62e-d9e2-4a13-8969-32dbee695e0a) # Benchmarks Using the following command (GHC 9.6.4): scripts/run-tests.sh --test-arguments '--pattern "word-search"' | Before | After | | --- | --- | | `0.98s` | `0.82s` | --- .../Challenges/_word-search/create-puzzle.sw | 2 +- .../_word-search/verify-solution.sw | 183 ---------------- data/scenarios/Challenges/word-search.yaml | 195 ++---------------- 3 files changed, 13 insertions(+), 367 deletions(-) delete mode 100644 data/scenarios/Challenges/_word-search/verify-solution.sw diff --git a/data/scenarios/Challenges/_word-search/create-puzzle.sw b/data/scenarios/Challenges/_word-search/create-puzzle.sw index 48023b1f9..8b748a48f 100644 --- a/data/scenarios/Challenges/_word-search/create-puzzle.sw +++ b/data/scenarios/Challenges/_word-search/create-puzzle.sw @@ -153,7 +153,7 @@ def singleTile = \expectedFwdOrdinal. \expectedBkwdOrdinal. return letterIndex; end; -def crossBack = \n. +def crossBack = \_n. currentLoc <- whereami; teleport self (0, snd currentLoc - 1); end; diff --git a/data/scenarios/Challenges/_word-search/verify-solution.sw b/data/scenarios/Challenges/_word-search/verify-solution.sw deleted file mode 100644 index 40405badb..000000000 --- a/data/scenarios/Challenges/_word-search/verify-solution.sw +++ /dev/null @@ -1,183 +0,0 @@ -/** -Algorithm: -We only need to check the base's -current position: if we find three contiguous highlights, -then we know that the player has just completed their -third highlight. -*/ - -def whichOrdinal = - isC <- ishere "lowercase c"; - if (isC) { - return 0; - } { - isO <- ishere "lowercase o"; - if (isO) { - return 1; - } { - isW <- ishere "lowercase w"; - if (isW) { - return 2; - } { - return (-1); - } - } - } - end; - - -def whichHighlightedOrdinal = \str. - if (str == "lowercase c") { - return 0; - } { - if (str == "lowercase o") { - return 1; - } { - if (str == "lowercase w") { - return 2; - } { - return (-1); - } - } - } - end; - -def countConsecutive = \expectedOrdinal. \n. - - thisOrdinal <- whichOrdinal; - nextOrdinal <- if (thisOrdinal == expectedOrdinal) { - return $ expectedOrdinal + 1; - } { - return 0; - }; - - if (nextOrdinal == 3) { - return true; - } { - if (n > 1) { - move; - countConsecutive nextOrdinal $ n - 1; - } { - return false; - }; - }; - end; - -def checkBackAndForth = - - foundBackward <- countConsecutive 0 3; - if (foundBackward) { - return true; - } { - turn back; - countConsecutive 0 3; - } - end; - -def checkDirections = \n. - if (n > 0) { - wasFound <- checkBackAndForth; - if wasFound { - return true; - } { - turn left; - checkDirections $ n - 1; - } - } { - return false; - } - end; - -def isMarkedInDirection = \d. - scanResult <- scan d; - ordinalNum <- case scanResult - (\_. return (-1)) - whichHighlightedOrdinal; - return $ ordinalNum >= 0; - end; - -/** -It's possible we could be one cell away from -a marked cell after finishing, either due -to using a directional `drill` command instead of -`drill down`, or due to an apparent bug which -does not evaluate the goal condition between the -`drill` and a `move` command. -*/ -def moveToMarkedCell = \n. - if (n > 0) { - isMarkedAhead <- isMarkedInDirection forward; - if isMarkedAhead { - move; - return true; - } { - turn left; - moveToMarkedCell $ n - 1; - }; - } { - return false; - }; - end; - -/** -Orient ourselves such that -a marked cell is behind us. -*/ -def findMarkBehind = \n. - if (n > 0) { - isMarkedBehind <- isMarkedInDirection back; - if isMarkedBehind { - return true; - } { - turn left; - findMarkBehind $ n - 1; - }; - } { - return false; - }; - end; - -/** -The cell we're on might be in the middle of a word, -rather than the end. Determine the orientation of -the line, then move along it until reaching the end. - -Algorithm: -0. Assumption: we are currently on a marked cell. -1. Turn in all all four directions to `scan back` - for a second marked cell. Stop turning if - we encounter one. - If none found after 4 turns, abort. -2. `scan forward` to see if there is a marked cell in - the opposite direction. - `move` (foward) once if there is. Since the word - is only three cells long, this will be the other - end of it. -*/ -def moveToWordExtrema = - foundCellBehind <- findMarkBehind 4; - if foundCellBehind { - isMarkedAhead <- isMarkedInDirection forward; - if isMarkedAhead { - move; - } {}; - } {}; - end; - -def checkSoln = - isMarkedHere <- isMarkedInDirection down; - atMarkedCell <- if isMarkedHere { - return true; - } { - moveToMarkedCell 4; - }; - - if atMarkedCell { - moveToWordExtrema; - checkDirections 4; - } { - return false; - } - end; - -as base {checkSoln}; \ No newline at end of file diff --git a/data/scenarios/Challenges/word-search.yaml b/data/scenarios/Challenges/word-search.yaml index 1cafa1230..d873f5c90 100644 --- a/data/scenarios/Challenges/word-search.yaml +++ b/data/scenarios/Challenges/word-search.yaml @@ -14,189 +14,8 @@ objectives: or vertically in either the upward or downward direction. Diagonal appearances are not valid. condition: | - /** - Algorithm: - We only need to check the base's - current position: if we find three contiguous highlights, - then we know that the player has just completed their - third highlight. - */ - - def whichOrdinal = - isC <- ishere "lowercase c"; - if (isC) { - return 0; - } { - isO <- ishere "lowercase o"; - if (isO) { - return 1; - } { - isW <- ishere "lowercase w"; - if (isW) { - return 2; - } { - return (-1); - } - } - } - end; - - - def whichHighlightedOrdinal = \str. - if (str == "lowercase c") { - return 0; - } { - if (str == "lowercase o") { - return 1; - } { - if (str == "lowercase w") { - return 2; - } { - return (-1); - } - } - } - end; - - def countConsecutive = \expectedOrdinal. \n. - - thisOrdinal <- whichOrdinal; - nextOrdinal <- if (thisOrdinal == expectedOrdinal) { - return $ expectedOrdinal + 1; - } { - return 0; - }; - - if (nextOrdinal == 3) { - return true; - } { - if (n > 1) { - move; - countConsecutive nextOrdinal $ n - 1; - } { - return false; - }; - }; - end; - - def checkBackAndForth = - - foundBackward <- countConsecutive 0 3; - if (foundBackward) { - return true; - } { - turn back; - countConsecutive 0 3; - } - end; - - def checkDirections = \n. - if (n > 0) { - wasFound <- checkBackAndForth; - if wasFound { - return true; - } { - turn left; - checkDirections $ n - 1; - } - } { - return false; - } - end; - - def isMarkedInDirection = \d. - scanResult <- scan d; - ordinalNum <- case scanResult - (\_. return (-1)) - whichHighlightedOrdinal; - return $ ordinalNum >= 0; - end; - - /** - It's possible we could be one cell away from - a marked cell after finishing, either due - to using a directional `drill` command instead of - `drill down`, or due to an apparent bug which - does not evaluate the goal condition between the - `drill` and a `move` command. - */ - def moveToMarkedCell = \n. - if (n > 0) { - isMarkedAhead <- isMarkedInDirection forward; - if isMarkedAhead { - move; - return true; - } { - turn left; - moveToMarkedCell $ n - 1; - }; - } { - return false; - }; - end; - - /** - Orient ourselves such that - a marked cell is behind us. - */ - def findMarkBehind = \n. - if (n > 0) { - isMarkedBehind <- isMarkedInDirection back; - if isMarkedBehind { - return true; - } { - turn left; - findMarkBehind $ n - 1; - }; - } { - return false; - }; - end; - - /** - The cell we're on might be in the middle of a word, - rather than the end. Determine the orientation of - the line, then move along it until reaching the end. - - Algorithm: - 0. Assumption: we are currently on a marked cell. - 1. Turn in all all four directions to `scan back` - for a second marked cell. Stop turning if - we encounter one. - If none found after 4 turns, abort. - 2. `scan forward` to see if there is a marked cell in - the opposite direction. - `move` (foward) once if there is. Since the word - is only three cells long, this will be the other - end of it. - */ - def moveToWordExtrema = - foundCellBehind <- findMarkBehind 4; - if foundCellBehind { - isMarkedAhead <- isMarkedInDirection forward; - if isMarkedAhead { - move; - } {}; - } {}; - end; - - def checkSoln = - isMarkedHere <- isMarkedInDirection down; - atMarkedCell <- if isMarkedHere { - return true; - } { - moveToMarkedCell 4; - }; - - if atMarkedCell { - moveToWordExtrema; - checkDirections 4; - } { - return false; - } - end; - - as base {checkSoln}; + foundStructure <- structure "cow" 0; + return $ case foundStructure (\_. false) (\_. true); robots: - name: base display: @@ -301,6 +120,16 @@ entities: description: - Ink for marking found words properties: [known, pickable] +structures: + - name: cow + recognize: [north, south, east, west] + structure: + palette: + 'c': [dirt, lowercase c] + 'o': [dirt, lowercase o] + 'w': [dirt, lowercase w] + map: | + cow recipes: - in: - [1, capital C]