aboutsummaryrefslogtreecommitdiff
path: root/Sources/SwiftChessNeo/Move.swift
diff options
context:
space:
mode:
Diffstat (limited to 'Sources/SwiftChessNeo/Move.swift')
-rw-r--r--Sources/SwiftChessNeo/Move.swift203
1 files changed, 203 insertions, 0 deletions
diff --git a/Sources/SwiftChessNeo/Move.swift b/Sources/SwiftChessNeo/Move.swift
new file mode 100644
index 0000000..efc88d7
--- /dev/null
+++ b/Sources/SwiftChessNeo/Move.swift
@@ -0,0 +1,203 @@
+//
+// Move.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 move from a start `Square` to an end `Square`.
+public struct Move: Hashable, CustomStringConvertible {
+
+ /// The move's start square.
+ public var start: Square
+
+ /// The move's end square.
+ public var end: Square
+
+ /// The move's change in file.
+ public var fileChange: Int {
+ return end.file.rawValue - start.file.rawValue
+ }
+
+ /// The move's change in rank.
+ public var rankChange: Int {
+ return end.rank.rawValue - start.rank.rawValue
+ }
+
+ /// The move is a real change in location.
+ public var isChange: Bool {
+ return start != end
+ }
+
+ /// The move is diagonal.
+ public var isDiagonal: Bool {
+ let fileChange = self.fileChange
+ return fileChange != 0 && abs(fileChange) == abs(rankChange)
+ }
+
+ /// The move is horizontal.
+ public var isHorizontal: Bool {
+ return start.file != end.file && start.rank == end.rank
+ }
+
+ /// The move is vertical.
+ public var isVertical: Bool {
+ return start.file == end.file && start.rank != end.rank
+ }
+
+ /// The move is horizontal or vertical.
+ public var isAxial: Bool {
+ return isHorizontal || isVertical
+ }
+
+ /// The move is leftward.
+ public var isLeftward: Bool {
+ return end.file < start.file
+ }
+
+ /// The move is rightward.
+ public var isRightward: Bool {
+ return end.file > start.file
+ }
+
+ /// The move is downward.
+ public var isDownward: Bool {
+ return end.rank < start.rank
+ }
+
+ /// The move is upward.
+ public var isUpward: Bool {
+ return end.rank > start.rank
+ }
+
+ /// The move is a knight jump two spaces horizontally and one space vertically, or two spaces vertically and one
+ /// space horizontally.
+ public var isKnightJump: Bool {
+ let fileChange = abs(self.fileChange)
+ let rankChange = abs(self.rankChange)
+ return (fileChange == 2 && rankChange == 1)
+ || (rankChange == 2 && fileChange == 1)
+ }
+
+ /// The move's direction in file, if any.
+ public var fileDirection: File.Direction? {
+ if self.isLeftward {
+ return .left
+ } else if self.isRightward {
+ return .right
+ } else {
+ return .none
+ }
+ }
+
+ /// The move's direction in rank, if any.
+ public var rankDirection: Rank.Direction? {
+ if self.isUpward {
+ return .up
+ } else if self.isDownward {
+ return .down
+ } else {
+ return .none
+ }
+ }
+
+ /// A textual representation of `self`.
+ public var description: String {
+ return "\(start) >>> \(end)"
+ }
+
+ /// The hash value.
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(start)
+ hasher.combine(end)
+ }
+
+ /// Create a move with start and end squares.
+ public init(start: Square, end: Square) {
+ self.start = start
+ self.end = end
+ }
+
+ /// Create a move with start and end locations.
+ public init(start: Location, end: Location) {
+ self.start = Square(location: start)
+ self.end = Square(location: end)
+ }
+
+ /// A castle move for `color` in `direction`.
+ public init(castle color: Color, direction: File.Direction) {
+ let rank: Rank = color.isWhite ? 1 : 8
+ self = Move(start: Square(file: .e, rank: rank), end: Square(file: direction == .left ? .c : .g, rank: rank))
+ }
+
+ /// Returns the castle squares for a rook.
+ internal func _castleSquares() -> (old: Square, new: Square) {
+ let rank = start.rank
+ let movedLeft = self.isLeftward
+ let old = Square(file: movedLeft ? .a : .h, rank: rank)
+ let new = Square(file: movedLeft ? .d : .f, rank: rank)
+ return (old, new)
+ }
+
+ /// Returns a move with the end and start of `self` reversed.
+ public func reversed() -> Move {
+ return Move(start: end, end: start)
+ }
+
+ /// Returns the result of rotating `self` 180 degrees.
+ public func rotated() -> Move {
+ let start = Square(file: self.start.file.opposite(),
+ rank: self.start.rank.opposite())
+ let end = Square(file: self.end.file.opposite(),
+ rank: self.end.rank.opposite())
+ return start >>> end
+ }
+
+ /// Returns `true` if `self` is castle move for `color`.
+ ///
+ /// - parameter color: The color to check the rank against. If `nil`, the rank can be either 1 or 8. The default
+ /// value is `nil`.
+ public func isCastle(for color: Color? = nil) -> Bool {
+ let startRank = start.rank
+ if let color = color {
+ guard startRank == Rank(startFor: color) else { return false }
+ } else {
+ guard startRank == 1 || startRank == 8 else { return false }
+ }
+ let endFile = end.file
+ return startRank == end.rank
+ && start.file == ._e
+ && (endFile == ._c || endFile == ._g)
+ }
+
+}
+
+infix operator >>>
+
+/// Returns `true` if both moves are the same.
+public func == (lhs: Move, rhs: Move) -> Bool {
+ return lhs.start == rhs.start && lhs.end == rhs.end
+}
+
+/// Returns a `Move` from the two squares.
+public func >>> (start: Square, end: Square) -> Move {
+ return Move(start: start, end: end)
+}
+
+/// Returns a `Move` from the two locations.
+public func >>> (start: Location, rhs: Location) -> Move {
+ return Square(location: start) >>> Square(location: rhs)
+}