Compare commits
73 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fa3580d2ce | |||
| 77a9e7f9e4 | |||
| d9b8ebace4 | |||
| 2ce751ad69 | |||
| 9b21f36f94 | |||
| 52ee0ed99a | |||
| efb982c1a7 | |||
| e6c44034aa | |||
| 921f5c6899 | |||
| f315a27db1 | |||
| f700ac2ec9 | |||
| 632765e72e | |||
| 17325af502 | |||
| 6373f189cc | |||
| 8e4e478ea3 | |||
| 7ebf83e7f4 | |||
| 612b3c7938 | |||
| faf65a02fb | |||
| 0f3cd549f6 | |||
| ce3df6cdce | |||
| 9ffafa0ee1 | |||
| 6f80d184de | |||
| 42fd768958 | |||
| f8e53472bf | |||
| ac147b5ee8 | |||
| fdf1f73ce9 | |||
| 0371a5d064 | |||
| aa31427b5f | |||
| 2694a19834 | |||
| 46d9b051ab | |||
| fc5a5ed5ac | |||
| beed7797b4 | |||
| 5b6255f58f | |||
| e2782cc397 | |||
| 1c4e3c1973 | |||
| 8c138eb699 | |||
| 16c757ff1f | |||
| b8ed2b3156 | |||
| 6fdd41c305 | |||
| 275489be73 | |||
| 88dda592b9 | |||
| 69458e8a28 | |||
| ad5f9e9122 | |||
| 7311b9add1 | |||
| 8f5ae059b1 | |||
| cca6079e56 | |||
| 6d8bcf1211 | |||
| cc4b32dad6 | |||
| c50d4de8d7 | |||
| f75b7cbe9d | |||
| e7b92a6ceb | |||
| 216bbfe0dd | |||
| 455b6e8a8b | |||
| 7c4e85e855 | |||
| 73d3dbbd38 | |||
| 77925776b8 | |||
| 717de7b90c | |||
| 782269b3d5 | |||
| d04cffff36 | |||
| 2f2b6e2d39 | |||
| 17221a7f78 | |||
| 1f64711de9 | |||
| 8b92378030 | |||
| 50514237ff | |||
| 59eebff8ed | |||
| 2ab3ec8f98 | |||
| 3bf665e7d4 | |||
| 7a5c82b638 | |||
| 702ac1ce2c | |||
| 2c5c1e1494 | |||
| 30e274b05f | |||
| 55795bf00a | |||
| 2ee384172c |
+8
-13
@@ -1,14 +1,9 @@
|
||||
# references:
|
||||
# * http://www.objc.io/issue-6/travis-ci.html
|
||||
# * https://github.com/supermarin/xcpretty#usage
|
||||
language: swift
|
||||
osx_image: xcode10.2
|
||||
xcode_project: Example/Example.xcodeproj
|
||||
xcode_scheme: SwiftChessExample
|
||||
xcode_destination: platform=iOS Simulator,OS=12.1,name=iPhone X
|
||||
|
||||
osx_image: xcode7.3
|
||||
language: objective-c
|
||||
# cache: cocoapods
|
||||
# podfile: Example/Podfile
|
||||
# before_install:
|
||||
# - gem install cocoapods # Since Travis is not always on latest version
|
||||
# - pod install --project-directory=Example
|
||||
script:
|
||||
- set -o pipefail && xcodebuild test -workspace Example/SwiftChess.xcworkspace -scheme SwiftChess-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty
|
||||
- pod lib lint
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
@@ -0,0 +1,8 @@
|
||||
disabled_rules:
|
||||
- trailing_whitespace
|
||||
- cyclomatic_complexity
|
||||
- nesting
|
||||
- type_name
|
||||
- force_cast
|
||||
- identifier_name
|
||||
- unused_closure_parameter
|
||||
@@ -7,13 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
09A4C0291E013ECB000CFBF4 /* BoardRaterThreatenedPiecesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09A4C0281E013ECB000CFBF4 /* BoardRaterThreatenedPiecesTests.swift */; };
|
||||
09AE32551E03D71D00A149FE /* BoardRaterPawnProgressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09AE32541E03D71D00A149FE /* BoardRaterPawnProgressionTests.swift */; };
|
||||
671989891DFFE0410053EA3D /* BoardRaterCenterOwnershipTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671989881DFFE0410053EA3D /* BoardRaterCenterOwnershipTests.swift */; };
|
||||
6719898D1DFFE0F40053EA3D /* BoardRaterBoardDominanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6719898C1DFFE0F40053EA3D /* BoardRaterBoardDominanceTests.swift */; };
|
||||
671989911DFFE8650053EA3D /* BoardRaterCenterDominanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671989901DFFE8650053EA3D /* BoardRaterCenterDominanceTests.swift */; };
|
||||
676EF7C51E15AC1700E275B4 /* BoardRaterKingSurroundingPossession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 676EF7C41E15AC1700E275B4 /* BoardRaterKingSurroundingPossession.swift */; };
|
||||
67A3EB161E3A926C00F6F01B /* BoardScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67A3EB121E3A826800F6F01B /* BoardScenarios.swift */; };
|
||||
676C911C1E478A3A00985A4F /* SwiftChess.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 67A9CA0D1DE64D6500510FB8 /* SwiftChess.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
67A9CA341DE64DD600510FB8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; };
|
||||
67A9CA351DE64DD800510FB8 /* MenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* MenuViewController.swift */; };
|
||||
67A9CA361DE64DDA00510FB8 /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67AD33A61D7C67BF002730DF /* GameViewController.swift */; };
|
||||
@@ -22,26 +16,19 @@
|
||||
67A9CA391DE64E0900510FB8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; };
|
||||
67A9CA3A1DE64E0E00510FB8 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
|
||||
67A9CA3C1DE64E2B00510FB8 /* SwiftChess.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 67A9CA0D1DE64D6500510FB8 /* SwiftChess.framework */; };
|
||||
67A9CA3D1DE64E7100510FB8 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 607FACEA1AFB9204008FA782 /* Info.plist */; };
|
||||
67B73A9B1E15351900C19176 /* PromotionSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B73A9A1E15351900C19176 /* PromotionSelectionViewController.swift */; };
|
||||
67B73A9F1E154C1E00C19176 /* AIPlayerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B73A9E1E154C1E00C19176 /* AIPlayerTests.swift */; };
|
||||
67D54A5D1DE7682D00C12258 /* BoardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67D54A511DE7680E00C12258 /* BoardTests.swift */; };
|
||||
67D54A5E1DE7683000C12258 /* GameTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67D54A521DE7680E00C12258 /* GameTests.swift */; };
|
||||
67D54A5F1DE7683300C12258 /* PieceMovementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67D54A531DE7680E00C12258 /* PieceMovementTests.swift */; };
|
||||
67D54A601DE7683800C12258 /* PlayerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67D54A541DE7680E00C12258 /* PlayerTests.swift */; };
|
||||
67D54A611DE7683A00C12258 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67D54A551DE7680E00C12258 /* Tests.swift */; };
|
||||
67D54A641DE976A900C12258 /* BoardRaterCountPiecesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67D54A631DE976A900C12258 /* BoardRaterCountPiecesTests.swift */; };
|
||||
67D54A661DE986F700C12258 /* PieceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67D54A651DE986F700C12258 /* PieceTests.swift */; };
|
||||
67D54A681DE9A2DD00C12258 /* PieceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67D54A671DE9A2DD00C12258 /* PieceView.swift */; };
|
||||
67F779201E1B923B00885B89 /* AIConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67F7791F1E1B923B00885B89 /* AIConfigurationTests.swift */; };
|
||||
67F779261E1C32A400885B89 /* BoardRaterCenterFourOccupationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67F779251E1C32A400885B89 /* BoardRaterCenterFourOccupationTests.swift */; };
|
||||
67F9DB6E1E1AC8DC00C7EC5A /* BoardRaterCheckMateOpportunityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67F9DB6D1E1AC8DC00C7EC5A /* BoardRaterCheckMateOpportunityTests.swift */; };
|
||||
67F9DB751E1AD3BB00C7EC5A /* AIBehaviourTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67F9DB741E1AD3BB00C7EC5A /* AIBehaviourTests.swift */; };
|
||||
67FD868D1E41099B0023335C /* BoardLocationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67FD868C1E41099B0023335C /* BoardLocationTests.swift */; };
|
||||
67FD86911E4128F00023335C /* OpeningsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67FD86901E4128F00023335C /* OpeningsTests.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
676C911D1E478A3A00985A4F /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 67A9CA071DE64D6500510FB8 /* SwiftChess.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 67A9C9DD1DE64CD200510FB8;
|
||||
remoteInfo = SwiftChess;
|
||||
};
|
||||
67A9CA0C1DE64D6500510FB8 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 67A9CA071DE64D6500510FB8 /* SwiftChess.xcodeproj */;
|
||||
@@ -65,9 +52,21 @@
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
676C911F1E478A3A00985A4F /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
676C911C1E478A3A00985A4F /* SwiftChess.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
09A4C0281E013ECB000CFBF4 /* BoardRaterThreatenedPiecesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterThreatenedPiecesTests.swift; sourceTree = "<group>"; };
|
||||
09AE32541E03D71D00A149FE /* BoardRaterPawnProgressionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterPawnProgressionTests.swift; sourceTree = "<group>"; };
|
||||
607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
607FACD71AFB9204008FA782 /* MenuViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewController.swift; sourceTree = "<group>"; };
|
||||
@@ -75,32 +74,14 @@
|
||||
607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
|
||||
607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
671989881DFFE0410053EA3D /* BoardRaterCenterOwnershipTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCenterOwnershipTests.swift; sourceTree = "<group>"; };
|
||||
6719898C1DFFE0F40053EA3D /* BoardRaterBoardDominanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterBoardDominanceTests.swift; sourceTree = "<group>"; };
|
||||
671989901DFFE8650053EA3D /* BoardRaterCenterDominanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCenterDominanceTests.swift; sourceTree = "<group>"; };
|
||||
676EF7C41E15AC1700E275B4 /* BoardRaterKingSurroundingPossession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterKingSurroundingPossession.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; };
|
||||
67A9CA271DE64DAA00510FB8 /* SwiftChessExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftChessExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
67AD33A61D7C67BF002730DF /* GameViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = "<group>"; };
|
||||
67AD33A81D7C67DF002730DF /* BoardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardView.swift; sourceTree = "<group>"; };
|
||||
67B73A9A1E15351900C19176 /* PromotionSelectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PromotionSelectionViewController.swift; sourceTree = "<group>"; };
|
||||
67B73A9E1E154C1E00C19176 /* AIPlayerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AIPlayerTests.swift; sourceTree = "<group>"; };
|
||||
67D54A511DE7680E00C12258 /* BoardTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardTests.swift; sourceTree = "<group>"; };
|
||||
67D54A521DE7680E00C12258 /* GameTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameTests.swift; sourceTree = "<group>"; };
|
||||
67D54A531DE7680E00C12258 /* PieceMovementTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PieceMovementTests.swift; sourceTree = "<group>"; };
|
||||
67D54A541DE7680E00C12258 /* PlayerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerTests.swift; sourceTree = "<group>"; };
|
||||
67D54A551DE7680E00C12258 /* Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = "<group>"; };
|
||||
67D54A631DE976A900C12258 /* BoardRaterCountPiecesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCountPiecesTests.swift; sourceTree = "<group>"; };
|
||||
67D54A651DE986F700C12258 /* PieceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PieceTests.swift; sourceTree = "<group>"; };
|
||||
67D54A671DE9A2DD00C12258 /* PieceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PieceView.swift; sourceTree = "<group>"; };
|
||||
67F7791F1E1B923B00885B89 /* AIConfigurationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AIConfigurationTests.swift; sourceTree = "<group>"; };
|
||||
67F779251E1C32A400885B89 /* BoardRaterCenterFourOccupationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCenterFourOccupationTests.swift; sourceTree = "<group>"; };
|
||||
67F9DB6D1E1AC8DC00C7EC5A /* BoardRaterCheckMateOpportunityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCheckMateOpportunityTests.swift; sourceTree = "<group>"; };
|
||||
67F9DB741E1AD3BB00C7EC5A /* AIBehaviourTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AIBehaviourTests.swift; sourceTree = "<group>"; };
|
||||
67FD868C1E41099B0023335C /* BoardLocationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardLocationTests.swift; sourceTree = "<group>"; };
|
||||
67FD86901E4128F00023335C /* OpeningsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpeningsTests.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -176,17 +157,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
607FACE91AFB9204008FA782 /* Supporting Files */,
|
||||
67D54A651DE986F700C12258 /* PieceTests.swift */,
|
||||
67FD868C1E41099B0023335C /* BoardLocationTests.swift */,
|
||||
67D54A511DE7680E00C12258 /* BoardTests.swift */,
|
||||
67D54A521DE7680E00C12258 /* GameTests.swift */,
|
||||
67D54A531DE7680E00C12258 /* PieceMovementTests.swift */,
|
||||
67D54A541DE7680E00C12258 /* PlayerTests.swift */,
|
||||
67B73A9E1E154C1E00C19176 /* AIPlayerTests.swift */,
|
||||
67F7791F1E1B923B00885B89 /* AIConfigurationTests.swift */,
|
||||
67F9DB741E1AD3BB00C7EC5A /* AIBehaviourTests.swift */,
|
||||
67FD86901E4128F00023335C /* OpeningsTests.swift */,
|
||||
67D54A621DE9768200C12258 /* BoardRaters */,
|
||||
67D54A551DE7680E00C12258 /* Tests.swift */,
|
||||
);
|
||||
path = Tests;
|
||||
@@ -196,7 +166,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
607FACEA1AFB9204008FA782 /* Info.plist */,
|
||||
67A3EB121E3A826800F6F01B /* BoardScenarios.swift */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
@@ -210,22 +179,6 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67D54A621DE9768200C12258 /* BoardRaters */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
67D54A631DE976A900C12258 /* BoardRaterCountPiecesTests.swift */,
|
||||
671989881DFFE0410053EA3D /* BoardRaterCenterOwnershipTests.swift */,
|
||||
6719898C1DFFE0F40053EA3D /* BoardRaterBoardDominanceTests.swift */,
|
||||
671989901DFFE8650053EA3D /* BoardRaterCenterDominanceTests.swift */,
|
||||
09A4C0281E013ECB000CFBF4 /* BoardRaterThreatenedPiecesTests.swift */,
|
||||
09AE32541E03D71D00A149FE /* BoardRaterPawnProgressionTests.swift */,
|
||||
676EF7C41E15AC1700E275B4 /* BoardRaterKingSurroundingPossession.swift */,
|
||||
67F9DB6D1E1AC8DC00C7EC5A /* BoardRaterCheckMateOpportunityTests.swift */,
|
||||
67F779251E1C32A400885B89 /* BoardRaterCenterFourOccupationTests.swift */,
|
||||
);
|
||||
name = BoardRaters;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67D54A691DE9A3C500C12258 /* Game */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -247,10 +200,13 @@
|
||||
67A9CA101DE64DAA00510FB8 /* Sources */,
|
||||
67A9CA111DE64DAA00510FB8 /* Frameworks */,
|
||||
67A9CA121DE64DAA00510FB8 /* Resources */,
|
||||
676C911F1E478A3A00985A4F /* Embed Frameworks */,
|
||||
677F42131F9DCE4C00BBD071 /* Swift Lint */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
676C911E1E478A3A00985A4F /* PBXTargetDependency */,
|
||||
);
|
||||
name = SwiftChessExample;
|
||||
productName = SwiftChessExample;
|
||||
@@ -264,6 +220,7 @@
|
||||
67A9CA231DE64DAA00510FB8 /* Sources */,
|
||||
67A9CA241DE64DAA00510FB8 /* Frameworks */,
|
||||
67A9CA251DE64DAA00510FB8 /* Resources */,
|
||||
677F42111F9DCD9A00BBD071 /* Swift Lint */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -282,15 +239,18 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0800;
|
||||
LastUpgradeCheck = 0800;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = CocoaPods;
|
||||
TargetAttributes = {
|
||||
67A9CA131DE64DAA00510FB8 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
DevelopmentTeam = VAA3W4LPY2;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
67A9CA261DE64DAA00510FB8 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
TestTargetID = 67A9CA131DE64DAA00510FB8;
|
||||
};
|
||||
@@ -298,7 +258,7 @@
|
||||
};
|
||||
buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "Example" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
@@ -353,12 +313,42 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
67A9CA3D1DE64E7100510FB8 /* Info.plist in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
677F42111F9DCD9A00BBD071 /* Swift Lint */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Swift Lint";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
|
||||
};
|
||||
677F42131F9DCE4C00BBD071 /* Swift Lint */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Swift Lint";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
67A9CA101DE64DAA00510FB8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
@@ -377,33 +367,18 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
67D54A601DE7683800C12258 /* PlayerTests.swift in Sources */,
|
||||
67FD86911E4128F00023335C /* OpeningsTests.swift in Sources */,
|
||||
67D54A611DE7683A00C12258 /* Tests.swift in Sources */,
|
||||
676EF7C51E15AC1700E275B4 /* BoardRaterKingSurroundingPossession.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 */,
|
||||
67D54A5E1DE7683000C12258 /* GameTests.swift in Sources */,
|
||||
67D54A661DE986F700C12258 /* PieceTests.swift in Sources */,
|
||||
671989891DFFE0410053EA3D /* BoardRaterCenterOwnershipTests.swift in Sources */,
|
||||
67B73A9F1E154C1E00C19176 /* AIPlayerTests.swift in Sources */,
|
||||
67F779201E1B923B00885B89 /* AIConfigurationTests.swift in Sources */,
|
||||
67D54A641DE976A900C12258 /* BoardRaterCountPiecesTests.swift in Sources */,
|
||||
67A3EB161E3A926C00F6F01B /* BoardScenarios.swift in Sources */,
|
||||
09AE32551E03D71D00A149FE /* BoardRaterPawnProgressionTests.swift in Sources */,
|
||||
09A4C0291E013ECB000CFBF4 /* BoardRaterThreatenedPiecesTests.swift in Sources */,
|
||||
67D54A5F1DE7683300C12258 /* PieceMovementTests.swift in Sources */,
|
||||
67F779261E1C32A400885B89 /* BoardRaterCenterFourOccupationTests.swift in Sources */,
|
||||
67F9DB6E1E1AC8DC00C7EC5A /* BoardRaterCheckMateOpportunityTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
676C911E1E478A3A00985A4F /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = SwiftChess;
|
||||
targetProxy = 676C911D1E478A3A00985A4F /* PBXContainerItemProxy */;
|
||||
};
|
||||
67A9CA291DE64DAA00510FB8 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 67A9CA131DE64DAA00510FB8 /* SwiftChessExample */;
|
||||
@@ -435,18 +410,27 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -482,18 +466,27 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -521,18 +514,20 @@
|
||||
67A9CA2F1DE64DAA00510FB8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = VAA3W4LPY2;
|
||||
INFOPLIST_FILE = SwiftChess/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = SteveBarnegren.SwiftChessExample;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -540,16 +535,18 @@
|
||||
67A9CA301DE64DAA00510FB8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
DEVELOPMENT_TEAM = VAA3W4LPY2;
|
||||
INFOPLIST_FILE = SwiftChess/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = SteveBarnegren.SwiftChessExample;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
@@ -569,7 +566,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = SteveBarnegren.SwiftChessExampleTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftChessExample.app/SwiftChessExample";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -587,7 +584,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = SteveBarnegren.SwiftChessExampleTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftChessExample.app/SwiftChessExample";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>classNames</key>
|
||||
<dict>
|
||||
<key>PerformanceTests</key>
|
||||
<dict>
|
||||
<key>testBishopMoveValidationPerformance()</key>
|
||||
<dict>
|
||||
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
|
||||
<dict>
|
||||
<key>baselineAverage</key>
|
||||
<real>0</real>
|
||||
<key>baselineIntegrationDisplayName</key>
|
||||
<string>Local Baseline</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>testCanAnyPieceMovePerformance()</key>
|
||||
<dict>
|
||||
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
|
||||
<dict>
|
||||
<key>baselineAverage</key>
|
||||
<real>0.033</real>
|
||||
<key>baselineIntegrationDisplayName</key>
|
||||
<string>Local Baseline</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>testKingMoveValidationPerformance()</key>
|
||||
<dict>
|
||||
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
|
||||
<dict>
|
||||
<key>baselineAverage</key>
|
||||
<real>0.003</real>
|
||||
<key>baselineIntegrationDisplayName</key>
|
||||
<string>Local Baseline</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>testKnightMoveValidationPerformance()</key>
|
||||
<dict>
|
||||
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
|
||||
<dict>
|
||||
<key>baselineAverage</key>
|
||||
<real>0.001</real>
|
||||
<key>baselineIntegrationDisplayName</key>
|
||||
<string>Local Baseline</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>testPawnMoveValidationPerformance()</key>
|
||||
<dict>
|
||||
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
|
||||
<dict>
|
||||
<key>baselineAverage</key>
|
||||
<real>0.001</real>
|
||||
<key>baselineIntegrationDisplayName</key>
|
||||
<string>Local Baseline</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>testQueenMoveValidationPerformance()</key>
|
||||
<dict>
|
||||
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
|
||||
<dict>
|
||||
<key>baselineAverage</key>
|
||||
<real>0.003</real>
|
||||
<key>baselineIntegrationDisplayName</key>
|
||||
<string>Local Baseline</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>testRookMoveValidationPerformance()</key>
|
||||
<dict>
|
||||
<key>com.apple.XCTPerformanceMetric_WallClockTime</key>
|
||||
<dict>
|
||||
<key>baselineAverage</key>
|
||||
<real>0</real>
|
||||
<key>baselineIntegrationDisplayName</key>
|
||||
<string>Local Baseline</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
+31
@@ -4,6 +4,37 @@
|
||||
<dict>
|
||||
<key>runDestinationsByUUID</key>
|
||||
<dict>
|
||||
<key>3E643A92-069B-413B-86C0-1FF211DBD9A9</key>
|
||||
<dict>
|
||||
<key>localComputer</key>
|
||||
<dict>
|
||||
<key>busSpeedInMHz</key>
|
||||
<integer>100</integer>
|
||||
<key>cpuCount</key>
|
||||
<integer>1</integer>
|
||||
<key>cpuKind</key>
|
||||
<string>Intel Core m7</string>
|
||||
<key>cpuSpeedInMHz</key>
|
||||
<integer>1300</integer>
|
||||
<key>logicalCPUCoresPerPackage</key>
|
||||
<integer>4</integer>
|
||||
<key>modelCode</key>
|
||||
<string>MacBook9,1</string>
|
||||
<key>physicalCPUCoresPerPackage</key>
|
||||
<integer>2</integer>
|
||||
<key>platformIdentifier</key>
|
||||
<string>com.apple.platform.macosx</string>
|
||||
</dict>
|
||||
<key>targetArchitecture</key>
|
||||
<string>i386</string>
|
||||
<key>targetDevice</key>
|
||||
<dict>
|
||||
<key>modelCode</key>
|
||||
<string>iPhone5,1</string>
|
||||
<key>platformIdentifier</key>
|
||||
<string>com.apple.platform.iphonesimulator</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>D188478B-4F41-448E-8BB9-06B1C7A6FB8B</key>
|
||||
<dict>
|
||||
<key>localComputer</key>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "67A9CA131DE64DAA00510FB8"
|
||||
BuildableName = "SwiftChessExample.app"
|
||||
BlueprintName = "SwiftChessExample"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "67A9CA261DE64DAA00510FB8"
|
||||
BuildableName = "SwiftChessExampleTests.xctest"
|
||||
BlueprintName = "SwiftChessExampleTests"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "67A9C9E61DE64CD300510FB8"
|
||||
BuildableName = "SwiftChessTests.xctest"
|
||||
BlueprintName = "SwiftChessTests"
|
||||
ReferencedContainer = "container:../SwiftChess/SwiftChess.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "67A9CA131DE64DAA00510FB8"
|
||||
BuildableName = "SwiftChessExample.app"
|
||||
BlueprintName = "SwiftChessExample"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "67A9CA131DE64DAA00510FB8"
|
||||
BuildableName = "SwiftChessExample.app"
|
||||
BlueprintName = "SwiftChessExample"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "67A9CA131DE64DAA00510FB8"
|
||||
BuildableName = "SwiftChessExample.app"
|
||||
BlueprintName = "SwiftChessExample"
|
||||
ReferencedContainer = "container:Example.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,24 +0,0 @@
|
||||
use_frameworks!
|
||||
|
||||
target 'SwiftChess_Example' do
|
||||
pod 'SwiftChess', :path => '../'
|
||||
|
||||
# target 'SwiftChess_Tests' do
|
||||
# inherit! :search_paths
|
||||
|
||||
|
||||
#end
|
||||
end
|
||||
|
||||
target 'SwiftChess_Tests' do
|
||||
pod 'SwiftChess', :path => '../'
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['SWIFT_VERSION'] = '3.0'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
PODS:
|
||||
- SwiftChess (0.1.0)
|
||||
|
||||
DEPENDENCIES:
|
||||
- SwiftChess (from `../`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
SwiftChess:
|
||||
:path: ../
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
SwiftChess: 7ec2077f755647df70261575a0546c0486930cf3
|
||||
|
||||
PODFILE CHECKSUM: 410ba32ae65123335cc9534558e1f605ee0bf56c
|
||||
|
||||
COCOAPODS: 1.0.1
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"name": "SwiftChess",
|
||||
"version": "0.1.0",
|
||||
"summary": "A short description of SwiftChess.",
|
||||
"description": "TODO: Add long description of the pod here.",
|
||||
"homepage": "https://github.com/<GITHUB_USERNAME>/SwiftChess",
|
||||
"license": {
|
||||
"type": "MIT",
|
||||
"file": "LICENSE"
|
||||
},
|
||||
"authors": {
|
||||
"Steve Barnegren": "steve.barnegren@gmail.com"
|
||||
},
|
||||
"source": {
|
||||
"git": "https://github.com/<GITHUB_USERNAME>/SwiftChess.git",
|
||||
"tag": "0.1.0"
|
||||
},
|
||||
"platforms": {
|
||||
"ios": "8.0"
|
||||
},
|
||||
"source_files": "SwiftChess/Classes/**/*"
|
||||
}
|
||||
Generated
-16
@@ -1,16 +0,0 @@
|
||||
PODS:
|
||||
- SwiftChess (0.1.0)
|
||||
|
||||
DEPENDENCIES:
|
||||
- SwiftChess (from `../`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
SwiftChess:
|
||||
:path: ../
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
SwiftChess: 7ec2077f755647df70261575a0546c0486930cf3
|
||||
|
||||
PODFILE CHECKSUM: 410ba32ae65123335cc9534558e1f605ee0bf56c
|
||||
|
||||
COCOAPODS: 1.0.1
|
||||
-1737
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
# Acknowledgements
|
||||
This application makes use of the following third party libraries:
|
||||
|
||||
## SwiftChess
|
||||
|
||||
Copyright (c) 2016 Steve Barnegren <steve.barnegren@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Generated by CocoaPods - https://cocoapods.org
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreferenceSpecifiers</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>This application makes use of the following third party libraries:</string>
|
||||
<key>Title</key>
|
||||
<string>Acknowledgements</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2016 Steve Barnegren <steve.barnegren@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
</string>
|
||||
<key>Title</key>
|
||||
<string>SwiftChess</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Generated by CocoaPods - https://cocoapods.org</string>
|
||||
<key>Title</key>
|
||||
<string></string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>StringsTable</key>
|
||||
<string>Acknowledgements</string>
|
||||
<key>Title</key>
|
||||
<string>Acknowledgements</string>
|
||||
</dict>
|
||||
</plist>
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
@interface PodsDummy_Pods_SwiftChess_Example : NSObject
|
||||
@end
|
||||
@implementation PodsDummy_Pods_SwiftChess_Example
|
||||
@end
|
||||
Generated
-91
@@ -1,91 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
|
||||
install_framework()
|
||||
{
|
||||
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
|
||||
local source="${BUILT_PRODUCTS_DIR}/$1"
|
||||
elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
|
||||
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
|
||||
elif [ -r "$1" ]; then
|
||||
local source="$1"
|
||||
fi
|
||||
|
||||
local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
if [ -L "${source}" ]; then
|
||||
echo "Symlinked..."
|
||||
source="$(readlink "${source}")"
|
||||
fi
|
||||
|
||||
# use filter instead of exclude so missing patterns dont' throw errors
|
||||
echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
|
||||
rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
|
||||
|
||||
local basename
|
||||
basename="$(basename -s .framework "$1")"
|
||||
binary="${destination}/${basename}.framework/${basename}"
|
||||
if ! [ -r "$binary" ]; then
|
||||
binary="${destination}/${basename}"
|
||||
fi
|
||||
|
||||
# Strip invalid architectures so "fat" simulator / device frameworks work on device
|
||||
if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
|
||||
strip_invalid_archs "$binary"
|
||||
fi
|
||||
|
||||
# Resign the code if required by the build settings to avoid unstable apps
|
||||
code_sign_if_enabled "${destination}/$(basename "$1")"
|
||||
|
||||
# Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
|
||||
if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
|
||||
local swift_runtime_libs
|
||||
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
|
||||
for lib in $swift_runtime_libs; do
|
||||
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
|
||||
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
|
||||
code_sign_if_enabled "${destination}/${lib}"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Signs a framework with the provided identity
|
||||
code_sign_if_enabled() {
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
# Use the current code_sign_identitiy
|
||||
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
||||
echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
|
||||
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# Strip invalid architectures
|
||||
strip_invalid_archs() {
|
||||
binary="$1"
|
||||
# Get architectures for current file
|
||||
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
|
||||
stripped=""
|
||||
for arch in $archs; do
|
||||
if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
|
||||
# Strip non-valid architectures in-place
|
||||
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
|
||||
stripped="$stripped $arch"
|
||||
fi
|
||||
done
|
||||
if [[ "$stripped" ]]; then
|
||||
echo "Stripped $binary of architectures:$stripped"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
if [[ "$CONFIGURATION" == "Debug" ]]; then
|
||||
install_framework "$BUILT_PRODUCTS_DIR/SwiftChess/SwiftChess.framework"
|
||||
fi
|
||||
if [[ "$CONFIGURATION" == "Release" ]]; then
|
||||
install_framework "$BUILT_PRODUCTS_DIR/SwiftChess/SwiftChess.framework"
|
||||
fi
|
||||
Generated
-102
@@ -1,102 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
|
||||
RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
|
||||
> "$RESOURCES_TO_COPY"
|
||||
|
||||
XCASSET_FILES=()
|
||||
|
||||
case "${TARGETED_DEVICE_FAMILY}" in
|
||||
1,2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
|
||||
;;
|
||||
1)
|
||||
TARGET_DEVICE_ARGS="--target-device iphone"
|
||||
;;
|
||||
2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad"
|
||||
;;
|
||||
*)
|
||||
TARGET_DEVICE_ARGS="--target-device mac"
|
||||
;;
|
||||
esac
|
||||
|
||||
realpath() {
|
||||
DIRECTORY="$(cd "${1%/*}" && pwd)"
|
||||
FILENAME="${1##*/}"
|
||||
echo "$DIRECTORY/$FILENAME"
|
||||
}
|
||||
|
||||
install_resource()
|
||||
{
|
||||
if [[ "$1" = /* ]] ; then
|
||||
RESOURCE_PATH="$1"
|
||||
else
|
||||
RESOURCE_PATH="${PODS_ROOT}/$1"
|
||||
fi
|
||||
if [[ ! -e "$RESOURCE_PATH" ]] ; then
|
||||
cat << EOM
|
||||
error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
|
||||
EOM
|
||||
exit 1
|
||||
fi
|
||||
case $RESOURCE_PATH in
|
||||
*.storyboard)
|
||||
echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
|
||||
ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
|
||||
;;
|
||||
*.xib)
|
||||
echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
|
||||
ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
|
||||
;;
|
||||
*.framework)
|
||||
echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
;;
|
||||
*.xcdatamodel)
|
||||
echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
|
||||
xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
|
||||
;;
|
||||
*.xcdatamodeld)
|
||||
echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
|
||||
xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
|
||||
;;
|
||||
*.xcmappingmodel)
|
||||
echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
|
||||
xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
|
||||
;;
|
||||
*.xcassets)
|
||||
ABSOLUTE_XCASSET_FILE=$(realpath "$RESOURCE_PATH")
|
||||
XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
|
||||
;;
|
||||
*)
|
||||
echo "$RESOURCE_PATH"
|
||||
echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
|
||||
mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
fi
|
||||
rm -f "$RESOURCES_TO_COPY"
|
||||
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
|
||||
then
|
||||
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
|
||||
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
|
||||
while read line; do
|
||||
if [[ $line != "`realpath $PODS_ROOT`*" ]]; then
|
||||
XCASSET_FILES+=("$line")
|
||||
fi
|
||||
done <<<"$OTHER_XCASSETS"
|
||||
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
fi
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
FOUNDATION_EXPORT double Pods_SwiftChess_ExampleVersionNumber;
|
||||
FOUNDATION_EXPORT const unsigned char Pods_SwiftChess_ExampleVersionString[];
|
||||
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
framework module Pods_SwiftChess_Example {
|
||||
umbrella header "Pods-SwiftChess_Example-umbrella.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
# Acknowledgements
|
||||
This application makes use of the following third party libraries:
|
||||
|
||||
## SwiftChess
|
||||
|
||||
Copyright (c) 2016 Steve Barnegren <steve.barnegren@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Generated by CocoaPods - https://cocoapods.org
|
||||
Example/Pods/Target Support Files/Pods-SwiftChess_Tests/Pods-SwiftChess_Tests-acknowledgements.plist
Generated
-56
@@ -1,56 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreferenceSpecifiers</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>This application makes use of the following third party libraries:</string>
|
||||
<key>Title</key>
|
||||
<string>Acknowledgements</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2016 Steve Barnegren <steve.barnegren@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
</string>
|
||||
<key>Title</key>
|
||||
<string>SwiftChess</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Generated by CocoaPods - https://cocoapods.org</string>
|
||||
<key>Title</key>
|
||||
<string></string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>StringsTable</key>
|
||||
<string>Acknowledgements</string>
|
||||
<key>Title</key>
|
||||
<string>Acknowledgements</string>
|
||||
</dict>
|
||||
</plist>
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
@interface PodsDummy_Pods_SwiftChess_Tests : NSObject
|
||||
@end
|
||||
@implementation PodsDummy_Pods_SwiftChess_Tests
|
||||
@end
|
||||
Generated
-91
@@ -1,91 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
|
||||
install_framework()
|
||||
{
|
||||
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
|
||||
local source="${BUILT_PRODUCTS_DIR}/$1"
|
||||
elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
|
||||
local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
|
||||
elif [ -r "$1" ]; then
|
||||
local source="$1"
|
||||
fi
|
||||
|
||||
local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
if [ -L "${source}" ]; then
|
||||
echo "Symlinked..."
|
||||
source="$(readlink "${source}")"
|
||||
fi
|
||||
|
||||
# use filter instead of exclude so missing patterns dont' throw errors
|
||||
echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
|
||||
rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
|
||||
|
||||
local basename
|
||||
basename="$(basename -s .framework "$1")"
|
||||
binary="${destination}/${basename}.framework/${basename}"
|
||||
if ! [ -r "$binary" ]; then
|
||||
binary="${destination}/${basename}"
|
||||
fi
|
||||
|
||||
# Strip invalid architectures so "fat" simulator / device frameworks work on device
|
||||
if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
|
||||
strip_invalid_archs "$binary"
|
||||
fi
|
||||
|
||||
# Resign the code if required by the build settings to avoid unstable apps
|
||||
code_sign_if_enabled "${destination}/$(basename "$1")"
|
||||
|
||||
# Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
|
||||
if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
|
||||
local swift_runtime_libs
|
||||
swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
|
||||
for lib in $swift_runtime_libs; do
|
||||
echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
|
||||
rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
|
||||
code_sign_if_enabled "${destination}/${lib}"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Signs a framework with the provided identity
|
||||
code_sign_if_enabled() {
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
# Use the current code_sign_identitiy
|
||||
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
||||
echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
|
||||
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# Strip invalid architectures
|
||||
strip_invalid_archs() {
|
||||
binary="$1"
|
||||
# Get architectures for current file
|
||||
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
|
||||
stripped=""
|
||||
for arch in $archs; do
|
||||
if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
|
||||
# Strip non-valid architectures in-place
|
||||
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
|
||||
stripped="$stripped $arch"
|
||||
fi
|
||||
done
|
||||
if [[ "$stripped" ]]; then
|
||||
echo "Stripped $binary of architectures:$stripped"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
if [[ "$CONFIGURATION" == "Debug" ]]; then
|
||||
install_framework "$BUILT_PRODUCTS_DIR/SwiftChess/SwiftChess.framework"
|
||||
fi
|
||||
if [[ "$CONFIGURATION" == "Release" ]]; then
|
||||
install_framework "$BUILT_PRODUCTS_DIR/SwiftChess/SwiftChess.framework"
|
||||
fi
|
||||
Generated
-102
@@ -1,102 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
|
||||
RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
|
||||
> "$RESOURCES_TO_COPY"
|
||||
|
||||
XCASSET_FILES=()
|
||||
|
||||
case "${TARGETED_DEVICE_FAMILY}" in
|
||||
1,2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
|
||||
;;
|
||||
1)
|
||||
TARGET_DEVICE_ARGS="--target-device iphone"
|
||||
;;
|
||||
2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad"
|
||||
;;
|
||||
*)
|
||||
TARGET_DEVICE_ARGS="--target-device mac"
|
||||
;;
|
||||
esac
|
||||
|
||||
realpath() {
|
||||
DIRECTORY="$(cd "${1%/*}" && pwd)"
|
||||
FILENAME="${1##*/}"
|
||||
echo "$DIRECTORY/$FILENAME"
|
||||
}
|
||||
|
||||
install_resource()
|
||||
{
|
||||
if [[ "$1" = /* ]] ; then
|
||||
RESOURCE_PATH="$1"
|
||||
else
|
||||
RESOURCE_PATH="${PODS_ROOT}/$1"
|
||||
fi
|
||||
if [[ ! -e "$RESOURCE_PATH" ]] ; then
|
||||
cat << EOM
|
||||
error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
|
||||
EOM
|
||||
exit 1
|
||||
fi
|
||||
case $RESOURCE_PATH in
|
||||
*.storyboard)
|
||||
echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
|
||||
ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
|
||||
;;
|
||||
*.xib)
|
||||
echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
|
||||
ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
|
||||
;;
|
||||
*.framework)
|
||||
echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
;;
|
||||
*.xcdatamodel)
|
||||
echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
|
||||
xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
|
||||
;;
|
||||
*.xcdatamodeld)
|
||||
echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
|
||||
xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
|
||||
;;
|
||||
*.xcmappingmodel)
|
||||
echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
|
||||
xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
|
||||
;;
|
||||
*.xcassets)
|
||||
ABSOLUTE_XCASSET_FILE=$(realpath "$RESOURCE_PATH")
|
||||
XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
|
||||
;;
|
||||
*)
|
||||
echo "$RESOURCE_PATH"
|
||||
echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
|
||||
mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
fi
|
||||
rm -f "$RESOURCES_TO_COPY"
|
||||
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
|
||||
then
|
||||
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
|
||||
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
|
||||
while read line; do
|
||||
if [[ $line != "`realpath $PODS_ROOT`*" ]]; then
|
||||
XCASSET_FILES+=("$line")
|
||||
fi
|
||||
done <<<"$OTHER_XCASSETS"
|
||||
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
fi
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
FOUNDATION_EXPORT double Pods_SwiftChess_TestsVersionNumber;
|
||||
FOUNDATION_EXPORT const unsigned char Pods_SwiftChess_TestsVersionString[];
|
||||
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
framework module Pods_SwiftChess_Tests {
|
||||
umbrella header "Pods-SwiftChess_Tests-umbrella.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,5 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
@interface PodsDummy_SwiftChess : NSObject
|
||||
@end
|
||||
@implementation PodsDummy_SwiftChess
|
||||
@end
|
||||
@@ -1,4 +0,0 @@
|
||||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
FOUNDATION_EXPORT double SwiftChessVersionNumber;
|
||||
FOUNDATION_EXPORT const unsigned char SwiftChessVersionString[];
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
framework module SwiftChess {
|
||||
umbrella header "SwiftChess-umbrella.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/SwiftChess
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
SKIP_INSTALL = YES
|
||||
@@ -13,34 +13,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
func application(_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1212" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="o9i-0S-2Up">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="o9i-0S-2Up">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
|
||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
@@ -39,20 +42,24 @@
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KRf-s7-H9a">
|
||||
<rect key="frame" x="133.5" y="264.5" width="108" height="138"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fGu-y2-Qxm">
|
||||
<rect key="frame" x="0.0" y="92" width="108" height="30"/>
|
||||
<state key="normal" title="AI vs AI"/>
|
||||
<connections>
|
||||
<action selector="AIvsAIButtonPressed:" destination="vXZ-lx-hvc" eventType="touchUpInside" id="mrX-sU-WvD"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kEX-Ea-5Xq">
|
||||
<rect key="frame" x="0.0" y="46" width="108" height="30"/>
|
||||
<state key="normal" title="Player vs Player"/>
|
||||
<connections>
|
||||
<action selector="playerVsPlayerButtonPressed:" destination="vXZ-lx-hvc" eventType="touchUpInside" id="xIZ-0U-CNW"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="gcM-Gf-hHc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="108" height="30"/>
|
||||
<state key="normal" title="Player vs AI"/>
|
||||
<connections>
|
||||
<action selector="playerVsAIButtonPressed:" destination="vXZ-lx-hvc" eventType="touchUpInside" id="QvL-y5-tdf"/>
|
||||
@@ -99,41 +106,50 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NnZ-Ew-a2B" customClass="BoardView" customModule="SwiftChessExample" customModuleProvider="target">
|
||||
<rect key="frame" x="8" y="154" width="359" height="359"/>
|
||||
<color key="backgroundColor" red="0.46274509800000002" green="0.71372549019999998" blue="0.97254901959999995" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" secondItem="NnZ-Ew-a2B" secondAttribute="height" multiplier="1:1" id="GNF-YV-5Vh"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ZZ0-mR-VXd">
|
||||
<rect key="frame" x="8" y="116" width="44" height="30"/>
|
||||
<state key="normal" title="Castle"/>
|
||||
<connections>
|
||||
<action selector="blackKingSideCastleButtonPressedWithSender:" destination="M5V-oM-g1K" eventType="touchUpInside" id="rLk-f9-Sot"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="eZD-P8-Hr3">
|
||||
<rect key="frame" x="323" y="116" width="44" height="30"/>
|
||||
<state key="normal" title="Castle"/>
|
||||
<connections>
|
||||
<action selector="blackQueenSideCastleButtonPressedWithSender:" destination="M5V-oM-g1K" eventType="touchUpInside" id="04c-Bn-Bkt"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Yxk-YT-5FA">
|
||||
<rect key="frame" x="8" y="521" width="44" height="30"/>
|
||||
<state key="normal" title="Castle"/>
|
||||
<connections>
|
||||
<action selector="whiteQueenSideCastleButtonPressedWithSender:" destination="M5V-oM-g1K" eventType="touchUpInside" id="3el-xi-NUE"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FwI-ZC-g1Z">
|
||||
<rect key="frame" x="323" y="521" width="44" height="30"/>
|
||||
<state key="normal" title="Castle"/>
|
||||
<connections>
|
||||
<action selector="whiteKingSideCastleButtonPressedWithSender:" destination="M5V-oM-g1K" eventType="touchUpInside" id="geO-9J-0qc"/>
|
||||
</connections>
|
||||
</button>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="JEV-Ul-qRP">
|
||||
<rect key="frame" x="177" y="121" width="20" height="20"/>
|
||||
</activityIndicatorView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="NnZ-Ew-a2B" firstAttribute="top" secondItem="eZD-P8-Hr3" secondAttribute="bottom" constant="8" id="8gI-BZ-sfM"/>
|
||||
<constraint firstItem="Yxk-YT-5FA" firstAttribute="leading" secondItem="NnZ-Ew-a2B" secondAttribute="leading" id="BxL-mm-tSn"/>
|
||||
<constraint firstItem="NnZ-Ew-a2B" firstAttribute="centerY" secondItem="0i2-vi-BZ9" secondAttribute="centerY" id="DzP-fd-RxD"/>
|
||||
<constraint firstItem="JEV-Ul-qRP" firstAttribute="centerY" secondItem="ZZ0-mR-VXd" secondAttribute="centerY" id="LLa-vl-Dcs"/>
|
||||
<constraint firstItem="Yxk-YT-5FA" firstAttribute="top" secondItem="NnZ-Ew-a2B" secondAttribute="bottom" constant="8" id="N2S-Kg-2L0"/>
|
||||
<constraint firstItem="ZZ0-mR-VXd" firstAttribute="leading" secondItem="NnZ-Ew-a2B" secondAttribute="leading" id="NAg-kl-feP"/>
|
||||
<constraint firstItem="eZD-P8-Hr3" firstAttribute="trailing" secondItem="NnZ-Ew-a2B" secondAttribute="trailing" id="NYh-P9-I1j"/>
|
||||
@@ -141,10 +157,12 @@
|
||||
<constraint firstItem="NnZ-Ew-a2B" firstAttribute="top" secondItem="ZZ0-mR-VXd" secondAttribute="bottom" constant="8" id="TgY-3v-zy1"/>
|
||||
<constraint firstItem="NnZ-Ew-a2B" firstAttribute="leading" secondItem="0i2-vi-BZ9" secondAttribute="leading" constant="8" id="Ve9-Wz-Mmx"/>
|
||||
<constraint firstItem="FwI-ZC-g1Z" firstAttribute="top" secondItem="NnZ-Ew-a2B" secondAttribute="bottom" constant="8" id="YnW-Zf-aL2"/>
|
||||
<constraint firstItem="JEV-Ul-qRP" firstAttribute="centerX" secondItem="0i2-vi-BZ9" secondAttribute="centerX" id="dOc-ve-oSq"/>
|
||||
<constraint firstItem="FwI-ZC-g1Z" firstAttribute="trailing" secondItem="NnZ-Ew-a2B" secondAttribute="trailing" id="rx5-mS-bp0"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="JEV-Ul-qRP" id="93U-eY-Z18"/>
|
||||
<outlet property="blackKingSideCastleButton" destination="ZZ0-mR-VXd" id="jhh-iW-CTM"/>
|
||||
<outlet property="blackQueenSideCastleButton" destination="eZD-P8-Hr3" id="yY5-WP-Yvk"/>
|
||||
<outlet property="boardView" destination="NnZ-Ew-a2B" id="qeo-BV-9YO"/>
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
protocol BoardViewDelegate {
|
||||
protocol BoardViewDelegate: class {
|
||||
func touchedSquareAtIndex(_ boardView: BoardView, index: Int)
|
||||
}
|
||||
|
||||
class BoardView: UIView {
|
||||
|
||||
// MARK: - Properties
|
||||
internal var delegate: BoardViewDelegate?
|
||||
internal weak var delegate: BoardViewDelegate?
|
||||
|
||||
// MARK: - init
|
||||
|
||||
@@ -29,7 +29,7 @@ class BoardView: UIView {
|
||||
self.setupBoardView()
|
||||
}
|
||||
|
||||
func setupBoardView(){
|
||||
func setupBoardView() {
|
||||
layer.borderColor = UIColor.black.cgColor
|
||||
layer.borderWidth = 1
|
||||
}
|
||||
@@ -94,7 +94,7 @@ class BoardView: UIView {
|
||||
|
||||
}
|
||||
|
||||
func boardIndexForLocation(_ location: CGPoint) -> Int{
|
||||
func boardIndexForLocation(_ location: CGPoint) -> Int {
|
||||
|
||||
// Flip y (0 at bottom)
|
||||
var location = location
|
||||
@@ -110,5 +110,4 @@ class BoardView: UIView {
|
||||
return gridX + (gridY*8)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
//swiftlint:disable file_length
|
||||
|
||||
import UIKit
|
||||
import SwiftChess
|
||||
|
||||
@@ -16,11 +18,12 @@ class GameViewController: UIViewController {
|
||||
@IBOutlet weak var whiteQueenSideCastleButton: UIButton!
|
||||
@IBOutlet weak var blackKingSideCastleButton: UIButton!
|
||||
@IBOutlet weak var blackQueenSideCastleButton: UIButton!
|
||||
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
|
||||
|
||||
var pieceViews = [PieceView]()
|
||||
var game: Game!
|
||||
var selectedIndex: Int? {
|
||||
didSet{
|
||||
didSet {
|
||||
updatePieceViewSelectedStates()
|
||||
}
|
||||
}
|
||||
@@ -31,12 +34,13 @@ class GameViewController: UIViewController {
|
||||
|
||||
// MARK: - Creation
|
||||
|
||||
class func gameViewController(game: Game) -> GameViewController{
|
||||
class func gameViewController(game: Game) -> GameViewController {
|
||||
|
||||
let storyboard = UIStoryboard(name: "Main", bundle: nil)
|
||||
let className = "GameViewController"
|
||||
let gameViewController: GameViewController = storyboard.instantiateViewController(withIdentifier: className) as! GameViewController
|
||||
gameViewController.game = game;
|
||||
let gameViewController: GameViewController =
|
||||
storyboard.instantiateViewController(withIdentifier: className) as! GameViewController
|
||||
gameViewController.game = game
|
||||
return gameViewController
|
||||
}
|
||||
|
||||
@@ -60,6 +64,9 @@ class GameViewController: UIViewController {
|
||||
addPieceView(at: location.x, y: location.y, piece: piece)
|
||||
}
|
||||
|
||||
// Activity Indicator
|
||||
activityIndicator.hidesWhenStopped = true
|
||||
|
||||
// Update castle buttons visibility
|
||||
updateCastleButtonsVisibility()
|
||||
|
||||
@@ -71,7 +78,7 @@ class GameViewController: UIViewController {
|
||||
// Take go if the first player is an AI player
|
||||
if !self.hasMadeInitialAppearance {
|
||||
if let player = game.currentPlayer as? AIPlayer {
|
||||
player.makeMove()
|
||||
player.makeMoveAsync()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +103,7 @@ class GameViewController: UIViewController {
|
||||
|
||||
func removePieceView(pieceView: PieceView) {
|
||||
|
||||
if let index = pieceViews.index(of: pieceView) {
|
||||
if let index = pieceViews.firstIndex(of: pieceView) {
|
||||
pieceViews.remove(at: index)
|
||||
}
|
||||
|
||||
@@ -113,15 +120,7 @@ class GameViewController: UIViewController {
|
||||
}
|
||||
|
||||
func pieceViewWithTag(_ tag: Int) -> PieceView? {
|
||||
|
||||
for pieceView in pieceViews {
|
||||
|
||||
if pieceView.piece.tag == tag {
|
||||
return pieceView
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
return pieceViews.first { $0.piece.tag == tag }
|
||||
}
|
||||
|
||||
// MARK: - Layout
|
||||
@@ -176,39 +175,35 @@ class GameViewController: UIViewController {
|
||||
let player = game.currentPlayer
|
||||
|
||||
var isHuman = true
|
||||
if let _ = player as? AIPlayer {
|
||||
if player is AIPlayer {
|
||||
isHuman = false
|
||||
}
|
||||
|
||||
// White king side button
|
||||
if isHuman && player?.color == .white && game.board.canColorCastle(color: .white, side: .kingSide){
|
||||
if isHuman && player?.color == .white && game.board.canColorCastle(color: .white, side: .kingSide) {
|
||||
whiteKingSideCastleButton.isHidden = false
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
whiteKingSideCastleButton.isHidden = true
|
||||
}
|
||||
|
||||
// White queen side button
|
||||
if isHuman && player?.color == .white && game.board.canColorCastle(color: .white, side: .queenSide){
|
||||
if isHuman && player?.color == .white && game.board.canColorCastle(color: .white, side: .queenSide) {
|
||||
whiteQueenSideCastleButton.isHidden = false
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
whiteQueenSideCastleButton.isHidden = true
|
||||
}
|
||||
|
||||
// Black king side button
|
||||
if isHuman && player?.color == .black && game.board.canColorCastle(color: .black, side: .kingSide){
|
||||
if isHuman && player?.color == .black && game.board.canColorCastle(color: .black, side: .kingSide) {
|
||||
blackKingSideCastleButton.isHidden = false
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
blackKingSideCastleButton.isHidden = true
|
||||
}
|
||||
|
||||
// Black queen side button
|
||||
if isHuman && player?.color == .black && game.board.canColorCastle(color: .black, side: .queenSide){
|
||||
if isHuman && player?.color == .black && game.board.canColorCastle(color: .black, side: .queenSide) {
|
||||
blackQueenSideCastleButton.isHidden = false
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
blackQueenSideCastleButton.isHidden = true
|
||||
}
|
||||
}
|
||||
@@ -216,7 +211,7 @@ class GameViewController: UIViewController {
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction func whiteKingSideCastleButtonPressed(sender: UIButton) {
|
||||
print("White king side castle button pressed");
|
||||
print("White king side castle button pressed")
|
||||
|
||||
if let player = game.currentPlayer as? Human {
|
||||
player.performCastleMove(side: .kingSide)
|
||||
@@ -224,7 +219,7 @@ class GameViewController: UIViewController {
|
||||
}
|
||||
|
||||
@IBAction func whiteQueenSideCastleButtonPressed(sender: UIButton) {
|
||||
print("White queen side castle button pressed");
|
||||
print("White queen side castle button pressed")
|
||||
|
||||
if let player = game.currentPlayer as? Human {
|
||||
player.performCastleMove(side: .queenSide)
|
||||
@@ -232,7 +227,7 @@ class GameViewController: UIViewController {
|
||||
}
|
||||
|
||||
@IBAction func blackKingSideCastleButtonPressed(sender: UIButton) {
|
||||
print("Black king side castle button pressed");
|
||||
print("Black king side castle button pressed")
|
||||
|
||||
if let player = game.currentPlayer as? Human {
|
||||
player.performCastleMove(side: .kingSide)
|
||||
@@ -240,7 +235,7 @@ class GameViewController: UIViewController {
|
||||
}
|
||||
|
||||
@IBAction func blackQueenSideCastleButtonPressed(sender: UIButton) {
|
||||
print("Black queen side castle button pressed");
|
||||
print("Black queen side castle button pressed")
|
||||
|
||||
if let player = game.currentPlayer as? Human {
|
||||
player.performCastleMove(side: .queenSide)
|
||||
@@ -258,7 +253,7 @@ extension GameViewController: BoardViewDelegate {
|
||||
|
||||
// Get the player (must be human)
|
||||
guard let player = game.currentPlayer as? Human else {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
let location = BoardLocation(index: index)
|
||||
@@ -272,7 +267,7 @@ extension GameViewController: BoardViewDelegate {
|
||||
}
|
||||
|
||||
// Select new piece if possible
|
||||
if player.occupiesSquareAt(location: location) {
|
||||
if player.occupiesSquare(at: location) {
|
||||
selectedIndex = index
|
||||
}
|
||||
|
||||
@@ -280,17 +275,17 @@ extension GameViewController: BoardViewDelegate {
|
||||
if let selectedIndex = selectedIndex {
|
||||
|
||||
do {
|
||||
try player.movePiece(fromLocation: BoardLocation(index: selectedIndex),
|
||||
toLocation: location)
|
||||
try player.movePiece(from: BoardLocation(index: selectedIndex),
|
||||
to: location)
|
||||
|
||||
} catch Player.MoveError.pieceUnableToMoveToLocation {
|
||||
print("Piece is unable to move to this location")
|
||||
|
||||
} catch Player.MoveError.cannotMoveInToCheck{
|
||||
} catch Player.MoveError.cannotMoveInToCheck {
|
||||
print("Player cannot move in to check")
|
||||
showAlert(title: "😜", message: "Player cannot move in to check")
|
||||
|
||||
} catch Player.MoveError.playerMustMoveOutOfCheck{
|
||||
} catch Player.MoveError.playerMustMoveOutOfCheck {
|
||||
print("Player must move out of check")
|
||||
showAlert(title: "🙃", message: "Player must move out of check")
|
||||
|
||||
@@ -305,7 +300,7 @@ extension GameViewController: BoardViewDelegate {
|
||||
|
||||
}
|
||||
|
||||
// MARK - GameDelegate
|
||||
// MARK: - GameDelegate
|
||||
|
||||
extension GameViewController: GameDelegate {
|
||||
|
||||
@@ -314,7 +309,7 @@ extension GameViewController: GameDelegate {
|
||||
}
|
||||
|
||||
func gameDidAddPiece(game: Game) {
|
||||
// do nothing
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
func gameDidMovePiece(game: Game, piece: Piece, toLocation: BoardLocation) {
|
||||
@@ -325,7 +320,7 @@ extension GameViewController: GameDelegate {
|
||||
|
||||
pieceView.location = toLocation
|
||||
|
||||
// Animage
|
||||
// Animate
|
||||
view.setNeedsLayout()
|
||||
|
||||
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut, animations: {
|
||||
@@ -343,8 +338,7 @@ extension GameViewController: GameDelegate {
|
||||
// Fade out and remove
|
||||
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut, animations: {
|
||||
pieceView.alpha = 0
|
||||
}, completion: {
|
||||
(finished: Bool) in
|
||||
}, completion: { (finished: Bool) in
|
||||
self.removePieceView(withTag: piece.tag)
|
||||
})
|
||||
|
||||
@@ -360,12 +354,12 @@ extension GameViewController: GameDelegate {
|
||||
}
|
||||
|
||||
func gameDidEndUpdates(game: Game) {
|
||||
// do nothing
|
||||
activityIndicator.stopAnimating()
|
||||
}
|
||||
|
||||
func gameWonByPlayer(game: Game, player: Player) {
|
||||
|
||||
let colorName = player.color.toString()
|
||||
let colorName = player.color.string
|
||||
|
||||
let title = "Checkmate!"
|
||||
let message = "\(colorName.capitalized) wins!"
|
||||
@@ -380,10 +374,10 @@ extension GameViewController: GameDelegate {
|
||||
func gameDidChangeCurrentPlayer(game: Game) {
|
||||
|
||||
// Deselect selected piece
|
||||
self.selectedIndex = nil;
|
||||
self.selectedIndex = nil
|
||||
|
||||
// Tell AI to take go
|
||||
if let _ = game.currentPlayer as? AIPlayer {
|
||||
if game.currentPlayer is AIPlayer {
|
||||
perform(#selector(tellAIToTakeGo), with: nil, afterDelay: 1)
|
||||
}
|
||||
|
||||
@@ -391,31 +385,34 @@ extension GameViewController: GameDelegate {
|
||||
updateCastleButtonsVisibility()
|
||||
}
|
||||
|
||||
func tellAIToTakeGo() {
|
||||
@objc func tellAIToTakeGo() {
|
||||
|
||||
if let player = game.currentPlayer as? AIPlayer {
|
||||
player.makeMove()
|
||||
activityIndicator.startAnimating()
|
||||
player.makeMoveAsync()
|
||||
}
|
||||
}
|
||||
|
||||
func promotedTypeForPawn(location: BoardLocation, player: Human, possiblePromotions: [Piece.PieceType], callback: @escaping (Piece.PieceType) -> Void) {
|
||||
func promotedTypeForPawn(location: BoardLocation,
|
||||
player: Human,
|
||||
possiblePromotions: [Piece.PieceType],
|
||||
callback: @escaping (Piece.PieceType) -> Void) {
|
||||
|
||||
boardView.isUserInteractionEnabled = false
|
||||
|
||||
let viewController = PromotionSelectionViewController.promotionSelectionViewController(pawnLocation: location, possibleTypes: possiblePromotions) {
|
||||
let viewController =
|
||||
PromotionSelectionViewController.promotionSelectionViewController(pawnLocation: location,
|
||||
possibleTypes: possiblePromotions) {
|
||||
|
||||
self.promotionSelectionViewController?.view.removeFromSuperview()
|
||||
self.promotionSelectionViewController?.removeFromParentViewController()
|
||||
self.promotionSelectionViewController?.removeFromParent()
|
||||
self.boardView.isUserInteractionEnabled = true
|
||||
callback($0)
|
||||
}
|
||||
|
||||
view.addSubview(viewController.view)
|
||||
addChildViewController(viewController)
|
||||
addChild(viewController)
|
||||
promotionSelectionViewController = viewController
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -11,29 +11,19 @@ import SwiftChess
|
||||
|
||||
class MenuViewController: UIViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
}
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
super.didReceiveMemoryWarning()
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction func playerVsAIButtonPressed(_ sender: UIButton){
|
||||
@IBAction func playerVsAIButtonPressed(_ sender: UIButton) {
|
||||
print("Player vs AI button pressed")
|
||||
|
||||
let whitePlayer = Human(color: .white)
|
||||
let blackPlayer = AIPlayer(color: .black)
|
||||
let blackPlayer = AIPlayer(color: .black, configuration: AIConfiguration(difficulty: .hard))
|
||||
|
||||
let game = Game(firstPlayer: whitePlayer, secondPlayer: blackPlayer)
|
||||
startGame(game: game)
|
||||
}
|
||||
|
||||
@IBAction func playerVsPlayerButtonPressed(_ sender: UIButton){
|
||||
@IBAction func playerVsPlayerButtonPressed(_ sender: UIButton) {
|
||||
print("Player vs Player button pressed")
|
||||
|
||||
let whitePlayer = Human(color: .white)
|
||||
@@ -43,11 +33,11 @@ class MenuViewController: UIViewController {
|
||||
startGame(game: game)
|
||||
}
|
||||
|
||||
@IBAction func AIvsAIButtonPressed(_ sender: UIButton){
|
||||
@IBAction func AIvsAIButtonPressed(_ sender: UIButton) {
|
||||
print("AI vs AI button pressed")
|
||||
|
||||
let whitePlayer = AIPlayer(color: .white)
|
||||
let blackPlayer = AIPlayer(color: .black)
|
||||
let whitePlayer = AIPlayer(color: .white, configuration: AIConfiguration(difficulty: .hard))
|
||||
let blackPlayer = AIPlayer(color: .black, configuration: AIConfiguration(difficulty: .hard))
|
||||
|
||||
let game = Game(firstPlayer: whitePlayer, secondPlayer: blackPlayer)
|
||||
startGame(game: game)
|
||||
@@ -60,4 +50,3 @@ class MenuViewController: UIViewController {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import SwiftChess
|
||||
class PieceView: UIView {
|
||||
|
||||
public var piece: Piece {
|
||||
didSet{
|
||||
didSet {
|
||||
update()
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ class PieceView: UIView {
|
||||
let imageView = UIImageView()
|
||||
|
||||
var selected = false {
|
||||
didSet{
|
||||
didSet {
|
||||
update()
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,6 @@ class PieceView: UIView {
|
||||
|
||||
backgroundColor = selected ? UIColor.red : UIColor.clear
|
||||
|
||||
|
||||
/*
|
||||
transform = CGAffineTransform.identity
|
||||
|
||||
|
||||
@@ -20,7 +20,10 @@ class PromotionSelectionViewController: UIViewController {
|
||||
var buttons = [UIButton]()
|
||||
|
||||
// MARK: - Creation
|
||||
public static func promotionSelectionViewController(pawnLocation: BoardLocation, possibleTypes: [Piece.PieceType], callback: @escaping (Piece.PieceType) -> Void) -> PromotionSelectionViewController {
|
||||
public static func promotionSelectionViewController(pawnLocation: BoardLocation,
|
||||
possibleTypes: [Piece.PieceType],
|
||||
callback: @escaping (Piece.PieceType) -> Void)
|
||||
-> PromotionSelectionViewController {
|
||||
|
||||
let viewController = PromotionSelectionViewController()
|
||||
viewController.pawnLocation = pawnLocation
|
||||
@@ -67,9 +70,9 @@ class PromotionSelectionViewController: UIViewController {
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
func buttonPressed(sender: UIButton) {
|
||||
@objc func buttonPressed(sender: UIButton) {
|
||||
|
||||
let index = buttons.index(of: sender)!
|
||||
let index = buttons.firstIndex(of: sender)!
|
||||
print("Button pressed at index: \(index)")
|
||||
|
||||
let chosenType = possibleTypes![index]
|
||||
@@ -91,5 +94,4 @@ class PromotionSelectionViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,289 +0,0 @@
|
||||
//
|
||||
// AIConfigurationTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 03/01/2017.
|
||||
// Copyright © 2017 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class AIConfigurationTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Count Pieces
|
||||
|
||||
func testBoardRaterCountPiecesWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P P P P P P" +
|
||||
"R K B Q G B K R" )
|
||||
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterCountPiecesWeighting = 1
|
||||
let lowValueRater = BoardRaterCountPieces(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterCountPiecesWeighting = 2
|
||||
let highValueRater = BoardRaterCountPieces(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Board Dominance
|
||||
|
||||
func testBoardDominanceWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- P - - - P P -" +
|
||||
"R K B Q G B K R" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterBoardDominanceWeighting = 1
|
||||
let lowValueRater = BoardRaterBoardDominance(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterBoardDominanceWeighting = 2
|
||||
let highValueRater = BoardRaterBoardDominance(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Center Ownership
|
||||
|
||||
func testCenterOwnershipWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - r g r - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - Q B - - -" +
|
||||
"- - - K P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- P - - - P P -" +
|
||||
"R K B Q G B K R" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterCenterOwnershipWeighting = 1
|
||||
let lowValueRater = BoardRaterCenterOwnership(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterCenterOwnershipWeighting = 2
|
||||
let highValueRater = BoardRaterCenterOwnership(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Center Dominance
|
||||
|
||||
func testCenterDominanceWeightingAffetsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - r g r - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - Q B - - -" +
|
||||
"- - - K P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- P - - - P P -" +
|
||||
"R K B Q G B K R" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterCenterDominanceWeighting = 1
|
||||
let lowValueRater = BoardRaterCenterDominance(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterCenterDominanceWeighting = 2
|
||||
let highValueRater = BoardRaterCenterDominance(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Threatened Pieces
|
||||
|
||||
func testBoardRaterThreatenedPiecesWeightingAffectsRating() {
|
||||
|
||||
// White is threatening the black rook with its bishop and knight
|
||||
let board = ASCIIBoard(pieces: "r - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- K - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - B" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterThreatenedPiecesWeighting = 1
|
||||
let lowValueRater = BoardRaterThreatenedPieces(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterThreatenedPiecesWeighting = 2
|
||||
let highValueRater = BoardRaterThreatenedPieces(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
func testBoardRaterThreatenedPiecesOwnPiecesMultiplierAffectsRating() {
|
||||
|
||||
// White and black rook are threatening each other, so advantage is neutral
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"r - - - - - - R" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterThreatenedPiecesOwnPiecesMultiplier = 1
|
||||
let lowValueRater = BoardRaterThreatenedPieces(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterThreatenedPiecesOwnPiecesMultiplier = 2
|
||||
let highValueRater = BoardRaterThreatenedPieces(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
// Result should be more negative for a higher value, as white is under threat
|
||||
XCTAssertLessThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Pawn Progression
|
||||
|
||||
func testPawnProgressionWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"p p p p p p p p" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P P P P P P" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterPawnProgressionWeighting = 1
|
||||
let lowValueRater = BoardRaterPawnProgression(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterPawnProgressionWeighting = 2
|
||||
let highValueRater = BoardRaterPawnProgression(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - King Surrounding Possession
|
||||
|
||||
func testKingSurroundingPossessionWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P P P - -" +
|
||||
"- - - P G P - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterKingSurroundingPossessionWeighting = 1
|
||||
let lowValueRater = BoardRaterKingSurroundingPossession(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterKingSurroundingPossessionWeighting = 2
|
||||
let highValueRater = BoardRaterKingSurroundingPossession(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Check Mate Opportunity
|
||||
|
||||
func testCheckMateOpportunityWeightingAffectsRating() {
|
||||
|
||||
// White can move Rook at (0,0) to (0,7) to check mate black
|
||||
let board = ASCIIBoard(pieces: "- - - - g p - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P P P - -" +
|
||||
"R - - P G P - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterCheckMateOpportunityWeighting = 1
|
||||
let lowValueRater = BoardRaterCheckMateOpportunity(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterCheckMateOpportunityWeighting = 2
|
||||
let highValueRater = BoardRaterCheckMateOpportunity(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Center Four Occupation
|
||||
|
||||
func testCenterFourOccupationWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - p g p - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - K R - - -" +
|
||||
"- - - Q R - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P P P - -" +
|
||||
"- - - P G P - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
lowValueConfig.boardRaterCenterFourOccupationWeighting = 1
|
||||
let lowValueRater = BoardRaterCenterFourOccupation(configuration: lowValueConfig)
|
||||
let lowValueRating = lowValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
var highValueConfig = AIConfiguration()
|
||||
highValueConfig.boardRaterCenterFourOccupationWeighting = 2
|
||||
let highValueRater = BoardRaterCenterFourOccupation(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
//
|
||||
// AIPlayerTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 29/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class AIPlayerTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testExample() {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
func testPerformanceExample() {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Test Cannot move in the check
|
||||
|
||||
func makeTestGame(board: Board, colorToMove: Color) -> Game {
|
||||
|
||||
let whitePlayer = AIPlayer(color: .white)
|
||||
let blackPlayer = AIPlayer(color: .black)
|
||||
|
||||
let game = Game(firstPlayer: whitePlayer, secondPlayer: blackPlayer, board: board, colorToMove: colorToMove)
|
||||
return game
|
||||
}
|
||||
|
||||
func testKnightCannotPutOwnKingInToCheck() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "r - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - * - - - - -" +
|
||||
"K - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - - - - - -" )
|
||||
|
||||
let knightLocation = board.locationOfCharacter("K")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(fromLocation: knightLocation, toLocation: testLocation))
|
||||
}
|
||||
|
||||
func testKingCannotMoveInToCheck() {
|
||||
|
||||
// This is a complex scenario because it was one that I observed from an actual game
|
||||
|
||||
let board = ASCIIBoard(pieces: "r k - - q b - r" +
|
||||
"p p p g k - - p" +
|
||||
"- - * p b p - -" +
|
||||
"P P - - p - p P" +
|
||||
"- - P - P - - -" +
|
||||
"- B - - Q P - -" +
|
||||
"- B - P K G P -" +
|
||||
"R K - - - - - R" )
|
||||
|
||||
let kingLocation = board.locationOfCharacter("g")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .black)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(fromLocation: kingLocation, toLocation: testLocation))
|
||||
}
|
||||
|
||||
func testPawnCannotPutOwnKingInToCheck() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - * - - - -" +
|
||||
"G - - P - - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let pawnLocation = board.locationOfCharacter("P")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(fromLocation: pawnLocation, toLocation: testLocation))
|
||||
|
||||
}
|
||||
|
||||
func testQueenCannotPutOwnKingInToCheck() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - * - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - Q - - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenLocation = board.locationOfCharacter("Q")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(fromLocation: queenLocation, toLocation: testLocation))
|
||||
}
|
||||
|
||||
func testRookCannotPutOwnKingInToCheck() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - * - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - R - - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rookLocation = board.locationOfCharacter("R")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(fromLocation: rookLocation, toLocation: testLocation))
|
||||
}
|
||||
|
||||
func testBishopCannotPutOwnKingInToCheck() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - *" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - B - - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let bishopLocation = board.locationOfCharacter("B")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(fromLocation: bishopLocation, toLocation: testLocation))
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
//
|
||||
// BoardRaterBoardDominanceTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 13/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterBoardDominanceTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterBoardDominance!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
self.boardRater = BoardRaterBoardDominance(configuration: AIConfiguration());
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testSingleQueenResultsInHigherValueThanSinglePawn() {
|
||||
|
||||
let queenBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - Q - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
let queenRating = boardRater.ratingfor(board: queenBoard.board, color: .white)
|
||||
|
||||
let pawnBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
let pawnRating = boardRater.ratingfor(board: pawnBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(queenRating, pawnRating)
|
||||
}
|
||||
|
||||
func testOwnPieceBlockingPathResultsInLowerValue() {
|
||||
|
||||
let blockedBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P - - - - - - -" +
|
||||
"Q P - - - - - -" )
|
||||
let blockedRating = boardRater.ratingfor(board: blockedBoard.board, color: .white)
|
||||
|
||||
let nonBockedBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"Q - - - - - - -" )
|
||||
let nonBockedRating = boardRater.ratingfor(board: nonBockedBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(nonBockedRating, blockedRating)
|
||||
|
||||
}
|
||||
|
||||
func testOpponantDominanceResultsInLowerValue() {
|
||||
|
||||
let whiteDominantBoard = ASCIIBoard(pieces: "R - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - k" +
|
||||
"- - - - - - - p" +
|
||||
"Q - - - - - - -" )
|
||||
let whiteRating = boardRater.ratingfor(board: whiteDominantBoard.board, color: .white)
|
||||
|
||||
let blackDominantBoard = ASCIIBoard(pieces: "r - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - K" +
|
||||
"- - - - - - - P" +
|
||||
"q - - - - - - -" )
|
||||
let blackRating = boardRater.ratingfor(board: blackDominantBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(whiteRating, blackRating)
|
||||
}
|
||||
|
||||
func testQueenInCornerResultsInLowerValueThanQueenInCenter() {
|
||||
|
||||
let queenInCornerBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"Q - - - - - - -" )
|
||||
let queenInCornerRating = boardRater.ratingfor(board: queenInCornerBoard.board, color: .white)
|
||||
|
||||
let queenInCenterBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - Q - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
let queenInCenterRating = boardRater.ratingfor(board: queenInCenterBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(queenInCenterRating, queenInCornerRating)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
//
|
||||
// BoardRaterCenterDominanceTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 13/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterCenterDominanceTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterCenterDominance!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
boardRater = BoardRaterCenterDominance(configuration: AIConfiguration())
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testPiecesWithCenterVisibilityResultsInHigherValueThanPiecesWithoutCenterVisibility() {
|
||||
|
||||
let centerVisibleBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - Q" +
|
||||
"- - - - - - - R" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
let centerVisibleRating = boardRater.ratingfor(board: centerVisibleBoard.board, color: .white)
|
||||
|
||||
let centerObstructedBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - P -" +
|
||||
"- - - - - - - Q" )
|
||||
let centerObstructedRating = boardRater.ratingfor(board: centerObstructedBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(centerVisibleRating, centerObstructedRating)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
//
|
||||
// BoardRaterCenterFourOccupationTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 03/01/2017.
|
||||
// Copyright © 2017 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterCenterFourOccupationTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
|
||||
func defaultBoardRater() -> BoardRaterCenterFourOccupation {
|
||||
|
||||
let configuration = AIConfiguration()
|
||||
let boardRater = BoardRaterCenterFourOccupation(configuration: configuration)
|
||||
return boardRater
|
||||
}
|
||||
|
||||
func testNorthEastCenterSquareResultsInHigherRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = defaultBoardRater().ratingfor(board: board.board, color: .white)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testSouthEastCenterSquareResultsInHigherRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = defaultBoardRater().ratingfor(board: board.board, color: .white)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testSouthWestCenterSquareResultsInHigherRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = defaultBoardRater().ratingfor(board: board.board, color: .white)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testNorthWestCenterSquareResultsInHigherRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = defaultBoardRater().ratingfor(board: board.board, color: .white)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testNonCenterSquaresResultInZeroRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "P P P P P P P P" +
|
||||
"P P P P P P P P" +
|
||||
"P P P P P P P P" +
|
||||
"P P P - - P P P" +
|
||||
"P P P - - P P P" +
|
||||
"P P P P P P P P" +
|
||||
"P P P P P P P P" +
|
||||
"P P P P P P P P" )
|
||||
|
||||
let rating = defaultBoardRater().ratingfor(board: board.board, color: .white)
|
||||
XCTAssertEqualWithAccuracy(rating, 0, accuracy: 0.01)
|
||||
}
|
||||
|
||||
func testOpponentOccupationResultsInNegativeRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - p p - - -" +
|
||||
"- - - p p - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = defaultBoardRater().ratingfor(board: board.board, color: .white)
|
||||
XCTAssertLessThan(rating, 0)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
//
|
||||
// BoardRaterCenterDominanceTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 13/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterCenterOwnershipTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterCenterOwnership!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
boardRater = BoardRaterCenterOwnership(configuration: AIConfiguration())
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testCenterReturnsHigherValueThatSide() {
|
||||
|
||||
let centerBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let centerRating = boardRater.ratingfor(board: centerBoard.board, color: .white);
|
||||
|
||||
let sideBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - P -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let sideRating = boardRater.ratingfor(board: sideBoard.board, color: .white);
|
||||
|
||||
XCTAssertGreaterThan(centerRating, sideRating);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
//
|
||||
// BoardRaterCountPieces.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 26/11/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterCountPiecesTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterCountPieces!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
// Initiailise a new board rater for each test
|
||||
boardRater = BoardRaterCountPieces(configuration: AIConfiguration());
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testWhiteWinningResultsInPositiveValue() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P P P P P P" +
|
||||
"R K B Q G B K R" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
XCTAssert(rating > 0, "Expected rating to be positive")
|
||||
}
|
||||
|
||||
func testWhiteLosingResultsInNegativeValue() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "r k b q g b k r" +
|
||||
"p p p p p p p p" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
XCTAssert(rating < 0, "Expected rating to be negative")
|
||||
}
|
||||
|
||||
func testGreaterNumberOfPiecesResultsInHigherValue() {
|
||||
|
||||
let fewerPiecesBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P P P P P P" )
|
||||
|
||||
let morePiecesBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P P P P P P" +
|
||||
"P P P P P P P P" )
|
||||
|
||||
let fewerPiecesRating = boardRater.ratingfor(board: fewerPiecesBoard.board, color: .white)
|
||||
let morePiecesRating = boardRater.ratingfor(board: morePiecesBoard.board, color: .white)
|
||||
XCTAssert(morePiecesRating > fewerPiecesRating, "Expected more pieces to produce higher rating")
|
||||
}
|
||||
|
||||
func testHigherValuePiecesResultsInHigherRating() {
|
||||
|
||||
let lowerValuePiecesBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P - - - - -" )
|
||||
|
||||
let higherValuePiecesBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R R R - - - - -" )
|
||||
|
||||
let lowerValuePiecesRating = boardRater.ratingfor(board: lowerValuePiecesBoard.board, color: .white)
|
||||
let higherValuePiecesRating = boardRater.ratingfor(board: higherValuePiecesBoard.board, color: .white)
|
||||
XCTAssert(higherValuePiecesRating > lowerValuePiecesRating, "Expected higher value pieces to produce higher rating")
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// MARK - Perfomance
|
||||
|
||||
func testRatingPerformance() {
|
||||
|
||||
let board = Board(state: .newGame)
|
||||
|
||||
self.measure {
|
||||
for _ in 0..<1000{
|
||||
let _ = self.boardRater.ratingfor(board: board, color: .white)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,391 +0,0 @@
|
||||
//
|
||||
// BoardRaterKingSurroundingPossession.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 29/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterKingSurroundingPossessionTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterKingSurroundingPossession!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
boardRater = BoardRaterKingSurroundingPossession(configuration: AIConfiguration())
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
// MARK: - Test obtaining surrounding spaces
|
||||
|
||||
func assertSurroundingSpacesAreCorrect(color: Color, board: ASCIIBoard) {
|
||||
|
||||
let indexes = board.indexesWithCharacter("*")
|
||||
let surroundingLocations = self.boardRater.locationsSurroundingKing(color: color, board: board.board)
|
||||
|
||||
XCTAssertEqual(indexes.count, surroundingLocations.count,
|
||||
"Expected counts to be the same (\(indexes.count) indexes \(surroundingLocations.count) surrounding locations).")
|
||||
|
||||
|
||||
for index in indexes {
|
||||
|
||||
let location = BoardLocation(index: index)
|
||||
var foundLocation = false
|
||||
|
||||
for surroundingLocation in surroundingLocations {
|
||||
|
||||
if surroundingLocation == location {
|
||||
foundLocation = true
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(foundLocation, "Expected location x: \(location.x) y: \(location.y) to be returned")
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
func testWhiteKingSurroundingSpacesReturnsCorrectIndexesInCenter() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - * * * - - -" +
|
||||
"- - * G * - - -" +
|
||||
"- - * * * - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .white, board: board)
|
||||
}
|
||||
|
||||
func testWhiteKingSurroundingSpacesReturnsCorrectIndexesInBottomLeft() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"* * - - - - - -" +
|
||||
"G * - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .white, board: board)
|
||||
}
|
||||
|
||||
func testWhiteKingSurroundingSpacesReturnsCorrectIndexesInBottomRight() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - * *" +
|
||||
"- - - - - - * G" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .white, board: board)
|
||||
}
|
||||
|
||||
func testWhiteKingSurroundingSpacesReturnsCorrectIndexesInTopLeft() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "G * - - - - - -" +
|
||||
"* * - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .white, board: board)
|
||||
}
|
||||
|
||||
func testWhiteKingSurroundingSpacesReturnsCorrectIndexesInTopRight() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - * G" +
|
||||
"- - - - - - * *" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .white, board: board)
|
||||
}
|
||||
|
||||
func testBlackKingSurroundingSpacesReturnsCorrectIndexesInCenter() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - * * * - - -" +
|
||||
"- - * g * - - -" +
|
||||
"- - * * * - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .black, board: board)
|
||||
}
|
||||
|
||||
func testBlackKingSurroundingSpacesReturnsCorrectIndexesInBottomLeft() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"* * - - - - - -" +
|
||||
"g * - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .black, board: board)
|
||||
}
|
||||
|
||||
func testBlackKingSurroundingSpacesReturnsCorrectIndexesInBottomRight() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - * *" +
|
||||
"- - - - - - * g" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .black, board: board)
|
||||
}
|
||||
|
||||
func testBlackKingSurroundingSpacesReturnsCorrectIndexesInTopLeft() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "g * - - - - - -" +
|
||||
"* * - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .black, board: board)
|
||||
}
|
||||
|
||||
func testBlackKingSurroundingSpacesReturnsCorrectIndexesInTopRight() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - * g" +
|
||||
"- - - - - - * *" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .black, board: board)
|
||||
}
|
||||
|
||||
// MARK: - Test Ratings
|
||||
|
||||
func testThatGreaterOpponentPossessionOfOurKingSurroundingsResultsInLowerRating() {
|
||||
|
||||
let lowRatingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"r - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let highRatingBoard = ASCIIBoard(pieces:"- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"r - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let lowRating = boardRater.ratingfor(board: lowRatingBoard.board, color: .white)
|
||||
let highRating = boardRater.ratingfor(board: highRatingBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highRating, lowRating)
|
||||
}
|
||||
|
||||
func testThatGreaterPossessionOfOurKingSurroundingsResultsInHigherRating() {
|
||||
|
||||
let lowRatingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let highRatingBoard = ASCIIBoard(pieces:"- - - - - - - -" +
|
||||
"- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let lowRating = boardRater.ratingfor(board: lowRatingBoard.board, color: .white)
|
||||
let highRating = boardRater.ratingfor(board: highRatingBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highRating, lowRating)
|
||||
}
|
||||
|
||||
func testThatGreaterPossessionOfOpponentKingSurroundingsResultsInHigherRating() {
|
||||
|
||||
let lowRatingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let highRatingBoard = ASCIIBoard(pieces:"- - - - g - - -" +
|
||||
"R - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let lowRating = boardRater.ratingfor(board: lowRatingBoard.board, color: .white)
|
||||
let highRating = boardRater.ratingfor(board: highRatingBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highRating, lowRating)
|
||||
}
|
||||
|
||||
func testThatGreaterOpponentPossessionOfOpponentKingSurroundingsResultsInLowerRating() {
|
||||
|
||||
let lowRatingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"r - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let highRatingBoard = ASCIIBoard(pieces:"- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"r - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let lowRating = boardRater.ratingfor(board: lowRatingBoard.board, color: .white)
|
||||
let highRating = boardRater.ratingfor(board: highRatingBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highRating, lowRating)
|
||||
}
|
||||
|
||||
|
||||
func testThatBlackandWhiteRatingsAreTheSame() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"Q - - - - - - b" +
|
||||
"R - - - p - - q" +
|
||||
"- k - - G - K -" )
|
||||
|
||||
let invertedBoard = ASCIIBoard(pieces: "- - - - G - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"q - - - - - - B" +
|
||||
"r - - - P - - Q" +
|
||||
"- K - - g - k -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
let invertedRating = boardRater.ratingfor(board: invertedBoard.board, color: .black)
|
||||
|
||||
XCTAssertEqualWithAccuracy(rating, invertedRating, accuracy: 0.01)
|
||||
}
|
||||
|
||||
func testThatPiecesSurroundingOwnKingResultsInPositiveRatingForWhite() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P P P - -" +
|
||||
"- - - P G P - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testThatPiecesSurroundingOwnKingResultsInPositiveRatingForBlack() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - p g p - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .black)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testThatPiecesSurroundingOpponentKingResultsInNegativeRatingForWhite() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - p g p - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
XCTAssertLessThan(rating, 0)
|
||||
}
|
||||
|
||||
func testThatPiecesSurroundingOpponentKingResultsInNegativeRatingForBlack() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P P P - -" +
|
||||
"- - - P G P - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .black)
|
||||
XCTAssertLessThan(rating, 0)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,431 +0,0 @@
|
||||
//
|
||||
// BoardRaterThreatenedPiecesTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steven Barnegren on 14/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterThreatenedPiecesTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterThreatenedPieces!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
boardRater = BoardRaterThreatenedPieces(configuration: AIConfiguration())
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testBoardRaterThreatededPiecesReturnsNoThreatIfNoOtherPieces() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - Q - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertEqualWithAccuracy(rating, 0, accuracy: 0.01)
|
||||
}
|
||||
|
||||
func testBoardRaterThreatenedPiecesReturnsNegativeValueIfThreatened() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"q - - - - - K -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssert(rating < 0);
|
||||
}
|
||||
|
||||
func testBoardRaterThreatenedPiecesReturnsPositiveValueIfThreateningOpponant() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"Q - - - - - k -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
XCTAssert(rating > 0);
|
||||
}
|
||||
|
||||
func testBoardRaterThreatenedPiecesReturnsHigherThreatValueForHigherValuePieces() {
|
||||
|
||||
let queenBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"q - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenIndex = queenBoard.indexOfCharacter("Q")
|
||||
let queenLocation = BoardLocation(index: queenIndex)
|
||||
let queenRating = boardRater.threatRatingForPiece(at: queenLocation,
|
||||
board: queenBoard.board,
|
||||
color: .white)
|
||||
|
||||
|
||||
|
||||
let knightBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"q - - - - - K -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let knightIndex = knightBoard.indexOfCharacter("K")
|
||||
let knightLocation = BoardLocation(index: knightIndex)
|
||||
let knightRating = boardRater.threatRatingForPiece(at: knightLocation,
|
||||
board: knightBoard.board,
|
||||
color: .white)
|
||||
|
||||
|
||||
XCTAssert(queenRating > knightRating);
|
||||
}
|
||||
/*
|
||||
func testOwnPiecesMultiplerShouldIncreaceValueOfIncomingThreats() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"q - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
boardRater.ownPiecesMultipler = 1
|
||||
let expectedLowRating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
boardRater.ownPiecesMultipler = 2
|
||||
let expectedHighRating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
|
||||
// Higher threat levels result in negative ratings!
|
||||
XCTAssert(expectedHighRating < expectedLowRating)
|
||||
}
|
||||
*/
|
||||
|
||||
func testBoardRaterThreatenedPiecesReturnsMoreNegativeThreatValueForFavourableTrade() {
|
||||
|
||||
// Good trade (White rook can be taken by the black queen, but the white pawn will then take the queen)
|
||||
let goodTradeBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - R - - -" +
|
||||
"- - - P - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - q" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
// Bad trade (White rook can be taken by the black pawn, then the white pawn will take the black pawn)
|
||||
let badTradeBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - p - -" +
|
||||
"- - - - R - - -" +
|
||||
"- - - P - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
|
||||
let rookLocation = BoardLocation(index: goodTradeBoard.indexOfCharacter("R"))
|
||||
|
||||
let goodTradeRating = boardRater.threatRatingForPiece(at: rookLocation, board: goodTradeBoard.board, color: .white)
|
||||
let badTradeRating = boardRater.threatRatingForPiece(at: rookLocation, board: badTradeBoard.board, color: .white)
|
||||
|
||||
XCTAssert(goodTradeRating < badTradeRating);
|
||||
}
|
||||
|
||||
// MARK - Get protected pieces tests
|
||||
|
||||
func testGetProtectingPiecesReturnsProtectingPieces() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - K - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - R -" +
|
||||
"- - - B - - - -" )
|
||||
|
||||
|
||||
let expectedIndexes = [
|
||||
board.indexOfCharacter("K"),
|
||||
board.indexOfCharacter("R"),
|
||||
board.indexOfCharacter("B"),
|
||||
]
|
||||
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
|
||||
let protectingLocations = boardRater.protectingPiecesLocationsforPiece(at: queenLocation,
|
||||
on: board.board)
|
||||
|
||||
// Check all of the expected locations appeared in the protecting locations array
|
||||
for expectedIndex in expectedIndexes {
|
||||
var foundIndex = false
|
||||
|
||||
for location in protectingLocations {
|
||||
if location == BoardLocation(index: expectedIndex) {
|
||||
foundIndex = true
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(foundIndex, "Failed to find expected index \(expectedIndex)")
|
||||
}
|
||||
|
||||
// Check all of the protecting locations were expected
|
||||
for location in protectingLocations {
|
||||
var wasExpected = false
|
||||
|
||||
for expectedIndex in expectedIndexes {
|
||||
if location == BoardLocation(index: expectedIndex) {
|
||||
wasExpected = true
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(wasExpected, "Found unexpected protecting location \(location)");
|
||||
}
|
||||
}
|
||||
|
||||
func testGetProtectingPiecesDoesntReturnNonProtectingPiecesOfSameColor() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - K - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - - - - -" +
|
||||
"- B - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
|
||||
let protectingLocations = boardRater.protectingPiecesLocationsforPiece(at: queenLocation,
|
||||
on: board.board)
|
||||
|
||||
// None of the pieces are protecting the queen, so expect count to be zero
|
||||
XCTAssertTrue(protectingLocations.count == 0)
|
||||
}
|
||||
|
||||
func testGetProtectingPiecesDoesntReturnThreateningPiecesOfOppositeColor() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - k - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - r -" +
|
||||
"- - - b - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
|
||||
let protectingLocations = boardRater.protectingPiecesLocationsforPiece(at: queenLocation,
|
||||
on: board.board)
|
||||
|
||||
// The black pieces cannot protect the white queen, so expect count to be zero
|
||||
XCTAssertTrue(protectingLocations.count == 0)
|
||||
}
|
||||
|
||||
func testGetProtectingPiecesDoesntReturnPawnsMovingStraightAhead() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - P -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
|
||||
let protectingLocations = boardRater.protectingPiecesLocationsforPiece(at: queenLocation,
|
||||
on: board.board)
|
||||
|
||||
XCTAssertTrue(protectingLocations.count == 0)
|
||||
}
|
||||
|
||||
func testGetProtectingPiecesReturnsPawnsMovingDiagonally() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - P - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
|
||||
let protectingLocations = boardRater.protectingPiecesLocationsforPiece(at: queenLocation,
|
||||
on: board.board)
|
||||
|
||||
XCTAssertTrue(protectingLocations.count == 1)
|
||||
}
|
||||
|
||||
// MARK - Get threatening pieces tests
|
||||
|
||||
func testGetThreateningPiecesReturnsThreateningPieces() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - k - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - r -" +
|
||||
"- - - b - - - -" )
|
||||
|
||||
|
||||
let expectedIndexes = [
|
||||
board.indexOfCharacter("k"),
|
||||
board.indexOfCharacter("r"),
|
||||
board.indexOfCharacter("b"),
|
||||
]
|
||||
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
|
||||
let threateningLocations = boardRater.threateningPiecesLocationsforPiece(at: queenLocation,
|
||||
on: board.board)
|
||||
|
||||
// Check all of the expected locations appeared in the protecting locations array
|
||||
for expectedIndex in expectedIndexes {
|
||||
var foundIndex = false
|
||||
|
||||
for location in threateningLocations {
|
||||
if location == BoardLocation(index: expectedIndex) {
|
||||
foundIndex = true
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(foundIndex, "Failed to find expected index \(expectedIndex)")
|
||||
}
|
||||
|
||||
// Check all of the protecting locations were expected
|
||||
for location in threateningLocations {
|
||||
var wasExpected = false
|
||||
|
||||
for expectedIndex in expectedIndexes {
|
||||
if location == BoardLocation(index: expectedIndex) {
|
||||
wasExpected = true
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(wasExpected, "Found unexpected threatening location \(location)");
|
||||
}
|
||||
}
|
||||
|
||||
func testGetThreateningPiecesDoesntReturnNonThreateningPiecesOfOppositeColor() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - k - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"r - - - - - - -" +
|
||||
"- b - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
|
||||
let threateningLocations = boardRater.threateningPiecesLocationsforPiece(at: queenLocation,
|
||||
on: board.board)
|
||||
|
||||
// None of the pieces are threatening the queen, so expect count to be zero
|
||||
XCTAssertTrue(threateningLocations.count == 0)
|
||||
}
|
||||
|
||||
func testGetThreateningPiecesDoesntReturnProtectingPiecesOfSameColor() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - K - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - R -" +
|
||||
"- - - B - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
|
||||
let threateningLocations = boardRater.threateningPiecesLocationsforPiece(at: queenLocation,
|
||||
on: board.board)
|
||||
|
||||
// The white pieces cannot threaten the white queen, so expect count to be zero
|
||||
XCTAssertTrue(threateningLocations.count == 0)
|
||||
}
|
||||
|
||||
func testGetThreateningPiecesDoesntReturnPawnsMovingStraightAhead() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - q -" +
|
||||
"- - - - - - P -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("q"))
|
||||
|
||||
let threateningLocations = boardRater.threateningPiecesLocationsforPiece(at: queenLocation,
|
||||
on: board.board)
|
||||
|
||||
XCTAssertTrue(threateningLocations.count == 0)
|
||||
}
|
||||
|
||||
func testGetThreateningPiecesReturnsPawnsMovingDiagonally() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - q -" +
|
||||
"- - - - - P - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("q"))
|
||||
|
||||
let threateningLocations = boardRater.threateningPiecesLocationsforPiece(at: queenLocation,
|
||||
on: board.board)
|
||||
|
||||
XCTAssertTrue(threateningLocations.count == 1)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
//
|
||||
// BoardScenarios.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 26/01/2017.
|
||||
// Copyright © 2017 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftChess
|
||||
|
||||
extension Board {
|
||||
|
||||
public static func whiteInStaleMateScenario() -> Board {
|
||||
|
||||
return ASCIIBoard(pieces: "- - r - r - - g" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"q - - - - - - -" +
|
||||
"- - - G - - - -" ).board
|
||||
}
|
||||
|
||||
public static func blackInStaleMateScenario() -> Board {
|
||||
|
||||
return ASCIIBoard(pieces: "- - R - R - - G" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"Q - - - - - - -" +
|
||||
"- - - g - - - -" ).board
|
||||
}
|
||||
|
||||
public static func whiteInCheckMateScenario() -> Board {
|
||||
|
||||
return ASCIIBoard(pieces: "- p g - - - - K" +
|
||||
"- - - - - P - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"r - - - - - - -" +
|
||||
"r - - G - - - -" ).board
|
||||
}
|
||||
|
||||
public static func blackInCheckMateScenario() -> Board {
|
||||
|
||||
return ASCIIBoard(pieces: "- - - g - - - R" +
|
||||
"- - - - - - - R" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- G - - - - - -" ).board
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,214 +0,0 @@
|
||||
//
|
||||
// PlayerTests.swift
|
||||
// SwiftChess
|
||||
//
|
||||
// Created by Steve Barnegren on 11/10/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class PlayerTests: XCTestCase {
|
||||
|
||||
// MARK: - Setup / Tear Down
|
||||
var game: Game!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
let firstPlayer = Human(color: .white)
|
||||
let secondPlayer = Human(color: .black)
|
||||
game = Game(firstPlayer: firstPlayer, secondPlayer: secondPlayer)
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
// Occupy square tests
|
||||
|
||||
func testOccupliesSquareAtLocationReturnsTrueWhenOccupiedByPlayerPiece() {
|
||||
|
||||
let location = BoardLocation(index: 0) // <-- should be occupied by white
|
||||
XCTAssert(game.whitePlayer.occupiesSquareAt(location: location), "Expected square to be occupied by player color")
|
||||
}
|
||||
|
||||
func testOccupliesSquareAtLocationReturnsFalseWhenSquareEmpty() {
|
||||
|
||||
let location = BoardLocation(x: 0, y: 2) // <-- should be empty
|
||||
XCTAssert(game.whitePlayer.occupiesSquareAt(location: location) == false, "Expected square to not be occupied by player color")
|
||||
}
|
||||
|
||||
func testOccupliesSquareAtLocationReturnsFalseWhenOccupiedByOppositeColor() {
|
||||
|
||||
let location = BoardLocation(x: 0, y: 7) // <-- should be occupied by black
|
||||
XCTAssert(game.whitePlayer.occupiesSquareAt(location: location) == false, "Expected square to not be occupied by player color")
|
||||
}
|
||||
|
||||
// Piece move tests
|
||||
|
||||
func testPlayerCannotMovePieceToSameLocation() {
|
||||
let location = BoardLocation(index: 0)
|
||||
XCTAssert(game.whitePlayer.canMovePiece(fromLocation: location, toLocation: location) == false)
|
||||
}
|
||||
|
||||
// MARK: - Move Errors
|
||||
|
||||
func gameForTestingCallbacks(board: Board, color: Color) -> Game {
|
||||
|
||||
let whitePlayer = Human(color: .white)
|
||||
let blackPlayer = Human(color: .black)
|
||||
|
||||
let game = Game(firstPlayer: whitePlayer, secondPlayer: blackPlayer, board: board, colorToMove: color)
|
||||
|
||||
return game
|
||||
}
|
||||
|
||||
func testMoveInToCheckErrorIsThrownByMovingQueen() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - * - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - - Q - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenLocation = board.locationOfCharacter("Q")
|
||||
let targetLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = gameForTestingCallbacks(board: board.board, color: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? Human else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
// Assert that the correct error is thrown
|
||||
XCTAssertTrue(player.canMovePieceWithError(fromLocation: queenLocation, toLocation: targetLocation).error == .cannotMoveInToCheck)
|
||||
}
|
||||
|
||||
func testMoveInToCheckErrorIsThrownByMovingPawn() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - * - - -" +
|
||||
"G - - - P - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let pieceLocation = board.locationOfCharacter("P")
|
||||
let targetLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = gameForTestingCallbacks(board: board.board, color: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? Human else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
// Assert that the correct error is thrown
|
||||
XCTAssertTrue(player.canMovePieceWithError(fromLocation: pieceLocation, toLocation: targetLocation).error == .cannotMoveInToCheck)
|
||||
}
|
||||
|
||||
func testMoveInToCheckErrorIsThrownByMovingKnight() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - * - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - - K - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let pieceLocation = board.locationOfCharacter("K")
|
||||
let targetLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = gameForTestingCallbacks(board: board.board, color: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? Human else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
// Assert that the correct error is thrown
|
||||
XCTAssertTrue(player.canMovePieceWithError(fromLocation: pieceLocation, toLocation: targetLocation).error == .cannotMoveInToCheck)
|
||||
}
|
||||
|
||||
func testMoveInToCheckErrorIsThrownByMovingBishop() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - * - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - - B - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let pieceLocation = board.locationOfCharacter("B")
|
||||
let targetLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = gameForTestingCallbacks(board: board.board, color: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? Human else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
// Assert that the correct error is thrown
|
||||
XCTAssertTrue(player.canMovePieceWithError(fromLocation: pieceLocation, toLocation: targetLocation).error == .cannotMoveInToCheck)
|
||||
}
|
||||
|
||||
func testMoveInToCheckErrorIsThrownByMovingRook() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - * - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - - R - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let pieceLocation = board.locationOfCharacter("R")
|
||||
let targetLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = gameForTestingCallbacks(board: board.board, color: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? Human else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
// Assert that the correct error is thrown
|
||||
XCTAssertTrue(player.canMovePieceWithError(fromLocation: pieceLocation, toLocation: targetLocation).error == .cannotMoveInToCheck)
|
||||
}
|
||||
|
||||
func testMoveInToCheckErrorIsThrownByMovingKing() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"* - - - - - - r" +
|
||||
"G - - - - - - -" )
|
||||
|
||||
let pieceLocation = board.locationOfCharacter("G")
|
||||
let targetLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = gameForTestingCallbacks(board: board.board, color: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? Human else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
// Assert that the correct error is thrown
|
||||
XCTAssertTrue(player.canMovePieceWithError(fromLocation: pieceLocation, toLocation: targetLocation).error == .cannotMoveInToCheck)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import UIKit
|
||||
import XCTest
|
||||
import SwiftChess
|
||||
|
||||
class Tests: XCTestCase {
|
||||
|
||||
@@ -19,11 +18,4 @@ class Tests: XCTestCase {
|
||||
XCTAssert(true, "Pass")
|
||||
}
|
||||
|
||||
func testPerformanceExample() {
|
||||
// This is an example of a performance test case.
|
||||
self.measure() {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,26 +1,150 @@
|
||||
# SwiftChess
|
||||
|
||||
[](http://cocoapods.org/pods/SwiftChess)
|
||||
[](http://cocoapods.org/pods/SwiftChess)
|
||||
[](http://cocoapods.org/pods/SwiftChess)
|
||||
[](https://travis-ci.org/SteveBarnegren/SwiftChess)
|
||||
[](https://twitter.com/stevebarnegren)
|
||||
|
||||
SwiftChess is a chess engine written in Swift.
|
||||
|
||||
Rather than a library that you can call to assist in making valid chess moves, SwiftChess aims to be a complete chess game, minus the UI.
|
||||

|
||||
|
||||
SwiftChess also includes a complete AI implementation.
|
||||
## Features
|
||||
|
||||
There's no documentation for now, as the public api is still in flux, but there is a complete example project for iOS.
|
||||
- Move validation
|
||||
- AI with three difficulty levels
|
||||
- Callbacks for check, checkmate and stalemate
|
||||
- Supports castling
|
||||
- Supports En Passent
|
||||
- Supports pawn promotion
|
||||
- Asyncronous AI move calculation
|
||||
|
||||
SwiftChess also has a reasonably comprehensive set of unit tests.
|
||||
|
||||
SwiftChess doesn't provide any UI, just all of the logic required to create a chess game. The example project contains a complete UIKit UI with touch handling that you start from if you like.
|
||||
|
||||
## Example
|
||||
|
||||
The example application contains a complete implementation of **SwiftChess**.
|
||||
|
||||
Run `Example/Example.xcodeproj`
|
||||
|
||||
The example app can run *player vs player*, *player vs AI*, *AI vs AI* matches
|
||||
## Basic Use
|
||||
|
||||
##### Start a game
|
||||
|
||||
```
|
||||
// Make a human player
|
||||
let whitePlayer = Human(color: .white)
|
||||
|
||||
// ... or an AI Player
|
||||
let blackPlayer = AIPlayer(color: .black, configuration: AIConfiguration(difficulty: .hard))
|
||||
|
||||
// Create a game
|
||||
let game = Game(firstPlayer: whitePlayer, secondPlayer: blackPlayer)
|
||||
```
|
||||
|
||||
##### Make a move
|
||||
|
||||
```
|
||||
if let player = game.currentPlayer as? Human {
|
||||
|
||||
let currentLocation = BoardLocation(x: 4, y: 1)
|
||||
let newLocation = BoardLocation(x: 4, y: 2)
|
||||
|
||||
try! player.movePiece(from: currentLocation,
|
||||
to: newLocation)
|
||||
}
|
||||
```
|
||||
|
||||
##### Tell the AI to make a move
|
||||
|
||||
```
|
||||
if let player = game.currentPlayer as? AIPlayer {
|
||||
player.makeMoveAsync()
|
||||
}
|
||||
```
|
||||
##### Then just wait for the callbacks!
|
||||
|
||||
```
|
||||
extension GameViewController: GameDelegate {
|
||||
|
||||
func gameDidMovePiece(game: Game, piece: Piece, toLocation: BoardLocation) {
|
||||
// Move piece on board
|
||||
}
|
||||
|
||||
func gameDidRemovePiece(game: Game, piece: Piece, location: BoardLocation) {
|
||||
// Remove piece from board
|
||||
}
|
||||
|
||||
func gameDidTransformPiece(game: Game, piece: Piece, location: BoardLocation) {
|
||||
// A pawn was promoted!
|
||||
}
|
||||
|
||||
func gameWonByPlayer(game: Game, player: Player) {
|
||||
ShowAlert("Checkmate!")
|
||||
}
|
||||
|
||||
func gameEndedInStaleMate(game: Game) {
|
||||
ShowAlert("Stalemate!")
|
||||
}
|
||||
|
||||
func gameDidChangeCurrentPlayer(game: Game) {
|
||||
// Make another move
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Persistence
|
||||
|
||||
The entire state of a **SwiftChess** game can be converted to and initialised from a `Dictionary`.
|
||||
|
||||
Get a snapshot of the current state:
|
||||
|
||||
```
|
||||
let dictionary: [String: Any] = game.dictionaryRepresentation
|
||||
```
|
||||
|
||||
Initialise a game with a previous snapshot:
|
||||
|
||||
```
|
||||
let game = Game(dictionary: dictionary)
|
||||
```
|
||||
|
||||
The returned dictionary stores all the information required to create a 'save game' feature. The player colors, AI difficulty, piece positions etc.
|
||||
|
||||
You can serialize this to JSON, save it to disk, send it over the network etc.
|
||||
|
||||
|
||||
## Other stuff
|
||||
|
||||
##### Make a castling move
|
||||
|
||||
```
|
||||
if game.board.canColorCastle(color: .white, side: .kingSide) {
|
||||
player.performCastleMove(side: .kingSide)
|
||||
}
|
||||
```
|
||||
|
||||
##### Support pawn promotion
|
||||
|
||||
```
|
||||
func promotedTypeForPawn(location: BoardLocation,
|
||||
player: Human,
|
||||
possiblePromotions: [Piece.PieceType],
|
||||
callback: @escaping (Piece.PieceType) -> Void) {
|
||||
|
||||
// Show UI for the user to select one of the possible promotion types
|
||||
// then call the handler
|
||||
|
||||
// ...or some games just promote to a queen
|
||||
callback(.queen)
|
||||
}
|
||||
```
|
||||
|
||||
## Author
|
||||
|
||||
Steve Barnegren
|
||||
|
||||
[Follow me on Twitter](https://twitter.com/stevebarnegren)
|
||||
Follow me on twitter [@SteveBarnegren](https://twitter.com/stevebarnegren)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+5
-12
@@ -8,8 +8,8 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'SwiftChess'
|
||||
s.version = '0.1.0'
|
||||
s.summary = 'A short description of SwiftChess.'
|
||||
s.version = '1.1'
|
||||
s.summary = 'Chess engine written in Swift'
|
||||
|
||||
# This description is used to generate tags and improve search results.
|
||||
# * Think: What does it do? Why did you write it? What is the focus?
|
||||
@@ -18,25 +18,18 @@ Pod::Spec.new do |s|
|
||||
# * Finally, don't worry about the indent, CocoaPods strips it!
|
||||
|
||||
s.description = <<-DESC
|
||||
TODO: Add long description of the pod here.
|
||||
Chess engine written in Swift, support player vs player, and player vs AI games.
|
||||
DESC
|
||||
|
||||
s.homepage = 'https://github.com/SteveBarnegren/SwiftChess'
|
||||
# s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
s.author = { 'Steve Barnegren' => 'steve.barnegren@gmail.com' }
|
||||
s.source = { :git => 'https://github.com/SteveBarnegren/SwiftChess.git', :tag => s.version.to_s }
|
||||
# s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
|
||||
s.social_media_url = 'https://twitter.com/stevebarnegren'
|
||||
s.swift_version = '5.0'
|
||||
|
||||
s.ios.deployment_target = '8.0'
|
||||
|
||||
s.source_files = 'SwiftChess/Source/**/*'
|
||||
|
||||
# s.resource_bundles = {
|
||||
# 'SwiftChess' => ['SwiftChess/Assets/*.png']
|
||||
# }
|
||||
|
||||
# s.public_header_files = 'Pod/Classes/**/*.h'
|
||||
# s.frameworks = 'UIKit', 'MapKit'
|
||||
# s.dependency 'AFNetworking', '~> 2.3'
|
||||
end
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
disabled_rules:
|
||||
- trailing_whitespace
|
||||
- cyclomatic_complexity
|
||||
- nesting
|
||||
- type_name
|
||||
- force_cast
|
||||
- identifier_name
|
||||
@@ -8,51 +8,107 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct AIConfiguration {
|
||||
|
||||
// BoardRater - Count Pieces
|
||||
var boardRaterCountPiecesWeighting: Double!
|
||||
public struct AIConfiguration {
|
||||
|
||||
// BoardRater - Board Dominance
|
||||
var boardRaterBoardDominanceWeighting: Double!
|
||||
|
||||
// BoardRater - Center Ownership
|
||||
var boardRaterCenterOwnershipWeighting: Double!
|
||||
|
||||
// BoardRater - Center Dominance
|
||||
var boardRaterCenterDominanceWeighting: Double!
|
||||
|
||||
// BoardRater - Threatened Pieces
|
||||
var boardRaterThreatenedPiecesWeighting: Double!
|
||||
var boardRaterThreatenedPiecesOwnPiecesMultiplier: Double!
|
||||
|
||||
// BoardRater - Pawn Progression
|
||||
var boardRaterPawnProgressionWeighting: Double!
|
||||
|
||||
// BoardRater - King Surrounding Possession
|
||||
var boardRaterKingSurroundingPossessionWeighting: Double!
|
||||
|
||||
// BoardRater - Check Mate Opportunity
|
||||
var boardRaterCheckMateOpportunityWeighting: Double!
|
||||
|
||||
// BoardRater - Center Four Occupation
|
||||
var boardRaterCenterFourOccupationWeighting: Double!
|
||||
|
||||
init() {
|
||||
setDefualtValues()
|
||||
public enum Difficulty: Int {
|
||||
case easy
|
||||
case medium
|
||||
case hard
|
||||
}
|
||||
|
||||
mutating func setDefualtValues() {
|
||||
boardRaterCountPiecesWeighting = 3 //1
|
||||
boardRaterBoardDominanceWeighting = 0.1
|
||||
boardRaterCenterOwnershipWeighting = 0.3
|
||||
boardRaterCenterDominanceWeighting = 0.3
|
||||
boardRaterCenterFourOccupationWeighting = 0.3
|
||||
boardRaterThreatenedPiecesWeighting = 1 // 1.5
|
||||
boardRaterThreatenedPiecesOwnPiecesMultiplier = 20 // Higher values will be more defensive
|
||||
boardRaterPawnProgressionWeighting = 1
|
||||
boardRaterKingSurroundingPossessionWeighting = 0.3
|
||||
boardRaterCheckMateOpportunityWeighting = 2
|
||||
struct ConfigurationValue {
|
||||
let easyValue: Double
|
||||
let difficultValue: Double
|
||||
let multiplier: Double
|
||||
|
||||
var value: Double {
|
||||
return easyValue + ((difficultValue - easyValue) * multiplier)
|
||||
}
|
||||
}
|
||||
|
||||
public let difficulty: Difficulty!
|
||||
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) {
|
||||
|
||||
self.difficulty = difficulty
|
||||
|
||||
let multiplier: Double
|
||||
|
||||
switch difficulty {
|
||||
case .easy: multiplier = 0
|
||||
case .medium: multiplier = 0.5
|
||||
case .hard: multiplier = 1
|
||||
}
|
||||
|
||||
func makeValue(_ easyValue: Double, _ hardValue: Double) -> ConfigurationValue {
|
||||
return ConfigurationValue(easyValue: easyValue, difficultValue: hardValue, multiplier: multiplier)
|
||||
}
|
||||
|
||||
suicideMultipler = makeValue(0, 0)
|
||||
boardRaterCountPiecesWeighting = makeValue(3, 3)
|
||||
boardRaterBoardDominanceWeighting = makeValue(0, 0.1)
|
||||
boardRaterCenterOwnershipWeighting = makeValue(0.1, 0.3)
|
||||
boardRaterCenterDominanceWeighting = makeValue(0, 0.3)
|
||||
boardRaterThreatenedPiecesWeighting = makeValue(0, 1.5)
|
||||
boardRaterPawnProgressionWeighting = makeValue(0.1, 1)
|
||||
boardRaterKingSurroundingPossessionWeighting = makeValue(0, 0.3)
|
||||
boardRaterCheckMateOpportunityWeighting = makeValue(0, 2)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,18 @@
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
// swiftlint:disable for_where
|
||||
import Foundation
|
||||
|
||||
open class AIPlayer : Player {
|
||||
public final class AIPlayer: Player {
|
||||
|
||||
let boardRaters : [BoardRater]!
|
||||
let configuration = AIConfiguration() // <-- We should pass this in eventually
|
||||
let boardRaters: [BoardRater]!
|
||||
public let configuration: AIConfiguration!
|
||||
var openingMoves = [OpeningMove]()
|
||||
|
||||
public init(color: Color){
|
||||
public init(color: Color, configuration: AIConfiguration) {
|
||||
|
||||
self.configuration = configuration
|
||||
|
||||
self.boardRaters = [
|
||||
BoardRaterCountPieces(configuration: configuration),
|
||||
@@ -29,28 +31,40 @@ open class AIPlayer : Player {
|
||||
BoardRaterCenterFourOccupation(configuration: configuration)
|
||||
]
|
||||
|
||||
openingMoves = Opening.allOpeningMoves(forColor: color)
|
||||
openingMoves = Opening.allOpeningMoves(for: color)
|
||||
|
||||
super.init()
|
||||
self.color = color
|
||||
}
|
||||
|
||||
public func makeMove() {
|
||||
public func makeMoveAsync() {
|
||||
|
||||
print("\n\n****** Make Move ******");
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
self.makeMoveSync()
|
||||
}
|
||||
}
|
||||
|
||||
public func makeMoveSync() {
|
||||
|
||||
//print("\n\n****** Make Move ******");
|
||||
|
||||
// Check that the game is in progress
|
||||
guard game.state == .inProgress else {
|
||||
return
|
||||
}
|
||||
|
||||
let board = game.board
|
||||
|
||||
|
||||
var move: Move!
|
||||
|
||||
// Get an opening move
|
||||
if let openingMove = openingMoveForBoard(board){
|
||||
print("Playing opening move")
|
||||
if let openingMove = openingMove(for: board) {
|
||||
//print("Playing opening move")
|
||||
move = openingMove
|
||||
}
|
||||
// Or, get the Highest rated move
|
||||
else{
|
||||
move = highestRatedMoveOnBoard(board)
|
||||
else {
|
||||
move = highestRatedMove(on: board)
|
||||
}
|
||||
|
||||
// Make move
|
||||
@@ -58,45 +72,49 @@ open class AIPlayer : Player {
|
||||
|
||||
switch move.type {
|
||||
case .singlePiece(let sourceLocation, let targetLocation):
|
||||
operations = game.board.movePiece(fromLocation: sourceLocation, toLocation: targetLocation)
|
||||
print("Chose move (\(sourceLocation.x),\(sourceLocation.y)) -> (\(targetLocation.x),\(targetLocation.y))");
|
||||
operations = game.board.movePiece(from: sourceLocation, to: targetLocation)
|
||||
case .castle(let color, let side):
|
||||
operations = game.board.performCastle(color: color, side: side)
|
||||
print("Chose Castling move");
|
||||
}
|
||||
|
||||
// Promote pawns
|
||||
let pawnsToPromoteLocations = game.board.getLocationsOfPromotablePawns(color: color)
|
||||
assert(pawnsToPromoteLocations.count < 2, "There should only ever be one pawn to promote at any time")
|
||||
if pawnsToPromoteLocations.count > 0 {
|
||||
game.board = promotePawnsOnBoard(game.board)
|
||||
game.board = promotePawns(on: game.board)
|
||||
|
||||
let location = pawnsToPromoteLocations.first!
|
||||
let transformOperation = BoardOperation(type: .transformPiece, piece: game.board.getPiece(at: location)!, location: location)
|
||||
let transformOperation = BoardOperation(type: .transformPiece,
|
||||
piece: game.board.getPiece(at: location)!,
|
||||
location: location)
|
||||
operations.append(transformOperation)
|
||||
}
|
||||
|
||||
self.game.playerDidMakeMove(player: self, boardOperations: operations)
|
||||
let strongGame = self.game!
|
||||
DispatchQueue.main.async {
|
||||
strongGame.playerDidMakeMove(player: self, boardOperations: operations)
|
||||
}
|
||||
}
|
||||
|
||||
func openingMoveForBoard(_ board: Board) -> Move? {
|
||||
func openingMove(for board: Board) -> Move? {
|
||||
|
||||
let possibleMoves = openingMoves.filter{
|
||||
let possibleMoves = openingMoves.filter {
|
||||
$0.board == board
|
||||
}
|
||||
|
||||
guard possibleMoves.count > 0 else{
|
||||
guard possibleMoves.count > 0 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let openingMove = possibleMoves[Int(arc4random()) % possibleMoves.count]
|
||||
let index = Int(arc4random_uniform(UInt32(possibleMoves.count)))
|
||||
let openingMove = possibleMoves[index]
|
||||
|
||||
return Move(type: .singlePiece(sourceLocation: openingMove.fromLocation,
|
||||
targetLocation: openingMove.toLocation),
|
||||
return Move(type: .singlePiece(from: openingMove.fromLocation,
|
||||
to: openingMove.toLocation),
|
||||
rating: 0)
|
||||
}
|
||||
|
||||
func highestRatedMoveOnBoard(_ board: Board) -> Move {
|
||||
func highestRatedMove(on board: Board) -> Move {
|
||||
|
||||
var possibleMoves = [Move]()
|
||||
|
||||
@@ -112,28 +130,33 @@ open class AIPlayer : Player {
|
||||
|
||||
for targetLocation in BoardLocation.all {
|
||||
|
||||
guard canAIMovePiece(fromLocation: sourceLocation, toLocation: targetLocation) else {
|
||||
guard canAIMovePiece(from: sourceLocation, to: targetLocation) else {
|
||||
continue
|
||||
}
|
||||
|
||||
// Make move
|
||||
var resultBoard = board
|
||||
resultBoard.movePiece(fromLocation: sourceLocation, toLocation: targetLocation)
|
||||
resultBoard.movePiece(from: sourceLocation, to: targetLocation)
|
||||
|
||||
// Promote pawns
|
||||
let pawnsToPromoteLocations = resultBoard.getLocationsOfPromotablePawns(color: color)
|
||||
assert(pawnsToPromoteLocations.count < 2, "There should only ever be one pawn to promote at any time")
|
||||
if pawnsToPromoteLocations.count > 0 {
|
||||
resultBoard = promotePawnsOnBoard(resultBoard)
|
||||
resultBoard = promotePawns(on: resultBoard)
|
||||
}
|
||||
|
||||
// Rate
|
||||
print("(\(sourceLocation.x),\(sourceLocation.y)) -> (\(targetLocation.x),\(targetLocation.y))")
|
||||
let rating = ratingForBoard(resultBoard)
|
||||
let move = Move(type: .singlePiece(sourceLocation: sourceLocation, targetLocation: targetLocation),
|
||||
var rating = ratingForBoard(resultBoard)
|
||||
|
||||
// reduce rating if suicide
|
||||
if resultBoard.canColorMoveAnyPieceToLocation(color: color.opposite, location: targetLocation) {
|
||||
rating -= (abs(rating) * configuration.suicideMultipler.value)
|
||||
}
|
||||
|
||||
let move = Move(type: .singlePiece(from: sourceLocation, to: targetLocation),
|
||||
rating: rating)
|
||||
possibleMoves.append(move)
|
||||
print("Rating: \(rating)")
|
||||
// print("Rating: \(rating)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,11 +178,11 @@ open class AIPlayer : Player {
|
||||
possibleMoves.append(move)
|
||||
}
|
||||
|
||||
print("Found \(possibleMoves.count) possible moves")
|
||||
//print("Found \(possibleMoves.count) possible moves")
|
||||
|
||||
// If there are no possible moves, we must be in stale mate
|
||||
if possibleMoves.count == 0 {
|
||||
print("There are no possible moves!!!!");
|
||||
print("There are no possible moves!!!!")
|
||||
}
|
||||
|
||||
// Choose move with highest rating
|
||||
@@ -170,51 +193,48 @@ open class AIPlayer : Player {
|
||||
|
||||
if move.rating > highestRating {
|
||||
highestRating = move.rating
|
||||
highestRatedMove = move;
|
||||
highestRatedMove = move
|
||||
}
|
||||
|
||||
//print("rating: \(move.rating)")
|
||||
}
|
||||
|
||||
return highestRatedMove;
|
||||
return highestRatedMove
|
||||
}
|
||||
|
||||
func canAIMovePiece(fromLocation: BoardLocation, toLocation: BoardLocation) -> Bool {
|
||||
func canAIMovePiece(from fromLocation: BoardLocation, to toLocation: BoardLocation) -> Bool {
|
||||
|
||||
// This is a stricter version of the canMove function, used by the AI, that returns false for errors
|
||||
|
||||
let canMove = canMovePieceWithError(fromLocation: fromLocation, toLocation: toLocation)
|
||||
if canMove.error != nil {
|
||||
do {
|
||||
return try canMovePiece(from: fromLocation, to: toLocation)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
|
||||
return canMove.result
|
||||
}
|
||||
|
||||
|
||||
func ratingForBoard(_ board: Board) -> Double {
|
||||
|
||||
var rating: Double = 0;
|
||||
var rating: Double = 0
|
||||
|
||||
for boardRater in boardRaters {
|
||||
|
||||
let result = boardRater.ratingfor(board: board, color: color)
|
||||
let result = boardRater.ratingFor(board: board, color: color)
|
||||
|
||||
let className = "\(boardRater)"
|
||||
print("\t\(className): \(result)")
|
||||
//let className = "\(boardRater)"
|
||||
//print("\t\(className): \(result)")
|
||||
rating += result
|
||||
}
|
||||
|
||||
// If opponent is in check mate, set the maximum rating
|
||||
if board.isColorInCheckMate(color: color.opposite()) {
|
||||
if board.isColorInCheckMate(color: color.opposite) {
|
||||
rating = Double.greatestFiniteMagnitude
|
||||
}
|
||||
|
||||
return rating
|
||||
}
|
||||
|
||||
|
||||
func promotePawnsOnBoard(_ board: Board) -> Board {
|
||||
func promotePawns(on board: Board) -> Board {
|
||||
|
||||
let pawnsToPromoteLocations = board.getLocationsOfPromotablePawns(color: color)
|
||||
|
||||
@@ -226,31 +246,29 @@ open class AIPlayer : Player {
|
||||
|
||||
let location = pawnsToPromoteLocations.first!
|
||||
|
||||
guard let piece = board.getPiece(at: location) else {
|
||||
guard board.getPiece(at: location) != nil else {
|
||||
return board
|
||||
}
|
||||
|
||||
// Get the ratings
|
||||
var bestType = Piece.PieceType.possiblePawnPromotionResultingTypes().first
|
||||
var bestRating = -Double.greatestFiniteMagnitude
|
||||
var highestRating = -Double.greatestFiniteMagnitude
|
||||
var promotedBoard: Board!
|
||||
|
||||
for pieceType in Piece.PieceType.possiblePawnPromotionResultingTypes() {
|
||||
|
||||
var newBoard = board
|
||||
|
||||
guard let piece = newBoard.getPiece(at: location) else {
|
||||
guard newBoard.getPiece(at: location) != nil else {
|
||||
return board
|
||||
}
|
||||
|
||||
let newPiece = newBoard.getPiece(at: location)?.byChangingType(newType: pieceType)
|
||||
newBoard.squares[location.index].piece = newPiece
|
||||
|
||||
newBoard.setPiece(newPiece!, at: location)
|
||||
|
||||
let rating = ratingForBoard(newBoard)
|
||||
|
||||
if rating > bestRating {
|
||||
bestRating = rating
|
||||
bestType = pieceType
|
||||
if rating > highestRating {
|
||||
highestRating = rating
|
||||
promotedBoard = newBoard
|
||||
}
|
||||
|
||||
@@ -260,10 +278,45 @@ 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 {
|
||||
case singlePiece(sourceLocation: BoardLocation, targetLocation: BoardLocation)
|
||||
case singlePiece(from: BoardLocation, to: BoardLocation)
|
||||
case castle(color: Color, side: CastleSide)
|
||||
}
|
||||
|
||||
@@ -271,7 +324,7 @@ struct Move {
|
||||
let rating: Double
|
||||
}
|
||||
|
||||
// MARK - BoardRater
|
||||
// MARK: - BoardRater
|
||||
|
||||
internal class BoardRater {
|
||||
|
||||
@@ -281,11 +334,7 @@ internal class BoardRater {
|
||||
self.configuration = configuration
|
||||
}
|
||||
|
||||
func ratingfor(board: Board, color: Color) -> Double{
|
||||
func ratingFor(board: Board, color: Color) -> Double {
|
||||
fatalError("Override ratingFor method in subclasses")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,19 +7,18 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftChess
|
||||
|
||||
func transformASCIIBoardInput(_ input: String) -> String{
|
||||
func transformASCIIBoardInput(_ input: String) -> String {
|
||||
|
||||
let boardArt = input.replacingOccurrences(of: " ", with: "")
|
||||
|
||||
var transformedArt = String()
|
||||
|
||||
for y in (0...7).reversed(){
|
||||
for y in (0...7).reversed() {
|
||||
for x in 0...7 {
|
||||
|
||||
let index = y*8 + x
|
||||
transformedArt.append(boardArt[boardArt.characters.index(boardArt.startIndex, offsetBy: index)])
|
||||
transformedArt.append(boardArt[boardArt.index(boardArt.startIndex, offsetBy: index)])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,103 +31,6 @@ public struct ASCIIBoard {
|
||||
let artString: String
|
||||
var stringContainsColors: Bool!
|
||||
|
||||
public init(
|
||||
// Row 8
|
||||
_ a8: Character,
|
||||
_ b8: Character,
|
||||
_ c8: Character,
|
||||
_ d8: Character,
|
||||
_ e8: Character,
|
||||
_ f8: Character,
|
||||
_ g8: Character,
|
||||
_ h8: Character,
|
||||
// Row 7
|
||||
_ a7: Character,
|
||||
_ b7: Character,
|
||||
_ c7: Character,
|
||||
_ d7: Character,
|
||||
_ e7: Character,
|
||||
_ f7: Character,
|
||||
_ g7: Character,
|
||||
_ h7: Character,
|
||||
// Row 6
|
||||
_ a6: Character,
|
||||
_ b6: Character,
|
||||
_ c6: Character,
|
||||
_ d6: Character,
|
||||
_ e6: Character,
|
||||
_ f6: Character,
|
||||
_ g6: Character,
|
||||
_ h6: Character,
|
||||
|
||||
// Row 5
|
||||
_ a5: Character,
|
||||
_ b5: Character,
|
||||
_ c5: Character,
|
||||
_ d5: Character,
|
||||
_ e5: Character,
|
||||
_ f5: Character,
|
||||
_ g5: Character,
|
||||
_ h5: Character,
|
||||
// Row 4
|
||||
_ a4: Character,
|
||||
_ b4: Character,
|
||||
_ c4: Character,
|
||||
_ d4: Character,
|
||||
_ e4: Character,
|
||||
_ f4: Character,
|
||||
_ g4: Character,
|
||||
_ h4: Character,
|
||||
// Row 3
|
||||
_ a3: Character,
|
||||
_ b3: Character,
|
||||
_ c3: Character,
|
||||
_ d3: Character,
|
||||
_ e3: Character,
|
||||
_ f3: Character,
|
||||
_ g3: Character,
|
||||
_ h3: Character,
|
||||
// Row 2
|
||||
_ a2: Character,
|
||||
_ b2: Character,
|
||||
_ c2: Character,
|
||||
_ d2: Character,
|
||||
_ e2: Character,
|
||||
_ f2: Character,
|
||||
_ g2: Character,
|
||||
_ h2: Character,
|
||||
// Row 1
|
||||
_ a1: Character,
|
||||
_ b1: Character,
|
||||
_ c1: Character,
|
||||
_ d1: Character,
|
||||
_ e1: Character,
|
||||
_ f1: Character,
|
||||
_ g1: Character,
|
||||
_ h1: Character
|
||||
){
|
||||
|
||||
var inputAsString =
|
||||
"\(a8) \(b8) \(c8) \(d8) \(e8) \(f8) \(g8) \(h8)" +
|
||||
"\(a7) \(b7) \(c7) \(d7) \(e7) \(f7) \(g7) \(h7)" +
|
||||
"\(a6) \(b6) \(c6) \(d6) \(e6) \(f6) \(g6) \(h6)" +
|
||||
"\(a5) \(b5) \(c5) \(d5) \(e5) \(f5) \(g5) \(h5)" +
|
||||
"\(a4) \(b4) \(c4) \(d4) \(e4) \(f4) \(g4) \(h4)" +
|
||||
"\(a3) \(b3) \(c3) \(d3) \(e3) \(f3) \(g3) \(h3)" +
|
||||
"\(a2) \(b2) \(c2) \(d2) \(e2) \(f2) \(g2) \(h2)" +
|
||||
"\(a1) \(b1) \(c1) \(d1) \(e1) \(f1) \(g1) \(h1)";
|
||||
|
||||
// Transform
|
||||
inputAsString = transformASCIIBoardInput(inputAsString)
|
||||
|
||||
// Check string format
|
||||
assert(inputAsString.characters.count == 64, "ASCII board art must be 128 characters long")
|
||||
|
||||
self.artString = inputAsString
|
||||
self.stringContainsColors = false
|
||||
|
||||
}
|
||||
|
||||
public init(pieces artString: String) {
|
||||
|
||||
var artString = artString
|
||||
@@ -137,7 +39,11 @@ public struct ASCIIBoard {
|
||||
artString = transformASCIIBoardInput(artString)
|
||||
|
||||
// Check string format
|
||||
#if swift(>=3.2)
|
||||
assert(artString.count == 64, "ASCII board art must be 128 characters long")
|
||||
#else
|
||||
assert(artString.characters.count == 64, "ASCII board art must be 128 characters long")
|
||||
#endif
|
||||
|
||||
self.artString = artString
|
||||
self.stringContainsColors = false
|
||||
@@ -163,21 +69,26 @@ public struct ASCIIBoard {
|
||||
var board = Board(state: .empty)
|
||||
|
||||
// Clear all pieces on the board
|
||||
(0..<64).forEach{
|
||||
board.squares[$0].piece = nil;
|
||||
BoardLocation.all.forEach {
|
||||
board.removePiece(at: $0)
|
||||
}
|
||||
|
||||
// Setup pieces from ascii art
|
||||
(0..<64).forEach{
|
||||
(0..<64).forEach {
|
||||
#if swift(>=3.2)
|
||||
let character = boardArt[boardArt.index(boardArt.startIndex, offsetBy: $0)]
|
||||
#else
|
||||
let character = boardArt[boardArt.characters.index(boardArt.startIndex, offsetBy: $0)]
|
||||
board.squares[$0].piece = pieceFromCharacter(character)
|
||||
#endif
|
||||
if let piece = piece(from: character) {
|
||||
board.setPiece(piece, at: BoardLocation(index: $0))
|
||||
}
|
||||
}
|
||||
|
||||
return board
|
||||
}
|
||||
|
||||
|
||||
func pieceFromCharacter(_ character: Character) -> Piece? {
|
||||
func piece(from character: Character) -> Piece? {
|
||||
|
||||
var piece: Piece?
|
||||
|
||||
@@ -213,13 +124,19 @@ public struct ASCIIBoard {
|
||||
return piece
|
||||
}
|
||||
|
||||
public func indexOfCharacter(_ character: Character) -> Int{
|
||||
public func indexOfCharacter(_ character: Character) -> Int {
|
||||
|
||||
var index: Int?
|
||||
|
||||
#if swift(>=3.2)
|
||||
if let idx = artString.firstIndex(of: character) {
|
||||
index = artString.distance(from: artString.startIndex, to: idx)
|
||||
}
|
||||
#else
|
||||
if let idx = artString.characters.index(of: character) {
|
||||
index = artString.characters.distance(from: artString.startIndex, to: idx)
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(index != nil, "Unable to find index of character: \(character)")
|
||||
return index!
|
||||
@@ -231,12 +148,16 @@ public struct ASCIIBoard {
|
||||
return BoardLocation(index: index)
|
||||
}
|
||||
|
||||
public func indexesWithCharacter(_ character: Character) -> [Int]{
|
||||
public func indexesWithCharacter(_ character: Character) -> [Int] {
|
||||
|
||||
var indexes = [Int]()
|
||||
|
||||
(0..<64).forEach{
|
||||
(0..<64).forEach {
|
||||
#if swift(>=3.2)
|
||||
let aCharacter = artString[artString.index(artString.startIndex, offsetBy: $0)]
|
||||
#else
|
||||
let aCharacter = artString[artString.characters.index(artString.startIndex, offsetBy: $0)]
|
||||
#endif
|
||||
if character == aCharacter {
|
||||
indexes.append($0)
|
||||
}
|
||||
@@ -251,7 +172,7 @@ public struct ASCIIBoard {
|
||||
|
||||
var locations = [BoardLocation]()
|
||||
|
||||
indexes.forEach{
|
||||
indexes.forEach {
|
||||
let location = BoardLocation(index: $0)
|
||||
locations.append(location)
|
||||
}
|
||||
|
||||
+153
-89
@@ -6,6 +6,9 @@
|
||||
//
|
||||
//
|
||||
|
||||
// swiftlint:disable file_length
|
||||
// swiftlint:disable type_body_length
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum CastleSide {
|
||||
@@ -15,36 +18,60 @@ public enum CastleSide {
|
||||
|
||||
// MARK: - ****** Square ******
|
||||
|
||||
public struct Square : Equatable {
|
||||
public struct Square: Equatable {
|
||||
|
||||
public var piece: Piece?
|
||||
|
||||
}
|
||||
|
||||
public func ==(lhs: Square, rhs: Square) -> Bool {
|
||||
public func == (lhs: Square, rhs: Square) -> Bool {
|
||||
|
||||
switch (lhs.piece, rhs.piece) {
|
||||
case (.none, .none):
|
||||
return true
|
||||
case (.some, .none):
|
||||
return true
|
||||
case (.none, .some):
|
||||
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 {
|
||||
public struct Board: Equatable {
|
||||
|
||||
public enum InitialState {
|
||||
case empty
|
||||
case newGame
|
||||
}
|
||||
|
||||
public var squares = [Square]()
|
||||
public private(set) var squares = [Square]()
|
||||
private var lastAssignedPieceTag = 0
|
||||
|
||||
// MARK: - Init
|
||||
public init(state: InitialState) {
|
||||
@@ -58,54 +85,55 @@ public struct Board {
|
||||
if state == .newGame {
|
||||
setupForNewGame()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mutating func setupForNewGame() {
|
||||
|
||||
// Setup white bottom row
|
||||
squares[0].piece = Piece(type: .rook, color: .white)
|
||||
squares[1].piece = Piece(type: .knight, color: .white)
|
||||
squares[2].piece = Piece(type: .bishop, color: .white)
|
||||
squares[3].piece = Piece(type: .queen, color: .white)
|
||||
squares[4].piece = Piece(type: .king, color: .white)
|
||||
squares[5].piece = Piece(type: .bishop, color: .white)
|
||||
squares[6].piece = Piece(type: .knight, color: .white)
|
||||
squares[7].piece = Piece(type: .rook, color: .white)
|
||||
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(makePiece(type: pieces[i], color: .white), at: BoardLocation(index: i))
|
||||
}
|
||||
|
||||
// Setup white pawn row
|
||||
for i in 8...15 {
|
||||
squares[i].piece = Piece(type: .pawn, color: .white)
|
||||
setPiece(makePiece(type: .pawn, color: .white), at: BoardLocation(index: i))
|
||||
}
|
||||
|
||||
// Setup black bottom row
|
||||
squares[63].piece = Piece(type: .rook, color: .black)
|
||||
squares[62].piece = Piece(type: .knight, color: .black)
|
||||
squares[61].piece = Piece(type: .bishop, color: .black)
|
||||
squares[60].piece = Piece(type: .queen, color: .black)
|
||||
squares[59].piece = Piece(type: .king, color: .black)
|
||||
squares[58].piece = Piece(type: .bishop, color: .black)
|
||||
squares[57].piece = Piece(type: .knight, color: .black)
|
||||
squares[56].piece = Piece(type: .rook, color: .black)
|
||||
for i in 56...63 {
|
||||
setPiece(makePiece(type: pieces[i-56], color: .black), at: BoardLocation(index: i))
|
||||
}
|
||||
|
||||
// Setup black pawn row
|
||||
for i in 48...55 {
|
||||
squares[i].piece = Piece(type: .pawn, color: .black)
|
||||
setPiece(makePiece(type: .pawn, color: .black), at: BoardLocation(index: i))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Manipulate Pieces
|
||||
|
||||
public mutating func setPiece(_ piece: Piece, at location: BoardLocation) {
|
||||
squares[location.index].piece = piece
|
||||
squares[location.index].piece?.location = location
|
||||
}
|
||||
|
||||
public func getPiece(at location: BoardLocation) -> Piece? {
|
||||
return squares[location.index].piece
|
||||
}
|
||||
|
||||
@discardableResult internal mutating func movePiece(fromLocation: BoardLocation, toLocation: BoardLocation) -> [BoardOperation] {
|
||||
public mutating func removePiece(at location: BoardLocation) {
|
||||
squares[location.index].piece = nil
|
||||
}
|
||||
|
||||
@discardableResult internal mutating func movePiece(from fromLocation: BoardLocation,
|
||||
to toLocation: BoardLocation) -> [BoardOperation] {
|
||||
|
||||
if toLocation == fromLocation {
|
||||
return []
|
||||
@@ -113,7 +141,7 @@ public struct Board {
|
||||
|
||||
var operations = [BoardOperation]()
|
||||
|
||||
guard var movingPiece = getPiece(at: fromLocation) else {
|
||||
guard let movingPiece = getPiece(at: fromLocation) else {
|
||||
fatalError("There is no piece on at (\(fromLocation.x),\(fromLocation.y))")
|
||||
}
|
||||
|
||||
@@ -126,6 +154,7 @@ public struct Board {
|
||||
}
|
||||
|
||||
squares[toLocation.index].piece = self.squares[fromLocation.index].piece
|
||||
squares[toLocation.index].piece?.location = toLocation
|
||||
squares[toLocation.index].piece?.hasMoved = true
|
||||
squares[fromLocation.index].piece = nil
|
||||
|
||||
@@ -134,14 +163,16 @@ public struct Board {
|
||||
|
||||
let stride = fromLocation.strideTo(location: toLocation)
|
||||
let enPassentStride = BoardStride(x: stride.x, y: 0)
|
||||
let enPassentLocation = fromLocation.incrementedBy(stride: enPassentStride)
|
||||
let enPassentLocation = fromLocation.incremented(by: enPassentStride)
|
||||
|
||||
guard let enPassentPiece = getPiece(at: enPassentLocation) else {
|
||||
break IF_EN_PASSANT
|
||||
}
|
||||
|
||||
if enPassentPiece.canBeTakenByEnPassant && enPassentPiece.color == movingPiece.color.opposite() {
|
||||
squares[enPassentLocation.index].piece = nil;
|
||||
if enPassentPiece.canBeTakenByEnPassant && enPassentPiece.color == movingPiece.color.opposite {
|
||||
squares[enPassentLocation.index].piece = nil
|
||||
let operation = BoardOperation(type: .removePiece, piece: enPassentPiece, location: enPassentLocation)
|
||||
operations.append(operation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,17 +208,18 @@ public struct Board {
|
||||
|
||||
for square in squares {
|
||||
|
||||
guard let piece = square.piece else{
|
||||
guard let piece = square.piece else {
|
||||
continue
|
||||
}
|
||||
|
||||
if piece == Piece(type: .king, color: color) {
|
||||
if piece.isSameTypeAndColor(asPiece: Piece(type: .king, color: color)) {
|
||||
king = piece
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// We'll implicitly unwrap this, because there should always be a king for each color on the board. If there isn't, it's an error
|
||||
// We'll implicitly unwrap this, because there should always be a king for each color on the board.
|
||||
// If there isn't, it's an error
|
||||
return king!
|
||||
}
|
||||
|
||||
@@ -195,7 +227,7 @@ public struct Board {
|
||||
|
||||
for (index, square) in squares.enumerated() {
|
||||
|
||||
guard let piece = square.piece else{
|
||||
guard let piece = square.piece else {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -207,7 +239,7 @@ public struct Board {
|
||||
fatalError("Couldn't find \(color) king. Kings should always exist")
|
||||
}
|
||||
|
||||
public func getLocationsOfColor(_ color: Color) -> [BoardLocation] {
|
||||
public func getLocations(of color: Color) -> [BoardLocation] {
|
||||
|
||||
var locations = [BoardLocation]()
|
||||
|
||||
@@ -231,7 +263,7 @@ public struct Board {
|
||||
|
||||
for square in squares {
|
||||
|
||||
guard let piece = square.piece else{
|
||||
guard let piece = square.piece else {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -290,7 +322,7 @@ public struct Board {
|
||||
}
|
||||
|
||||
// Work out if we're in check
|
||||
let oppositionLocations = getLocationsOfColor( color.opposite() )
|
||||
let oppositionLocations = getLocations(of: color.opposite)
|
||||
|
||||
// Pieces will not move to take the king, so change it for a pawn of the same color
|
||||
var noKingBoard = self
|
||||
@@ -302,7 +334,7 @@ public struct Board {
|
||||
continue
|
||||
}
|
||||
|
||||
if piece.movement.canPieceMove(fromLocation: location, toLocation: kingLocation!, board: noKingBoard) {
|
||||
if piece.movement.canPieceMove(from: location, to: kingLocation!, board: noKingBoard) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -316,7 +348,7 @@ public struct Board {
|
||||
return false
|
||||
}
|
||||
|
||||
for pieceLocation in getLocationsOfColor( color ) {
|
||||
for pieceLocation in getLocations(of: color) {
|
||||
|
||||
guard let piece = getPiece(at: pieceLocation) else {
|
||||
continue
|
||||
@@ -324,13 +356,11 @@ public struct Board {
|
||||
|
||||
for targetLocation in BoardLocation.all {
|
||||
|
||||
let canMove = piece.movement.canPieceMove(fromLocation: pieceLocation,
|
||||
toLocation: targetLocation,
|
||||
board: self)
|
||||
let canMove = piece.movement.canPieceMove(from: pieceLocation, to: targetLocation, board: self)
|
||||
|
||||
if canMove {
|
||||
var resultBoard = self
|
||||
resultBoard.movePiece(fromLocation: pieceLocation, toLocation: targetLocation)
|
||||
resultBoard.movePiece(from: pieceLocation, to: targetLocation)
|
||||
if resultBoard.isColorInCheck(color: color) == false {
|
||||
return false
|
||||
}
|
||||
@@ -345,15 +375,14 @@ public struct Board {
|
||||
|
||||
if !isColorAbleToMove(color: color) && !isColorInCheckMate(color: color) {
|
||||
return true
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isColorAbleToMove(color: Color) -> Bool {
|
||||
|
||||
for pieceLocation in getLocationsOfColor(color) {
|
||||
for pieceLocation in getLocations(of: color) {
|
||||
|
||||
guard let piece = getPiece(at: pieceLocation) else {
|
||||
continue
|
||||
@@ -361,16 +390,14 @@ public struct Board {
|
||||
|
||||
for targetLocation in BoardLocation.all {
|
||||
|
||||
let canMove = piece.movement.canPieceMove(fromLocation: pieceLocation,
|
||||
toLocation: targetLocation,
|
||||
board: self)
|
||||
let canMove = piece.movement.canPieceMove(from: pieceLocation, to: targetLocation, board: self)
|
||||
|
||||
guard canMove == true else {
|
||||
continue
|
||||
}
|
||||
|
||||
var resultBoard = self
|
||||
resultBoard.movePiece(fromLocation: pieceLocation, toLocation: targetLocation)
|
||||
resultBoard.movePiece(from: pieceLocation, to: targetLocation)
|
||||
if resultBoard.isColorInCheck(color: color) == false {
|
||||
return true
|
||||
}
|
||||
@@ -394,7 +421,7 @@ public struct Board {
|
||||
continue
|
||||
}
|
||||
|
||||
if piece.movement.canPieceMove(fromLocation: BoardLocation(index: index), toLocation: location, board: self) {
|
||||
if piece.movement.canPieceMove(from: BoardLocation(index: index), to: location, board: self) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -413,14 +440,14 @@ public struct Board {
|
||||
|
||||
public func possibleMoveLocationsForPiece(atLocation location: BoardLocation) -> [BoardLocation] {
|
||||
|
||||
guard let piece = squares[location.index].piece else{
|
||||
guard let piece = squares[location.index].piece else {
|
||||
return []
|
||||
}
|
||||
|
||||
var locations = [BoardLocation]()
|
||||
|
||||
BoardLocation.all.forEach{
|
||||
if piece.movement.canPieceMove(fromLocation: location, toLocation: $0, board: self){
|
||||
BoardLocation.all.forEach {
|
||||
if piece.movement.canPieceMove(from: location, to: $0, board: self) {
|
||||
locations.append($0)
|
||||
}
|
||||
}
|
||||
@@ -430,7 +457,7 @@ public struct Board {
|
||||
|
||||
// MARK: - Castling
|
||||
|
||||
struct CastleMove{
|
||||
struct CastleMove {
|
||||
let yPos: Int
|
||||
let kingStartXPos: Int
|
||||
let rookStartXPos: Int
|
||||
@@ -470,16 +497,16 @@ public struct Board {
|
||||
rookEndXPos = 3
|
||||
case (.black, .kingSide):
|
||||
yPos = 7
|
||||
kingStartXPos = 3
|
||||
rookStartXPos = 0
|
||||
kingEndXPos = 1
|
||||
rookEndXPos = 2
|
||||
kingStartXPos = 4
|
||||
rookStartXPos = 7
|
||||
kingEndXPos = 6
|
||||
rookEndXPos = 5
|
||||
case (.black, .queenSide):
|
||||
yPos = 7
|
||||
kingStartXPos = 3
|
||||
rookStartXPos = 7
|
||||
kingEndXPos = 5
|
||||
rookEndXPos = 4
|
||||
kingStartXPos = 4
|
||||
rookStartXPos = 0
|
||||
kingEndXPos = 2
|
||||
rookEndXPos = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -513,7 +540,9 @@ public struct Board {
|
||||
}
|
||||
|
||||
// Check that there are no pieces between the king and the rook
|
||||
for xPos in min(castleMove.kingStartXPos, castleMove.rookStartXPos)..<max(castleMove.kingStartXPos, castleMove.rookStartXPos) {
|
||||
let rStart = min(castleMove.kingStartXPos, castleMove.rookStartXPos)
|
||||
let rEnd = max(castleMove.kingStartXPos, castleMove.rookStartXPos)
|
||||
for xPos in rStart..<rEnd {
|
||||
|
||||
if xPos == castleMove.kingStartXPos || xPos == castleMove.rookStartXPos {
|
||||
continue
|
||||
@@ -521,7 +550,7 @@ public struct Board {
|
||||
|
||||
let location = BoardLocation(x: xPos, y: castleMove.yPos)
|
||||
|
||||
if let piece = getPiece(at: location) {
|
||||
if getPiece(at: location) != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -533,7 +562,9 @@ public struct Board {
|
||||
}
|
||||
|
||||
// Check that the king will not end up in, or move through check
|
||||
for xPos in min(castleMove.kingEndXPos, castleMove.kingStartXPos)...max(castleMove.kingEndXPos, castleMove.kingStartXPos) {
|
||||
let kStart = min(castleMove.kingEndXPos, castleMove.kingStartXPos)
|
||||
let kEnd = max(castleMove.kingEndXPos, castleMove.kingStartXPos)
|
||||
for xPos in kStart...kEnd {
|
||||
|
||||
if xPos == castleMove.kingStartXPos {
|
||||
continue
|
||||
@@ -541,7 +572,7 @@ public struct Board {
|
||||
|
||||
var newBoard = self
|
||||
let newLocation = BoardLocation(x: xPos, y: castleMove.yPos)
|
||||
newBoard.movePiece(fromLocation: castleMove.kingStartLocation, toLocation: newLocation)
|
||||
newBoard.movePiece(from: castleMove.kingStartLocation, to: newLocation)
|
||||
if newBoard.isColorInCheck(color: color) {
|
||||
return false
|
||||
}
|
||||
@@ -552,12 +583,15 @@ public struct Board {
|
||||
|
||||
@discardableResult internal mutating func performCastle(color: Color, side: CastleSide) -> [BoardOperation] {
|
||||
|
||||
assert(canColorCastle(color: color, side: side) == true, "\(color) is unable to castle on side \(side). Call canColorCastle(color: side:) first")
|
||||
assert(canColorCastle(color: color, side: side) == true,
|
||||
"\(color) is unable to castle on side \(side). Call canColorCastle(color: side:) first")
|
||||
|
||||
let castleMove = CastleMove(color: color, side: side)
|
||||
|
||||
let moveKingOperations = self.movePiece(fromLocation: castleMove.kingStartLocation, toLocation: castleMove.kingEndLocation)
|
||||
let moveRookOperations = self.movePiece(fromLocation: castleMove.rookStartLocation, toLocation: castleMove.rookEndLocation)
|
||||
let moveKingOperations = self.movePiece(from: castleMove.kingStartLocation,
|
||||
to: castleMove.kingEndLocation)
|
||||
let moveRookOperations = self.movePiece(from: castleMove.rookStartLocation,
|
||||
to: castleMove.rookEndLocation)
|
||||
|
||||
return moveKingOperations + moveRookOperations
|
||||
}
|
||||
@@ -567,10 +601,10 @@ public struct Board {
|
||||
public func printBoardColors() {
|
||||
printBoard { (square: Square) -> Character? in
|
||||
|
||||
if let piece = square.piece{
|
||||
if let piece = square.piece {
|
||||
return piece.color == .white ? "W" : "B"
|
||||
}
|
||||
return nil;
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,9 +613,9 @@ public struct Board {
|
||||
|
||||
var character: Character?
|
||||
|
||||
if let piece = square.piece{
|
||||
if let piece = square.piece {
|
||||
|
||||
switch (piece.type){
|
||||
switch piece.type {
|
||||
case .rook:
|
||||
character = "R"
|
||||
case .knight:
|
||||
@@ -597,7 +631,7 @@ public struct Board {
|
||||
|
||||
}
|
||||
}
|
||||
return character;
|
||||
return character
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,9 +640,9 @@ public struct Board {
|
||||
|
||||
var character: Character?
|
||||
|
||||
if let piece = square.piece{
|
||||
if let piece = square.piece {
|
||||
|
||||
switch (piece.type){
|
||||
switch piece.type {
|
||||
case .rook:
|
||||
character = piece.color == .white ? "R" : "r"
|
||||
case .knight:
|
||||
@@ -618,23 +652,21 @@ public struct Board {
|
||||
case .queen:
|
||||
character = piece.color == .white ? "Q" : "q"
|
||||
case .king:
|
||||
character = piece.color == .white ? "K" : "k"
|
||||
character = piece.color == .white ? "G" : "g"
|
||||
case .pawn:
|
||||
character = piece.color == .white ? "P" : "p"
|
||||
}
|
||||
|
||||
}
|
||||
return character;
|
||||
return character
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func printBoard( _ squarePrinter: (Square) -> Character? ){
|
||||
func printBoard( _ squarePrinter: (Square) -> Character? ) {
|
||||
|
||||
var printString = String()
|
||||
|
||||
for y in (0...7).reversed(){
|
||||
for y in (0...7).reversed() {
|
||||
for x in 0...7 {
|
||||
|
||||
let index = y*8 + x
|
||||
@@ -649,6 +681,38 @@ public struct Board {
|
||||
}
|
||||
}
|
||||
|
||||
public func ==(lhs: Board, rhs: Board) -> Bool {
|
||||
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.compactMap { Square(dictionary: $0) }
|
||||
if squares.count == 64 {
|
||||
self.squares = squares
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
lastAssignedPieceTag = squares.compactMap { $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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,31 +8,40 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct BoardLocation : Equatable {
|
||||
public struct BoardLocation: Equatable {
|
||||
|
||||
public enum GridPosition : Int{
|
||||
case a1; case b1; case c1; case d1; case e1; case f1; case g1; case h1;
|
||||
case a2; case b2; case c2; case d2; case e2; case f2; case g2; case h2;
|
||||
case a3; case b3; case c3; case d3; case e3; case f3; case g3; case h3;
|
||||
case a4; case b4; case c4; case d4; case e4; case f4; case g4; case h4;
|
||||
case a5; case b5; case c5; case d5; case e5; case f5; case g5; case h5;
|
||||
case a6; case b6; case c6; case d6; case e6; case f6; case g6; case h6;
|
||||
case a7; case b7; case c7; case d7; case e7; case f7; case g7; case h7;
|
||||
case a8; case b8; case c8; case d8; case e8; case f8; case g8; case h8;
|
||||
public enum GridPosition: Int {
|
||||
case a1; case b1; case c1; case d1; case e1; case f1; case g1; case h1
|
||||
case a2; case b2; case c2; case d2; case e2; case f2; case g2; case h2
|
||||
case a3; case b3; case c3; case d3; case e3; case f3; case g3; case h3
|
||||
case a4; case b4; case c4; case d4; case e4; case f4; case g4; case h4
|
||||
case a5; case b5; case c5; case d5; case e5; case f5; case g5; case h5
|
||||
case a6; case b6; case c6; case d6; case e6; case f6; case g6; case h6
|
||||
case a7; case b7; case c7; case d7; case e7; case f7; case g7; case h7
|
||||
case a8; case b8; case c8; case d8; case e8; case f8; case g8; case h8
|
||||
}
|
||||
|
||||
public var index: Int
|
||||
|
||||
private static var allLocationsBacking: [BoardLocation]?
|
||||
public static var all: [BoardLocation] {
|
||||
|
||||
// TODO: using a computed property could be expensive, can we store this so it doesn't need to be computed each time?
|
||||
var locations = [BoardLocation]()
|
||||
|
||||
(0..<64).forEach{
|
||||
locations.append(BoardLocation(index: $0))
|
||||
if let all = allLocationsBacking {
|
||||
return all
|
||||
} else {
|
||||
var locations = [BoardLocation]()
|
||||
|
||||
(0..<64).forEach {
|
||||
locations.append(BoardLocation(index: $0))
|
||||
}
|
||||
|
||||
allLocationsBacking = locations
|
||||
return allLocationsBacking!
|
||||
}
|
||||
|
||||
return locations
|
||||
}
|
||||
|
||||
public var isDarkSquare: Bool {
|
||||
return (index + y) % 2 == 0
|
||||
}
|
||||
|
||||
public var x: Int {
|
||||
@@ -55,7 +64,7 @@ public struct BoardLocation : Equatable {
|
||||
self.index = x + (y*8)
|
||||
}
|
||||
|
||||
public init(gridPosition: GridPosition){
|
||||
public init(gridPosition: GridPosition) {
|
||||
self.index = gridPosition.rawValue
|
||||
}
|
||||
|
||||
@@ -71,36 +80,36 @@ public struct BoardLocation : Equatable {
|
||||
return self + BoardLocation(x: x, y: y)
|
||||
}
|
||||
|
||||
func incrementedBy(stride: BoardStride) -> BoardLocation {
|
||||
func incremented(by stride: BoardStride) -> BoardLocation {
|
||||
|
||||
// TODO: for performance, we should probably only check this if we're in debug mode
|
||||
if !canIncrementBy(stride: stride) {
|
||||
print("WARNING! BoardLocation is being incremented by a stride that will result in wrapping! call canIncrementBy(stride: BoardStride) first")
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
|
||||
func canIncrementBy(stride: BoardStride) -> Bool {
|
||||
func canIncrement(by stride: BoardStride) -> Bool {
|
||||
|
||||
// Check will not wrap to right
|
||||
if x + stride.x > 7 {
|
||||
if x + stride.x > 7 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check will not wrap to left
|
||||
if x + stride.x < 0 {
|
||||
if x + stride.x < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check will not wrap top
|
||||
if y + stride.y > 7 {
|
||||
if y + stride.y > 7 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check will not wrap bottom
|
||||
if y + stride.y < 0 {
|
||||
if y + stride.y < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -120,10 +129,33 @@ public struct BoardLocation : Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public func ==(lhs: BoardLocation, rhs: BoardLocation) -> Bool {
|
||||
public func == (lhs: BoardLocation, rhs: BoardLocation) -> Bool {
|
||||
return lhs.index == rhs.index
|
||||
}
|
||||
|
||||
public func +(left: BoardLocation, right: BoardLocation) -> BoardLocation {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,30 +8,30 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class BoardRaterBoardDominance : BoardRater {
|
||||
class BoardRaterBoardDominance: BoardRater {
|
||||
|
||||
override func ratingfor(board: Board, color: Color) -> Double {
|
||||
override func ratingFor(board: Board, color: Color) -> Double {
|
||||
|
||||
let squareValue = Double(1);
|
||||
let squareValue = Double(1)
|
||||
|
||||
var rating = Double(0)
|
||||
|
||||
// Check this color pieces
|
||||
for sourcelocation in BoardLocation.all {
|
||||
|
||||
guard let piece = board.getPiece(at: sourcelocation) else{
|
||||
continue;
|
||||
guard let piece = board.getPiece(at: sourcelocation) else {
|
||||
continue
|
||||
}
|
||||
|
||||
for targetLocation in BoardLocation.all {
|
||||
if piece.movement.canPieceMove(fromLocation: sourcelocation, toLocation: targetLocation, board: board) {
|
||||
rating += (piece.color == color) ? squareValue : -squareValue;
|
||||
if piece.movement.canPieceMove(from: sourcelocation, to: targetLocation, board: board) {
|
||||
rating += (piece.color == color) ? squareValue : -squareValue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return rating * configuration.boardRaterBoardDominanceWeighting;
|
||||
return rating * configuration.boardRaterBoardDominanceWeighting.value
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ import Foundation
|
||||
Rates the board according to which player's pieces are able to move to the squares at the center of the board
|
||||
*/
|
||||
|
||||
class BoardRaterCenterDominance : BoardRater {
|
||||
class BoardRaterCenterDominance: BoardRater {
|
||||
|
||||
override func ratingfor(board: Board, color: Color) -> Double {
|
||||
override func ratingFor(board: Board, color: Color) -> Double {
|
||||
|
||||
var rating = Double(0)
|
||||
|
||||
@@ -26,7 +26,11 @@ class BoardRaterCenterDominance : BoardRater {
|
||||
|
||||
for targetLocation in BoardLocation.all {
|
||||
|
||||
if sourceLocation == targetLocation || piece.movement.canPieceMove(fromLocation: sourceLocation, toLocation: targetLocation, board: board) {
|
||||
if sourceLocation == targetLocation ||
|
||||
piece.movement.canPieceMove(from: sourceLocation,
|
||||
to: targetLocation,
|
||||
board: board) {
|
||||
|
||||
let value = dominanceValueFor(location: targetLocation)
|
||||
rating += (piece.color == color) ? value : -value
|
||||
}
|
||||
@@ -34,12 +38,12 @@ class BoardRaterCenterDominance : BoardRater {
|
||||
}
|
||||
}
|
||||
|
||||
return rating * configuration.boardRaterCenterDominanceWeighting
|
||||
return rating * configuration.boardRaterCenterDominanceWeighting.value
|
||||
}
|
||||
|
||||
func dominanceValueFor(location: BoardLocation) -> Double {
|
||||
|
||||
let axisMiddle = 3.5;
|
||||
let axisMiddle = 3.5
|
||||
|
||||
let x = Double(location.x)
|
||||
let y = Double(location.y)
|
||||
@@ -51,5 +55,4 @@ class BoardRaterCenterDominance : BoardRater {
|
||||
return axisMiddle - distance
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -10,17 +10,16 @@ import Foundation
|
||||
|
||||
class BoardRaterCenterFourOccupation: BoardRater {
|
||||
|
||||
override func ratingfor(board: Board, color: Color) -> Double {
|
||||
override func ratingFor(board: Board, color: Color) -> Double {
|
||||
|
||||
let value = Double(1);
|
||||
let value = Double(1)
|
||||
var rating = Double(0)
|
||||
|
||||
BoardLocation(x: 3, y: 3)
|
||||
let locations = [
|
||||
BoardLocation(x: 4, y: 4), // NE
|
||||
BoardLocation(x: 4, y: 3), // SE
|
||||
BoardLocation(x: 3, y: 3), // SW
|
||||
BoardLocation(x: 3, y: 4), // NW
|
||||
BoardLocation(x: 3, y: 4) // NW
|
||||
]
|
||||
|
||||
for location in locations {
|
||||
@@ -32,6 +31,6 @@ class BoardRaterCenterFourOccupation: BoardRater {
|
||||
rating += piece.color == color ? value : -value
|
||||
}
|
||||
|
||||
return rating * configuration.boardRaterCenterFourOccupationWeighting
|
||||
return rating * configuration.boardRaterCenterFourOccupationWeighting.value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ import Foundation
|
||||
Rates the board according to which player's pieces are occupying the center of the board
|
||||
*/
|
||||
|
||||
class BoardRaterCenterOwnership : BoardRater {
|
||||
class BoardRaterCenterOwnership: BoardRater {
|
||||
|
||||
override func ratingfor(board: Board, color: Color) -> Double {
|
||||
override func ratingFor(board: Board, color: Color) -> Double {
|
||||
|
||||
var rating = Double(0)
|
||||
|
||||
@@ -29,13 +29,13 @@ class BoardRaterCenterOwnership : BoardRater {
|
||||
rating += (piece.color == color) ? distance : -distance
|
||||
}
|
||||
|
||||
return rating * configuration.boardRaterCenterOwnershipWeighting
|
||||
return rating * configuration.boardRaterCenterOwnershipWeighting.value
|
||||
|
||||
}
|
||||
|
||||
func dominanceValueFor(location: BoardLocation) -> Double {
|
||||
|
||||
let axisMiddle = 3.5;
|
||||
let axisMiddle = 3.5
|
||||
|
||||
let x = Double(location.x)
|
||||
let y = Double(location.y)
|
||||
|
||||
@@ -14,16 +14,16 @@ import Foundation
|
||||
Iterates over all possible moves, makes them, and checks if the resulting state is check mate
|
||||
*/
|
||||
|
||||
class BoardRaterCheckMateOpportunity : BoardRater {
|
||||
class BoardRaterCheckMateOpportunity: BoardRater {
|
||||
|
||||
override func ratingfor(board: Board, color: Color) -> Double {
|
||||
override func ratingFor(board: Board, color: Color) -> Double {
|
||||
|
||||
let value = Double(1)
|
||||
var rating = Double(0)
|
||||
|
||||
for (index, square) in board.squares.enumerated() {
|
||||
|
||||
guard let piece = square.piece else{
|
||||
guard let piece = square.piece else {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -31,22 +31,21 @@ class BoardRaterCheckMateOpportunity : BoardRater {
|
||||
|
||||
let sourceLocation = BoardLocation(index: index)
|
||||
|
||||
if piece.movement.canPieceMove(fromLocation: sourceLocation, toLocation: location, board: board) {
|
||||
if piece.movement.canPieceMove(from: sourceLocation, to: location, board: board) {
|
||||
|
||||
var movedBoard = board
|
||||
movedBoard.movePiece(fromLocation: sourceLocation, toLocation: location)
|
||||
movedBoard.movePiece(from: sourceLocation, to: location)
|
||||
|
||||
if piece.color == color && movedBoard.isColorInCheckMate(color: color.opposite()){
|
||||
if piece.color == color && movedBoard.isColorInCheckMate(color: color.opposite) {
|
||||
rating += value
|
||||
}
|
||||
else if piece.color == color.opposite() && movedBoard.isColorInCheckMate(color: color){
|
||||
} else if piece.color == color.opposite && movedBoard.isColorInCheckMate(color: color) {
|
||||
rating -= value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rating * configuration.boardRaterCheckMateOpportunityWeighting
|
||||
return rating * configuration.boardRaterCheckMateOpportunityWeighting.value
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class BoardRaterCountPieces : BoardRater {
|
||||
class BoardRaterCountPieces: BoardRater {
|
||||
|
||||
override func ratingfor(board: Board, color: Color) -> Double {
|
||||
override func ratingFor(board: Board, color: Color) -> Double {
|
||||
|
||||
var rating : Double = 0
|
||||
var rating: Double = 0
|
||||
|
||||
for square in board.squares {
|
||||
|
||||
@@ -20,10 +20,10 @@ class BoardRaterCountPieces : BoardRater {
|
||||
continue
|
||||
}
|
||||
|
||||
rating += piece.color == color ? piece.value() : -piece.value()
|
||||
rating += piece.color == color ? piece.value : -piece.value
|
||||
}
|
||||
|
||||
return rating * configuration.boardRaterCountPiecesWeighting
|
||||
return rating * configuration.boardRaterCountPiecesWeighting.value
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,38 +8,39 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class BoardRaterKingSurroundingPossession : BoardRater {
|
||||
class BoardRaterKingSurroundingPossession: BoardRater {
|
||||
|
||||
override func ratingfor(board: Board, color: Color) -> Double {
|
||||
override func ratingFor(board: Board, color: Color) -> Double {
|
||||
|
||||
let squareValue = Double(1)
|
||||
var rating = Double(0)
|
||||
|
||||
let ownKingLocations = locationsSurroundingKing(color: color, board: board)
|
||||
let opponentKingLocations = locationsSurroundingKing(color: color.opposite(), board: board)
|
||||
let opponentKingLocations = locationsSurroundingKing(color: color.opposite, board: board)
|
||||
|
||||
// The kings will be able to move to their surrounding locations, so remove them from the board
|
||||
var noKingsBoard = board
|
||||
noKingsBoard.squares[noKingsBoard.getKingLocation(color: .white).index].piece = nil
|
||||
noKingsBoard.squares[noKingsBoard.getKingLocation(color: .black).index].piece = nil
|
||||
noKingsBoard.removePiece(at: noKingsBoard.getKingLocation(color: .white))
|
||||
noKingsBoard.removePiece(at: noKingsBoard.getKingLocation(color: .black))
|
||||
|
||||
// we don't want to encourage the king to move out in to the open
|
||||
rating += Double(8 - ownKingLocations.count) * squareValue * 3
|
||||
|
||||
for location in ownKingLocations {
|
||||
|
||||
if noKingsBoard.doesColorOccupyLocation(color: color, location: location) {
|
||||
rating += squareValue
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
|
||||
if noKingsBoard.doesColorOccupyLocation(color: color.opposite(), location: location) {
|
||||
if noKingsBoard.doesColorOccupyLocation(color: color.opposite, location: location) {
|
||||
rating -= squareValue
|
||||
continue
|
||||
}
|
||||
|
||||
if noKingsBoard.canColorMoveAnyPieceToLocation(color: color, location: location) {
|
||||
rating += squareValue
|
||||
}
|
||||
|
||||
else if noKingsBoard.canColorMoveAnyPieceToLocation(color: color.opposite(), location: location) {
|
||||
} else if noKingsBoard.canColorMoveAnyPieceToLocation(color: color.opposite, location: location) {
|
||||
rating -= squareValue
|
||||
}
|
||||
|
||||
@@ -49,24 +50,22 @@ class BoardRaterKingSurroundingPossession : BoardRater {
|
||||
|
||||
if noKingsBoard.doesColorOccupyLocation(color: color, location: location) {
|
||||
rating += squareValue
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
|
||||
if noKingsBoard.doesColorOccupyLocation(color: color.opposite(), location: location) {
|
||||
if noKingsBoard.doesColorOccupyLocation(color: color.opposite, location: location) {
|
||||
rating -= squareValue
|
||||
continue
|
||||
}
|
||||
|
||||
if noKingsBoard.canColorMoveAnyPieceToLocation(color: color, location: location) {
|
||||
rating += squareValue
|
||||
}
|
||||
|
||||
else if noKingsBoard.canColorMoveAnyPieceToLocation(color: color.opposite(), location: location) {
|
||||
} else if noKingsBoard.canColorMoveAnyPieceToLocation(color: color.opposite, location: location) {
|
||||
rating -= squareValue
|
||||
}
|
||||
}
|
||||
|
||||
return rating * configuration.boardRaterKingSurroundingPossessionWeighting
|
||||
return rating * configuration.boardRaterKingSurroundingPossessionWeighting.value
|
||||
}
|
||||
|
||||
func locationsSurroundingKing(color: Color, board: Board) -> [BoardLocation] {
|
||||
@@ -74,22 +73,22 @@ class BoardRaterKingSurroundingPossession : BoardRater {
|
||||
let kingLocation = board.getKingLocation(color: color)
|
||||
|
||||
let strides = [
|
||||
BoardStride(x: 0, y: 1), // N
|
||||
BoardStride(x: 1, y: 1), // NE
|
||||
BoardStride(x: 1, y: 0), // E
|
||||
BoardStride(x: 1, y: -1), // SE
|
||||
BoardStride(x: 0, y: -1), // S
|
||||
BoardStride(x: 0, y: 1), // N
|
||||
BoardStride(x: 1, y: 1), // NE
|
||||
BoardStride(x: 1, y: 0), // E
|
||||
BoardStride(x: 1, y: -1), // SE
|
||||
BoardStride(x: 0, y: -1), // S
|
||||
BoardStride(x: -1, y: -1), // SW
|
||||
BoardStride(x: -1, y: 0), // W
|
||||
BoardStride(x: -1, y: 1), // NW
|
||||
BoardStride(x: -1, y: 0), // W
|
||||
BoardStride(x: -1, y: 1) // NW
|
||||
]
|
||||
|
||||
var surroundingLocations = [BoardLocation]()
|
||||
|
||||
for stride in strides {
|
||||
|
||||
if kingLocation.canIncrementBy(stride: stride) {
|
||||
let location = kingLocation.incrementedBy(stride: stride)
|
||||
if kingLocation.canIncrement(by: stride) {
|
||||
let location = kingLocation.incremented(by: stride)
|
||||
surroundingLocations.append(location)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class BoardRaterPawnProgression : BoardRater {
|
||||
class BoardRaterPawnProgression: BoardRater {
|
||||
|
||||
override func ratingfor(board: Board, color: Color) -> Double {
|
||||
override func ratingFor(board: Board, color: Color) -> Double {
|
||||
|
||||
var rating = Double(0)
|
||||
|
||||
@@ -38,12 +38,11 @@ class BoardRaterPawnProgression : BoardRater {
|
||||
if color == .white {
|
||||
|
||||
if location.y < 2 {
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
squaresAdvanced = location.y - 2
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
|
||||
if location.y > 5 {
|
||||
return 0
|
||||
@@ -52,7 +51,7 @@ class BoardRaterPawnProgression : BoardRater {
|
||||
squaresAdvanced = 7 - (location.y + 2)
|
||||
}
|
||||
|
||||
return Double(squaresAdvanced) * configuration.boardRaterPawnProgressionWeighting // <- should probably add some sort of curve
|
||||
return Double(squaresAdvanced) * configuration.boardRaterPawnProgressionWeighting.value
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,128 +10,215 @@ import Foundation
|
||||
|
||||
// Tendancy to protect own pieces
|
||||
|
||||
class BoardRaterThreatenedPieces : BoardRater {
|
||||
class BoardRaterThreatenedPieces: BoardRater {
|
||||
|
||||
override func ratingfor(board: Board, color: Color) -> Double {
|
||||
override func ratingFor(board: Board, color: Color) -> Double {
|
||||
|
||||
var rating = Double(0)
|
||||
|
||||
for location in BoardLocation.all {
|
||||
|
||||
guard let piece = board.getPiece(at: location) else {
|
||||
continue;
|
||||
}
|
||||
|
||||
let threatRating = threatRatingForPiece(at: location, board: board, color: color)
|
||||
|
||||
// For a same color, subtract the threat rating (less preferrable move)
|
||||
if piece.color == color {
|
||||
rating -= threatRating * configuration.boardRaterThreatenedPiecesOwnPiecesMultiplier
|
||||
}
|
||||
// For opposite color, add the treat rating (more preferable move)
|
||||
else{
|
||||
rating += threatRating
|
||||
}
|
||||
|
||||
rating += (piece.color == color) ? -threatRating : threatRating;
|
||||
}
|
||||
|
||||
return rating * configuration.boardRaterThreatenedPiecesWeighting
|
||||
}
|
||||
|
||||
|
||||
// Returns a more positive rating the more the piece is threatened
|
||||
func threatRatingForPiece(at location: BoardLocation, board: Board, color: Color) -> Double {
|
||||
|
||||
guard let piece = board.getPiece(at: location) else{
|
||||
fatalError()
|
||||
}
|
||||
|
||||
var rating = Double(0)
|
||||
|
||||
let threateningPieceLocations = threateningPiecesLocationsforPiece(at: location, on: board)
|
||||
let isBeingThreatened = threateningPieceLocations.isEmpty ? false : true
|
||||
|
||||
let protectingPieceLocations = protectingPiecesLocationsforPiece(at: location, on: board)
|
||||
let isBeingProtected = protectingPieceLocations.isEmpty ? false : true
|
||||
|
||||
for threateningPieceLocation in threateningPieceLocations {
|
||||
|
||||
guard let threateningPiece = board.getPiece(at: threateningPieceLocation) else {
|
||||
continue
|
||||
}
|
||||
|
||||
let pieceIsProtected = (isBeingProtected && piece.value() < threateningPiece.value())
|
||||
|
||||
if !pieceIsProtected {
|
||||
let rating = board.getPieces(color: color)
|
||||
.map { threatValue(forPiece: $0, on: board) }
|
||||
.reduce(0, +)
|
||||
* configuration.boardRaterThreatenedPiecesWeighting.value
|
||||
|
||||
rating += piece.value()
|
||||
}
|
||||
}
|
||||
|
||||
return rating
|
||||
}
|
||||
|
||||
// MARK - Get protecting / Threatening pieces
|
||||
|
||||
func protectingPiecesLocationsforPiece(at location: BoardLocation, on board: Board) -> [BoardLocation] {
|
||||
func threatValue(forPiece piece: Piece, on board: Board) -> Double {
|
||||
|
||||
var newBoard = board
|
||||
let threatenedByPieces = getPieces(threatening: piece, on: board)
|
||||
let protectedByPieces = getPieces(protecting: piece, on: board)
|
||||
let isThreatened = threatenedByPieces.count > 0
|
||||
let isProtected = protectedByPieces.count > 0
|
||||
|
||||
guard let protectedPiece = board.getPiece(at: location) else {
|
||||
fatalError("Expected board location to contain piece")
|
||||
// Threatened but not protected
|
||||
if isThreatened && !isProtected {
|
||||
return -piece.value * 3
|
||||
}
|
||||
|
||||
// Change the piece color to be opposite, to simulate if the piece was taken
|
||||
let oppositeColorPiece = Piece(type: protectedPiece.type, color: protectedPiece.color.opposite())
|
||||
newBoard.setPiece(oppositeColorPiece, at: location)
|
||||
|
||||
var pieces = [BoardLocation]()
|
||||
|
||||
for sourceLocation in BoardLocation.all {
|
||||
// Threatened, but protected (only return if the trade is not preferable)
|
||||
if isThreatened && isProtected {
|
||||
|
||||
guard let protectingPiece = newBoard.getPiece(at: sourceLocation) else{
|
||||
continue
|
||||
let lowestValueThreat = threatenedByPieces.lowestPieceValue
|
||||
|
||||
if lowestValueThreat < piece.value {
|
||||
return -piece.value
|
||||
}
|
||||
|
||||
guard protectingPiece.color == protectedPiece.color else{
|
||||
continue
|
||||
}
|
||||
// Here we could bump the value to encourage a good trade?
|
||||
}
|
||||
|
||||
let targetPieces = getPieces(threatenedBy: piece, on: board)
|
||||
for targetPiece in targetPieces {
|
||||
|
||||
if protectingPiece.movement.canPieceMove(fromLocation: sourceLocation, toLocation: location, board: newBoard) {
|
||||
pieces.append(sourceLocation)
|
||||
let isTargetProtected = isPieceProtected(targetPiece, on: board)
|
||||
|
||||
// If it's protected, is it a good trade
|
||||
if isTargetProtected && targetPiece.value < piece.value {
|
||||
return 0
|
||||
} else {
|
||||
return targetPiece.value
|
||||
}
|
||||
}
|
||||
|
||||
return pieces
|
||||
// Nothing much interesting
|
||||
return 0
|
||||
}
|
||||
|
||||
func threateningPiecesLocationsforPiece(at location: BoardLocation, on board: Board) -> [BoardLocation] {
|
||||
// MARK: - Helpers
|
||||
|
||||
func getPieces(protecting piece: Piece, on board: Board) -> [Piece] {
|
||||
|
||||
guard let threatenedPiece = board.getPiece(at: location) else {
|
||||
fatalError("Expected board location to contain piece")
|
||||
var alteredBoard = board
|
||||
alteredBoard.setPiece(piece.withOppositeColor, at: piece.location)
|
||||
|
||||
return alteredBoard.getPieces(color: piece.color).filter {
|
||||
$0.movement.canPieceMove(from: $0.location,
|
||||
to: piece.location,
|
||||
board: alteredBoard,
|
||||
accountForCheckState: true)
|
||||
}
|
||||
|
||||
let threatenedColor = threatenedPiece.color
|
||||
|
||||
var pieces = [BoardLocation]()
|
||||
|
||||
for sourceLocation in BoardLocation.all {
|
||||
|
||||
guard let threateningPiece = board.getPiece(at: sourceLocation) else{
|
||||
continue
|
||||
}
|
||||
|
||||
guard threateningPiece.color == threatenedColor.opposite() else{
|
||||
continue
|
||||
}
|
||||
|
||||
if threateningPiece.movement.canPieceMove(fromLocation: sourceLocation, toLocation: location, board: board) {
|
||||
pieces.append(sourceLocation)
|
||||
}
|
||||
}
|
||||
|
||||
return pieces
|
||||
}
|
||||
|
||||
func getPieces(protectedBy piece: Piece, on board: Board) -> [Piece] {
|
||||
|
||||
return board.getPieces(color: piece.color).filter {
|
||||
piece.movement.canPieceMove(from: piece.location,
|
||||
to: $0.location,
|
||||
board: board,
|
||||
accountForCheckState: true)
|
||||
}
|
||||
}
|
||||
|
||||
func isPieceProtected(_ piece: Piece, on board: Board) -> Bool {
|
||||
|
||||
var alteredBoard = board
|
||||
alteredBoard.setPiece(piece.withOppositeColor, at: piece.location)
|
||||
|
||||
for square in alteredBoard.squares {
|
||||
|
||||
guard let squarePiece = square.piece else {
|
||||
continue
|
||||
}
|
||||
|
||||
guard squarePiece.color == piece.color else {
|
||||
continue
|
||||
}
|
||||
|
||||
if squarePiece.movement.canPieceMove(from: squarePiece.location,
|
||||
to: piece.location,
|
||||
board: alteredBoard,
|
||||
accountForCheckState: true) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func isPieceThreatened(_ piece: Piece, on board: Board) -> Bool {
|
||||
|
||||
for square in board.squares {
|
||||
|
||||
guard let squarePiece = square.piece else {
|
||||
continue
|
||||
}
|
||||
|
||||
guard squarePiece.color == piece.color.opposite else {
|
||||
continue
|
||||
}
|
||||
|
||||
if squarePiece.movement.canPieceMove(from: squarePiece.location,
|
||||
to: piece.location,
|
||||
board: board,
|
||||
accountForCheckState: true) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func getPieces(threatening piece: Piece, on board: Board) -> [Piece] {
|
||||
|
||||
return board.getPieces(color: piece.color.opposite).filter {
|
||||
$0.movement.canPieceMove(from: $0.location,
|
||||
to: piece.location,
|
||||
board: board,
|
||||
accountForCheckState: true)
|
||||
}
|
||||
}
|
||||
|
||||
func getPieces(threatenedBy piece: Piece, on board: Board) -> [Piece] {
|
||||
|
||||
return board.getPieces(color: piece.color.opposite).filter {
|
||||
piece.movement.canPieceMove(from: piece.location,
|
||||
to: $0.location,
|
||||
board: board,
|
||||
accountForCheckState: true)
|
||||
}
|
||||
}
|
||||
|
||||
func canPieceMoveToSafety(_ piece: Piece, on board: Board) -> Bool {
|
||||
|
||||
for location in BoardLocation.all {
|
||||
|
||||
if piece.movement.canPieceMove(from: piece.location,
|
||||
to: location,
|
||||
board: board,
|
||||
accountForCheckState: true) {
|
||||
|
||||
var boardCopy = board
|
||||
boardCopy.movePiece(from: piece.location, to: location)
|
||||
let movedPiece = boardCopy.getPiece(at: location)!
|
||||
if !isPieceThreatened(movedPiece, on: boardCopy) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
extension Collection where Iterator.Element == Piece {
|
||||
|
||||
var lowestPieceValue: Double {
|
||||
|
||||
if self.count == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
var result = self.first!.value
|
||||
|
||||
for piece in self {
|
||||
|
||||
let pieceValue = piece.value
|
||||
|
||||
if pieceValue < result {
|
||||
result = pieceValue
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
var highestPieceValue: Double {
|
||||
|
||||
if self.count == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
var result = self.first!.value
|
||||
|
||||
for piece in self {
|
||||
|
||||
let pieceValue = piece.value
|
||||
|
||||
if pieceValue > result {
|
||||
result = pieceValue
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,12 +10,11 @@ import Foundation
|
||||
|
||||
public struct BoardStride {
|
||||
|
||||
public var x: Int;
|
||||
public var y: Int;
|
||||
public var x: Int
|
||||
public var y: Int
|
||||
|
||||
public init(x: Int, y: Int){
|
||||
self.x = x;
|
||||
self.y = y;
|
||||
public init(x: Int, y: Int) {
|
||||
self.x = x
|
||||
self.y = y
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
+246
-26
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
open class Game {
|
||||
public final class Game {
|
||||
|
||||
// MARK: Types
|
||||
public enum State: Equatable {
|
||||
@@ -16,7 +16,7 @@ open class Game {
|
||||
case staleMate(color: Color)
|
||||
case won(color: Color)
|
||||
|
||||
public static func ==(lhs: State, rhs: State) -> Bool {
|
||||
public static func == (lhs: State, rhs: State) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case (.inProgress, .inProgress):
|
||||
return true
|
||||
@@ -29,17 +29,38 @@ open class Game {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum GameType: Int {
|
||||
case humanVsHuman
|
||||
case humanVsComputer
|
||||
case computerVsComputer
|
||||
}
|
||||
|
||||
// MARK: Properties
|
||||
open var board = Board(state: .newGame)
|
||||
open var whitePlayer: Player!
|
||||
open var blackPlayer: Player!
|
||||
open var currentPlayer: Player!
|
||||
open var state = Game.State.inProgress
|
||||
open weak var delegate: GameDelegate?
|
||||
public internal(set) var board: Board
|
||||
public let whitePlayer: Player!
|
||||
public let blackPlayer: Player!
|
||||
public internal(set) var currentPlayer: Player!
|
||||
public internal(set) var state = Game.State.inProgress
|
||||
public weak var delegate: GameDelegate?
|
||||
|
||||
public var gameType: GameType {
|
||||
|
||||
switch (self.whitePlayer, self.blackPlayer) {
|
||||
case (is Human, is Human):
|
||||
return .humanVsHuman
|
||||
case (is AIPlayer, is AIPlayer):
|
||||
return .computerVsComputer
|
||||
default:
|
||||
return .humanVsComputer
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Init
|
||||
public init(firstPlayer: Player, secondPlayer: Player, board: Board = Board(state: .newGame), colorToMove: Color = .white){
|
||||
public init(firstPlayer: Player,
|
||||
secondPlayer: Player,
|
||||
board: Board = Board(state: .newGame),
|
||||
colorToMove: Color = .white) {
|
||||
|
||||
self.board = board
|
||||
|
||||
@@ -59,11 +80,10 @@ open class Game {
|
||||
self.currentPlayer = (colorToMove == .white ? self.whitePlayer : self.blackPlayer)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Game : PlayerDelegate
|
||||
extension Game : PlayerDelegate {
|
||||
extension Game: PlayerDelegate {
|
||||
|
||||
func playerDidMakeMove(player: Player, boardOperations: [BoardOperation]) {
|
||||
|
||||
@@ -72,32 +92,38 @@ extension Game : PlayerDelegate {
|
||||
print("Warning - Wrong player took turn")
|
||||
}
|
||||
|
||||
// Tell delegate we will begin updates
|
||||
delegate?.gameWillBeginUpdates(game: self)
|
||||
|
||||
// Process board operations
|
||||
processBoardOperations(boardOperations: boardOperations)
|
||||
|
||||
// Check for game ended
|
||||
if board.isColorInCheckMate(color: currentPlayer.color.opposite()) {
|
||||
if board.isColorInCheckMate(color: currentPlayer.color.opposite) {
|
||||
state = .won(color: currentPlayer.color)
|
||||
delegate?.gameWonByPlayer(game: self, player: currentPlayer)
|
||||
return
|
||||
}
|
||||
|
||||
// Check for stalemate
|
||||
if board.isColorInStalemate(color: currentPlayer.color.opposite()) {
|
||||
state = .staleMate(color: currentPlayer.color.opposite())
|
||||
if board.isColorInStalemate(color: currentPlayer.color.opposite) {
|
||||
state = .staleMate(color: currentPlayer.color.opposite)
|
||||
delegate?.gameEndedInStaleMate(game: self)
|
||||
return
|
||||
}
|
||||
|
||||
// Tell the delegate that we've ended updates
|
||||
delegate?.gameDidEndUpdates(game: self)
|
||||
|
||||
// Switch to the other player
|
||||
if player === whitePlayer {
|
||||
currentPlayer = blackPlayer
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
currentPlayer = whitePlayer
|
||||
}
|
||||
|
||||
self.delegate?.gameDidChangeCurrentPlayer(game: self)
|
||||
|
||||
}
|
||||
|
||||
func processBoardOperations(boardOperations: [BoardOperation]) {
|
||||
@@ -106,11 +132,17 @@ extension Game : PlayerDelegate {
|
||||
|
||||
switch boardOperation.type! {
|
||||
case .movePiece:
|
||||
self.delegate?.gameDidMovePiece(game: self, piece: boardOperation.piece, toLocation: boardOperation.location)
|
||||
self.delegate?.gameDidMovePiece(game: self,
|
||||
piece: boardOperation.piece,
|
||||
toLocation: boardOperation.location)
|
||||
case .removePiece:
|
||||
self.delegate?.gameDidRemovePiece(game: self, piece: boardOperation.piece, location: boardOperation.location)
|
||||
self.delegate?.gameDidRemovePiece(game: self,
|
||||
piece: boardOperation.piece,
|
||||
location: boardOperation.location)
|
||||
case .transformPiece:
|
||||
self.delegate?.gameDidTransformPiece(game: self, piece: boardOperation.piece, location: boardOperation.location)
|
||||
self.delegate?.gameDidTransformPiece(game: self,
|
||||
piece: boardOperation.piece,
|
||||
location: boardOperation.location)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -119,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 {
|
||||
|
||||
@@ -128,13 +338,23 @@ public protocol GameDelegate: class {
|
||||
func gameEndedInStaleMate(game: Game)
|
||||
|
||||
// Piece adding / removing / modifying
|
||||
func gameWillBeginUpdates(game: Game) // Updates will begin
|
||||
func gameDidAddPiece(game: Game) // A new piece was added to the board (do we actually need to include this functionality?)
|
||||
func gameDidRemovePiece(game: Game, piece: Piece, location: BoardLocation) // A piece was removed from the board
|
||||
func gameDidMovePiece(game: Game, piece: Piece, toLocation: BoardLocation) // A piece was moved on the board
|
||||
func gameDidTransformPiece(game: Game, piece: Piece, location: BoardLocation) // A piece was transformed (eg. pawn was promoted to another piece)
|
||||
func gameDidEndUpdates(game: Game) // Updates will end
|
||||
|
||||
// Updates will begin
|
||||
func gameWillBeginUpdates(game: Game)
|
||||
// A new piece was added to the board
|
||||
func gameDidAddPiece(game: Game)
|
||||
// A piece was removed from the board
|
||||
func gameDidRemovePiece(game: Game, piece: Piece, location: BoardLocation)
|
||||
// A piece was moved on the board
|
||||
func gameDidMovePiece(game: Game, piece: Piece, toLocation: BoardLocation)
|
||||
// A piece was transformed (eg. pawn was promoted to another piece)
|
||||
func gameDidTransformPiece(game: Game, piece: Piece, location: BoardLocation)
|
||||
// Updates will end)
|
||||
func gameDidEndUpdates(game: Game)
|
||||
|
||||
// Callbacks from player
|
||||
func promotedTypeForPawn(location: BoardLocation, player: Human, possiblePromotions: [Piece.PieceType], callback: @escaping (Piece.PieceType) -> Void )
|
||||
func promotedTypeForPawn(location: BoardLocation,
|
||||
player: Human,
|
||||
possiblePromotions: [Piece.PieceType],
|
||||
callback: @escaping (Piece.PieceType) -> Void )
|
||||
}
|
||||
|
||||
@@ -6,18 +6,25 @@
|
||||
//
|
||||
//
|
||||
|
||||
//swiftlint:disable line_length
|
||||
|
||||
import Foundation
|
||||
|
||||
open class Human : Player {
|
||||
public final class Human: Player {
|
||||
|
||||
public init(color: Color){
|
||||
public init(color: Color) {
|
||||
super.init()
|
||||
self.color = color
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
public func movePiece(fromLocation: BoardLocation, toLocation: BoardLocation) throws {
|
||||
public func movePiece(from fromLocation: BoardLocation, to toLocation: BoardLocation) throws {
|
||||
|
||||
// Check that the game is in progress
|
||||
guard game.state == .inProgress else {
|
||||
throw MoveError.gameIsNotInProgress
|
||||
}
|
||||
|
||||
// Check that we're the current player
|
||||
guard game.currentPlayer === self else {
|
||||
@@ -25,13 +32,14 @@ open class Human : Player {
|
||||
}
|
||||
|
||||
// Check if move is allowed
|
||||
let canMove = canMovePieceWithError(fromLocation: fromLocation, toLocation: toLocation)
|
||||
if let error = canMove.error {
|
||||
do {
|
||||
_ = try canMovePiece(from: fromLocation, to: toLocation)
|
||||
} catch let error {
|
||||
throw error
|
||||
}
|
||||
|
||||
// Move the piece
|
||||
var operations = game.board.movePiece(fromLocation: fromLocation, toLocation: toLocation)
|
||||
var operations = game.board.movePiece(from: fromLocation, to: toLocation)
|
||||
|
||||
// Make pawn promotions
|
||||
let promotablePawnLocations = game.board.getLocationsOfPromotablePawns(color: color)
|
||||
@@ -44,10 +52,10 @@ open class Human : Player {
|
||||
player: self,
|
||||
possiblePromotions: Piece.PieceType.possiblePawnPromotionResultingTypes(),
|
||||
callback: {
|
||||
|
||||
|
||||
// Change the piece
|
||||
let newPiece = self.game.board.squares[pawnLocation.index].piece?.byChangingType(newType: $0)
|
||||
self.game.board.squares[pawnLocation.index].piece = newPiece
|
||||
self.game.board.setPiece(newPiece!, at: pawnLocation)
|
||||
|
||||
// Add a transform piece operation
|
||||
let modifyOperation = BoardOperation(type: .transformPiece, piece: newPiece!, location: pawnLocation)
|
||||
@@ -58,7 +66,7 @@ open class Human : Player {
|
||||
})
|
||||
}
|
||||
// ... Or if no pawn promotions, end move
|
||||
else{
|
||||
else {
|
||||
// Inform the delegate that we made a move
|
||||
delegate?.playerDidMakeMove(player: self, boardOperations: operations)
|
||||
|
||||
@@ -85,7 +93,33 @@ open class Human : Player {
|
||||
delegate?.playerDidMakeMove(player: self, boardOperations: operations)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,12 @@ struct OpeningMove {
|
||||
let board: Board
|
||||
let fromLocation: BoardLocation
|
||||
let toLocation: BoardLocation
|
||||
|
||||
init(board: Board, from fromLocation: BoardLocation, to toLocation: BoardLocation) {
|
||||
self.board = board
|
||||
self.fromLocation = fromLocation
|
||||
self.toLocation = toLocation
|
||||
}
|
||||
}
|
||||
|
||||
class Opening {
|
||||
@@ -22,53 +28,48 @@ class Opening {
|
||||
ItalianGame(),
|
||||
SicilianDefense(),
|
||||
QueensGambit(),
|
||||
KingsGambit(),
|
||||
KingsGambit()
|
||||
]
|
||||
}
|
||||
|
||||
static func allOpeningMoves(forColor color: Color) -> [OpeningMove] {
|
||||
static func allOpeningMoves(for color: Color) -> [OpeningMove] {
|
||||
|
||||
var openingMoves = [OpeningMove]()
|
||||
|
||||
allOpenings().forEach{
|
||||
openingMoves += $0.moves(forColor: color)
|
||||
allOpenings().forEach {
|
||||
openingMoves += $0.moves(for: color)
|
||||
}
|
||||
|
||||
return openingMoves
|
||||
}
|
||||
|
||||
public func moves(forColor color: Color) -> [OpeningMove] {
|
||||
public func moves(for color: Color) -> [OpeningMove] {
|
||||
|
||||
var moves = [OpeningMove]()
|
||||
|
||||
var board = Board(state: .newGame)
|
||||
for locations in moveLocations(){
|
||||
for locations in moveLocations() {
|
||||
|
||||
let move = OpeningMove(board: board,
|
||||
fromLocation: locations.fromLocation,
|
||||
toLocation: locations.toLocation)
|
||||
from: locations.fromLocation,
|
||||
to: locations.toLocation)
|
||||
moves.append(move)
|
||||
|
||||
board.movePiece(fromLocation: locations.fromLocation,
|
||||
toLocation: locations.toLocation)
|
||||
board.movePiece(from: locations.fromLocation, to: locations.toLocation)
|
||||
|
||||
//move.board.printBoardPieces()
|
||||
|
||||
}
|
||||
|
||||
// Filter for color
|
||||
return moves.enumerated().flatMap{ (index, value) in
|
||||
return moves.enumerated().compactMap { (index, value) in
|
||||
index % 2 == (color == .white ? 0 : 1) ? value : nil
|
||||
}
|
||||
}
|
||||
/*
|
||||
public func moveLocations(forColor color: Color) -> [(fromLocation: BoardLocation, toLocation: BoardLocation)] {
|
||||
|
||||
return moveLocations().enumerated().flatMap{ (index, value) in
|
||||
index % 2 == (color == .white ? 0 : 1) ? value : nil
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func moveLocations() -> [(fromLocation: BoardLocation, toLocation: BoardLocation)] {
|
||||
|
||||
return moveGridPositions().map{
|
||||
return moveGridPositions().map {
|
||||
(BoardLocation(gridPosition: $0), BoardLocation(gridPosition: $1))
|
||||
}
|
||||
}
|
||||
@@ -83,14 +84,15 @@ class Opening {
|
||||
|
||||
class RuyLopez: Opening {
|
||||
|
||||
override func moveGridPositions() -> [(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
override func moveGridPositions() ->
|
||||
[(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
|
||||
let moves: [(BoardLocation.GridPosition, BoardLocation.GridPosition)] = [
|
||||
(.e2, .e4), // white moves pawn to e4
|
||||
(.e7, .e5), // black moves pawn to e5
|
||||
(.g1, .f3), // white moves knight to f3
|
||||
(.b8, .c6), // black moves knight to c6
|
||||
(.f1, .b5), // white moves bishop to b5
|
||||
(.f1, .b5) // white moves bishop to b5
|
||||
]
|
||||
|
||||
return moves
|
||||
@@ -101,14 +103,15 @@ class RuyLopez: Opening {
|
||||
|
||||
class ItalianGame: Opening {
|
||||
|
||||
override func moveGridPositions() -> [(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
override func moveGridPositions() ->
|
||||
[(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
|
||||
let moves: [(BoardLocation.GridPosition, BoardLocation.GridPosition)] = [
|
||||
(.e2, .e4), // white moves pawn to e4
|
||||
(.e7, .e5), // black moves pawn to e5
|
||||
(.g1, .f3), // white moves knight to f3
|
||||
(.b8, .c6), // black moves knight to c6
|
||||
(.f1, .c4), // white moves bishop to c4
|
||||
(.f1, .c4) // white moves bishop to c4
|
||||
]
|
||||
|
||||
return moves
|
||||
@@ -119,11 +122,12 @@ class ItalianGame: Opening {
|
||||
|
||||
class SicilianDefense: Opening {
|
||||
|
||||
override func moveGridPositions() -> [(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
override func moveGridPositions() ->
|
||||
[(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
|
||||
let moves: [(BoardLocation.GridPosition, BoardLocation.GridPosition)] = [
|
||||
(.e2, .e4), // white moves pawn to e4
|
||||
(.c7, .c5), // black moves pawn to c5
|
||||
(.c7, .c5) // black moves pawn to c5
|
||||
]
|
||||
|
||||
return moves
|
||||
@@ -134,12 +138,13 @@ class SicilianDefense: Opening {
|
||||
|
||||
class QueensGambit: Opening {
|
||||
|
||||
override func moveGridPositions() -> [(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
override func moveGridPositions() ->
|
||||
[(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
|
||||
let moves: [(BoardLocation.GridPosition, BoardLocation.GridPosition)] = [
|
||||
(.d2, .d4), // white moves pawn to d4
|
||||
(.d7, .d5), // black moves pawn to d5
|
||||
(.c2, .c4), // white moves pawn to c4
|
||||
(.c2, .c4) // white moves pawn to c4
|
||||
]
|
||||
|
||||
return moves
|
||||
@@ -150,18 +155,15 @@ class QueensGambit: Opening {
|
||||
|
||||
class KingsGambit: Opening {
|
||||
|
||||
override func moveGridPositions() -> [(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
override func moveGridPositions() ->
|
||||
[(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
|
||||
let moves: [(BoardLocation.GridPosition, BoardLocation.GridPosition)] = [
|
||||
(.e2, .e4), // white moves pawn to e4
|
||||
(.e7, .e5), // black moves pawn to e5
|
||||
(.f2, .f4), // white moves pawn to f4
|
||||
(.f2, .f4) // white moves pawn to f4
|
||||
]
|
||||
|
||||
return moves
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+120
-40
@@ -8,25 +8,26 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum Color {
|
||||
case white
|
||||
case black
|
||||
public enum Color: String {
|
||||
case white = "White"
|
||||
case black = "Black"
|
||||
|
||||
public func opposite() -> Color {
|
||||
public var opposite: Color {
|
||||
return (self == .white) ? .black : .white
|
||||
}
|
||||
|
||||
public func toString() -> String {
|
||||
return (self == .white) ? "white" : "black"
|
||||
public var string: String {
|
||||
return rawValue.lowercased()
|
||||
}
|
||||
|
||||
public var stringWithCapital: String {
|
||||
return rawValue
|
||||
}
|
||||
}
|
||||
|
||||
public struct Piece : Equatable {
|
||||
public struct Piece: Equatable {
|
||||
|
||||
static private var lastAssignedTag = 0
|
||||
|
||||
public enum PieceType {
|
||||
public enum PieceType: Int {
|
||||
case pawn
|
||||
case rook
|
||||
case knight
|
||||
@@ -34,6 +35,17 @@ public struct Piece : Equatable {
|
||||
case queen
|
||||
case king
|
||||
|
||||
var value: Double {
|
||||
switch self {
|
||||
case .pawn: return 1
|
||||
case .rook: return 5
|
||||
case .knight: return 3
|
||||
case .bishop: return 3
|
||||
case .queen: return 9
|
||||
case .king: return 0 // King is always treated as a unique case
|
||||
}
|
||||
}
|
||||
|
||||
static func possiblePawnPromotionResultingTypes() -> [PieceType] {
|
||||
return [.queen, .knight, .rook, .bishop]
|
||||
}
|
||||
@@ -41,54 +53,122 @@ public struct Piece : Equatable {
|
||||
|
||||
public let type: PieceType
|
||||
public let color: Color
|
||||
public var tag: Int!
|
||||
public var hasMoved = false
|
||||
public var canBeTakenByEnPassant = false
|
||||
public internal(set) var tag: Int!
|
||||
public internal(set) var hasMoved = false
|
||||
public internal(set) var canBeTakenByEnPassant = false
|
||||
public internal(set) var location = BoardLocation(index: 0)
|
||||
|
||||
var movement : PieceMovement {
|
||||
return PieceMovement.pieceMovementForPieceType(pieceType: self.type)
|
||||
}
|
||||
|
||||
public init(type: PieceType, color: Color){
|
||||
self.type = type
|
||||
self.color = color
|
||||
|
||||
// assign the next tag
|
||||
Piece.lastAssignedTag += 1
|
||||
self.tag = Piece.lastAssignedTag
|
||||
var movement: PieceMovement! {
|
||||
return PieceMovement.pieceMovement(for: self.type)
|
||||
}
|
||||
|
||||
public init(type: PieceType, color: Color, tag: Int){
|
||||
var withOppositeColor: Piece {
|
||||
return Piece(type: type, color: color.opposite)
|
||||
}
|
||||
|
||||
var value: Double {
|
||||
return type.value
|
||||
}
|
||||
|
||||
public init(type: PieceType, color: Color, tag: Int = 0) {
|
||||
self.type = type
|
||||
self.color = color
|
||||
self.tag = tag
|
||||
}
|
||||
|
||||
func value() -> Double {
|
||||
|
||||
switch type {
|
||||
case .pawn: return 1
|
||||
case .rook: return 5
|
||||
case .knight: return 3
|
||||
case .bishop: return 3
|
||||
case .queen: return 9
|
||||
case .king: return 0 // King is always treated as a unique case
|
||||
}
|
||||
}
|
||||
|
||||
func byChangingType(newType: PieceType) -> Piece {
|
||||
|
||||
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{
|
||||
} 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,39 +6,104 @@
|
||||
//
|
||||
//
|
||||
|
||||
//swiftlint:disable file_length
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: - PieceMovement (Base Class)
|
||||
|
||||
let pawnMovement = PieceMovementPawn()
|
||||
let rookMovement = PieceMovementRook()
|
||||
let knightMovement = PieceMovementKnight()
|
||||
let bishopMovement = PieceMovementBishop()
|
||||
let queenMovement = PieceMovementQueen()
|
||||
let kingMovement = PieceMovementKing()
|
||||
|
||||
open class PieceMovement {
|
||||
|
||||
public class func pieceMovementForPieceType(pieceType: Piece.PieceType) -> PieceMovement {
|
||||
public class func pieceMovement(for pieceType: Piece.PieceType) -> PieceMovement {
|
||||
|
||||
switch pieceType {
|
||||
case .pawn:
|
||||
return PieceMovementPawn()
|
||||
return pawnMovement
|
||||
case .rook:
|
||||
return PieceMovementRook()
|
||||
return rookMovement
|
||||
case .knight:
|
||||
return PieceMovementKnight()
|
||||
return knightMovement
|
||||
case .bishop:
|
||||
return PieceMovementBishop()
|
||||
return bishopMovement
|
||||
case .queen:
|
||||
return PieceMovementQueen()
|
||||
return queenMovement
|
||||
case .king:
|
||||
return PieceMovementKing()
|
||||
return kingMovement
|
||||
}
|
||||
}
|
||||
|
||||
public init(){
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
open func canPieceMove(fromLocation: BoardLocation, toLocation: BoardLocation, board: Board) -> Bool {
|
||||
func canPieceMove(from fromLocation: BoardLocation,
|
||||
to toLocation: BoardLocation,
|
||||
board: Board,
|
||||
accountForCheckState: Bool = false) -> Bool {
|
||||
|
||||
if fromLocation == toLocation {
|
||||
return false
|
||||
}
|
||||
|
||||
let canMove = isMovementPossible(from: fromLocation, to: toLocation, board: board)
|
||||
|
||||
if canMove && accountForCheckState {
|
||||
|
||||
let color = board.getPiece(at: fromLocation)!.color
|
||||
|
||||
var boardCopy = board
|
||||
boardCopy.movePiece(from: fromLocation, to: toLocation)
|
||||
return boardCopy.isColorInCheck(color: color) ? false : true
|
||||
} else {
|
||||
return canMove
|
||||
}
|
||||
}
|
||||
|
||||
func isMovementPossible(from fromLocation: BoardLocation, to toLocation: BoardLocation, board: Board) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func canPieceMove(fromLocation: BoardLocation, toLocation: BoardLocation, board: Board, stride: BoardStride) -> Bool {
|
||||
// swiftlint:disable function_body_length
|
||||
func canPieceMove(from fromLocation: BoardLocation,
|
||||
to toLocation: BoardLocation,
|
||||
board: Board,
|
||||
stride: BoardStride) -> Bool {
|
||||
|
||||
enum Direction: Int {
|
||||
case increasing
|
||||
case decresing
|
||||
case none
|
||||
}
|
||||
|
||||
var strideDirectionX = Direction.none
|
||||
if stride.x < 0 { strideDirectionX = .decresing }
|
||||
if stride.x > 0 { strideDirectionX = .increasing }
|
||||
|
||||
var locationDirectionX = Direction.none
|
||||
if toLocation.x - fromLocation.x < 0 { locationDirectionX = .decresing }
|
||||
if toLocation.x - fromLocation.x > 0 { locationDirectionX = .increasing }
|
||||
|
||||
if strideDirectionX != locationDirectionX {
|
||||
return false
|
||||
}
|
||||
|
||||
var strideDirectionY = Direction.none
|
||||
if stride.y < 0 { strideDirectionY = .decresing }
|
||||
if stride.y > 0 { strideDirectionY = .increasing }
|
||||
|
||||
var locationDirectionY = Direction.none
|
||||
if toLocation.y - fromLocation.y < 0 { locationDirectionY = .decresing }
|
||||
if toLocation.y - fromLocation.y > 0 { locationDirectionY = .increasing }
|
||||
|
||||
if strideDirectionY != locationDirectionY {
|
||||
return false
|
||||
}
|
||||
|
||||
// Make sure cannot take king
|
||||
if let piece = board.getPiece(at: toLocation) {
|
||||
@@ -48,33 +113,31 @@ open class PieceMovement {
|
||||
}
|
||||
|
||||
// Get the moving piece
|
||||
var movingPiece = board.getPiece(at: fromLocation)
|
||||
|
||||
if movingPiece == nil {
|
||||
guard let movingPiece = board.getPiece(at: fromLocation) else {
|
||||
print("Cannot from an index that does not contain a piece")
|
||||
return false
|
||||
}
|
||||
|
||||
// Increment by stride
|
||||
if !fromLocation.canIncrementBy(stride: stride) {
|
||||
if !fromLocation.canIncrement(by: stride) {
|
||||
return false
|
||||
}
|
||||
var testLocation = fromLocation.incrementedBy(stride: stride)
|
||||
var testLocation = fromLocation.incremented(by: stride)
|
||||
|
||||
while testLocation.isInBounds() {
|
||||
|
||||
// If there is a piece on the square
|
||||
if let piece = board.getPiece(at: testLocation) {
|
||||
|
||||
if piece.color == movingPiece!.color {
|
||||
if piece.color == movingPiece.color {
|
||||
return false
|
||||
}
|
||||
|
||||
if piece.color == movingPiece!.color.opposite() && testLocation == toLocation {
|
||||
if piece.color == movingPiece.color.opposite && testLocation == toLocation {
|
||||
return true
|
||||
}
|
||||
|
||||
if piece.color == movingPiece!.color.opposite() && testLocation != toLocation {
|
||||
if piece.color == movingPiece.color.opposite && testLocation != toLocation {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -84,22 +147,22 @@ open class PieceMovement {
|
||||
}
|
||||
|
||||
// Increment by stride
|
||||
if !testLocation.canIncrementBy(stride: stride) {
|
||||
if !testLocation.canIncrement(by: stride) {
|
||||
return false
|
||||
}
|
||||
testLocation = testLocation.incrementedBy(stride: stride)
|
||||
testLocation = testLocation.incremented(by: stride)
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func canPieceOccupySquare(pieceLocation: BoardLocation, xOffset: Int, yOffset: Int, board: Board) -> Bool{
|
||||
func canPieceOccupySquare(pieceLocation: BoardLocation, xOffset: Int, yOffset: Int, board: Board) -> Bool {
|
||||
|
||||
let targetLocation = pieceLocation.incrementedBy(x: xOffset, y: yOffset)
|
||||
|
||||
// Check if in bounds
|
||||
guard targetLocation.isInBounds() else{
|
||||
guard targetLocation.isInBounds() else {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -109,16 +172,14 @@ open class PieceMovement {
|
||||
}
|
||||
|
||||
// Check if space is occupied
|
||||
var movingPiece = board.getPiece(at: pieceLocation)
|
||||
|
||||
if movingPiece == nil {
|
||||
print("Cannot from an index that does not contain a piece")
|
||||
guard let movingPiece = board.getPiece(at: pieceLocation) else {
|
||||
print("Cannot move from an index that does not contain a piece")
|
||||
return false
|
||||
}
|
||||
|
||||
if let otherPiece = board.getPiece(at: targetLocation) {
|
||||
|
||||
if otherPiece.color == movingPiece!.color {
|
||||
if otherPiece.color == movingPiece.color {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -132,17 +193,26 @@ open class PieceMovement {
|
||||
|
||||
open class PieceMovementStraightLine: PieceMovement {
|
||||
|
||||
override open func canPieceMove(fromLocation: BoardLocation, toLocation: BoardLocation, board: Board) -> Bool {
|
||||
let strides = [
|
||||
BoardStride(x: 0, y: -1 ), // Down
|
||||
BoardStride(x: 0, y: 1 ), // Up
|
||||
BoardStride(x: -1, y: 0 ), // Left
|
||||
BoardStride(x: 1, y: 0 ) // Right
|
||||
]
|
||||
|
||||
override func isMovementPossible(from fromLocation: BoardLocation,
|
||||
to toLocation: BoardLocation,
|
||||
board: Board) -> Bool {
|
||||
|
||||
let strides = [
|
||||
BoardStride(x: 0, y: -1 ), // Down
|
||||
BoardStride(x: 0, y: 1 ), // Up
|
||||
BoardStride(x: -1, y: 0 ), // Left
|
||||
BoardStride(x: 1, y: 0 ) // Right
|
||||
]
|
||||
let sameX = fromLocation.x == toLocation.x
|
||||
let sameY = fromLocation.y == toLocation.y
|
||||
|
||||
if !(sameX || sameY) {
|
||||
return false
|
||||
}
|
||||
|
||||
for stride in strides {
|
||||
if canPieceMove(fromLocation: fromLocation, toLocation: toLocation, board: board, stride: stride) {
|
||||
if canPieceMove(from: fromLocation, to: toLocation, board: board, stride: stride) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -156,17 +226,23 @@ open class PieceMovementStraightLine: PieceMovement {
|
||||
|
||||
open class PieceMovementDiagonal: PieceMovement {
|
||||
|
||||
override open func canPieceMove(fromLocation: BoardLocation, toLocation: BoardLocation, board: Board) -> Bool {
|
||||
let strides = [
|
||||
BoardStride(x: 1, y: -1 ), // South East
|
||||
BoardStride(x: -1, y: -1 ), // South West
|
||||
BoardStride(x: 1, y: 1 ), // North East
|
||||
BoardStride(x: -1, y: 1 ) // North West
|
||||
]
|
||||
|
||||
override func isMovementPossible(from fromLocation: BoardLocation,
|
||||
to toLocation: BoardLocation,
|
||||
board: Board) -> Bool {
|
||||
|
||||
let strides = [
|
||||
BoardStride(x: 1, y: -1 ), // South East
|
||||
BoardStride(x: -1, y: -1 ), // South West
|
||||
BoardStride(x: 1, y: 1 ), // North East
|
||||
BoardStride(x: -1, y: 1 ) // North West
|
||||
]
|
||||
if fromLocation.isDarkSquare != toLocation.isDarkSquare {
|
||||
return false
|
||||
}
|
||||
|
||||
for stride in strides {
|
||||
if canPieceMove(fromLocation: fromLocation, toLocation: toLocation, board: board, stride: stride) {
|
||||
if canPieceMove(from: fromLocation, to: toLocation, board: board, stride: stride) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -181,13 +257,15 @@ open class PieceMovementDiagonal: PieceMovement {
|
||||
|
||||
open class PieceMovementQueen: PieceMovement {
|
||||
|
||||
let movements : [PieceMovement] = [PieceMovementStraightLine(), PieceMovementDiagonal()]
|
||||
let movements: [PieceMovement] = [PieceMovementStraightLine(), PieceMovementDiagonal()]
|
||||
|
||||
override open func canPieceMove(fromLocation: BoardLocation, toLocation: BoardLocation, board: Board) -> Bool {
|
||||
override func isMovementPossible(from fromLocation: BoardLocation,
|
||||
to toLocation: BoardLocation,
|
||||
board: Board) -> Bool {
|
||||
|
||||
for pieceMovement in movements {
|
||||
|
||||
if pieceMovement.canPieceMove(fromLocation: fromLocation, toLocation: toLocation, board: board) {
|
||||
if pieceMovement.canPieceMove(from: fromLocation, to: toLocation, board: board) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -203,12 +281,11 @@ open class PieceMovementRook: PieceMovement {
|
||||
|
||||
let straightLineMovement = PieceMovementStraightLine()
|
||||
|
||||
override open func canPieceMove(fromLocation: BoardLocation, toLocation: BoardLocation, board: Board) -> Bool {
|
||||
|
||||
return straightLineMovement.canPieceMove(fromLocation: fromLocation, toLocation: toLocation, board: board)
|
||||
|
||||
return false
|
||||
override func isMovementPossible(from fromLocation: BoardLocation,
|
||||
to toLocation: BoardLocation,
|
||||
board: Board) -> Bool {
|
||||
|
||||
return straightLineMovement.canPieceMove(from: fromLocation, to: toLocation, board: board)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,12 +295,11 @@ open class PieceMovementBishop: PieceMovement {
|
||||
|
||||
let diagonalMovement = PieceMovementDiagonal()
|
||||
|
||||
override open func canPieceMove(fromLocation: BoardLocation, toLocation: BoardLocation, board: Board) -> Bool {
|
||||
|
||||
return diagonalMovement.canPieceMove(fromLocation: fromLocation, toLocation: toLocation, board: board)
|
||||
|
||||
return false
|
||||
override func isMovementPossible(from fromLocation: BoardLocation,
|
||||
to toLocation: BoardLocation,
|
||||
board: Board) -> Bool {
|
||||
|
||||
return diagonalMovement.canPieceMove(from: fromLocation, to: toLocation, board: board)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +307,20 @@ open class PieceMovementBishop: PieceMovement {
|
||||
|
||||
open class PieceMovementKnight: PieceMovement {
|
||||
|
||||
override open func canPieceMove(fromLocation: BoardLocation, toLocation: BoardLocation, board: Board) -> Bool {
|
||||
let offsets: [(x: Int, y: Int)] = [
|
||||
(1, 2),
|
||||
(2, 1),
|
||||
(2, -1),
|
||||
(-2, 1),
|
||||
(-1, -2),
|
||||
(-2, -1),
|
||||
(1, -2),
|
||||
(-1, 2)
|
||||
]
|
||||
|
||||
override func isMovementPossible(from fromLocation: BoardLocation,
|
||||
to toLocation: BoardLocation,
|
||||
board: Board) -> Bool {
|
||||
|
||||
// Make sure cannot take king
|
||||
if let piece = board.getPiece(at: toLocation) {
|
||||
@@ -240,22 +329,15 @@ open class PieceMovementKnight: PieceMovement {
|
||||
}
|
||||
}
|
||||
|
||||
let offsets: [(x: Int, y: Int)] = [
|
||||
(1,2),
|
||||
(2,1),
|
||||
(2,-1),
|
||||
(-2,1),
|
||||
(-1,-2),
|
||||
(-2,-1),
|
||||
(1,-2),
|
||||
(-1,2)
|
||||
]
|
||||
|
||||
for offset in offsets {
|
||||
|
||||
let offsetLocation = fromLocation.incrementedBy(x: offset.x, y: offset.y)
|
||||
|
||||
if toLocation == offsetLocation && canPieceOccupySquare(pieceLocation: fromLocation, xOffset: offset.x, yOffset: offset.y, board: board) {
|
||||
if toLocation == offsetLocation
|
||||
&& canPieceOccupySquare(pieceLocation: fromLocation,
|
||||
xOffset: offset.x,
|
||||
yOffset: offset.y,
|
||||
board: board) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -267,9 +349,25 @@ open class PieceMovementKnight: PieceMovement {
|
||||
|
||||
// MARK: - PieceMovementPawn
|
||||
|
||||
// swiftlint:disable function_body_length
|
||||
open class PieceMovementPawn: PieceMovement {
|
||||
|
||||
override open func canPieceMove(fromLocation: BoardLocation, toLocation: BoardLocation, board: Board) -> Bool {
|
||||
override func isMovementPossible(from fromLocation: BoardLocation,
|
||||
to toLocation: BoardLocation,
|
||||
board: Board) -> Bool {
|
||||
|
||||
// Get the moving piece
|
||||
guard let movingPiece = board.getPiece(at: fromLocation) else {
|
||||
return false
|
||||
}
|
||||
|
||||
if movingPiece.color == .white && toLocation.y == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if movingPiece.color == .black && toLocation.y == 7 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Make sure cannot take king
|
||||
if let piece = board.getPiece(at: toLocation) {
|
||||
@@ -278,24 +376,20 @@ open class PieceMovementPawn: PieceMovement {
|
||||
}
|
||||
}
|
||||
|
||||
// Get the moving piece
|
||||
guard let movingPiece = board.getPiece(at: fromLocation) else{
|
||||
return false
|
||||
}
|
||||
|
||||
let color = movingPiece.color
|
||||
|
||||
// ****** Test forward locations ******
|
||||
var forwardStrides = [BoardStride]()
|
||||
|
||||
// Test one ahead offset
|
||||
let oneAheadStride = (color == .white ? BoardStride(x: 0, y: 1) : BoardStride(x: 0, y: -1))
|
||||
var canMoveOneAhead = true
|
||||
|
||||
ONE_AHEAD: if fromLocation.canIncrementBy(stride: oneAheadStride) {
|
||||
ONE_AHEAD: if fromLocation.canIncrement(by: oneAheadStride) {
|
||||
|
||||
let location = fromLocation.incrementedBy(stride: oneAheadStride)
|
||||
let location = fromLocation.incremented(by: oneAheadStride)
|
||||
|
||||
if let _ = board.getPiece(at: toLocation) {
|
||||
if board.getPiece(at: location) != nil {
|
||||
canMoveOneAhead = false
|
||||
break ONE_AHEAD
|
||||
}
|
||||
|
||||
@@ -304,52 +398,49 @@ open class PieceMovementPawn: PieceMovement {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Test two ahead offset
|
||||
var twoAheadStride: BoardStride?
|
||||
|
||||
if color == .white && fromLocation.y == 1 {
|
||||
twoAheadStride = BoardStride(x: 0, y: 2)
|
||||
}
|
||||
else if color == .black && fromLocation.y == 6 {
|
||||
twoAheadStride = BoardStride(x: 0, y: -2)
|
||||
}
|
||||
|
||||
TWO_AHEAD: if let twoAheadStride = twoAheadStride {
|
||||
if canMoveOneAhead {
|
||||
|
||||
let twoAheadLocation = fromLocation.incrementedBy(stride: twoAheadStride)
|
||||
|
||||
if toLocation != twoAheadLocation {
|
||||
break TWO_AHEAD
|
||||
var twoAheadStride: BoardStride?
|
||||
|
||||
if color == .white && fromLocation.y == 1 {
|
||||
twoAheadStride = BoardStride(x: 0, y: 2)
|
||||
} else if color == .black && fromLocation.y == 6 {
|
||||
twoAheadStride = BoardStride(x: 0, y: -2)
|
||||
}
|
||||
|
||||
let oneAheadLocation = fromLocation.incrementedBy(stride: oneAheadStride)
|
||||
|
||||
if board.getPiece(at: oneAheadLocation) == nil && board.getPiece(at: twoAheadLocation) == nil {
|
||||
return true
|
||||
TWO_AHEAD: if let twoAheadStride = twoAheadStride {
|
||||
|
||||
let twoAheadLocation = fromLocation.incremented(by: twoAheadStride)
|
||||
|
||||
if toLocation != twoAheadLocation {
|
||||
break TWO_AHEAD
|
||||
}
|
||||
|
||||
if board.getPiece(at: twoAheadLocation) == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ****** Test Diagonal locations ******
|
||||
var diagonalStrides = [BoardStride]()
|
||||
|
||||
if color == .white {
|
||||
diagonalStrides.append( BoardStride(x: -1, y: 1) )
|
||||
diagonalStrides.append( BoardStride(x: 1, y: 1) )
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
diagonalStrides.append( BoardStride(x: -1, y: -1) )
|
||||
diagonalStrides.append( BoardStride(x: 1, y: -1) )
|
||||
}
|
||||
|
||||
for stride in diagonalStrides {
|
||||
|
||||
guard fromLocation.canIncrementBy(stride: stride) else {
|
||||
guard fromLocation.canIncrement(by: stride) else {
|
||||
continue
|
||||
}
|
||||
|
||||
let location = fromLocation.incrementedBy(stride: stride)
|
||||
let location = fromLocation.incremented(by: stride)
|
||||
|
||||
if location != toLocation {
|
||||
continue
|
||||
@@ -357,7 +448,7 @@ open class PieceMovementPawn: PieceMovement {
|
||||
|
||||
// If the target square has an opponent piece
|
||||
if let piece = board.getPiece(at: location) {
|
||||
if piece.color == color.opposite() {
|
||||
if piece.color == color.opposite {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -365,17 +456,17 @@ open class PieceMovementPawn: PieceMovement {
|
||||
// If can make en passent move
|
||||
let enPassentStride = BoardStride(x: stride.x, y: 0)
|
||||
|
||||
guard fromLocation.canIncrementBy(stride: enPassentStride) else {
|
||||
guard fromLocation.canIncrement(by: enPassentStride) else {
|
||||
break
|
||||
}
|
||||
|
||||
let enPassentLocation = fromLocation.incrementedBy(stride: enPassentStride)
|
||||
let enPassentLocation = fromLocation.incremented(by: enPassentStride)
|
||||
|
||||
guard let passingPiece = board.getPiece(at: enPassentLocation) else {
|
||||
break
|
||||
}
|
||||
|
||||
if passingPiece.canBeTakenByEnPassant && passingPiece.color == color.opposite() {
|
||||
if passingPiece.canBeTakenByEnPassant && passingPiece.color == color.opposite {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -386,12 +477,24 @@ open class PieceMovementPawn: PieceMovement {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - PieceMovementKing
|
||||
|
||||
open class PieceMovementKing: PieceMovement {
|
||||
|
||||
override open func canPieceMove(fromLocation: BoardLocation, toLocation: BoardLocation, board: Board) -> Bool {
|
||||
let offsets: [(x: Int, y: Int)] = [
|
||||
(0, 1), // North
|
||||
(1, 1), // North-East
|
||||
(1, 0), // East
|
||||
(1, -1), // South-East
|
||||
(0, -1), // South
|
||||
(-1, -1), // South-West
|
||||
(-1, 0), // West
|
||||
(-1, 1) // North- West
|
||||
]
|
||||
|
||||
override func isMovementPossible(from fromLocation: BoardLocation,
|
||||
to toLocation: BoardLocation,
|
||||
board: Board) -> Bool {
|
||||
|
||||
// Make sure cannot take king
|
||||
if let piece = board.getPiece(at: toLocation) {
|
||||
@@ -400,24 +503,16 @@ open class PieceMovementKing: PieceMovement {
|
||||
}
|
||||
}
|
||||
|
||||
let offsets: [(x: Int, y: Int)] = [
|
||||
(0,1), // North
|
||||
(1,1), // North-East
|
||||
(1,0), // East
|
||||
(1,-1), // South-East
|
||||
(0,-1), // South
|
||||
(-1,-1), // South-West
|
||||
(-1,0), // West
|
||||
(-1,1) // North- West
|
||||
]
|
||||
|
||||
for offset in offsets {
|
||||
|
||||
let offsetLocation = fromLocation.incrementedBy(x: offset.x, y: offset.y)
|
||||
|
||||
if toLocation == offsetLocation
|
||||
&& offsetLocation.isInBounds()
|
||||
&& canPieceOccupySquare(pieceLocation: fromLocation, xOffset: offset.x, yOffset: offset.y, board: board) {
|
||||
&& canPieceOccupySquare(pieceLocation: fromLocation,
|
||||
xOffset: offset.x,
|
||||
yOffset: offset.y,
|
||||
board: board) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ open class Player {
|
||||
weak var game: Game!
|
||||
weak var delegate: PlayerDelegate?
|
||||
|
||||
public func occupiesSquareAt(location: BoardLocation) -> Bool{
|
||||
public func occupiesSquare(at location: BoardLocation) -> Bool {
|
||||
|
||||
if let piece = self.game.board.getPiece(at: location){
|
||||
if let piece = self.game.board.getPiece(at: location) {
|
||||
if piece.color == self.color {
|
||||
return true
|
||||
}
|
||||
@@ -29,11 +29,7 @@ open class Player {
|
||||
return false
|
||||
}
|
||||
|
||||
public func canMovePiece(fromLocation: BoardLocation, toLocation: BoardLocation) -> Bool {
|
||||
return canMovePieceWithError(fromLocation: fromLocation, toLocation: toLocation).result
|
||||
}
|
||||
|
||||
public enum MoveError : Error {
|
||||
public enum MoveError: Int, Error, Equatable {
|
||||
case notThisPlayersTurn
|
||||
case movingToSameLocation
|
||||
case noPieceToMove
|
||||
@@ -41,48 +37,50 @@ open class Player {
|
||||
case pieceUnableToMoveToLocation
|
||||
case playerMustMoveOutOfCheck
|
||||
case cannotMoveInToCheck
|
||||
case gameIsNotInProgress
|
||||
|
||||
public static func == (lhs: MoveError, rhs: MoveError) -> Bool {
|
||||
return lhs.rawValue == rhs.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
public func canMovePieceWithError(fromLocation: BoardLocation, toLocation: BoardLocation) -> (result: Bool, error: MoveError?) {
|
||||
func canMovePiece(from fromLocation: BoardLocation, to toLocation: BoardLocation) throws -> Bool {
|
||||
|
||||
// We can't move to our current location
|
||||
if fromLocation == toLocation {
|
||||
return (false, .movingToSameLocation)
|
||||
throw MoveError.movingToSameLocation
|
||||
}
|
||||
|
||||
// Get the piece
|
||||
guard let piece = self.game.board.getPiece(at: fromLocation) else {
|
||||
return (false, .noPieceToMove)
|
||||
throw MoveError.noPieceToMove
|
||||
}
|
||||
|
||||
// Check that the piece color matches the player color
|
||||
if piece.color != self.color {
|
||||
return (false, .pieceColorDoesNotMatchPlayerColor)
|
||||
throw MoveError.pieceColorDoesNotMatchPlayerColor
|
||||
}
|
||||
|
||||
// Make sure the piece can move to the location
|
||||
if !piece.movement.canPieceMove(fromLocation: fromLocation, toLocation: toLocation, board: game.board) {
|
||||
return (false, .pieceUnableToMoveToLocation)
|
||||
if !piece.movement.canPieceMove(from: fromLocation, to: toLocation, board: game.board) {
|
||||
throw MoveError.pieceUnableToMoveToLocation
|
||||
}
|
||||
|
||||
// Move the piece
|
||||
let inCheckBeforeMove = self.game.board.isColorInCheck(color: self.color)
|
||||
var board = self.game.board
|
||||
board.movePiece(fromLocation: fromLocation, toLocation: toLocation)
|
||||
var inCheckAfterMove = board.isColorInCheck(color: self.color)
|
||||
board.movePiece(from: fromLocation, to: toLocation)
|
||||
let inCheckAfterMove = board.isColorInCheck(color: self.color)
|
||||
|
||||
// Return
|
||||
if inCheckBeforeMove && inCheckAfterMove {
|
||||
return (false, .playerMustMoveOutOfCheck)
|
||||
throw MoveError.playerMustMoveOutOfCheck
|
||||
}
|
||||
|
||||
if !inCheckBeforeMove && inCheckAfterMove {
|
||||
return (false, .cannotMoveInToCheck)
|
||||
throw MoveError.cannotMoveInToCheck
|
||||
}
|
||||
|
||||
return (true, nil)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,31 @@
|
||||
671989831DEB11900053EA3D /* BoardRaterCenterOwnership.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671989821DEB11900053EA3D /* BoardRaterCenterOwnership.swift */; };
|
||||
6719898B1DFFE0D80053EA3D /* BoardRaterBoardDominance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6719898A1DFFE0D80053EA3D /* BoardRaterBoardDominance.swift */; };
|
||||
6719898F1DFFE7550053EA3D /* BoardRaterCenterDominance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6719898E1DFFE7550053EA3D /* BoardRaterCenterDominance.swift */; };
|
||||
673596B922A1B43A003086FF /* AIPlayerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596AD22A1B43A003086FF /* AIPlayerTests.swift */; };
|
||||
673596BA22A1B43A003086FF /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596AE22A1B43A003086FF /* PerformanceTests.swift */; };
|
||||
673596BB22A1B43A003086FF /* AIBehaviourTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596AF22A1B43A003086FF /* AIBehaviourTests.swift */; };
|
||||
673596BC22A1B43A003086FF /* GameTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596B022A1B43A003086FF /* GameTests.swift */; };
|
||||
673596BD22A1B43A003086FF /* BoardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596B122A1B43A003086FF /* BoardTests.swift */; };
|
||||
673596BE22A1B43A003086FF /* OpeningsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596B222A1B43A003086FF /* OpeningsTests.swift */; };
|
||||
673596BF22A1B43A003086FF /* PieceMovementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596B322A1B43A003086FF /* PieceMovementTests.swift */; };
|
||||
673596C022A1B43A003086FF /* BoardLocationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596B422A1B43A003086FF /* BoardLocationTests.swift */; };
|
||||
673596C122A1B43A003086FF /* PlayerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596B522A1B43A003086FF /* PlayerTests.swift */; };
|
||||
673596C222A1B43A003086FF /* PieceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596B622A1B43A003086FF /* PieceTests.swift */; };
|
||||
673596C322A1B43A003086FF /* AIConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596B722A1B43A003086FF /* AIConfigurationTests.swift */; };
|
||||
673596C422A1B43A003086FF /* SquareTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596B822A1B43A003086FF /* SquareTests.swift */; };
|
||||
673596C822A1B448003086FF /* DictionaryRepresentableExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596C622A1B448003086FF /* DictionaryRepresentableExtensions.swift */; };
|
||||
673596C922A1B448003086FF /* BoardScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596C722A1B448003086FF /* BoardScenarios.swift */; };
|
||||
673596D422A1B45A003086FF /* BoardRaterCountPiecesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596CB22A1B459003086FF /* BoardRaterCountPiecesTests.swift */; };
|
||||
673596D522A1B45A003086FF /* BoardRaterCheckMateOpportunityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596CC22A1B459003086FF /* BoardRaterCheckMateOpportunityTests.swift */; };
|
||||
673596D622A1B45A003086FF /* BoardRaterCenterDominanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596CD22A1B459003086FF /* BoardRaterCenterDominanceTests.swift */; };
|
||||
673596D722A1B45A003086FF /* BoardRaterCenterOwnershipTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596CE22A1B459003086FF /* BoardRaterCenterOwnershipTests.swift */; };
|
||||
673596D822A1B45A003086FF /* BoardRaterKingSurroundingPossession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596CF22A1B459003086FF /* BoardRaterKingSurroundingPossession.swift */; };
|
||||
673596D922A1B45A003086FF /* BoardRaterCenterFourOccupationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596D022A1B459003086FF /* BoardRaterCenterFourOccupationTests.swift */; };
|
||||
673596DA22A1B45A003086FF /* BoardRaterBoardDominanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596D122A1B45A003086FF /* BoardRaterBoardDominanceTests.swift */; };
|
||||
673596DB22A1B45A003086FF /* BoardRaterThreatenedPiecesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596D222A1B45A003086FF /* BoardRaterThreatenedPiecesTests.swift */; };
|
||||
673596DC22A1B45A003086FF /* BoardRaterPawnProgressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 673596D322A1B45A003086FF /* BoardRaterPawnProgressionTests.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 */; };
|
||||
@@ -49,7 +73,31 @@
|
||||
671989821DEB11900053EA3D /* BoardRaterCenterOwnership.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCenterOwnership.swift; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
673596AD22A1B43A003086FF /* AIPlayerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AIPlayerTests.swift; sourceTree = "<group>"; };
|
||||
673596AE22A1B43A003086FF /* PerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceTests.swift; sourceTree = "<group>"; };
|
||||
673596AF22A1B43A003086FF /* AIBehaviourTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AIBehaviourTests.swift; sourceTree = "<group>"; };
|
||||
673596B022A1B43A003086FF /* GameTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameTests.swift; sourceTree = "<group>"; };
|
||||
673596B122A1B43A003086FF /* BoardTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardTests.swift; sourceTree = "<group>"; };
|
||||
673596B222A1B43A003086FF /* OpeningsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpeningsTests.swift; sourceTree = "<group>"; };
|
||||
673596B322A1B43A003086FF /* PieceMovementTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PieceMovementTests.swift; sourceTree = "<group>"; };
|
||||
673596B422A1B43A003086FF /* BoardLocationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardLocationTests.swift; sourceTree = "<group>"; };
|
||||
673596B522A1B43A003086FF /* PlayerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerTests.swift; sourceTree = "<group>"; };
|
||||
673596B622A1B43A003086FF /* PieceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PieceTests.swift; sourceTree = "<group>"; };
|
||||
673596B722A1B43A003086FF /* AIConfigurationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AIConfigurationTests.swift; sourceTree = "<group>"; };
|
||||
673596B822A1B43A003086FF /* SquareTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SquareTests.swift; sourceTree = "<group>"; };
|
||||
673596C622A1B448003086FF /* DictionaryRepresentableExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryRepresentableExtensions.swift; sourceTree = "<group>"; };
|
||||
673596C722A1B448003086FF /* BoardScenarios.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardScenarios.swift; sourceTree = "<group>"; };
|
||||
673596CB22A1B459003086FF /* BoardRaterCountPiecesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCountPiecesTests.swift; sourceTree = "<group>"; };
|
||||
673596CC22A1B459003086FF /* BoardRaterCheckMateOpportunityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCheckMateOpportunityTests.swift; sourceTree = "<group>"; };
|
||||
673596CD22A1B459003086FF /* BoardRaterCenterDominanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCenterDominanceTests.swift; sourceTree = "<group>"; };
|
||||
673596CE22A1B459003086FF /* BoardRaterCenterOwnershipTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCenterOwnershipTests.swift; sourceTree = "<group>"; };
|
||||
673596CF22A1B459003086FF /* BoardRaterKingSurroundingPossession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterKingSurroundingPossession.swift; sourceTree = "<group>"; };
|
||||
673596D022A1B459003086FF /* BoardRaterCenterFourOccupationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterCenterFourOccupationTests.swift; sourceTree = "<group>"; };
|
||||
673596D122A1B45A003086FF /* BoardRaterBoardDominanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterBoardDominanceTests.swift; sourceTree = "<group>"; };
|
||||
673596D222A1B45A003086FF /* BoardRaterThreatenedPiecesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterThreatenedPiecesTests.swift; sourceTree = "<group>"; };
|
||||
673596D322A1B45A003086FF /* BoardRaterPawnProgressionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardRaterPawnProgressionTests.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 +140,39 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
673596C522A1B43E003086FF /* Supporting */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
673596C722A1B448003086FF /* BoardScenarios.swift */,
|
||||
673596C622A1B448003086FF /* DictionaryRepresentableExtensions.swift */,
|
||||
);
|
||||
path = Supporting;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
673596CA22A1B44B003086FF /* Board Raters */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
673596D122A1B45A003086FF /* BoardRaterBoardDominanceTests.swift */,
|
||||
673596CD22A1B459003086FF /* BoardRaterCenterDominanceTests.swift */,
|
||||
673596D022A1B459003086FF /* BoardRaterCenterFourOccupationTests.swift */,
|
||||
673596CE22A1B459003086FF /* BoardRaterCenterOwnershipTests.swift */,
|
||||
673596CC22A1B459003086FF /* BoardRaterCheckMateOpportunityTests.swift */,
|
||||
673596CB22A1B459003086FF /* BoardRaterCountPiecesTests.swift */,
|
||||
673596CF22A1B459003086FF /* BoardRaterKingSurroundingPossession.swift */,
|
||||
673596D322A1B45A003086FF /* BoardRaterPawnProgressionTests.swift */,
|
||||
673596D222A1B45A003086FF /* BoardRaterThreatenedPiecesTests.swift */,
|
||||
);
|
||||
path = "Board Raters";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
677BE815200A2D54004B27DB /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
677BE816200A2D78004B27DB /* DictionaryRepresentable.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
67A9C9D41DE64CD200510FB8 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -123,6 +204,20 @@
|
||||
67A9C9EB1DE64CD300510FB8 /* SwiftChessTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
673596C522A1B43E003086FF /* Supporting */,
|
||||
673596CA22A1B44B003086FF /* Board Raters */,
|
||||
673596AF22A1B43A003086FF /* AIBehaviourTests.swift */,
|
||||
673596B722A1B43A003086FF /* AIConfigurationTests.swift */,
|
||||
673596AD22A1B43A003086FF /* AIPlayerTests.swift */,
|
||||
673596B422A1B43A003086FF /* BoardLocationTests.swift */,
|
||||
673596B122A1B43A003086FF /* BoardTests.swift */,
|
||||
673596B022A1B43A003086FF /* GameTests.swift */,
|
||||
673596B222A1B43A003086FF /* OpeningsTests.swift */,
|
||||
673596AE22A1B43A003086FF /* PerformanceTests.swift */,
|
||||
673596B322A1B43A003086FF /* PieceMovementTests.swift */,
|
||||
673596B622A1B43A003086FF /* PieceTests.swift */,
|
||||
673596B522A1B43A003086FF /* PlayerTests.swift */,
|
||||
673596B822A1B43A003086FF /* SquareTests.swift */,
|
||||
67A9C9EE1DE64CD300510FB8 /* Info.plist */,
|
||||
);
|
||||
path = SwiftChessTests;
|
||||
@@ -131,6 +226,7 @@
|
||||
67A9C9F81DE64D2500510FB8 /* Source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
677BE815200A2D54004B27DB /* Extensions */,
|
||||
67F9DB791E2438EC00C7EC5A /* ASCIIBoard.swift */,
|
||||
67FD86881E4105B80023335C /* BoardStride.swift */,
|
||||
67FD868A1E4105D40023335C /* BoardLocation.swift */,
|
||||
@@ -211,6 +307,7 @@
|
||||
67A9C9DA1DE64CD200510FB8 /* Frameworks */,
|
||||
67A9C9DB1DE64CD200510FB8 /* Headers */,
|
||||
67A9C9DC1DE64CD200510FB8 /* Resources */,
|
||||
67B663191F9939A4004621B2 /* Swift Lint */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -246,25 +343,28 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0800;
|
||||
LastUpgradeCheck = 0800;
|
||||
LastUpgradeCheck = 1020;
|
||||
ORGANIZATIONNAME = "Steve Barnegren";
|
||||
TargetAttributes = {
|
||||
67A9C9DD1DE64CD200510FB8 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
67A9C9E61DE64CD300510FB8 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 67A9C9D81DE64CD200510FB8 /* Build configuration list for PBXProject "SwiftChess" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 67A9C9D41DE64CD200510FB8;
|
||||
productRefGroup = 67A9C9DF1DE64CD200510FB8 /* Products */;
|
||||
@@ -294,6 +394,23 @@
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
67B663191F9939A4004621B2 /* Swift Lint */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Swift Lint";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
67A9C9D91DE64CD200510FB8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
@@ -321,6 +438,7 @@
|
||||
67F779241E1C326D00885B89 /* BoardRaterCenterFourOccupation.swift in Sources */,
|
||||
67A9CA011DE64D2500510FB8 /* AIPlayer.swift in Sources */,
|
||||
6719898F1DFFE7550053EA3D /* BoardRaterCenterDominance.swift in Sources */,
|
||||
677BE817200A2D78004B27DB /* DictionaryRepresentable.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -328,6 +446,29 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
673596D622A1B45A003086FF /* BoardRaterCenterDominanceTests.swift in Sources */,
|
||||
673596C422A1B43A003086FF /* SquareTests.swift in Sources */,
|
||||
673596DB22A1B45A003086FF /* BoardRaterThreatenedPiecesTests.swift in Sources */,
|
||||
673596C222A1B43A003086FF /* PieceTests.swift in Sources */,
|
||||
673596BA22A1B43A003086FF /* PerformanceTests.swift in Sources */,
|
||||
673596BF22A1B43A003086FF /* PieceMovementTests.swift in Sources */,
|
||||
673596D822A1B45A003086FF /* BoardRaterKingSurroundingPossession.swift in Sources */,
|
||||
673596BD22A1B43A003086FF /* BoardTests.swift in Sources */,
|
||||
673596D922A1B45A003086FF /* BoardRaterCenterFourOccupationTests.swift in Sources */,
|
||||
673596DC22A1B45A003086FF /* BoardRaterPawnProgressionTests.swift in Sources */,
|
||||
673596BB22A1B43A003086FF /* AIBehaviourTests.swift in Sources */,
|
||||
673596C822A1B448003086FF /* DictionaryRepresentableExtensions.swift in Sources */,
|
||||
673596C122A1B43A003086FF /* PlayerTests.swift in Sources */,
|
||||
673596B922A1B43A003086FF /* AIPlayerTests.swift in Sources */,
|
||||
673596C322A1B43A003086FF /* AIConfigurationTests.swift in Sources */,
|
||||
673596BE22A1B43A003086FF /* OpeningsTests.swift in Sources */,
|
||||
673596D422A1B45A003086FF /* BoardRaterCountPiecesTests.swift in Sources */,
|
||||
673596BC22A1B43A003086FF /* GameTests.swift in Sources */,
|
||||
673596C922A1B448003086FF /* BoardScenarios.swift in Sources */,
|
||||
673596C022A1B43A003086FF /* BoardLocationTests.swift in Sources */,
|
||||
673596DA22A1B45A003086FF /* BoardRaterBoardDominanceTests.swift in Sources */,
|
||||
673596D722A1B45A003086FF /* BoardRaterCenterOwnershipTests.swift in Sources */,
|
||||
673596D522A1B45A003086FF /* BoardRaterCheckMateOpportunityTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -346,20 +487,30 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -399,20 +550,30 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -455,7 +616,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = SteveBarnegren.SwiftChess;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -473,7 +634,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = SteveBarnegren.SwiftChess;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -481,11 +642,14 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
INFOPLIST_FILE = SwiftChessTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = SteveBarnegren.SwiftChessTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -493,11 +657,13 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
INFOPLIST_FILE = SwiftChessTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = SteveBarnegren.SwiftChessTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>1.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
+55
-65
@@ -6,6 +6,8 @@
|
||||
// Copyright © 2017 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
//swiftlint:disable xctfail_message
|
||||
|
||||
/*
|
||||
|
||||
AI behaviour tests are tests that try to avoid or encourage certain behaviours in the AI.
|
||||
@@ -31,8 +33,8 @@ class AIBehaviourTests: XCTestCase {
|
||||
|
||||
func makeGameWithBoard(board: Board, colorToMove: Color) -> Game {
|
||||
|
||||
let whitePlayer = AIPlayer(color: .white)
|
||||
let blackPlayer = AIPlayer(color: .black)
|
||||
let whitePlayer = AIPlayer(color: .white, configuration: AIConfiguration(difficulty: .hard))
|
||||
let blackPlayer = AIPlayer(color: .black, configuration: AIConfiguration(difficulty: .hard))
|
||||
|
||||
let game = Game(firstPlayer: whitePlayer, secondPlayer: blackPlayer, board: board, colorToMove: colorToMove)
|
||||
|
||||
@@ -60,7 +62,7 @@ class AIBehaviourTests: XCTestCase {
|
||||
if endBoardPiece != nil && startBoardPiece != nil {
|
||||
|
||||
if endBoardPiece!.color != startBoardPiece!.color
|
||||
&& endBoardPiece!.type != startBoardPiece!.type{
|
||||
&& endBoardPiece!.type != startBoardPiece!.type {
|
||||
return location
|
||||
}
|
||||
}
|
||||
@@ -77,21 +79,20 @@ class AIBehaviourTests: XCTestCase {
|
||||
|
||||
func test_ScenarioOne_BlackShouldNotGiveAwayBishop() {
|
||||
|
||||
|
||||
// In the following example, the black player can move the bishop at (5,7) to the * location (2,4).
|
||||
// The can look like a good move because the bishop will then threaten the white queen at (3,3).
|
||||
// The white queen will also be threatening the black bishop, but because this is a lower value piece black can think that it is in a more preferrable position.
|
||||
// The white queen will also be threatening the black bishop,
|
||||
// but because this is a lower value piece black can think that it is in a more preferrable position.
|
||||
// In reality, because the black bishop is unprotected, the white queen will take it.
|
||||
|
||||
let board = ASCIIBoard(pieces: "r - b - q b - r" +
|
||||
"p p g - - p p p" +
|
||||
"- - - - - k - -" +
|
||||
"- - * - - - - -" +
|
||||
"- - p Q P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P G - - P P P" +
|
||||
"R K B - - B K R" )
|
||||
|
||||
let board = ASCIIBoard(pieces: "r - b - q b - r" +
|
||||
"p p g - - p p p" +
|
||||
"- - - - - k - -" +
|
||||
"- - * - - - - -" +
|
||||
"- - p Q P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P G - - P P P" +
|
||||
"R K B - - B K R" )
|
||||
|
||||
let location = board .locationOfCharacter("*")
|
||||
|
||||
@@ -102,7 +103,7 @@ class AIBehaviourTests: XCTestCase {
|
||||
return
|
||||
}
|
||||
|
||||
player.makeMove()
|
||||
player.makeMoveSync()
|
||||
|
||||
// If there is not piece at the location, then test has passed
|
||||
guard let piece = game.board.getPiece(at: location) else {
|
||||
@@ -118,63 +119,52 @@ class AIBehaviourTests: XCTestCase {
|
||||
XCTFail("Black moved bishop")
|
||||
}
|
||||
|
||||
func test_ScenarioTwo_BlackShouldTradeKnight() {
|
||||
func testBlackShouldTradePawnForQueen() {
|
||||
|
||||
// In this example, the black knight at (2, 1) can either take the white rook at (0,0), or trade itself for the white queen at (0,2)
|
||||
// Both of these are good moves
|
||||
|
||||
let board = ASCIIBoard(pieces: "- r - - q b k r" +
|
||||
"p - - g - - p p" +
|
||||
"- - - - b p - -" +
|
||||
"- - - - p - - -" +
|
||||
"- - - p P - - -" +
|
||||
"Q - - - - - - -" +
|
||||
"P P k P K P P P" +
|
||||
"R K B G - - - R" )
|
||||
let board = ASCIIBoard(pieces: "g p - - - - - -" +
|
||||
"p p - - - - - -" +
|
||||
"- - - - p - - -" +
|
||||
"- - - - - Q - -" +
|
||||
"- - - - B - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P - - - - - -" +
|
||||
"G P - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(x: 0, y: 2)
|
||||
let rookLocation = BoardLocation(x: 0, y: 0)
|
||||
|
||||
let queenLocation = board.locationOfCharacter("Q")
|
||||
let game = makeGameWithBoard(board: board.board, colorToMove: .black)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
XCTFail("Expected an AI Player")
|
||||
|
||||
guard let player = game.blackPlayer as? AIPlayer else {
|
||||
XCTFail()
|
||||
return
|
||||
}
|
||||
|
||||
player.makeMove()
|
||||
player.makeMoveSync()
|
||||
|
||||
if let queenLocationPiece = game.board.getPiece(at: queenLocation) {
|
||||
|
||||
if queenLocationPiece.color == .black && queenLocationPiece.type == .knight {
|
||||
print("PASSED - Black took queen")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if let rookLocationPiece = game.board.getPiece(at: rookLocation) {
|
||||
|
||||
if rookLocationPiece.color == .black && rookLocationPiece.type == .knight {
|
||||
print("PASSED - black took rook")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
let location = findMovedPieceLocation(startBoard: board.board, endBoard: game.board, color: .black)
|
||||
|
||||
guard let piece = game.board.getPiece(at: location) else {
|
||||
XCTFail("Couldn't find moved piece")
|
||||
return
|
||||
}
|
||||
|
||||
XCTFail("FAILED - Black moved \(piece.type) to (\(location.x),\(location.y))")
|
||||
XCTAssertEqual(game.board.getPiece(at: queenLocation)?.type, .pawn)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
func testBlackShouldTakeWhiteQueenWithPawn() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - p g" +
|
||||
"- - - b - - p p" +
|
||||
"- - - - q - - -" +
|
||||
"- B p k P p - -" +
|
||||
"- - - P Q - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P - - - - - -" +
|
||||
"G P - - - - - -" )
|
||||
|
||||
let queenLocation = board.locationOfCharacter("Q")
|
||||
let game = makeGameWithBoard(board: board.board, colorToMove: .black)
|
||||
|
||||
guard let player = game.blackPlayer as? AIPlayer else {
|
||||
XCTFail()
|
||||
return
|
||||
}
|
||||
|
||||
player.makeMoveSync()
|
||||
|
||||
XCTAssertEqual(game.board.getPiece(at: queenLocation)?.type, .pawn)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
//
|
||||
// AIConfigurationTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 03/01/2017.
|
||||
// Copyright © 2017 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
//swiftlint:disable type_body_length
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class AIConfigurationTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Count Pieces
|
||||
|
||||
func testBoardRaterCountPiecesWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P P P P P P" +
|
||||
"R K B Q G B K R" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
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 = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterCountPieces(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Board Dominance
|
||||
|
||||
func testBoardDominanceWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- P - - - P P -" +
|
||||
"R K B Q G B K R" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
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 = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterBoardDominance(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Center Ownership
|
||||
|
||||
func testCenterOwnershipWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - r g r - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - Q B - - -" +
|
||||
"- - - K P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- P - - - P P -" +
|
||||
"R K B Q G B K R" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
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 = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterCenterOwnership(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Center Dominance
|
||||
|
||||
func testCenterDominanceWeightingAffetsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - r g r - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - Q B - - -" +
|
||||
"- - - K P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- P - - - P P -" +
|
||||
"R K B Q G B K R" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
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 = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterCenterDominance(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Threatened Pieces
|
||||
|
||||
func testBoardRaterThreatenedPiecesWeightingAffectsRating() {
|
||||
|
||||
// White is threatening the black rook with its bishop and knight
|
||||
let board = ASCIIBoard(pieces: "r - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- K - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - B" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
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 = 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 testBoardRaterThreatenedPiecesOwnPiecesWeightingAffectsRating() {
|
||||
|
||||
// White and black rook are threatening each other, so advantage is neutral
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"r - - - - - - R" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
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 = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterThreatenedPieces(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
// Result should be more negative for a higher value, as white is under threat
|
||||
XCTAssertLessThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Pawn Progression
|
||||
|
||||
func testPawnProgressionWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"p p p p p p p p" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P P P P P P" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
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 = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterPawnProgression(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - King Surrounding Possession
|
||||
|
||||
func testKingSurroundingPossessionWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P P P - -" +
|
||||
"- - - P G P - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
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 =
|
||||
AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 10)
|
||||
let highValueRater = BoardRaterKingSurroundingPossession(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Check Mate Opportunity
|
||||
|
||||
func testCheckMateOpportunityWeightingAffectsRating() {
|
||||
|
||||
// White can move Rook at (0,0) to (0,7) to check mate black
|
||||
let board = ASCIIBoard(pieces: "- - - - g p - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P P P - -" +
|
||||
"R - - P G P - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
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 = AIConfiguration.ConfigurationValue(easyValue: 2,
|
||||
difficultValue: 2,
|
||||
multiplier: 1)
|
||||
let highValueRater = BoardRaterCheckMateOpportunity(configuration: highValueConfig)
|
||||
let highValueRating = highValueRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highValueRating, lowValueRating)
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Board Rater - Center Four Occupation
|
||||
|
||||
func testCenterFourOccupationWeightingAffectsRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - p g p - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - K R - - -" +
|
||||
"- - - Q R - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P P P - -" +
|
||||
"- - - P G P - -" )
|
||||
|
||||
var lowValueConfig = AIConfiguration()
|
||||
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 = 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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
//
|
||||
// AIPlayerTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 29/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class AIPlayerTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testExample() {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
// func testPerformanceExample() {
|
||||
// // This is an example of a performance test case.
|
||||
// self.measure {
|
||||
// // Put the code you want to measure the time of here.
|
||||
// }
|
||||
// }
|
||||
|
||||
// MARK: - Test Cannot move in the check
|
||||
|
||||
func makeTestGame(board: Board, colorToMove: Color) -> Game {
|
||||
|
||||
let whitePlayer = AIPlayer(color: .white, configuration: AIConfiguration(difficulty: .hard))
|
||||
let blackPlayer = AIPlayer(color: .black, configuration: AIConfiguration(difficulty: .hard))
|
||||
|
||||
let game = Game(firstPlayer: whitePlayer, secondPlayer: blackPlayer, board: board, colorToMove: colorToMove)
|
||||
return game
|
||||
}
|
||||
|
||||
func testKnightCannotPutOwnKingInToCheck() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "r - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - * - - - - -" +
|
||||
"K - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - - - - - -" )
|
||||
|
||||
let knightLocation = board.locationOfCharacter("K")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(from: knightLocation, to: testLocation))
|
||||
}
|
||||
|
||||
func testKingCannotMoveInToCheck() {
|
||||
|
||||
// This is a complex scenario because it was one that I observed from an actual game
|
||||
|
||||
let board = ASCIIBoard(pieces: "r k - - q b - r" +
|
||||
"p p p g k - - p" +
|
||||
"- - * p b p - -" +
|
||||
"P P - - p - p P" +
|
||||
"- - P - P - - -" +
|
||||
"- B - - Q P - -" +
|
||||
"- B - P K G P -" +
|
||||
"R K - - - - - R" )
|
||||
|
||||
let kingLocation = board.locationOfCharacter("g")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .black)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(from: kingLocation, to: testLocation))
|
||||
}
|
||||
|
||||
func testPawnCannotPutOwnKingInToCheck() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - * - - - -" +
|
||||
"G - - P - - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let pawnLocation = board.locationOfCharacter("P")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(from: pawnLocation, to: testLocation))
|
||||
|
||||
}
|
||||
|
||||
func testQueenCannotPutOwnKingInToCheck() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - * - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - Q - - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenLocation = board.locationOfCharacter("Q")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(from: queenLocation, to: testLocation))
|
||||
}
|
||||
|
||||
func testRookCannotPutOwnKingInToCheck() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - * - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - R - - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rookLocation = board.locationOfCharacter("R")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
XCTAssertFalse(player.canAIMovePiece(from: rookLocation, to: testLocation))
|
||||
}
|
||||
|
||||
func testBishopCannotPutOwnKingInToCheck() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - *" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"G - - B - - - r" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let bishopLocation = board.locationOfCharacter("B")
|
||||
let testLocation = board.locationOfCharacter("*")
|
||||
|
||||
let game = makeTestGame(board: board.board, colorToMove: .white)
|
||||
|
||||
guard let player = game.currentPlayer as? AIPlayer else {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
//
|
||||
// BoardRaterBoardDominanceTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 13/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterBoardDominanceTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterBoardDominance!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
self.boardRater = BoardRaterBoardDominance(configuration: AIConfiguration(difficulty: .hard))
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testSingleQueenResultsInHigherValueThanSinglePawn() {
|
||||
|
||||
let queenBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - Q - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
let queenRating = boardRater.ratingFor(board: queenBoard.board, color: .white)
|
||||
|
||||
let pawnBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
let pawnRating = boardRater.ratingFor(board: pawnBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(queenRating, pawnRating)
|
||||
}
|
||||
|
||||
func testOwnPieceBlockingPathResultsInLowerValue() {
|
||||
|
||||
let blockedBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P - - - - - - -" +
|
||||
"Q P - - - - - -" )
|
||||
let blockedRating = boardRater.ratingFor(board: blockedBoard.board, color: .white)
|
||||
|
||||
let nonBockedBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"Q - - - - - - -" )
|
||||
let nonBockedRating = boardRater.ratingFor(board: nonBockedBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(nonBockedRating, blockedRating)
|
||||
|
||||
}
|
||||
|
||||
func testOpponantDominanceResultsInLowerValue() {
|
||||
|
||||
let whiteDominantBoard = ASCIIBoard(pieces: "R - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - k" +
|
||||
"- - - - - - - p" +
|
||||
"Q - - - - - - -" )
|
||||
let whiteRating = boardRater.ratingFor(board: whiteDominantBoard.board, color: .white)
|
||||
|
||||
let blackDominantBoard = ASCIIBoard(pieces: "r - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - K" +
|
||||
"- - - - - - - P" +
|
||||
"q - - - - - - -" )
|
||||
let blackRating = boardRater.ratingFor(board: blackDominantBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(whiteRating, blackRating)
|
||||
}
|
||||
|
||||
func testQueenInCornerResultsInLowerValueThanQueenInCenter() {
|
||||
|
||||
let queenInCornerBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"Q - - - - - - -" )
|
||||
let queenInCornerRating = boardRater.ratingFor(board: queenInCornerBoard.board, color: .white)
|
||||
|
||||
let queenInCenterBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - Q - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
let queenInCenterRating = boardRater.ratingFor(board: queenInCenterBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(queenInCenterRating, queenInCornerRating)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// BoardRaterCenterDominanceTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 13/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterCenterDominanceTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterCenterDominance!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
boardRater = BoardRaterCenterDominance(configuration: AIConfiguration(difficulty: .hard))
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testPiecesWithCenterVisibilityResultsInHigherValueThanPiecesWithoutCenterVisibility() {
|
||||
|
||||
let centerVisibleBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - Q" +
|
||||
"- - - - - - - R" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
let centerVisibleRating = boardRater.ratingFor(board: centerVisibleBoard.board, color: .white)
|
||||
|
||||
let centerObstructedBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - P -" +
|
||||
"- - - - - - - Q" )
|
||||
let centerObstructedRating = boardRater.ratingFor(board: centerObstructedBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(centerVisibleRating, centerObstructedRating)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
//
|
||||
// BoardRaterCenterFourOccupationTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 03/01/2017.
|
||||
// Copyright © 2017 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterCenterFourOccupationTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func defaultBoardRater() -> BoardRaterCenterFourOccupation {
|
||||
|
||||
let configuration = AIConfiguration(difficulty: .hard)
|
||||
let boardRater = BoardRaterCenterFourOccupation(configuration: configuration)
|
||||
return boardRater
|
||||
}
|
||||
|
||||
func testNorthEastCenterSquareResultsInHigherRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = defaultBoardRater().ratingFor(board: board.board, color: .white)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testSouthEastCenterSquareResultsInHigherRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = defaultBoardRater().ratingFor(board: board.board, color: .white)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testSouthWestCenterSquareResultsInHigherRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = defaultBoardRater().ratingFor(board: board.board, color: .white)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testNorthWestCenterSquareResultsInHigherRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = defaultBoardRater().ratingFor(board: board.board, color: .white)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testNonCenterSquaresResultInZeroRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "P P P P P P P P" +
|
||||
"P P P P P P P P" +
|
||||
"P P P P P P P P" +
|
||||
"P P P - - P P P" +
|
||||
"P P P - - P P P" +
|
||||
"P P P P P P P P" +
|
||||
"P P P P P P P P" +
|
||||
"P P P P P P P P" )
|
||||
|
||||
let rating = defaultBoardRater().ratingFor(board: board.board, color: .white)
|
||||
XCTAssertEqual(rating, 0, accuracy: 0.01)
|
||||
}
|
||||
|
||||
func testOpponentOccupationResultsInNegativeRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - p p - - -" +
|
||||
"- - - p p - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = defaultBoardRater().ratingFor(board: board.board, color: .white)
|
||||
XCTAssertLessThan(rating, 0)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// BoardRaterCenterDominanceTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 13/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterCenterOwnershipTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterCenterOwnership!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
boardRater = BoardRaterCenterOwnership(configuration: AIConfiguration(difficulty: .hard))
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testCenterReturnsHigherValueThatSide() {
|
||||
|
||||
let centerBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - P - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let centerRating = boardRater.ratingFor(board: centerBoard.board, color: .white)
|
||||
|
||||
let sideBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - P -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let sideRating = boardRater.ratingFor(board: sideBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(centerRating, sideRating)
|
||||
}
|
||||
|
||||
}
|
||||
+33
-34
@@ -16,7 +16,7 @@ class BoardRaterCheckMateOpportunityTests: XCTestCase {
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
boardRater = BoardRaterCheckMateOpportunity(configuration: AIConfiguration())
|
||||
boardRater = BoardRaterCheckMateOpportunity(configuration: AIConfiguration(difficulty: .hard))
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
@@ -27,57 +27,57 @@ class BoardRaterCheckMateOpportunityTests: XCTestCase {
|
||||
func testBoardWithNoCheckMateOpportuniesResultsInZeroRating() {
|
||||
|
||||
let board = Board(state: .newGame)
|
||||
let whiteRating = boardRater.ratingfor(board: board, color: .white)
|
||||
let blackRating = boardRater.ratingfor(board: board, color: .black)
|
||||
let whiteRating = boardRater.ratingFor(board: board, color: .white)
|
||||
let blackRating = boardRater.ratingFor(board: board, color: .black)
|
||||
|
||||
let accuracy = Double(0.1)
|
||||
XCTAssertEqualWithAccuracy(whiteRating, 0, accuracy: accuracy)
|
||||
XCTAssertEqualWithAccuracy(blackRating, 0, accuracy: accuracy)
|
||||
XCTAssertEqual(whiteRating, 0, accuracy: accuracy)
|
||||
XCTAssertEqual(blackRating, 0, accuracy: accuracy)
|
||||
}
|
||||
|
||||
func testThatOpponentKingCheckMateOpportunityResultsInPositiveRating() {
|
||||
|
||||
// White can move the rook at (0, 0) to (0, 7) to put black in check mate
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- R - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - G - - -" )
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- R - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - G - - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testThatOwnKingCheckMateOpportunityResultsInNegativeRating() {
|
||||
|
||||
// Black can move the rook at (0, 7) to (0, 0) to put white in check mate
|
||||
let board = ASCIIBoard(pieces: "r - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- r - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
let board = ASCIIBoard(pieces: "r - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- r - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
XCTAssertLessThan(rating, 0)
|
||||
}
|
||||
|
||||
func testThatMultipleCheckMateOpportunitiesResultInHigherRating() {
|
||||
|
||||
// White can move the rook at (0, 0) to (0, 7) to put black in check mate
|
||||
let singleCheckMateBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- R - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - G - - -" )
|
||||
let singleCheckMateBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- R - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - G - - -" )
|
||||
|
||||
// White can also move the rook at (7, 0) to (7, 7) to put black in check mate
|
||||
let multipleCheckMateBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
@@ -89,11 +89,10 @@ class BoardRaterCheckMateOpportunityTests: XCTestCase {
|
||||
"- - - - - - - -" +
|
||||
"R - - - G - - R" )
|
||||
|
||||
let singleRating = boardRater.ratingfor(board: singleCheckMateBoard.board, color: .white)
|
||||
let multipleRating = boardRater.ratingfor(board: multipleCheckMateBoard.board, color: .white)
|
||||
let singleRating = boardRater.ratingFor(board: singleCheckMateBoard.board, color: .white)
|
||||
let multipleRating = boardRater.ratingFor(board: multipleCheckMateBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(multipleRating, singleRating)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// BoardRaterCountPieces.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 26/11/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterCountPiecesTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterCountPieces!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
// Initiailise a new board rater for each test
|
||||
boardRater = BoardRaterCountPieces(configuration: AIConfiguration(difficulty: .hard))
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testWhiteWinningResultsInPositiveValue() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P P P P P P" +
|
||||
"R K B Q G B K R" )
|
||||
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
XCTAssert(rating > 0, "Expected rating to be positive")
|
||||
}
|
||||
|
||||
func testWhiteLosingResultsInNegativeValue() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "r k b q g b k r" +
|
||||
"p p p p p p p p" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
XCTAssert(rating < 0, "Expected rating to be negative")
|
||||
}
|
||||
|
||||
func testGreaterNumberOfPiecesResultsInHigherValue() {
|
||||
|
||||
let fewerPiecesBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P P P P P P" )
|
||||
|
||||
let morePiecesBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P P P P P P" +
|
||||
"P P P P P P P P" )
|
||||
|
||||
let fewerPiecesRating = boardRater.ratingFor(board: fewerPiecesBoard.board, color: .white)
|
||||
let morePiecesRating = boardRater.ratingFor(board: morePiecesBoard.board, color: .white)
|
||||
XCTAssert(morePiecesRating > fewerPiecesRating, "Expected more pieces to produce higher rating")
|
||||
}
|
||||
|
||||
func testHigherValuePiecesResultsInHigherRating() {
|
||||
|
||||
let lowerValuePiecesBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"P P P - - - - -" )
|
||||
|
||||
let higherValuePiecesBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R R R - - - - -" )
|
||||
|
||||
let lowerValuePiecesRating = boardRater.ratingFor(board: lowerValuePiecesBoard.board, color: .white)
|
||||
let higherValuePiecesRating = boardRater.ratingFor(board: higherValuePiecesBoard.board, color: .white)
|
||||
XCTAssert(higherValuePiecesRating > lowerValuePiecesRating,
|
||||
"Expected higher value pieces to produce higher rating")
|
||||
}
|
||||
|
||||
// MARK: - Perfomance
|
||||
|
||||
func testRatingPerformance() {
|
||||
|
||||
let board = Board(state: .newGame)
|
||||
|
||||
self.measure {
|
||||
for _ in 0..<1000 {
|
||||
_ = self.boardRater.ratingFor(board: board, color: .white)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,403 @@
|
||||
//
|
||||
// BoardRaterKingSurroundingPossession.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 29/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
// swiftlint:disable type_body_length
|
||||
// swiftlint:disable file_length
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterKingSurroundingPossessionTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterKingSurroundingPossession!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
boardRater = BoardRaterKingSurroundingPossession(configuration: AIConfiguration(difficulty: .hard))
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
// MARK: - Test obtaining surrounding spaces
|
||||
|
||||
func assertSurroundingSpacesAreCorrect(color: Color, board: ASCIIBoard) {
|
||||
|
||||
let indexes = board.indexesWithCharacter("*")
|
||||
let surroundingLocations = self.boardRater.locationsSurroundingKing(color: color, board: board.board)
|
||||
|
||||
XCTAssertEqual(indexes.count, surroundingLocations.count,
|
||||
"Expected same: (\(indexes.count) indexes \(surroundingLocations.count) surrounding locations).")
|
||||
|
||||
for index in indexes {
|
||||
|
||||
let location = BoardLocation(index: index)
|
||||
let foundLocation = surroundingLocations.contains { $0 == location }
|
||||
|
||||
XCTAssertTrue(foundLocation, "Expected location x: \(location.x) y: \(location.y) to be returned")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func testWhiteKingSurroundingSpacesReturnsCorrectIndexesInCenter() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - * * * - - -" +
|
||||
"- - * G * - - -" +
|
||||
"- - * * * - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .white, board: board)
|
||||
}
|
||||
|
||||
func testWhiteKingSurroundingSpacesReturnsCorrectIndexesInBottomLeft() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"* * - - - - - -" +
|
||||
"G * - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .white, board: board)
|
||||
}
|
||||
|
||||
func testWhiteKingSurroundingSpacesReturnsCorrectIndexesInBottomRight() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - * *" +
|
||||
"- - - - - - * G" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .white, board: board)
|
||||
}
|
||||
|
||||
func testWhiteKingSurroundingSpacesReturnsCorrectIndexesInTopLeft() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "G * - - - - - -" +
|
||||
"* * - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .white, board: board)
|
||||
}
|
||||
|
||||
func testWhiteKingSurroundingSpacesReturnsCorrectIndexesInTopRight() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - * G" +
|
||||
"- - - - - - * *" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .white, board: board)
|
||||
}
|
||||
|
||||
func testBlackKingSurroundingSpacesReturnsCorrectIndexesInCenter() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - * * * - - -" +
|
||||
"- - * g * - - -" +
|
||||
"- - * * * - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .black, board: board)
|
||||
}
|
||||
|
||||
func testBlackKingSurroundingSpacesReturnsCorrectIndexesInBottomLeft() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"* * - - - - - -" +
|
||||
"g * - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .black, board: board)
|
||||
}
|
||||
|
||||
func testBlackKingSurroundingSpacesReturnsCorrectIndexesInBottomRight() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - * *" +
|
||||
"- - - - - - * g" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .black, board: board)
|
||||
}
|
||||
|
||||
func testBlackKingSurroundingSpacesReturnsCorrectIndexesInTopLeft() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "g * - - - - - -" +
|
||||
"* * - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .black, board: board)
|
||||
}
|
||||
|
||||
func testBlackKingSurroundingSpacesReturnsCorrectIndexesInTopRight() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - * g" +
|
||||
"- - - - - - * *" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
assertSurroundingSpacesAreCorrect(color: .black, board: board)
|
||||
}
|
||||
|
||||
// MARK: - Test Ratings
|
||||
|
||||
func testThatGreaterOpponentPossessionOfOurKingSurroundingsResultsInLowerRating() {
|
||||
|
||||
let lowRatingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"r - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let highRatingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"r - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let lowRating = boardRater.ratingFor(board: lowRatingBoard.board, color: .white)
|
||||
let highRating = boardRater.ratingFor(board: highRatingBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highRating, lowRating)
|
||||
}
|
||||
|
||||
func testThatGreaterPossessionOfOurKingSurroundingsResultsInHigherRating() {
|
||||
|
||||
let lowRatingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let highRatingBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let lowRating = boardRater.ratingFor(board: lowRatingBoard.board, color: .white)
|
||||
let highRating = boardRater.ratingFor(board: highRatingBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highRating, lowRating)
|
||||
}
|
||||
|
||||
func testThatGreaterPossessionOfOpponentKingSurroundingsResultsInHigherRating() {
|
||||
|
||||
let lowRatingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let highRatingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"R - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let lowRating = boardRater.ratingFor(board: lowRatingBoard.board, color: .white)
|
||||
let highRating = boardRater.ratingFor(board: highRatingBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highRating, lowRating)
|
||||
}
|
||||
|
||||
func testThatGreaterOpponentPossessionOfOpponentKingSurroundingsResultsInLowerRating() {
|
||||
|
||||
let lowRatingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"r - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let highRatingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"r - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let lowRating = boardRater.ratingFor(board: lowRatingBoard.board, color: .white)
|
||||
let highRating = boardRater.ratingFor(board: highRatingBoard.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(highRating, lowRating)
|
||||
}
|
||||
|
||||
func testThatBlackandWhiteRatingsAreTheSame() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"Q - - - - - - b" +
|
||||
"R - - - p - - q" +
|
||||
"- k - - G - K -" )
|
||||
|
||||
let invertedBoard = ASCIIBoard(pieces: "- - - - G - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"q - - - - - - B" +
|
||||
"r - - - P - - Q" +
|
||||
"- K - - g - k -" )
|
||||
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
let invertedRating = boardRater.ratingFor(board: invertedBoard.board, color: .black)
|
||||
|
||||
XCTAssertEqual(rating, invertedRating, accuracy: 0.01)
|
||||
}
|
||||
|
||||
func testThatPiecesSurroundingOwnKingResultsInPositiveRatingForWhite() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P P P - -" +
|
||||
"- - - P G P - -" )
|
||||
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testThatPiecesSurroundingOwnKingResultsInPositiveRatingForBlack() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - p g p - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .black)
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
func testThatPiecesSurroundingOpponentKingResultsInMoreNegativeRatingForWhite() {
|
||||
|
||||
let openKingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let surroundedKingBoard = ASCIIBoard(pieces: "- - - p g p - -" +
|
||||
"- - - p p p - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let openKingRating = boardRater.ratingFor(board: openKingBoard.board, color: .white)
|
||||
let surroundedKingRating = boardRater.ratingFor(board: surroundedKingBoard.board, color: .white)
|
||||
|
||||
XCTAssertLessThan(surroundedKingRating, openKingRating)
|
||||
}
|
||||
|
||||
func testThatPiecesSurroundingOpponentKingResultsInMoreNegativeRatingForBlack() {
|
||||
|
||||
let openKingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - G - - -" )
|
||||
|
||||
let surroundedKingBoard = ASCIIBoard(pieces: "- - - - g - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P P P - -" +
|
||||
"- - - P G P - -" )
|
||||
|
||||
let openKingRating = boardRater.ratingFor(board: openKingBoard.board, color: .black)
|
||||
let surroundedKingRating = boardRater.ratingFor(board: surroundedKingBoard.board, color: .black)
|
||||
XCTAssertLessThan(surroundedKingRating, openKingRating)
|
||||
}
|
||||
|
||||
}
|
||||
+55
-56
@@ -17,7 +17,7 @@ class BoardRaterPawnProgressionTests: XCTestCase {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
boardRater = BoardRaterPawnProgression(configuration: AIConfiguration())
|
||||
boardRater = BoardRaterPawnProgression(configuration: AIConfiguration(difficulty: .hard))
|
||||
|
||||
}
|
||||
|
||||
@@ -28,14 +28,14 @@ class BoardRaterPawnProgressionTests: XCTestCase {
|
||||
|
||||
func testProgressedPawnResultsInHigherRatingForWhitePlayer() {
|
||||
|
||||
let progressedBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- P - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
let progressedBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- P - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let lessProgressedBoard = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
@@ -46,8 +46,8 @@ class BoardRaterPawnProgressionTests: XCTestCase {
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let progressedRating = boardRater.ratingfor(board: progressedBoard.board, color: .white)
|
||||
let lessProgressedRating = boardRater.ratingfor(board: lessProgressedBoard.board, color: .white)
|
||||
let progressedRating = boardRater.ratingFor(board: progressedBoard.board, color: .white)
|
||||
let lessProgressedRating = boardRater.ratingFor(board: lessProgressedBoard.board, color: .white)
|
||||
|
||||
XCTAssert(progressedRating > lessProgressedRating)
|
||||
}
|
||||
@@ -72,77 +72,76 @@ class BoardRaterPawnProgressionTests: XCTestCase {
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let progressedRating = boardRater.ratingfor(board: progressedBoard.board, color: .black)
|
||||
let lessProgressedRating = boardRater.ratingfor(board: lessProgressedBoard.board, color: .black)
|
||||
let progressedRating = boardRater.ratingFor(board: progressedBoard.board, color: .black)
|
||||
let lessProgressedRating = boardRater.ratingFor(board: lessProgressedBoard.board, color: .black)
|
||||
|
||||
XCTAssert(progressedRating > lessProgressedRating)
|
||||
}
|
||||
|
||||
func testWhitePawnsOnStartingRowResultInZeroRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- P - P - - P -" +
|
||||
"- - - - - - - -" )
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- P - P - - P -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertEqualWithAccuracy(rating, 0, accuracy: 0.0001)
|
||||
XCTAssertEqual(rating, 0, accuracy: 0.0001)
|
||||
}
|
||||
|
||||
func testBlackPawnsOnStartingRowResultInZeroRating() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- p - p - - p -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- p - p - - p -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = boardRater.ratingfor(board: board.board, color: .black)
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .black)
|
||||
|
||||
XCTAssertEqualWithAccuracy(rating, 0, accuracy: 0.0001)
|
||||
XCTAssertEqual(rating, 0, accuracy: 0.0001)
|
||||
}
|
||||
|
||||
func testWhiteAndBlackPawnRelativeSquaresResultInTheSameValue() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - p" +
|
||||
"P - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - p" +
|
||||
"P - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let whiteRating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
let blackRating = boardRater.ratingfor(board: board.board, color: .black)
|
||||
let whiteRating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
let blackRating = boardRater.ratingFor(board: board.board, color: .black)
|
||||
|
||||
XCTAssertEqualWithAccuracy(whiteRating, blackRating, accuracy: 0.0001)
|
||||
XCTAssertEqual(whiteRating, blackRating, accuracy: 0.0001)
|
||||
}
|
||||
|
||||
func testTotalWhiteAndBlackRowsValueAreEqual() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" )
|
||||
let board = ASCIIBoard(pieces: "P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" +
|
||||
"P - - - - - - p" )
|
||||
|
||||
let whiteRating = boardRater.ratingfor(board: board.board, color: .white)
|
||||
let blackRating = boardRater.ratingfor(board: board.board, color: .black)
|
||||
let whiteRating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
let blackRating = boardRater.ratingFor(board: board.board, color: .black)
|
||||
|
||||
XCTAssertEqualWithAccuracy(whiteRating, blackRating, accuracy: 0.0001)
|
||||
XCTAssertEqual(whiteRating, blackRating, accuracy: 0.0001)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
//
|
||||
// BoardRaterThreatenedPiecesTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steven Barnegren on 14/12/2016.
|
||||
// Copyright © 2016 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
// swiftlint:disable type_body_length
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class BoardRaterThreatenedPiecesTests: XCTestCase {
|
||||
|
||||
var boardRater: BoardRaterThreatenedPieces!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
boardRater = BoardRaterThreatenedPieces(configuration: AIConfiguration(difficulty: .hard))
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testBoardRaterThreatededPiecesReturnsNoThreatIfNoOtherPieces() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - Q - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertEqual(rating, 0, accuracy: 0.01)
|
||||
}
|
||||
|
||||
func testBoardRaterThreatenedPiecesReturnsNegativeValueIfThreatened() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"q - - - - - K -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertLessThan(rating, 0)
|
||||
}
|
||||
|
||||
func testBoardRaterThreatenedPiecesReturnsPositiveValueIfThreateningOpponant() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"Q - - - - - k -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let rating = boardRater.ratingFor(board: board.board, color: .white)
|
||||
|
||||
XCTAssertGreaterThan(rating, 0)
|
||||
}
|
||||
|
||||
// MARK: - Get protected pieces tests
|
||||
|
||||
func testGetProtectingPiecesReturnsProtectingPieces() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - K - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - R -" +
|
||||
"- - - B - - - -" )
|
||||
|
||||
let expectedIndexes = [
|
||||
board.indexOfCharacter("K"),
|
||||
board.indexOfCharacter("R"),
|
||||
board.indexOfCharacter("B")
|
||||
]
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
let gameBoard = board.board
|
||||
let protectingLocations = boardRater.getPieces(protecting: gameBoard.getPiece(at: queenLocation)!,
|
||||
on: board.board).map { $0.location }
|
||||
|
||||
// Check all of the expected locations appeared in the protecting locations array
|
||||
for expectedIndex in expectedIndexes {
|
||||
var foundIndex = false
|
||||
|
||||
for location in protectingLocations {
|
||||
if location == BoardLocation(index: expectedIndex) {
|
||||
foundIndex = true
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(foundIndex, "Failed to find expected index \(expectedIndex)")
|
||||
}
|
||||
|
||||
// Check all of the protecting locations were expected
|
||||
for location in protectingLocations {
|
||||
var wasExpected = false
|
||||
|
||||
for expectedIndex in expectedIndexes {
|
||||
if location == BoardLocation(index: expectedIndex) {
|
||||
wasExpected = true
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(wasExpected, "Found unexpected protecting location \(location)")
|
||||
}
|
||||
}
|
||||
|
||||
func testGetProtectingPiecesDoesntReturnNonProtectingPiecesOfSameColor() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - K - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"R - - - - - - -" +
|
||||
"- B - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
let gameBoard = board.board
|
||||
|
||||
let protectingPieces = boardRater.getPieces(protecting: gameBoard.getPiece(at: queenLocation)!,
|
||||
on: gameBoard)
|
||||
|
||||
// None of the pieces are protecting the queen, so expect count to be zero
|
||||
XCTAssertTrue(protectingPieces.count == 0)
|
||||
}
|
||||
|
||||
func testGetProtectingPiecesDoesntReturnThreateningPiecesOfOppositeColor() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - k - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - r -" +
|
||||
"- - - b - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
let gameBoard = board.board
|
||||
|
||||
let protectingPieces = boardRater.getPieces(protecting: gameBoard.getPiece(at: queenLocation)!,
|
||||
on: gameBoard)
|
||||
|
||||
// The black pieces cannot protect the white queen, so expect count to be zero
|
||||
XCTAssertTrue(protectingPieces.count == 0)
|
||||
}
|
||||
|
||||
func testGetProtectingPiecesDoesntReturnPawnsMovingStraightAhead() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - P -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
let gameBoard = board.board
|
||||
|
||||
let protectingPieces = boardRater.getPieces(protecting: gameBoard.getPiece(at: queenLocation)!,
|
||||
on: gameBoard)
|
||||
|
||||
XCTAssertTrue(protectingPieces.count == 0)
|
||||
|
||||
}
|
||||
|
||||
func testGetProtectingPiecesReturnsPawnsMovingDiagonally() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - P - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
let gameBoard = board.board
|
||||
|
||||
let protectingPieces = boardRater.getPieces(protecting: gameBoard.getPiece(at: queenLocation)!,
|
||||
on: gameBoard)
|
||||
|
||||
XCTAssertTrue(protectingPieces.count == 1)
|
||||
}
|
||||
|
||||
// MARK: - Get threatening pieces tests
|
||||
|
||||
func testGetThreateningPiecesReturnsThreateningPieces() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - k - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - r -" +
|
||||
"- - - b - - - -" )
|
||||
|
||||
let expectedIndexes = [
|
||||
board.indexOfCharacter("k"),
|
||||
board.indexOfCharacter("r"),
|
||||
board.indexOfCharacter("b")
|
||||
]
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
let gameBoard = board.board
|
||||
|
||||
let threateningLocations = boardRater.getPieces(threatening: gameBoard.getPiece(at: queenLocation)!,
|
||||
on: gameBoard).map { $0.location }
|
||||
|
||||
// Check all of the expected locations appeared in the protecting locations array
|
||||
for expectedIndex in expectedIndexes {
|
||||
var foundIndex = false
|
||||
|
||||
for location in threateningLocations {
|
||||
if location == BoardLocation(index: expectedIndex) {
|
||||
foundIndex = true
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(foundIndex, "Failed to find expected index \(expectedIndex)")
|
||||
}
|
||||
|
||||
// Check all of the protecting locations were expected
|
||||
for location in threateningLocations {
|
||||
var wasExpected = false
|
||||
|
||||
for expectedIndex in expectedIndexes {
|
||||
if location == BoardLocation(index: expectedIndex) {
|
||||
wasExpected = true
|
||||
}
|
||||
}
|
||||
|
||||
XCTAssertTrue(wasExpected, "Found unexpected threatening location \(location)")
|
||||
}
|
||||
}
|
||||
|
||||
func testGetThreateningPiecesDoesntReturnNonThreateningPiecesOfOppositeColor() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - k - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"r - - - - - - -" +
|
||||
"- b - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
let gameBoard = board.board
|
||||
|
||||
let threateningPieces = boardRater.getPieces(threatening: gameBoard.getPiece(at: queenLocation)!,
|
||||
on: gameBoard)
|
||||
|
||||
// None of the pieces are threatening the queen, so expect count to be zero
|
||||
XCTAssertTrue(threateningPieces.count == 0)
|
||||
}
|
||||
|
||||
func testGetThreateningPiecesDoesntReturnProtectingPiecesOfSameColor() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - K - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - Q -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - R -" +
|
||||
"- - - B - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("Q"))
|
||||
let gameBoard = board.board
|
||||
|
||||
let threateningPieces = boardRater.getPieces(threatening: gameBoard.getPiece(at: queenLocation)!,
|
||||
on: gameBoard)
|
||||
|
||||
// The white pieces cannot threaten the white queen, so expect count to be zero
|
||||
XCTAssertTrue(threateningPieces.count == 0)
|
||||
}
|
||||
|
||||
func testGetThreateningPiecesDoesntReturnPawnsMovingStraightAhead() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - q -" +
|
||||
"- - - - - - P -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("q"))
|
||||
let gameBoard = board.board
|
||||
|
||||
let threateningPieces = boardRater.getPieces(threatening: gameBoard.getPiece(at: queenLocation)!,
|
||||
on: gameBoard)
|
||||
|
||||
XCTAssertTrue(threateningPieces.count == 0)
|
||||
}
|
||||
|
||||
func testGetThreateningPiecesReturnsPawnsMovingDiagonally() {
|
||||
|
||||
let board = ASCIIBoard(pieces: "- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - q -" +
|
||||
"- - - - - P - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" )
|
||||
|
||||
let queenLocation = BoardLocation(index: board.indexOfCharacter("q"))
|
||||
let gameBoard = board.board
|
||||
|
||||
let threateningPieces = boardRater.getPieces(threatening: gameBoard.getPiece(at: queenLocation)!,
|
||||
on: gameBoard)
|
||||
|
||||
XCTAssertTrue(threateningPieces.count == 1)
|
||||
}
|
||||
|
||||
}
|
||||
+42
-10
@@ -6,6 +6,8 @@
|
||||
// Copyright © 2017 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
//swiftlint:disable function_body_length
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
@@ -95,10 +97,9 @@ class BoardLocationTests: XCTestCase {
|
||||
(BoardLocation.GridPosition.e8, 60),
|
||||
(BoardLocation.GridPosition.f8, 61),
|
||||
(BoardLocation.GridPosition.g8, 62),
|
||||
(BoardLocation.GridPosition.h8, 63),
|
||||
(BoardLocation.GridPosition.h8, 63)
|
||||
]
|
||||
|
||||
|
||||
for (grid, index) in testCases {
|
||||
XCTAssertEqual(BoardLocation(gridPosition: grid).index, index)
|
||||
XCTAssertEqual(BoardLocation(index: index).gridPosition, grid)
|
||||
@@ -108,14 +109,15 @@ class BoardLocationTests: XCTestCase {
|
||||
|
||||
func testMoveLocationsForColorReturnsCorrectLocations() {
|
||||
|
||||
class FakeOpening : Opening {
|
||||
override func moveGridPositions() -> [(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
class FakeOpening: Opening {
|
||||
override func moveGridPositions()
|
||||
-> [(fromPosition: BoardLocation.GridPosition, toPosition: BoardLocation.GridPosition)] {
|
||||
let moves: [(BoardLocation.GridPosition, BoardLocation.GridPosition)] = [
|
||||
(.e2, .e4), // white moves pawn to e4
|
||||
(.e7, .e5), // black moves pawn to e5
|
||||
(.g1, .f3), // white moves knight to f3
|
||||
(.b8, .c6), // black moves knight to c6
|
||||
(.f1, .b5), // white moves bishop to b5
|
||||
(.f1, .b5) // white moves bishop to b5
|
||||
]
|
||||
return moves
|
||||
}
|
||||
@@ -124,20 +126,20 @@ class BoardLocationTests: XCTestCase {
|
||||
let expectedWhiteLocations: [(fromLocation: BoardLocation, toLocation: BoardLocation)] = [
|
||||
(BoardLocation(gridPosition: .e2), BoardLocation(gridPosition: .e4)),
|
||||
(BoardLocation(gridPosition: .g1), BoardLocation(gridPosition: .f3)),
|
||||
(BoardLocation(gridPosition: .f1), BoardLocation(gridPosition: .b5)),
|
||||
(BoardLocation(gridPosition: .f1), BoardLocation(gridPosition: .b5))
|
||||
]
|
||||
|
||||
let expectedBlackLocations: [(fromLocation: BoardLocation, toLocation: BoardLocation)] = [
|
||||
(BoardLocation(gridPosition: .e7), BoardLocation(gridPosition: .e5)),
|
||||
(BoardLocation(gridPosition: .b8), BoardLocation(gridPosition: .c6)),
|
||||
(BoardLocation(gridPosition: .b8), BoardLocation(gridPosition: .c6))
|
||||
]
|
||||
|
||||
let opening = FakeOpening()
|
||||
|
||||
let whiteMoves = opening.moves(forColor: .white)
|
||||
let whiteMoves = opening.moves(for: .white)
|
||||
XCTAssertEqual(whiteMoves.count, expectedWhiteLocations.count)
|
||||
|
||||
let blackMoves = opening.moves(forColor: .black)
|
||||
let blackMoves = opening.moves(for: .black)
|
||||
XCTAssertEqual(blackMoves.count, expectedBlackLocations.count)
|
||||
|
||||
for i in 0..<whiteMoves.count {
|
||||
@@ -157,5 +159,35 @@ class BoardLocationTests: XCTestCase {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
func testIsDarkSquareReturnsExpectedValue() {
|
||||
|
||||
let board = ASCIIBoard(colors: "! * ! * ! * ! *" +
|
||||
"* ! * ! * ! * !" +
|
||||
"! * ! * ! * ! *" +
|
||||
"* ! * ! * ! * !" +
|
||||
"! * ! * ! * ! *" +
|
||||
"* ! * ! * ! * !" +
|
||||
"! * ! * ! * ! *" +
|
||||
"* ! * ! * ! * !" )
|
||||
|
||||
let darkLocatons = board.locationsWithCharacter("*")
|
||||
let lightLocations = board.locationsWithCharacter("!")
|
||||
|
||||
darkLocatons.forEach {
|
||||
XCTAssertTrue($0.isDarkSquare, "Expected \($0) to be dark")
|
||||
}
|
||||
|
||||
lightLocations.forEach {
|
||||
XCTAssertFalse($0.isDarkSquare, "Expected \($0) to be light")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Dictionary Representable
|
||||
|
||||
func testDictionaryRepresentable() {
|
||||
|
||||
let location = BoardLocation(index: 14)
|
||||
XCTAssertEqual(location, location.toDictionaryAndBack)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -64,19 +64,19 @@ class GameTests: XCTestCase {
|
||||
|
||||
// White player moves pawn
|
||||
do {
|
||||
try whitePlayer.movePiece(fromLocation: BoardLocation(x: 0, y: 1),
|
||||
toLocation: BoardLocation(x: 0, y: 2))
|
||||
try whitePlayer.movePiece(from: BoardLocation(x: 0, y: 1),
|
||||
to: BoardLocation(x: 0, y: 2))
|
||||
} catch {
|
||||
XCTFail()
|
||||
XCTFail("Expected to be able to move piece")
|
||||
return
|
||||
}
|
||||
|
||||
// Black player moves pawn
|
||||
do {
|
||||
try blackPlayer.movePiece(fromLocation: BoardLocation(x: 7, y: 6),
|
||||
toLocation: BoardLocation(x: 7, y: 5))
|
||||
try blackPlayer.movePiece(from: BoardLocation(x: 7, y: 6),
|
||||
to: BoardLocation(x: 7, y: 5))
|
||||
} catch {
|
||||
XCTFail()
|
||||
XCTFail("Expected to be able to move piece")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -107,8 +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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,7 +30,7 @@ class OpeningsTests: XCTestCase {
|
||||
print("Testing \(opening)")
|
||||
|
||||
var board = Board(state: .newGame)
|
||||
for (source, target) in opening.moveLocations(){
|
||||
for (source, target) in opening.moveLocations() {
|
||||
|
||||
// Assert that the piece exists
|
||||
guard let piece = board.getPiece(at: source) else {
|
||||
@@ -39,10 +39,9 @@ class OpeningsTests: XCTestCase {
|
||||
}
|
||||
|
||||
// Assert the piece can move
|
||||
if piece.movement.canPieceMove(fromLocation: source, toLocation: target, board: board) {
|
||||
board.movePiece(fromLocation: source, toLocation: target)
|
||||
}
|
||||
else{
|
||||
if piece.movement.canPieceMove(from: source, to: target, board: board) {
|
||||
board.movePiece(from: source, to: target)
|
||||
} else {
|
||||
XCTFail("Cannot move piece from \(source) to \(target)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
//
|
||||
// PerformanceTests.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Steve Barnegren on 02/02/2017.
|
||||
// Copyright © 2017 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftChess
|
||||
|
||||
class PerformanceTests: XCTestCase {
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testPawnMoveValidationPerformance() {
|
||||
|
||||
let board = Board(state: .newGame)
|
||||
let pawnLocation = BoardLocation(x: 0, y: 1)
|
||||
|
||||
guard let pawn = board.getPiece(at: pawnLocation) else {
|
||||
XCTFail("Expected to be able to get piece")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssert(pawn.type == .pawn)
|
||||
|
||||
self.measure {
|
||||
|
||||
BoardLocation.all.forEach {
|
||||
_ = pawn.movement.canPieceMove(from: pawnLocation,
|
||||
to: $0,
|
||||
board: board)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testQueenMoveValidationPerformance() {
|
||||
|
||||
let asciiBoard = ASCIIBoard(pieces: "- - - - - - - g" +
|
||||
"- - - R - - p -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - Q - - - r" +
|
||||
"- - - - - - - -" +
|
||||
"P P - - - - - -" +
|
||||
"G - - - - - - -" )
|
||||
|
||||
let queenLocation = asciiBoard.locationOfCharacter("Q")
|
||||
let board = asciiBoard.board
|
||||
|
||||
guard let queen = board.getPiece(at: queenLocation) else {
|
||||
XCTFail("Expected to be able to get piece")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssert(queen.type == .queen)
|
||||
|
||||
self.measure {
|
||||
|
||||
BoardLocation.all.forEach {
|
||||
_ = queen.movement.canPieceMove(from: queenLocation,
|
||||
to: $0,
|
||||
board: board)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testKingMoveValidationPerformance() {
|
||||
|
||||
let asciiBoard = ASCIIBoard(pieces: "- - - - - - - g" +
|
||||
"- - - R - - p -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - Q - - - r" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P - - - -" +
|
||||
"- - - G - - - -" )
|
||||
|
||||
let kingLocation = asciiBoard.locationOfCharacter("G")
|
||||
let board = asciiBoard.board
|
||||
|
||||
guard let king = board.getPiece(at: kingLocation) else {
|
||||
XCTFail("Expected to be able tp get piece")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssert(king.type == .king)
|
||||
|
||||
self.measure {
|
||||
|
||||
BoardLocation.all.forEach {
|
||||
_ = king.movement.canPieceMove(from: kingLocation,
|
||||
to: $0,
|
||||
board: board)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testKnightMoveValidationPerformance() {
|
||||
|
||||
let asciiBoard = ASCIIBoard(pieces: "- - - - - - - g" +
|
||||
"- - - R - - p -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - Q - K - r" +
|
||||
"- - - - - - - -" +
|
||||
"- - - P - - - -" +
|
||||
"- - - G - - - -" )
|
||||
|
||||
let knightLocation = asciiBoard.locationOfCharacter("K")
|
||||
let board = asciiBoard.board
|
||||
|
||||
guard let knight = board.getPiece(at: knightLocation) else {
|
||||
XCTFail("Exected to be able to get piece")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssert(knight.type == .knight)
|
||||
|
||||
self.measure {
|
||||
|
||||
BoardLocation.all.forEach {
|
||||
_ = knight.movement.canPieceMove(from: knightLocation,
|
||||
to: $0,
|
||||
board: board)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testBishopMoveValidationPerformance() {
|
||||
|
||||
let asciiBoard = ASCIIBoard(pieces: "- - - - - - - g" +
|
||||
"- - - R - - p -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - - - - - -" +
|
||||
"- - - Q - K - r" +
|
||||
"- - - - - B - -" +
|
||||
"- - - P - - - -" +
|
||||
"- - - G - - - -" )
|
||||
|
||||
let bishopLocation = asciiBoard.locationOfCharacter("B")
|
||||
let board = asciiBoard.board
|
||||
|
||||
guard let bishop = board.getPiece(at: bishopLocation) else {
|
||||
XCTFail("Expected to be able to get piece")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssert(bishop.type == .bishop)
|
||||
|
||||
self.measure {
|
||||
|
||||
BoardLocation.all.forEach {
|
||||
_ = bishop.movement.canPieceMove(from: bishopLocation,
|
||||
to: $0,
|
||||
board: board)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testRookMoveValidationPerformance() {
|
||||
|
||||
let asciiBoard = ASCIIBoard(pieces: "- - - - - - - g" +
|
||||
"- - - - - - p -" +
|
||||
"- - - - - - - -" +
|
||||
"- R - - - - - -" +
|
||||
"- - - Q - K - r" +
|
||||
"- - - - - B - -" +
|
||||
"- - - P - - - -" +
|
||||
"- - - G - - - -" )
|
||||
|
||||
let rookLocation = asciiBoard.locationOfCharacter("R")
|
||||
let board = asciiBoard.board
|
||||
|
||||
guard let rook = board.getPiece(at: rookLocation) else {
|
||||
XCTFail("Expected to be able to get piece")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssert(rook.type == .rook)
|
||||
|
||||
self.measure {
|
||||
|
||||
BoardLocation.all.forEach {
|
||||
_ = rook.movement.canPieceMove(from: rookLocation,
|
||||
to: $0,
|
||||
board: board)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testCanAnyPieceMovePerformance() {
|
||||
|
||||
let asciiBoard = ASCIIBoard(pieces: "r - b q g b - r" +
|
||||
"p p p - - p - -" +
|
||||
"k - - - p - - k" +
|
||||
"- - - p - - - -" +
|
||||
"- - - P - - - -" +
|
||||
"K - - - P - - -" +
|
||||
"P P P - - P P -" +
|
||||
"R - B Q G B K R" )
|
||||
|
||||
let board = asciiBoard.board
|
||||
|
||||
self.measure {
|
||||
|
||||
BoardLocation.all.forEach {
|
||||
_ = board.canColorMoveAnyPieceToLocation(color: .white, location: $0)
|
||||
_ = board.canColorMoveAnyPieceToLocation(color: .black, location: $0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user