Skip to content

Instantly share code, notes, and snippets.

@d-ronnqvist
Created October 19, 2014 15:47
Show Gist options
  • Save d-ronnqvist/89768210611e18417b6d to your computer and use it in GitHub Desktop.
Save d-ronnqvist/89768210611e18417b6d to your computer and use it in GitHub Desktop.
Swift alternative to class clusters?

I wanted to use enums, structs, and classes to create small, elegant objects for a basic chess game.

It started with the small squares in the chess board, and created the logic part in the main definition and an extension that is use for rendering

enum Row: Character {
    case A = "A"
    case B = "B"
    case C = "C"
    case D = "D"
    case E = "E"
    case F = "F"
    case G = "G"
    case H = "H"
}

enum Column: Int {
    case One   = 1
    case Two   = 2
    case Three = 3
    case Four  = 4
    case Five  = 5
    case Six   = 6
    case Seven = 7
    case Eight = 8
}

struct Square {
    let row: Row
    let col: Column
}

extension Square {
    var position: SCNVector3 {
        get {
            // calculated based on row and column
        }
    }
}

Then I wanted to to something similar for the pieces, so I defined these enums

enum PieceType: String {
    case Pawn   = "Pawn"
    case Rook   = "Rook"
    case Knight = "Knight"
    case Bishop = "Bishop"
    case Queen  = "Queen"
    case King   = "King"
}

enum PieceColor {
    case White
    case Black
}

If this would have been Objective-C then I would have created a base class and used subclasses to override and customize behavior for the specific pieces (pawn, rook, knight, etc.). This class would have been implemneted as a class cluster so that one of the subclasses would have been returned based on the type that was passed to the initliazer

class Piece {
    let type: PieceType
    let color: PieceColor
    
    var location: Square?

    init(_ type: PieceType, color: PieceColor) {
        // In ObjC I would have done a class cluster here
    }
    
    var possibleSquaresToMoveTo: [Square] {
        get {
            return [] // base class isn't meant to be used
        }
    }
}

class Knight: Piece {
    init(color: PieceColor) {
        super.init(.Knight, color: color)
    }
    
    override var possibleSquaresToMoveTo: [Square] {
        get {
            // calculate possible squares based on the Knights movement pattern and the current location
        }
    }
}

The main problem I have with this design is that it's still possible to create a base instance, so the Piece initlizer shouldn't really be used.

My next idea was to rethink the possibleSquaresToMoveTo calculated property. Perhaps the Swift way would be to define a function that maps from the current square to all the possible squares that can be moved to (Square -> [Square])

In either case, the Chessboard would have to be involved to filter the results since the Piece doesn't know of all the other Pieces on the board and their locations. So maybe all of this logic really belongs in the board (alhtough I kind of like the idea that the piece gives the basic pattern and the board filters it down).

In either case, I'm trying to involve having switch aPiece.type in the code (with a class cluster I would only have it in the Piece initiliazer)


What would be a nice Swift (possibly even functional) way of solving this problem?

@d-ronnqvist
Copy link
Author

I'm also having a similar extension on the Piece class that get's the correct SCNGeometry object from a file based on the type and the color

@chriseidhof
Copy link

I don't think you need any classes, rather, I would have a top-level function possibleSquares to move to that switches on the PieceType... that should work =).

@chriseidhof
Copy link

The functional way is to write a couple of these functions and then combine them into something larger...

@chriseidhof
Copy link

In Haskell, there is only data (enums) and top-level functions. No such thing as instance methods... So you can probably solve it that way, and always move functions to extensions if you feel it's better...

@d-ronnqvist
Copy link
Author

I'm thinking that I should have functions that allow movement in straight lines and diagonally for a given number of steps. Then the rook, bishop, queen, and king could be written as a combination of those. In that case I will probably make the Piece a struct instead.

This is all so new and I still think in Objective-C ;)

Copy link

ghost commented Nov 7, 2018

Would be great to see how you guys @d-ronnqvist @chriseidhof solve this problem after 4 years of study and experimentation with Swift.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment