- Learn
- Build a Game
- Chess
- 4 Special Moves
4 Special Moves
By the end of this chapter, your game has the three Moves that surprise new players: castling, en passant, and Promotion. For Promotion, the game stops to ask what a Pawn on the last Rank should become.
The game as it is at the end of this chapter. Click the game to play.
If your game and this chapter part ways, here is the chapter’s finished project. Open it and compare, or start Chapter 5 from it.
To open it, start Myth Engine, choose File › Open Project... and pick the downloaded file.
4.1 The Idea
Play your Board from Chapter 3 for a moment. Clear the two Squares between White’s King and the Rook on h1. Play e2 to e4 and e7 to e5. Move the Knights from g1 to f3 and b8 to c6, and the Bishops from f1 to c4 and f8 to c5. Now click White’s King. Two dots, on e2 and f1. The King can step up or aside, but it can’t castle. Push a Pawn all the way up the Board, and it reaches the last Rank and stays a Pawn.
Chess has three Moves that break the pattern, and this chapter builds all three.
Castling is the King’s one long step. It moves two Squares toward a Rook, and the Rook jumps over it to the Square beside it. That’s allowed only while neither has moved, with nothing between them, and with the King safe on every Square it touches.
En passant catches a Pawn in a hurry. A Pawn may move two Squares on its first Move, and it might land beside an enemy Pawn. That enemy may then capture it as if it had moved only one, by stepping diagonally behind it. It has one chance, on the very next Move, and never again.
Promotion is the Pawn’s reward. A Pawn that reaches the last Rank becomes a Queen, a Rook, a Bishop or a Knight. The player chooses, so the game stops and asks.
Here’s the real problem. Each of these needs the game to remember something the Board doesn’t show. Look at a King on e1. Has it moved away and come back? The picture can’t tell you, and it can’t tell you whether the Pawn on d5 arrived a moment ago, two Squares at once. So the Game Rules start to keep a little history. They write down which castlings are still allowed, and which Square a Pawn has skipped.
Promotion needs one more new thing, a Game State. It’s a single word for what the whole game is doing: Playing, or Promotion. Think of the sign on a shop door. While it says Promotion, the Board takes no clicks, and only the panel answers. When the choice is made, the sign turns back to Playing.
4.2 The Plan
Here’s how the pieces work together. Read each line from left to right, and come back after The Promotion choice.
- You click a Piece -> Select and Move asks Find Legal Moves.
- Find Legal Moves -> Find Moves and Keep Safe Moves, then Try Castling and Find En Passant Move.
- You click a mark -> Select and Move asks Make Move -> Update Castling moves the Rook too, if the King castles.
- A Pawn’s mark on the last Rank -> Select and Move opens the Promotion panel and sets the Game State to Promotion.
- You press a Piece -> Report Choice sends promotionChosen.
- Choose Promotion hears it -> Make Move, and the Pawn becomes the chosen Kind -> moveMade.
- Start Turn hears moveMade -> the selection is cleared, and the Turn passes.
You’ll build the memory first. Next comes the one Function that makes a whole Move, then the ones that find the new Moves, and you’ll castle when Select and Move has changed. The Promotion panel comes last.
4.3 Set Up
Playing, PromotionGAME SETTINGS > General > Game State is new. Your project has Playing already, so add Promotion the way The Set up card says.
The Panel Backdrop is a new picture from the Starter Kit, a dark green sheet you can see through. PLACE THESE puts the panel’s seven pieces on the screen, all hidden. You’ll make them in the last part of the chapter, and come back here to place them then. The four Promotion Buttons are one Object, placed four times. Each placement’s line with Data Structure > Values > Kind says which Piece it offers, and A placement’s own values shows where that box is.
4.4 What the Game Rules Remember Now
Two new fields in Board State hold the short memory.
What the Game Rules remember about the game besides the Position table. sideToMove: the Side whose Turn it is (White moves first). selected: the Square of the selected Piece (empty when none is selected). lastFrom and lastTo: the two Squares of the last Move (empty before the first Move). checkSquare: the Square of the King in Check (empty when the Side to move is not in Check). enPassantSquare: the Square a Pawn has just passed over with a two-Square Move, where an enemy Pawn may take it en passant on the very next Move (empty otherwise). promotionSquare: while the Promotion choice is open, the Square the selected Pawn will be promoted on (empty otherwise).
enPassantSquare is the Square a Pawn has skipped. After e2 to e4, it’s e3, for one Move only. promotionSquare is where a promoting Pawn will land, while the player chooses. Both are Text and start empty, so clear each one’s 0.
The long memory is a table of its own.
One row of the "Castling" Data Table, which follows it. The four castlings, one row per Side and side of the Board. kingFrom and kingTo: where the King starts and lands (it moves two Squares toward the Rook). rookFrom and rookTo: where the Rook starts and lands (on the Square the King crosses). rookPasses: the Square next to the Rook's, which the Rook crosses (on the King's side it is also where the King lands). isAllowed: yes while neither the King nor this Rook has moved and the Rook has not been taken; a new game starts with every castling allowed.
e1g1h1f1g1Yese1c1a1d1b1Yese8g8h8f8g8Yese8c8a8d8b8YesCastling has a row for each of the four castlings: White’s and Black’s, on the King’s side and on the Queen’s. Each row names the King’s Square before and after, and the Rook’s. One more, rookPasses, is a Square that must be empty too, one neither Piece lands on. On the Queen’s side that’s b1, or b8 for Black: the Rook crosses it on its way from a1 to d1. On the King’s side there’s no such Square. The King lands on g1, right beside the Rook’s h1, so those rows give g1 again. Try Castling then looks at g1 twice, and that does no harm.
The last column, isAllowed, comes from a Boolean field. It starts at true. Once a King or its Rook moves, the game sets it to false for good, and that castling is over.
Make Castling Entry’s six fields first, all Text but the last. The table gets its columns from them. Add the four rows. Give each one its name, and type its five Squares. Leave the table’s isAllowed on Yes, the way it shows true.
Next, Sides learns where its Pawns promote.
One row of the "Sides" Data Table, which follows it. One row per Side. forward: the way its Pawns move along the Ranks (1 = up, toward Rank 8; -1 = down). pawnRank: the Rank its Pawns start on. opponent: the other Side. promotionRank: the last Rank for its Pawns, where a Pawn is promoted.
12Black8-17White1Add a Number field to Sides Entry, promotionRank, with 8 in its Value. White’s row keeps the 8. Black’s Pawns march the other way, so its row gets 1.
And Words gets one more row, the words under the Board while the panel is open.
Your moveCheckPromotion: choose a PieceAdd a row named Promotion. Its text is Promotion: choose a Piece.
4.5 One Whole Move
Until now, a Move was one Piece going from one Square to another. Castling moves two Pieces at once. En passant captures a Pawn that isn’t even on the Square you land on. So the game needs one Function that makes a whole Move, whatever kind it is.
4.5.1 Update Castling
This one keeps the Castling table honest. It runs before every Move and looks at all four rows.
Is this Move a King castling? That’s a King leaving a row’s kingFrom for that row’s kingTo. When it is, the Rook goes too, from rookFrom to rookTo, with Move Piece. That’s all castling is to the game. The King’s own two Squares come later, in Make Move, like any other Move.
Now the honest part. Does this Move leave a row’s King Square or its Rook Square, or land on that Rook Square and capture the Rook? Any one of those ends that castling. isAllowed becomes No.
Keeps the Castling table up to date for one Move, before the Move is made. When the Move is a King castling (from its starting Square to a castling's King Square), the Rook moves too. Any Move from the King's or a Rook's starting Square, or onto a Rook's starting Square (taking it), ends that castling for the rest of the game. from and to: the Squares of the Move (a1 to h8).
- Type
Text- Name
kind
- Type
Text- Name
castling
- Variable
kind- Value
data('Position', from, 'kind')
dataCount('Castling')times- Variable
castling- Value
dataRow('Castling', local.index)
kind == "King" && data('Castling', castling, 'kingFrom') == from && data('Castling', castling, 'kingTo') == to- from
data('Castling', castling, 'rookFrom')- to
data('Castling', castling, 'rookTo')
data('Castling', castling, 'kingFrom') == from || data('Castling', castling, 'rookFrom') == from || data('Castling', castling, 'rookFrom') == to- Table
Castling- Row
castling- Column
"isAllowed"- Value
"false"
Step 5 names the row the Repeat is on, castling, so each later step reads that row by name. Step 9’s Row is castling, bare, and its Column is "isAllowed", in quote marks. Its Value is the word "false". In that Boolean column, it lands as false. Steps 6 and 8 are two Ifs, one after the other at the same indent. The first joins its tests with &&. The second uses ||, because any one of its three tests is enough.
4.5.2 Make Move
Make Move is the one whole Move. Select and Move will call it, and so will the Promotion choice. From Chapter 7, the Computer will too.
It’s handed the Game Rules, as gameRules, and the two Squares. Before anything moves, it reads the Piece’s Kind and the File and Rank of both Squares. It asks Update Castling. Next comes the en passant capture. When a Pawn lands on the enPassantSquare, the Pawn it caught is standing beside the Square it left, and that Pawn goes. After all that, the Piece itself moves, with Move Piece.
Last comes the memory. The old enPassantSquare is emptied, because its one chance is over. If this Move was a Pawn’s two-Square start, the Square it skipped becomes the new one. And the Move’s two Squares become the last Move, for the soft yellow.
Makes one Legal Move on the Position table, with everything it brings: the Rook's part of castling, the Pawn taken en passant, the Squares that may be taken en passant on the next Move, and the last Move's Squares. gameRules: the Game Rules Object, whose Board State it updates. from and to: the Squares of the Move (a1 to h8).
boardStateData StructureBoard State- Type
Text- Name
kind
- Name
fromFile- Value
0
- Name
fromRank- Value
0
- Name
toFile- Value
0
- Name
toRank- Value
0
- Name
passedPawn- Value
0
- Name
passedRank- Value
0
- Type
Text- Name
passedSquare
- Variable
kind- Value
data('Position', from, 'kind')
- Variable
fromFile- Value
data('Position', from, 'file')
- Variable
fromRank- Value
data('Position', from, 'rank')
- Variable
toFile- Value
data('Position', to, 'file')
- Variable
toRank- Value
data('Position', to, 'rank')
- from
from- to
to
kind == "Pawn" && to == gameRules.boardState.enPassantSquare- Variable
passedPawn- Value
(fromRank - 1) * 8 + (toFile - 1)
- Table
Position- Row
passedPawn- Column
'kind'- Value
''
- Table
Position- Row
passedPawn- Column
"side"- Value
''
- from
from- to
to
- Component Value
gameRules.boardState.enPassantSquare- Value
''
kind == "Pawn" && abs(toRank - fromRank) == 2- Variable
passedRank- Value
(fromRank + toRank) / 2
- Variable
passedSquare- Value
dataRow('Position', (passedRank - 1) * 8 + (fromFile - 1))
- Component Value
gameRules.boardState.enPassantSquare- Value
passedSquare
- Component Value
gameRules.boardState.lastFrom- Value
from
- Component Value
gameRules.boardState.lastTo- Value
to
Steps 16 and 22 do some counting. A Square’s row in Position comes from its Rank and File: eight rows for each Rank, plus one for each File. The rows count from 0, so a1 is row 0, and that’s why each one takes 1 off first. Step 16 finds the caught Pawn that way. Here passedPawn is that row number, so it’s a Number. Step 22 finds the Rank halfway along the Pawn’s two-Square rush, and step 23 turns it into a Square’s name.
Steps 17 and 18 name two columns of Position, 'kind' and "side", each in its quote marks. Make Move also declares kind, so without them, the Column would read that name instead. Both kinds make a word.
Its Parameter gameRules is an Object, Structural, with a Board State in boardState, as in Look For Check. The others are Text.
4.6 Finding the Special Moves
Making a Move is half the work, and the other half is the dots. Two new Functions find the special Moves, and Chapter 3’s try, check, take back needs one change before them.
4.6.1 Drop Move If Unsafe
Drop Move If Unsafe tries a Move and takes it back. For en passant, that isn’t quite enough. The captured Pawn stands beside the Square the Move lands on. So the try has to lift it away first, and the take back has to put it back.
So the Function gets a new Text Parameter, taken: the Square of the Piece the Move would capture. For every ordinary Move, that’s the same Square as to. Only en passant hands it another.
Tries one marked Move on the Position table, asks whether the mover's own King is then attacked, and takes the Move back, so the Position is as it was; if the King would be attacked, the Move is unmarked in the Targets table. from and to: the Squares of the Move (a1 to h8). taken: the Square of the Piece the Move would take: the same as to, except for en passant. kingSquare: where the mover's King stands now. enemy: the other Side.
- Type
Text- Name
takenKind
- Type
Text- Name
takenSide
- Type
Text- Name
checkSquare
- Variable
takenKind- Value
data('Position', taken, 'kind')- Value
data('Position', to, 'kind')
- Variable
takenSide- Value
data('Position', taken, 'side')- Value
data('Position', to, 'side')
- Table
Position- Row
taken- Column
"kind"- Value
''
- Table
Position- Row
taken- Column
"side"- Value
''
- from
from- to
to
- Variable
checkSquare- Value
kingSquare
from == kingSquare- Variable
checkSquare- Value
to
- Action Name
kingLook- square
checkSquare- bySide
enemy
kingLook.attacked == true- Table
Targets- Row
to- Column
"reachable"- Value
"false"
- from
to- to
from
- Table
Position- Row
taken- Row
to- Column
"kind"- Value
takenKind
- Table
Position- Row
taken- Row
to- Column
"side"- Value
takenSide
Add taken with the + on the Start block. Leave its place alone. Steps 4 and 5 read taken now, where they read to. Four Rows hold taken: the new steps 6 and 7, and steps 16 and 17, which put the captured Piece back.
Steps 6 and 7 are new, and they go in the middle of the line, before Move Piece. Here the order matters. The captured Pawn has to be gone before the Move is tried.
Add the two Set Data Cells from the Action List. Leave them apart from the line for now. Click the round handle under step 5, then the one above the new step 6. Step 6 joins there, ahead of Move Piece. Join step 7 after it the same way. Move Piece follows both, with the rest of the line still behind it. Actions, one at a time shows the handles.
That’s how to put a step anywhere in a line. You’ll do it again soon.
4.6.2 Keep Safe Moves
Keep Safe Moves calls Drop Move If Unsafe, so its call has a new box.
Of the Squares marked in the Targets table for the Piece on one Square, unmarks every one that would leave its own King attacked, so only Legal Moves stay marked. from: the Piece's Square (a1 to h8).
- Type
Text- Name
side
- Type
Text- Name
enemy
- Type
Text- Name
kingSquare
- Variable
side- Value
data('Position', from, 'side')
- Variable
enemy- Value
data('Sides', side, 'opponent')
- Action Name
kingLook- side
side
- Variable
kingSquare- Value
kingLook.value
dataCount('Targets')timesdata('Targets', local.index, 'reachable') == true- from
from- to
dataRow('Targets', local.index)- taken
dataRow('Targets', local.index)- kingSquare
kingSquare- enemy
enemy
Step 10’s taken is the same as its to, dataRow('Targets', local.index). Every Move it checks is an ordinary one.
4.6.3 Try Castling
Here’s castling’s long checklist.
Try Castling is handed one row of the Castling table, still allowed, and the enemy’s Side. It reads the row’s Squares and looks along the path between the King and the Rook. Is every Square there empty? Those are kingTo, rookTo and rookPasses, and if any one holds a Piece, there’s no castling.
The lamp from Chapter 3 comes back next, three times. Is Square Attacked looks out from where the King stands, then from the Square it crosses, then from where it lands. Notice the middle one. The Square the King crosses is the one its Rook lands on, rookTo. Each look hands back two answers. One is attacked, Yes or No. The other is attackers, how many enemy Pieces reach that Square. The three attackers are added into attacks. If the sum is 0, the King’s landing Square gets its mark in Targets.
Marks one castling's King Square in the Targets table when the castling is legal now: the Squares between the King and the Rook are empty, and the King is not in Check, does not cross an attacked Square, and does not land on one. castling: the row (0 = first) of the Castling table, still allowed. enemy: the other Side.
- Name
row- Value
0
- Type
Text- Name
kingFrom
- Type
Text- Name
kingTo
- Type
Text- Name
rookTo
- Type
Text- Name
rookPasses
- Name
attacks- Value
0
- Variable
row- Value
castling
- Variable
kingFrom- Value
data('Castling', row, 'kingFrom')
- Variable
kingTo- Value
data('Castling', row, 'kingTo')
- Variable
rookTo- Value
data('Castling', row, 'rookTo')
- Variable
rookPasses- Value
data('Castling', row, 'rookPasses')
data('Position', kingTo, 'kind') == "" && data('Position', rookTo, 'kind') == "" && data('Position', rookPasses, 'kind') == ""- Action Name
startLook- square
kingFrom- bySide
enemy
- Variable
attacks- Value
startLook.attackers
- Action Name
crossLook- square
rookTo- bySide
enemy
- Variable
attacks- Operator
+=- Value
crossLook.attackers
- Action Name
landLook- square
kingTo- bySide
enemy
- Variable
attacks- Operator
+=- Value
landLook.attackers
attacks == 0- Table
Targets- Row
kingTo- Column
"reachable"- Value
"true"
Step 7 copies castling, the row number it was handed, into a declared Variable, row. Steps 8 to 11 read row. It’s the same number under a shorter name, so reading castling would work too.
One word, two things. In Update Castling, castling was a Text Variable holding a row’s name. Here it’s a Parameter holding the row’s number, so make it a Number.
Steps 13, 15 and 17 are three calls to the same Function, each with its own Action Name: startLook, crossLook and landLook. Step 14 sets attacks. Steps 16 and 18 add on with +=. Step 12’s If joins three tests with &&, and each compares with an empty text.
4.6.4 Find En Passant Move
This one is all about one Pawn’s chance.
Find En Passant Move is handed a Piece’s Square and the enPassantSquare. Four things must be true at once before a dot goes on.
- There is an enPassantSquare.
- The Piece is a Pawn.
- That Square is one Rank ahead, the way the Pawn’s forward points.
- It’s one File to the left or right.
When all four hold, the enemy Pawn stands on this Pawn’s own Rank, in the enPassantSquare’s File. That’s passedPawn. Here it’s the Square’s name, so it’s Text, not the Number it was in Make Move.
The mark goes on, and Drop Move If Unsafe gets its say, with passedPawn as taken. Can an en passant capture leave its own King attacked? It can, so the game checks before it offers you that dot.
Marks the en passant Square in the Targets table when the Pawn on one Square may take en passant there, and the Move does not leave its own King attacked. from: the Pawn's Square (a1 to h8). enPassantSquare: the Square an enemy Pawn has just passed over (empty when none).
- Type
Text- Name
side
- Type
Text- Name
enemy
- Name
fromFile- Value
0
- Name
fromRank- Value
0
- Name
targetFile- Value
0
- Name
targetRank- Value
0
- Name
forward- Value
0
- Type
Text- Name
passedPawn
- Type
Text- Name
kingSquare
- Variable
side- Value
data('Position', from, 'side')
- Variable
forward- Value
data('Sides', side, 'forward')
- Variable
fromFile- Value
data('Position', from, 'file')
- Variable
fromRank- Value
data('Position', from, 'rank')
- Variable
targetFile- Value
data('Position', enPassantSquare, 'file')
- Variable
targetRank- Value
data('Position', enPassantSquare, 'rank')
enPassantSquare != "" && data('Position', from, 'kind') == "Pawn" && (targetRank - fromRank) == forward && abs(targetFile - fromFile) == 1- Variable
passedPawn- Value
dataRow('Position', (fromRank - 1) * 8 + (targetFile - 1))
- Table
Targets- Row
enPassantSquare- Column
"reachable"- Value
"true"
- Action Name
kingLook- side
side
- Variable
kingSquare- Value
kingLook.value
- Variable
enemy- Value
data('Sides', side, 'opponent')
- from
from- to
enPassantSquare- taken
passedPawn- kingSquare
kingSquare- enemy
enemy
Step 16’s If joins all four tests with &&. Type its whole condition as the card spells it, as you did in Chapter 3.
4.6.5 Find Legal Moves
Now the three ways of finding Moves come together, in Find Legal Moves. Picture Targets as one sheet of paper. Find Moves wipes it clean and dots every ordinary Move. Keep Safe Moves crosses out the unsafe ones, as in Chapter 3. Then two more hands add their dots to the same sheet, a castling dot and an en passant dot, each already checked for safety. Nobody wipes the sheet again, so every dot stays for Select and Move to show.
Finds every Legal Move of the Piece on one Square and marks them in the Targets table: the ordinary Moves of its Kind that do not leave its own King attacked, then castling and en passant when they are legal. from: the Piece's Square (a1 to h8). enPassantSquare: the Square an enemy Pawn has just passed over (empty when none).
- Type
Text- Name
side
- Type
Text- Name
enemy
- Variable
side- Value
data('Position', from, 'side')
- Variable
enemy- Value
data('Sides', side, 'opponent')
- from
from
- from
from
dataCount('Castling')timesdata('Castling', local.index, 'kingFrom') == from && data('Castling', local.index, 'isAllowed') == true- castling
local.index- enemy
enemy
- from
from- enPassantSquare
enPassantSquare
Only a King on its starting Square can match a row, so for every other Piece, step 9 never runs. Its castling box takes local.index, the row the Repeat is on.
4.7 The Click, and Whose Turn
Select and Move learns all of it now.
4.7.1 Select and Move
What Select and Move remembers on the Game Rules. side: the Side to move (White or Black), to know the Rank where its Pawns promote.
Decides what a click on a Square means. A click on a Square the selected Piece may move to makes that Move (Make Move: castling and en passant included) and tells the Game Rules "moveMade" (Start Turn then starts the other Side's Turn); when the Move takes a Pawn to its last Rank, it opens the Promotion choice instead (Game State Promotion), and Choose Promotion makes the Move. A click on a Piece of the Side to move selects it and marks its Legal Moves (Find Legal Moves); any other click clears the selection. Then it tells everyone "positionChanged". Its Other is the clicked Square.
Any Objectself.boardStateself.selectAndMoveData- Type
Text- Name
selectedSquare
- Type
Text- Name
clickedSquare
- Variable
clickedSquare- Value
other.squareInfo.name
- Variable
selectedSquare- Value
self.boardState.selected
selectedSquare != "" && data('Targets', clickedSquare, 'reachable') == true- Component Value
self.selectAndMoveData.side- Value
self.boardState.sideToMove
data('Position', selectedSquare, 'kind') == "Pawn" && data('Position', clickedSquare, 'rank') == data('Sides', self.selectAndMoveData.side, 'promotionRank')- Component Value
self.boardState.promotionSquare- Value
clickedSquare
- Variable
$status- Value
data('Words', 'Promotion', 'text')
- UI Group
"Promotion"
- Game State
Promotion
- gameRules
self- from
selectedSquare- to
clickedSquare
- Custom Event
moveMade
data('Position', clickedSquare, 'side') == self.boardState.sideToMove && clickedSquare != selectedSquare- Component Value
self.boardState.selected- Value
clickedSquare
- from
clickedSquare- enPassantSquare
self.boardState.enPassantSquare
- Component Value
self.boardState.selected- Value
''
- Custom Event
positionChanged
Here is Select and Move’s whole card as it ends this chapter. Two things change. A click on a mark makes the Move with Make Move, unless a Pawn is reaching its last Rank, where the Move waits for the player’s choice. And a click on a Piece asks Find Legal Moves.
Select and Move needs to remember whose Turn it is, so make Select and Move Data first. Attach it through the + on the canvas’s Data Structures card, with selectAndMoveData as its slot name.
Start with the Then line of step 5. Delete its six old steps, from Move Piece to Clear Targets. The line is empty now. Add its new steps with the If’s Add Inside Then, and join each one. The side is kept in self.selectAndMoveData.side.
Step 7’s If asks two things. Is the selected Piece a Pawn, and is it going to its Side’s promotionRank? Its condition joins both tests with &&.
When both are true, steps 8 to 11 get ready for the choice. The landing Square goes into promotionSquare, and $status takes the Promotion words that will show under the Board. Set UI Group Visibility shows every Object in the group Promotion. Type "Promotion" into its UI Group box, with the quote marks, and leave Visible on true. Then Set Game State turns the sign to Promotion.
The Else, steps 13 and 14, is the ordinary Move: Make Move, with self in gameRules, and then moveMade.
Lower down, in the second If, delete Find Moves and Keep Safe Moves. They are the two calls you built in Chapter 3. Find Legal Moves is step 18 on this whole card. Add it in their place, with clickedSquare in from and self.boardState.enPassantSquare in enPassantSquare.
4.7.2 Start Turn
Select and Move used to clear the selection itself after a Move, and its new Then line doesn’t. A Promotion’s Move comes later, after a button is pressed. Select and Move can’t clear it then. The new Turn does it instead, at its start, for both kinds of Move.
Starts each Turn: the first one (White's) when the game begins, and the next one after every Move (Select and Move or Choose Promotion sends "moveMade"). It gives the Turn to the other Side with nothing selected and no Moves marked, and asks whether that Side is in Check (Look For Check), which sets the Check mark and the status line.
Any Objectself.boardState- 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')
- Component Value
self.boardState.selected- Value
''
- gameRules
self
Steps 4 and 5 go between step 3 and Look For Check. It’s the same move you made in Drop Move If Unsafe. Add the two blocks apart from the line, then use the round handles to join them after step 3, in order.
Run the game. Play e2 to e4 and e7 to e5. Move White’s Knight from g1 to f3, and Black’s from b8 to c6. White’s Bishop goes from f1 to c4, and Black’s from f8 to c5. Click White’s King. Three dots now. Two are e2 and f1, as before, and the new one is g1. Click g1. The King steps over two Squares, and the Rook on h1 jumps to f1.
Try en passant in a new game. Play e2 to e4, a7 to a6 and e4 to e5. Now d7 to d5, the Black Pawn’s two-Square rush, landing right beside yours. Click your Pawn on e5. Two dots wait: e6, one step ahead, and d6, beside it. Click d6, and the Black Pawn on d5 is gone.
Leave the Pawns short of the last Rank for now, because a Pawn that reached it would wait for a panel you haven’t made.
4.8 The Promotion Choice
Now the game learns to stop and ask. The panel is seven pieces on the screen: a sheet to dim the game, a cream card, four Pieces and a Cancel button. They come from four Objects, because the four Pieces are one Object, placed four times.
4.8.1 Promotion Choice
Each button has to say what it stands for, and a small form of one field holds it.
What one button of the Promotion panel stands for. kind: the Kind the Pawn becomes (Queen, Rook, Bishop, or Knight); empty for the button that cancels the Move.
Promotion Choice has one Text field, kind, empty to start. The Queen’s button will carry Queen. The Cancel button carries nothing, and that empty kind is how the game knows it was Cancel.
4.8.2 Report Choice
Press a button, and it says so. That’s all. It doesn’t decide what the choice means, because the Game Rules do that.
When the Player presses this button of the Promotion panel, it tells whoever listens (the Game Rules) with "promotionChosen"; the listener reads the button's Promotion Choice (a Kind, or empty to cancel) as Other.
Any Objectself.promotionChoice- Custom Event
promotionChosen
It hears UI Activated, the Event a Screen UI Object gets when the player presses it. Myth names it On Hud Activated by itself. It sends promotionChosen to everyone, and whoever listens reads the button’s Promotion Choice through other.
4.8.3 Show Promotion Choice
The panel shows real Pieces, in the colors of the Side that’s promoting. Each time the Board changes, every Promotion Button reads whose Turn it is and its own kind, then picks its frame from Kinds.
Shows this Promotion Button's Kind (its Promotion Choice) in the Piece Set art of the Side to move, after every change (the Game Rules send "positionChanged" and are its Other), so the panel always offers the Pieces of the Side that promotes.
Any Objectself.promotionChoice- Type
Text- Name
choiceKind
- Type
Text- Name
side
- Variable
side- Value
other.boardState.sideToMove
- Variable
choiceKind- Value
self.promotionChoice.kind
- Frame
data('Kinds', choiceKind, side)
It’s the reading Show Piece On Square makes in Chapter 2: the row of the Kind, in the column of the Side. Its Other is the Game Rules, the Object that sent positionChanged. Nothing needs making for it.
4.8.4 The Panel’s Objects
Now the four Objects. All four are Screen UI Objects in the UI Group Promotion, so they show and hide together.
Window / UICenterUIX 960, Y 1100Promotion19Panel BackdropX 960, Y 1100The Panel Backdrop covers the whole game, 960 by 1100, in the dark green sheet. It has no Logic at all. Its UI Interaction stays a Button, as it comes, so it takes every click that lands on it. While the panel is open, a click meant for the Board hits the Backdrop instead, and nothing happens. It works by being in the way.
Window / UICenterUIX 560, Y 270TextPromotion20Square Highlight#EFE6CFX 560, Y 270Promotion26Semibold#503A2BCenterX 0, Y 100The Promotion Panel is the cream card, with the word Promotion near its top. Its picture is the plain white square from Chapter 2, and its Tint makes it cream. Nobody presses it, so its Element Type is Text.
Window / UICenterUIX 120, Y 144Promotion21Carved Walnut PiecesX 0, Y 10X 104, Y 104{kind}15Semibold#503A2BCenterX 0, Y -56Promotion ChoiceThe Promotion Button is one Piece from the walnut Piece Set, with its name under it. Its Sprite has a Transform of its own. Positioning stays on Independent, the way a Text / UI’s does. Its Position, X 0 and Y 10, lifts the Piece a little to leave room for the name. Size sits right under it. Its Text {kind} shows its own Promotion Choice, so the Queen’s button says Queen. Give it both Logic Components, Report Choice and Show Promotion Choice.
Window / UICenterUIX 160, Y 40Promotion21Square Highlight#E2D5B4X 160, Y 40Cancel18Semibold#503A2BCenterPromotion ChoiceCancel Promotion is a small button that says Cancel. It carries a Promotion Choice like the others, but its kind stays empty, and that’s the whole difference.
Look at the four Sprites’ Scene Depth Draw Order: 19 for the Backdrop, 20 for the Panel, 21 for the buttons. The higher number wins. So the buttons sit on the card, and the card sits on the sheet.
4.8.5 Choose Promotion
Now the Game Rules answer the panel.
Choose Promotion hears promotionChosen. First it makes sure the game is waiting for a choice, with Check Game State, whose answer isChoosing is true only while the sign says Promotion.
It reads the button’s kind, and the Square the Pawn will land on. If a Piece was chosen, Make Move makes the Pawn’s Move. One Set Data Cell writes the chosen Kind over Pawn, and moveMade passes the Turn. Cancel makes no Move at all. The Pawn stays selected, with its dots, and Look For Check puts the right words back under the Board.
Either way, the choice closes. promotionSquare is emptied, the group is hidden, and the sign turns back to Playing. Last, positionChanged redraws the Board.
What Choose Promotion remembers on the Game Rules while the Promotion choice is made. chosenKind: the Kind the Player chose (empty: the choice was cancelled). landingSquare: the Square the Pawn moves to.
Closes the Promotion choice when the Player presses one of its buttons ("promotionChosen"; the button is its Other). A Kind makes the waiting Pawn Move (Make Move), puts the chosen Kind on the Square, and tells the Game Rules "moveMade"; Cancel makes no Move, and the Pawn stays selected. Then the panel is hidden, the game is played again (Game State Playing), and everyone hears "positionChanged".
Any Objectself.boardStateself.choosePromotionData- Action Name
isChoosing- Game State
Promotion
isChoosing.value == true- Component Value
self.choosePromotionData.chosenKind- Value
other.promotionChoice.kind
- Component Value
self.choosePromotionData.landingSquare- Value
self.boardState.promotionSquare
self.choosePromotionData.chosenKind != ""- gameRules
self- from
self.boardState.selected- to
self.choosePromotionData.landingSquare
- Table
Position- Row
self.choosePromotionData.landingSquare- Column
"kind"- Value
self.choosePromotionData.chosenKind
- Custom Event
moveMade
- gameRules
self
- Component Value
self.boardState.promotionSquare- Value
''
- UI Group
"Promotion"- Visible
No
- Game State
Playing
- Custom Event
positionChanged
Check Game State’s list and Set Game State’s both show Playing as Playing · Initial, because the game starts in it. Pick Promotion in step 1, and Playing · Initial in step 13, the Set Game State. Step 12’s Visible is No.
Make Choose Promotion Data before its Logic, and add it beside Board State on the canvas’s Data Structures card. Its slot is choosePromotionData. Those fields hold the choice and its landing Square while the Move is made.
Step 7’s Column is "kind", with its quote marks. Its Other is the button that sent promotionChosen, and carries a Promotion Choice in promotionChoice.
Board StateSelect and MoveSelect and Move DataChoose PromotionChoose Promotion DataAttach Choose Promotion to the Game Rules.
4.8.6 Report Click
One promise from The idea is left: while the panel is open, the Board takes no clicks. The Backdrop already stops most of them, and Report Click makes sure of the rest.
When the Player clicks this Square while the game is being played (Game State Playing), it tells whoever listens (the Game Rules) with "squareClicked"; the listener reads which Square it was as Other. While the Promotion choice is open, the Board does not answer.
Any Object- Custom Event
squareClicked
- Action Name
isPlaying- Game State
Playing
isPlaying.value == true- Custom Event
squareClicked
Delete its old step. Add the new ones from the card, with the Trigger inside the If. Check Game State asks whether the sign says Playing. The If keeps every click to itself while the sign says Promotion. Its condition is isPlaying.value == true.
Now go back to the Set up card and place the seven pieces, each hidden. Type each Promotion Button’s Kind into its placement’s Values. The Promotion Panel’s cream and Cancel Promotion’s are already set on their Object cards, in Tint.
Run the game. Play a2 to a4, b7 to b5, a4 to b5, a7 to a6, b5 to a6, c8 to b7, a6 to b7 and b8 to c6. Your Pawn stands on b7, one step from the end. Click it, then b8.
For a moment, the game holds its breath. The Board dims under the dark green sheet, and a cream panel offers four pale Pieces: Queen, Rook, Bishop and Knight. Under the Board it says Promotion: choose a Piece. Click a Square, and nothing answers.
Press Cancel. The panel goes, and your Pawn is still on b7, still selected. Click b8 again and press the Queen, and a White Queen stands on b8, where the Pawn would have landed.
Your Pawns have somewhere to go now.
Watch for each of these.
- Play e2 to e4 and e7 to e5, then the Knights and the Bishops out, as in the castling test. Click White’s King on e1. Dots on e2, f1 and g1. Click g1, and the Rook on h1 lands on f1.
- Move a King away and back again. Its dots never offer castling after that, even with the Squares between clear.
- After e2 to e4, a7 to a6, e4 to e5 and d7 to d5, click the Pawn on e5. Dots on e6 and d6. Take d6, and d5 is empty.
- Wait one Move instead, and the dot on d6 is gone for good.
- Walk a Pawn to the last Rank. The game dims, the panel asks, and Promotion: choose a Piece shows under the Board.
- While the panel is open, click the Board. Nothing happens.
- Press Cancel. The Pawn stays where it was, still selected.
- Choose a Knight. A Knight stands on the last Rank, and the Turn passes.
A Move is one Function now. Make Move carries everything a Move brings: the Rook that castles along, the Pawn taken en passant, the Square a Pawn has skipped. Find Legal Moves adds castling and en passant to the ordinary Moves. And the Promotion panel is a question the game waits on, with the sign on the door saying Promotion.
Underneath is a small idea with a long reach. The Board shows where everything is, never what has happened. Anything a rule needs from the past, the game has to write down while it happens: a castling crossed off for good, a skipped Square kept for exactly one Move.
4.9 If It Didn’t Work
This is the longest chapter yet, and a slip somewhere along the way 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. Hold that block up to the card, quote marks, @ and $ included.
Castling never shows its dot? Start with the Castling table, where four rows of Squares were typed by hand. Perhaps a Square is typed a little off, or isAllowed says false. Next, look at Try Castling’s step 12. Each test compares with an empty text, and && joins them. Or look at Find Legal Moves’ step 8: both tests have to hold.
The King castles, but the Rook stays home? Update Castling’s step 7 moves the Rook, from the row’s rookFrom to its rookTo, when step 6’s If says it should. Look for a test in that condition that doesn’t match the card.
A strange Piece is left behind on d5 after an en passant capture? Make Move’s step 17 needs 'kind', with its quote marks.
The dot on d6 never shows? Make Move may never write the skipped Square, so look at its steps 21 to 24. Or Select and Move’s Find Legal Moves is missing its enPassantSquare, self.boardState.enPassantSquare, in the second box.
An enemy Piece vanishes the moment you click one of yours? Drop Move If Unsafe’s steps 6 and 7 may have landed at the end of the line, where they empty the Square after the Move is put back. They belong before Move Piece. Use the round handles to join them after step 5, and try the Move again.
The panel never shows? Each of the four Objects needs the Group Promotion in its UI Interaction, spelled the same as in Select and Move’s step 10.
The panel shows, but pressing a Piece does nothing? Report Choice may be missing from that Object. Or Choose Promotion isn’t attached to the Game Rules, or its step 1 asks about Playing instead of Promotion.
The Board still answers clicks while the panel is open? Look at Report Click’s Check Game State, which should name Playing, the only state where a click counts.
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 Promotion panel asks the player. What if a Pawn always became a Queen by itself, and the panel never showed? Or what if your chess had a fourth special Move of its own? Picture a Piece that swaps places with a friend once a game, with a table like Castling to remember whether it’s been used. You know where every Move is made now.
Still stuck? Search the manual, or ask in the Myth Engine Discord (opens a new tab).
A Pawn that reached the far side of the Board stands there as a Queen. In Chapter 5, the game learns how it ends.
