aboutsummaryrefslogtreecommitdiff
path: root/Sources/SwiftChessNeo/Piece.swift
diff options
context:
space:
mode:
Diffstat (limited to 'Sources/SwiftChessNeo/Piece.swift')
-rw-r--r--Sources/SwiftChessNeo/Piece.swift297
1 files changed, 297 insertions, 0 deletions
diff --git a/Sources/SwiftChessNeo/Piece.swift b/Sources/SwiftChessNeo/Piece.swift
new file mode 100644
index 0000000..492ad87
--- /dev/null
+++ b/Sources/SwiftChessNeo/Piece.swift
@@ -0,0 +1,297 @@
+//
+// Piece.swift
+// Sage
+//
+// Copyright 2016-2017 Nikolai Vazquez
+// Modified by SuperGeroy
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/// A chess piece.
+public struct Piece: Hashable, CustomStringConvertible {
+
+ /// A piece kind.
+ public enum Kind: Int {
+
+ /// Pawn piece kind.
+ case pawn
+
+ /// Knight piece kind.
+ case knight
+
+ /// Bishop piece kind.
+ case bishop
+
+ /// Rook piece kind.
+ case rook
+
+ /// Queen piece kind.
+ case queen
+
+ /// King piece kind.
+ case king
+
+ /// Pawn
+ internal static let _pawn = Kind.pawn
+
+ /// Knight
+ internal static let _knight = Kind.knight
+
+ /// Bishop
+ internal static let _bishop = Kind.bishop
+
+ /// Rook
+ internal static let _rook = Kind.rook
+
+ /// Queen
+ internal static let _queen = Kind.queen
+
+ /// King
+ internal static let _king = Kind.king
+
+ /// An array of all piece kinds.
+ public static let all: [Kind] = [.pawn, .knight, .bishop, .rook, .queen, .king]
+
+ /// The piece kind's name.
+ public var name: String {
+ switch self {
+ case .pawn: return "Pawn"
+ case .knight: return "Knight"
+ case .bishop: return "Bishop"
+ case .rook: return "Rook"
+ case .queen: return "Queen"
+ case .king: return "King"
+ }
+ }
+
+ /// The piece kind's relative value. Can be used to determine how valuable a piece or combination of pieces is.
+ public var relativeValue: Double {
+ switch self {
+ case .pawn: return 1
+ case .knight: return 3
+ case .bishop: return 3.25
+ case .rook: return 5
+ case .queen: return 9
+ case .king: return .infinity
+ }
+ }
+
+ /// The piece is `Pawn`.
+ public var isPawn: Bool {
+ return self == ._pawn
+ }
+
+ /// The piece `Knight`.
+ public var isKnight: Bool {
+ return self == ._knight
+ }
+
+ /// The piece is `Bishop`.
+ public var isBishop: Bool {
+ return self == ._bishop
+ }
+
+ /// The piece is `Rook`.
+ public var isRook: Bool {
+ return self == ._rook
+ }
+
+ /// The piece is `Queen`.
+ public var isQueen: Bool {
+ return self == ._queen
+ }
+
+ /// The piece is `King`.
+ public var isKing: Bool {
+ return self == ._king
+ }
+
+ /// Returns `true` if `self` can be a promotion for a pawn.
+ public func canPromote() -> Bool {
+ return !(isPawn || isKing)
+ }
+
+ /// Returns `true` if `self` can be a promotion for `other`.
+ public func canPromote(_ other: Kind) -> Bool {
+ return canPromote() ? other.isPawn : false
+ }
+
+ }
+
+ internal static let _whiteHashes: [Int] = whitePieces.map({ $0.rawValue })
+
+ internal static let _blackHashes: [Int] = blackPieces.map({ $0.rawValue })
+
+ internal static func _hashes(for color: Color) -> [Int] {
+ return color.isWhite ? _whiteHashes : _blackHashes
+ }
+
+ internal static let _whiteNonQueens: [Piece] = whitePieces.filter({ !$0.kind.isQueen })
+
+ internal static let _blackNonQueens: [Piece] = blackPieces.filter({ !$0.kind.isQueen })
+
+ internal static func _nonQueens(for color: Color) -> [Piece] {
+ return color.isWhite ? _whiteNonQueens : _blackNonQueens
+ }
+
+ /// An array of all pieces.
+ public static let all: [Piece] = {
+ return [.white, .black].reduce([]) { pieces, color in
+ return pieces + Kind.all.map({ Piece(kind: $0, color: color) })
+ }
+ }()
+
+ /// An array of all white pieces.
+ public static let whitePieces: [Piece] = all.filter({ $0.color.isWhite })
+
+ /// An array of all black pieces.
+ public static let blackPieces: [Piece] = all.filter({ $0.color.isBlack })
+
+ /// Returns an array of all pieces for `color`.
+ public static func pieces(for color: Color) -> [Piece] {
+ return color.isWhite ? whitePieces : blackPieces
+ }
+
+ /// The piece's kind.
+ public var kind: Kind
+
+ /// The piece's color.
+ public var color: Color
+
+ /// The character for the piece. Uppercase if white or lowercase if black.
+ public var character: Character {
+ switch kind {
+ case .pawn: return color.isWhite ? "P" : "p"
+ case .knight: return color.isWhite ? "N" : "n"
+ case .bishop: return color.isWhite ? "B" : "b"
+ case .rook: return color.isWhite ? "R" : "r"
+ case .queen: return color.isWhite ? "Q" : "q"
+ case .king: return color.isWhite ? "K" : "k"
+ }
+ }
+
+ /// A textual representation of `self`.
+ public var description: String {
+ return "\(kind.name)(\(color))"
+ }
+
+ /// The piece's raw value.
+ public var rawValue: Int {
+ return (kind.rawValue << 1) | color.numericValue
+ }
+
+ /// Create a piece from an integer value.
+ internal init?(value: Int) {
+ guard let kind = Kind(rawValue: value >> 1) else {
+ return nil
+ }
+ self.init(kind: kind, color: value & 1 == 0 ? .white : .black)
+ }
+
+ /// Create a piece from `kind` and `color`.
+ public init(kind: Kind, color: Color) {
+ self.kind = kind
+ self.color = color
+ }
+
+ /// Create a pawn piece with `color`.
+ public init(pawn color: Color) {
+ self.init(kind: ._pawn, color: color)
+ }
+
+ /// Create a knight piece with `color`.
+ public init(knight color: Color) {
+ self.init(kind: ._knight, color: color)
+ }
+
+ /// Create a bishop piece with `color`.
+ public init(bishop color: Color) {
+ self.init(kind: ._bishop, color: color)
+ }
+
+ /// Create a rook piece with `color`.
+ public init(rook color: Color) {
+ self.init(kind: ._rook, color: color)
+ }
+
+ /// Create a queen piece with `color`.
+ public init(queen color: Color) {
+ self.init(kind: ._queen, color: color)
+ }
+
+ /// Create a king piece with `color`.
+ public init(king color: Color) {
+ self.init(kind: ._king, color: color)
+ }
+
+ /// Create a piece from a character.
+ public init?(character: Character) {
+ switch character {
+ case "P": self.init(pawn: .white)
+ case "p": self.init(pawn: .black)
+ case "N": self.init(knight: .white)
+ case "n": self.init(knight: .black)
+ case "B": self.init(bishop: .white)
+ case "b": self.init(bishop: .black)
+ case "R": self.init(rook: .white)
+ case "r": self.init(rook: .black)
+ case "Q": self.init(queen: .white)
+ case "q": self.init(queen: .black)
+ case "K": self.init(king: .white)
+ case "k": self.init(king: .black)
+ default:
+ return nil
+ }
+ }
+
+ /// Returns `true` if `self` can be a promotion for `other`.
+ public func canPromote(_ other: Piece) -> Bool {
+ return kind.canPromote(other.kind) && color == other.color
+ }
+
+ /// Returns `true` if `self` can be a promotion for `color`.
+ public func canPromote(_ color: Color) -> Bool {
+ return kind.canPromote() ? self.color == color : false
+ }
+
+ /// The special character for the piece.
+ public func specialCharacter(background color: Color = .white) -> Character {
+ switch kind {
+ case .pawn: return color == self.color ? "♙" : "♟"
+ case .knight: return color == self.color ? "♘" : "♞"
+ case .bishop: return color == self.color ? "♗" : "♝"
+ case .rook: return color == self.color ? "♖" : "♜"
+ case .queen: return color == self.color ? "♕" : "♛"
+ case .king: return color == self.color ? "♔" : "♚"
+ }
+ }
+
+ public func unicodeCharacter() -> Character {
+ switch kind {
+ case .pawn: return "♟"
+ case .knight: return "♞"
+ case .bishop: return "♝"
+ case .rook: return "♜"
+ case .queen: return "♛"
+ case .king: return "♚"
+ }
+ }
+
+}
+
+/// Returns `true` if both pieces are the same.
+public func == (lhs: Piece, rhs: Piece) -> Bool {
+ return lhs.kind == rhs.kind
+ && lhs.color == rhs.color
+}