Five Steps to Create a Chess App 5/5

Step 5: move pieces around

拇指 muzhi.com
6 min readOct 11, 2019

--

To let different parts of our software talk with each other in professional way, we’ll create something called “protocol” in Swift programming language, which is similar to “interface” in Java programming language. Right click “Chess” folder on the left navigation panel and select “New File…” to create a new swift file. Make sure to choose “Swift File” under “iOS”. Click “Next” button to continue.

create a new swift file for our protocol

Give this protocol a name “ChessDelegate”. Click “Create” button to continue.

ChessDelegate is the protocol name

Key word “protocol” is another data type in Swift programming language. We used “class” and “struct” before. Type in the following 3 lines of code shawn in line 11, 12 and 13.

protocol ChessDelegate contains a single function
import Foundationprotocol ChessDelegate {
func movePiece(fromCol: Int, fromRow: Int, toCol: Int, toRow: Int)
}

Go to BoardView.swift to declare a variable chessDelegate with type “ChessDelegate?”. The question mark means that chessDelegate could be nil. function “touchesBegan(..)” and “touchesEnded(..)” are both system provided mechanism to detect events like fingers touching and leaving device screen.

add new code to capture finger events

Here is the complete code of class BoardView.

import UIKitclass BoardView: UIView {
var pieces = Set<ChessPiece>()
var chessDelegate: ChessDelegate?
var fromCol = -1
var fromRow = -1
override func draw(_ rect: CGRect) {
drawBoard()
drawPieces()
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
let fingerLocation = touch.location(in: self)
fromCol = Int(fingerLocation.x / 80)
fromRow = Int(fingerLocation.y / 80)
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
let fingerLocation = touch.location(in: self)
let toCol = Int(fingerLocation.x / 80)
let toRow = Int(fingerLocation.y / 80)
chessDelegate?.movePiece(fromCol: fromCol, fromRow: fromRow, toCol: toCol, toRow: toRow)
}

func drawPieces() {
for piece in pieces {
let pieceImage = UIImage(named: piece.imageName)
pieceImage?.draw(in: CGRect(x: piece.col * 80, y: piece.row * 80, width: 80, height: 80))
}
}
func drawBoard() {
drawTwoRowsAt(y: 0 * 80)
drawTwoRowsAt(y: 2 * 80)
drawTwoRowsAt(y: 4 * 80)
drawTwoRowsAt(y: 6 * 80)
}

func drawTwoRowsAt(y: CGFloat) {
drawSquareAt(x: 1 * 80, y: y)
drawSquareAt(x: 3 * 80, y: y)
drawSquareAt(x: 5 * 80, y: y)
drawSquareAt(x: 7 * 80, y: y)

drawSquareAt(x: 0 * 80, y: y + 80)
drawSquareAt(x: 2 * 80, y: y + 80)
drawSquareAt(x: 4 * 80, y: y + 80)
drawSquareAt(x: 6 * 80, y: y + 80)
}

func drawSquareAt(x: CGFloat, y: CGFloat) {
let path = UIBezierPath(rect: CGRect(x: x, y: y, width: 80, height: 80))
UIColor.lightGray.setFill()
path.fill()
}
}

Add code to actually move a piece in struct ChessEngine.

add 2 functions “pieceAt(..)” and “movePiece(..)” in struct ChessEngine

Here is the complete code of ChessEngine.

import Foundationstruct ChessEngine {
var pieces = Set<ChessPiece>()

func pieceAt(col: Int, row: Int) -> ChessPiece? {
for piece in pieces {
if piece.col == col && piece.row == row {
return piece
}
}
return nil
}

mutating func movePiece(fromCol: Int, fromRow: Int, toCol: Int, toRow: Int) {
guard let movingPiece = pieceAt(col: fromCol, row: fromRow) else {
return
}
pieces.remove(movingPiece)
pieces.insert(ChessPiece(col: toCol, row: toRow, imageName: movingPiece.imageName))
}

mutating func initializeGame() {
pieces.removeAll()

pieces.insert(ChessPiece(col: 0, row: 0, imageName: "Rook-black"))
pieces.insert(ChessPiece(col: 7, row: 0, imageName: "Rook-black"))
pieces.insert(ChessPiece(col: 0, row: 7, imageName: "Rook-white"))
pieces.insert(ChessPiece(col: 7, row: 7, imageName: "Rook-white"))

pieces.insert(ChessPiece(col: 1, row: 0, imageName: "Knight-black"))
pieces.insert(ChessPiece(col: 6, row: 0, imageName: "Knight-black"))
pieces.insert(ChessPiece(col: 1, row: 7, imageName: "Knight-white"))
pieces.insert(ChessPiece(col: 6, row: 7, imageName: "Knight-white"))

pieces.insert(ChessPiece(col: 2, row: 0, imageName: "Bishop-black"))
pieces.insert(ChessPiece(col: 5, row: 0, imageName: "Bishop-black"))
pieces.insert(ChessPiece(col: 2, row: 7, imageName: "Bishop-white"))
pieces.insert(ChessPiece(col: 5, row: 7, imageName: "Bishop-white"))

pieces.insert(ChessPiece(col: 3, row: 0, imageName: "Queen-black"))
pieces.insert(ChessPiece(col: 3, row: 7, imageName: "Queen-white"))

pieces.insert(ChessPiece(col: 4, row: 0, imageName: "King-black"))
pieces.insert(ChessPiece(col: 4, row: 7, imageName: "King-white"))

pieces.insert(ChessPiece(col: 0, row: 1, imageName: "Pawn-black"))
pieces.insert(ChessPiece(col: 1, row: 1, imageName: "Pawn-black"))
pieces.insert(ChessPiece(col: 2, row: 1, imageName: "Pawn-black"))
pieces.insert(ChessPiece(col: 3, row: 1, imageName: "Pawn-black"))
pieces.insert(ChessPiece(col: 4, row: 1, imageName: "Pawn-black"))
pieces.insert(ChessPiece(col: 5, row: 1, imageName: "Pawn-black"))
pieces.insert(ChessPiece(col: 6, row: 1, imageName: "Pawn-black"))
pieces.insert(ChessPiece(col: 7, row: 1, imageName: "Pawn-black"))

pieces.insert(ChessPiece(col: 0, row: 6, imageName: "Pawn-white"))
pieces.insert(ChessPiece(col: 1, row: 6, imageName: "Pawn-white"))
pieces.insert(ChessPiece(col: 2, row: 6, imageName: "Pawn-white"))
pieces.insert(ChessPiece(col: 3, row: 6, imageName: "Pawn-white"))
pieces.insert(ChessPiece(col: 4, row: 6, imageName: "Pawn-white"))
pieces.insert(ChessPiece(col: 5, row: 6, imageName: "Pawn-white"))
pieces.insert(ChessPiece(col: 6, row: 6, imageName: "Pawn-white"))
pieces.insert(ChessPiece(col: 7, row: 6, imageName: "Pawn-white"))
}
}

Go back to ViewController.swift to let class ViewController to conform to protocol ChessDelegate. In the function “movePiece(..)” inside ViewController.swift, the job of actually moving the piece is delegated to chessEngine(see line 28).

class ViewController conforms to protocol ChessDelegate

Here is the complete code of class ViewController.

import UIKitclass ViewController: UIViewController, ChessDelegate {    var chessEngine = ChessEngine()    @IBOutlet weak var boardView: BoardView!

override func viewDidLoad() {
super.viewDidLoad()

chessEngine.initializeGame()
boardView.pieces = chessEngine.pieces
boardView.setNeedsDisplay()

boardView.chessDelegate = self
}

func movePiece(fromCol: Int, fromRow: Int, toCol: Int, toRow: Int) {
chessEngine.movePiece(fromCol: fromCol, fromRow: fromRow, toCol: toCol, toRow: toRow)
boardView.pieces = chessEngine.pieces
boardView.setNeedsDisplay()
}
}

That’s it, a playable chess game. What if we need to capture a piece? Simple enough, take it out of the board just like we do when using non-digital chess.

a playable chess on simulator

Again, this is NOT a tutorial of coding or programming or Swift or Xcode etc. I just provide you with a whiteboard and marker, or a piece of paper and pencil, so you can start playing “Problem Solving” game with your kids. For example,

In step 1, kids could create a new app whenever they have some new idea to try.

In step 2, kids could drag out more views with different colour and put onto screen.

In step 3, kids could be challenged with questions like “how to centre the board on screen”, “how to use for loop to simplify duplicated code”.

In step 4, kids might need some calculation to sit pieces exactly on squares.

In step 5, kids could move on to write piece rules for each piece: king, queen, bishop, rook, knight and pawn, or to let the moving piece follow finger during the progress of dragging.

This is where our fun journey starts. Stay tuned. Let’s see how we’ll use Xcode, our “whiteboard” or “white paper”, to develop kids mathematical and reasoning skills down the road. Only the sky is your limit. :-D

--

--