diff --git a/Sources/Engine/Board.swift b/Sources/Engine/Board.swift index 88cd9e8..05e6f62 100644 --- a/Sources/Engine/Board.swift +++ b/Sources/Engine/Board.swift @@ -5,6 +5,7 @@ enum Event { protocol EventDelegate { func notify(_ event: Event) func movePiece(_ piece: Piece, to dst: Square.Position) throws + func addPieceToTarget(_ piece: Piece, target: Square.Position) } public class Board: CustomStringConvertible, EventDelegate { public typealias Grid = [[Square]] @@ -24,6 +25,13 @@ public class Board: CustomStringConvertible, EventDelegate { } + internal func addPieceToTarget(_ piece: Piece, target: Square.Position) { + guard var square = self[target] else { + return + } + square.targetted.insert(piece) + } + public private(set) var halfMoveClock: UInt8 = 0 public var fullMoveClock: UInt8 { @@ -35,10 +43,16 @@ public class Board: CustomStringConvertible, EventDelegate { .Black: [], ] + public internal(set) var history = History() + public private(set) var turn: Color = .White func movePiece(_ piece: Piece, to dst: Square.Position) throws { let from = piece.position + history.add( + .pieceMove( + from: squares[from.index!], + to: squares[dst.index!])) piece.position = dst squares[dst.index!].piece = piece squares[from.index!].piece = nil @@ -230,6 +244,9 @@ public class Board: CustomStringConvertible, EventDelegate { #warning("Handle better.") do { try setBoard() + for square in squares where square.piece != nil { + square.piece?.getLegalPosition() + } } catch Fen.FenError.NotAppropriateLength(let n, let column) { fatalError("Not appropriate length: \(n) on \(column)") } catch { diff --git a/Sources/Engine/History.swift b/Sources/Engine/History.swift new file mode 100644 index 0000000..4c4f6a2 --- /dev/null +++ b/Sources/Engine/History.swift @@ -0,0 +1,71 @@ +public struct History { + public typealias Array = [( + SANMoveDescriptor.Value?, SANMoveDescriptor.Value? + )] + + public enum SANMoveDescriptor { + public typealias Value = String + case pieceMove(from: Square, to: Square) + case pawnPush(to: Square, promotion: Piece?) + + public var value: Value { + return switch self { + case .pieceMove(let from, let to): + { + guard let piece = from.piece else { + return "" + } + #warning("Ugly ass code 🤢") + var result = + piece.kind == .Pawn + ? "" + : "\(piece.kind.fenRepresentation(with: piece.color))" + if let ambiguity = (to.targetted.first { $0 ~= piece }) { + let file = + ambiguity.position.file != from.position.file + ? Square.Position.File[from.position.file] : nil + var rank: Int8? { + if file == nil { + return ambiguity.position.rank + != from.position.rank + ? from.position.rank : nil + } + return nil + } + if let f = file { + result += f.rawValue + } else if let r = rank { + result += String(r) + } else { + result += + Square.Position.File[from.position.file]! + .rawValue + + String(from.position.rank) + } + } + if to.piece != nil { + result += "x" + } + result += + "\(Square.Position.File[to.position.file]!.rawValue)\(String(to.position.rank))" + return result + }() + case .pawnPush(let to, let promotion): + "" + } + } + } + + public private(set) var values: Array = [] + + internal mutating func add(_ san: SANMoveDescriptor) { + #warning("To be tested") + if let last = values.last { + if last.1 == nil { + values[values.count - 1].1 = san.value + return + } + } + values.append((san.value, nil)) + } +} diff --git a/Sources/Engine/Pieces/Piece.swift b/Sources/Engine/Pieces/Piece.swift index 5023495..c90bbfd 100644 --- a/Sources/Engine/Pieces/Piece.swift +++ b/Sources/Engine/Pieces/Piece.swift @@ -53,7 +53,7 @@ public enum Kind: String, CaseIterable { } } -public class Piece { +public class Piece: Hashable { #warning("TODO: To be removed, handle everything through the delegate") internal weak var board: Board? public internal(set) var color: Color @@ -94,6 +94,7 @@ public class Piece { } } + delegate?.addPieceToTarget(self, target: pos) return true } @@ -102,4 +103,30 @@ public class Piece { self.position = pos self.color = col } + + /// Two pieces are equal when they share the same kind, color and position + public static func == (lhs: Piece, rhs: Piece) -> Bool { + return lhs.kind == rhs.kind && lhs.color == rhs.color + && lhs.position == rhs.position + } + + /// Two pieces are not equal when they either do not share the same kind, + /// color or position + public static func != (lhs: Piece, rhs: Piece) -> Bool { + return !(lhs == rhs) + } + + /// Checks if tho pieces are similar yet not equal. + /// They are considered simmilar if they share the same color and the same kind, + /// but differ in position. + public static func ~= (lhs: Piece, rhs: Piece) -> Bool { + return lhs.kind == rhs.kind && lhs.color == rhs.color + && lhs.position != rhs.position + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(kind) + hasher.combine(position) + hasher.combine(color) + } } diff --git a/Sources/Engine/Square.swift b/Sources/Engine/Square.swift index 22165c5..ee018a1 100644 --- a/Sources/Engine/Square.swift +++ b/Sources/Engine/Square.swift @@ -75,6 +75,7 @@ public struct Square: Equatable { public let position: Position public internal(set) var piece: Piece? = nil public let color: Color + public internal(set) var targetted: Set = [] public static func == (lhs: Square, rhs: Square) -> Bool { return lhs.position == rhs.position diff --git a/Sources/exe/main.swift b/Sources/exe/main.swift index 06d4206..2b8acc0 100644 --- a/Sources/exe/main.swift +++ b/Sources/exe/main.swift @@ -24,5 +24,6 @@ do { print(board) print(board.fen) +print(board.history.values) // let square = board.getSquareInfo(on: .init(rank: 2, file: 7))