From 1d7f1095d5294cd5e09d6e0ea4987e9d4bdc57fc Mon Sep 17 00:00:00 2001 From: cdricms <36056008+cdricms@users.noreply.github.com> Date: Fri, 28 Jun 2024 00:02:48 +0200 Subject: [PATCH] Lots of changes --- Sources/Engine/Board.swift | 58 ++++++++++++++++++++--------- Sources/Engine/Pieces/Bishop.swift | 23 ++++-------- Sources/Engine/Pieces/King.swift | 25 +++++-------- Sources/Engine/Pieces/Knight.swift | 25 +++++-------- Sources/Engine/Pieces/Pawn.swift | 45 ++++++++++------------ Sources/Engine/Pieces/Piece.swift | 36 ++++++++++++------ Sources/Engine/Pieces/Queen.swift | 25 +++++-------- Sources/Engine/Pieces/Rook.swift | 21 +++++------ Sources/Engine/Square.swift | 31 ++++++++++++++- Sources/exe/main.swift | 13 ++++++- Tests/EngineTests/EngineTests.swift | 12 +++--- 11 files changed, 175 insertions(+), 139 deletions(-) diff --git a/Sources/Engine/Board.swift b/Sources/Engine/Board.swift index b24651b..c7bac90 100644 --- a/Sources/Engine/Board.swift +++ b/Sources/Engine/Board.swift @@ -1,4 +1,12 @@ -public class Board: CustomStringConvertible { +enum Event { + case kingInCheck(_ by: Piece) + case piecePinned(from: Piece, on: Piece) +} +protocol EventDelegate { + func notify(_ event: Event) + func movePiece(_ piece: Piece, to dst: Square.Position) +} +public class Board: CustomStringConvertible, EventDelegate { public typealias Grid = [[Square]] private enum UnicodeBar: String, CustomStringConvertible { @@ -12,6 +20,18 @@ public class Board: CustomStringConvertible { } } + func notify(_ event: Event) { + + } + + func movePiece(_ piece: Piece, to dst: Square.Position) { + + } + + public func getSquareInfo(on pos: Square.Position) -> Square? { + self[pos] + } + private var squares = [Square]() private var board: Grid { var board = Grid() @@ -37,7 +57,8 @@ public class Board: CustomStringConvertible { let r = 8 - Int(rank) if c == "/" { if file != 9 { - throw Fen.FenError.NotAppropriateLength(n: file, column: index) + throw Fen.FenError.NotAppropriateLength( + n: file, column: index) } rank -= 1 file = 0 @@ -51,7 +72,7 @@ public class Board: CustomStringConvertible { let f = file for i in f..<(f + n) { file += 1 - b[8*r+Int(i)].piece = nil + b[8 * r + Int(i)].piece = nil } file -= 1 } else if c.isASCII { @@ -60,19 +81,20 @@ public class Board: CustomStringConvertible { let piece: Piece = switch k { case .Pawn: - Pawn(color: c, on: .init(rank: rank, file: file)) + Pawn(with: c, on: .init(rank: rank, file: file)) case .Knight: - Knight(color: c, on: .init(rank: rank, file: file)) + Knight(with: c, on: .init(rank: rank, file: file)) case .Bishop: - Bishop(color: c, on: .init(rank: rank, file: file)) + Bishop(with: c, on: .init(rank: rank, file: file)) case .Rook: - Rook(color: c, on: .init(rank: rank, file: file)) + Rook(with: c, on: .init(rank: rank, file: file)) case .Queen: - Queen(color: c, on: .init(rank: rank, file: file)) + Queen(with: c, on: .init(rank: rank, file: file)) case .King: - King(color: c, on: .init(rank: rank, file: file)) + King(with: c, on: .init(rank: rank, file: file)) } - b[8*r+Int(file)-1].piece = piece + piece.delegate = self + b[8 * r + Int(file) - 1].piece = piece case .none: throw Fen.FenError.InvalidCharacter( c: String(c), column: index) @@ -82,14 +104,16 @@ public class Board: CustomStringConvertible { file += 1 index += 1 } - #if DEBUG - print(b) - #endif + #if DEBUG + print(b) + #endif squares = b } - public required init(fen: Fen = - .init(fen: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1") + public required init( + fen: Fen = + .init( + fen: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1") ) { var rank: Int8 = 8 self.fen = fen @@ -134,7 +158,7 @@ public class Board: CustomStringConvertible { return boardString } - public subscript(pos: Square.Position) -> Square? { + internal subscript(pos: Square.Position) -> Square? { guard let i = pos.index else { return nil } @@ -143,4 +167,4 @@ public class Board: CustomStringConvertible { } return squares[i] } -} \ No newline at end of file +} diff --git a/Sources/Engine/Pieces/Bishop.swift b/Sources/Engine/Pieces/Bishop.swift index 1c00951..515c0da 100644 --- a/Sources/Engine/Pieces/Bishop.swift +++ b/Sources/Engine/Pieces/Bishop.swift @@ -1,32 +1,26 @@ final class Bishop: Piece, DiagonalMoves { - weak var board: Board? - var kind: Kind = .Bishop - var unicodeRepresentation: String { + override var unicodeRepresentation: String { return color == .Black ? "♝" : "♗" } - var color: Color - var position: Square.Position - - var pseudoLegalPositions: [Square.Position] { + override var pseudoLegalPositions: [Square.Position] { return getDiagonalMoves(from: position) } - var legalPositions: [Square.Position] { + override var legalPositions: [Square.Position] { return pseudoLegalPositions.filter { isLegal(on: $0) } } - func move(to dst: Square.Position) -> Bool { - return false + override func move(to dst: Square.Position) { } - func isLegal(on pos: Square.Position) -> Bool { + override func isLegal(on pos: Square.Position) -> Bool { if let board = board, let s = board[pos] { if let p = s.piece { if p.color == color { return false } if p.kind == .King { - // TODO: Notify board of check + delegate?.notify(.kingInCheck(self)) return false } } @@ -34,9 +28,8 @@ final class Bishop: Piece, DiagonalMoves { return true } - init(color: Color, on position: Square.Position) { - self.color = color - self.position = position + init(with color: Color, on position: Square.Position) { + super.init(kind: .Bishop, on: position, with: color) } } diff --git a/Sources/Engine/Pieces/King.swift b/Sources/Engine/Pieces/King.swift index 916f8ec..95abee5 100644 --- a/Sources/Engine/Pieces/King.swift +++ b/Sources/Engine/Pieces/King.swift @@ -1,15 +1,10 @@ final class King: Piece { - weak var board: Board? - var kind: Kind = .King - var unicodeRepresentation: String { + override var unicodeRepresentation: String { return color == .Black ? "♛" : "♕" } - var color: Color - var position: Square.Position - - var pseudoLegalPositions: [Square.Position] { + override var pseudoLegalPositions: [Square.Position] { [ position + (1, 0), position + (1, 1), @@ -18,19 +13,18 @@ final class King: Piece { position + (-1, 0), position + (-1, -1), position + (0, -1), - position + (1, -1) - ].filter {$0.index != nil} + position + (1, -1), + ].filter { $0.index != nil } } - var legalPositions: [Square.Position] { + override var legalPositions: [Square.Position] { return pseudoLegalPositions.filter { isLegal(on: $0) } } - func move(to dst: Square.Position) -> Bool { - return false + override func move(to dst: Square.Position) { } - func isLegal(on pos: Square.Position) -> Bool { + override func isLegal(on pos: Square.Position) -> Bool { if let board = board, let s = board[pos] { if let p = s.piece { if p.color == color { return false } @@ -44,9 +38,8 @@ final class King: Piece { return true } - init(color: Color, on position: Square.Position) { - self.color = color - self.position = position + init(with color: Color, on position: Square.Position) { + super.init(kind: .King, on: position, with: color) } } diff --git a/Sources/Engine/Pieces/Knight.swift b/Sources/Engine/Pieces/Knight.swift index 34a6323..1a1e636 100644 --- a/Sources/Engine/Pieces/Knight.swift +++ b/Sources/Engine/Pieces/Knight.swift @@ -1,15 +1,9 @@ final class Knight: Piece { - weak var board: Board? - var kind: Kind = .Knight - - var unicodeRepresentation: String { + override var unicodeRepresentation: String { return color == .Black ? "♞" : "♘" } - var color: Color - var position: Square.Position - - var pseudoLegalPositions: [Square.Position] { + override var pseudoLegalPositions: [Square.Position] { [ position + (2, 1), position + (2, -1), @@ -18,24 +12,24 @@ final class Knight: Piece { position + (1, 2), position + (1, -2), position + (-1, 2), - position + (-1, -2) + position + (-1, -2), ].filter { $0.index != nil } } - var legalPositions: [Square.Position] { + override var legalPositions: [Square.Position] { return pseudoLegalPositions.filter { isLegal(on: $0) } } - func move(to dst: Square.Position) -> Bool { - return false + override func move(to dst: Square.Position) { } - func isLegal(on pos: Square.Position) -> Bool { + override func isLegal(on pos: Square.Position) -> Bool { if let board = board, let s = board[pos] { if let p = s.piece { if p.color == color { return false } if p.kind == .King { // TODO: Notify board of check + delegate?.notify(.kingInCheck(self)) return false } } @@ -44,9 +38,8 @@ final class Knight: Piece { return true } - init(color: Color, on position: Square.Position) { - self.color = color - self.position = position + init(with color: Color, on position: Square.Position) { + super.init(kind: .Knight, on: position, with: color) } } diff --git a/Sources/Engine/Pieces/Pawn.swift b/Sources/Engine/Pieces/Pawn.swift index fa41d1a..1c92645 100644 --- a/Sources/Engine/Pieces/Pawn.swift +++ b/Sources/Engine/Pieces/Pawn.swift @@ -1,51 +1,47 @@ final class Pawn: Piece { - var kind: Kind = .Pawn - weak var board: Board? - var color: Color - var position: Square.Position - var pseudoLegalPositions: [Square.Position] { + override var pseudoLegalPositions: [Square.Position] { let sign: Int8 = color == .Black ? -1 : 1 return [ position + (1 * sign, 0), position + (2 * sign, 0), position + (1 * sign, 1), - position + (1 * sign, -1) + position + (1 * sign, -1), ].filter { $0.index != nil } } - var legalPositions: [Square.Position] { + + override var legalPositions: [Square.Position] { pseudoLegalPositions.filter { isLegal(on: $0) } } - var unicodeRepresentation: String { + override var unicodeRepresentation: String { color == .Black ? "♟" : "♙" } - func move(to dst: Square.Position) -> Bool { - guard board != nil else { - return false - } - + override func move(to dst: Square.Position) { if !(legalPositions.contains { $0 == dst }) { - return false + return } - if let board = board, var s = board[position], var d = board[dst] { - s.piece = self - d.piece = nil - } + delegate?.movePiece(self, to: dst) - position = dst + // if let board = board, var s = board[position], var d = board[dst] { + // s.piece = self + // d.piece = nil + // } - return true + // position = dst + + // return true } - func isLegal(on pos: Square.Position) -> Bool { + override func isLegal(on pos: Square.Position) -> Bool { // TODO: Handle "En-Passant" if let board = board, let s = board[pos] { if let p = s.piece { if p.color == color { return false } if p.kind == .King { // TODO: Notify board of check + delegate?.notify(.kingInCheck(self)) return false } } @@ -54,10 +50,7 @@ final class Pawn: Piece { return true } - init( - color: Color, on position: Square.Position - ) { - self.color = color - self.position = position + init(with color: Color, on position: Square.Position) { + super.init(kind: .Pawn, on: position, with: color) } } diff --git a/Sources/Engine/Pieces/Piece.swift b/Sources/Engine/Pieces/Piece.swift index 881521f..e1c0117 100644 --- a/Sources/Engine/Pieces/Piece.swift +++ b/Sources/Engine/Pieces/Piece.swift @@ -1,4 +1,4 @@ -enum Kind: String, CaseIterable { +public enum Kind: String, CaseIterable { case Pawn, Knight, Bishop, Rook, Queen, King var value: Int8 { @@ -39,14 +39,28 @@ enum Kind: String, CaseIterable { } } -protocol Piece { - var board: Board? { get } - var color: Color { get } - var unicodeRepresentation: String { get } - var kind: Kind { get } - var position: Square.Position { get } - var pseudoLegalPositions: [Square.Position] { get } - var legalPositions: [Square.Position] { get } - func move(to dst: Square.Position) -> Bool - func isLegal(on pos: Square.Position) -> Bool +public class Piece { + #warning("TODO: TO be removed, handle everything through the delegate") + internal weak var board: Board? + public internal(set) var color: Color + public var unicodeRepresentation: String { + return "" + } + public internal(set) var kind: Kind + public internal(set) var position: Square.Position + internal var pseudoLegalPositions: [Square.Position] { + return [] + } + internal var legalPositions: [Square.Position] { + return [] + } + internal var delegate: EventDelegate? + internal func move(to dst: Square.Position) {} + internal func isLegal(on pos: Square.Position) -> Bool { false } + + internal init(kind: Kind, on pos: Square.Position, with col: Color) { + self.kind = kind + self.position = pos + self.color = col + } } diff --git a/Sources/Engine/Pieces/Queen.swift b/Sources/Engine/Pieces/Queen.swift index 9c3d74a..585a649 100644 --- a/Sources/Engine/Pieces/Queen.swift +++ b/Sources/Engine/Pieces/Queen.swift @@ -1,33 +1,27 @@ final class Queen: Piece, LinearMoves, DiagonalMoves { - weak var board: Board? - var kind: Kind = .Queen - - var unicodeRepresentation: String { + override var unicodeRepresentation: String { return color == .Black ? "♛" : "♕" } - var color: Color - var position: Square.Position - - var pseudoLegalPositions: [Square.Position] { + override var pseudoLegalPositions: [Square.Position] { return getDiagonalMoves(from: position) + getLinearMoves(from: position) } - var legalPositions: [Square.Position] { + override var legalPositions: [Square.Position] { return pseudoLegalPositions.filter { isLegal(on: $0) } } - func move(to dst: Square.Position) -> Bool { - - return false + override func move(to dst: Square.Position) { + } - func isLegal(on pos: Square.Position) -> Bool { + override func isLegal(on pos: Square.Position) -> Bool { if let board = board, let s = board[pos] { if let p = s.piece { if p.color == color { return false } if p.kind == .King { // TODO: Notify board of check + delegate?.notify(.kingInCheck(self)) return false } } @@ -36,9 +30,8 @@ final class Queen: Piece, LinearMoves, DiagonalMoves { return true } - init(color: Color, on position: Square.Position) { - self.color = color - self.position = position + init(with color: Color, on position: Square.Position) { + super.init(kind: .Queen, on: position, with: color) } } diff --git a/Sources/Engine/Pieces/Rook.swift b/Sources/Engine/Pieces/Rook.swift index 01245d6..740fd9d 100644 --- a/Sources/Engine/Pieces/Rook.swift +++ b/Sources/Engine/Pieces/Rook.swift @@ -1,32 +1,27 @@ final class Rook: Piece, LinearMoves { - weak var board: Board? - var kind: Kind = .Rook - var unicodeRepresentation: String { + override var unicodeRepresentation: String { return color == .Black ? "♜" : "♖" } - var color: Color - var position: Square.Position - - var pseudoLegalPositions: [Square.Position] { + override var pseudoLegalPositions: [Square.Position] { return getLinearMoves(from: position) } - var legalPositions: [Square.Position] { + override var legalPositions: [Square.Position] { return pseudoLegalPositions.filter { isLegal(on: $0) } } - func move(to dst: Square.Position) -> Bool { - return false + override func move(to dst: Square.Position) { } - func isLegal(on pos: Square.Position) -> Bool { + override func isLegal(on pos: Square.Position) -> Bool { if let board = board, let s = board[pos] { if let p = s.piece { if p.color == color { return false } if p.kind == .King { // TODO: Notify board of check + delegate?.notify(.kingInCheck(self)) return false } } @@ -35,8 +30,10 @@ final class Rook: Piece, LinearMoves { return true } - init(color: Color, on position: Square.Position) { + init(with color: Color, on position: Square.Position) { + super.init(kind: .Rook, on: position, with: color) self.color = color + self.kind = .Rook self.position = position } diff --git a/Sources/Engine/Square.swift b/Sources/Engine/Square.swift index 1c217a9..ab78fbf 100644 --- a/Sources/Engine/Square.swift +++ b/Sources/Engine/Square.swift @@ -8,7 +8,34 @@ public struct Square: Equatable { guard (rank > 0 && rank < 9) && (file > 0 && file < 9) else { return nil } - return Int(8*(8-rank)+file-1) + return Int(8 * (8 - rank) + file - 1) + } + + public init(rank r: Int8, file f: Int8) { + rank = r + file = f + } + + public enum File: String, CustomStringConvertible { + case a, b, c, d, e, f, g, h + + public static subscript(_ f: Int8) -> Self? { + return switch f { + case 1: Self.a + case 2: Self.b + case 3: Self.c + case 4: Self.d + case 5: Self.e + case 6: Self.f + case 7: Self.g + case 8: Self.h + default: nil + } + } + + public var description: String { + self.rawValue.uppercased() + } } public static func == (lhs: Position, rhs: Position) -> Bool { @@ -34,7 +61,7 @@ public struct Square: Equatable { public let position: Position public let index: Int - var piece: Piece? = nil + public internal(set) var piece: Piece? = nil public let color: Color public static func == (lhs: Square, rhs: Square) -> Bool { diff --git a/Sources/exe/main.swift b/Sources/exe/main.swift index 913434a..16bd551 100644 --- a/Sources/exe/main.swift +++ b/Sources/exe/main.swift @@ -1,5 +1,14 @@ import Engine -let board = Board(fen: .init(fen: "rnbqkb1r/pppppppp/2n5/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")) +let board = Board( + fen: .init( + fen: "rnbqkb1r/pppppppp/2n5/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")) // let board: Board = .init() -print(board) \ No newline at end of file +print(board) + +// Execute every time the timer changes +// board.on(.timer) { time in + +// } + +// let square = board.getSquareInfo(on: .init(rank: 2, file: 7)) diff --git a/Tests/EngineTests/EngineTests.swift b/Tests/EngineTests/EngineTests.swift index 77cda75..912e460 100644 --- a/Tests/EngineTests/EngineTests.swift +++ b/Tests/EngineTests/EngineTests.swift @@ -19,7 +19,7 @@ final class EngineTests: XCTestCase { } } func testDiagonalMoves() throws { - let b: Bishop = .init(color: .White, on: .init(rank: 4, file: 4)) + let b: Bishop = .init(with: .White, on: .init(rank: 4, file: 4)) let result = [ Square.Position(rank: 5, file: 3), Square.Position(rank: 6, file: 2), @@ -39,7 +39,7 @@ final class EngineTests: XCTestCase { } func testLinearMoves() throws { - let r: Rook = .init(color: .White, on: .init(rank: 4, file: 4)) + let r: Rook = .init(with: .White, on: .init(rank: 4, file: 4)) let result = [ Square.Position(rank: 5, file: 4), Square.Position(rank: 6, file: 4), @@ -60,7 +60,7 @@ final class EngineTests: XCTestCase { } func testKingMoves() throws { - let k: King = .init(color: .White, on: .init(rank: 2, file: 8)) + let k: King = .init(with: .White, on: .init(rank: 2, file: 8)) let result = [ Square.Position(rank: 3, file: 8), Square.Position(rank: 1, file: 8), @@ -72,7 +72,7 @@ final class EngineTests: XCTestCase { } func testKnightMoves() throws { - let n: Knight = .init(color: .White, on: .init(rank: 4, file: 4)) + let n: Knight = .init(with: .White, on: .init(rank: 4, file: 4)) let result = [ Square.Position(rank: 6, file: 5), Square.Position(rank: 6, file: 3), @@ -87,7 +87,7 @@ final class EngineTests: XCTestCase { } func testPawnMoves() throws { - let pw: Pawn = .init(color: .White, on: .init(rank: 4, file: 4)) + let pw: Pawn = .init(with: .White, on: .init(rank: 4, file: 4)) var result = [ Square.Position(rank: 5, file: 4), Square.Position(rank: 6, file: 4), @@ -95,7 +95,7 @@ final class EngineTests: XCTestCase { Square.Position(rank: 5, file: 3), ] XCTAssertEqual(result, pw.pseudoLegalPositions) - let pb: Pawn = .init(color: .Black, on: .init(rank: 4, file: 4)) + let pb: Pawn = .init(with: .Black, on: .init(rank: 4, file: 4)) result = [ Square.Position(rank: 3, file: 4), Square.Position(rank: 2, file: 4),