- Learn
- Build a Game
- Chess
- 7 The Computer
7 The Computer
By the end of this chapter, the other Side thinks for itself. The Computer answers your Moves at the Strength you chose, and its Piece glides across the Board. Undo takes your last Turn back.
The game as it is at the end of this chapter. Click the game to play.
If your game and this chapter part ways, here is the chapter’s finished project. Open it and compare, or start Chapter 8 from it.
To open it, right-click the downloaded file, choose Extract All... and then Extract. Start Myth Engine, choose File › Open Project... and pick the .mythproj file in the new folder. CREDITS.md and the licenses folder beside it come with the game.
7.1 The Idea
Play your game from Chapter 6. Move a White Pawn, and then walk round the table and move a Black one. Every Move on the Board is yours, both Sides. The chair across from you is empty.
This chapter fills it, and the other Side becomes the Computer. It’s the one part of your game that isn’t built from blocks. A chess program called Stockfish chooses its Moves. Stockfish comes into your game as a Library, a file of code your game carries inside it. Everything else is still the Logic you built, every rule that judges the Computer’s Moves and yours.
Here’s the real problem. You can’t ask Stockfish a question and stand still until it answers. Your game would freeze while it thinks. So the game asks the way you’d post a letter. It sends the question and goes on with its life, and the answer comes back later as a message of its own, computerMoveChosen. In between, the sign on the shop door from Chapter 4 says Computer’s Turn. The Board takes no clicks.
When the answer arrives, the Computer’s Piece doesn’t jump. It glides to its new Square in a little over a third of a second, and that glide is a slide.
Two promises get kept here. Chapter 6’s Strength starts to matter, at last. And a new button, Undo, takes your last Turn back, with the Computer’s reply to it.
7.2 The Plan
Here’s how the pieces work together. Read each line from left to right, once now for the shape, and again after the Computer plays.
- A Turn goes on -> Look For Game End sends gameContinues -> Make Computer Move asks whether it’s the Computer’s Turn.
- It is -> Ask The Computer turns the sign to Computer’s Turn and asks Stockfish.
- Stockfish answers -> computerMoveChosen -> Make Computer Move checks the Move with Find Legal Moves.
- The Move is legal -> Plan The Slide -> slideStarted.
- The slide starts -> Slide Piece glides the Moving Piece, and Show Piece and Square Marks hide what it carries.
- The slide lands -> pieceLanded -> Make Computer Move makes the Move with Make Move -> moveMade -> Start Turn writes it in the Move History.
- No answer in time -> Mark Computer Unavailable -> the Retry button shows.
- Undo is pressed -> Undo -> Take Back Moves starts the game again and makes every Move it keeps.
7.3 Set Up
Playing, Promotion, Game Over, Computer's Turn, Computer UnavailableTwo Game States join the list, Computer’s Turn and Computer Unavailable, and they go after Game Over, as the page’s passage on the Set up card says.
Each line under PLACE THESE waits for a part of this chapter, so each part sends you back here. The Moving Piece and the Unavailable Message are new Objects. Undo Button is a variant of Tool Button, and Retry Button a variant of Panel Button. The two Moving Piece lines are no copy slip: one carries a Piece, and the other a Rook when the Computer castles. Each button’s variant adds its own Logic, as Flip Button did in Chapter 6.
7.4 The Computer’s Tables
The Computer needs tables.
7.4.1 Strengths
One row of the "Strengths" Data Table, which follows it. How the Computer plays at each Strength, one row per Strength button of the New Game panel (the row name is the button's word). skillLevel: Stockfish's Skill Level, from 0 (weakest) to 20 (strongest). thinkingSeconds: how long Stockfish thinks about each Move, in seconds.
00.240.3580.5140.8201.2Strengths has a row for each Strength on the New Game panel, by the same names. Its skillLevel is how well Stockfish plays, from 0 up to 20. Its thinkingSeconds is how long it thinks. Gentle thinks for 0.2 seconds, a blink, and Expert takes 1.2 seconds, long enough to notice.
7.4.2 Chosen Moves
One row of the "Chosen Moves" Data Table, which follows it. The Move the Computer chose, written by the Stockfish Bridge just before it says "computerMoveChosen". from and to: the Squares the Piece moves from and to (a1 to h8). landingKind: the Kind of the Piece once it has landed: its own Kind, or, when the Move promotes a Pawn, the Kind the Pawn becomes (Queen, Rook, Bishop, or Knight).
Chosen Moves has one row, Computer, with three empty Text columns. Make those fields in Chosen Moves Entry, and the table gets its columns from them. Stockfish writes its answer here: from, to, and landingKind, the Kind the Piece will be once it lands. That last one matters only for a Pawn that promotes. It becomes whatever Kind Stockfish named.
7.4.3 Words
Your moveCheckPromotion: choose a PieceYou win · CheckmateYou lose · CheckmateDraw · StalemateDraw · Insufficient materialDraw · Fifty-move ruleDraw · Threefold repetitionThinking…Opponent disconnectedTwo rows join Words. Thinking… ends with three dots that are one character, not three periods, so copy it from the card. Disconnected says Opponent disconnected.
7.4.4 Stockfish Bridge
stockfish-bridge.js, from the zip781.9 KBstockfishBridgeStockfishBridgeClassic BuildThe Stockfish Bridge is the Library. It’s Stockfish, and a small bridge around it. The bridge turns your Position table and Board State into words Stockfish reads, and asks for a Move at the Strength you chose. It writes the answer into Chosen Moves and sends computerMoveChosen.
A Library card shows how to add it, from the download to the Alias. The Alias is the name your Logic calls it by, so type stockfishBridge exactly. Once the file is in, Myth shows its size. It’s the card’s Size, 781.9 KB, when you have the right file.
Myth reads a Library’s code when you import it, and a yellow note lists what that code could do. Keep a Library only if you trust it, the note says. That’s good advice. This one names a few web addresses in Stockfish’s credits, and thinks in the background on your computer. The game never needs the internet to play.
The zip has two more things beside the Library’s file, CREDITS.md and a licenses folder. They’re Stockfish’s. Copy them into the folder that holds your project’s .mythproj file, the one you pick in File › Open Project…, and keep them there.
7.5 Every Move, Written Down
Before the Computer plays, the game learns to keep a record. Undo will need it later in this chapter, and so will the Computer’s own Moves.
7.5.1 Move History
One row of the "Move History" Data Table, which follows it. Every Move of the game so far, in the order they were made, one row per Move (the first Move is row 0; each row is named by its number). from and to: the Squares the Piece moved from and to (a1 to h8). landingKind: the Kind of the Piece once it had landed: its own Kind, or, for a Promotion, the Kind the Pawn became. The number of rows is the number of Moves made. Undo takes rows off the end and plays the rest again. The table starts empty.
Move History starts with no rows at all. Each Move adds one: its from and to, and the Kind that landed.
7.5.2 Record Move
Writes the Move just made (Board State's lastFrom and lastTo) at the end of the Move History table, with the Kind the Piece landed as. gameRules: the Game Rules Object, whose Board State holds the last Move.
boardStateData StructureBoard State- Type
Text- Name
fromSquare
- Type
Text- Name
toSquare
- Name
lastRow- Value
0
- Variable
fromSquare- Value
gameRules.boardState.lastFrom
- Variable
toSquare- Value
gameRules.boardState.lastTo
- Action Name
addedRow- Table
Move History- Row
dataCount('Move History')
- Variable
lastRow- Value
dataCount('Move History') - 1
- Table
Move History- Row
lastRow- Column
"from"- Value
fromSquare
- Table
Move History- Row
lastRow- Column
"to"- Value
toSquare
- Table
Move History- Row
lastRow- Column
"landingKind"- Value
data('Position', toSquare, 'kind')
Record Move writes the Move that was made last at the bottom of the Move History. Board State already knows it, in lastFrom and lastTo. It adds a row at the end, as Record Position did in Chapter 5, and fills it in. Its Control Data Row has no Operation line, because that stays as it starts, on adding the row.
7.5.3 Pass The Turn
Gives the Turn to the other Side (the Sides table's opponent column). gameRules: the Game Rules Object, whose Board State holds whose Turn it is (sideToMove).
boardStateData StructureBoard State- Type
Text- Name
side
- Variable
side- Value
gameRules.boardState.sideToMove
- Component Value
gameRules.boardState.sideToMove- Value
data('Sides', side, 'opponent')
Pass The Turn does the work you’ve met before, in Start Turn. They give the Turn to the other Side. Undo needs them too, so now they’re a Function of their own.
7.5.4 Start The Turn
Starts the Turn of the Side to move, in the position on the Board: marks a King in Check and sets the status line (Look For Check), then tells the Game Rules "turnStarted" (Look For Game End asks whether the game is over; if it goes on, Make Computer Move asks whether it is the Computer's Turn). gameRules: the Game Rules Object.
boardStateData StructureBoard State- gameRules
gameRules
- Applies to
gameRules- Custom Event
turnStarted
Start The Turn holds the two steps Start Turn always began a Turn with. Start Turn and Undo will both start Turns now, so those steps get a home that both can call.
7.5.5 Start Turn
Starts each Turn: the first one (White's) when the game begins, and the next one after every Move, which it first writes down in the Move History (Record Move) before giving the Turn to the other Side (Pass The Turn). Each Turn starts with Start The Turn: it asks whether the Side to move is in Check, then tells the Game Rules that the Turn has started ("turnStarted").
Any Objectself.boardState- gameRules
self
- Custom Event
turnStarted
- gameRules
self
- Custom Event
positionChanged
- Type
Text- Name
side
- Variable
side- Value
self.boardState.sideToMove
- Component Value
self.boardState.sideToMove- Value
data('Sides', side, 'opponent')
- gameRules
self
- gameRules
self
- Component Value
self.boardState.selected- Value
''
- gameRules
self
- Custom Event
turnStarted
- gameRules
self
Start Turn gets shorter. Its side Declare goes, with the steps that moved into the new Functions. When Created calls Start The Turn, then sends positionChanged as before. On Move Made writes the Move down first, with Record Move, and then it passes the Turn, clears the selection and the dots, and starts the next Turn.
The struck steps keep their old numbers, so some numbers show twice. Delete the struck ones first. In When Created, Start The Turn goes in front of the old step that sends positionChanged. In On Move Made, Record Move and Pass The Turn go in front of the old step that clears the selection. Start The Turn goes last, after Clear Targets.
To put a step in front of an old one, add it apart from the line. Use the round handles to join it after the block it follows, as in Chapter 4. To put it first, start from the Mode’s bottom handle.
Run the game. It plays the way it did, and the Move History fills up where you can’t see it.
7.6 Asking the Computer
Now the question, and the answer.
7.6.1 Ask The Computer
Asks the Computer for its Move: the Board waits (Game State Computer's Turn), the status line says the Computer is thinking, and the Stockfish Bridge (a Library of code) asks Stockfish for a Move at the Strength in Board State; it answers with "computerMoveChosen". The named timer answerWait rings once if no answer has come in time: the Strength's thinking time plus spareSeconds. gameRules: the Game Rules Object. spareSeconds: how much longer than its thinking time the Computer may take to answer, starting Stockfish included.
boardStateData StructureBoard State- Name
waitSeconds- Value
0
- Game State
Computer's Turn
- Variable
$status- Value
data('Words', 'Thinking', 'text')
- Applies to
gameRules- Java Script
lib.ext.stockfishBridge.chooseComputerMove(api, ctx.self);
- Variable
waitSeconds- Value
data('Strengths', gameRules.boardState.strength, 'thinkingSeconds')
- Variable
waitSeconds- Operator
+=- Value
spareSeconds
- Applies to
gameRules- Timer Name
"answerWait"- Repeat Every (s)
waitSeconds- Ring Once
true
Ask The Computer puts the question. First, Set Game State turns the sign to Computer’s Turn, so the Board stops answering, and $status says Thinking…. One step of code, Run Code (JS), asks the Library for a Move. Type it exactly as the card has it. It needs Advanced Mode. It’s one of only two lines of code you’ll write in this game. The other comes in Chapter 8, and it asks the Library for a Hint.
The last three steps start a clock. What if Stockfish never answers? Steps 5 and 6 add up waitSeconds: this Strength’s thinking time, and spareSeconds more, 20 seconds of patience. The second one adds on, with +=. Start Recurring Timer starts a timer named answerWait on the Game Rules. Its Ring Once is true. It rings one time, and stops.
7.6.3 Slides and Plan The Slide
One row of the "Slides" Data Table, which follows it. Where the Pieces of the Computer's Move slide, written just before they slide (Plan The Slide) and read by the Moving Pieces (each placement follows one row) and by the Pieces, which show nothing on a Square a slide starts from. Row Piece: the Piece that moves. Row Rook: the Rook, when the Move is a castling (empty otherwise). from and to: the Squares it slides from and to (a1 to h8).
Slides says where each Piece of the Computer’s Move will glide. Row Piece is the Piece that moves, and row Rook is for a castling, when the Rook moves too.
Writes where the Pieces of one Move slide, before the Move is made (the Slides table): the Piece from its Square to the new one, and, when the Move is a castling, the Rook too, as the Castling table says. from and to: the Squares the Piece moves from and to.
- Type
Text- Name
kind
- Type
Text- Name
rookFrom
- Type
Text- Name
rookTo
- Variable
kind- Value
data('Position', from, 'kind')
- Table
Slides
- Table
Slides- Row
"Piece"- Column
'from'- Value
from
- Table
Slides- Row
"Piece"- Column
'to'- Value
to
dataCount('Castling')timeskind == "King" && data('Castling', local.index, 'kingFrom') == from && data('Castling', local.index, 'kingTo') == to- Variable
rookFrom- Value
data('Castling', local.index, 'rookFrom')
- Variable
rookTo- Value
data('Castling', local.index, 'rookTo')
- Table
Slides- Row
"Rook"- Column
'from'- Value
rookFrom
- Table
Slides- Row
"Rook"- Column
'to'- Value
rookTo
Plan The Slide fills it in before the Move is made. It empties the table, and writes the Move’s two Squares into row Piece. Next it walks the Castling table from Chapter 4. Is the Piece a King, going from a row’s kingFrom to its kingTo? That’s a castling, and the Rook’s two Squares go into row Rook.
7.6.4 Make Computer Move
This is the chapter’s biggest card, with five Events. Take them in order, and they tell the whole story of a Computer Turn.
Make Make Computer Move Data first, then add it beside Board State on the canvas’s Data Structures card. Its slot name is makeComputerMoveData. It keeps the Move while the answer is checked and the Piece slides.
What Make Computer Move remembers on the Game Rules about the Computer's Move. fromSquare and toSquare: the Move's Squares. landingKind: the Kind a Pawn becomes, or empty.
Plays the Computer's Turns. When a Turn goes on ("gameContinues", from Look For Game End) and the Side to move is the Player's opponent (the Sides table), it asks the Computer for a Move (Ask The Computer: the Board waits in Computer's Turn while the Stockfish Bridge asks Stockfish at the Strength in Board State). When Stockfish answers ("computerMoveChosen"; the Move is in the Chosen Moves table) and it is still the Computer's Turn and the Move is a Legal Move, the Move slides first (Plan The Slide fills the Slides table; everyone hears "slideStarted"). When it has landed ("pieceLanded", from the Moving Piece), it is made if it is still the Computer's Turn, the way the Player's Moves are made: Make Move, the Kind it lands as (a promoted Pawn becomes the Kind Stockfish named), then "moveMade" (Start Turn starts the Player's Turn) and "positionChanged". When Stockfish gives no Move, or one that is not legal, or does not answer within its thinking time and spareSeconds more (the answerWait timer), the position stays and the Computer is marked unavailable (Mark Computer Unavailable) until the Player presses Retry ("retryPressed"), which asks again. spareSeconds: how much longer than its thinking time the Computer may take to answer, starting Stockfish included. A Player whose device asks for less motion (the system setting "reduce motion", the Myth Global prefersReducedMotion) sees the Move made at once, with no slide.
Any Objectself.boardStateself.makeComputerMoveDataself.boardState.sideToMove == data('Sides', self.boardState.playerSide, 'opponent')- gameRules
self- spareSeconds
@self.spareSeconds
- Action Name
isThinking- Game State
Computer's Turn
isThinking.value == true- Timer Name
"answerWait"
- Component Value
self.makeComputerMoveData.fromSquare- Value
data('Chosen Moves', 'Computer', 'from')
- Component Value
self.makeComputerMoveData.toSquare- Value
data('Chosen Moves', 'Computer', 'to')
- from
self.makeComputerMoveData.fromSquare- enPassantSquare
self.boardState.enPassantSquare
data('Targets', self.makeComputerMoveData.toSquare, 'reachable') == true$prefersReducedMotion == 1- Custom Event
pieceLanded
- from
self.makeComputerMoveData.fromSquare- to
self.makeComputerMoveData.toSquare
- Custom Event
slideStarted
- gameRules
self
- Action Name
isLanding- Game State
Computer's Turn
isLanding.value == true- Component Value
self.makeComputerMoveData.fromSquare- Value
data('Chosen Moves', 'Computer', 'from')
- Component Value
self.makeComputerMoveData.toSquare- Value
data('Chosen Moves', 'Computer', 'to')
- Component Value
self.makeComputerMoveData.landingKind- Value
data('Chosen Moves', 'Computer', 'landingKind')
- Game State
Playing
- gameRules
self- from
self.makeComputerMoveData.fromSquare- to
self.makeComputerMoveData.toSquare
- Table
Position- Row
self.makeComputerMoveData.toSquare- Column
"kind"- Value
self.makeComputerMoveData.landingKind
- Custom Event
moveMade
- Custom Event
positionChanged
- Action Name
isStillThinking- Game State
Computer's Turn
isStillThinking.value == true- gameRules
self
- Action Name
isUnavailable- Game State
Computer Unavailable
isUnavailable.value == true- gameRules
self- spareSeconds
@self.spareSeconds
On Game Continues comes first. It asks whether the Side to move is the Player’s opponent, the one the Sides table names. If it is, Ask The Computer puts the question. On your own Turn, nothing happens at all.
On Computer Move Chosen hears the answer, and its first two steps ask a question of their own. Check Game State asks whether the sign still says Computer’s Turn, and the If goes on only if it does. Why ask? An answer can come late, after you’ve pressed Undo, and a late answer counts for nothing.
It stops the clock and reads the Move from Chosen Moves. But it doesn’t take Stockfish’s word for it. Find Legal Moves marks Targets for that Piece, as it does for yours. Is the to Square reachable? Only then does the Move go ahead. A Move that isn’t legal, or no Move at all, clears the dots and marks the Computer unavailable.
Inside the legal branch, there’s one more question. The Global $prefersReducedMotion is one Myth Engine keeps for you. It’s 1 when your computer’s own settings ask for less motion, and then the Move lands at once, with no slide. Otherwise Plan The Slide fills Slides, and slideStarted goes out to everyone.
On Piece Landed makes the Move. It checks the sign once more, reads the Move again, and turns the sign back to Playing first. That’s Chapter 5’s lesson from Choose Promotion. A Move can end the game, and a Playing set after it would wake a finished game up again. Make Move comes next, with the Kind it lands as. Last come moveMade and positionChanged, as your own Moves send.
On the Answer Wait Timer is the clock ringing: if the Computer is still thinking, it’s marked unavailable. Its When bar is a Recurring Timer, and Events: the When bars shows how to give one its name. On Retry Pressed asks again, only while the Computer is unavailable.
Each Check Game State has its own Action Name and its own Game State in the list, and each If reads that name’s value. Its spareSeconds is a constant Number Shared Variable, as the card shows.
7.6.5 Look For Game End
Ends the game at the start of every Turn (Start Turn sends "turnStarted") when the Side to move has no Legal Move (Is Out Of Moves), when neither Side can give Checkmate (Is Material Insufficient), when the same position has come timesSeenForDraw times (Record Position, Is Position Repeated), or when fiftyMoveCountForDraw Moves in a row have had no Capture and no Pawn Move (the fifty-move rule; Make Move counts them). The status line shows the result (Show Result), and the game is over (Game State Game Over), so the Board no longer answers and the final position stays. Otherwise it tells the Game Rules "gameContinues", and the Turn goes on. timesSeenForDraw: 3, threefold repetition. fiftyMoveCountForDraw: 100, fifty Moves by each Side.
Any Objectself.boardState- Action Name
outOfMoves- gameRules
self
- Action Name
material
- gameRules
self
- Action Name
repetition- timesForDraw
@self.timesSeenForDraw
outOfMoves.value == true || material.value == true || repetition.value == true || self.boardState.fiftyMoveCount >= @self.fiftyMoveCountForDraw- gameRules
self- isOutOfMoves
outOfMoves.value- isMaterialInsufficient
material.value- isRepeated
repetition.value
- Game State
Game Over
- Custom Event
gameContinues
Look For Game End gets an Else. When no ending is found, step 9 sends gameContinues, and Make Computer Move hears it. Add the Else to step 5’s If with Add Else. Add the Trigger through the Else’s Add Inside Else, and join it there.
7.6.6 Game Rules
Board StateSelect and MoveSelect and Move DataChoose PromotionChoose Promotion DataMake Computer MoveMake Computer Move DataUndoUndo DataAttach Make Computer Move to the Game Rules now. Undo’s line waits until Undo exists, later in this chapter.
You won’t see the Computer move yet, because its Piece needs something to carry it. Run the game now, and the words stay on Thinking…, with no Piece moving. That’s expected, because nothing says the Piece has landed yet. The next part does. Keep going.
7.7 The Slide
One Object carries the Computer’s Piece across the Board.
7.7.1 Moving Piece
X 3.4765, Y 3.476512Carved Walnut PiecesX 3.4765, Y 3.4765Slide PieceSlide Piece DataThe Moving Piece looks like any Piece, the same picture at the same size. But it stands on no Square, and its Scene Depth Draw Order is 12, so it’s drawn over the Pieces. It’s the Computer’s hand.
7.7.2 Slide Piece
Start this card at its end. Make the On Board Flipped Event first, with its two Modes, Stay Hidden and Land At Once. Step 14 and On Position Changed’s step 3 pick them from lists with Switch Mode, and a list holds only what’s already there. Modes shows how to make the pair.
Make Slide Piece Data before the Logic. Add it to the canvas’s Data Structures card with slidePieceData as its slot. Those fields keep the Piece’s Kind, Side and Board direction through the slide.
What Slide Piece remembers on the Moving Piece while it slides. isFlipped: whether the Board is drawn turned over. kind and side: the Piece it shows.
Slides one Piece of the Computer's Move across the Board before the Move is made. When the Game Rules say "slideStarted" (they are its Other), it reads its row of the Slides table: if the row names a Square, it shows the Piece standing there and glides from that Square to the row's other Square in slideSeconds, starting and ending slowly. The Moving Piece that says so (saysWhenLanded) then tells the Game Rules "pieceLanded", and they make the Move; the next "positionChanged" hides it again. While it slides, a Board turned over or back ("boardFlipped") ends the slide at once (Event Logic Land At Once): the Move is made, drawn the new way round; between slides a turned Board changes nothing here (Stay Hidden). slide: which row of the Slides table it follows (Piece, or Rook for a castling). slideSeconds: how long the slide takes. saysWhenLanded: true for the one Moving Piece that says when the slide is over (a King and its Rook land together). squareMeters, boardLeft, and boardBottom: where the Squares are (as for Place On Board).
Any Objectself.slidePieceData- Type
Text- Name
toSquare
- Type
Text- Name
fromSquare
- Variable
fromSquare- Value
data('Slides', self.slide, 'from')
- Variable
toSquare- Value
data('Slides', self.slide, 'to')
fromSquare != ""- Component Value
self.slidePieceData.isFlipped- Value
other.boardState.isFlipped
- Action Name
startSquare- square
fromSquare- isFlipped
self.slidePieceData.isFlipped- squareMeters
@self.squareMeters- boardLeft
@self.boardLeft- boardBottom
@self.boardBottom
- Action Name
endSquare- square
toSquare- isFlipped
self.slidePieceData.isFlipped- squareMeters
@self.squareMeters- boardLeft
@self.boardLeft- boardBottom
@self.boardBottom
- Component Value
self.slidePieceData.kind- Value
data('Position', fromSquare, 'kind')
- Component Value
self.slidePieceData.side- Value
data('Position', fromSquare, 'side')
- Frame
data('Kinds', self.slidePieceData.kind, self.slidePieceData.side)
- X
startSquare.x- Y
startSquare.y
- Visible
Yes
- Event
On Board Flipped- Mode
Land At Once
- Value
self.transform.position.x- Target
endSquare.x- Duration
@self.slideSeconds- Ease
Sine in Out
- Value
self.transform.position.y- Target
endSquare.y- Duration
@self.slideSeconds- Ease
Sine in Out
self.saysWhenLanded == true- Timer Name
"landing"- Repeat Every (s)
@self.slideSeconds- Ring Once
Yes
- Custom Event
pieceLanded
- Visible
No
- Timer Name
"landing"
- Event
On Board Flipped- Mode
Stay Hidden
self.saysWhenLanded == true- Custom Event
pieceLanded
Slide Piece hears slideStarted, and reads its own row of Slides, Piece or Rook, as its slide Per Instance Variable says. An empty Rook row means no castling, and Return ends it there.
Otherwise, it gets ready. Square Position tells it where both Squares are drawn now, turned or not. Set Frame gives it the picture of the Piece on the from Square, and Set Position and Set Visible put it there, in plain view. Two Tween steps glide it, one across and one up or down. Type self.transform.position.x into the first one’s Value box, and self.transform.position.y into the second’s. Each moves its value to the Target over slideSeconds, 0.36 seconds, its Duration. The Ease Sine in Out starts slowly and ends slowly, the way a hand sets a Piece down.
The Moving Piece whose saysWhenLanded is true starts a timer, landing, as long as the slide. When it rings, pieceLanded goes to the Game Rules. A King and its Rook land together, so only one of them says so.
When positionChanged comes, the Moving Piece hides again and stops its timer.
The two On Board Flipped Events are one Event with two ways to answer, two Modes. Stay Hidden does nothing. Land At Once makes the Move land right then. Why? Press Flip mid-slide, and the Piece would glide along a line on a Board that isn’t there anymore. Switch Mode switches between them. It runs at the start of the slide, and again when the Piece hides.
Its Other is the Game Rules, which sends slideStarted. Its Shared Variables include Place On Board’s three Numbers again.
Now go to the Set up card and place the two Moving Pieces, hidden. The second sets slide to Rook, and saysWhenLanded to Off. Both are in the placement’s Per Instance Variables. A Boolean there is a switch, and Off is the card’s No.
7.7.3 Show Piece and Square Marks
Shows the Piece that stands on this Piece Object's Square: once the Board is laid out (Lay Out The Board sends "boardLaidOut"), and again after every Move (the Game Rules send "positionChanged"). While the Computer's Move slides ("slideStarted"), a Piece on a Square a slide starts from (the Slides table) shows nothing, because a Moving Piece carries it.
Any Objectself.squareInfo- piece
self
- piece
self
dataFind('Slides', 'from', self.squareInfo.name) != (-1)- Alpha
0
While a Piece slides, the one on its starting Square must vanish, or you’d see it twice. The dataFind in its If looks down the from column of Slides for this Square’s name. It gives -1 when the name isn’t there. Any other answer means a slide starts here, and Set Alpha hides the Piece.
Shows the highlight on this Square after every change (the Game Rules send "positionChanged" and are its Other): a tint when it was part of the last Move, when its Piece is selected, or when its King is in Check (the most important one shows). The colors, and how strongly each shows, are its Parameters. While the Computer's Move slides ("slideStarted"), no highlight is shown.
Any Objectself.squareInfo- Alpha
0
self.squareInfo.name == other.boardState.lastFrom || self.squareInfo.name == other.boardState.lastTo- Value
@self.lastMoveColor
- Alpha
@self.lastMoveAlpha
self.squareInfo.name == other.boardState.selected- Value
@self.selectedColor
- Alpha
@self.selectedAlpha
self.squareInfo.name == other.boardState.checkSquare- Value
@self.checkColor
- Alpha
@self.checkAlpha
- Alpha
0
Square Marks hides its color for the slide too. The Move sets it again when it lands.
Run the game. Play e2 to e4.
For a moment, the words under the Board say Thinking…. Then a Black Piece lifts from its Square and glides to a new one, slow at the start and slow at the end. The words go back to Your move.
The chair across the table isn’t empty anymore. Which Move it chose is up to Stockfish, and it may choose another next time.
7.8 When the Computer Can’t Answer
You may never see this part. It shows only if Stockfish fails to start or to answer.
7.8.1 Report Retry
What the Retry button does: it tells whoever listens (the Game Rules) with "retryPressed".
Any Object- Custom Event
retryPressed
Report Retry is one more button’s Logic Component. UI Activated starts it. It sends retryPressed, as Report Flip sends its message.
7.9 Undo
Undo needs a new button, and an idea. How do you take a Move back, when Board State doesn’t remember the Board before it? Undo doesn’t run the game backward. It sets the Board up fresh, and makes every Move still in the Move History again, quickly, where you can’t see. That’s why Record Move came first.
7.9.1 Go Back To The Start
Puts the game back as it is when a game starts: the starting position, every castling allowed again, no position seen yet, and nothing marked (the tables as they were made), and Board State as a game starts: White to move, no en passant Square, no Moves counted for the fifty-move rule, no last Move, and nothing selected. gameRules: the Game Rules Object.
boardStateData StructureBoard State- Table
Position
- Table
Castling
- Table
Position History
- Component Value
gameRules.boardState.sideToMove- Value
'White'
- Component Value
gameRules.boardState.enPassantSquare- Value
''
- Component Value
gameRules.boardState.fiftyMoveCount- Value
0
- Component Value
gameRules.boardState.lastFrom- Value
''
- Component Value
gameRules.boardState.lastTo- Value
''
- Component Value
gameRules.boardState.selected- Value
''
Go Back To The Start sets everything as a new game has it, the tables and Board State alike. Reset Data Table, which emptied Slides in Plan The Slide, puts each table back the way you made it, every row as it was.
7.9.2 Take Back Moves
Takes back every Move after the first movesKept Moves: they leave the Move History, the game goes back to its start (Go Back To The Start), and the Moves kept are made again in order, as the game made them, with the position of each Turn recorded first (as at the start of every Turn) so threefold repetition still counts them. Castling, en passant, Promotion, and the fifty-move count come back as they were, because every Move is made with Make Move. gameRules: the Game Rules Object. movesKept: how many Moves, from the first, stay made.
boardStateData StructureBoard State- Type
Text- Name
movedFrom
- Type
Text- Name
movedTo
- Type
Text- Name
landingKind
dataCount('Move History') - movesKepttimes- Action Name
addedRow- Operation
Remove- Table
Move History- Row
dataCount('Move History') - 1
- gameRules
gameRules
movesKepttimes- Variable
movedFrom- Value
data('Move History', local.index, 'from')
- Variable
movedTo- Value
data('Move History', local.index, 'to')
- Variable
landingKind- Value
data('Move History', local.index, 'landingKind')
- gameRules
gameRules
- gameRules
gameRules- from
movedFrom- to
movedTo
- Table
Position- Row
movedTo- Column
"kind"- Value
landingKind
- gameRules
gameRules
Take Back Moves keeps the first movesKept Moves, and forgets the rest. The first Repeat removes rows from the bottom of the Move History, one each time round, with Control Data Row’s Operation on Remove.
Next the game goes back to the start. The second Repeat makes each Move it kept, in order. For each one, it records the position first, as Look For Game End does at the start of a Turn. Make Move makes it, the Piece gets the Kind it landed as, and the Turn passes.
Castling, en passant, a Promotion and the fifty-move count all come back as they were. No rule of Undo’s own does that. Make Move does it, the same Make Move as in play.
7.9.3 Undo
Make Undo Data before the Logic, and add it beside Board State with undoData as its slot name. It keeps movesKept while Undo rebuilds the game.
What Undo remembers on the Game Rules. movesKept: how many Moves of the Move History stay when the Player's last Turn is taken back (Take Back Moves plays them again).
Takes back the Player's last Turn when the Player presses Undo ("undoPressed"): the Computer's reply and the Player's Move before it, or only the Player's Move when the Computer has not replied (it is still thinking, or the game ended on that Move). Then that Turn starts again, as play went: a finished game is played again, and if the Turn is the Computer's (a Player who plays Black, back at the start), the Computer moves again. A Stockfish answer still on its way counts for nothing, because the Game State is no longer Computer's Turn. Undo answers only when a Move has been made, and not while the Promotion choice or a menu (the New Game panel) is open.
Any Objectself.boardStateself.undoDatadataCount('Move History') > 0- Component Value
self.undoData.movesKept- Value
dataCount('Move History') - 1
self.boardState.sideToMove == self.boardState.playerSide && self.undoData.movesKept > 0- Component Value
self.undoData.movesKept- Operator
-=- Value
1
- gameRules
self- movesKept
self.undoData.movesKept
- Game State
Playing
- gameRules
self
- Custom Event
positionChanged
Undo hears undoPressed. Is there a Move to take back? If so, movesKept starts as every Move but the last. And if it’s your Turn now, the last Move was the Computer’s reply, so your Move before it goes too. Step 4’s Operator is -=.
That If has a second test, self.undoData.movesKept > 0, joined with &&. Play Black, and the Computer’s first Move may be the only one there is. Then there’s no Move of yours to take back with it, and the count must not go below zero.
Take Back Moves does the work. Set Game State turns the sign back to Playing, even on a finished game, and Start The Turn starts this Turn again. If that Turn is the Computer’s, it asks Stockfish once more.
Its description says Undo doesn’t answer while the Promotion choice or the New Game panel is open. No step on the card does that. The Backdrop does. It lies over the buttons while a panel is open, so a press never reaches Undo.
Attach Undo to the Game Rules now. That’s the line on the Game Rules’ card that waited.
7.9.4 Can Undo
Asks whether the Undo button can be used: once a Move has been made (the Move History has a row). isOn (returned): true when it can.
- Type
Boolean- Name
isOn- Value
false
dataCount('Move History') > 0- Variable
isOn- Value
true
- Value
isOn
Can Undo asks whether there’s a Move left to take back. Its Return Type is Boolean. The Return hands back isOn, which its caller reads as value.
7.9.6 Report Undo
Now the button’s job. Report Undo sends undoPressed when the button is pressed. On positionChanged it asks Can Undo, named canUse. Show Button On Or Off takes that answer as canUse.value, with self in button. Here self is the Undo button.
What the Undo button does: it tells whoever listens (the Game Rules) with "undoPressed". After every change on the Board ("positionChanged"), which the Game Rules also send when the game begins, it asks Can Undo whether the button can be used now, and turns it on or off (Show Button On Or Off).
Any ObjectUI Interaction- Custom Event
undoPressed
- Action Name
canUse
- button
self- isOn
canUse.value
7.10 New Game, One More Check
Starts every game with the Side and the Strength the Player chose last, and lets the Player start a new game. When the game begins (Game Start, before the first Turn), it takes the choices saved on this device (Persistent Values), when the game has them (the Sides and Strengths tables; otherwise, and the first time, Board State's own playerSide and strength), and turns the Board over for a Player who plays Black. When the Player presses New Game ("newGamePressed"), it opens the New Game panel, a menu that holds the game while it is open, showing the current choices as chosen and asking "Replace the current game?" when a game is in progress and has Moves. Each Side or Strength pressed ("sideChosen", "strengthChosen"; the button is its Other) becomes the chosen one. Play ("playPressed") saves the choices and restarts the game, which starts again from the beginning with them.
Any Objectself.boardState- Action Name
savedSide- Key
"playerSide"- Default
self.boardState.playerSide
- Action Name
savedStrength- Key
"strength"- Default
self.boardState.strength
- Component Value
self.boardState.playerSide- Value
savedSide.value
- Component Value
self.boardState.strength- Value
savedStrength.value
- Action Name
isKnownSide- Table
Sides- Row
savedSide.value
isKnownSide.value == true- Component Value
self.boardState.playerSide- Value
savedSide.value
- Action Name
isKnownStrength- Table
Strengths- Row
savedStrength.value
isKnownStrength.value == true- Component Value
self.boardState.strength- Value
savedStrength.value
self.boardState.playerSide == "Black"- Component Value
self.boardState.isFlipped- Value
true
- Component Value
self.boardState.chosenSide- Value
self.boardState.playerSide
- Component Value
self.boardState.chosenStrength- Value
self.boardState.strength
- Menu Element
New Game Panel
- Menu Element
New Game Panel
- Action Name
isOver- Game State
Game Over
self.boardState.lastFrom != "" && isOver.value == false- Element
Replace Question
- Element
Replace Question- Visible
No
- Custom Event
newGameChoiceChanged
- Component Value
self.boardState.chosenSide- Value
other.newGameOption.option
- Custom Event
newGameChoiceChanged
- Component Value
self.boardState.chosenStrength- Value
other.newGameOption.option
- Custom Event
newGameChoiceChanged
- Action Name
persistentWriteResult- Key
"playerSide"- Value
self.boardState.chosenSide
- Action Name
persistentWriteResult2- Key
"strength"- Value
self.boardState.chosenStrength
New Game used to trust whatever Side and Strength it found saved. Now it checks first. Check Data Row Exists asks the Sides table, and then the Strengths table, whether it has a row of that name. A saved word the game doesn’t know is passed over, and Board State keeps its own White and Casual. Why now? From this chapter, Ask The Computer reads the Strength’s row of Strengths. A word with no row there would leave the Computer nothing to read. Each If reads that check’s answer. The new steps go in the middle of the line, between steps 2 and 9.
Here’s a quiet surprise. Play as Black, and the Computer moves first. There’s no step for it. White’s first Turn starts, Look For Game End sends gameContinues, and it’s the Computer’s Turn.
Watch for each of these.
- Start a game as White, and Undo is faded. Play e2 to e4. Thinking… shows, and a Black Piece glides to its Square, and Your move comes back.
- Click a Black Piece while the words say Thinking…. Nothing answers.
- After a reply, press Undo. Your Move and the reply both go, and Undo fades.
- Press New Game, choose Black, and press Play. The Board turns. The Computer makes White’s first Move, and a White Piece glides on the far side of the Board.
- Choose Gentle, and play a few Moves. Try Expert after that. Expert thinks for 1.2 seconds against Gentle’s 0.2, and it plays a good deal better.
- If the Computer castles, its King and its Rook glide together.
- Press Flip while a Piece is gliding. The glide is over in a moment, so give yourself time: set slideSeconds to
3on Slide Piece’s Shared Variables card, for one run. The Piece lands at once, in its place on the turned Board. Then put slideSeconds back to0.36.
The game asks, and goes on. Stockfish answers with a message, and the game checks the Move before it trusts it. The Moving Piece glides it home. Make Move makes it, the same Make Move as yours, and the Move History writes it down. Undo makes every Move again from the start.
Underneath is one idea. The Move History is the whole game, and the Board follows from it. So taking a Move back needs no rule of its own. The game starts over without the last Move.
7.11 If It Didn’t Work
This is a long chapter, with messages that cross between the Game Rules, the Library and the Moving Pieces. A slip somewhere is normal. Watch what the game does, and think it through.
A block drawn in red, with a number on the Errors bar? Open the bar. It names the block and what it misses. New Game may still show Chapter 6’s two false Number errors for its saved words. Keep those Values as the card shows. For another error, compare its block with the card, including each quote mark and prefix.
It says Thinking… and stays there, and nothing moves? Stockfish may never have heard the question, so look at Ask The Computer’s Run Code line, letter by letter, and the Library’s Alias, stockfishBridge. Or the answer came, and nobody listened. Is Make Computer Move attached to the Game Rules?
Opponent disconnected shows under the Board, twenty seconds or more after your Move? That’s the clock from Ask The Computer, ringing. Perhaps the Library’s file didn’t import whole, so import stockfish-bridge.js again from the zip.
The Computer’s Piece jumps, and doesn’t glide? Perhaps your computer asks for less motion, and that’s the game being kind to it. If not, look at the two Tween steps.
The Piece glides, but the Move never happens? Only the first Moving Piece says when it lands, so its saysWhenLanded must be Yes, and the Rook’s Off.
You see two of the same Piece during a slide? Look at Show Piece’s new Event, and its != -1.
Undo stays faded? Report Undo’s On Position Changed may have no arrow into Can Undo or Show Button On Or Off. Its isOn must read canUse.value. Undo wakes, but a press does nothing? Then look at the Game Rules, and whether Undo is attached to them. Undo answers, but takes back too much or too little? Look at its step 3 If, and its two tests, joined with &&: your Turn now, and a Move left to keep.
Each of these is one small fix. Make it, run the game again, and you’re back with the chapter. The catch-up download in the Goal is this chapter’s game, finished, if you’d like to compare.
The Computer plays at five Strengths, each one a row of Strengths. What would a sixth be? A Beginner below Gentle, maybe, with a skillLevel of 0 and almost no thinking time. Or a Patient one that thinks for three seconds. Add the row, and a button for it on the panel, a Strength Option placed once more. How your Computer plays is up to you.
Still stuck? Search the manual, or ask in the Myth Engine Discord (opens a new tab).
Your game has an opponent now, one that thinks. In Chapter 8, when you’re stuck, you’ll ask it for a little advice.
