TutorialsCocktail Shaker Sort

5  The Finished Puzzle

Goal

By the end of this chapter, Picture Puzzle is finished. Press Sort, and the computer runs the whole sort by itself, at Slow, Steady or Fast, while the pieces glide past each other instead of jumping. Choose 9, 25 or 64 pieces. Choose the Village, the Forest or the Harbor, or upload a picture of your own. Open How it works, and follow the sort line by line. When the last piece lands, the lines between the pieces disappear.

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, to open and compare. It’s the finished game, the same one the Welcome page plays.

Picture Puzzle, Chapter 5 finishedMyth project · 6.9 MB

To open it, start Myth Engine, choose File › Open Project... and pick the downloaded file.

5.1 The Idea

The Village is whole at the end of Chapter 4. It took 1478 presses of Step to get there, and your hand did every one.

This chapter hands the pressing to the game. Press Sort, and a timer starts. Every time it rings, it asks the computer for a Step, the very Step your hand asked for. The computer doesn’t sort a new way. It asks the same question about the same pairs, in the same order. So Sort ends on the same counts as Step: 1478 comparisons and 819 swaps.

A timer that rings over and over, with the same wait between rings, is a recurring timer. It’s like a metronome on a piano. It doesn’t play a note. It only keeps the beat, and the computer plays a Step on every tick. How fast it ticks is the speed: Slow, Steady or Fast.

There’s a catch, and it’s the chapter’s one hard idea. From now on, the pieces slide. Two pieces of a swap glide past each other instead of jumping. But the board changes at once. The slide only shows it, a fraction of a second later. So while the pieces glide, the next comparison has to wait, or the board would run ahead of the picture.

The game keeps that wait with a cooldown, a stopwatch with a name. Every slide starts it. While it runs, new moves wait their turn.

The rest of the chapter is everything around the sort. The game learns who plays, you or the computer, so the computer’s colors show only while it’s sorting. The board learns three sizes. The Preview learns three pictures and one of yours. And a panel called How it works explains the sort while it runs.

Did you know?

A board laid out back to front is the most work a sort can have. Every pair of its pieces is out of order, so it takes one swap for every pair. That’s 36 swaps on 9 pieces, 300 on 25, and 2016 on 64.

5.2 The Plan

Here’s how the new pieces work together. Come back to these lines at the end, when every name is something you’ve built.

  • Two slots trade pieces -> Slide Pieces starts the pieceSlide cooldown and sends slideStarted -> the two Pieces glide to their slots.
  • A press, a tap or H -> Let Player Play -> $whoPlays is Player, a running sort pauses, and the Outlines lose their green and amber.
  • Sort, or A -> Sort Timer lets the computer play and starts the pictureSort timer.
  • Every ring of the timer -> Sort Timer asks Computer Sort for Steps, as many as the speed allows, while no piece slides.
  • The sort ends -> Computer Sort sends sortEnded -> Sort Timer stops the timer.
  • A Count Button -> $gridSize changes and pieceCountChosen goes out -> Arrange Board shuffles, and every Piece and Outline lays itself out for the new size.
  • A Picture Button, or Upload -> Use Picture sends pictureChosen -> the Preview and the pieces show the new picture, and Arrange Board shuffles.
  • Every piece home and nothing sliding -> the Whole Picture covers the board.
  • How it works, or F -> Lesson Panel Switch turns the Puzzle Controls off and the Lesson Panel Controls on -> the panel shows, and the puzzle waits.

5.3 Set Up

Chapter 5 brings the rest of the pictures, five Commands, a second set of keys, nine Globals and a lot of placements.

ART lists the pictures this chapter starts to use. The Starter Kit brought every one of them. Four are named Uploaded. They’re a plain dark green square for now, and the Upload button paints your own picture into them while the game runs.

COMMANDS and INPUT CONTEXTS go together, so read about both before you start. The card shows the Commands first, but the order you make them in matters here.

An Input Context is a set of keys. Your project has one already. It’s called Default, and every key you’ve made so far lives in it. This chapter renames it Puzzle Controls, and adds a second context, Lesson Panel Controls, for the How it works panel. Only one of the two is on at a time.

So make them in this order. First, rename Default to Puzzle Controls. Then, with its row selected, add Run or Pause (A), Player Plays (H), Computer Plays (C) and How It Works (F). They join Puzzle Controls. Then add the Lesson Panel Controls context. It starts Inactive at Start, and its row is selected now, so Close Panel goes into it, with its two keys, F and Escape. The Set up card shows where each of these lives.

F and Escape now have two jobs each. F opens the panel from Puzzle Controls and closes it from Lesson Panel Controls. Escape cancels a selection in one and closes the panel in the other. But the two contexts are never on at once, so a key only ever means one thing.

GLOBAL VARIABLES are nine new values, and you make them in Show Piece’s Globals card, as before. Three Texts start empty: $sortButtonLabel, $lessonPass and $lessonOutcome. Each part of the chapter says what its own Globals are for, when it uses them.

PLACE THESE is long. Don’t place anything yet. Each part places its own, once the Objects and Logic it needs exist.

Set upWhat this chapter adds
ART (sprites, from the starter kit)
Gold Face
Village Pieces 9
Village Pieces 25
Forest Picture
Harbor Picture
Forest Pieces 9
Harbor Pieces 9
Forest Pieces 25
Harbor Pieces 25
Forest Pieces 64
Harbor Pieces 64
Panel Face
Uploaded Picture
Uploaded Pieces 9
Uploaded Pieces 25
Uploaded Pieces 64
COMMANDS (Game Settings > Input Manager)
Run or PauseButton
KeybindingsA
Player PlaysButton
KeybindingsH
Computer PlaysButton
KeybindingsC
How It WorksButton
KeybindingsF
Close PanelButton
KeybindingsF, Escape
INPUT CONTEXTS (Game Settings > Input Manager)
Puzzle Controls Active at Start(rename Default)
CommandsReset, New Arrangement, Choose Piece 1, Choose Piece 2, Choose Piece 3, Choose Piece 4, Choose Piece 5, Choose Piece 6, Choose Piece 7, Choose Piece 8, Choose Piece 9, Focus Left, Focus Right, Focus Up, Focus Down, Select Focused Piece, Cancel, Step, Run or Pause, Player Plays, Computer Plays, How It Works
Lesson Panel ControlsInactive at Start(new)
CommandsClose Panel
GLOBAL VARIABLES
$speedTextstarts at Fast
$sortButtonLabelTextstarts at
$slideFromNumberstarts at -1
$slideToNumberstarts at -1
$slideSecondsNumberstarts at 0
$pictureTextstarts at Village
$whoPlaysTextstarts at Player
$lessonPassTextstarts at
$lessonOutcomeTextstarts at
SCENE Picture Table: PLACE THESE
ObjectXY
Sort Button900-677
with Per Instance Variables > Command = Sort
Speed Caption815-577
Whole Picture340-500
Speed Button715-611
with Text / UI > Text = Slow (Edit Object Locally)
with Per Instance Variables > Speed = Slow
Speed Underline715-633
with Per Instance Variables > Speed = Slow
Speed Button815-611
with Text / UI > Text = Steady (Edit Object Locally)
with Per Instance Variables > Speed = Steady
Speed Underline815-633
with Per Instance Variables > Speed = Steady
Speed Button915-611
with Text / UI > Text = Fast (Edit Object Locally)
Speed Underline915-633
Pieces Caption815-486
Count Button715-520
with Text / UI > Text = 9 (Edit Object Locally)
with Per Instance Variables > Piece Count = 9 Pieces
Count Underline715-542
with Per Instance Variables > Piece Count = 9 Pieces
Count Button815-520
with Text / UI > Text = 25 (Edit Object Locally)
with Per Instance Variables > Piece Count = 25 Pieces
Count Underline815-542
with Per Instance Variables > Piece Count = 25 Pieces
Count Button915-520
with Text / UI > Text = 64 (Edit Object Locally)
Count Underline915-542
Picture Button95-139
Picture Name95-181
Picture Button195-139
with Sprite > Sprite = Forest Picture (Edit Object Locally)
with Per Instance Variables > Picture = Forest
Picture Name195-181
with Text / UI > Text = Forest (Edit Object Locally)
Picture Button295-139
with Sprite > Sprite = Harbor Picture (Edit Object Locally)
with Per Instance Variables > Picture = Harbor
Picture Name295-181
with Text / UI > Text = Harbor (Edit Object Locally)
Puzzle Button495-141
with Transform > Bounding Box > Size = X 225, Y 44 (Edit Object Locally)
with Sprite > Sprite = Gold Face (Edit Object Locally)
with Sprite > Transform > Size = X 225, Y 44 (Edit Object Locally)
with Text / UI > Text = Upload (Edit Object Locally)
with Text / UI > Color = #FFFFFF (Edit Object Locally)
with Per Instance Variables > Command = Upload
Puzzle Button815-783
with Transform > Bounding Box > Size = X 260, Y 39 (Edit Object Locally)
with Sprite > Transform > Size = X 260, Y 39 (Edit Object Locally)
with Text / UI > Text = How it works (Edit Object Locally)
with Per Instance Variables > Command = Lesson
Lesson Panel500-420
Lesson Title500-118
Lesson Line500-201
with Text / UI > Text = Each piece belongs in one home slot. (Edit Object Locally)
Lesson Line500-246
with Text / UI > Text = Board Slots stores the piece in each slot. (Edit Object Locally)
with Text / UI > Font Size = 18 (Edit Object Locally)
Lesson Line500-282
with Text / UI > Text = Swapping two values moves two pieces. (Edit Object Locally)
with Text / UI > Font Size = 17 (Edit Object Locally)
Lesson Line500-337
with Text / UI > Text = The computer compares two neighboring pieces. (Edit Object Locally)
with Text / UI > Font Size = 18 (Edit Object Locally)
Lesson Line500-384
with Text / UI > Text = If the left piece's home is later, they swap. (Edit Object Locally)
with Text / UI > Font Size = 20 (Edit Object Locally)
Lesson Line500-430
with Text / UI > Text = Forward settles the largest; backward settles the smallest. (Edit Object Locally)
with Text / UI > Font Size = 17 (Edit Object Locally)
Lesson Line500-565
with Text / UI > Text = A pass with no swaps ends the sort; every piece home ends it sooner. (Edit Object Locally)
with Text / UI > Font Size = 17 (Edit Object Locally)
Lesson Line500-617
with Text / UI > Text = Arrow keys: move focus. Enter: select. Space: Step. (Edit Object Locally)
with Text / UI > Font Size = 15 (Edit Object Locally)
Lesson Line500-651
with Text / UI > Text = A: Sort/Pause. R: Reset. N: Shuffle. F or Escape: Close. (Edit Object Locally)
with Text / UI > Font Size = 15 (Edit Object Locally)
Lesson State500-475
Lesson Result500-521
Close Button868-166

Save your project, and again at the end of each part.

5.4 Pieces That Glide

First, the pieces learn to move.

Until now, an exchange was a jump. One frame the two pieces were here, and the next they were there. Now each piece starts in the other’s slot and glides home along a straight line. Your exchanges take 0.22 seconds, about a blink.

5.4.1 Slide Pieces

Slide Pieces is the start of every slide. By the time anything calls it, Board Slots has already changed. The two numbers have traded places, and each Piece shows its new piece. Slide Pieces only arranges the show.

It’s given the two slots and how many seconds the slide lasts. It writes all three into Globals, $slideFrom, $slideTo and $slideSeconds, where every Piece can read them. It starts the pieceSlide cooldown on Puzzle Rules, for those same seconds. Last, it sends slideStarted.

The cooldown’s name comes back on many cards in this chapter, always “pieceSlide”. Keep those quotes. Values, quote marks and all explains the formula slots.

FunctionSlide Pieces

Shows two slots trading pieces as a slide: each of the two pieces starts at the other slot and moves to its own over seconds. The board has already changed; the slide only shows it. While the pieceSlide cooldown of Puzzle Rules runs, new moves wait.

PARAMETERS
NameTypeStarts at
puzzleRulesObjectPuzzle Rules
firstSlotNumber0
secondSlotNumber0
secondsNumber0.22
ACTIONS
1Change Variable
Variable
$slideFrom
Value
firstSlot
2Change Variable
Variable
$slideTo
Value
secondSlot
3Change Variable
Variable
$slideSeconds
Value
seconds
4Start Cooldown
Applies to
puzzleRules
Cooldown Key
"pieceSlide"
Seconds
seconds
5Trigger Custom Event
Custom Event
slideStarted

5.4.2 Slide Piece

Slide Piece needs a place to keep the other slot while it sets up the glide. Make this form with the Data Structures card’s + before its Events.

Data StructureSlide Piece Data

What each Piece remembers while it slides: otherSlot, the other slot of the exchange, where the slide starts.

otherSlotNumberdefault 0

Slide Piece lives on every Piece. When slideStarted arrives, 62 of the 64 Pieces have nothing to do. Their If says no.

The two that answer are standing on $slideFrom and $slideTo. Each shows the piece that came from the other slot, so it should start there. First it works out the other slot, kept in self.slidePieceData.otherSlot. It takes $slideFrom, and if that’s its own slot, $slideTo instead.

Then it jumps to the middle of otherSlot, through Slot Center, and steps in front of the other pieces with Set Z Order. Two Tween Actions glide it home: one for position.x, one for position.y, each over $slideSeconds. Each tweens a value of the Piece’s own Transform. Leave Value Of on Component, and type or choose self.transform.position.x in the Value box, or position.y for the second. The card gives that as Value self.transform and Property position.x. Its Target is home.x or home.y, and its Duration is $slideSeconds. The engine does the gliding. Slide Piece only says where to and how long.

Its Every Step Event has two Modes. Resting does nothing, and it’s where a Piece spends most of its life. Sliding watches the pieceSlide cooldown, frame after frame. When the cooldown runs out, the piece is home. It steps back among the others, switches to Resting, and sends slideEnded.

One more Event is for a slide that’s cut short, before the piece gets home. Press Reset or Shuffle in the middle of a slide, and boardArranged arrives while the piece is still on its way. Then Control Tween ends the glide where it is, and the piece settles at once. It starts on Operation Stop and Which All, the choices it needs, so it ends both of the Piece’s tweens.

Make the Every Step Event and its two Modes before the slideStarted Actions, because Switch Mode picks them from lists.

Logic ComponentSlide PieceAttach to: Piece

Slides this Piece onto its slot when its slot was one of the two in a slide: it starts at the other slot and moves in a straight line to its own over slideSeconds, then stands exactly on its slot. While the Piece slides, only this Logic moves it.

Attach toAny Object
DATA STRUCTURES
Slot Numberself.slotNumber
Slide Piece Dataself.slidePieceData
SHARED VARIABLES
NameTypeKindStarting Value
puzzleRulesObjectConstantNone
On Slide Started
WhenslideStartedCustom Event
1Ifself.slotNumber.slot == $slideFrom || self.slotNumber.slot == $slideTo
Then
2Change Component Value
Component Value
self.slidePieceData.otherSlot
Value
$slideFrom
3Ifself.slotNumber.slot == $slideFrom
Then
4Change Component Value
Component Value
self.slidePieceData.otherSlot
Value
$slideTo
5Slot CenterFunction
Action Name
start
slot
self.slidePieceData.otherSlot
6Set Position
Position Relative To
Screen
X
start.x
Y
start.y
7Set Z Order
Depth Amount
1
8Slot CenterFunction
Action Name
home
slot
self.slotNumber.slot
9Tween
Value
self.transform
Property
position.x
Target
home.x
Duration
$slideSeconds
10Tween
Value
self.transform
Property
position.y
Target
home.y
Duration
$slideSeconds
11Switch Mode
Event
Every Step
Mode
Sliding
Every Step
WhenStep
ModeResting (Starting Mode)
(no Actions)
Every Step
WhenStep
ModeSliding
1Check Cooldown Ready
Action Name
slideDone
Applies to
@self.puzzleRules
Cooldown Key
"pieceSlide"
2IfslideDone.value == true
Then
3Set Z Order
Depth Amount
0
4Switch Mode
Event
Every Step
Mode
Resting
5Trigger Custom Event
Custom Event
slideEnded
On Board Arranged
WhenboardArrangedCustom Event
1Control Tween
2Set Z Order
Depth Amount
0
3Switch Mode
Event
Every Step
Mode
Resting

The Piece gets Slide Piece. Its puzzleRules Shared Variable already names Puzzle Rules, and this Logic uses that same value.

ObjectPieceAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 68, Y 68
Sprite
Z Index Within Object-1
SpriteVillage Pieces 64
Transform > SizeX 68, Y 68
Data Structure
From LogicShow Piece, Lay Out Slot, Piece Pointer, Slide Piece
From LogicShow Piece, Lay Out Slot, Piece Pointer
Data StructureSlot Number
Data Structure
From LogicSlide Piece
Data StructureSlide Piece Data
Logic
Show Piece
Lay Out Slot
Piece Pointer
Slide Piece
Shared Variables
puzzleRulesPuzzle Rules

5.4.3 Make Player Exchange

Make Player Exchange is your exchange, and it calls Slide Pieces right after Moves counts. It gains two inputs, puzzleRules and slideSeconds, and hands both on.

FunctionMake Player ExchangeAddDelete

The player's exchange: the pieces of two slots trade places, Moves counts it, the two pieces slide over slideSeconds, and every Piece is told.

PARAMETERS
NameTypeStarts at
firstSlotNumber0
secondSlotNumber0
puzzleRulesObjectPuzzle Rules
slideSecondsNumber0.22
ACTIONS
1Exchange SlotsFunction
firstSlot
firstSlot
secondSlot
secondSlot
2Change Variable
Variable
$moves
Operator
+=
Value
1
3Slide PiecesFunction
puzzleRules
puzzleRules
firstSlot
firstSlot
secondSlot
secondSlot
seconds
slideSeconds
4Trigger Custom Event
Custom Event
piecesExchanged

5.4.4 Player Exchange

Player Exchange decides how long your slides last. It gains a Parameter, exchangeSlideSeconds, at 0.22, and both of its calls to Make Player Exchange pass it along.

It gains one Event too, clearSelectionRequested. When the computer takes over, a half-done selection has to end, and only Player Exchange can switch its own pieceChosen back. So this Event ends the selection the way the others do: a Switch Mode to Nothing Selected, then Clear Selection. Nothing sends it yet. Let Computer Play will, in the next part.

Logic ComponentPlayer ExchangeAttach to: Puzzle RulesAddDelete

The player exchanges two pieces: the first piece chosen is selected, the second one trades places with it (choosing the selected piece again cancels). A drag from one piece to another exchanges them at once. exchangeSlideSeconds is how long the two pieces of an exchange slide.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
puzzleRulesObjectConstantNone
exchangeSlideSecondsNumberConstant0.22
On Piece Chosen
WhenpieceChosenCustom Event
ModeNothing Selected (Starting Mode)
1Change Variable
Variable
$selectedSlot
Value
$chosenSlot
2Change Variable
Variable
$message
Value
data('Messages', 'selected', 'words')
3Switch Mode
Event
On Piece Chosen
Mode
One Selected
4Trigger Custom Event
Custom Event
selectionChanged
On Piece Chosen
WhenpieceChosenCustom Event
ModeOne Selected
1If$chosenSlot != $selectedSlot
Then
2Make Player ExchangeFunction
firstSlot
$selectedSlot
secondSlot
$chosenSlot
puzzleRules
@self.puzzleRules
slideSeconds
@self.exchangeSlideSeconds
3Change Variable
Variable
$message
Value
""
4Switch Mode
Event
On Piece Chosen
Mode
Nothing Selected
5Clear SelectionFunction
On Pieces Dropped
WhenpiecesDroppedCustom Event
1Make Player ExchangeFunction
firstSlot
$pressedSlot
secondSlot
$chosenSlot
puzzleRules
@self.puzzleRules
slideSeconds
@self.exchangeSlideSeconds
2Change Variable
Variable
$message
Value
""
3Switch Mode
Event
On Piece Chosen
Mode
Nothing Selected
4Clear SelectionFunction
On Clear Selection Requested
WhenclearSelectionRequestedCustom Event
1Switch Mode
Event
On Piece Chosen
Mode
Nothing Selected
2Clear SelectionFunction
On Selection Canceled
WhenselectionCanceledCustom Event
1Switch Mode
Event
On Piece Chosen
Mode
Nothing Selected
2Clear SelectionFunction
On Board Arranged
WhenboardArrangedCustom Event
1Change Variable
Variable
$moves
Value
0
2Switch Mode
Event
On Piece Chosen
Mode
Nothing Selected
3Clear SelectionFunction

5.4.5 Piece Press

Now the wait. A press on a piece while two pieces are still gliding would start a new exchange before the last one shows. So Piece Press asks first. Check Cooldown Ready answers whether the pieceSlide cooldown has run out. If it hasn’t, the press is ignored.

Logic ComponentPiece PressAttach to: Puzzle RulesAddDelete

Follows one press of the pointer on a piece: released on the same piece it is a tap, released on another piece it is a drag, and released anywhere else it is forgotten. A press cut off (the game lost focus, or the touch was cut off) is forgotten too, when Input Interruptions sends selectionCanceled.

Attach toAny Object
On Piece Pressed
WhenpiecePressedCustom Event
1Change Variable
Variable
$pressedSlot
Value
$chosenSlot
2Trigger Custom Event
Custom Event
selectionChanged
1Check Cooldown Ready
Action Name
slideDone
Cooldown Key
"pieceSlide"
2IfslideDone.value == true
Then
3Change Variable
Variable
$pressedSlot
Value
$chosenSlot
4Trigger Custom Event
Custom Event
selectionChanged
On Piece Released
WhenpieceReleasedCustom Event
1If$pressedSlot >= 0
Then
2If$pressedSlot == $chosenSlot
Then
3Trigger Custom Event on Object
Custom Event
pieceChosen
4Otherwise
5Trigger Custom Event on Object
Custom Event
piecesDropped
6Change Variable
Variable
$pressedSlot
Value
-1
7Trigger Custom Event
Custom Event
selectionChanged
When the Left Mouse Button Is Released
WhenMouse ReleaseMouse button: left
1Switch Mode
Event
On End Step
Mode
Release Seen
On End Step
WhenEnd Step
ModeNo Release (Starting Mode)
(no Actions)
On End Step
WhenEnd Step
ModeRelease Seen
1Change Variable
Variable
$pressedSlot
Value
-1
2Trigger Custom Event
Custom Event
selectionChanged
3Switch Mode
Event
On End Step
Mode
No Release
On Selection Canceled
WhenselectionCanceledCustom Event
1Change Variable
Variable
$pressedSlot
Value
-1
2Trigger Custom Event
Custom Event
selectionChanged

Run the game. Tap two pieces. They glide past each other into their new slots. The Step button’s pieces still jump for now. They learn to glide two parts from here, once the speeds exist.

5.5 Who Plays

Next, the game learns whose turn it is.

When you play, the board shows your colors: blue for the focus or a press, gold for a choice. When the computer sorts, it adds green for settled slots and amber for its pair. Mixing the two is confusing. Green slots after your own exchange would mean nothing, because the computer has forgotten that board.

So the game keeps one Text, $whoPlays. It says Player or Computer, and green and amber show only while it says Computer.

5.5.1 Let Player Play

Let Player Play hands the board to you. If the computer was playing, $whoPlays becomes Player, and pauseRequested goes to Puzzle Rules, so a running sort stops where it is. Last, whoPlaysChanged tells the Outlines.

If you’re already playing, its If says no, and nothing happens. Its If reads $whoPlays == "Computer". Type the whole condition, quote marks and all.

FunctionLet Player Play

The player takes over from the computer: $whoPlays becomes Player, a running sort pauses where it is, and the Outlines are told (whoPlaysChanged). When the player is already playing, nothing changes.

PARAMETERS
NameTypeStarts at
puzzleRulesObjectPuzzle Rules
ACTIONS
1If$whoPlays == "Computer"
Then
2Change Variable
Variable
$whoPlays
Value
'Player'
3Trigger Custom Event on Object
Applies to
puzzleRules
Custom Event
pauseRequested
4Trigger Custom Event
Custom Event
whoPlaysChanged

5.5.2 Let Computer Play

Let Computer Play is its mirror. It hands the board to the computer, and it ends a half-done selection on the way. It can’t switch Player Exchange’s Mode, so it asks: Trigger Custom Event on Object sends clearSelectionRequested to Puzzle Rules, where Player Exchange answers.

FunctionLet Computer Play

The computer takes over from the player: $whoPlays becomes Computer, a half-done selection ends, and the Outlines are told (whoPlaysChanged). When the computer is already playing, nothing changes.

PARAMETERS
NameTypeStarts at
puzzleRulesObjectPuzzle Rules
ACTIONS
1If$whoPlays == "Player"
Then
2Change Variable
Variable
$whoPlays
Value
'Computer'
3Trigger Custom Event on Object
Applies to
puzzleRules
Custom Event
clearSelectionRequested
4Trigger Custom Event
Custom Event
whoPlaysChanged

5.5.3 Who Plays

Who Plays is the switch, and it lives on Puzzle Rules. H hands the board to you, and so does a press on a piece. C hands it to the computer. So does every comparison, which means a Step takes over without asking.

Logic ComponentWho PlaysAttach to: Puzzle Rules

Hands the game to the player or to the computer ($whoPlays): H and a press on a piece let the player play, and C and a comparison of the computer let the computer play. Keys that choose a piece let the player play through Choose Slot, and Sort through Sort Timer. The board never changes when who plays changes.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
puzzleRulesObjectConstantNone
When Player Is Pressed
WhenCommand PressedCommand: Player Plays
1Let Player PlayFunction
puzzleRules
@self.puzzleRules
When Computer Is Pressed
WhenCommand PressedCommand: Computer Plays
1Let Computer PlayFunction
puzzleRules
@self.puzzleRules
On Piece Pressed
WhenpiecePressedCustom Event
1Let Player PlayFunction
puzzleRules
@self.puzzleRules
On Pair Compared
WhenpairComparedCustom Event
1Let Computer PlayFunction
puzzleRules
@self.puzzleRules

Here is Puzzle Rules as it is at the end of this chapter. Who Plays is the first of the five Logic Components it gains in this chapter, and the rest come one part at a time. Attach Who Plays now, using Puzzle Rules’ puzzleRules Shared Variable, and each of the others when its part makes it.

ObjectPuzzle RulesAddDelete
Data Structure
From LogicMake Board
Data StructureMake Board Data
Data Structure
From LogicComputer Sort
Data StructureComputer Sort Data
Logic
Make Board
Arrange Board
Pieces Home
Puzzle Commands
Player Exchange
Piece Press
Input Interruptions
Keyboard Focus
Picture Complete
Computer Sort
Sort Timer
Who Plays
Lesson Panel Switch
Upload Picture
Lesson Lines
Shared Variables
puzzleRulesPuzzle Rules
outlinePiece Outline
piecePiece
puzzleRulesPuzzle Rules

5.5.4 Choose Slot

The keys 1 to 9 and Enter come through Choose Slot. A key hands the board to you at once, even while pieces slide. Then Choose Slot waits for the slide, the same way Piece Press does, before it chooses anything.

FunctionChoose SlotAddDelete

Tells Puzzle Rules that the player chose a slot, as a tap on a piece does. Keys 1 to 9 and Enter use it. A key also lets the player play, even while pieces slide.

PARAMETERS
NameTypeStarts at
puzzleRulesObjectPuzzle Rules
slotNumber0
ACTIONS
1Change Variable
Variable
$chosenSlot
Value
slot
2Trigger Custom Event on Object
Applies to
puzzleRules
Custom Event
pieceChosen
1Let Player PlayFunction
puzzleRules
puzzleRules
2Check Cooldown Ready
Action Name
slideDone
Applies to
puzzleRules
Cooldown Key
"pieceSlide"
3IfslideDone.value == true
Then
4Change Variable
Variable
$chosenSlot
Value
slot
5Trigger Custom Event on Object
Applies to
puzzleRules
Custom Event
pieceChosen

5.5.5 Color Outline

Before Color Outline paints green or amber, it asks whether the computer is playing. Each of those Ifs gains $whoPlays == "Computer", joined to its other tests with &&. Type the whole new condition from the Changes card. Every test must be true.

FunctionColor OutlineAddDelete

Colors one Outline from what is shown on the board now: a settled slot is green, the keyboard focus and a pressed piece are blue, the selected piece is gold, the pair the computer compared last is amber, and every other Outline keeps the normal color. Green and amber are the computer's colors: they show only while the computer plays ($whoPlays).

PARAMETERS
NameTypeStarts at
outlineObjectStructural
Required Components
Slot NameslotNumber
Component TypeData Structure
Required SchemaSlot Number
ACTIONS
1Declare Variable
Name
outlineSlot
Value
0
2Change Variable
Variable
outlineSlot
Value
outline.slotNumber.slot
3Change Sprite Tint Property
Applies to
outline
Value
data('Outline Colors', 'normal', 'color')
4If$comparedSlot >= 0 && outlineSlot < $rangeStart
Then
4If$whoPlays == "Computer" && $comparedSlot >= 0 && outlineSlot < $rangeStart
Then
5Change Sprite Tint Property
Applies to
outline
Value
data('Outline Colors', 'settled', 'color')
6If$comparedSlot >= 0 && outlineSlot > $rangeEnd
Then
6If$whoPlays == "Computer" && $comparedSlot >= 0 && outlineSlot > $rangeEnd
Then
7Change Sprite Tint Property
Applies to
outline
Value
data('Outline Colors', 'settled', 'color')
8IfoutlineSlot == $focusSlot || outlineSlot == $pressedSlot
Then
9Change Sprite Tint Property
Applies to
outline
Value
data('Outline Colors', 'focus', 'color')
10IfoutlineSlot == $selectedSlot
Then
11Change Sprite Tint Property
Applies to
outline
Value
data('Outline Colors', 'selected', 'color')
12If$comparedSlot >= 0 && outlineSlot >= $comparedSlot && outlineSlot <= ($comparedSlot + 1)
Then
12If$whoPlays == "Computer" && $comparedSlot >= 0 && outlineSlot >= $comparedSlot && outlineSlot <= ($comparedSlot + 1)
Then
13Change Sprite Tint Property
Applies to
outline
Value
data('Outline Colors', 'compared', 'color')

5.5.6 Show Outline

Show Outline hears one more message, whoPlaysChanged, so every edge repaints the moment the board changes hands.

Logic ComponentShow OutlineAttach to: Piece OutlineAddDelete

Colors this Outline whenever what it shows may have changed: the player's selection, focus or press, or the computer's compared pair and unsorted range, or who plays.

Attach toAny Object
DATA STRUCTURES
Slot Numberself.slotNumber
On Selection Changed
WhenselectionChangedCustom Event
1Color OutlineFunction
outline
self
On Pair Compared
WhenpairComparedCustom Event
1Color OutlineFunction
outline
self
On Sort Cleared
WhensortClearedCustom Event
1Color OutlineFunction
outline
self
On Pass Finished
WhenpassFinishedCustom Event
1Color OutlineFunction
outline
self
On Who Plays Changed
WhenwhoPlaysChangedCustom Event
1Color OutlineFunction
outline
self

Run the game. Press C, then Step a few times. The amber walks along as before. Press H. The amber is gone, and the edges keep their plain color. Press Step again, and it’s back, because a comparison hands the board to the computer.

5.6 Sort, by Itself

Now the timer. This is the part the whole chapter is for.

Before Sort can run, it needs words for its button, numbers for its speeds, and a way to hear that the sort has ended.

Messages gains seven rows. Two are the button’s own words, Sort and Pause. Paused is what the bottom line says when you stop the sort. The other four wait for later parts.

Data TableMessagesData Structure: Messages EntryAddDelete
Row 0reset
wordsReset.
Row 1selected
wordsChoose another piece.
Row 2solved
wordsPicture complete.
Row 3swapped
wordsSwapped.
Row 4kept
wordsKept.
Row 5invalid
wordsThis puzzle needs each home position exactly once.
Row 6paused
wordsPaused.
Row 7sortButton
wordsSort
Row 8pauseButton
wordsPause
Row 9forwardPass
wordsForward pass.
Row 10backwardPass
wordsBackward pass.
Row 11uploaded
wordsPicture loaded.
Row 12uploadFailed
wordsCould not open that image. Try a PNG, JPEG or WebP.

Sort Speeds is a new table, one row for each speed. Its three columns are the whole feel of a speed. How often the timer rings is intervalSeconds. How many Steps it may ask for on one ring is comparisonsPerTick. And how long a swap’s slide takes is slideSeconds.

Slow rings every 0.4 seconds and asks for 1 Step, so you can follow every pair with your eyes. Steady rings every 0.06 seconds. Fast rings every 0.0167 seconds, and asks for up to 16 Steps each time. Fast’s slides take 0.07 seconds, Steady’s 0.18 and Slow’s 0.35.

The table comes with its own Data Structure, named after it. Make that form’s fields first.

Data StructureSort Speeds Entry

One row of the "Sort Speeds" Data Table.

intervalSecondsNumberdefault 0
comparisonsPerTickNumberdefault 1
slideSecondsNumberdefault 0
Data TableSort SpeedsData Structure: Sort Speeds Entry
Row 0Slow
intervalSeconds0.4
comparisonsPerTick1
slideSeconds0.35
Row 1Steady
intervalSeconds0.06
comparisonsPerTick1
slideSeconds0.18
Row 2Fast
intervalSeconds0.0167
comparisonsPerTick16
slideSeconds0.07

5.6.1 Compare Next Pair

Compare Next Pair is where the computer’s swaps learn to glide. After it counts a swap, it calls Slide Pieces for the same two slots. The seconds come from Sort Speeds, in the row for $speed, so a Slow swap glides longer than a Fast one. It gains a puzzleRules Parameter to hand on.

FunctionCompare Next PairAddDelete

One comparison of the computer: it reads the pieces of a slot and the slot to its right, and swaps them when the left piece's ID is larger. It counts the comparison and any swap, and tells the board.

PARAMETERS
NameTypeStarts at
leftSlotNumber0
puzzleRulesObjectPuzzle Rules
ACTIONS
1Change Variable
Variable
$comparisons
Operator
+=
Value
1
2Ifdata('Board Slots', leftSlot, 'piece') > data('Board Slots', leftSlot + 1, 'piece')
Then
3Exchange SlotsFunction
firstSlot
leftSlot
secondSlot
leftSlot + 1
4Change Variable
Variable
$swaps
Operator
+=
Value
1
5Slide PiecesFunction
puzzleRules
puzzleRules
firstSlot
leftSlot
secondSlot
leftSlot + 1
seconds
data('Sort Speeds', $speed, 'slideSeconds')
6Change Variable
Variable
$message
Value
data('Messages', 'swapped', 'words')
7Otherwise
8Change Variable
Variable
$message
Value
data('Messages', 'kept', 'words')
9Change Variable
Variable
$comparedSlot
Value
leftSlot
10Trigger Custom Event
Custom Event
pairCompared

5.6.2 Request Step

Request Step changes in two ways. First, it sends pauseRequested. A Step you ask for takes the sort out of the timer’s hands, so a running sort stops, and you decide each Step from there. Then it waits for any slide to land before it sends stepRequested.

FunctionRequest StepAddDelete

Asks Puzzle Rules to pause a running sort, then for one Step of the computer's sort once no piece is sliding. The Step Button and the Step Command (Space) both use it.

PARAMETERS
NameTypeStarts at
puzzleRulesObjectPuzzle Rules
ACTIONS
1Trigger Custom Event on Object
Applies to
puzzleRules
Custom Event
pauseRequested
Custom Event
stepRequested
2Check Cooldown Ready
Action Name
slideDone
Applies to
puzzleRules
Cooldown Key
"pieceSlide"
3IfslideDone.value == true
Then
4Trigger Custom Event on Object
Applies to
puzzleRules
Custom Event
stepRequested

5.6.3 Request Sort and Request Lesson

Two more Functions have Request Step’s old shape, one message each. Request Sort sends sortRequested. It’s for the Sort button and A. And for the How it works button and F, Request Lesson sends lessonRequested, a message the panel will answer. Nothing listens for lessonRequested yet. The last part will.

FunctionRequest Sort

Asks Puzzle Rules to start the computer's sort, or to pause it while it runs. The Sort Button and the Run or Pause Command (A) both use it.

PARAMETERS
NameTypeStarts at
puzzleRulesObjectPuzzle Rules
ACTIONS
1Trigger Custom Event on Object
Applies to
puzzleRules
Custom Event
sortRequested
FunctionRequest Lesson

Asks Puzzle Rules to open the How it works panel. The How it works Button and the How It Works Command (F) both use it.

PARAMETERS
NameTypeStarts at
puzzleRulesObjectPuzzle Rules
ACTIONS
1Trigger Custom Event on Object
Applies to
puzzleRules
Custom Event
lessonRequested

Puzzle Commands learns the two new keys, A and F, and each one calls its own new Function.

Logic ComponentPuzzle CommandsAttach to: Puzzle RulesAddDelete

The keys ask for the same things as the Buttons: R for Reset, N for a new arrangement. Escape cancels a selection. Space asks the computer for one Step. A starts or pauses the computer's sort, and F opens the How it works panel.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
puzzleRulesObjectConstantNone
When Reset Is Pressed
WhenCommand PressedCommand: Reset
1Request ResetFunction
puzzleRules
@self.puzzleRules
When New Is Pressed
WhenCommand PressedCommand: New Arrangement
1Request ShuffleFunction
puzzleRules
@self.puzzleRules
When Cancel Is Pressed
WhenCommand PressedCommand: Cancel
1Trigger Custom Event on Object
Custom Event
selectionCanceled
When Step Is Pressed
WhenCommand PressedCommand: Step
1Request StepFunction
puzzleRules
@self.puzzleRules
When Run Is Pressed
WhenCommand PressedCommand: Run or Pause
1Request SortFunction
puzzleRules
@self.puzzleRules
When Lesson Is Pressed
WhenCommand PressedCommand: How It Works
1Request LessonFunction
puzzleRules
@self.puzzleRules

5.6.4 Computer Sort

Computer Sort learns to speak up about two things it already does. Each call to Compare Next Pair passes puzzleRules now.

Every time a pass begins, Computer Sort says which way, with forwardPassStarted or backwardPassStarted. The How it works panel will listen. And when the sort can’t go on, it says sortEnded. That happens on a board it refuses, in Fresh’s Otherwise. It happens when a pass ends the sort, right after the small If switches to Finished, in both passes. And it happens when every piece comes home.

Logic ComponentComputer SortAttach to: Puzzle RulesAddDelete

The computer's cocktail shaker sort, one comparison per Step. The first Step on a board checks it and begins a forward pass from the first slot. Passes then go back and forth over the unsorted range, which shrinks by one slot at the end of each pass, until every piece is home or a pass makes no swaps. When the sort is finished, or the board cannot be sorted, it sends sortEnded.

Attach toAny Object
DATA STRUCTURES
Computer Sort Dataself.computerSortData
SHARED VARIABLES
NameTypeKindStarting Value
puzzleRulesObjectConstantNone
On Step Requested
WhenstepRequestedCustom Event
ModeFresh (Starting Mode)
1Check Board ValidFunction
Action Name
boardCheck
2IfboardCheck.value == true
Then
3Change Variable
Variable
$rangeStart
Value
0
4Change Variable
Variable
$rangeEnd
Value
$gridSize * $gridSize - 1
5Change Component Value
Component Value
self.computerSortData.swapsBeforePass
Value
$swaps
6Compare Next PairFunction
leftSlot
$rangeStart
puzzleRules
@self.puzzleRules
7Switch Mode
Event
On Step Requested
Mode
Forward Pass
8Trigger Custom Event on Object
Custom Event
forwardPassStarted
9Otherwise
10Change Variable
Variable
$message
Value
data('Messages', 'invalid', 'words')
11Trigger Custom Event on Object
Custom Event
sortEnded
On Step Requested
WhenstepRequestedCustom Event
ModeForward Pass
1Compare Next PairFunction
leftSlot
$comparedSlot + 1
puzzleRules
@self.puzzleRules
2If($comparedSlot + 1) == $rangeEnd
Then
3Change Variable
Variable
$rangeEnd
Operator
-=
Value
1
4Finish Sort PassFunction
Action Name
forwardPassEnd
swapsBeforePass
self.computerSortData.swapsBeforePass
5IfforwardPassEnd.value == false
Then
6Switch Mode
Event
On Step Requested
Mode
Finished
7Trigger Custom Event on Object
Custom Event
sortEnded
8Trigger Custom Event
Custom Event
passFinished
9IfforwardPassEnd.value == true
Then
10Switch Mode
Event
On Step Requested
Mode
Backward Pass
11Trigger Custom Event on Object
Custom Event
backwardPassStarted
12Change Component Value
Component Value
self.computerSortData.swapsBeforePass
Value
$swaps
On Step Requested
WhenstepRequestedCustom Event
ModeBackward Pass
1Compare Next PairFunction
leftSlot
$comparedSlot - 1
puzzleRules
@self.puzzleRules
2If$comparedSlot == $rangeStart
Then
3Change Variable
Variable
$rangeStart
Operator
+=
Value
1
4Finish Sort PassFunction
Action Name
backwardPassEnd
swapsBeforePass
self.computerSortData.swapsBeforePass
5IfbackwardPassEnd.value == false
Then
6Switch Mode
Event
On Step Requested
Mode
Finished
7Trigger Custom Event on Object
Custom Event
sortEnded
8Trigger Custom Event
Custom Event
passFinished
9IfbackwardPassEnd.value == true
Then
10Switch Mode
Event
On Step Requested
Mode
Forward Pass
11Trigger Custom Event on Object
Custom Event
forwardPassStarted
12Change Component Value
Component Value
self.computerSortData.swapsBeforePass
Value
$swaps
On Step Requested
WhenstepRequestedCustom Event
ModeFinished
(no Actions)
On Board Arranged
WhenboardArrangedCustom Event
1Switch Mode
Event
On Step Requested
Mode
Fresh
2Clear SortFunction
On Pieces Exchanged
WhenpiecesExchangedCustom Event
1Switch Mode
Event
On Step Requested
Mode
Fresh
2Clear SortFunction
On Variable Changed · Pieces Home
WhenVariable ChangedGlobal Variable: piecesHome
1If$piecesHome == ($gridSize * $gridSize)
Then
2Switch Mode
Event
On Step Requested
Mode
Finished
3Trigger Custom Event on Object
Custom Event
sortEnded

5.6.5 Sort Timer

Sort Timer runs the sort by itself, from Puzzle Rules. Take it beat by beat.

Its sortRequested Event has two Modes, Stopped and Running. Stopped is where it starts. A press of Sort there asks one question: is some piece still away from home? If so, it lets the computer play, clears the bottom line, and starts the timer. A press of Sort in Running pauses. It stops the timer and says Paused.

Its speedChosen Event has the same two Modes, Stopped and Running, with a different job in each. Stopped does nothing, because a sort that isn’t running only needs $speed for later. Running starts the timer again, so the new speed takes hold at once.

Two Functions start and stop the timer. They can’t switch Modes, so Sort Timer switches both of those Events itself, with two Switch Modes just before each call. Those pick their Modes from lists, and they work on Sort Timer itself, so their Applies To stays Self. So make the sortRequested and speedChosen Events first, each with its two Modes and no Actions yet. Make its puzzleRules Shared Variable from its card first. Then attach Sort Timer to Puzzle Rules, using Puzzle Rules’ puzzleRules Shared Variable.

5.6.6 Start Sort Timer

Start Sort Timer starts the pictureSort timer on Puzzle Rules. Start Recurring Timer reads how often it rings from Sort Speeds, and starting it again gives it the new beat. Then the button’s word becomes Pause. Sort Timer has already switched both Events to Running before it calls this.

FunctionStart Sort Timer

Starts the pictureSort timer at the chosen speed (or starts it again at a new speed) and makes the Sort Button read Pause.

PARAMETERS
NameTypeStarts at
puzzleRulesObjectPuzzle Rules
ACTIONS
1Start Recurring Timer
Applies to
puzzleRules
Timer Name
"pictureSort"
Repeat Every (s)
data('Sort Speeds', $speed, 'intervalSeconds')
2Change Variable
Variable
$sortButtonLabel
Value
data('Messages', 'pauseButton', 'words')

5.6.7 Stop Sort Timer

Stop Sort Timer undoes both. The timer stops, and the button reads Sort. Before each call, Sort Timer switches both Events back to Stopped. The board, the pass and the counters stay as they are, waiting for the next Sort or Step. That’s what makes Pause a pause.

FunctionStop Sort Timer

Stops the pictureSort timer and makes the Sort Button read Sort. The board, the pass and the counters stay as they are.

PARAMETERS
NameTypeStarts at
puzzleRulesObjectPuzzle Rules
ACTIONS
1Stop Recurring Timer
Applies to
puzzleRules
Timer Name
"pictureSort"
2Change Variable
Variable
$sortButtonLabel
Value
data('Messages', 'sortButton', 'words')

Now fill in Sort Timer. Here are its first three Events: when the game starts, Sort, and a new speed. The last two each show twice on the card, once for each Mode.

When the game starts, Sort Timer switches both Events to Stopped and calls Stop Sort Timer. Nothing is running yet. But $sortButtonLabel starts empty, and this is what first writes Sort on the button.

Logic ComponentSort TimerAttach to: Puzzle Rules

Runs the computer's sort by itself: Sort lets the computer play and starts the pictureSort timer, and every ring of the timer asks Computer Sort for Steps at the chosen speed. Sort again, a Step, the player taking over, a player exchange, Reset, Shuffle, Escape or opening the How it works panel pauses it, and it stops when the sort has ended. The board, the pass and the counters are kept.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
puzzleRulesObjectConstantNone
When the Game Starts
WhenGame Start
1Switch Mode
Event
On Sort Requested
Mode
Stopped
2Switch Mode
Event
On Speed Chosen
Mode
Stopped
3Stop Sort TimerFunction
puzzleRules
@self.puzzleRules
On Sort Requested
WhensortRequestedCustom Event
ModeStopped (Starting Mode)
1If$piecesHome < ($gridSize * $gridSize)
Then
2Let Computer PlayFunction
puzzleRules
@self.puzzleRules
3Change Variable
Variable
$message
Value
""
4Switch Mode
Event
On Sort Requested
Mode
Running
5Switch Mode
Event
On Speed Chosen
Mode
Running
6Start Sort TimerFunction
puzzleRules
@self.puzzleRules
On Sort Requested
WhensortRequestedCustom Event
ModeRunning
1Switch Mode
Event
On Sort Requested
Mode
Stopped
2Switch Mode
Event
On Speed Chosen
Mode
Stopped
3Stop Sort TimerFunction
puzzleRules
@self.puzzleRules
4Change Variable
Variable
$message
Value
data('Messages', 'paused', 'words')
On Speed Chosen
WhenspeedChosenCustom Event
ModeStopped (Starting Mode)
(no Actions)
On Speed Chosen
WhenspeedChosenCustom Event
ModeRunning
1Switch Mode
Event
On Sort Requested
Mode
Running
2Switch Mode
Event
On Speed Chosen
Mode
Running
3Start Sort TimerFunction
puzzleRules
@self.puzzleRules

Then the ring itself. Every time pictureSort rings, a Repeat asks for as many Steps as the speed’s comparisonsPerTick. Before each one, it checks two things. Is some piece still away from home, with the picture not yet whole? And has every slide landed? When both answers are yes, it sends stepRequested to Computer Sort.

That’s why a ring at Fast stops early. Sixteen Steps in a row would rush past the pieces before any of them could glide. But the first swap starts a slide, and the rest of that ring’s Steps find the cooldown running. The next ring tries again.

You might wonder why the ring doesn’t call Request Step. It would pause the sort, the very sort that’s asking for a Step.

After the ring come five more Events. Each has the same three Actions: two Switch Modes back to Stopped, then Stop Sort Timer. A pause, the end of the sort, a new arrangement, your own exchange or Escape stops the timer.

Logic ComponentSort Timercontinued
On the Picture Sort Timer
WhenRecurring TimerTimer name: pictureSort
1Repeatdata('Sort Speeds', $speed, 'comparisonsPerTick')times
Each time
2Check Cooldown Ready
Action Name
slideDone
Cooldown Key
"pieceSlide"
3If$piecesHome < ($gridSize * $gridSize) && slideDone.value == true
Then
4Trigger Custom Event on Object
Custom Event
stepRequested
On Pause Requested
WhenpauseRequestedCustom Event
1Switch Mode
Event
On Sort Requested
Mode
Stopped
2Switch Mode
Event
On Speed Chosen
Mode
Stopped
3Stop Sort TimerFunction
puzzleRules
@self.puzzleRules
On Sort Ended
WhensortEndedCustom Event
1Switch Mode
Event
On Sort Requested
Mode
Stopped
2Switch Mode
Event
On Speed Chosen
Mode
Stopped
3Stop Sort TimerFunction
puzzleRules
@self.puzzleRules
On Board Arranged
WhenboardArrangedCustom Event
1Switch Mode
Event
On Sort Requested
Mode
Stopped
2Switch Mode
Event
On Speed Chosen
Mode
Stopped
3Stop Sort TimerFunction
puzzleRules
@self.puzzleRules
On Pieces Exchanged
WhenpiecesExchangedCustom Event
1Switch Mode
Event
On Sort Requested
Mode
Stopped
2Switch Mode
Event
On Speed Chosen
Mode
Stopped
3Stop Sort TimerFunction
puzzleRules
@self.puzzleRules
On Selection Canceled
WhenselectionCanceledCustom Event
1Switch Mode
Event
On Sort Requested
Mode
Stopped
2Switch Mode
Event
On Speed Chosen
Mode
Stopped
3Stop Sort TimerFunction
puzzleRules
@self.puzzleRules

5.6.8 The Sort Button

The Sort button is an Object of its own, blue, with the live word {$sortButtonLabel}. Its picture is Gold Face, which is blue on screen. Its Command Variable says Sort, and Button Action calls Request Sort.

ObjectSort Button
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 164, Y 45
Text / UI
Text{$sortButtonLabel}
Font Size16
EmphasisSemibold
AlignmentCenter
RenderingVector
Sprite
Z Index Within Object-1
SpriteGold Face
Transform > SizeX 164, Y 45
UI Interaction(as it is added)
Logic
Button Action
Shared Variables
puzzleRulesPuzzle Rules

It uses Button Action too. That Logic gains one question here. Before it reads its command, it asks Check Input Context Active whether the Puzzle Controls are on. They always are, until the last part, where the panel switches them off. Its If compares a Boolean.

The Changes card adds Button Action’s command branches. Build Sort and Lesson now, because their Request Functions exist. Upload waits until Request Upload is made in Three pictures and one of your own.

Logic ComponentButton ActionAttach to: Puzzle Button, Sort ButtonAddDelete

Clicking or tapping a Puzzle Button runs the Request Function of its command: Reset, Shuffle, Step, Sort, Upload or Lesson. Each placement sets its own command and its own text. While the How it works panel is open, the Button does nothing.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
puzzleRulesObjectConstantNone
PER INSTANCE VARIABLES
NameTypeStarting Value
commandTextReset
On Hud Activated
WhenUI Activated
1Ifself.command == "Reset"
Then
2Request ResetFunction
puzzleRules
@self.puzzleRules
3Ifself.command == "Shuffle"
Then
4Request ShuffleFunction
puzzleRules
@self.puzzleRules
5Ifself.command == "Step"
Then
6Request StepFunction
puzzleRules
@self.puzzleRules
1Check Input Context Active
Action Name
puzzleControlsOn
Input Context
Puzzle Controls
2IfpuzzleControlsOn.value == true
Then
3Ifself.command == "Reset"
Then
4Request ResetFunction
puzzleRules
@self.puzzleRules
5Ifself.command == "Shuffle"
Then
6Request ShuffleFunction
puzzleRules
@self.puzzleRules
7Ifself.command == "Step"
Then
8Request StepFunction
puzzleRules
@self.puzzleRules
9Ifself.command == "Sort"
Then
10Request SortFunction
puzzleRules
@self.puzzleRules
11Ifself.command == "Upload"
Then
12Request UploadFunction
puzzleRules
@self.puzzleRules
13Ifself.command == "Lesson"
Then
14Request LessonFunction
puzzleRules
@self.puzzleRules

Place the Sort button from PLACE THESE, at 900 and -677. Its Command Variable is Sort. Its puzzleRules Shared Variable names Puzzle Rules.

5.6.9 Slow, Steady and Fast

Some Object cards name Logic you’ll make later in this part. Make the Object first, then attach that Logic when its card comes. Later parts follow that order too.

Three Speed Buttons sit in a row under the word Speed, with a short blue line under the chosen one. The line’s picture is Gold Face, the same blue as the Sort button. That’s three new Objects: the Speed Caption, the Speed Button and the Speed Underline.

ObjectSpeed Caption
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Text / UI
TextSpeed
Font Size13
EmphasisSemibold
Color#526478
RenderingVector
ObjectSpeed Button
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 92, Y 36
Text / UI
TextSpeed
Font Size16
EmphasisSemibold
Color#263D54
AlignmentCenter
RenderingVector
Sprite
Z Index Within Object-1
SpriteButton Face
Transform > SizeX 92, Y 36
UI Interaction(as it is added)
Logic
Choose Speed
ObjectSpeed Underline
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 88, Y 3
Sprite
Z Index Within Object-1
SpriteGold Face
Transform > SizeX 88, Y 3
Logic
Show Speed Underline

Choose Speed is the button’s Logic. It asks the Puzzle Controls the same question as Button Action. Then it writes its own speed, a Text Per Instance Variable, into $speed, and sends speedChosen.

Logic ComponentChoose SpeedAttach to: Speed Button

Clicking or tapping a Speed Button makes its speed the chosen one. Each placement sets its speed (a row of Sort Speeds) and its text. While the How it works panel is open, the Button does nothing.

Attach toAny Object
PER INSTANCE VARIABLES
NameTypeStarting Value
speedTextFast
On Hud Activated
WhenUI Activated
1Check Input Context Active
Action Name
puzzleControlsOn
Input Context
Puzzle Controls
2IfpuzzleControlsOn.value == true
Then
3Change Variable
Variable
$speed
Value
self.speed
4Trigger Custom Event
Custom Event
speedChosen

Underline Chosen Speed shows one underline when its speed is the chosen one, and hides it otherwise. Show Speed Underline calls it when the underline is made. It calls it again at every speedChosen.

FunctionUnderline Chosen Speed

Shows one speed underline when its speed is the chosen one, and hides it otherwise.

PARAMETERS
NameTypeStarts at
underlineObject
speedTextFast
ACTIONS
1Ifspeed == $speed
Then
2Set Visible
Applies to
underline
Visible
true
3Otherwise
4Set Visible
Applies to
underline
Visible
false
Logic ComponentShow Speed UnderlineAttach to: Speed Underline

Shows this underline under the chosen speed's Button only. Each placement sets the speed it stands for.

Attach toAny Object
PER INSTANCE VARIABLES
NameTypeStarting Value
speedTextFast
When Created
WhenCreate
1Underline Chosen SpeedFunction
underline
self
speed
self.speed
On Speed Chosen
WhenspeedChosenCustom Event
1Underline Chosen SpeedFunction
underline
self
speed
self.speed

Place the Speed Caption, then the three Speed Buttons and their three Underlines, from PLACE THESE. Each button and the underline under it share one word, Slow, Steady or Fast: in the button’s Text, and in both Speed Variable fields.

Run the game, and press Sort. The button reads Pause, and the board comes alive. Pairs glide past each other, the amber flickers along the rows, and green creeps in from both ends.

5.7 Nine, Twenty-Five or Sixty-Four

Next, the board learns three sizes.

The board is made once, when the game starts, for the largest size: 64 slots. A smaller board uses its first slots and hides the rest. Each slot it keeps grows.

Piece Counts is a new table, one row for each size. Its gridSize is how many slots fill a row, such as the 3 of a board of 9 pieces, three rows of three. Its piecesColumn names the column of Pictures that holds the picture cut for that size.

The table comes with its own Data Structure, named after it. Make that form’s fields first.

Data StructurePiece Counts Entry

One row of the "Piece Counts" Data Table.

gridSizeNumberdefault 8
piecesColumnTextdefault (empty)
Data TablePiece CountsData Structure: Piece Counts Entry
Row 09 Pieces
gridSize3
piecesColumnpieces9
Row 125 Pieces
gridSize5
piecesColumnpieces25
Row 264 Pieces
gridSize8
piecesColumnpieces64

Pictures is a table of Sprites, one row for each picture. Each row holds the picture whole, for the Preview, and cut three ways. Pick each cell’s Sprite from its list.

The table comes with its own Data Structure, named after it. Make that form’s fields first.

Data StructurePictures Entry

One row of the "Pictures" Data Table.

previewThing Spritedefault None
pieces9Thing Spritedefault None
pieces25Thing Spritedefault None
pieces64Thing Spritedefault None
Data TablePicturesData Structure: Pictures Entry
Row 0Village
previewVillage Picture
pieces9Village Pieces 9
pieces25Village Pieces 25
pieces64Village Pieces 64
Row 1Forest
previewForest Picture
pieces9Forest Pieces 9
pieces25Forest Pieces 25
pieces64Forest Pieces 64
Row 2Harbor
previewHarbor Picture
pieces9Harbor Pieces 9
pieces25Harbor Pieces 25
pieces64Harbor Pieces 64
Row 3Uploaded
previewUploaded Picture
pieces9Uploaded Pieces 9
pieces25Uploaded Pieces 25
pieces64Uploaded Pieces 64

5.7.1 Choose Piece Sprite

Choose Piece Sprite gives a Piece the right cut of the right picture. It looks in Piece Counts for the row whose gridSize is the board’s, with dataFind. That formula answers a row’s number, or -1 when no row matches. The row names the column, and $picture names the row of Pictures. Set Sprite does the rest.

Its piece input names no Object, so it stays on Structural, with nothing under it.

FunctionChoose Piece Sprite

Gives a Piece the Sprite of the chosen picture cut for the chosen piece count: Piece Counts names the column of Pictures for the board's gridSize, and $picture names the row.

PARAMETERS
pieceObject
ACTIONS
1Declare Variable
Name
countRow
Value
0
2Declare Variable
Type
Text
Name
piecesColumn
3Change Variable
Variable
countRow
Value
dataFind('Piece Counts', 'gridSize', $gridSize)
4IfcountRow >= 0
Then
5Change Variable
Variable
piecesColumn
Value
data('Piece Counts', countRow, 'piecesColumn')
6Set Sprite
Applies to
piece
Sprite
data('Pictures', $picture, piecesColumn)

5.7.2 Show Piece

Show Piece calls Choose Piece Sprite before it shows its frame, when it’s placed and after every new arrangement.

Logic ComponentShow PieceAttach to: PieceAddDelete

Shows the picture frame of the piece that Board Slots puts in this Piece's slot, cut for the chosen piece count. Make Board gives each Piece its slot in its Slot Number (0 is the top-left slot, counting right, then down).

Attach toAny Object
DATA STRUCTURES
Slot Numberself.slotNumber
On Placed on Board
WhenplacedOnBoardCustom Event
1Choose Piece SpriteFunction
piece
self
2Set Frame
Frame
data('Board Slots', self.slotNumber.slot, 'piece')
On Board Arranged
WhenboardArrangedCustom Event
1Choose Piece SpriteFunction
piece
self
2Set Frame
Frame
data('Board Slots', self.slotNumber.slot, 'piece')
On Pieces Exchanged
WhenpiecesExchangedCustom Event
1Set Frame
Frame
data('Board Slots', self.slotNumber.slot, 'piece')
On Pair Compared
WhenpairComparedCustom Event
1Set Frame
Frame
data('Board Slots', self.slotNumber.slot, 'piece')

5.7.3 Lay Out One Slot

Lay Out One Slot puts one Piece or Outline where the board’s size wants it. Is its slot on the board? Then it’s shown, set on its slot’s middle, and scaled. A slot is $boardSide / $gridSize pixels across, so on 9 pieces it’s a third of the board. The Object was drawn to fit a slot of drawnSlotSide, 70 pixels, so its scale is slotSide, the slot’s side, divided by drawnSlotSide. A slot past the end of the board is hidden, and a hidden Piece answers no press.

FunctionLay Out One Slot

Lays out one Piece or Outline for the board's piece count: a slot on the board is shown at its center and sized to the slot; a slot beyond the piece count is hidden, so it shows nothing and answers no input. drawnSlotSide is the slot side, in screen pixels, that the Object fits at scale 1.

PARAMETERS
NameTypeStarts at
slotObjectObjectStructural
Required Components
Slot NameslotNumber
Component TypeData Structure
Required SchemaSlot Number
drawnSlotSideNumber70
ACTIONS
1Declare Variable
Name
slotSide
Value
0
2IfslotObject.slotNumber.slot < ($gridSize * $gridSize)
Then
3Set Visible
Applies to
slotObject
Visible
true
4Slot CenterFunction
Action Name
center
slot
slotObject.slotNumber.slot
5Set Position
Applies to
slotObject
Position Relative To
Screen
X
center.x
Y
center.y
6Change Variable
Variable
slotSide
Value
$boardSide / $gridSize
7Set Scale
Applies to
slotObject
Horizontal Scale
slotSide / drawnSlotSide
Vertical Scale
slotSide / drawnSlotSide
8Otherwise
9Set Visible
Applies to
slotObject
Visible
false

5.7.4 Lay Out Slot

Lay Out Slot hands both its jobs to Lay Out One Slot now. Its old Slot Center and Set Position come out, and it gains a Shared Variable, drawnSlotSide, and an Event, boardArranged, for every new size.

The Piece Outline keeps drawnSlotSide at 70. Its square already fills the whole slot, and that same measure sets every new scale.

Logic ComponentLay Out SlotAttach to: Piece Outline, PieceAddDelete

Places this Piece or Outline for the board's piece count: on its slot's center and sized to the slot when the slot is on the board, hidden when it is not. drawnSlotSide is the slot side, in screen pixels, that the Object fits at scale 1 (70, a slot of the 64-piece board).

Attach toAny Object
DATA STRUCTURES
Slot Numberself.slotNumber
SHARED VARIABLES
NameTypeKindStarting Value
drawnSlotSideNumberConstant70
On Placed on Board
WhenplacedOnBoardCustom Event
1Slot CenterFunction
Action Name
center
slot
self.slotNumber.slot
2Set Position
Position Relative To
Screen
X
center.x
Y
center.y
1Lay Out One SlotFunction
slotObject
self
drawnSlotSide
@self.drawnSlotSide
On Board Arranged
WhenboardArrangedCustom Event
1Lay Out One SlotFunction
slotObject
self
drawnSlotSide
@self.drawnSlotSide

5.7.5 Make Board

Make Board finds the largest size in the last row of Piece Counts. dataCount answers how many rows a table has, so the last row is one less. It makes that size squared: 64 slots.

The rest of the board was ready already. One question changes, in the If at the end of When the Game Starts. Since Chapter 1, that If has sent a Shuffle when the count of slots is a multiple of 5, where every fifth piece wouldn’t deal each piece once. Now a game that starts at a smaller size gets a Shuffle too.

Keep the If and its request. Replace its condition with the card’s whole formula: the board starts smaller, or its slot count is a multiple of 5. The || joins those two tests. The struck If is the old condition; the green one is its replacement.

Logic ComponentMake BoardAttach to: Puzzle RulesAddDelete

Makes the board when the game begins: a row of Board Slots for each slot, holding the starting arrangement, and on the screen an Outline with a Piece in front of it for each slot. The board is made once, for the largest piece count (the last row of Piece Counts); a smaller piece count uses its first slots and hides the rest (Lay Out Slot). The starting arrangement takes every fifth piece; a board where that would not hold each piece once (a piece count that is a multiple of 5, or a game that starts at a smaller count) starts with a Shuffle instead. slotCount is how many slots it makes; outline and piece are the Objects it makes.

Attach toAny Object
DATA STRUCTURES
Make Board Dataself.makeBoardData
SHARED VARIABLES
NameTypeKindStarting Value
outlineObjectConstantNone
pieceObjectConstantNone
When the Game Starts
WhenGame Start
1Declare Variable
Name
largestGridSize
Value
0
2Change Variable
Variable
largestGridSize
Value
data('Piece Counts', dataCount('Piece Counts') - 1, 'gridSize')
3Change Component Value
Component Value
self.makeBoardData.slotCount
Value
largestGridSize * largestGridSize
Value
$gridSize * $gridSize
4Repeatself.makeBoardData.slotCounttimes
Each time
5Control Data Row
Action Name
addedRow
Table
Board Slots
Row
text("Slot ", local.index + 1)
6Set Data Cell
Table
Board Slots
Row
local.index
Column
"piece"
Value
(5 * local.index + 3) % self.makeBoardData.slotCount
7Set Data Cell
Table
Board Slots
Row
local.index
Column
"startPiece"
Value
data('Board Slots', local.index, 'piece')
8Trigger Custom Event on Object
Custom Event
boardMade
7If(self.makeBoardData.slotCount % 5) == 0
Then
9If$gridSize != largestGridSize || (self.makeBoardData.slotCount % 5) == 0
Then
10Trigger Custom Event on Object
Custom Event
shuffleRequested
When the Scene Starts
WhenScene Start
1Repeatself.makeBoardData.slotCounttimes
Each time
2Create Instance
Object to Create
@self.outline
X
0
Y
0
Created As
newOutline
3Change Variable
Variable
newOutline.slot
Value
local.index
4Trigger Custom Event on Object
Applies to
newOutline
Custom Event
placedOnBoard
5Create Instance
Object to Create
@self.piece
X
0
Y
0
Created As
newPiece
6Change Variable
Variable
newPiece.slot
Value
local.index
7Trigger Custom Event on Object
Applies to
newPiece
Custom Event
placedOnBoard

5.7.6 Arrange Board

Arrange Board learns that a new size or a new picture means a new deal. Both send a Shuffle. Reset and Shuffle also start the pieceSlide cooldown again at 0 seconds, so a slide under way ends at once.

Logic ComponentArrange BoardAttach to: Puzzle RulesAddDelete

Lays out a whole new arrangement when it is asked: Reset puts the starting arrangement back, Shuffle makes a new one, and so does a new piece count or a new picture. Then it tells every Piece that the board was arranged.

Attach toAny Object
On Reset Requested
WhenresetRequestedCustom Event
1Restore Start ArrangementFunction
2Change Variable
Variable
$message
Value
data('Messages', 'reset', 'words')
3Start Cooldown
Cooldown Key
"pieceSlide"
Seconds
0
4Trigger Custom Event
Custom Event
boardArranged
On Shuffle Requested
WhenshuffleRequestedCustom Event
1Shuffle BoardFunction
2Change Variable
Variable
$message
Value
""
3Start Cooldown
Cooldown Key
"pieceSlide"
Seconds
0
4Trigger Custom Event
Custom Event
boardArranged
On Piece Count Chosen
WhenpieceCountChosenCustom Event
1Trigger Custom Event on Object
Custom Event
shuffleRequested
On Picture Chosen
WhenpictureChosenCustom Event
1Trigger Custom Event on Object
Custom Event
shuffleRequested

5.7.7 Hide Focus

Hide Focus takes the keyboard’s blue focus off the board. It’s the two steps Keyboard Focus did on a press, made into a Function, because a new size needs them too. The focus could be sitting on a slot the new board hides.

FunctionHide Focus

Hides the keyboard focus ($focusSlot -1), and tells the Outlines.

ACTIONS
1Change Variable
Variable
$focusSlot
Value
-1
2Trigger Custom Event
Custom Event
selectionChanged

Keyboard Focus calls Hide Focus on a press, where those two steps were. It gains a pieceCountChosen Event that calls it too.

Logic ComponentKeyboard FocusAttach to: Puzzle RulesAddDelete

The keyboard plays like the pointer: keys 1 to 9 choose a slot, the arrow keys move a blue focus over the board, and Enter chooses the focused slot.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
puzzleRulesObjectConstantNone
When Piece1 Is Pressed
WhenCommand PressedCommand: Choose Piece 1
1Choose SlotFunction
puzzleRules
@self.puzzleRules
slot
0
When Piece2 Is Pressed
WhenCommand PressedCommand: Choose Piece 2
1Choose SlotFunction
puzzleRules
@self.puzzleRules
slot
1
When Piece3 Is Pressed
WhenCommand PressedCommand: Choose Piece 3
1Choose SlotFunction
puzzleRules
@self.puzzleRules
slot
2
When Piece4 Is Pressed
WhenCommand PressedCommand: Choose Piece 4
1Choose SlotFunction
puzzleRules
@self.puzzleRules
slot
3
When Piece5 Is Pressed
WhenCommand PressedCommand: Choose Piece 5
1Choose SlotFunction
puzzleRules
@self.puzzleRules
slot
4
When Piece6 Is Pressed
WhenCommand PressedCommand: Choose Piece 6
1Choose SlotFunction
puzzleRules
@self.puzzleRules
slot
5
When Piece7 Is Pressed
WhenCommand PressedCommand: Choose Piece 7
1Choose SlotFunction
puzzleRules
@self.puzzleRules
slot
6
When Piece8 Is Pressed
WhenCommand PressedCommand: Choose Piece 8
1Choose SlotFunction
puzzleRules
@self.puzzleRules
slot
7
When Piece9 Is Pressed
WhenCommand PressedCommand: Choose Piece 9
1Choose SlotFunction
puzzleRules
@self.puzzleRules
slot
8
When Left Is Pressed
WhenCommand PressedCommand: Focus Left
1Move FocusFunction
distance
-1
When Right Is Pressed
WhenCommand PressedCommand: Focus Right
1Move FocusFunction
distance
1
When Up Is Pressed
WhenCommand PressedCommand: Focus Up
1Move FocusFunction
distance
-$gridSize
When Down Is Pressed
WhenCommand PressedCommand: Focus Down
1Move FocusFunction
distance
$gridSize
When Select Is Pressed
WhenCommand PressedCommand: Select Focused Piece
1If$focusSlot >= 0
Then
2Choose SlotFunction
puzzleRules
@self.puzzleRules
slot
$focusSlot
On Piece Pressed
WhenpiecePressedCustom Event
1Change Variable
Variable
$focusSlot
Value
-1
2Trigger Custom Event
Custom Event
selectionChanged
1Hide FocusFunction
On Piece Count Chosen
WhenpieceCountChosenCustom Event
1Hide FocusFunction

5.7.8 The Count Buttons

Three Count Buttons sit under the word Pieces, with their own blue underlines. They work the way the Speed Buttons do. Your hands know this one.

ObjectPieces Caption
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Text / UI
TextPieces
Font Size13
EmphasisSemibold
Color#526478
RenderingVector
ObjectCount Button
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 92, Y 36
Text / UI
TextCount
Font Size16
EmphasisSemibold
Color#263D54
AlignmentCenter
RenderingVector
Sprite
Z Index Within Object-1
SpriteButton Face
Transform > SizeX 92, Y 36
UI Interaction(as it is added)
Logic
Choose Piece Count
ObjectCount Underline
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 88, Y 3
Sprite
Z Index Within Object-1
SpriteGold Face
Transform > SizeX 88, Y 3
Logic
Show Count Underline

Choose Piece Count reads its pieceCount, a row’s name such as 9 Pieces. It writes that row’s gridSize into $gridSize and sends pieceCountChosen.

Logic ComponentChoose Piece CountAttach to: Count Button

Clicking or tapping a Count Button makes its piece count the board's: $gridSize becomes the count's gridSize, and a new arrangement of that size is shuffled. Each placement sets its count (a row of Piece Counts) and its text. While the How it works panel is open, the Button does nothing.

Attach toAny Object
PER INSTANCE VARIABLES
NameTypeStarting Value
pieceCountText64 Pieces
On Hud Activated
WhenUI Activated
1Check Input Context Active
Action Name
puzzleControlsOn
Input Context
Puzzle Controls
2IfpuzzleControlsOn.value == true
Then
3Change Variable
Variable
$gridSize
Value
data('Piece Counts', self.pieceCount, 'gridSize')
4Trigger Custom Event
Custom Event
pieceCountChosen
FunctionUnderline Chosen Count

Shows one piece-count underline when its count is the board's, and hides it otherwise.

PARAMETERS
NameTypeStarts at
underlineObject
pieceCountText64 Pieces
ACTIONS
1Ifdata('Piece Counts', pieceCount, 'gridSize') == $gridSize
Then
2Set Visible
Applies to
underline
Visible
true
3Otherwise
4Set Visible
Applies to
underline
Visible
false
Logic ComponentShow Count UnderlineAttach to: Count Underline

Shows this underline under the chosen piece count's Button only. Each placement sets the count it stands for.

Attach toAny Object
PER INSTANCE VARIABLES
NameTypeStarting Value
pieceCountText64 Pieces
When Created
WhenCreate
1Underline Chosen CountFunction
underline
self
pieceCount
self.pieceCount
On Piece Count Chosen
WhenpieceCountChosenCustom Event
1Underline Chosen CountFunction
underline
self
pieceCount
self.pieceCount

Place the caption, the buttons and the underlines. Each button and its underline share a row’s name, such as 25 Pieces, and the button’s Text is the number alone.

Run the game, and press 9. Nine big pieces fill the board, shuffled, and the caption reads 0 / 9, or close to it. A shuffle can drop a piece home by chance.

5.8 Three Pictures and One of Your Own

Next, the Preview learns more pictures.

5.8.1 Use Picture

Use Picture makes a row of Pictures the one on the board. It writes the row’s name into $picture and sends pictureChosen. Arrange Board already listens for that message.

FunctionUse Picture

Makes a row of Pictures the picture the board shows: $picture becomes that row, and everyone who shows the picture is told (pictureChosen). Arrange Board then shuffles a new arrangement of it.

PARAMETERS
NameTypeStarts at
pictureTextVillage
ACTIONS
1Change Variable
Variable
$picture
Value
picture
2Trigger Custom Event
Custom Event
pictureChosen

5.8.2 Show Picture

Show Picture shows $picture whole, from the preview column of Pictures. It answers when the Preview is made and at every pictureChosen. The Preview uses it now. The Whole Picture will too.

Logic ComponentShow PictureAttach to: Picture Preview, Whole Picture

Shows the chosen picture whole ($picture's preview in Pictures). The Picture Preview and the Whole Picture both use it.

Attach toAny Object
When Created
WhenCreate
1Set Sprite
Sprite
data('Pictures', $picture, 'preview')
On Picture Chosen
WhenpictureChosenCustom Event
1Set Sprite
Sprite
data('Pictures', $picture, 'preview')
ObjectPicture PreviewAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 248, Y 248
Sprite
Z Index Within Object-1
SpriteVillage Picture
Transform > SizeX 248, Y 248
Logic
Show Picture

5.8.3 The Picture Buttons

Three small pictures sit at the top left, each with its name under it. A Picture Button is the picture. Its Text / UI has no words, because the name belongs to the separate Object beneath it. A Picture Name is the word underneath.

ObjectPicture Button
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 84, Y 62
Text / UI
Font Size16
EmphasisSemibold
Color#263D54
AlignmentCenter
RenderingVector
Sprite
Z Index Within Object-1
SpriteVillage Picture
Transform > SizeX 84, Y 62
UI Interaction(as it is added)
Logic
Choose Picture
ObjectPicture Name
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Text / UI
TextVillage
Font Size12
EmphasisSemibold
Color#526478
RenderingVector

Choose Picture asks the Puzzle Controls, then calls Use Picture with its own picture, a row’s name.

Logic ComponentChoose PictureAttach to: Picture Button

Clicking or tapping a Picture Button makes its picture the one the board shows: $picture becomes the Button's row of Pictures, and a new arrangement is shuffled. Each placement sets its picture (a row of Pictures) and its Sprite. While the How it works panel is open, the Button does nothing.

Attach toAny Object
PER INSTANCE VARIABLES
NameTypeStarting Value
pictureTextVillage
On Hud Activated
WhenUI Activated
1Check Input Context Active
Action Name
puzzleControlsOn
Input Context
Puzzle Controls
2IfpuzzleControlsOn.value == true
Then
3Use PictureFunction
picture
self.picture

Place the three Picture Buttons and their Names. The Village is the Object as it is. The Forest and the Harbor each change their Sprite, their name’s Text and their picture box.

5.8.4 Upload Picture

The Upload button lets you sort a picture of your own.

Myth has no block that opens your computer’s file chooser. So Upload Picture holds a short program in Run Code (JS), written in JavaScript, the language of web pages. Copy it from the card exactly as it is, line breaks and all.

Here’s what it does. It opens the chooser, for a PNG, JPEG, WebP or AVIF picture up to 25 MB. Pick one, and it cuts a square from the middle. It paints that square into the Uploaded row’s four Sprites, and sends pictureUploaded. A picture it can’t open sends uploadFailed instead. Canceling sends nothing at all.

The rest of Upload Picture is ordinary Logic, the kind you’ve built all along. A picture takes a moment to open. Press F in that moment, and the picture arrives with the panel open. Upload Picture closes the panel, so you see it. Then Use Picture chooses the Uploaded row, the way a Picture Button chooses the Village, and the bottom line says Picture loaded. The row’s name, Uploaded, goes into Use Picture’s box bare, as the card shows it.

Your picture lasts until the game closes. Choose the Village again, and the Village comes back.

Logic ComponentUpload PictureAttach to: Puzzle Rules

Lets the player rebuild a picture of their own. Upload opens the file chooser; a PNG, JPEG, WebP or AVIF picture up to 25 MB is cut to a square from its middle and becomes the picture the board shows, for this session only, with a new arrangement. A picture that cannot be opened changes nothing but the message; canceling changes nothing.

Attach toAny Object
On Upload Requested
WhenuploadRequestedCustom Event
1Run Code (JS)
Java Script
const host=window.__mythBabylon,scene=host&&host.controller;
if(!scene)return;
const largestFileBytes=25*1024*1024;
const uploadedRow=scene.dataRowByRef(scene.dataTable('Pictures'),'Uploaded');
if(!uploadedRow)return;
const sprites=Object.values(uploadedRow.cells);
if(window.__picturePuzzleChooser)window.__picturePuzzleChooser.remove();
const chooser=document.createElement('input');
chooser.type='file';chooser.accept='image/png,image/jpeg,image/webp,image/avif';chooser.style.display='none';
document.body.appendChild(chooser);window.__picturePuzzleChooser=chooser;
const finished=()=>{chooser.remove();if(window.__picturePuzzleChooser===chooser)window.__picturePuzzleChooser=null;};
chooser.addEventListener('cancel',finished,{once:true});
chooser.addEventListener('change',async()=>{
const file=chooser.files&&chooser.files[0];let fileUrl='';
try{
if(!file)return;
if(file.size>largestFileBytes)throw new Error('The picture is larger than 25 MB.');
fileUrl=URL.createObjectURL(file);
const chosen=new Image();chosen.src=fileUrl;await chosen.decode();
const side=Math.min(chosen.naturalWidth,chosen.naturalHeight);
if(side<1)throw new Error('The picture is empty.');
const size=Math.max(...sprites.map(name=>(host.RT.textures[name]||{}).natW||1));
const canvas=document.createElement('canvas');canvas.width=canvas.height=size;
canvas.getContext('2d').drawImage(chosen,(chosen.naturalWidth-side)/2,(chosen.naturalHeight-side)/2,side,side,0,0,size,size);
const square=new Image();square.src=canvas.toDataURL('image/png');await square.decode();
if(host.controller!==scene||window.__picturePuzzleChooser!==chooser)return;
sprites.forEach(name=>{
const old=host.RT.textures[name]||{};
host.RT.textures[name]={url:square.src,img:square,natW:size,natH:size,filterMode:old.filterMode||'smooth',filterScale:1};
scene.instances.filter(it=>it.spriteName===name&&!it.destroyed).forEach(it=>scene.swapSprite(it,name));
});
api.fireEvent('pictureUploaded');
}catch(error){if(host.controller===scene)api.fireEvent('uploadFailed');}
finally{if(fileUrl)URL.revokeObjectURL(fileUrl);finished();}
},{once:true});
chooser.click();
On Picture Uploaded
WhenpictureUploadedCustom Event
1Check Input Context Active
Action Name
lessonOpenAtUpload
Input Context
Lesson Panel Controls
2IflessonOpenAtUpload.value == true
Then
3Trigger Custom Event on Object
Custom Event
lessonCloseRequested
4Use PictureFunction
picture
"Uploaded"
5Change Variable
Variable
$message
Value
data('Messages', 'uploaded', 'words')
On Upload Failed
WhenuploadFailedCustom Event
1Change Variable
Variable
$message
Value
data('Messages', 'uploadFailed', 'words')

Request Upload asks for it.

FunctionRequest Upload

Asks Puzzle Rules to let the player choose a picture of their own. The Upload Button uses it.

PARAMETERS
NameTypeStarts at
puzzleRulesObjectPuzzle Rules
ACTIONS
1Trigger Custom Event on Object
Applies to
puzzleRules
Custom Event
uploadRequested

Now finish Button Action’s Upload branch with Request Upload. Place the Upload button with Command set to Upload. It’s the Puzzle Button once more, with its own size, white words, and Gold Face, the Sort button’s blue.

Run the game. Press Forest, and a waterfall in a green forest takes the board, shuffled. Press Harbor, and boats.

5.9 The Whole Picture

Next, the picture’s last moment.

A finished board still shows thin lines between the pieces. Each piece is a little smaller than its slot. When every piece is home, the game lays the picture whole over the board, and the lines disappear.

5.9.1 The Whole Picture

The Whole Picture is the picture again, the size of the whole board. Its Scene Depth Draw Order of 5 draws it over the pieces.

ObjectWhole Picture
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 560, Y 560
Sprite
Scene Depth Draw Order5
Z Index Within Object-1
SpriteVillage Picture
Transform > SizeX 560, Y 560
Logic
Show Whole Picture
Show Picture
Shared Variables
puzzleRulesPuzzle Rules

5.9.2 Update Whole Picture

Update Whole Picture asks two things. Is the Game State Solved? And has every slide landed, so that each piece stands on its own slot? When both answers are yes, the Whole Picture shows, and otherwise it hides.

The slide matters. The last swap finishes the board the moment it’s made, but the two pieces still have to glide home. The picture waits for them.

FunctionUpdate Whole Picture

Shows the whole picture over the board when the picture is complete (Game State Solved) and no piece is sliding, and hides it otherwise.

PARAMETERS
NameTypeStarts at
pictureObject
puzzleRulesObjectPuzzle Rules
ACTIONS
1Check Game State
Action Name
isSolved
Game State
Solved
2Check Cooldown Ready
Action Name
slideDone
Applies to
puzzleRules
Cooldown Key
"pieceSlide"
3IfisSolved.value == true && slideDone.value == true
Then
4Set Visible
Applies to
picture
Visible
true
5Otherwise
6Set Visible
Applies to
picture
Visible
false

5.9.3 Show Whole Picture

Show Whole Picture asks that question whenever the answer might change: when it’s made, when the Game State changes, when a slide ends, and after a new arrangement.

Logic ComponentShow Whole PictureAttach to: Whole Picture

Shows the whole picture, without the gaps between the pieces, once every piece is home and no piece is sliding.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
puzzleRulesObjectConstantNone
When Created
WhenCreate
1Update Whole PictureFunction
picture
self
puzzleRules
@self.puzzleRules
On Game State Changed
WhenGame State Changed
1Update Whole PictureFunction
picture
self
puzzleRules
@self.puzzleRules
On Slide Ended
WhenslideEndedCustom Event
1Update Whole PictureFunction
picture
self
puzzleRules
@self.puzzleRules
On Board Arranged
WhenboardArrangedCustom Event
1Update Whole PictureFunction
picture
self
puzzleRules
@self.puzzleRules

Place the Whole Picture at 340 and -500, over the board. It’s hidden until the picture is complete.

5.10 How It Works

Last comes the panel that explains it all, while the sort runs.

Press How it works, or F, and a white panel covers the game. It says how the sort works in a few short lines, the ones you’ve been learning. Two lines follow the sort itself: the unsorted range and which pass it’s in, and the last pair with what happened to it. While the panel is open, the puzzle waits.

The waiting is the Input Contexts’ work. Opening the panel turns the Puzzle Controls off and the Lesson Panel Controls on. From then on, only Close Panel’s keys answer.

But a context only switches keys. A press on a piece or a button isn’t a key. That’s why the buttons ask Check Input Context Active before they act. They’ve been asking since the Sort button. Until now, the answer was always yes, and now it can be no.

5.10.1 The Panel’s Objects

The panel is made of six new Objects, most of them words. Lesson Panel is the white face. Lesson Title says How it works, in big dark letters. Lesson Line is one line of words, placed nine times. Lesson State and Lesson Result are the two lines that follow the sort, and the Close Button closes it.

ObjectLesson Panel
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 920, Y 760
Sprite
Z Index Within Object-1
SpritePanel Face
Transform > SizeX 920, Y 760
Logic
Show With Lesson Panel
ObjectLesson Title
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Text / UI
TextHow it works
Font Size27
EmphasisExtra Bold
Color#263D54
RenderingVector
Logic
Show With Lesson Panel
ObjectLesson Line
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Text / UI
TextEach piece has a home position.
Font Size22
EmphasisMedium
Color#526478
RenderingVector
Logic
Show With Lesson Panel

The two sort lines count slots from 1, the way you would, so each of their live values adds 1 to the slot it shows.

ObjectLesson State
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Text / UI
TextUnsorted: {$rangeStart + 1} to {$rangeEnd + 1}. {$lessonPass}
Font Size19
EmphasisMedium
Color#526478
RenderingVector
Logic
Show Sort Lines
ObjectLesson Result
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Text / UI
TextLast pair: slots {$comparedSlot + 1} and {$comparedSlot + 2}. {$lessonOutcome}
Font Size18
EmphasisMedium
Color#526478
RenderingVector
Logic
Show Sort Lines
ObjectClose Button
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 110, Y 40
Text / UI
TextClose
Font Size16
EmphasisSemibold
Color#263D54
AlignmentCenter
RenderingVector
Sprite
Z Index Within Object-1
SpriteButton Face
Transform > SizeX 110, Y 40
UI Interaction(as it is added)
Logic
Close Lesson
Show With Lesson Panel
Shared Variables
puzzleRulesPuzzle Rules

5.10.2 Show If Lesson Open

Show If Lesson Open shows one part of the panel while the Lesson Panel Controls are on, and hides it otherwise. Its part input names no Object, so it stays on Structural.

FunctionShow If Lesson Open

Shows one part of the How it works panel while the panel is open (the Lesson Panel Controls are on), and hides it otherwise.

PARAMETERS
partObject
ACTIONS
1Check Input Context Active
Action Name
lessonOpen
Input Context
Lesson Panel Controls
2IflessonOpen.value == true
Then
3Set Visible
Applies to
part
Visible
true
4Otherwise
5Set Visible
Applies to
part
Visible
false

5.10.3 Show With Lesson Panel

Show With Lesson Panel is on the panel, its title, its lines and its button. When each is made, it moves it to the front with Set Z Order and asks the question. It asks again at every lessonToggled.

Logic ComponentShow With Lesson PanelAttach to: Lesson Panel, Lesson Title, Lesson Line, Close Button

Shows this part of the How it works panel only while the panel is open, in front of the game. The panel, its title, its lines and its Close Button use it.

Attach toAny Object
When Created
WhenCreate
1Set Z Order
Depth Amount
200
2Show If Lesson OpenFunction
part
self
On Lesson Toggled
WhenlessonToggledCustom Event
1Show If Lesson OpenFunction
part
self

5.10.4 Show If Sort Under Way

The two sort lines have one more condition. Before the first comparison on a board, they’d have nothing true to say. So they show only while the panel is open and $comparedSlot is 0 or more.

FunctionShow If Sort Under Way

Shows one line about the computer's sort while the How it works panel is open and the sort is under way, and hides it otherwise. Before the first comparison on a board ($comparedSlot is -1) the line has nothing to tell yet.

PARAMETERS
lineObject
ACTIONS
1Check Input Context Active
Action Name
lessonOpen
Input Context
Lesson Panel Controls
2IflessonOpen.value == true && $comparedSlot >= 0
Then
3Set Visible
Applies to
line
Visible
true
4Otherwise
5Set Visible
Applies to
line
Visible
false

5.10.5 Show Sort Lines

Show Sort Lines asks at the same moments as Show With Lesson Panel, and also after every comparison and every fresh start.

Logic ComponentShow Sort LinesAttach to: Lesson State, Lesson Result

Shows this line about the computer's sort while the How it works panel is open and the sort is under way, in front of the game. The Lesson State and the Lesson Result use it.

Attach toAny Object
When Created
WhenCreate
1Set Z Order
Depth Amount
200
2Show If Sort Under WayFunction
line
self
On Lesson Toggled
WhenlessonToggledCustom Event
1Show If Sort Under WayFunction
line
self
On Pair Compared
WhenpairComparedCustom Event
1Show If Sort Under WayFunction
line
self
On Sort Cleared
WhensortClearedCustom Event
1Show If Sort Under WayFunction
line
self

5.10.6 Lesson Lines

Lesson Lines keeps the two lines’ words. After every comparison, it copies the bottom line’s Swapped or Kept into $lessonOutcome. When a pass begins, it writes Forward pass or Backward pass into $lessonPass. Remember forwardPassStarted and backwardPassStarted, from Computer Sort? This is who they were for.

Logic ComponentLesson LinesAttach to: Puzzle Rules

Keeps the words of the How it works panel's two lines about the computer's sort up to date: the pass it is in ($lessonPass) and what its last comparison did ($lessonOutcome).

Attach toAny Object
On Pair Compared
WhenpairComparedCustom Event
1Change Variable
Variable
$lessonOutcome
Value
$message
On Forward Pass Started
WhenforwardPassStartedCustom Event
1Change Variable
Variable
$lessonPass
Value
data('Messages', 'forwardPass', 'words')
On Backward Pass Started
WhenbackwardPassStartedCustom Event
1Change Variable
Variable
$lessonPass
Value
data('Messages', 'backwardPass', 'words')

5.10.7 Close Lesson Panel

Close Lesson Panel turns the Lesson Panel Controls off and the Puzzle Controls back on, then sends lessonToggled. It’s the first card with Set Input Context Active, the Action that turns a set of keys on or off.

The first Set Input Context Active turns the lesson keys off, with Active false. The second turns the puzzle keys on. Active starts true, so that second card line is left out. Opening uses those same values.

FunctionClose Lesson Panel

Closes the How it works panel: the Lesson Panel Controls go off and the Puzzle Controls on again, and the panel's parts are told (lessonToggled).

ACTIONS
1Set Input Context Active
Input Context
Lesson Panel Controls
Active
false
2Set Input Context Active
Input Context
Puzzle Controls
3Trigger Custom Event
Custom Event
lessonToggled

5.10.8 Lesson Panel Switch

Lesson Panel Switch opens and closes the panel, from Puzzle Rules. Opening does what Escape does first, with selectionCanceled. That ends a press or a choice, and Sort Timer hears it and pauses the sort. Then the contexts switch, and lessonToggled goes out.

Closing comes from F or Escape, through Close Panel, or from the Close Button’s message.

Logic ComponentLesson Panel SwitchAttach to: Puzzle Rules

Opens the How it works panel when it is asked, and closes it on Close, F or Escape. While the panel is open the computer is stopped and only the Lesson Panel Controls are on, so the puzzle answers no key, Button or piece.

Attach toAny Object
On Lesson Requested
WhenlessonRequestedCustom Event
1Trigger Custom Event on Object
Custom Event
selectionCanceled
2Set Input Context Active
Input Context
Puzzle Controls
Active
No
3Set Input Context Active
Input Context
Lesson Panel Controls
4Trigger Custom Event
Custom Event
lessonToggled
When Close Is Pressed
WhenCommand PressedCommand: Close Panel
1Close Lesson PanelFunction
On Lesson Close Requested
WhenlessonCloseRequestedCustom Event
1Close Lesson PanelFunction

5.10.9 Close Lesson

Close Lesson lets a press on the Close Button end the lesson. Its request reaches Puzzle Rules, so clicking and pressing a closing key use the same panel switch.

Logic ComponentClose LessonAttach to: Close Button

Clicking or tapping the Close Button asks Puzzle Rules to close the How it works panel.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
puzzleRulesObjectConstantNone
On Hud Activated
WhenUI Activated
1Trigger Custom Event on Object
Applies to
@self.puzzleRules
Custom Event
lessonCloseRequested

5.10.10 Piece Pointer

Piece Pointer asks the Puzzle Controls too, on a press and on a release. With the panel open, a piece under it tells Puzzle Rules nothing.

Logic ComponentPiece PointerAttach to: PieceAddDelete

Tells Puzzle Rules when the pointer is pressed on this Piece and when it is released on it. Puzzle Rules decides what the press and the release mean. While the How it works panel is open, the Piece tells nothing.

Attach toAny Object
DATA STRUCTURES
Slot Numberself.slotNumber
SHARED VARIABLES
NameTypeKindStarting Value
puzzleRulesObjectConstantNone
When Left Is Clicked
WhenMouse Pressed on ObjectMouse button: left
1Change Variable
Variable
$chosenSlot
Value
self.slotNumber.slot
2Trigger Custom Event on Object
Applies to
@self.puzzleRules
Custom Event
piecePressed
1Check Input Context Active
Action Name
controlsOnAtPress
Input Context
Puzzle Controls
2IfcontrolsOnAtPress.value == true
Then
3Change Variable
Variable
$chosenSlot
Value
self.slotNumber.slot
4Trigger Custom Event on Object
Applies to
@self.puzzleRules
Custom Event
piecePressed
When Left Is Released
WhenMouse Released on ObjectMouse button: left
1Change Variable
Variable
$chosenSlot
Value
self.slotNumber.slot
2Trigger Custom Event on Object
Applies to
@self.puzzleRules
Custom Event
pieceReleased
1Check Input Context Active
Action Name
controlsOnAtRelease
Input Context
Puzzle Controls
2IfcontrolsOnAtRelease.value == true
Then
3Change Variable
Variable
$chosenSlot
Value
self.slotNumber.slot
4Trigger Custom Event on Object
Applies to
@self.puzzleRules
Custom Event
pieceReleased

Now place the panel from PLACE THESE: the Lesson Panel, the Title, the nine Lesson Lines with their own words and sizes, the two sort lines, and the Close Button. Last, place the How it works button, the Puzzle Button one more time, with Command set to Lesson.

Run the game, press Sort, and then press F to open the panel. The sort stops, and the panel tells you where it was.

Play it!

Watch for each of these.

  • Under the Preview, 64 and Fast are underlined. The board starts at 0 / 64, with the button beside Step reading Sort.
  • Press Sort. It reads Pause, and pairs glide past each other along the rows. The amber pair flickers ahead, and green closes in from both ends.
  • Press F while it runs. The panel opens, and the sort stops. A line reads Unsorted, then two slot numbers and Forward pass or Backward pass. The line under it names the last pair, by its two slots, and says Swapped or Kept.
  • Press F again, then Sort. The sort goes on from the same pair.
  • Then let it run all the way to the end, without touching anything. The caption reads 64 / 64, and the counter says Comparisons 1478 and Swaps 819, the same as all those Steps in Chapter 4. The bottom line says Picture complete, and the thin lines between the pieces disappear. The button reads Sort again.
  • Press Sort on the finished picture. Nothing happens.
  • Press 9. Nine large pieces fill the board, shuffled, and the underline moves to 9.
  • Press Slow, then Sort. One pair every 0.4 seconds, and each swap glides for 0.35 seconds. You can follow every comparison.
  • Press H. The sort pauses, and the green and amber leave the edges. Press C, and they’re back.
  • Press Forest, then Harbor. Each one shuffles a new board of its picture.
  • Press 64, Village, then Upload, and pick a photo of your own. It fills the board, cut into 64 pieces. The bottom line says Picture loaded.
  • Tap two pieces. They glide into each other’s slots in 0.22 seconds, and Moves counts one.
How it works

Slide Pieces starts every glide, and the pieceSlide cooldown holds new moves until it lands. Who Plays decides whose colors show. Sort Timer presses Step for you, ring after ring, at the speed Sort Speeds gives. Piece Counts and Pictures choose the size and the picture, and every Piece lays itself out. How it works switches which keys listen. The buttons ask before they act.

Underneath all of it, the sort hasn’t changed since Chapter 4. Sort is a hand on Step that never tires. The board changes in an instant, and the slide only shows it later. The game you see is always a moment behind the numbers, and the cooldown keeps the two in step.

5.11 If It Didn’t Work

This chapter has more pieces than any other, so expect a slip or two. That’s normal. Run the game, try the one thing that misbehaves, and watch what it does.

Pieces jump instead of gliding? Look for Slide Piece on the Piece, and at its first If, which compares the Piece’s slot with $slideFrom and $slideTo. If a piece glides from the wrong place, look at otherSlot’s second step, inside the small If.

A piece glides and then stands a little off its slot? Look at the two Tween Actions. One is position.x, the other position.y, and each Target reads home.

Pieces stop answering after the first exchange, and never wake up? Perhaps the cooldown never ends. Look at Slide Pieces’ Start Cooldown, whose Seconds is seconds. Then look at the name pieceSlide on every card that asks for it. It should be spelled the same each time, with the same quote marks the card shows.

Sort does nothing? Look at the Sort button’s Command Variable, Sort, and Button Action’s Request Sort call. Next, look at Sort Timer’s sortRequested Event, and check that its Stopped Mode is the one it starts with.

Sort runs a few Steps and stops? Perhaps the ring calls Request Step, which pauses the sort. The ring sends stepRequested itself.

The button never reads Pause? Look at Start Sort Timer’s last step, and at the Sort button’s Text, {$sortButtonLabel}.

The sort finishes, but the button still says Pause? Look for each sortEnded in Computer Sort, two of them in the passes’ small Ifs, and for Sort Timer’s sortEnded Event.

Pressing 9 leaves 64 small pieces on the board? Look at Lay Out Slot’s boardArranged Event, and at Lay Out One Slot’s If. If nine pieces show the wrong pictures, look at Choose Piece Sprite.

Nothing on the board answers, ever? Perhaps the Puzzle Controls are off. Look at the INPUT CONTEXTS: Puzzle Controls is active at start, and Lesson Panel Controls isn’t. And look at the spelling of Puzzle Controls in each Check Input Context Active.

The panel never closes? Look for Close Panel in the Lesson Panel Controls, not in Puzzle Controls.

Upload opens no chooser at all? Perhaps a mark went missing in the program. Open the catch-up download, and go down its Run Code (JS) box beside yours, line by line.

Each of these is one small fix. Make it, run the game, and you’re back with the chapter. The catch-up download in the Goal is the finished game, if you’d like to compare.

Challenge

The game is yours now, so make it say something of yours. Make a fourth speed, slower than Slow, so a friend can watch every pair and guess before it’s swapped. It’s a new row in Sort Speeds, a fourth Speed Button and a fourth Underline. Or give How it works a line in your own words, one more Lesson Line on the panel. What would you want someone to see, watching a sort for the first time?

In Chapter 1, the pieces lay where they’d been dealt, and nothing on the board could move them. Now they glide home by themselves, a pair at a time, and every piece, color, word and count on that screen is one you put there.