- Learn
- Tutorials
- Algorithms
- A* Search
- 4 Solve and Pause
4 Solve and Pause
By the end of this chapter, a gold Solve button sits beside Step. Press it, and the search runs on its own, and the Tiles slide home one after another. Press it again, and everything holds still until you’re ready.
The game as it is at the end of this chapter. Click the game to play.
If your game and this chapter part ways, here is the chapter’s finished project. Open it and compare, or start Chapter 5 from it.
To open it, start Myth Engine, choose File › Open Project... and pick the downloaded file.
4.1 The Idea
Try the game above. This time, press the gold button, Solve, beside Step, or press A.
The count doesn’t climb. It leaps. Before your eye can follow it, the count is at 20 and the card says Solving... And the Tiles begin to move on their own. Tile 1 slides up, then Tile 8 slides right, then the next, each at the same even speed as a click. The gold button reads Pause now.
Press it. The Tile that’s moving finishes its slide, and then nothing moves. The card says Paused.
Press Solve again. The Tiles go on from where they stopped, until the last one slides home and the card says Solved. The button reads Solve again, all by itself.
In Chapter 3, all of that took 46 presses of Step, one press at a time. Solve makes no new kind of search. It presses Step for you.
That’s the whole idea of this chapter, and here’s a way to picture it. Solve is a finger on the Step button. Every 0.05 seconds it presses, up to 8 times in a row, and each press is the very Step you took by hand. While a Tile slides, the finger lifts, so the Route plays one slide at a time. Pausing lifts it too, and nothing is lost. Every line in the notebook and every record of the Route stays where it was.
So who decides when a Step happens? Until now, Run Search listened for the Step button itself. Now a Step can come from the button, from Space or from Solve’s timer, so one new Logic Component, Solve Timer, takes every request. Run Search hears only one message, takeStep, and does what it always did.
One thing will look different. Press Step once, and the card says Paused, not Searching... Step takes one Step and then pauses Solve, in case it was running. A search that waits for your next press is a paused search, and the card says so.
For that, the Status Line has to remember what’s happening, not only its words. Each situation is one row of Messages, such as searching or solving. A situation has two sets of words now: one while Solve runs, and one while it’s paused.
Partway through this chapter, Step goes quiet for a while, and that’s expected. Solve Timer gives it back.
4.2 The Plan
Here’s how the new pieces join the game. Read each line once for its shape, and come back to it after the last part.
- You press Solve, or A -> Solve Timer starts its timer, solveTick, and the button reads Pause.
- Each ring of solveTick -> Solve Timer asks for up to 8 Steps -> unless a Tile slides, each one becomes
takeStep-> Run Search takes one Step, as before. - You press Step, or Space ->
stepPressedreaches Solve Timer -> it asks for one Step, then sendspauseSolve. - A Move is made ->
boardChanged-> Solve Timer takes no Step untilslideFinished. - You press Pause or Escape, the Route ends, or your hand moves a Tile ->
pauseSolve-> the timer stops, the button reads Solve, and the Status Line shows its paused words. - Run Search, Check Goal or Start Board names a situation -> Show Status Row keeps it in
$statusRowand shows its words.
4.3 Set Up
This chapter’s Set up card has two Commands, two Globals and one placement.
COMMANDS adds Solve, a Button joined to A, and Pause, a Button joined to Escape. Make them in the Input Manager, the way you made Step.
GLOBAL VARIABLES adds two Text Globals. The first, $solveButtonWords, is what the gold button says, and it starts empty. The second, $statusRow, is the situation the Status Line is in. It starts at ready. On Start Board’s canvas, press + on the Globals card and choose New Global… for each, as before. Clear the Default box of $solveButtonWords. Type ready into the Default box of $statusRow, with no quote marks.
PLACE THESE has the gold button. It waits for the last part, once everything it rings is ready. The Set up card on the Making page says more about each block.
AEscape4.4 Words That Wait
First, the Status Line learns to remember.
4.4.1 Messages, Changed
Messages gets a second column, pausedWords, a Text like words. A column is a field of Messages Entry, so open Messages Entry and press Add Field. Clear its Value box, as you did for words, because it starts empty.
One row of the "Messages" Data Table.
The new column shows up in Messages at once. Fill in each row’s pausedWords from the card below.
Look down that column. A search and the Route’s slides say Paused while they wait. Every other row keeps its own words, so a pause never hides Solved or Try a new puzzle.
Three rows go at the end. The solveButton and pauseButton rows are the gold button’s two words. The ready row has no words at all, because that’s the Status Line when nothing is under way.
SolvedSolvedSearching...PausedTry a new puzzle.Try a new puzzle.Building route...Building route...Solving...PausedSolvePause4.4.2 Show Status Row
Until now, every piece that changed the Status Line wrote its words straight onto it. Show Status Row writes down the situation first.
It’s handed a row’s name, in row. It keeps that name in $statusRow, and then it shows that row’s words. So the words are the same as before, and the game also knows which row they came from. Solve Timer will read that row again when Solve pauses, and show its pausedWords instead.
It’s two Change Variables. The second reads the row back by $statusRow, which the first has set a moment before.
Shows a situation on the Status Line: $statusRow becomes row, the Messages row of that situation, and the Status Line shows that row's words. While Solve is paused, Solve Timer shows the same row's pausedWords instead.
- Variable
$statusRow- Value
row
- Variable
$statusLine- Value
data('Messages', $statusRow, 'words')
Every place that wrote words onto the Status Line calls it now. On each card below, the old Change Variable is struck. Show Status Row takes its step, with its row typed bare, as the card shows it.
Check Goal names the solved row.
Says "Solved" on the Status Line when a Move, the player's or the Route's, makes the Goal, as its Tile begins to slide.
Any Object$boardState == data('Puzzle Settings', 'puzzle', 'goalBoard')- Variable
$statusLine- Value
data('Messages', 'solved', 'words')
- row
solved
Start Board names tryNew, when it refuses a puzzle.
Sets up the Board State when the puzzle opens: the Start Board from Puzzle Settings, when it can reach the Goal (Check Start Board) and is not already the Goal. A Board that cannot, or that leaves nothing to solve, is refused: the Board opens as the Goal, and the Status Line asks for a new puzzle.
Any Object- Action Name
startCheck- board
data('Puzzle Settings', 'puzzle', 'startBoard')
startCheck.value == true && data('Puzzle Settings', 'puzzle', 'startBoard') != data('Puzzle Settings', 'puzzle', 'goalBoard')- Variable
$boardState- Value
data('Puzzle Settings', 'puzzle', 'startBoard')
- Variable
$boardState- Value
data('Puzzle Settings', 'puzzle', 'goalBoard')
- Variable
$statusLine- Value
data('Messages', 'tryNew', 'words')
- row
tryNew
Run the game. Nothing looks different, and that’s right. The words are the same, and now the game also remembers which row each one came from.
4.5 One Message for Every Step
Now Run Search stops listening for the Step button. From here on, every Step reaches it as one message, takeStep, whoever asked for it.
4.5.1 Run Search, Changed
On Run Search’s canvas, find On Step Pressed, the Event block with five Modes beside it. Right-click it and choose Change Event…. In the window, choose Custom Events > Project Events > Add Custom Event…, then type takeStep. A small window asks “Change Event?” first. Press Change Event.
The Event now listens for takeStep, and its name follows: On Take Step. All five Modes stay, with their Actions. Every Switch Mode that named On Step Pressed now names On Take Step by itself, so the lines the card marks there are right already.
Leave Run Search’s other Event, When Step Is Pressed, as it is. Space still rings stepPressed there, the way the Step button does, so Run Search sends that message. It no longer listens for it.
The rest of Run Search’s changes are small. Where it set the Status Line’s words, Show Status Row names the situation instead.
Not Started gains an Else, step 6. If the Board is the Goal already, there’s nothing to search. So it sends pauseSolve to Puzzle Rules, and a running Solve stops. To add it, right-click step 1, the If, and choose Add Else, then put its Action in with Add inside Else.
Runs the A* solver one Step at a time, from the Board shown. Solve Timer sends takeStep for each Step. The first Step stores that Board as the first open Search State; each Step then Expands the best open Search State (Expand Best State) until the Goal is accepted (goalAccepted). Each Step then copies one record of the Route, back along the parents (Building Route), and then plays one of its Moves (Playing Route). When the search stops (searchStopped) or the Route has been played, Step has nothing more to do (Finished). A hand Move cancels the search. The Status Line says what the solver is doing ($statusRow).
Any Objectself.runSearchData- Applies To
@self.puzzleRules- Custom Event
stepPressed
$boardState != data('Puzzle Settings', 'puzzle', 'goalBoard')- board
$boardState- movesSoFar
0- parentState
-1
- Variable
$statusLine- Value
data('Messages', 'searching', 'words')
- row
searching
- Event
On Take Step- Event
On Step Pressed- Mode
Searching
- puzzleRules
@self.puzzleRules
- Applies To
@self.puzzleRules- Custom Event
pauseSolve
- puzzleRules
@self.puzzleRules
Building Route names solving where it once wrote the words. Playing Route doesn’t change. Finished gets its first Action: it sends pauseSolve, because the Route has been played and there’s nothing left to do.
- Action Name
copied- board
self.runSearchData.routeBoard
copied.value == (-1)- Component Value
self.runSearchData.movesPlayed- Value
0
- Variable
$statusLine- Value
data('Messages', 'solving', 'words')
- row
solving
- Event
On Take Step- Event
On Step Pressed- Mode
Playing Route
- Component Value
self.runSearchData.routeBoard- Value
copied.value
- Component Value
self.runSearchData.routeNextBoard- Value
data('Solution Route', text(self.runSearchData.movesPlayed + 1), 'state')
- Action Name
routeTile- board
$boardState- nextBoard
self.runSearchData.routeNextBoard
- puzzleRules
@self.puzzleRules- tile
routeTile.value
- Applies To
@self.puzzleRules- Custom Event
pauseSolve
On Goal Accepted names building, and On Search Stopped names tryNew.
- Component Value
self.runSearchData.routeBoard- Value
data('Puzzle Settings', 'puzzle', 'goalBoard')
- Variable
$statusLine- Value
data('Messages', 'building', 'words')
- row
building
- Event
On Take Step- Event
On Step Pressed- Mode
Building Route
- Variable
$statusLine- Value
data('Messages', 'tryNew', 'words')
- row
tryNew
- Event
On Take Step- Event
On Step Pressed- Mode
Finished
On Board Changed names ready where it emptied the Status Line, so a hand Move clears the words. And a hand Move stops Solve too. Step 13 sends pauseSolve, at the end of the Else, inside it.
$boardState == self.runSearchData.routeNextBoard- Component Value
self.runSearchData.movesPlayed- Operator
+=- Value
1
$boardState == data('Puzzle Settings', 'puzzle', 'goalBoard')- Event
On Take Step- Event
On Step Pressed- Mode
Finished
- Table
"Search States"
- Table
"Solution Route"
- Component Value
self.runSearchData.routeNextBoard- Value
-1
- Variable
$statesChecked- Value
0
$boardState != data('Puzzle Settings', 'puzzle', 'goalBoard')- Variable
$statusLine- Value
""
- row
ready
- Event
On Take Step- Event
On Step Pressed- Mode
Not Started
- Applies To
@self.puzzleRules- Custom Event
pauseSolve
Run the game and press Step. Nothing happens. Run Search waits for takeStep now, and nothing sends it yet.
4.8 If It Didn’t Work
This chapter moves where a Step comes from, so a slip can make Step do too little or too much. That’s normal. Press Step once and watch the count.
Step does nothing at all? Perhaps Solve Timer isn’t on Puzzle Rules yet, or On Step Due’s Starting Mode isn’t No Tile Sliding. Look at its one Action too, which sends takeStep, spelled the same as Run Search’s Event.
One press of Step adds 2 to the count? Perhaps Run Search still has an On Step Pressed Event beside On Take Step, so both answer. Change Event turns the old Event into the new one, and keeps its Actions. Delete the extra Event.
Solve does nothing, and the button never says Pause? Look at the gold button’s placement first, where message should be solvePressed, and then at On Solve Pressed, which should start in Paused.
Solve searches, but no Tile ever slides? On Step Due may have switched to Tile Sliding and never come back. Look at On Slide Finished, which switches On Step Due to No Tile Sliding.
The button shows no word, or the wrong one? Its Text should be {$solveButtonWords}, braces and all, and When the Scene Starts sets that Global to the solveButton row’s words.
The card says Paused while Solve runs? Look at On Solve Pressed’s step 4, which reads ‘words’, and On Pause Solve’s step 4, which reads ‘pausedWords’. The two look alike, so they swap without a sound.
The words are gone where they should be? Show Status Row’s row has to match a row of Messages, letter for letter, such as searching or tryNew.
Each of these is one small fix. Make it, run the game again, and you’re back with the chapter. The catch-up download at the top of this chapter is its finished project, if you’d like to compare.
Slow the finger down, and watch the search work one Board at a time. Select Puzzle Rules, and look under Variables in its Properties. Set stepsPerTick to 1 and solveSeconds to 0.5. Run the game and press Solve. Now the count climbs two Boards a second, slow enough to read the words as they change.
Try it the other way, too, and see how fast you can make it. Set them back to 0.05 and 8 when you’re done.
Your solver runs on its own now, and it waits when you ask it to. In Chapter 5, it gets new puzzles, and a second way to guess.
