Build a GameCreating Chess

4  Special Moves

Goal

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.

Chess, Chapter 4 finishedMyth project · 15.6 MB

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

Set upWhat this chapter adds
ART (sprites, from the starter kit)
Panel Backdrop
GAME SETTINGS > General > Game State
Available Game StatesPlaying, Promotion
SCENE Chess Table: PLACE THESE
ObjectXY
Panel Backdrop00hidden
Promotion Panel070hidden
Promotion Button-19566hidden
with Data Structure > Values > Kind = Queen
Promotion Button-6566hidden
with Data Structure > Values > Kind = Rook
Promotion Button6566hidden
with Data Structure > Values > Kind = Bishop
Promotion Button19566hidden
with Data Structure > Values > Kind = Knight
Cancel Promotion0-35hidden

GAME 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.

Data StructureBoard StateAddDelete

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).

sideToMoveTextdefault White
selectedTextdefault (empty)
lastFromTextdefault (empty)
lastToTextdefault (empty)
checkSquareTextdefault (empty)
enPassantSquareTextdefault (empty)
promotionSquareTextdefault (empty)

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.

Data StructureCastling Entry

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.

kingFromTextdefault (empty)
kingToTextdefault (empty)
rookFromTextdefault (empty)
rookToTextdefault (empty)
rookPassesTextdefault (empty)
isAllowedBooleandefault true
Data TableCastlingData Structure: Castling Entry
Row 0White Kingside
kingFrome1
kingTog1
rookFromh1
rookTof1
rookPassesg1
isAllowedYes
Row 1White Queenside
kingFrome1
kingToc1
rookFroma1
rookTod1
rookPassesb1
isAllowedYes
Row 2Black Kingside
kingFrome8
kingTog8
rookFromh8
rookTof8
rookPassesg8
isAllowedYes
Row 3Black Queenside
kingFrome8
kingToc8
rookFroma8
rookTod8
rookPassesb8
isAllowedYes

Castling 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.

Data StructureSides EntryAddDelete

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.

forwardNumberdefault 1
pawnRankNumberdefault 2
opponentTextdefault (empty)
promotionRankNumberdefault 8
Data TableSidesData Structure: Sides EntryAddDelete
Row 0White
forward1
pawnRank2
opponentBlack
promotionRank8
Row 1Black
forward-1
pawnRank7
opponentWhite
promotionRank1

Add 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.

Data TableWordsData Structure: Words EntryAddDelete
Row 0Your Move
textYour move
Row 1Check
textCheck
Row 2Promotion
textPromotion: choose a Piece

Add 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.

FunctionUpdate Castling

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).

PARAMETERS
fromText
toText
ACTIONS
1Declare Variable
Type
Text
Name
kind
2Declare Variable
Type
Text
Name
castling
3Change Variable
Variable
kind
Value
data('Position', from, 'kind')
4RepeatdataCount('Castling')times
Each time
5Change Variable
Variable
castling
Value
dataRow('Castling', local.index)
6Ifkind == "King" && data('Castling', castling, 'kingFrom') == from && data('Castling', castling, 'kingTo') == to
Then
7Move PieceFunction
from
data('Castling', castling, 'rookFrom')
to
data('Castling', castling, 'rookTo')
8Ifdata('Castling', castling, 'kingFrom') == from || data('Castling', castling, 'rookFrom') == from || data('Castling', castling, 'rookFrom') == to
Then
9Set Data Cell
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.

FunctionMake Move

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).

PARAMETERS
NameTypeStarts at
gameRulesObjectStructural
Required Components
Slot NameboardState
Component TypeData Structure
Required SchemaBoard State
fromText
toText
ACTIONS
1Declare Variable
Type
Text
Name
kind
2Declare Variable
Name
fromFile
Value
0
3Declare Variable
Name
fromRank
Value
0
4Declare Variable
Name
toFile
Value
0
5Declare Variable
Name
toRank
Value
0
6Declare Variable
Name
passedPawn
Value
0
7Declare Variable
Name
passedRank
Value
0
8Declare Variable
Type
Text
Name
passedSquare
9Change Variable
Variable
kind
Value
data('Position', from, 'kind')
10Change Variable
Variable
fromFile
Value
data('Position', from, 'file')
11Change Variable
Variable
fromRank
Value
data('Position', from, 'rank')
12Change Variable
Variable
toFile
Value
data('Position', to, 'file')
13Change Variable
Variable
toRank
Value
data('Position', to, 'rank')
14Update CastlingFunction
from
from
to
to
15Ifkind == "Pawn" && to == gameRules.boardState.enPassantSquare
Then
16Change Variable
Variable
passedPawn
Value
(fromRank - 1) * 8 + (toFile - 1)
17Set Data Cell
Table
Position
Row
passedPawn
Column
'kind'
Value
''
18Set Data Cell
Table
Position
Row
passedPawn
Column
"side"
Value
''
19Move PieceFunction
from
from
to
to
20Change Component Value
Component Value
gameRules.boardState.enPassantSquare
Value
''
21Ifkind == "Pawn" && abs(toRank - fromRank) == 2
Then
22Change Variable
Variable
passedRank
Value
(fromRank + toRank) / 2
23Change Variable
Variable
passedSquare
Value
dataRow('Position', (passedRank - 1) * 8 + (fromFile - 1))
24Change Component Value
Component Value
gameRules.boardState.enPassantSquare
Value
passedSquare
25Change Component Value
Component Value
gameRules.boardState.lastFrom
Value
from
26Change Component Value
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.

FunctionDrop Move If UnsafeAddDelete

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.

PARAMETERS
fromText
toText
takenText
kingSquareText
enemyText
ACTIONS
1Declare Variable
Type
Text
Name
takenKind
2Declare Variable
Type
Text
Name
takenSide
3Declare Variable
Type
Text
Name
checkSquare
4Change Variable
Variable
takenKind
Value
data('Position', taken, 'kind')
Value
data('Position', to, 'kind')
5Change Variable
Variable
takenSide
Value
data('Position', taken, 'side')
Value
data('Position', to, 'side')
6Set Data Cell
Table
Position
Row
taken
Column
"kind"
Value
''
7Set Data Cell
Table
Position
Row
taken
Column
"side"
Value
''
8Move PieceFunction
from
from
to
to
9Change Variable
Variable
checkSquare
Value
kingSquare
10Iffrom == kingSquare
Then
11Change Variable
Variable
checkSquare
Value
to
12Is Square AttackedFunction
Action Name
kingLook
square
checkSquare
bySide
enemy
13IfkingLook.attacked == true
Then
14Set Data Cell
Table
Targets
Row
to
Column
"reachable"
Value
"false"
15Move PieceFunction
from
to
to
from
16Set Data Cell
Table
Position
Row
taken
Row
to
Column
"kind"
Value
takenKind
17Set Data Cell
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.

FunctionKeep Safe MovesAddDelete

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).

PARAMETERS
fromText
ACTIONS
1Declare Variable
Type
Text
Name
side
2Declare Variable
Type
Text
Name
enemy
3Declare Variable
Type
Text
Name
kingSquare
4Change Variable
Variable
side
Value
data('Position', from, 'side')
5Change Variable
Variable
enemy
Value
data('Sides', side, 'opponent')
6Find KingFunction
Action Name
kingLook
side
side
7Change Variable
Variable
kingSquare
Value
kingLook.value
8RepeatdataCount('Targets')times
Each time
9Ifdata('Targets', local.index, 'reachable') == true
Then
10Drop Move If UnsafeFunction
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.

FunctionTry Castling

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.

PARAMETERS
NameTypeStarts at
castlingNumber0
enemyText
ACTIONS
1Declare Variable
Name
row
Value
0
2Declare Variable
Type
Text
Name
kingFrom
3Declare Variable
Type
Text
Name
kingTo
4Declare Variable
Type
Text
Name
rookTo
5Declare Variable
Type
Text
Name
rookPasses
6Declare Variable
Name
attacks
Value
0
7Change Variable
Variable
row
Value
castling
8Change Variable
Variable
kingFrom
Value
data('Castling', row, 'kingFrom')
9Change Variable
Variable
kingTo
Value
data('Castling', row, 'kingTo')
10Change Variable
Variable
rookTo
Value
data('Castling', row, 'rookTo')
11Change Variable
Variable
rookPasses
Value
data('Castling', row, 'rookPasses')
12Ifdata('Position', kingTo, 'kind') == "" && data('Position', rookTo, 'kind') == "" && data('Position', rookPasses, 'kind') == ""
Then
13Is Square AttackedFunction
Action Name
startLook
square
kingFrom
bySide
enemy
14Change Variable
Variable
attacks
Value
startLook.attackers
15Is Square AttackedFunction
Action Name
crossLook
square
rookTo
bySide
enemy
16Change Variable
Variable
attacks
Operator
+=
Value
crossLook.attackers
17Is Square AttackedFunction
Action Name
landLook
square
kingTo
bySide
enemy
18Change Variable
Variable
attacks
Operator
+=
Value
landLook.attackers
19Ifattacks == 0
Then
20Set Data Cell
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.

FunctionFind En Passant Move

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).

PARAMETERS
fromText
enPassantSquareText
ACTIONS
1Declare Variable
Type
Text
Name
side
2Declare Variable
Type
Text
Name
enemy
3Declare Variable
Name
fromFile
Value
0
4Declare Variable
Name
fromRank
Value
0
5Declare Variable
Name
targetFile
Value
0
6Declare Variable
Name
targetRank
Value
0
7Declare Variable
Name
forward
Value
0
8Declare Variable
Type
Text
Name
passedPawn
9Declare Variable
Type
Text
Name
kingSquare
10Change Variable
Variable
side
Value
data('Position', from, 'side')
11Change Variable
Variable
forward
Value
data('Sides', side, 'forward')
12Change Variable
Variable
fromFile
Value
data('Position', from, 'file')
13Change Variable
Variable
fromRank
Value
data('Position', from, 'rank')
14Change Variable
Variable
targetFile
Value
data('Position', enPassantSquare, 'file')
15Change Variable
Variable
targetRank
Value
data('Position', enPassantSquare, 'rank')
16IfenPassantSquare != "" && data('Position', from, 'kind') == "Pawn" && (targetRank - fromRank) == forward && abs(targetFile - fromFile) == 1
Then
17Change Variable
Variable
passedPawn
Value
dataRow('Position', (fromRank - 1) * 8 + (targetFile - 1))
18Set Data Cell
Table
Targets
Row
enPassantSquare
Column
"reachable"
Value
"true"
19Find KingFunction
Action Name
kingLook
side
side
20Change Variable
Variable
kingSquare
Value
kingLook.value
21Change Variable
Variable
enemy
Value
data('Sides', side, 'opponent')
22Drop Move If UnsafeFunction
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.7 The Click, and Whose Turn

Select and Move learns all of it now.

4.7.1 Select and Move

Data StructureSelect and Move Data

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.

sideTextdefault (empty)
Logic ComponentSelect and MoveAttach to: Game Rules

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.

Attach toAny Object
DATA STRUCTURES
Board Stateself.boardState
Select and Move Dataself.selectAndMoveData
On Square Clicked
WhensquareClickedCustom Event
1Declare Variable
Type
Text
Name
selectedSquare
2Declare Variable
Type
Text
Name
clickedSquare
3Change Variable
Variable
clickedSquare
Value
other.squareInfo.name
4Change Variable
Variable
selectedSquare
Value
self.boardState.selected
5IfselectedSquare != "" && data('Targets', clickedSquare, 'reachable') == true
Then
6Change Component Value
Component Value
self.selectAndMoveData.side
Value
self.boardState.sideToMove
7Ifdata('Position', selectedSquare, 'kind') == "Pawn" && data('Position', clickedSquare, 'rank') == data('Sides', self.selectAndMoveData.side, 'promotionRank')
Then
8Change Component Value
Component Value
self.boardState.promotionSquare
Value
clickedSquare
9Change Variable
Variable
$status
Value
data('Words', 'Promotion', 'text')
10Set UI Group Visibility
UI Group
"Promotion"
11Set Game State
Game State
Promotion
12Otherwise
13Make MoveFunction
gameRules
self
from
selectedSquare
to
clickedSquare
14Trigger Custom Event on Object
Custom Event
moveMade
15Otherwise
16Ifdata('Position', clickedSquare, 'side') == self.boardState.sideToMove && clickedSquare != selectedSquare
Then
17Change Component Value
Component Value
self.boardState.selected
Value
clickedSquare
18Find Legal MovesFunction
from
clickedSquare
enPassantSquare
self.boardState.enPassantSquare
19Otherwise
20Change Component Value
Component Value
self.boardState.selected
Value
''
21Clear TargetsFunction
22Trigger Custom Event
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.

Logic ComponentStart TurnAttach to: Game RulesAddDelete

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.

Attach toAny Object
DATA STRUCTURES
Board Stateself.boardState
When Created
WhenCreate
1Look For CheckFunction
gameRules
self
2Trigger Custom Event
Custom Event
positionChanged
On Move Made
WhenmoveMadeCustom Event
1Declare Variable
Type
Text
Name
side
2Change Variable
Variable
side
Value
self.boardState.sideToMove
3Change Component Value
Component Value
self.boardState.sideToMove
Value
data('Sides', side, 'opponent')
4Change Component Value
Component Value
self.boardState.selected
Value
''
5Clear TargetsFunction
6Look For CheckFunction
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.

Data StructurePromotion Choice

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.

kindTextdefault (empty)

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.

Logic ComponentReport ChoiceAttach to: Promotion Button, Cancel Promotion

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.

Attach toAny Object
DATA STRUCTURES
Promotion Choiceself.promotionChoice
On Hud Activated
WhenUI Activated
1Trigger Custom Event
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.

Logic ComponentShow Promotion ChoiceAttach to: Promotion Button

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.

Attach toAny Object
DATA STRUCTURES
Promotion Choiceself.promotionChoice
On Position Changed
WhenpositionChangedCustom Event
1Declare Variable
Type
Text
Name
choiceKind
2Declare Variable
Type
Text
Name
side
3Change Variable
Variable
side
Value
other.boardState.sideToMove
4Change Variable
Variable
choiceKind
Value
self.promotionChoice.kind
5Set Frame
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.

ObjectPanel Backdrop
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 960, Y 1100
UI Interaction
GroupPromotion
Sprite
Scene Depth Draw Order19
SpritePanel Backdrop
Transform > SizeX 960, Y 1100

The 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.

ObjectPromotion Panel
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 560, Y 270
UI Interaction
Element TypeText
GroupPromotion
Sprite
Scene Depth Draw Order20
SpriteSquare Highlight
Tint#EFE6CF
Transform > SizeX 560, Y 270
Text / UI
TextPromotion
Font Size26
EmphasisSemibold
Color#503A2B
AlignmentCenter
Transform > PositionX 0, Y 100

The 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.

ObjectPromotion Button
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 120, Y 144
UI Interaction
GroupPromotion
Sprite
Scene Depth Draw Order21
SpriteCarved Walnut Pieces
Transform > PositionX 0, Y 10
Transform > SizeX 104, Y 104
Text / UI
Text{kind}
Font Size15
EmphasisSemibold
Color#503A2B
AlignmentCenter
Transform > PositionX 0, Y -56
Data Structure
Data StructurePromotion Choice
Logic
Report Choice
Show Promotion Choice

The 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.

ObjectCancel Promotion
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 160, Y 40
UI Interaction
GroupPromotion
Sprite
Scene Depth Draw Order21
SpriteSquare Highlight
Tint#E2D5B4
Transform > SizeX 160, Y 40
Text / UI
TextCancel
Font Size18
EmphasisSemibold
Color#503A2B
AlignmentCenter
Data Structure
Data StructurePromotion Choice
Logic
Report Choice

Cancel 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.

Data StructureChoose Promotion Data

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.

chosenKindTextdefault (empty)
landingSquareTextdefault (empty)
Logic ComponentChoose PromotionAttach to: Game Rules

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".

Attach toAny Object
DATA STRUCTURES
Board Stateself.boardState
Choose Promotion Dataself.choosePromotionData
On Promotion Chosen
WhenpromotionChosenCustom Event
1Check Game State
Action Name
isChoosing
Game State
Promotion
2IfisChoosing.value == true
Then
3Change Component Value
Component Value
self.choosePromotionData.chosenKind
Value
other.promotionChoice.kind
4Change Component Value
Component Value
self.choosePromotionData.landingSquare
Value
self.boardState.promotionSquare
5Ifself.choosePromotionData.chosenKind != ""
Then
6Make MoveFunction
gameRules
self
from
self.boardState.selected
to
self.choosePromotionData.landingSquare
7Set Data Cell
Table
Position
Row
self.choosePromotionData.landingSquare
Column
"kind"
Value
self.choosePromotionData.chosenKind
8Trigger Custom Event on Object
Custom Event
moveMade
9Otherwise
10Look For CheckFunction
gameRules
self
11Change Component Value
Component Value
self.boardState.promotionSquare
Value
''
12Set UI Group Visibility
UI Group
"Promotion"
Visible
No
13Set Game State
Game State
Playing
14Trigger Custom Event
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.

ObjectGame RulesAddDelete
Data Structure
Data StructureBoard State
Data Structure
From LogicSelect and Move
Data StructureSelect and Move Data
Data Structure
From LogicChoose Promotion
Data StructureChoose Promotion Data
Logic
Select and Move
Start Turn
Choose Promotion

Attach 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.

Logic ComponentReport ClickAttach to: SquareAddDelete

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.

Attach toAny Object
When Left Is Clicked
WhenMouse Pressed on ObjectMouse button: left
1Trigger Custom Event
Custom Event
squareClicked
1Check Game State
Action Name
isPlaying
Game State
Playing
2IfisPlaying.value == true
Then
3Trigger Custom Event
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.

Play it!

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.
How it works

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.

Challenge

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.