Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| faf65a02fb | |||
| 0f3cd549f6 | |||
| ce3df6cdce | |||
| 9ffafa0ee1 | |||
| 6f80d184de |
@@ -15,6 +15,9 @@
|
||||
676902581E432380007C76D7 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676902571E432380007C76D7 /* PerformanceTests.swift */; };
|
||||
676C911C1E478A3A00985A4F /* SwiftChess.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 67A9CA0D1DE64D6500510FB8 /* SwiftChess.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
676EF7C51E15AC1700E275B4 /* BoardRaterKingSurroundingPossession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676EF7C41E15AC1700E275B4 /* BoardRaterKingSurroundingPossession.swift */; };
|
||||
677BE819200A3749004B27DB /* DictionaryRepresentableExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 677BE818200A3749004B27DB /* DictionaryRepresentableExtensions.swift */; };
|
||||
677BE81C200A3BDE004B27DB /* SquareTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 677BE81B200A3BDE004B27DB /* SquareTests.swift */; };
|
||||
677BE81D200A52D8004B27DB /* AIConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67F7791F1E1B923B00885B89 /* AIConfigurationTests.swift */; };
|
||||
67A3EB161E3A926C00F6F01B /* BoardScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A3EB121E3A826800F6F01B /* BoardScenarios.swift */; };
|
||||
67A9CA341DE64DD600510FB8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; };
|
||||
67A9CA351DE64DD800510FB8 /* MenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* MenuViewController.swift */; };
|
||||
@@ -101,6 +104,8 @@
|
||||
671989901DFFE8650053EA3D /* BoardRaterCenterDominanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCenterDominanceTests.swift; sourceTree = "<group>"; };
|
||||
676902571E432380007C76D7 /* PerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceTests.swift; sourceTree = "<group>"; };
|
||||
676EF7C41E15AC1700E275B4 /* BoardRaterKingSurroundingPossession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterKingSurroundingPossession.swift; sourceTree = "<group>"; };
|
||||
677BE818200A3749004B27DB /* DictionaryRepresentableExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryRepresentableExtensions.swift; sourceTree = "<group>"; };
|
||||
677BE81B200A3BDE004B27DB /* SquareTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SquareTests.swift; sourceTree = "<group>"; };
|
||||
67A3EB121E3A826800F6F01B /* BoardScenarios.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardScenarios.swift; sourceTree = "<group>"; };
|
||||
67A9CA071DE64D6500510FB8 /* SwiftChess.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftChess.xcodeproj; path = ../SwiftChess/SwiftChess.xcodeproj; sourceTree = "<group>"; };
|
||||
67A9CA141DE64DAA00510FB8 /* SwiftChessExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftChessExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -199,6 +204,7 @@
|
||||
children = (
|
||||
607FACE91AFB9204008FA782 /* Supporting Files */,
|
||||
67D54A651DE986F700C12258 /* PieceTests.swift */,
|
||||
677BE81B200A3BDE004B27DB /* SquareTests.swift */,
|
||||
67FD868C1E41099B0023335C /* BoardLocationTests.swift */,
|
||||
67D54A511DE7680E00C12258 /* BoardTests.swift */,
|
||||
67D54A521DE7680E00C12258 /* GameTests.swift */,
|
||||
@@ -220,6 +226,7 @@
|
||||
children = (
|
||||
607FACEA1AFB9204008FA782 /* Info.plist */,
|
||||
67A3EB121E3A826800F6F01B /* BoardScenarios.swift */,
|
||||
677BE818200A3749004B27DB /* DictionaryRepresentableExtensions.swift */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
@@ -441,11 +448,13 @@
|
||||
67FD86911E4128F00023335C /* OpeningsTests.swift in Sources */,
|
||||
67D54A611DE7683A00C12258 /* Tests.swift in Sources */,
|
||||
676EF7C51E15AC1700E275B4 /* BoardRaterKingSurroundingPossession.swift in Sources */,
|
||||
677BE81C200A3BDE004B27DB /* SquareTests.swift in Sources */,
|
||||
67FD868D1E41099B0023335C /* BoardLocationTests.swift in Sources */,
|
||||
67D54A5D1DE7682D00C12258 /* BoardTests.swift in Sources */,
|
||||
67F9DB751E1AD3BB00C7EC5A /* AIBehaviourTests.swift in Sources */,
|
||||
671989911DFFE8650053EA3D /* BoardRaterCenterDominanceTests.swift in Sources */,
|
||||
6719898D1DFFE0F40053EA3D /* BoardRaterBoardDominanceTests.swift in Sources */,
|
||||
677BE819200A3749004B27DB /* DictionaryRepresentableExtensions.swift in Sources */,
|
||||
67D54A5E1DE7683000C12258 /* GameTests.swift in Sources */,
|
||||
673B95191E4CE5880086CA97 /* BoardRaterThreatenedPiecesTests.swift in Sources */,
|
||||
67D54A661DE986F700C12258 /* PieceTests.swift in Sources */,
|
||||
@@ -453,6 +462,7 @@
|
||||
67B73A9F1E154C1E00C19176 /* AIPlayerTests.swift in Sources */,
|
||||
676902581E432380007C76D7 /* PerformanceTests.swift in Sources */,
|
||||
67D54A641DE976A900C12258 /* BoardRaterCountPiecesTests.swift in Sources */,
|
||||
677BE81D200A52D8004B27DB /* AIConfigurationTests.swift in Sources */,
|
||||
67A3EB161E3A926C00F6F01B /* BoardScenarios.swift in Sources */,
|
||||
09AE32551E03D71D00A149FE /* BoardRaterPawnProgressionTests.swift in Sources */,
|
||||
67D54A5F1DE7683300C12258 /* PieceMovementTests.swift in Sources */,
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
// Copyright © 2017 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
//swiftlint:disable type_body_length
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
@@ -35,12 +37,16 @@ class AIConfigurationTests: XCTestCase {
|
||||
"R K B Q G B K R" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterCountPiecesWeighting = 1
|
||||
lowValueConfig.boardRaterCountPiecesWeighting = AIConfiguration.ConfigurationValue(easyValue: 1,
|
||||
difficultValue: 1,
|
||||
multiplier: 10)
|
||||
let lowValueRater = BoardRaterCountPieces(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterCountPiecesWeighting = 2
|
||||
highValueConfig.boardRaterCountPiecesWeighting = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterCountPieces(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
@@ -61,12 +67,16 @@ class AIConfigurationTests: XCTestCase {
|
||||
"R K B Q G B K R" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterBoardDominanceWeighting = 1
|
||||
lowValueConfig.boardRaterBoardDominanceWeighting = AIConfiguration.ConfigurationValue(easyValue: 1,
|
||||
difficultValue: 1,
|
||||
multiplier: 10)
|
||||
let lowValueRater = BoardRaterBoardDominance(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterBoardDominanceWeighting = 2
|
||||
highValueConfig.boardRaterBoardDominanceWeighting = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterBoardDominance(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
@@ -87,12 +97,16 @@ class AIConfigurationTests: XCTestCase {
|
||||
"R K B Q G B K R" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterCenterOwnershipWeighting = 1
|
||||
lowValueConfig.boardRaterCenterOwnershipWeighting = AIConfiguration.ConfigurationValue(easyValue: 1,
|
||||
difficultValue: 1,
|
||||
multiplier: 10)
|
||||
let lowValueRater = BoardRaterCenterOwnership(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterCenterOwnershipWeighting = 2
|
||||
highValueConfig.boardRaterCenterOwnershipWeighting = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterCenterOwnership(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
@@ -113,12 +127,16 @@ class AIConfigurationTests: XCTestCase {
|
||||
"R K B Q G B K R" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterCenterDominanceWeighting = 1
|
||||
lowValueConfig.boardRaterCenterDominanceWeighting = AIConfiguration.ConfigurationValue(easyValue: 1,
|
||||
difficultValue: 1,
|
||||
multiplier: 10)
|
||||
let lowValueRater = BoardRaterCenterDominance(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterCenterDominanceWeighting = 2
|
||||
highValueConfig.boardRaterCenterDominanceWeighting = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterCenterDominance(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
@@ -140,19 +158,23 @@ class AIConfigurationTests: XCTestCase {
|
||||
"- - - - G - - B" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterThreatenedPiecesWeighting = 1
|
||||
lowValueConfig.boardRaterThreatenedPiecesWeighting = AIConfiguration.ConfigurationValue(easyValue: 1,
|
||||
difficultValue: 1,
|
||||
multiplier: 10)
|
||||
let lowValueRater = BoardRaterThreatenedPieces(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterThreatenedPiecesWeighting = 2
|
||||
highValueConfig.boardRaterThreatenedPiecesWeighting = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterThreatenedPieces(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
func testBoardRaterThreatenedPiecesOwnPiecesMultiplierAffectsRating() {
|
||||
func testBoardRaterThreatenedPiecesOwnPiecesWeightingAffectsRating() {
|
||||
|
||||
// White and black rook are threatening each other, so advantage is neutral
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
@@ -165,12 +187,16 @@ class AIConfigurationTests: XCTestCase {
|
||||
"- - - - G - - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterThreatenedPiecesOwnPiecesMultiplier = 1
|
||||
lowValueConfig.boardRaterThreatenedPiecesWeighting = AIConfiguration.ConfigurationValue(easyValue: 1,
|
||||
difficultValue: 1,
|
||||
multiplier: 10)
|
||||
let lowValueRater = BoardRaterThreatenedPieces(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterThreatenedPiecesOwnPiecesMultiplier = 2
|
||||
highValueConfig.boardRaterThreatenedPiecesWeighting = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterThreatenedPieces(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
@@ -192,12 +218,16 @@ class AIConfigurationTests: XCTestCase {
|
||||
"- - - - G - - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterPawnProgressionWeighting = 1
|
||||
lowValueConfig.boardRaterPawnProgressionWeighting = AIConfiguration.ConfigurationValue(easyValue: 1,
|
||||
difficultValue: 1,
|
||||
multiplier: 10)
|
||||
let lowValueRater = BoardRaterPawnProgression(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterPawnProgressionWeighting = 2
|
||||
highValueConfig.boardRaterPawnProgressionWeighting = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterPawnProgression(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
@@ -218,12 +248,18 @@ class AIConfigurationTests: XCTestCase {
|
||||
"- - - P G P - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterKingSurroundingPossessionWeighting = 1
|
||||
lowValueConfig.boardRaterKingSurroundingPossessionWeighting =
|
||||
AIConfiguration.ConfigurationValue(easyValue: 1,
|
||||
difficultValue: 1,
|
||||
multiplier: 10)
|
||||
let lowValueRater = BoardRaterKingSurroundingPossession(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterKingSurroundingPossessionWeighting = 2
|
||||
highValueConfig.boardRaterKingSurroundingPossessionWeighting =
|
||||
AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterKingSurroundingPossession(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
@@ -245,12 +281,16 @@ class AIConfigurationTests: XCTestCase {
|
||||
"R - - P G P - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterCheckMateOpportunityWeighting = 1
|
||||
lowValueConfig.boardRaterCheckMateOpportunityWeighting = AIConfiguration.ConfigurationValue(easyValue: 1,
|
||||
difficultValue: 1,
|
||||
multiplier: 1)
|
||||
let lowValueRater = BoardRaterCheckMateOpportunity(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterCheckMateOpportunityWeighting = 2
|
||||
highValueConfig.boardRaterCheckMateOpportunityWeighting = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 1)
|
||||
let highValueRater = BoardRaterCheckMateOpportunity(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
@@ -272,15 +312,33 @@ class AIConfigurationTests: XCTestCase {
|
||||
"- - - P G P - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterCenterFourOccupationWeighting = 1
|
||||
lowValueConfig.boardRaterCenterFourOccupationWeighting = AIConfiguration.ConfigurationValue(easyValue: 1,
|
||||
difficultValue: 1,
|
||||
multiplier: 1)
|
||||
let lowValueRater = BoardRaterCenterFourOccupation(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterCenterFourOccupationWeighting = 2
|
||||
highValueConfig.boardRaterCenterFourOccupationWeighting = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 1)
|
||||
let highValueRater = BoardRaterCenterFourOccupation(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - AIConfiguration Dictionary Representable
|
||||
|
||||
func testDictionaryRepresentable() {
|
||||
|
||||
let easy = AIConfiguration(difficulty: .easy)
|
||||
XCTAssertEqual(easy, easy.toDictionaryAndBack)
|
||||
|
||||
let medium = AIConfiguration(difficulty: .medium)
|
||||
XCTAssertEqual(medium, medium.toDictionaryAndBack)
|
||||
|
||||
let hard = AIConfiguration(difficulty: .hard)
|
||||
XCTAssertEqual(hard, hard.toDictionaryAndBack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,4 +183,17 @@ class AIPlayerTests: XCTestCase {
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(from: bishopLocation, to: testLocation))
|
||||
}
|
||||
|
||||
// MARK: - Dictionary Representable
|
||||
|
||||
func testDictionaryRepresentable() {
|
||||
|
||||
let whiteEasy = AIPlayer(color: .white,
|
||||
configuration: AIConfiguration(difficulty: .easy))
|
||||
XCTAssertEqual(whiteEasy, whiteEasy.toDictionaryAndBack)
|
||||
|
||||
let blackHard = AIPlayer(color: .black,
|
||||
configuration: AIConfiguration(difficulty: .hard))
|
||||
XCTAssertEqual(blackHard, blackHard.toDictionaryAndBack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,5 +182,12 @@ class BoardLocationTests: XCTestCase {
|
||||
XCTAssertFalse($0.isDarkSquare, "Expected \($0) to be light")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Dictionary Representable
|
||||
|
||||
func testDictionaryRepresentable() {
|
||||
|
||||
let location = BoardLocation(index: 14)
|
||||
XCTAssertEqual(location, location.toDictionaryAndBack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ class BoardTests: XCTestCase {
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssert(returnedPiece == piece, "Expected pieces to be the same")
|
||||
XCTAssert(returnedPiece.isSameTypeAndColor(asPiece: piece), "Expected pieces to be the same")
|
||||
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ class BoardTests: XCTestCase {
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssert(returnedPiece == piece, "Expected pieces to be the same")
|
||||
XCTAssert(returnedPiece.isSameTypeAndColor(asPiece: piece), "Expected pieces to be the same")
|
||||
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ class BoardTests: XCTestCase {
|
||||
func verifyPieceExistance(piece: Piece) {
|
||||
|
||||
let matchingPieces = pieces.filter {
|
||||
return $0 == piece
|
||||
return $0.isSameTypeAndColor(asPiece: piece)
|
||||
}
|
||||
|
||||
XCTAssert(matchingPieces.count != 0,
|
||||
@@ -277,8 +277,8 @@ class BoardTests: XCTestCase {
|
||||
board.setPiece(whiteKing, at: BoardLocation(index: 0))
|
||||
board.setPiece(blackKing, at: BoardLocation(index: 1))
|
||||
|
||||
XCTAssert(board.getKing(color: .white) == whiteKing, "Unable to find white king")
|
||||
XCTAssert(board.getKing(color: .black) == blackKing, "Unable to find black king")
|
||||
XCTAssert(board.getKing(color: .white).isSameTypeAndColor(asPiece: whiteKing), "Unable to find white king")
|
||||
XCTAssert(board.getKing(color: .black).isSameTypeAndColor(asPiece: blackKing), "Unable to find black king")
|
||||
|
||||
}
|
||||
|
||||
@@ -1104,5 +1104,22 @@ class BoardTests: XCTestCase {
|
||||
XCTAssertEqual(piece.location, location)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Dictionary Representable
|
||||
|
||||
func testDictionaryRepresentable() {
|
||||
|
||||
let asciiBoard = ASCIIBoard(pieces: "r - - - g - - r" +
|
||||
"p p p p p p p p" +
|
||||
"- - - - - - - -" +
|
||||
"- K - - - b - -" +
|
||||
"- - B - - - k -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P P P P P P" +
|
||||
"R - - - G - - R" )
|
||||
|
||||
let board = asciiBoard.board
|
||||
XCTAssertEqual(board, board.toDictionaryAndBack)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// DictionaryRepresentableExtensions.swift
|
||||
// SwiftChessExampleTests
|
||||
//
|
||||
// Created by Steve Barnegren on 13/01/2018.
|
||||
// Copyright © 2018 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@testable import SwiftChess
|
||||
|
||||
extension DictionaryRepresentable {
|
||||
|
||||
var toDictionaryAndBack: Self? {
|
||||
|
||||
let dictionary = self.dictionaryRepresentation
|
||||
return Self(dictionary: dictionary)
|
||||
}
|
||||
}
|
||||
@@ -107,4 +107,45 @@ class GameTests: XCTestCase {
|
||||
XCTAssertTrue(game.state == Game.State.won(color: .black))
|
||||
}
|
||||
|
||||
// MARK: - Game State Dictionary Representable
|
||||
|
||||
func testGameStateDictionaryRepresentable() {
|
||||
|
||||
let inProgress = Game.State.inProgress
|
||||
XCTAssertEqual(inProgress, inProgress.toDictionaryAndBack)
|
||||
|
||||
let whiteStalemate = Game.State.staleMate(color: .white)
|
||||
XCTAssertEqual(whiteStalemate, whiteStalemate.toDictionaryAndBack)
|
||||
|
||||
let blackStalemate = Game.State.staleMate(color: .black)
|
||||
XCTAssertEqual(blackStalemate, blackStalemate.toDictionaryAndBack)
|
||||
|
||||
let whiteWon = Game.State.won(color: .white)
|
||||
XCTAssertEqual(whiteWon, whiteWon.toDictionaryAndBack)
|
||||
|
||||
let blackWon = Game.State.won(color: .black)
|
||||
XCTAssertEqual(blackWon, blackWon.toDictionaryAndBack)
|
||||
}
|
||||
|
||||
// MARK: - Game Dictionary Representable
|
||||
|
||||
func testGameDictionaryRepresentable() {
|
||||
|
||||
do {
|
||||
let whitePlayer = Human(color: .white)
|
||||
let blackPlayer = Human(color: .black)
|
||||
let board = Board(state: .newGame)
|
||||
let game = Game(firstPlayer: whitePlayer, secondPlayer: blackPlayer, board: board, colorToMove: .white)
|
||||
XCTAssertEqual(game, game.toDictionaryAndBack)
|
||||
}
|
||||
|
||||
do {
|
||||
let whitePlayer = Human(color: .white)
|
||||
let blackPlayer = AIPlayer(color: .black, configuration: AIConfiguration(difficulty: .hard))
|
||||
let board = Board(state: .newGame)
|
||||
let game = Game(firstPlayer: whitePlayer, secondPlayer: blackPlayer, board: board, colorToMove: .black)
|
||||
XCTAssertEqual(game, game.toDictionaryAndBack)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import SwiftChess
|
||||
@testable import SwiftChess
|
||||
|
||||
class PieceTests: XCTestCase {
|
||||
|
||||
@@ -38,4 +38,23 @@ class PieceTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - DictionaryRepresentable
|
||||
|
||||
func testPieceDictionaryRepresentable() {
|
||||
|
||||
var piece1 = Piece(type: .pawn, color: .white)
|
||||
piece1.tag = 0
|
||||
piece1.hasMoved = false
|
||||
piece1.canBeTakenByEnPassant = false
|
||||
piece1.location = BoardLocation(index: 0)
|
||||
XCTAssertEqual(piece1, piece1.toDictionaryAndBack)
|
||||
|
||||
var piece2 = Piece(type: .bishop, color: .black)
|
||||
piece2.tag = 15
|
||||
piece2.hasMoved = true
|
||||
piece2.canBeTakenByEnPassant = true
|
||||
piece2.location = BoardLocation(index: 15)
|
||||
XCTAssertEqual(piece2, piece2.toDictionaryAndBack)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -248,6 +248,14 @@ class PlayerTests: XCTestCase {
|
||||
} catch let error {
|
||||
XCTAssert(error as! Player.MoveError == .cannotMoveInToCheck)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Human dictionary Representable
|
||||
|
||||
func testHumanDictionaryRepresentable() {
|
||||
|
||||
let whiteHuman = Human(color: .white)
|
||||
XCTAssertEqual(whiteHuman, whiteHuman.toDictionaryAndBack)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// SquareTests.swift
|
||||
// SwiftChessExampleTests
|
||||
//
|
||||
// Created by Steve Barnegren on 13/01/2018.
|
||||
// Copyright © 2018 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class SquareTests: XCTestCase {
|
||||
|
||||
func testDictionaryRepresentable() {
|
||||
|
||||
let piece = Piece(type: .bishop, color: .black)
|
||||
let squareWithPiece = Square(piece: piece)
|
||||
XCTAssertEqual(squareWithPiece, squareWithPiece.toDictionaryAndBack)
|
||||
|
||||
let squareWithoutPiece = Square(piece: nil)
|
||||
XCTAssertEqual(squareWithoutPiece, squareWithoutPiece.toDictionaryAndBack)
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'SwiftChess'
|
||||
s.version = '0.3.0'
|
||||
s.version = '1.0'
|
||||
s.summary = 'Chess engine written in Swift'
|
||||
|
||||
# This description is used to generate tags and improve search results.
|
||||
|
||||
@@ -27,16 +27,16 @@ public struct AIConfiguration {
|
||||
}
|
||||
|
||||
public let difficulty: Difficulty!
|
||||
var suicideMultipler: ConfigurationValue!
|
||||
var boardRaterCountPiecesWeighting: ConfigurationValue!
|
||||
var boardRaterBoardDominanceWeighting: ConfigurationValue!
|
||||
var boardRaterCenterOwnershipWeighting: ConfigurationValue!
|
||||
var boardRaterCenterDominanceWeighting: ConfigurationValue!
|
||||
var boardRaterThreatenedPiecesWeighting: ConfigurationValue!
|
||||
var boardRaterPawnProgressionWeighting: ConfigurationValue!
|
||||
var boardRaterKingSurroundingPossessionWeighting: ConfigurationValue!
|
||||
var boardRaterCheckMateOpportunityWeighting: ConfigurationValue!
|
||||
var boardRaterCenterFourOccupationWeighting: ConfigurationValue!
|
||||
internal var suicideMultipler: ConfigurationValue
|
||||
internal var boardRaterCountPiecesWeighting: ConfigurationValue
|
||||
internal var boardRaterBoardDominanceWeighting: ConfigurationValue
|
||||
internal var boardRaterCenterOwnershipWeighting: ConfigurationValue
|
||||
internal var boardRaterCenterDominanceWeighting: ConfigurationValue
|
||||
internal var boardRaterThreatenedPiecesWeighting: ConfigurationValue
|
||||
internal var boardRaterPawnProgressionWeighting: ConfigurationValue
|
||||
internal var boardRaterKingSurroundingPossessionWeighting: ConfigurationValue
|
||||
internal var boardRaterCheckMateOpportunityWeighting: ConfigurationValue
|
||||
internal var boardRaterCenterFourOccupationWeighting: ConfigurationValue
|
||||
|
||||
public init(difficulty: Difficulty) {
|
||||
|
||||
@@ -66,4 +66,49 @@ public struct AIConfiguration {
|
||||
boardRaterCenterFourOccupationWeighting = makeValue(0.1, 0.3)
|
||||
}
|
||||
|
||||
internal init() {
|
||||
|
||||
let zeroValue = ConfigurationValue(easyValue: 0, difficultValue: 0, multiplier: 0)
|
||||
|
||||
difficulty = .easy
|
||||
suicideMultipler = zeroValue
|
||||
boardRaterCountPiecesWeighting = zeroValue
|
||||
boardRaterBoardDominanceWeighting = zeroValue
|
||||
boardRaterCenterOwnershipWeighting = zeroValue
|
||||
boardRaterCenterDominanceWeighting = zeroValue
|
||||
boardRaterThreatenedPiecesWeighting = zeroValue
|
||||
boardRaterPawnProgressionWeighting = zeroValue
|
||||
boardRaterKingSurroundingPossessionWeighting = zeroValue
|
||||
boardRaterCheckMateOpportunityWeighting = zeroValue
|
||||
boardRaterCenterFourOccupationWeighting = zeroValue
|
||||
}
|
||||
}
|
||||
|
||||
extension AIConfiguration: DictionaryRepresentable {
|
||||
|
||||
struct Keys {
|
||||
static let difficulty = "difficulty"
|
||||
}
|
||||
|
||||
init?(dictionary: [String: Any]) {
|
||||
|
||||
if let raw = dictionary[Keys.difficulty] as? Int, let difficulty = Difficulty(rawValue: raw) {
|
||||
self.init(difficulty: difficulty)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var dictionaryRepresentation: [String: Any] {
|
||||
|
||||
var dictionary = [String: Any]()
|
||||
dictionary[Keys.difficulty] = difficulty.rawValue
|
||||
return dictionary
|
||||
}
|
||||
}
|
||||
|
||||
extension AIConfiguration: Equatable {
|
||||
public static func == (lhs: AIConfiguration, rhs: AIConfiguration) -> Bool {
|
||||
return lhs.difficulty == rhs.difficulty
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// swiftlint:disable for_where
|
||||
import Foundation
|
||||
|
||||
open class AIPlayer: Player {
|
||||
public final class AIPlayer: Player {
|
||||
|
||||
let boardRaters: [BoardRater]!
|
||||
public let configuration: AIConfiguration!
|
||||
@@ -278,6 +278,41 @@ open class AIPlayer: Player {
|
||||
}
|
||||
}
|
||||
|
||||
extension AIPlayer: Equatable {
|
||||
public static func == (lhs: AIPlayer, rhs: AIPlayer) -> Bool {
|
||||
return lhs.color == rhs.color && lhs.configuration == rhs.configuration
|
||||
}
|
||||
}
|
||||
|
||||
extension AIPlayer: DictionaryRepresentable {
|
||||
|
||||
struct Keys {
|
||||
static let color = "color"
|
||||
static let configuration = "configuration"
|
||||
}
|
||||
|
||||
convenience init?(dictionary: [String: Any]) {
|
||||
|
||||
guard
|
||||
let colorRaw = dictionary[Keys.color] as? String,
|
||||
let color = Color(rawValue: colorRaw),
|
||||
let configurationDict = dictionary[Keys.configuration] as? [String: Any],
|
||||
let configuration = AIConfiguration(dictionary: configurationDict) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self.init(color: color, configuration: configuration)
|
||||
}
|
||||
|
||||
var dictionaryRepresentation: [String: Any] {
|
||||
|
||||
var dictionary = [String: Any]()
|
||||
dictionary[Keys.color] = color.rawValue
|
||||
dictionary[Keys.configuration] = configuration.dictionaryRepresentation
|
||||
return dictionary
|
||||
}
|
||||
}
|
||||
|
||||
struct Move {
|
||||
|
||||
enum MoveType {
|
||||
|
||||
@@ -30,12 +30,37 @@ public func == (lhs: Square, rhs: Square) -> Bool {
|
||||
case (.none, .none):
|
||||
return true
|
||||
case (.some(let rp), .some(let lp)):
|
||||
return rp == lp
|
||||
return rp.isSameTypeAndColor(asPiece: lp)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
extension Square: DictionaryRepresentable {
|
||||
|
||||
struct Keys {
|
||||
static let piece = "piece"
|
||||
}
|
||||
|
||||
init?(dictionary: [String: Any]) {
|
||||
|
||||
if let dict = dictionary[Keys.piece] as? [String: Any], let piece = Piece(dictionary: dict) {
|
||||
self.piece = piece
|
||||
}
|
||||
}
|
||||
|
||||
var dictionaryRepresentation: [String: Any] {
|
||||
|
||||
var dictionary = [String: Any]()
|
||||
|
||||
if let piece = self.piece {
|
||||
dictionary[Keys.piece] = piece.dictionaryRepresentation
|
||||
}
|
||||
|
||||
return dictionary
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ****** Board ******
|
||||
|
||||
public struct Board: Equatable {
|
||||
@@ -46,6 +71,7 @@ public struct Board: Equatable {
|
||||
}
|
||||
|
||||
public private(set) var squares = [Square]()
|
||||
private var lastAssignedPieceTag = 0
|
||||
|
||||
// MARK: - Init
|
||||
public init(state: InitialState) {
|
||||
@@ -59,31 +85,35 @@ public struct Board: Equatable {
|
||||
if state == .newGame {
|
||||
setupForNewGame()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mutating func setupForNewGame() {
|
||||
|
||||
let pieces: [Piece.PieceType] = [.rook, .knight, .bishop, .queen, .king, .bishop, .knight, .rook]
|
||||
|
||||
func makePiece(type: Piece.PieceType, color: Color) -> Piece {
|
||||
lastAssignedPieceTag += 1
|
||||
return Piece(type: type, color: color, tag: lastAssignedPieceTag)
|
||||
}
|
||||
|
||||
// Setup white bottom row
|
||||
for i in 0...7 {
|
||||
setPiece(Piece(type: pieces[i], color: .white), at: BoardLocation(index: i))
|
||||
setPiece(makePiece(type: pieces[i], color: .white), at: BoardLocation(index: i))
|
||||
}
|
||||
|
||||
// Setup white pawn row
|
||||
for i in 8...15 {
|
||||
setPiece(Piece(type: .pawn, color: .white), at: BoardLocation(index: i))
|
||||
setPiece(makePiece(type: .pawn, color: .white), at: BoardLocation(index: i))
|
||||
}
|
||||
|
||||
// Setup black bottom row
|
||||
for i in 56...63 {
|
||||
setPiece(Piece(type: pieces[i-56], color: .black), at: BoardLocation(index: i))
|
||||
setPiece(makePiece(type: pieces[i-56], color: .black), at: BoardLocation(index: i))
|
||||
}
|
||||
|
||||
// Setup black pawn row
|
||||
for i in 48...55 {
|
||||
setPiece(Piece(type: .pawn, color: .black), at: BoardLocation(index: i))
|
||||
setPiece(makePiece(type: .pawn, color: .black), at: BoardLocation(index: i))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +212,7 @@ public struct Board: Equatable {
|
||||
continue
|
||||
}
|
||||
|
||||
if piece == Piece(type: .king, color: color) {
|
||||
if piece.isSameTypeAndColor(asPiece: Piece(type: .king, color: color)) {
|
||||
king = piece
|
||||
break
|
||||
}
|
||||
@@ -654,3 +684,35 @@ public struct Board: Equatable {
|
||||
public func == (lhs: Board, rhs: Board) -> Bool {
|
||||
return lhs.squares == rhs.squares
|
||||
}
|
||||
|
||||
extension Board: DictionaryRepresentable {
|
||||
|
||||
struct Keys {
|
||||
static let squares = "squares"
|
||||
}
|
||||
|
||||
init?(dictionary: [String: Any]) {
|
||||
|
||||
guard let squaresDicts = dictionary[Keys.squares] as? [[String: Any]] else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let squares = squaresDicts.flatMap { Square(dictionary: $0) }
|
||||
if squares.count == 64 {
|
||||
self.squares = squares
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
lastAssignedPieceTag = squares.flatMap { $0.piece }.map { $0.tag }.max() ?? 0
|
||||
}
|
||||
|
||||
var dictionaryRepresentation: [String: Any] {
|
||||
|
||||
var dictionary = [String: Any]()
|
||||
let squares = self.squares.map { $0.dictionaryRepresentation }
|
||||
dictionary[Keys.squares] = squares
|
||||
return dictionary
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,12 +82,10 @@ public struct BoardLocation: Equatable {
|
||||
|
||||
func incremented(by stride: BoardStride) -> BoardLocation {
|
||||
|
||||
// TODO: Only call this in debug mode to increace performance!
|
||||
if !canIncrement(by: stride) {
|
||||
// swiftlint:disable line_length
|
||||
print("WARNING! BoardLocation is being incremented by a stride that will result in wrapping! call canIncrementBy(stride: BoardStride) first")
|
||||
// swiftlint:enable line_length
|
||||
}
|
||||
// swiftlint:disable line_length
|
||||
assert(canIncrement(by: stride),
|
||||
"BoardLocation is being incremented by a stride that will result in wrapping! call canIncrementBy(stride: BoardStride) first")
|
||||
// swiftlint:enable line_length
|
||||
|
||||
return BoardLocation(x: x + stride.x,
|
||||
y: y + stride.y)
|
||||
@@ -138,3 +136,26 @@ public func == (lhs: BoardLocation, rhs: BoardLocation) -> Bool {
|
||||
public func + (left: BoardLocation, right: BoardLocation) -> BoardLocation {
|
||||
return BoardLocation(index: left.index + right.index)
|
||||
}
|
||||
|
||||
extension BoardLocation: DictionaryRepresentable {
|
||||
|
||||
struct Keys {
|
||||
static let index = "index"
|
||||
}
|
||||
|
||||
init?(dictionary: [String: Any]) {
|
||||
|
||||
guard let index = dictionary[Keys.index] as? Int else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self.index = index
|
||||
}
|
||||
|
||||
var dictionaryRepresentation: [String: Any] {
|
||||
|
||||
var dictionary = [String: Any]()
|
||||
dictionary[Keys.index] = index
|
||||
return dictionary
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// DictionaryRepresentable.swift
|
||||
// SwiftChess
|
||||
//
|
||||
// Created by Steve Barnegren on 13/01/2018.
|
||||
// Copyright © 2018 Steve Barnegren. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol DictionaryRepresentable {
|
||||
|
||||
init?(dictionary: [String: Any])
|
||||
var dictionaryRepresentation: [String: Any] {get}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
open class Game {
|
||||
public final class Game {
|
||||
|
||||
// MARK: Types
|
||||
public enum State: Equatable {
|
||||
@@ -30,7 +30,7 @@ open class Game {
|
||||
}
|
||||
}
|
||||
|
||||
public enum GameType {
|
||||
public enum GameType: Int {
|
||||
case humanVsHuman
|
||||
case humanVsComputer
|
||||
case computerVsComputer
|
||||
@@ -151,6 +151,184 @@ extension Game: PlayerDelegate {
|
||||
|
||||
}
|
||||
|
||||
// MARK: - DictionaryRepresentable
|
||||
|
||||
extension Game.State: DictionaryRepresentable {
|
||||
|
||||
struct Keys {
|
||||
static let type = "type"
|
||||
static let type_inProgress = "inProgress"
|
||||
static let type_stalemate = "stalemate"
|
||||
static let type_won = "won"
|
||||
static let color = "color"
|
||||
}
|
||||
|
||||
init?(dictionary: [String: Any]) {
|
||||
|
||||
guard let type = dictionary[Keys.type] as? String else {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch type {
|
||||
case Keys.type_inProgress:
|
||||
self = .inProgress
|
||||
case Keys.type_stalemate:
|
||||
guard let raw = dictionary[Keys.color] as? String, let color = Color(rawValue: raw) else {
|
||||
return nil
|
||||
}
|
||||
self = .staleMate(color: color)
|
||||
case Keys.type_won:
|
||||
guard let raw = dictionary[Keys.color] as? String, let color = Color(rawValue: raw) else {
|
||||
return nil
|
||||
}
|
||||
self = .won(color: color)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var dictionaryRepresentation: [String: Any] {
|
||||
|
||||
var dictionary = [String: Any]()
|
||||
|
||||
switch self {
|
||||
case .inProgress:
|
||||
dictionary[Keys.type] = Keys.type_inProgress
|
||||
case .staleMate(let color):
|
||||
dictionary[Keys.type] = Keys.type_stalemate
|
||||
dictionary[Keys.color] = color.rawValue
|
||||
case .won(let color):
|
||||
dictionary[Keys.type] = Keys.type_won
|
||||
dictionary[Keys.color] = color.rawValue
|
||||
}
|
||||
|
||||
return dictionary
|
||||
}
|
||||
}
|
||||
|
||||
extension Game: DictionaryRepresentable {
|
||||
|
||||
struct Keys {
|
||||
static let state = "state"
|
||||
static let gameType = "gameType"
|
||||
static let board = "board"
|
||||
static let whitePlayerType = "whitePlayerType"
|
||||
static let blackPlayerType = "blackPlayerType"
|
||||
static let playerType_human = "playerType_human"
|
||||
static let playerType_ai = "playerType_ai"
|
||||
static let whitePlayer = "PlayerOne"
|
||||
static let blackPlayer = "PlayerTwo"
|
||||
static let currentPlayerColor = "currentPlayerColor"
|
||||
}
|
||||
|
||||
public convenience init?(dictionary: [String: Any]) {
|
||||
|
||||
// State
|
||||
guard let stateDict = dictionary[Keys.state] as? [String: Any],
|
||||
let state = State(dictionary: stateDict),
|
||||
let gameTypeRaw = dictionary[Keys.gameType] as? Int,
|
||||
let gameType = GameType(rawValue: gameTypeRaw),
|
||||
let boardDict = dictionary[Keys.board] as? [String: Any],
|
||||
let board = Board(dictionary: boardDict),
|
||||
let currentPlayerColorRaw = dictionary[Keys.currentPlayerColor] as? String,
|
||||
let currentPlayerColor = Color(rawValue: currentPlayerColorRaw)
|
||||
else {
|
||||
print("Unable to recreate game, missing values")
|
||||
return nil
|
||||
}
|
||||
|
||||
func makePlayer(type: String, dictionary: [String: Any]) -> Player? {
|
||||
|
||||
switch type {
|
||||
case Keys.playerType_human:
|
||||
return Human(dictionary: dictionary)
|
||||
case Keys.playerType_ai:
|
||||
return AIPlayer(dictionary: dictionary)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// White Player
|
||||
guard let whitePlayerType = dictionary[Keys.whitePlayerType] as? String,
|
||||
let whitePlayerDict = dictionary[Keys.whitePlayer] as? [String: Any],
|
||||
let whitePlayer = makePlayer(type: whitePlayerType, dictionary: whitePlayerDict) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Black Player
|
||||
guard let blackPlayerType = dictionary[Keys.blackPlayerType] as? String,
|
||||
let blackPlayerDict = dictionary[Keys.blackPlayer] as? [String: Any],
|
||||
let blackPlayer = makePlayer(type: blackPlayerType, dictionary: blackPlayerDict) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self.init(firstPlayer: whitePlayer,
|
||||
secondPlayer: blackPlayer,
|
||||
board: board,
|
||||
colorToMove: currentPlayerColor)
|
||||
}
|
||||
|
||||
public var dictionaryRepresentation: [String: Any] {
|
||||
|
||||
var dictionary = [String: Any]()
|
||||
dictionary[Keys.state] = state.dictionaryRepresentation
|
||||
dictionary[Keys.gameType] = gameType.rawValue
|
||||
dictionary[Keys.board] = board.dictionaryRepresentation
|
||||
|
||||
// White Player
|
||||
if let whiteHuman = self.whitePlayer as? Human {
|
||||
dictionary[Keys.whitePlayerType] = Keys.playerType_human
|
||||
dictionary[Keys.whitePlayer] = whiteHuman.dictionaryRepresentation
|
||||
} else if let whiteAI = self.whitePlayer as? AIPlayer {
|
||||
dictionary[Keys.whitePlayerType] = Keys.playerType_ai
|
||||
dictionary[Keys.whitePlayer] = whiteAI.dictionaryRepresentation
|
||||
} else {
|
||||
fatalError("Cannot determine white player type")
|
||||
}
|
||||
|
||||
// Black Player
|
||||
if let blackHuman = self.blackPlayer as? Human {
|
||||
dictionary[Keys.blackPlayerType] = Keys.playerType_human
|
||||
dictionary[Keys.blackPlayer] = blackHuman.dictionaryRepresentation
|
||||
} else if let blackAI = self.blackPlayer as? AIPlayer {
|
||||
dictionary[Keys.blackPlayerType] = Keys.playerType_ai
|
||||
dictionary[Keys.blackPlayer] = blackAI.dictionaryRepresentation
|
||||
} else {
|
||||
fatalError("Cannot determine black player type")
|
||||
}
|
||||
|
||||
dictionary[Keys.currentPlayerColor] = currentPlayer.color.rawValue
|
||||
return dictionary
|
||||
}
|
||||
}
|
||||
|
||||
extension Game: Equatable {
|
||||
public static func == (lhs: Game, rhs: Game) -> Bool {
|
||||
|
||||
func arePlayersEqual(p1: Player, p2: Player) -> Bool {
|
||||
|
||||
if let h1 = p1 as? Human, let h2 = p2 as? Human {
|
||||
return h1 == h2
|
||||
} else if let ai1 = p1 as? AIPlayer, let ai2 = p2 as? AIPlayer {
|
||||
return ai1 == ai2
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if arePlayersEqual(p1: lhs.whitePlayer, p2: rhs.whitePlayer)
|
||||
&& arePlayersEqual(p1: lhs.blackPlayer, p2: rhs.blackPlayer)
|
||||
&& arePlayersEqual(p1: lhs.currentPlayer, p2: rhs.currentPlayer)
|
||||
&& lhs.board == rhs.board
|
||||
&& lhs.state == rhs.state {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - GameDelegate
|
||||
public protocol GameDelegate: class {
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
open class Human: Player {
|
||||
public final class Human: Player {
|
||||
|
||||
public init(color: Color) {
|
||||
super.init()
|
||||
@@ -94,3 +94,32 @@ open class Human: Player {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Human: Equatable {
|
||||
public static func == (lhs: Human, rhs: Human) -> Bool {
|
||||
return lhs.color == rhs.color
|
||||
}
|
||||
}
|
||||
|
||||
extension Human: DictionaryRepresentable {
|
||||
|
||||
struct Keys {
|
||||
static let color = "color"
|
||||
}
|
||||
|
||||
convenience init?(dictionary: [String: Any]) {
|
||||
|
||||
if let raw = dictionary[Keys.color] as? String, let color = Color(rawValue: raw) {
|
||||
self.init(color: color)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var dictionaryRepresentation: [String: Any] {
|
||||
|
||||
var dictionary = [String: Any]()
|
||||
dictionary[Keys.color] = color.rawValue
|
||||
return dictionary
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ public enum Color: String {
|
||||
|
||||
public struct Piece: Equatable {
|
||||
|
||||
static private var lastAssignedTag = 0
|
||||
|
||||
public enum PieceType: Int {
|
||||
case pawn
|
||||
case rook
|
||||
@@ -71,17 +69,8 @@ public struct Piece: Equatable {
|
||||
var value: Double {
|
||||
return type.value
|
||||
}
|
||||
|
||||
public init(type: PieceType, color: Color) {
|
||||
self.type = type
|
||||
self.color = color
|
||||
|
||||
// assign the next tag
|
||||
Piece.lastAssignedTag += 1
|
||||
self.tag = Piece.lastAssignedTag
|
||||
}
|
||||
|
||||
public init(type: PieceType, color: Color, tag: Int) {
|
||||
public init(type: PieceType, color: Color, tag: Int = 0) {
|
||||
self.type = type
|
||||
self.color = color
|
||||
self.tag = tag
|
||||
@@ -92,13 +81,94 @@ public struct Piece: Equatable {
|
||||
let piece = Piece(type: newType, color: color, tag: tag)
|
||||
return piece
|
||||
}
|
||||
|
||||
func isSameTypeAndColor(asPiece other: Piece) -> Bool {
|
||||
|
||||
if self.type == other.type && self.color == other.color {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func == (left: Piece, right: Piece) -> Bool {
|
||||
|
||||
if left.type == right.type && left.color == right.color {
|
||||
if left.type == right.type
|
||||
&& left.color == right.color
|
||||
&& left.tag == right.tag
|
||||
&& left .hasMoved == right.hasMoved
|
||||
&& left.canBeTakenByEnPassant == right.canBeTakenByEnPassant
|
||||
&& left.location == right.location {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
extension Piece: DictionaryRepresentable {
|
||||
|
||||
private struct Keys {
|
||||
static let type = "type"
|
||||
static let color = "color"
|
||||
static let tag = "tag"
|
||||
static let hasMoved = "hasMoved"
|
||||
static let canBeTakenByEnPassant = "canBeTakenByEnPassant"
|
||||
static let location = "location"
|
||||
}
|
||||
|
||||
init?(dictionary: [String: Any]) {
|
||||
|
||||
// Type
|
||||
if let raw = dictionary[Keys.type] as? Int, let type = PieceType(rawValue: raw) {
|
||||
self.type = type
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Color
|
||||
if let raw = dictionary[Keys.color] as? String, let color = Color(rawValue: raw) {
|
||||
self.color = color
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tag
|
||||
if let tag = dictionary[Keys.tag] as? Int {
|
||||
self.tag = tag
|
||||
}
|
||||
|
||||
// Has Moved
|
||||
if let hasMoved = dictionary[Keys.hasMoved] as? Bool {
|
||||
self.hasMoved = hasMoved
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Can be taken by en passent
|
||||
if let canBeTakenByEnPassent = dictionary[Keys.canBeTakenByEnPassant] as? Bool {
|
||||
self.canBeTakenByEnPassant = canBeTakenByEnPassent
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Location
|
||||
if let dict = dictionary[Keys.location] as? [String: Any], let location = BoardLocation(dictionary: dict) {
|
||||
self.location = location
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var dictionaryRepresentation: [String: Any] {
|
||||
|
||||
var dictionary = [String: Any]()
|
||||
dictionary[Keys.type] = type.rawValue
|
||||
dictionary[Keys.color] = color.rawValue
|
||||
if let tag = self.tag { dictionary[Keys.tag] = tag }
|
||||
dictionary[Keys.hasMoved] = hasMoved
|
||||
dictionary[Keys.canBeTakenByEnPassant] = canBeTakenByEnPassant
|
||||
dictionary[Keys.location] = location.dictionaryRepresentation
|
||||
return dictionary
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
6719898B1DFFE0D80053EA3D /* BoardRaterBoardDominance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6719898A1DFFE0D80053EA3D /* BoardRaterBoardDominance.swift */; };
|
||||
6719898F1DFFE7550053EA3D /* BoardRaterCenterDominance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6719898E1DFFE7550053EA3D /* BoardRaterCenterDominance.swift */; };
|
||||
676EF7C31E15A8A500E275B4 /* BoardRaterKingSurroundingPossession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676EF7C21E15A8A500E275B4 /* BoardRaterKingSurroundingPossession.swift */; };
|
||||
677BE817200A2D78004B27DB /* DictionaryRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 677BE816200A2D78004B27DB /* DictionaryRepresentable.swift */; };
|
||||
67A9C9E81DE64CD300510FB8 /* SwiftChess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 67A9C9DE1DE64CD200510FB8 /* SwiftChess.framework */; };
|
||||
67A9C9EF1DE64CD300510FB8 /* SwiftChess.h in Headers */ = {isa = PBXBuildFile; fileRef = 67A9C9E11DE64CD200510FB8 /* SwiftChess.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
67A9CA011DE64D2500510FB8 /* AIPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A9C9FA1DE64D2500510FB8 /* AIPlayer.swift */; };
|
||||
@@ -50,6 +51,7 @@
|
||||
6719898A1DFFE0D80053EA3D /* BoardRaterBoardDominance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterBoardDominance.swift; sourceTree = "<group>"; };
|
||||
6719898E1DFFE7550053EA3D /* BoardRaterCenterDominance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCenterDominance.swift; sourceTree = "<group>"; };
|
||||
676EF7C21E15A8A500E275B4 /* BoardRaterKingSurroundingPossession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterKingSurroundingPossession.swift; sourceTree = "<group>"; };
|
||||
677BE816200A2D78004B27DB /* DictionaryRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryRepresentable.swift; sourceTree = "<group>"; };
|
||||
67A9C9DE1DE64CD200510FB8 /* SwiftChess.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftChess.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
67A9C9E11DE64CD200510FB8 /* SwiftChess.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftChess.h; sourceTree = "<group>"; };
|
||||
67A9C9E21DE64CD200510FB8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
@@ -92,6 +94,14 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
677BE815200A2D54004B27DB /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
677BE816200A2D78004B27DB /* DictionaryRepresentable.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67A9C9D41DE64CD200510FB8 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -131,6 +141,7 @@
|
||||
67A9C9F81DE64D2500510FB8 /* Source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
677BE815200A2D54004B27DB /* Extensions */,
|
||||
67F9DB791E2438EC00C7EC5A /* ASCIIBoard.swift */,
|
||||
67FD86881E4105B80023335C /* BoardStride.swift */,
|
||||
67FD868A1E4105D40023335C /* BoardLocation.swift */,
|
||||
@@ -341,6 +352,7 @@
|
||||
67F779241E1C326D00885B89 /* BoardRaterCenterFourOccupation.swift in Sources */,
|
||||
67A9CA011DE64D2500510FB8 /* AIPlayer.swift in Sources */,
|
||||
6719898F1DFFE7550053EA3D /* BoardRaterCenterDominance.swift in Sources */,
|
||||
677BE817200A2D78004B27DB /* DictionaryRepresentable.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user