Build a GameCreating Chess

9  Threats

Goal

By the end of this chapter, a Threats button sits in the middle of the row. Press it, and the Board shows what could happen next. Every Piece that could be captured turns red. One that nothing could capture back gets a ring, and a pinned one an amber bar.

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 10 from it.

Chess, Chapter 9 finishedZip of a Myth project · 11.8 MB

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.

9.1 The Idea

Play your game from Chapter 8 for a while. Sooner or later the Computer takes one of your Pieces, and you never saw it coming. The Piece stood there for a whole Turn, open to capture, and nothing on the Board said so.

This chapter lets the Board say so. A Threat is a Capture that could happen next, on the very next Move. Press Threats, and the game is in Threats mode. Every Piece an enemy Piece could legally capture turns red, with a red outline around it. That’s an attacked Piece.

Two more marks tell you more. A Piece that’s unprotected has a ring inside its outline, and its red is a little stronger. If it’s captured, nothing of its own Side can capture back. A Piece that’s pinned gets a short amber bar under it. It stands between its own King and an enemy Piece, so moving it would put its King in Check. A small legend under the buttons names all three.

Here’s the hard part. To know whether a Piece is protected, the game has to ask what would happen after a Capture. It has to make the Capture, look, and take it back. A good chess player does this with folded hands, moving the Pieces only in their head. Your game will do the same, in the Position table, for a moment, and the Board on the screen never sees it.

9.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 marks first show.

  • Threats is pressed -> Report Threats sends threatsPressed -> Show Threats turns Threats mode on and calls Find Threats.
  • A Turn starts -> turnStarted -> Show Threats calls Find Threats again.
  • Find Threats -> Mark Captures for every Piece, Mark Pins for each King, Mark Unprotected Pieces -> the Threats table.
  • Every Square, Threat Mark and Pin Mark hears positionChanged -> on the Square, Square Marks tints the red. On its Threat Mark, Show Threat Mark draws the outline and the ring. On its Pin Mark, Show Pin Mark draws the amber bar under the Piece’s foot.

9.3 Set Up

Set upWhat this chapter adds
ART (sprites, from the starter kit)
Threat Marks
Legend Keys
Pin Marks
SCENE Chess Table: PLACE THESE
ObjectXY
Legend Key-1209hidden
with Sprite > Transform > Position = X -23.5, Y 0 (Edit Object Locally)
Legend Key09hidden
with Sprite > Frame = 1 (Edit Object Locally)
with Sprite > Transform > Position = X -34, Y 0 (Edit Object Locally)
with Text / UI > Text = Unprotected (Edit Object Locally)
Legend Key1209hidden
with Sprite > Frame = 2 (Edit Object Locally)
with Sprite > Transform > Position = X -17.5, Y 0 (Edit Object Locally)
with Text / UI > Text = Pinned (Edit Object Locally)
Threats Button040
with Text / UI > Text = Threats (Edit Object Locally)

The three pictures come from the Starter Kit, as before. Leave the placements for now. The legend and the Threats button go in later in the chapter, once Show Threats exists, and the chapter says when.

9.4 Where the Threats Are Kept

A Threat belongs to a Square, so the game keeps one row for each.

9.4.1 Threats

Data StructureThreats Entry

One row of the "Threats" Data Table, which follows it. What Threats mode marks on each Square: one row per Square, a1 to h8, in the same order as the Position table. isAttacked: yes when the Piece standing there can be legally captured by an enemy Piece (the King: when it is in Check). isUnprotected: yes when it is attacked, is not a King, and no Capture of it can be answered by a legal recapture. pinnedBy: the Square of the enemy Queen, Rook, or Bishop that pins the Piece standing there to its own King; empty when it is not pinned. Find Threats fills it while Threats mode is on; otherwise every row is no and empty.

isAttackedBooleandefault false
isUnprotectedBooleandefault false
pinnedByTextdefault (empty)
Data TableThreatsData Structure: Threats Entry

Threats has three columns, made from the fields of Threats Entry. isAttacked and isUnprotected are Yes or No. pinnedBy is Text, and it says more than yes. It holds the Square of the enemy Piece that pins this one. Nothing reads which Square yet. Chapter 10 will.

The table starts with no rows at all, not even one for a1. That’s the next piece’s job.

9.4.2 Board State

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). playerSide: the Side the Player plays (White unless chosen otherwise), so the end of the game can say who won. fiftyMoveCount: the Moves made since the last Capture or Pawn Move, both Sides counted, for the fifty-move rule. isFlipped: whether the Board is drawn turned over, Black at the bottom (false: White at the bottom, a1 at the bottom-left). strength: the Strength the Computer plays at (Gentle, Casual, Club, Strong, or Expert; Casual unless chosen otherwise). chosenSide and chosenStrength: while the New Game panel is open, the Side and the Strength it shows as chosen. isShowingThreats: whether Threats mode is on (the Threats button; kept on this device).

sideToMoveTextdefault White
selectedTextdefault (empty)
lastFromTextdefault (empty)
lastToTextdefault (empty)
checkSquareTextdefault (empty)
enPassantSquareTextdefault (empty)
promotionSquareTextdefault (empty)
playerSideTextdefault White
fiftyMoveCountNumberdefault 0
isFlippedBooleandefault false
strengthTextdefault Casual
chosenSideTextdefault (empty)
chosenStrengthTextdefault (empty)
isShowingThreatsBooleandefault false

Board State gets one more field, isShowingThreats. It’s the one place the game knows whether Threats mode is on.

9.4.3 Clear Threats

FunctionClear Threats

Marks nothing on any Square: the Threats table is emptied, then gets one row for each Square of the Position table, a1 to h8 in the same order, every cell its column's default (no, or empty). The Threats table has no rows of its own; Clear Threats makes them, each time it is used.

ACTIONS
1Declare Variable
Type
Text
Name
square
2Reset Data Table
Table
Threats
3RepeatdataCount('Position')times
Each time
4Change Variable
Variable
square
Value
dataRow('Position', local.index)
5Control Data Row
Action Name
addedRow
Table
Threats
Row
square

Clear Threats wipes the slate. Every Square gets its row back, named as Position names it, and nothing is marked. Its Control Data Row has no Operation line, because it stays as it starts, on adding the row.

9.5 A Walk, Written Once

Before anything is marked, one old piece of Logic gets taken apart.

9.5.1 Find First Piece Along

FunctionFind First Piece Along

Looks back from one Square along one direction of the Directions table, Square by Square, and finds the first Piece in the way. square: the Square looked from (a1 to h8). direction: the row (0 = first) of the Directions table. bySide: the Side whose Pieces move this way (a Pawn's direction is turned round by its Side's forward). firstPiece (returned): the Square of the first Piece, or empty when the edge of the Board, or the end of the direction's steps, comes first.

PARAMETERS
NameTypeStarts at
squareText
directionNumber0
bySideText
RETURN TYPEText
ACTIONS
1Declare Variable
Name
forward
Value
1
2Declare Variable
Name
file
Value
0
3Declare Variable
Name
rank
Value
0
4Declare Variable
Name
stepsLeft
Value
0
5Declare Variable
Type
Boolean
Name
isOnBoard
Value
false
6Declare Variable
Name
index
Value
0
7Declare Variable
Type
Boolean
Name
keepLooking
Value
true
8Declare Variable
Type
Text
Name
firstPiece
9Change Variable
Variable
forward
Value
data('Sides', bySide, 'forward')
10Change Variable
Variable
file
Value
data('Position', square, 'file')
11Change Variable
Variable
rank
Value
data('Position', square, 'rank')
12Change Variable
Variable
stepsLeft
Value
data('Directions', direction, 'steps')
13WhilekeepLooking == true && stepsLeft > 0
Each time
14Change Variable
Variable
file
Operator
-=
Value
data('Directions', direction, 'fileStep')
15Change Variable
Variable
rank
Operator
-=
Value
data('Directions', direction, 'rankStep') * forward
16Change Variable
Variable
stepsLeft
Operator
-=
Value
1
17Change Variable
Variable
isOnBoard
Value
false
18Iffile >= 1 && file <= 8 && rank >= 1 && rank <= 8
Then
19Change Variable
Variable
isOnBoard
Value
true
20Change Variable
Variable
index
Value
(rank - 1) * 8 + (file - 1)
21Change Variable
Variable
keepLooking
Value
false
22IfisOnBoard == true && data('Position', index, 'kind') == ""
Then
23Change Variable
Variable
keepLooking
Value
true
24IfisOnBoard == true && data('Position', index, 'kind') != ""
Then
25Change Variable
Variable
firstPiece
Value
dataRow('Position', index)
26Return
Value
firstPiece

Remember Find Attacker Along, from Chapter 3? It walks from a Square, step by step along a direction, until it meets a Piece. There it asks one question. Could that Piece capture along the line, onto the Square it started from? The pins in this chapter need the same walk. Their question at the end is different.

So the walk moves into a Function of its own, Find First Piece Along. Its walk is Find Attacker Along’s old walk, with the same blocks and values below the Declares. If you built Chapter 3, your hands know them. Only the end changes. Step 24 asks only whether a Piece stands there, and step 25 names its Square in firstPiece. Its Return Type is Text. The Return hands back firstPiece, and a call reads it as value.

Build it with Find Attacker Along open beside it. Read each old block, and build it again here by hand, one at a time.

9.5.2 Find Attacker Along

Almost all of Find Attacker Along is built again, so here is its whole new card.

FunctionFind Attacker Along

Looks back from one Square along one direction of the Directions table for the first Piece in the way (Find First Piece Along). attackers (returned): 1 when that Piece belongs to bySide and is of the direction's Kind, so it could capture onto the Square, else 0 (for a Pawn, the direction is turned round by its Side's forward). square: the Square looked from (a1 to h8). direction: the row (0 = first) of the Directions table. bySide: the attacking Side.

PARAMETERS
NameTypeStarts at
squareText
directionNumber0
bySideText
RETURN TYPENumber
ACTIONS
1Declare Variable
Type
Text
Name
piece
2Declare Variable
Name
attackers
Value
0
3Find First Piece AlongFunction
Action Name
pieceLook
square
square
direction
direction
bySide
bySide
4Change Variable
Variable
piece
Value
pieceLook.value
5Ifpiece != "" && data('Position', piece, 'side') == bySide && data('Position', piece, 'kind') == data('Directions', direction, 'kind')
Then
6Change Variable
Variable
attackers
Value
1
7Return
Value
attackers

Now Find Attacker Along gets short. It asks Find First Piece Along for the first Piece in the way, and checks it the way it always did. Is it on bySide? Is it the direction’s Kind? Then it could capture onto the Square, and attackers is 1.

Open your Find Attacker Along. Keep its Parameters and its Number Return Type, and delete the old line’s blocks. Rebuild the line from the card. Steps 3 and 4 ask Find First Piece Along and read pieceLook.value. The If joins three tests with &&, and they now ask about piece. The Return hands back attackers.

Run the game. The game still knows every rule it did before the walk moved. Now put a King in Check, to see the walk at work. Play e2 to e4, then your Bishop from f1 to c4, and take the Pawn on f7 with it, if the way is still open. Black’s King turns red, so the walk still works from its new home.

9.6 Pieces Under Attack

Now the marks begin. This part makes the red, and the next part the rings and bars.

9.6.1 Mark Captures

FunctionMark Captures

Marks, in the Threats table, every enemy Piece that the Piece on one Square can legally capture. It asks Find Legal Moves, so a Capture that would leave the capturing Side's own King attacked does not count. En passant is left to Find Threats, because the Pawn it takes does not stand on the Square moved to. from: the Square of the capturing Piece.

PARAMETERS
fromText
ACTIONS
1Declare Variable
Type
Text
Name
side
2Declare Variable
Type
Text
Name
enemy
3Declare Variable
Type
Text
Name
target
4Change Variable
Variable
side
Value
data('Position', from, 'side')
5Change Variable
Variable
enemy
Value
data('Sides', side, 'opponent')
6Find Legal MovesFunction
from
from
enPassantSquare
''
7RepeatdataCount('Targets')times
Each time
8Change Variable
Variable
target
Value
dataRow('Targets', local.index)
9Ifdata('Targets', target, 'reachable') == true && data('Position', target, 'side') == enemy
Then
10Set Data Cell
Table
Threats
Row
target
Column
"isAttacked"
Value
"true"

How does the game know a Piece could be captured? It asks the rules you already wrote. Mark Captures takes one Piece, and calls Find Legal Moves for it, the same Find Legal Moves that marks your dots. Every reachable Square with an enemy Piece on it is a Capture. That Piece is attacked. Its row in Threats says so, in isAttacked. Its Value is "true", in quote marks, as in Chapter 3’s Look At Square, and in a Yes or No column the word lands as Yes.

A Capture that would leave the capturing King in Check isn’t legal. It doesn’t count. The rules of chess are written once, and this is that same writing at work.

9.6.2 Find Passed Pawn

FunctionFind Passed Pawn

Finds the Pawn that the Side to move can take en passant right now: the enemy Pawn that has just passed one of its Pawns by moving two Squares. It stands one Rank behind the en passant Square, as seen by the Side to move. gameRules: the Game Rules Object. passedPawn (returned): its Square, or empty when no Pawn can be taken en passant (Can Take En Passant).

PARAMETERS
NameTypeStarts at
gameRulesObjectStructural
Required Components
Slot NameboardState
Component TypeData Structure
Required SchemaBoard State
RETURN TYPEText
ACTIONS
1Declare Variable
Type
Text
Name
enPassant
2Declare Variable
Type
Text
Name
side
3Declare Variable
Name
passedRank
Value
0
4Declare Variable
Name
passedFile
Value
0
5Declare Variable
Type
Text
Name
passedPawn
6Can Take En PassantFunction
Action Name
enPassantLook
gameRules
gameRules
7IfenPassantLook.value == true
Then
8Change Variable
Variable
enPassant
Value
gameRules.boardState.enPassantSquare
9Change Variable
Variable
side
Value
gameRules.boardState.sideToMove
10Change Variable
Variable
passedRank
Value
data('Position', enPassant, 'rank')
11Change Variable
Variable
passedRank
Operator
-=
Value
data('Sides', side, 'forward')
12Change Variable
Variable
passedFile
Value
data('Position', enPassant, 'file')
13Change Variable
Variable
passedPawn
Value
dataRow('Position', (passedRank - 1) * 8 + passedFile - 1)
14Return
Value
passedPawn

En passant is the one Capture where the Piece taken isn’t on the Square moved to. So Mark Captures leaves it out, and Find Passed Pawn finds it. Passed means here that it has gone past, two Squares at once, on the Move before. It isn’t the passed Pawn chess players talk about. Can Take En Passant from Chapter 5 says whether it can happen. If it can, the Pawn stands one Rank behind the en passant Square, as the Side to move sees it.

9.6.3 Find Threats

FunctionFind Threats

Fills the Threats table for the position on the Board: every Piece that an enemy Piece can legally capture is attacked (Mark Captures, for each Piece of both Sides), the King in Check is attacked (Board State's checkSquare), and so is a Pawn that the Side to move can take en passant (Find Passed Pawn); every Piece pinned to its King is marked (Mark Pins, for each King); then every attacked Piece with no legal recapture is unprotected (Mark Unprotected Pieces). gameRules: the Game Rules Object.

PARAMETERS
NameTypeStarts at
gameRulesObjectStructural
Required Components
Slot NameboardState
Component TypeData Structure
Required SchemaBoard State
ACTIONS
1Declare Variable
Type
Text
Name
kingSquare
2Declare Variable
Type
Text
Name
square
3Declare Variable
Type
Text
Name
passedPawn
4Clear ThreatsFunction
5Change Variable
Variable
kingSquare
Value
gameRules.boardState.checkSquare
6IfkingSquare != ""
Then
7Set Data Cell
Table
Threats
Row
kingSquare
Column
"isAttacked"
Value
"true"
8Find Passed PawnFunction
Action Name
passedLook
gameRules
gameRules
9Change Variable
Variable
passedPawn
Value
passedLook.value
10IfpassedPawn != ""
Then
11Set Data Cell
Table
Threats
Row
passedPawn
Column
"isAttacked"
Value
"true"
12RepeatdataCount('Position')times
Each time
13Change Variable
Variable
square
Value
dataRow('Position', local.index)
14Ifdata('Position', square, 'side') != ""
Then
15Mark CapturesFunction
from
square
16Ifdata('Position', square, 'kind') == "King"
Then
17Mark PinsFunction
king
square
18Mark Unprotected PiecesFunction
gameRules
gameRules
passedPawn
passedPawn
19Clear TargetsFunction

Find Threats fills the whole table. It clears it first. Next it marks the King in Check, from checkSquare. A Piece can give Check even while it’s pinned to its own King. Mark Captures wouldn’t count that Capture as legal, because it would leave the capturing King open. It’s Check all the same, so Find Threats marks that King itself. A passed Pawn is attacked too. Then the Repeat walks every Square, and Mark Captures runs for every Piece of both Sides.

Leave steps 16, 17 and 18 for now. Mark Pins and Mark Unprotected Pieces don’t exist yet, and this chapter comes back for them. Build steps 1 to 15, then step 19 after the Repeat.

Why step 19? Find Legal Moves marks the Targets table for every Piece it asks about. Clear Targets empties it again, or your game would show some Piece’s dots that nobody selected.

9.6.4 Show Threats

Logic ComponentShow ThreatsAttach to: Game Rules

Turns Threats mode on and off, and keeps its marks up to date. When the game begins (Game Start) it takes the choice kept on this device (the Persistent Value "threats"), and shows the legend (the UI Group "Threats Legend") when Threats mode is on. At the start of every Turn ("turnStarted") it fills the Threats table again (Find Threats) while Threats mode is on. When the Threats button is pressed ("threatsPressed") on the Player's Turn or after the game has ended, it turns Threats mode over (Board State's isShowingThreats), fills or empties the Threats table, shows or hides the legend, keeps the choice on this device, and every Square redraws ("positionChanged").

Attach toAny Object
DATA STRUCTURES
Board Stateself.boardState
When the Game Starts
WhenGame Start
1Clear ThreatsFunction
2Load Persistent Value
Action Name
savedThreats
Key
"threats"
Default
self.boardState.isShowingThreats
3IfsavedThreats.value == true
Then
4Change Component Value
Component Value
self.boardState.isShowingThreats
Value
true
When Created
WhenCreate
1Ifself.boardState.isShowingThreats == true
Then
2Set UI Group Visibility
UI Group
"Threats Legend"
On Turn Started
WhenturnStartedCustom Event
1Ifself.boardState.isShowingThreats == true
Then
2Find ThreatsFunction
gameRules
self
On Threats Pressed
WhenthreatsPressedCustom Event
1Can Show ThreatsFunction
Action Name
threatsLook
2IfthreatsLook.value == true
Then
3Ifself.boardState.isShowingThreats == true
Then
4Change Component Value
Component Value
self.boardState.isShowingThreats
Value
false
5Clear ThreatsFunction
6Set UI Group Visibility
UI Group
"Threats Legend"
Visible
No
7Otherwise
8Change Component Value
Component Value
self.boardState.isShowingThreats
Value
true
9Find ThreatsFunction
gameRules
self
10Set UI Group Visibility
UI Group
"Threats Legend"
11Ifself.boardState.selected != ""
Then
12Find Legal MovesFunction
from
self.boardState.selected
enPassantSquare
self.boardState.enPassantSquare
13Save Persistent Value
Action Name
persistentWriteResult
Key
"threats"
Value
self.boardState.isShowingThreats
14Trigger Custom Event
Custom Event
positionChanged

Show Threats runs Threats mode, from the Game Rules. It has four Events.

When the Game Starts comes before anything is drawn. Clear Threats gives every Square its row, so nothing reads an empty table. Then Load Persistent Value reads the choice kept on this computer, under 'threats', as New Game read the Side in Chapter 6. A kept true turns Threats mode on.

When Created shows the legend, if Threats mode is on. Set UI Group Visibility shows every Object in the group Threats Legend at once. Its Visible starts on Yes, so leave it. Its UI Group is a box you type in, not a list, so "Threats Legend" goes in now, with its quote marks, before any Legend Key wears it.

On Turn Started finds the threats again, at the start of every Turn. A Move changes them all.

On Threats Pressed is the button. Can Show Threats says whether it can be pressed now. If so, it turns isShowingThreats over, like Flip Board’s coin, from No to Yes or from Yes to No. Turned on, it finds the threats and shows the legend. Turned off, it clears them, and the legend hides with Visible on No. Is a Piece selected? Find Legal Moves runs for it again. Find Threats emptied the Targets its dots come from. Last, Save Persistent Value keeps the choice, and positionChanged tells every Square to look again. Those last three steps come after the inner If and its Else, still inside the first If.

9.6.5 Report Threats and Can Show Threats

FunctionCan Show Threats

Asks whether the Threats button can be used: on the Player's Turn (Game State Playing) or once the game has ended (Game Over), when no Move is being made. isOn (returned): true when it can.

RETURN TYPEBoolean
ACTIONS
1Declare Variable
Type
Boolean
Name
isOn
Value
false
2Check Game State
Action Name
isPlaying
Game State
Playing
3Check Game State
Action Name
isOver
Game State
Game Over
4IfisPlaying.value == true || isOver.value == true
Then
5Change Variable
Variable
isOn
Value
true
6Return
Value
isOn
Logic ComponentReport Threats

What the Threats button does: it tells whoever listens (the Game Rules) with "threatsPressed". After every change on the Board ("positionChanged"), which the Game Rules also send when the game begins, it asks Can Show Threats whether the button can be used now, and turns it on or off (Show Button On Or Off).

Attach toAny Object
COMPONENTS
self.uiUI Interaction
On Hud Activated
WhenUI Activated
1Trigger Custom Event
Custom Event
threatsPressed
On Position Changed
WhenpositionChangedCustom Event
1Can Show ThreatsFunction
Action Name
canUse
2Show Button On Or OffFunction
button
self
isOn
canUse.value

Report Threats sends threatsPressed on UI Activated, as Report Hint sent its message. On positionChanged it asks Can Show Threats, named canUse, then hands canUse.value to Show Button On Or Off. The button keeps its own look up to date. Can Show Threats answers the button’s question. It’s yes on your Turn, and yes once the game is over too, so you can look back at how it ended. While the Computer thinks, it’s no.

9.6.6 Game Rules

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
Data Structure
From LogicMake Computer Move
Data StructureMake Computer Move Data
Data Structure
From LogicUndo
Data StructureUndo Data
Data Structure
From LogicGive A Hint
Data StructureGive A Hint Data
Logic
Select and Move
Start Turn
Choose Promotion
Look For Game End
Flip Board
New Game
Make Computer Move
Undo
Give A Hint
Show Threats

Attach Show Threats to the Game Rules.

9.6.7 Square Marks

Logic ComponentSquare MarksAttach to: SquareAddDelete

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 attacked in Threats mode (the Threats table; a stronger red when it is unprotected), when its Piece is selected, when it is one of the Hint's two Squares (the Chosen Moves table, row Hint), 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.

Attach toAny Object
DATA STRUCTURES
Square Infoself.squareInfo
SHARED VARIABLES
NameTypeKindStarting Value
selectedColorColorConstant#f4d273
selectedAlphaNumberConstant0.44
lastMoveColorColorConstant#e9c44f
lastMoveAlphaNumberConstant0.32
checkColorColorConstant#cd493f
checkAlphaNumberConstant0.66
hintColorColorConstant#61a9b8
hintAlphaNumberConstant0.35
attackedColorColorConstant#d64b46
attackedAlphaNumberConstant0.4
unprotectedAlphaNumberConstant0.5
On Position Changed
WhenpositionChangedCustom Event
1Set Alpha
Alpha
0
2Ifself.squareInfo.name == other.boardState.lastFrom || self.squareInfo.name == other.boardState.lastTo
Then
3Change Sprite Tint Property
Value
@self.lastMoveColor
4Set Alpha
Alpha
@self.lastMoveAlpha
5Ifdata('Threats', self.squareInfo.name, 'isAttacked') == true
Then
6Change Sprite Tint Property
Value
@self.attackedColor
7Set Alpha
Alpha
@self.attackedAlpha
8Ifdata('Threats', self.squareInfo.name, 'isUnprotected') == true
Then
9Set Alpha
Alpha
@self.unprotectedAlpha
10Ifself.squareInfo.name == other.boardState.selected
Then
11Change Sprite Tint Property
Value
@self.selectedColor
12Set Alpha
Alpha
@self.selectedAlpha
13Ifself.squareInfo.name == data('Chosen Moves', 'Hint', 'from') || self.squareInfo.name == data('Chosen Moves', 'Hint', 'to')
Then
14Change Sprite Tint Property
Value
@self.hintColor
15Set Alpha
Alpha
@self.hintAlpha
16Ifself.squareInfo.name == other.boardState.checkSquare
Then
17Change Sprite Tint Property
Value
@self.checkColor
18Set Alpha
Alpha
@self.checkAlpha
On Slide Started
WhenslideStartedCustom Event
1Set Alpha
Alpha
0

Square Marks gains attackedColor, attackedAlpha and unprotectedAlpha as constant Shared Variables, with two Ifs at steps 5 to 9. The first If tints an attacked Square red: attackedColor, at attackedAlpha, 0.4. The second makes it stronger, 0.5, for an unprotected Piece. Nothing marks a Piece unprotected yet. That If waits for the next part of the chapter, and it does no harm to build it now.

Both go after the last Move’s If, and before the selected Square’s. Order matters, as it did for the Hint. Each If paints over the one before it. So a selected Piece shows its gold over the red, and a King in Check its own red.

Add both new Ifs apart from the line. Use the round handles to join the first after step 2’s If, on the main line. Join the second after the first. The selected Square’s If follows them both. Each new If gets its own Actions with Add Inside Then, joined on its True line.

9.6.8 Legend Key

ObjectLegend Key
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorBottom Center
Presentation > Render LayerUI
Bounding Box > SizeX 110, Y 18
UI Interaction
Element TypeText
GroupThreats Legend
Sprite
Scene Depth Draw Order2
SpriteLegend Keys
Transform > PositionX -25, Y 0
Transform > SizeX 12, Y 12
Text / UI
TextAttacked
Font Size12
EmphasisSemibold
Color#6E7968
AlignmentCenter
Transform > PositionX 14, Y 0

A Legend Key is one small picture and one word, side by side. Attacked sits next to a red square. It’s a UI Object in the group Threats Legend, and its Element Type is Text, because nobody presses it.

Now go to the Set up card and place the three keys, hidden, in a row under the buttons. Each sets its own Frame from the Legend Keys picture, and its own word. The words aren’t the same length, so each placement moves its little picture to sit close beside its word, on the left. Even Attacked moves it a little. Its X goes from the Object’s -25 to -23.5.

Now make Threats Button from Tool Button, the way you made Hint Button. Report Threats supplies its job.

Object variantThreats ButtonVariant of: Tool Button
Logic
Report Threats

Place Threats Button from the Set up card, with Threats as its Text. It fills the space in the middle of the row, at X 0, that Chapter 6 left.

Run the game. Press Threats.

The legend appears under the buttons, and the Board shows nothing at all. That’s right. At the start of a game, no Piece can reach an enemy one.

Now play e2 to e4. After the reply, move your Queen from d1 to h5, and look at Black’s side as it lands. The Pawns your Queen could take are red.

9.7 Unprotected and Pinned

The red tells you a Piece could be captured, but not whether losing it would hurt. This part answers two more questions. The chapter’s hard idea lives here too.

9.7.1 Can Capture

FunctionCan Capture

Answers whether the Piece on one Square can legally capture an enemy Piece: the Capture must be one of its Moves, and must not leave its own King attacked. from: the capturing Piece's Square. to: the Square it moves to. taken: the Square of the Piece it takes (the same as to, except en passant). enPassantSquare: the en passant Square when the Capture may be en passant, else empty. canCapture (returned): yes when it can.

PARAMETERS
fromText
toText
takenText
enPassantSquareText
RETURN TYPEBoolean
ACTIONS
1Declare Variable
Type
Text
Name
side
2Declare Variable
Type
Text
Name
enemy
3Declare Variable
Type
Boolean
Name
canCapture
Value
false
4Change Variable
Variable
side
Value
data('Position', from, 'side')
5Change Variable
Variable
enemy
Value
data('Sides', side, 'opponent')
6Find MovesFunction
from
from
7Find En Passant MoveFunction
from
from
enPassantSquare
enPassantSquare
8Ifdata('Targets', to, 'reachable') == true && data('Position', taken, 'side') == enemy
Then
9Find KingFunction
Action Name
kingLook
side
side
10Drop Move If UnsafeFunction
from
from
to
to
taken
taken
kingSquare
kingLook.value
enemy
enemy
11Ifdata('Targets', to, 'reachable') == true && data('Position', taken, 'side') == enemy
Then
12Change Variable
Variable
canCapture
Value
true
13Return
Value
canCapture

Can Capture asks about one Capture only: this Piece, onto that Square. Find Moves and Find En Passant Move mark every Square it could go to, en passant included. Is the Square marked, with an enemy on it? Then Drop Move If Unsafe, from Chapter 3, unmarks it if it would leave its own King in Check. If the Square is still marked after that, the answer is yes.

Step 11 asks step 8’s question again, on the main line after it. Why is that safe? If step 8 said no, nothing in between ran, so step 11 says no too.

It’s Find Legal Moves in miniature. Asking about one Capture is quicker than finding every Move, and this game asks a great many.

9.7.2 Can Side Capture

FunctionCan Side Capture

Answers whether any Piece of one Side can legally capture the enemy Piece on a Square (Can Capture, for each of its Pieces in turn until one can). square: the Square (a1 to h8). bySide: the capturing Side. canCapture (returned): yes when one can.

PARAMETERS
squareText
bySideText
RETURN TYPEBoolean
ACTIONS
1Declare Variable
Type
Text
Name
piece
2Declare Variable
Type
Boolean
Name
canCapture
Value
false
3RepeatdataCount('Position')times
Each time
4Change Variable
Variable
piece
Value
dataRow('Position', local.index)
5Ifdata('Position', piece, 'side') == bySide && canCapture == false
Then
6Can CaptureFunction
Action Name
captureLook
from
piece
to
square
taken
square
enPassantSquare
''
7Change Variable
Variable
canCapture
Value
captureLook.value
8Return
Value
canCapture

Can Side Capture asks the same of a whole Side. It walks every Square, and asks Can Capture of each Piece on bySide. As soon as one says yes, the If stops asking, and the answer is yes.

9.7.3 Can Recapture

FunctionCan Recapture

Answers whether a Capture can be answered: the Piece on from legally captures, and then a Piece of the captured Side can legally capture back on the Square it moved to. Pinned Pieces cannot, since every Capture is a Legal Move. from: the capturing Piece's Square. to: the Square it moves to. taken: the Square of the Piece it takes (the same as to, except en passant). enPassantSquare: the en passant Square for an en passant Capture, else empty. canRecapture (returned): yes when the Capture can be made and answered.

PARAMETERS
fromText
toText
takenText
enPassantSquareText
RETURN TYPEBoolean
ACTIONS
1Declare Variable
Type
Text
Name
takenKind
2Declare Variable
Type
Text
Name
defender
3Declare Variable
Type
Boolean
Name
canRecapture
Value
false
4Change Variable
Variable
takenKind
Value
data('Position', taken, 'kind')
5Change Variable
Variable
defender
Value
data('Position', taken, 'side')
6Can CaptureFunction
Action Name
captureLook
from
from
to
to
taken
taken
enPassantSquare
enPassantSquare
7IfcaptureLook.value == true
Then
8Set Data Cell
Table
Position
Row
taken
Column
"kind"
Value
''
9Set Data Cell
Table
Position
Row
taken
Column
"side"
Value
''
10Move PieceFunction
from
from
to
to
11Can Side CaptureFunction
Action Name
recaptureLook
square
to
bySide
defender
12Change Variable
Variable
canRecapture
Value
recaptureLook.value
13Move PieceFunction
from
to
to
from
14Set Data Cell
Table
Position
Row
taken
Column
"kind"
Value
takenKind
15Set Data Cell
Table
Position
Row
taken
Column
"side"
Value
defender
16Return
Value
canRecapture

Here’s the chapter’s one hard idea. Take it slowly.

A Piece is protected when, after an enemy captures it, its own Side can capture back. So the game has to look one Move ahead. Can Recapture does it the way a player does in their head.

First it notes the taken Piece’s Kind and Side, takenKind and defender, so it can put them back. Then it asks Can Capture whether the Capture is legal at all. If it is, the If makes it, for real, in the Position table. Two Set Data Cells lift the taken Piece off. Move Piece carries the capturing Piece onto its Square.

Now the question. Can Side Capture asks whether any Piece of the defender’s Side could capture back on that Square. Its answer is canRecapture.

After that, everything goes back where it was, in the opposite order. Move Piece carries the Piece home again. The last two Set Data Cells put the taken Piece back, its Kind and its Side.

It looks like the game moves Pieces to find out. It does. But only in the table, and only for a moment. Nothing sends positionChanged in between, so no Square, Piece or mark ever redraws. On the screen, the Board never moves.

And here’s a quiet thing it gets right. A pinned Piece can’t capture back, because its Capture would leave its King in Check. Can Capture already says no to that. So a pinned defender is no protection at all.

9.7.4 Is Unprotected

FunctionIs Unprotected

Answers whether an attacked Piece is unprotected: no enemy Capture of it can be answered by a legal recapture (Can Recapture, for each enemy Piece in turn until one Capture can be answered). square: the Piece's Square. passedPawn: the Pawn the Side to move can take en passant, else empty (Find Passed Pawn). enPassantSquare: the en passant Square. isUnprotected (returned): yes when it is unprotected.

PARAMETERS
squareText
passedPawnText
enPassantSquareText
RETURN TYPEBoolean
ACTIONS
1Declare Variable
Type
Text
Name
side
2Declare Variable
Type
Text
Name
enemy
3Declare Variable
Type
Text
Name
attacker
4Declare Variable
Type
Boolean
Name
isProtected
Value
false
5Declare Variable
Type
Boolean
Name
isUnprotected
Value
false
6Change Variable
Variable
side
Value
data('Position', square, 'side')
7Change Variable
Variable
enemy
Value
data('Sides', side, 'opponent')
8RepeatdataCount('Position')times
Each time
9Change Variable
Variable
attacker
Value
dataRow('Position', local.index)
10Ifdata('Position', attacker, 'side') == enemy && isProtected == false
Then
11Can RecaptureFunction
Action Name
recaptureLook
from
attacker
to
square
taken
square
enPassantSquare
''
12Change Variable
Variable
isProtected
Value
recaptureLook.value
13Ifsquare == passedPawn && data('Position', attacker, 'kind') == "Pawn" && data('Position', attacker, 'side') == enemy && isProtected == false
Then
14Can RecaptureFunction
Action Name
enPassantLook
from
attacker
to
enPassantSquare
taken
square
enPassantSquare
enPassantSquare
15Change Variable
Variable
isProtected
Value
enPassantLook.value
16IfisProtected == false
Then
17Change Variable
Variable
isUnprotected
Value
true
18Return
Value
isUnprotected

Is Unprotected asks Can Recapture about every enemy Piece that might capture this one. One Capture with an answer is enough, and isProtected is yes. If none has an answer, the Piece is unprotected.

The second If is en passant again. A passed Pawn is taken from a different Square, the en passant Square, so that Capture gets its own question.

9.7.5 Mark Unprotected Pieces

FunctionMark Unprotected Pieces

Marks, in the Threats table, every attacked Piece other than a King that is unprotected (Is Unprotected). It runs once every attacked Piece is marked. gameRules: the Game Rules Object. passedPawn: the Pawn the Side to move can take en passant, else empty (Find Passed Pawn).

PARAMETERS
NameTypeStarts at
gameRulesObjectStructural
Required Components
Slot NameboardState
Component TypeData Structure
Required SchemaBoard State
passedPawnText
ACTIONS
1Declare Variable
Type
Text
Name
enPassant
2Declare Variable
Type
Text
Name
square
3Change Variable
Variable
enPassant
Value
gameRules.boardState.enPassantSquare
4RepeatdataCount('Position')times
Each time
5Change Variable
Variable
square
Value
dataRow('Position', local.index)
6Ifdata('Threats', square, 'isAttacked') == true && data('Position', square, 'kind') != "King"
Then
7Is UnprotectedFunction
Action Name
unprotectedLook
square
square
passedPawn
passedPawn
enPassantSquare
enPassant
8Set Data Cell
Table
Threats
Row
square
Column
"isUnprotected"
Value
unprotectedLook.value

Mark Unprotected Pieces asks Is Unprotected about every attacked Piece, and writes the answer into its row. It runs after every attack is marked, so it only asks about the red ones. A King is left out. A King that’s attacked is in Check, and that has its own color.

9.7.6 Find Pin Along

FunctionFind Pin Along

Looks from a King along one line (a direction of the Directions table) for a pin: the first Piece on the line is one of the King's own, and the next Piece beyond it is an enemy that moves along this line (the direction's Kind). That own Piece is pinned: the Threats table's pinnedBy gets the enemy Piece's Square. king: the King's Square. direction: the row (0 = first) of the Directions table.

PARAMETERS
NameTypeStarts at
kingText
directionNumber0
ACTIONS
1Declare Variable
Type
Text
Name
side
2Declare Variable
Type
Text
Name
enemy
3Declare Variable
Type
Text
Name
candidate
4Declare Variable
Type
Text
Name
pinner
5Change Variable
Variable
side
Value
data('Position', king, 'side')
6Change Variable
Variable
enemy
Value
data('Sides', side, 'opponent')
7Find First Piece AlongFunction
Action Name
firstLook
square
king
direction
direction
bySide
enemy
8Change Variable
Variable
candidate
Value
firstLook.value
9Ifcandidate != "" && data('Position', candidate, 'side') == side
Then
10Find First Piece AlongFunction
Action Name
beyondLook
square
candidate
direction
direction
bySide
enemy
11Change Variable
Variable
pinner
Value
beyondLook.value
12Ifpinner != "" && data('Position', pinner, 'side') == enemy && data('Position', pinner, 'kind') == data('Directions', direction, 'kind')
Then
13Set Data Cell
Table
Threats
Row
candidate
Column
"pinnedBy"
Value
pinner

A pin is a line. On it, from the King outward, stand one Piece of the King’s own Side and then an enemy that slides along that line. A Bishop on a diagonal, a Rook on a File, a Queen on either. Move the Piece in between, and the King is open.

Find Pin Along looks for that from a King, along one direction. Find First Piece Along finds the first Piece in the way, and calls it candidate. Is it the King’s own? Then it walks on from there, and the next Piece is pinner. Is pinner an enemy of the direction’s Kind? Then candidate is pinned, and its pinnedBy names pinner’s Square.

Both walks pass enemy as bySide, though the first Piece they look for is the King’s own. bySide only sets which way a direction points. A pinner moves toward the King, so the walk from the King looks back along the enemy’s way of moving.

Step 12’s If sits on the main line, after step 9’s, not inside it. Why is that safe? If the first Piece isn’t the King’s own, step 11 never runs. Then pinner stays empty, as it starts each time, and step 12 says no.

That’s the walk from the start of the chapter, used twice in a row, and the reason it moved out.

9.7.7 Mark Pins

FunctionMark Pins

Marks, in the Threats table, every Piece pinned to one King (Find Pin Along, for every line a Queen, Rook, or Bishop slides along). king: the King's Square.

PARAMETERS
kingText
ACTIONS
1RepeatdataCount('Directions')times
Each time
2Ifdata('Directions', local.index, 'steps') > 1
Then
3Find Pin AlongFunction
king
king
direction
local.index

Mark Pins tries every direction from one King. Only a direction whose steps is more than 1 can pin, because only a Piece that slides can pin. A Knight’s or a King’s one step never does.

9.7.8 Find Threats, the Last Three Steps

Go back to Find Threats. Add the three steps that waited. Their card is the one under Find Threats, back in the part on pieces under attack.

Steps 16 and 17 go inside the Repeat, at the end of its line. Right-click the Repeat and choose Add Inside Repeat for the If for a King, and join it. Its Add Inside Then adds Mark Pins, joined on the True line.

Step 18 goes after the whole Repeat, before Clear Targets. Add Mark Unprotected Pieces apart from the line, then use the round handles to join it after the Repeat. Clear Targets stays behind it.

9.7.9 Show Threat Mark

Logic ComponentShow Threat MarkAttach to: Threat Mark

Outlines this Threat Mark's Square in Threats mode when the Piece standing there is attacked, with a double ring around it when it is unprotected (the Threats table), after every change (the Game Rules send "positionChanged"), and hides the mark while the Computer's Move slides ("slideStarted").

Attach toAny Object
DATA STRUCTURES
Square Infoself.squareInfo
On Position Changed
WhenpositionChangedCustom Event
1Ifdata('Threats', self.squareInfo.name, 'isAttacked') == true
Then
2Set Visible
Visible
Yes
3Otherwise
4Set Visible
Visible
No
5Ifdata('Threats', self.squareInfo.name, 'isUnprotected') == true
Then
6Set Frame
Frame
1
7Otherwise
8Set Frame
Frame
0
On Slide Started
WhenslideStartedCustom Event
1Set Visible
Visible
No

Show Threat Mark hears positionChanged, and reads its own Square’s row of Threats. An attacked Piece shows the mark. Any other hides it. An unprotected one gets Frame 1 of the picture, the outline with a second ring inside it. The rest get Frame 0, the outline alone.

While the Computer’s Piece slides, the mark hides, the way Square Marks hides its color.

9.7.10 Show Pin Mark

Logic ComponentShow Pin MarkAttach to: Pin Mark

Shows the amber bar under this Pin Mark's Piece in Threats mode when the Piece is pinned to its own King (the Threats table's pinnedBy), after every change (the Game Rules send "positionChanged"), and hides it while the Computer's Move slides ("slideStarted").

Attach toAny Object
DATA STRUCTURES
Square Infoself.squareInfo
On Position Changed
WhenpositionChangedCustom Event
1Ifdata('Threats', self.squareInfo.name, 'pinnedBy') != ""
Then
2Set Visible
Visible
Yes
3Otherwise
4Set Visible
Visible
No
On Slide Started
WhenslideStartedCustom Event
1Set Visible
Visible
No

Show Pin Mark is the same idea, for one question. Is pinnedBy empty? If not, the bar shows, and if it is, the bar hides.

9.7.11 Place On Board

Place On Board’s Logic doesn’t change. There’s nothing on its card to build, and it names two more Objects to attach it to, the two marks next.

Logic ComponentPlace On BoardAttach to: Piece, Rank Label, File Label, Square, Move Mark, Threat Mark, Pin MarkAddDelete

Keeps this Object on its Square (Square Info) when the Board is turned over: when the Game Rules say "boardFlipped" (they are its Other), it moves to where its Square is now drawn (Square Position). The Piece, the Square, the Move Mark, the Threat Mark, and the Pin Mark of each Square all use it. squareMeters: how wide one Square is (3.75 m: the Board art is 30 m across). boardLeft and boardBottom: where the Board's bottom-left corner is in the world (0 and 4.375 m: the game window is 140 px taller than the Board, for the status line and the buttons under it).

Attach toAny Object
DATA STRUCTURES
Square Infoself.squareInfo
SHARED VARIABLES
NameTypeKindStarting Value
squareMetersNumberConstant3.75
boardLeftNumberConstant0
boardBottomNumberConstant4.375
On Board Flipped
WhenboardFlippedCustom Event
1Declare Variable
Type
Boolean
Name
isFlipped
Value
false
2Change Variable
Variable
isFlipped
Value
other.boardState.isFlipped
3Square PositionFunction
Action Name
mySquare
square
self.squareInfo.name
isFlipped
isFlipped
squareMeters
@self.squareMeters
boardLeft
@self.boardLeft
boardBottom
@self.boardBottom
4Set Position
X
mySquare.x
Y
mySquare.y

9.7.12 Threat Mark and Pin Mark

ObjectThreat Mark
Transform
Bounding Box > SizeX 3.75, Y 3.75
Sprite
Scene Depth Draw Order11
SpriteThreat Marks
Transform > SizeX 3.75, Y 3.75
Data Structure
Data StructureSquare Info
Logic
Show Threat Mark
Place On Board
ObjectPin Mark
Transform
Bounding Box > SizeX 3.75, Y 3.75
Sprite
Scene Depth Draw Order11
SpritePin Marks
Transform > SizeX 3.75, Y 3.75
Data Structure
Data StructureSquare Info
Logic
Show Pin Mark
Place On Board

The Threat Mark and the Pin Mark each live on one Square, the way a Move Mark does. Each has a Square Info. Place On Board keeps it on its Square when the Board turns. Their Scene Depth Draw Order is 11. That’s higher than the Piece’s, so they’re drawn over it. The bar crosses the Piece’s foot, and the ring circles it.

9.7.13 Lay Out The Board

Logic ComponentLay Out The BoardAttach to: BoardAddDelete

Makes the Objects that show each Square of the Board when the Scene starts: for every row of the Position table (one Square, a1 to h8), a Piece Object, a Square, a Move Mark, a Threat Mark and a Pin Mark are made on that Square (Square Position), and each is given the Square's name (its Square Info); a Square in the left or right column also gets a Rank Label, and one in the bottom or top row a File Label (turned over, the h-File is on the left and Rank 8 at the bottom). Then it says "boardLaidOut". pieceObject, squareObject, moveMarkObject, threatMarkObject, pinMarkObject: the Objects made on each Square; rankLabelObject, fileLabelObject: the labels. squareMeters: how wide one Square is.

Attach toAny Object
DATA STRUCTURES
Lay Out The Board Dataself.layOutTheBoardData
SHARED VARIABLES
NameTypeKindStarting Value
pieceObjectObjectConstantNone
rankLabelObjectObjectConstantNone
fileLabelObjectObjectConstantNone
squareMetersNumberConstant3.75
squareObjectObjectConstantNone
moveMarkObjectObjectConstantNone
threatMarkObjectObjectConstantNone
pinMarkObjectObjectConstantNone
When the Scene Starts
WhenScene Start
1Declare Variable
Name
boardBottom
Value
0
2Declare Variable
Name
boardLeft
Value
0
3Change Variable
Variable
boardLeft
Value
self.transform.position.x - 4 * @self.squareMeters
4Change Variable
Variable
boardBottom
Value
self.transform.position.y - 4 * @self.squareMeters
5RepeatdataCount('Position')times
Each time
6Change Component Value
Component Value
self.layOutTheBoardData.squareName
Value
dataRow('Position', local.index)
7Square PositionFunction
Action Name
spot
square
self.layOutTheBoardData.squareName
isFlipped
No
squareMeters
@self.squareMeters
boardLeft
boardLeft
boardBottom
boardBottom
8Create Instance
Object to Create
@self.pieceObject
X
spot.x
Y
spot.y
Created As
piece
9Change Variable
Variable
piece.name
Value
self.layOutTheBoardData.squareName
10Create Instance
Object to Create
@self.squareObject
X
spot.x
Y
spot.y
Created As
square
11Change Variable
Variable
square.name
Value
self.layOutTheBoardData.squareName
12Create Instance
Object to Create
@self.moveMarkObject
X
spot.x
Y
spot.y
Created As
moveMark
13Change Variable
Variable
moveMark.name
Value
self.layOutTheBoardData.squareName
14Create Instance
Object to Create
@self.threatMarkObject
X
spot.x
Y
spot.y
Created As
threatMark
15Change Variable
Variable
threatMark.name
Value
self.layOutTheBoardData.squareName
16Create Instance
Object to Create
@self.pinMarkObject
X
spot.x
Y
spot.y
Created As
pinMark
17Change Variable
Variable
pinMark.name
Value
self.layOutTheBoardData.squareName
18Ifdata('Position', self.layOutTheBoardData.squareName, 'file') == 1 || data('Position', self.layOutTheBoardData.squareName, 'file') == 8
Then
19Create Instance
Object to Create
@self.rankLabelObject
X
spot.x
Y
spot.y
Created As
rankLabel
20Change Variable
Variable
rankLabel.name
Value
self.layOutTheBoardData.squareName
21Ifdata('Position', self.layOutTheBoardData.squareName, 'rank') == 1 || data('Position', self.layOutTheBoardData.squareName, 'rank') == 8
Then
22Create Instance
Object to Create
@self.fileLabelObject
X
spot.x
Y
spot.y
Created As
fileLabel
23Change Variable
Variable
fileLabel.name
Value
self.layOutTheBoardData.squareName
24Trigger Custom Event
Custom Event
boardLaidOut

Lay Out The Board makes the two marks on every Square, as it makes the Move Mark. Two new constant Object Shared Variables, threatMarkObject and pinMarkObject, and four new steps, 14 to 17.

The order they come in changes nothing on the Board. So click the Repeat’s last step that isn’t inside an If, add step 14, and join it. Go on from there. If your step numbers in this one Logic don’t match the card’s, that’s all right. Here the order doesn’t matter.

9.7.14 Board

ObjectBoard
Transform
Bounding Box > SizeX 30, Y 30
Sprite
SpriteWalnut Board
Transform > SizeX 30, Y 30
Data Structure
From LogicLay Out The Board
Data StructureLay Out The Board Data
Logic
Lay Out The Board
Shared Variables
pieceObjectPiece
rankLabelObjectRank Label
fileLabelObjectFile Label
squareObjectSquare
moveMarkObjectMove Mark
threatMarkObjectThreat Mark
pinMarkObjectPin Mark

On the Board’s Shared Variables card, choose Threat Mark and Pin Mark for the two new Values. Both start as None buttons. Press each and pick its Object, as in Chapter 1.

Run the game. Press Threats if it’s off, and play e2 to e4, then d1 to h5, as before.

Your Queen lands, and the Board shows you at once. The Pawn on f7 is red, with a red outline, and under it, most likely, lies a short amber bar. Your Queen, that Pawn and Black’s King stand on one diagonal. If the Pawn stepped off that line, its King would be in Check at once, so it has to stay.

Your Board can see one Move ahead now.

Play it!

Watch for each of these.

  • Start a new game as White, and press the Threats button in the middle of the row. The legend shows under the buttons: Attacked, Unprotected, Pinned. Nothing on the Board is marked.
  • Play e2 to e4, wait for the reply, then play d1 to h5. As your Queen lands, the Pawns it could take turn red, with a red outline.
  • The Pawn on f7 has an amber bar under it, unless Black’s first reply moved its f-Pawn or g-Pawn. It’s pinned to its King.
  • Leave one of your Pieces where the Computer could take it, with nothing of yours able to take it back. Its outline gets a ring, and its red is stronger. A Pawn on e4, with a Black Knight on f6 and nothing guarding it, is one.
  • Click a red Piece. Its Square turns gold, and its outline stays.
  • Press Threats again. Every mark goes, and so does the legend.
  • Play e2 to e4, and look at Threats while the words say Thinking…. It’s faded.
  • Turn Threats on, and close the game. Run it again. Threats mode is still on, and the legend is back.
How it works

Threats asks the rules you already wrote. Mark Captures asks Find Legal Moves what every Piece could take. Can Recapture makes a Capture in the table, asks who could take back, and puts it all back. Find Pin Along walks out from each King. The answers go into one row per Square, and three pieces of Logic draw them.

Underneath is one idea. A question about the future can be asked of the present. Change the table, ask, and change it back, all before anything is drawn on the screen.

9.8 If It Didn’t Work

This chapter has many small Functions, and most of them call each other, sometimes three deep. A slip in one can hide behind the others. Watch what the Board does. Think it through from there.

A block drawn in red, with a number on the Errors bar? Open the bar. It names the block and what it misses. Compare that block with its card.

A King in Check no longer turns red, after the first part? Look at Find Attacker Along’s If. Its three tests ask about piece, and piece must be declared as Text.

Threats stays faded on your Turn? Look at Report Threats’ On Position Changed. Both calls need joining, with canUse.value in Show Button On Or Off’s isOn. Threats lights up, but a press does nothing? Check Show Threats on the Game Rules, where it needs to be attached. Perhaps the placement still picks Hint Button instead of Threats Button.

The legend never shows? Each Legend Key’s Group must be Threats Legend, the same words Show Threats names.

Dots appear for a Piece you didn’t select? Find Threats’ last step, Clear Targets, may be missing or Unattached.

Pieces jump to the wrong Squares, or vanish, when Threats is on? Can Recapture didn’t put everything back. Look at its last three steps. Move Piece there carries the Piece back, so its from and to are swapped from the first Move Piece’s.

No outline, ring or bar anywhere, though the red shows? Look at Lay Out The Board’s four new steps, and at the Board, where its two new Shared Variables need Threat Mark and Pin Mark. A ring never shows? Find Threats’ step 18 may still be missing.

The marks stay behind when you press Flip, while every Piece moves to its new Square? Place On Board may not be attached to that mark’s Object.

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 Board shows three things now. What else would help a player see the game? Perhaps a Piece attacked twice, wearing a second outline so you can tell it from one attacked once. Or the Squares the enemy could move to, faintly tinted, so a King knows where not to step. The Threats table has room for another column, and Square Marks for another If. What your Board shows is up to you.

Still stuck? Search the manual, or ask in the Myth Engine Discord (opens a new tab).

Your Board shows what could happen next. In Chapter 10, the threats get lines you can follow, from each pinning Piece to its King.