public struct Fen: CustomStringConvertible { public enum CastlingAvailibility: String { case Neither = "-" case WhiteKingSide = "K" case WhiteQueenSide = "Q" case BlackKingSide = "k" case BlackQueenSide = "q" case WhiteSide = "KQ" case BlackSide = "kq" case Kings = "Kk" case Queens = "Qq" case WKingBQueen = "Kq" case WQueenBKing = "Qk" case All = "KQkq" } private var _fen: String = "" public private(set) var value: String { get { return _fen } set { _fen = newValue let splitted = _fen.split(separator: " ") guard splitted.count == 6 else { return } placement = String(splitted[0]) activeColor = switch splitted[1] { case "w": .White case "b": .Black default: .White } castlingAvailibility = CastlingAvailibility( rawValue: String(splitted[2])) ?? .Neither enPassant = String(splitted[3]) halfMoveClock = if let c = splitted[4].first, c.isWholeNumber { UInt8(String(c)) ?? 0 } else { 0 } fullMoveClock = if let c = splitted[5].first, c.isWholeNumber { UInt8(String(c)) ?? 1 } else { 1 } } } public private(set) var placement: String = "" // 70 chars public private(set) var activeColor: Color = .White // 1 char public private(set) var castlingAvailibility: CastlingAvailibility = .All // 1 to 4 chars public private(set) var enPassant: String = "-" // 1 or 2 chars public private(set) var halfMoveClock: UInt8 = 0 public package(set) var fullMoveClock: UInt8 = 1 public init(fen value: String) { self.value = value } internal mutating func set( from board: Board.Grid, castling ca: CastlingAvailibility, enPassant: String ) { #warning( "Determine active color, halfMoveClock, fullMoveClock based on history SAN later passed in arguments" ) var placement = "" var rankNr = 0 for rank in board { var count = 0 for i in 0.. 0 { placement += String(count) count = 0 } placement += piece.kind.fenRepresentation(with: piece.color) } else { count += 1 } } if count > 0 { placement += String(count) } if rankNr != rank.count - 1 { placement += "/" } rankNr += 1 } value = placement + " w " + ca.rawValue + " " + enPassant + " 0 " + "1" } public enum FenError: Error { case InvalidCharacter(c: String, column: Int8) case NumberTooBig(n: Int8, column: Int8) case NumberTooSmall(n: Int8, column: Int8) case NotAppropriateLength(n: Int8, column: Int8) } public var description: String { return value } }