Initial check-in into Mercurial. Branched from 1.0 release of Apple's sample code. No longer requires garbage collection. Fixed some memory leaks of CG objects. Fixed a bug when advancing to the 8th row in the Checkers game.
authorJens Alfke <jens@mooseyard.com>
Fri Mar 07 11:43:02 2008 -0800 (2008-03-07)
changeset 0e9f7ba4718e1
child 1 3eb7be1dd7b6
Initial check-in into Mercurial. Branched from 1.0 release of Apple's sample code. No longer requires garbage collection. Fixed some memory leaks of CG objects. Fixed a bug when advancing to the 8th row in the Checkers game.
.hgignore
English.lproj/InfoPlist.strings
English.lproj/MainMenu.nib/designable.nib
English.lproj/MainMenu.nib/keyedobjects.nib
GeekGameBoard.xcodeproj/project.pbxproj
Read Me.rtf
Resources/Green Ball.png
Resources/Info.plist
Resources/Red Ball.png
Resources/White Ball.png
Resources/Wood.jpg
Resources/Yellow Ball.png
Source/Bit.h
Source/Bit.m
Source/BitHolder.h
Source/BitHolder.m
Source/BoardView.h
Source/BoardView.m
Source/Card.h
Source/Card.m
Source/CheckersGame.h
Source/CheckersGame.m
Source/Deck.h
Source/Deck.m
Source/DemoBoardView.h
Source/DemoBoardView.m
Source/DiscPiece.h
Source/DiscPiece.m
Source/Dispenser.h
Source/Dispenser.m
Source/GGBUtils.h
Source/GGBUtils.m
Source/Game.h
Source/Game.m
Source/GeekGameBoard_Prefix.pch
Source/GoGame.h
Source/GoGame.m
Source/Grid.h
Source/Grid.m
Source/HexGrid.h
Source/HexGrid.m
Source/HexchequerGame.h
Source/HexchequerGame.m
Source/KlondikeGame.h
Source/KlondikeGame.m
Source/Piece.h
Source/Piece.m
Source/PlayingCard.h
Source/PlayingCard.m
Source/QuartzUtils.h
Source/QuartzUtils.m
Source/Stack.h
Source/Stack.m
Source/TicTacToeGame.h
Source/TicTacToeGame.m
Source/main.m
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Fri Mar 07 11:43:02 2008 -0800
     1.3 @@ -0,0 +1,9 @@
     1.4 +syntax: glob
     1.5 +.DS_Store
     1.6 +build
     1.7 +.svn
     1.8 +*.pbxuser
     1.9 +*.perspectivev3
    1.10 +*.mpkg
    1.11 +*.framework
    1.12 +(*)
    1.13 \ No newline at end of file
     2.1 Binary file English.lproj/InfoPlist.strings has changed
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/English.lproj/MainMenu.nib/designable.nib	Fri Mar 07 11:43:02 2008 -0800
     3.3 @@ -0,0 +1,2126 @@
     3.4 +<?xml version="1.0" encoding="UTF-8"?>
     3.5 +<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.01">
     3.6 +	<data>
     3.7 +		<int key="IBDocument.SystemTarget">0</int>
     3.8 +		<string key="IBDocument.SystemVersion">9B18</string>
     3.9 +		<string key="IBDocument.InterfaceBuilderVersion">629</string>
    3.10 +		<string key="IBDocument.AppKitVersion">949</string>
    3.11 +		<string key="IBDocument.HIToolboxVersion">343.00</string>
    3.12 +		<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
    3.13 +			<bool key="EncodedWithXMLCoder">YES</bool>
    3.14 +			<integer value="380"/>
    3.15 +			<integer value="371"/>
    3.16 +		</object>
    3.17 +		<object class="NSArray" key="IBDocument.PluginDependencies">
    3.18 +			<bool key="EncodedWithXMLCoder">YES</bool>
    3.19 +			<string id="617114957">com.apple.InterfaceBuilderKit</string>
    3.20 +			<string id="248469711">com.apple.InterfaceBuilder.CocoaPlugin</string>
    3.21 +		</object>
    3.22 +		<object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
    3.23 +			<bool key="EncodedWithXMLCoder">YES</bool>
    3.24 +			<object class="NSCustomObject" id="1021">
    3.25 +				<string key="NSClassName" id="1039455869">NSApplication</string>
    3.26 +			</object>
    3.27 +			<object class="NSCustomObject" id="1014">
    3.28 +				<string key="NSClassName">FirstResponder</string>
    3.29 +			</object>
    3.30 +			<object class="NSCustomObject" id="1050">
    3.31 +				<reference key="NSClassName" ref="1039455869"/>
    3.32 +			</object>
    3.33 +			<object class="NSMenu" id="649796088">
    3.34 +				<string key="NSTitle">AMainMenu</string>
    3.35 +				<object class="NSMutableArray" key="NSMenuItems">
    3.36 +					<bool key="EncodedWithXMLCoder">YES</bool>
    3.37 +					<object class="NSMenuItem" id="694149608">
    3.38 +						<reference key="NSMenu" ref="649796088"/>
    3.39 +						<string key="NSTitle" id="101265034">GeekGameBoard</string>
    3.40 +						<string key="NSKeyEquiv" id="1003"/>
    3.41 +						<int key="NSKeyEquivModMask">1048576</int>
    3.42 +						<int key="NSMnemonicLoc">2147483647</int>
    3.43 +						<object class="NSCustomResource" key="NSOnImage" id="484312224">
    3.44 +							<string key="NSClassName" id="140112029">NSImage</string>
    3.45 +							<string key="NSResourceName">NSMenuCheckmark</string>
    3.46 +						</object>
    3.47 +						<object class="NSCustomResource" key="NSMixedImage" id="309443010">
    3.48 +							<reference key="NSClassName" ref="140112029"/>
    3.49 +							<string key="NSResourceName">NSMenuMixedState</string>
    3.50 +						</object>
    3.51 +						<string key="NSAction">submenuAction:</string>
    3.52 +						<object class="NSMenu" key="NSSubmenu" id="110575045">
    3.53 +							<reference key="NSTitle" ref="101265034"/>
    3.54 +							<object class="NSMutableArray" key="NSMenuItems">
    3.55 +								<bool key="EncodedWithXMLCoder">YES</bool>
    3.56 +								<object class="NSMenuItem" id="238522557">
    3.57 +									<reference key="NSMenu" ref="110575045"/>
    3.58 +									<string key="NSTitle">About GeekGameBoard</string>
    3.59 +									<reference key="NSKeyEquiv" ref="1003"/>
    3.60 +									<int key="NSMnemonicLoc">2147483647</int>
    3.61 +									<reference key="NSOnImage" ref="484312224"/>
    3.62 +									<reference key="NSMixedImage" ref="309443010"/>
    3.63 +								</object>
    3.64 +								<object class="NSMenuItem" id="304266470">
    3.65 +									<reference key="NSMenu" ref="110575045"/>
    3.66 +									<bool key="NSIsDisabled">YES</bool>
    3.67 +									<bool key="NSIsSeparator">YES</bool>
    3.68 +									<reference key="NSTitle" ref="1003"/>
    3.69 +									<reference key="NSKeyEquiv" ref="1003"/>
    3.70 +									<int key="NSKeyEquivModMask">1048576</int>
    3.71 +									<int key="NSMnemonicLoc">2147483647</int>
    3.72 +									<reference key="NSOnImage" ref="484312224"/>
    3.73 +									<reference key="NSMixedImage" ref="309443010"/>
    3.74 +								</object>
    3.75 +								<object class="NSMenuItem" id="609285721">
    3.76 +									<reference key="NSMenu" ref="110575045"/>
    3.77 +									<string type="base64-UTF8" key="NSTitle">UHJlZmVyZW5jZXPigKY</string>
    3.78 +									<string key="NSKeyEquiv">,</string>
    3.79 +									<int key="NSKeyEquivModMask">1048576</int>
    3.80 +									<int key="NSMnemonicLoc">2147483647</int>
    3.81 +									<reference key="NSOnImage" ref="484312224"/>
    3.82 +									<reference key="NSMixedImage" ref="309443010"/>
    3.83 +								</object>
    3.84 +								<object class="NSMenuItem" id="481834944">
    3.85 +									<reference key="NSMenu" ref="110575045"/>
    3.86 +									<bool key="NSIsDisabled">YES</bool>
    3.87 +									<bool key="NSIsSeparator">YES</bool>
    3.88 +									<reference key="NSTitle" ref="1003"/>
    3.89 +									<reference key="NSKeyEquiv" ref="1003"/>
    3.90 +									<int key="NSKeyEquivModMask">1048576</int>
    3.91 +									<int key="NSMnemonicLoc">2147483647</int>
    3.92 +									<reference key="NSOnImage" ref="484312224"/>
    3.93 +									<reference key="NSMixedImage" ref="309443010"/>
    3.94 +								</object>
    3.95 +								<object class="NSMenuItem" id="1046388886">
    3.96 +									<reference key="NSMenu" ref="110575045"/>
    3.97 +									<string key="NSTitle" id="487627014">Services</string>
    3.98 +									<reference key="NSKeyEquiv" ref="1003"/>
    3.99 +									<int key="NSKeyEquivModMask">1048576</int>
   3.100 +									<int key="NSMnemonicLoc">2147483647</int>
   3.101 +									<reference key="NSOnImage" ref="484312224"/>
   3.102 +									<reference key="NSMixedImage" ref="309443010"/>
   3.103 +									<string key="NSAction">submenuAction:</string>
   3.104 +									<object class="NSMenu" key="NSSubmenu" id="752062318">
   3.105 +										<reference key="NSTitle" ref="487627014"/>
   3.106 +										<object class="NSMutableArray" key="NSMenuItems">
   3.107 +											<bool key="EncodedWithXMLCoder">YES</bool>
   3.108 +										</object>
   3.109 +										<string key="NSName">_NSServicesMenu</string>
   3.110 +									</object>
   3.111 +								</object>
   3.112 +								<object class="NSMenuItem" id="646227648">
   3.113 +									<reference key="NSMenu" ref="110575045"/>
   3.114 +									<bool key="NSIsDisabled">YES</bool>
   3.115 +									<bool key="NSIsSeparator">YES</bool>
   3.116 +									<reference key="NSTitle" ref="1003"/>
   3.117 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.118 +									<int key="NSKeyEquivModMask">1048576</int>
   3.119 +									<int key="NSMnemonicLoc">2147483647</int>
   3.120 +									<reference key="NSOnImage" ref="484312224"/>
   3.121 +									<reference key="NSMixedImage" ref="309443010"/>
   3.122 +								</object>
   3.123 +								<object class="NSMenuItem" id="755159360">
   3.124 +									<reference key="NSMenu" ref="110575045"/>
   3.125 +									<string key="NSTitle">Hide GeekGameBoard</string>
   3.126 +									<string key="NSKeyEquiv" id="712247123">h</string>
   3.127 +									<int key="NSKeyEquivModMask">1048576</int>
   3.128 +									<int key="NSMnemonicLoc">2147483647</int>
   3.129 +									<reference key="NSOnImage" ref="484312224"/>
   3.130 +									<reference key="NSMixedImage" ref="309443010"/>
   3.131 +								</object>
   3.132 +								<object class="NSMenuItem" id="342932134">
   3.133 +									<reference key="NSMenu" ref="110575045"/>
   3.134 +									<string key="NSTitle">Hide Others</string>
   3.135 +									<reference key="NSKeyEquiv" ref="712247123"/>
   3.136 +									<int key="NSKeyEquivModMask">1572864</int>
   3.137 +									<int key="NSMnemonicLoc">2147483647</int>
   3.138 +									<reference key="NSOnImage" ref="484312224"/>
   3.139 +									<reference key="NSMixedImage" ref="309443010"/>
   3.140 +								</object>
   3.141 +								<object class="NSMenuItem" id="908899353">
   3.142 +									<reference key="NSMenu" ref="110575045"/>
   3.143 +									<string key="NSTitle">Show All</string>
   3.144 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.145 +									<int key="NSKeyEquivModMask">1048576</int>
   3.146 +									<int key="NSMnemonicLoc">2147483647</int>
   3.147 +									<reference key="NSOnImage" ref="484312224"/>
   3.148 +									<reference key="NSMixedImage" ref="309443010"/>
   3.149 +								</object>
   3.150 +								<object class="NSMenuItem" id="1056857174">
   3.151 +									<reference key="NSMenu" ref="110575045"/>
   3.152 +									<bool key="NSIsDisabled">YES</bool>
   3.153 +									<bool key="NSIsSeparator">YES</bool>
   3.154 +									<reference key="NSTitle" ref="1003"/>
   3.155 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.156 +									<int key="NSKeyEquivModMask">1048576</int>
   3.157 +									<int key="NSMnemonicLoc">2147483647</int>
   3.158 +									<reference key="NSOnImage" ref="484312224"/>
   3.159 +									<reference key="NSMixedImage" ref="309443010"/>
   3.160 +								</object>
   3.161 +								<object class="NSMenuItem" id="632727374">
   3.162 +									<reference key="NSMenu" ref="110575045"/>
   3.163 +									<string key="NSTitle">Quit GeekGameBoard</string>
   3.164 +									<string key="NSKeyEquiv">q</string>
   3.165 +									<int key="NSKeyEquivModMask">1048576</int>
   3.166 +									<int key="NSMnemonicLoc">2147483647</int>
   3.167 +									<reference key="NSOnImage" ref="484312224"/>
   3.168 +									<reference key="NSMixedImage" ref="309443010"/>
   3.169 +								</object>
   3.170 +							</object>
   3.171 +							<string key="NSName">_NSAppleMenu</string>
   3.172 +						</object>
   3.173 +					</object>
   3.174 +					<object class="NSMenuItem" id="379814623">
   3.175 +						<reference key="NSMenu" ref="649796088"/>
   3.176 +						<string key="NSTitle" id="589729360">File</string>
   3.177 +						<reference key="NSKeyEquiv" ref="1003"/>
   3.178 +						<int key="NSKeyEquivModMask">1048576</int>
   3.179 +						<int key="NSMnemonicLoc">2147483647</int>
   3.180 +						<reference key="NSOnImage" ref="484312224"/>
   3.181 +						<reference key="NSMixedImage" ref="309443010"/>
   3.182 +						<string key="NSAction">submenuAction:</string>
   3.183 +						<object class="NSMenu" key="NSSubmenu" id="720053764">
   3.184 +							<reference key="NSTitle" ref="589729360"/>
   3.185 +							<object class="NSMutableArray" key="NSMenuItems">
   3.186 +								<bool key="EncodedWithXMLCoder">YES</bool>
   3.187 +								<object class="NSMenuItem" id="705341025">
   3.188 +									<reference key="NSMenu" ref="720053764"/>
   3.189 +									<string key="NSTitle">New</string>
   3.190 +									<string key="NSKeyEquiv">n</string>
   3.191 +									<int key="NSKeyEquivModMask">1048576</int>
   3.192 +									<int key="NSMnemonicLoc">2147483647</int>
   3.193 +									<reference key="NSOnImage" ref="484312224"/>
   3.194 +									<reference key="NSMixedImage" ref="309443010"/>
   3.195 +								</object>
   3.196 +								<object class="NSMenuItem" id="722745758">
   3.197 +									<reference key="NSMenu" ref="720053764"/>
   3.198 +									<string type="base64-UTF8" key="NSTitle">T3BlbuKApg</string>
   3.199 +									<string key="NSKeyEquiv">o</string>
   3.200 +									<int key="NSKeyEquivModMask">1048576</int>
   3.201 +									<int key="NSMnemonicLoc">2147483647</int>
   3.202 +									<reference key="NSOnImage" ref="484312224"/>
   3.203 +									<reference key="NSMixedImage" ref="309443010"/>
   3.204 +								</object>
   3.205 +								<object class="NSMenuItem" id="1025936716">
   3.206 +									<reference key="NSMenu" ref="720053764"/>
   3.207 +									<string key="NSTitle" id="1022827674">Open Recent</string>
   3.208 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.209 +									<int key="NSKeyEquivModMask">1048576</int>
   3.210 +									<int key="NSMnemonicLoc">2147483647</int>
   3.211 +									<reference key="NSOnImage" ref="484312224"/>
   3.212 +									<reference key="NSMixedImage" ref="309443010"/>
   3.213 +									<string key="NSAction">submenuAction:</string>
   3.214 +									<object class="NSMenu" key="NSSubmenu" id="1065607017">
   3.215 +										<reference key="NSTitle" ref="1022827674"/>
   3.216 +										<object class="NSMutableArray" key="NSMenuItems">
   3.217 +											<bool key="EncodedWithXMLCoder">YES</bool>
   3.218 +											<object class="NSMenuItem" id="759406840">
   3.219 +												<reference key="NSMenu" ref="1065607017"/>
   3.220 +												<string key="NSTitle">Clear Menu</string>
   3.221 +												<reference key="NSKeyEquiv" ref="1003"/>
   3.222 +												<int key="NSKeyEquivModMask">1048576</int>
   3.223 +												<int key="NSMnemonicLoc">2147483647</int>
   3.224 +												<reference key="NSOnImage" ref="484312224"/>
   3.225 +												<reference key="NSMixedImage" ref="309443010"/>
   3.226 +											</object>
   3.227 +										</object>
   3.228 +										<string key="NSName">_NSRecentDocumentsMenu</string>
   3.229 +									</object>
   3.230 +								</object>
   3.231 +								<object class="NSMenuItem" id="425164168">
   3.232 +									<reference key="NSMenu" ref="720053764"/>
   3.233 +									<bool key="NSIsDisabled">YES</bool>
   3.234 +									<bool key="NSIsSeparator">YES</bool>
   3.235 +									<reference key="NSTitle" ref="1003"/>
   3.236 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.237 +									<int key="NSKeyEquivModMask">1048576</int>
   3.238 +									<int key="NSMnemonicLoc">2147483647</int>
   3.239 +									<reference key="NSOnImage" ref="484312224"/>
   3.240 +									<reference key="NSMixedImage" ref="309443010"/>
   3.241 +								</object>
   3.242 +								<object class="NSMenuItem" id="776162233">
   3.243 +									<reference key="NSMenu" ref="720053764"/>
   3.244 +									<string key="NSTitle">Close</string>
   3.245 +									<string key="NSKeyEquiv">w</string>
   3.246 +									<int key="NSKeyEquivModMask">1048576</int>
   3.247 +									<int key="NSMnemonicLoc">2147483647</int>
   3.248 +									<reference key="NSOnImage" ref="484312224"/>
   3.249 +									<reference key="NSMixedImage" ref="309443010"/>
   3.250 +								</object>
   3.251 +								<object class="NSMenuItem" id="1023925487">
   3.252 +									<reference key="NSMenu" ref="720053764"/>
   3.253 +									<string key="NSTitle">Save</string>
   3.254 +									<string key="NSKeyEquiv">s</string>
   3.255 +									<int key="NSKeyEquivModMask">1048576</int>
   3.256 +									<int key="NSMnemonicLoc">2147483647</int>
   3.257 +									<reference key="NSOnImage" ref="484312224"/>
   3.258 +									<reference key="NSMixedImage" ref="309443010"/>
   3.259 +								</object>
   3.260 +								<object class="NSMenuItem" id="117038363">
   3.261 +									<reference key="NSMenu" ref="720053764"/>
   3.262 +									<string type="base64-UTF8" key="NSTitle">U2F2ZSBBc+KApg</string>
   3.263 +									<string key="NSKeyEquiv">S</string>
   3.264 +									<int key="NSKeyEquivModMask">1179648</int>
   3.265 +									<int key="NSMnemonicLoc">2147483647</int>
   3.266 +									<reference key="NSOnImage" ref="484312224"/>
   3.267 +									<reference key="NSMixedImage" ref="309443010"/>
   3.268 +								</object>
   3.269 +								<object class="NSMenuItem" id="579971712">
   3.270 +									<reference key="NSMenu" ref="720053764"/>
   3.271 +									<string key="NSTitle">Revert to Saved</string>
   3.272 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.273 +									<int key="NSMnemonicLoc">2147483647</int>
   3.274 +									<reference key="NSOnImage" ref="484312224"/>
   3.275 +									<reference key="NSMixedImage" ref="309443010"/>
   3.276 +								</object>
   3.277 +								<object class="NSMenuItem" id="1010469920">
   3.278 +									<reference key="NSMenu" ref="720053764"/>
   3.279 +									<bool key="NSIsDisabled">YES</bool>
   3.280 +									<bool key="NSIsSeparator">YES</bool>
   3.281 +									<reference key="NSTitle" ref="1003"/>
   3.282 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.283 +									<int key="NSKeyEquivModMask">1048576</int>
   3.284 +									<int key="NSMnemonicLoc">2147483647</int>
   3.285 +									<reference key="NSOnImage" ref="484312224"/>
   3.286 +									<reference key="NSMixedImage" ref="309443010"/>
   3.287 +								</object>
   3.288 +								<object class="NSMenuItem" id="294629803">
   3.289 +									<reference key="NSMenu" ref="720053764"/>
   3.290 +									<string key="NSTitle">Page Setup...</string>
   3.291 +									<string key="NSKeyEquiv">P</string>
   3.292 +									<int key="NSKeyEquivModMask">1179648</int>
   3.293 +									<int key="NSMnemonicLoc">2147483647</int>
   3.294 +									<reference key="NSOnImage" ref="484312224"/>
   3.295 +									<reference key="NSMixedImage" ref="309443010"/>
   3.296 +									<reference key="NSToolTip" ref="1003"/>
   3.297 +								</object>
   3.298 +								<object class="NSMenuItem" id="49223823">
   3.299 +									<reference key="NSMenu" ref="720053764"/>
   3.300 +									<string type="base64-UTF8" key="NSTitle">UHJpbnTigKY</string>
   3.301 +									<string key="NSKeyEquiv">p</string>
   3.302 +									<int key="NSKeyEquivModMask">1048576</int>
   3.303 +									<int key="NSMnemonicLoc">2147483647</int>
   3.304 +									<reference key="NSOnImage" ref="484312224"/>
   3.305 +									<reference key="NSMixedImage" ref="309443010"/>
   3.306 +								</object>
   3.307 +							</object>
   3.308 +						</object>
   3.309 +					</object>
   3.310 +					<object class="NSMenuItem" id="952259628">
   3.311 +						<reference key="NSMenu" ref="649796088"/>
   3.312 +						<string key="NSTitle" id="459142759">Edit</string>
   3.313 +						<reference key="NSKeyEquiv" ref="1003"/>
   3.314 +						<int key="NSKeyEquivModMask">1048576</int>
   3.315 +						<int key="NSMnemonicLoc">2147483647</int>
   3.316 +						<reference key="NSOnImage" ref="484312224"/>
   3.317 +						<reference key="NSMixedImage" ref="309443010"/>
   3.318 +						<string key="NSAction">submenuAction:</string>
   3.319 +						<object class="NSMenu" key="NSSubmenu" id="789758025">
   3.320 +							<reference key="NSTitle" ref="459142759"/>
   3.321 +							<object class="NSMutableArray" key="NSMenuItems">
   3.322 +								<bool key="EncodedWithXMLCoder">YES</bool>
   3.323 +								<object class="NSMenuItem" id="1058277027">
   3.324 +									<reference key="NSMenu" ref="789758025"/>
   3.325 +									<string key="NSTitle">Undo</string>
   3.326 +									<string key="NSKeyEquiv">z</string>
   3.327 +									<int key="NSKeyEquivModMask">1048576</int>
   3.328 +									<int key="NSMnemonicLoc">2147483647</int>
   3.329 +									<reference key="NSOnImage" ref="484312224"/>
   3.330 +									<reference key="NSMixedImage" ref="309443010"/>
   3.331 +								</object>
   3.332 +								<object class="NSMenuItem" id="790794224">
   3.333 +									<reference key="NSMenu" ref="789758025"/>
   3.334 +									<string key="NSTitle">Redo</string>
   3.335 +									<string key="NSKeyEquiv">Z</string>
   3.336 +									<int key="NSKeyEquivModMask">1179648</int>
   3.337 +									<int key="NSMnemonicLoc">2147483647</int>
   3.338 +									<reference key="NSOnImage" ref="484312224"/>
   3.339 +									<reference key="NSMixedImage" ref="309443010"/>
   3.340 +								</object>
   3.341 +								<object class="NSMenuItem" id="1040322652">
   3.342 +									<reference key="NSMenu" ref="789758025"/>
   3.343 +									<bool key="NSIsDisabled">YES</bool>
   3.344 +									<bool key="NSIsSeparator">YES</bool>
   3.345 +									<reference key="NSTitle" ref="1003"/>
   3.346 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.347 +									<int key="NSKeyEquivModMask">1048576</int>
   3.348 +									<int key="NSMnemonicLoc">2147483647</int>
   3.349 +									<reference key="NSOnImage" ref="484312224"/>
   3.350 +									<reference key="NSMixedImage" ref="309443010"/>
   3.351 +								</object>
   3.352 +								<object class="NSMenuItem" id="296257095">
   3.353 +									<reference key="NSMenu" ref="789758025"/>
   3.354 +									<string key="NSTitle">Cut</string>
   3.355 +									<string key="NSKeyEquiv">x</string>
   3.356 +									<int key="NSKeyEquivModMask">1048576</int>
   3.357 +									<int key="NSMnemonicLoc">2147483647</int>
   3.358 +									<reference key="NSOnImage" ref="484312224"/>
   3.359 +									<reference key="NSMixedImage" ref="309443010"/>
   3.360 +								</object>
   3.361 +								<object class="NSMenuItem" id="860595796">
   3.362 +									<reference key="NSMenu" ref="789758025"/>
   3.363 +									<string key="NSTitle">Copy</string>
   3.364 +									<string key="NSKeyEquiv">c</string>
   3.365 +									<int key="NSKeyEquivModMask">1048576</int>
   3.366 +									<int key="NSMnemonicLoc">2147483647</int>
   3.367 +									<reference key="NSOnImage" ref="484312224"/>
   3.368 +									<reference key="NSMixedImage" ref="309443010"/>
   3.369 +								</object>
   3.370 +								<object class="NSMenuItem" id="29853731">
   3.371 +									<reference key="NSMenu" ref="789758025"/>
   3.372 +									<string key="NSTitle">Paste</string>
   3.373 +									<string key="NSKeyEquiv">v</string>
   3.374 +									<int key="NSKeyEquivModMask">1048576</int>
   3.375 +									<int key="NSMnemonicLoc">2147483647</int>
   3.376 +									<reference key="NSOnImage" ref="484312224"/>
   3.377 +									<reference key="NSMixedImage" ref="309443010"/>
   3.378 +								</object>
   3.379 +								<object class="NSMenuItem" id="437104165">
   3.380 +									<reference key="NSMenu" ref="789758025"/>
   3.381 +									<string key="NSTitle">Delete</string>
   3.382 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.383 +									<int key="NSKeyEquivModMask">1048576</int>
   3.384 +									<int key="NSMnemonicLoc">2147483647</int>
   3.385 +									<reference key="NSOnImage" ref="484312224"/>
   3.386 +									<reference key="NSMixedImage" ref="309443010"/>
   3.387 +								</object>
   3.388 +								<object class="NSMenuItem" id="583158037">
   3.389 +									<reference key="NSMenu" ref="789758025"/>
   3.390 +									<string key="NSTitle">Select All</string>
   3.391 +									<string key="NSKeyEquiv">a</string>
   3.392 +									<int key="NSKeyEquivModMask">1048576</int>
   3.393 +									<int key="NSMnemonicLoc">2147483647</int>
   3.394 +									<reference key="NSOnImage" ref="484312224"/>
   3.395 +									<reference key="NSMixedImage" ref="309443010"/>
   3.396 +								</object>
   3.397 +								<object class="NSMenuItem" id="212016141">
   3.398 +									<reference key="NSMenu" ref="789758025"/>
   3.399 +									<bool key="NSIsDisabled">YES</bool>
   3.400 +									<bool key="NSIsSeparator">YES</bool>
   3.401 +									<reference key="NSTitle" ref="1003"/>
   3.402 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.403 +									<int key="NSKeyEquivModMask">1048576</int>
   3.404 +									<int key="NSMnemonicLoc">2147483647</int>
   3.405 +									<reference key="NSOnImage" ref="484312224"/>
   3.406 +									<reference key="NSMixedImage" ref="309443010"/>
   3.407 +								</object>
   3.408 +								<object class="NSMenuItem" id="676164635">
   3.409 +									<reference key="NSMenu" ref="789758025"/>
   3.410 +									<string key="NSTitle" id="1050731385">Speech</string>
   3.411 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.412 +									<int key="NSKeyEquivModMask">1048576</int>
   3.413 +									<int key="NSMnemonicLoc">2147483647</int>
   3.414 +									<reference key="NSOnImage" ref="484312224"/>
   3.415 +									<reference key="NSMixedImage" ref="309443010"/>
   3.416 +									<string key="NSAction">submenuAction:</string>
   3.417 +									<object class="NSMenu" key="NSSubmenu" id="785027613">
   3.418 +										<reference key="NSTitle" ref="1050731385"/>
   3.419 +										<object class="NSMutableArray" key="NSMenuItems">
   3.420 +											<bool key="EncodedWithXMLCoder">YES</bool>
   3.421 +											<object class="NSMenuItem" id="731782645">
   3.422 +												<reference key="NSMenu" ref="785027613"/>
   3.423 +												<string key="NSTitle">Start Speaking</string>
   3.424 +												<reference key="NSKeyEquiv" ref="1003"/>
   3.425 +												<int key="NSKeyEquivModMask">1048576</int>
   3.426 +												<int key="NSMnemonicLoc">2147483647</int>
   3.427 +												<reference key="NSOnImage" ref="484312224"/>
   3.428 +												<reference key="NSMixedImage" ref="309443010"/>
   3.429 +											</object>
   3.430 +											<object class="NSMenuItem" id="680220178">
   3.431 +												<reference key="NSMenu" ref="785027613"/>
   3.432 +												<string key="NSTitle">Stop Speaking</string>
   3.433 +												<reference key="NSKeyEquiv" ref="1003"/>
   3.434 +												<int key="NSKeyEquivModMask">1048576</int>
   3.435 +												<int key="NSMnemonicLoc">2147483647</int>
   3.436 +												<reference key="NSOnImage" ref="484312224"/>
   3.437 +												<reference key="NSMixedImage" ref="309443010"/>
   3.438 +											</object>
   3.439 +										</object>
   3.440 +									</object>
   3.441 +								</object>
   3.442 +							</object>
   3.443 +						</object>
   3.444 +					</object>
   3.445 +					<object class="NSMenuItem" id="517895433">
   3.446 +						<reference key="NSMenu" ref="649796088"/>
   3.447 +						<string key="NSTitle" id="898761740">Game</string>
   3.448 +						<reference key="NSKeyEquiv" ref="1003"/>
   3.449 +						<int key="NSKeyEquivModMask">1048576</int>
   3.450 +						<int key="NSMnemonicLoc">2147483647</int>
   3.451 +						<reference key="NSOnImage" ref="484312224"/>
   3.452 +						<reference key="NSMixedImage" ref="309443010"/>
   3.453 +						<string key="NSAction">submenuAction:</string>
   3.454 +						<object class="NSMenu" key="NSSubmenu" id="330268596">
   3.455 +							<reference key="NSTitle" ref="898761740"/>
   3.456 +							<object class="NSMutableArray" key="NSMenuItems">
   3.457 +								<bool key="EncodedWithXMLCoder">YES</bool>
   3.458 +								<object class="NSMenuItem" id="394352720">
   3.459 +									<reference key="NSMenu" ref="330268596"/>
   3.460 +									<string key="NSTitle">Klondike (Solitaire)</string>
   3.461 +									<string key="NSKeyEquiv" id="344781584">1</string>
   3.462 +									<int key="NSKeyEquivModMask">1048840</int>
   3.463 +									<int key="NSMnemonicLoc">2147483647</int>
   3.464 +									<reference key="NSOnImage" ref="484312224"/>
   3.465 +									<reference key="NSMixedImage" ref="309443010"/>
   3.466 +								</object>
   3.467 +								<object class="NSMenuItem" id="154289436">
   3.468 +									<reference key="NSMenu" ref="330268596"/>
   3.469 +									<bool key="NSIsDisabled">YES</bool>
   3.470 +									<bool key="NSIsSeparator">YES</bool>
   3.471 +									<reference key="NSTitle" ref="1003"/>
   3.472 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.473 +									<int key="NSKeyEquivModMask">1048576</int>
   3.474 +									<int key="NSMnemonicLoc">2147483647</int>
   3.475 +									<reference key="NSOnImage" ref="484312224"/>
   3.476 +									<reference key="NSMixedImage" ref="309443010"/>
   3.477 +								</object>
   3.478 +								<object class="NSMenuItem" id="630661937">
   3.479 +									<reference key="NSMenu" ref="330268596"/>
   3.480 +									<string key="NSTitle">Checkers</string>
   3.481 +									<string key="NSKeyEquiv" id="5220549">2</string>
   3.482 +									<int key="NSKeyEquivModMask">1048840</int>
   3.483 +									<int key="NSMnemonicLoc">2147483647</int>
   3.484 +									<reference key="NSOnImage" ref="484312224"/>
   3.485 +									<reference key="NSMixedImage" ref="309443010"/>
   3.486 +									<int key="NSTag">1</int>
   3.487 +								</object>
   3.488 +								<object class="NSMenuItem" id="778498721">
   3.489 +									<reference key="NSMenu" ref="330268596"/>
   3.490 +									<string key="NSTitle">Go</string>
   3.491 +									<string key="NSKeyEquiv" id="8808733">3</string>
   3.492 +									<int key="NSKeyEquivModMask">1048840</int>
   3.493 +									<int key="NSMnemonicLoc">2147483647</int>
   3.494 +									<reference key="NSOnImage" ref="484312224"/>
   3.495 +									<reference key="NSMixedImage" ref="309443010"/>
   3.496 +									<int key="NSTag">4</int>
   3.497 +								</object>
   3.498 +								<object class="NSMenuItem" id="538211827">
   3.499 +									<reference key="NSMenu" ref="330268596"/>
   3.500 +									<string key="NSTitle">Hexchequer</string>
   3.501 +									<string key="NSKeyEquiv">4</string>
   3.502 +									<int key="NSKeyEquivModMask">1048840</int>
   3.503 +									<int key="NSMnemonicLoc">2147483647</int>
   3.504 +									<reference key="NSOnImage" ref="484312224"/>
   3.505 +									<reference key="NSMixedImage" ref="309443010"/>
   3.506 +									<int key="NSTag">2</int>
   3.507 +								</object>
   3.508 +								<object class="NSMenuItem" id="739065818">
   3.509 +									<reference key="NSMenu" ref="330268596"/>
   3.510 +									<string key="NSTitle">Tic-Tac-Toe</string>
   3.511 +									<string key="NSKeyEquiv" id="720655175">5</string>
   3.512 +									<int key="NSKeyEquivModMask">1048840</int>
   3.513 +									<int key="NSMnemonicLoc">2147483647</int>
   3.514 +									<reference key="NSOnImage" ref="484312224"/>
   3.515 +									<reference key="NSMixedImage" ref="309443010"/>
   3.516 +									<int key="NSTag">3</int>
   3.517 +								</object>
   3.518 +							</object>
   3.519 +						</object>
   3.520 +					</object>
   3.521 +					<object class="NSMenuItem" id="586577488">
   3.522 +						<reference key="NSMenu" ref="649796088"/>
   3.523 +						<string key="NSTitle" id="180305338">View</string>
   3.524 +						<reference key="NSKeyEquiv" ref="1003"/>
   3.525 +						<int key="NSKeyEquivModMask">1048576</int>
   3.526 +						<int key="NSMnemonicLoc">2147483647</int>
   3.527 +						<reference key="NSOnImage" ref="484312224"/>
   3.528 +						<reference key="NSMixedImage" ref="309443010"/>
   3.529 +						<string key="NSAction">submenuAction:</string>
   3.530 +						<object class="NSMenu" key="NSSubmenu" id="466310130">
   3.531 +							<reference key="NSTitle" ref="180305338"/>
   3.532 +							<object class="NSMutableArray" key="NSMenuItems">
   3.533 +								<bool key="EncodedWithXMLCoder">YES</bool>
   3.534 +								<object class="NSMenuItem" id="713673133">
   3.535 +									<reference key="NSMenu" ref="466310130"/>
   3.536 +									<string key="NSTitle">Full Screen</string>
   3.537 +									<string key="NSKeyEquiv">f</string>
   3.538 +									<int key="NSKeyEquivModMask">1048576</int>
   3.539 +									<int key="NSMnemonicLoc">2147483647</int>
   3.540 +									<reference key="NSOnImage" ref="484312224"/>
   3.541 +									<reference key="NSMixedImage" ref="309443010"/>
   3.542 +								</object>
   3.543 +								<object class="NSMenuItem" id="30531644">
   3.544 +									<reference key="NSMenu" ref="466310130"/>
   3.545 +									<bool key="NSIsDisabled">YES</bool>
   3.546 +									<bool key="NSIsSeparator">YES</bool>
   3.547 +									<reference key="NSTitle" ref="1003"/>
   3.548 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.549 +									<int key="NSKeyEquivModMask">1048576</int>
   3.550 +									<int key="NSMnemonicLoc">2147483647</int>
   3.551 +									<reference key="NSOnImage" ref="484312224"/>
   3.552 +									<reference key="NSMixedImage" ref="309443010"/>
   3.553 +								</object>
   3.554 +								<object class="NSMenuItem" id="102151532">
   3.555 +									<reference key="NSMenu" ref="466310130"/>
   3.556 +									<string key="NSTitle">Show Toolbar</string>
   3.557 +									<string key="NSKeyEquiv">t</string>
   3.558 +									<int key="NSKeyEquivModMask">1572864</int>
   3.559 +									<int key="NSMnemonicLoc">2147483647</int>
   3.560 +									<reference key="NSOnImage" ref="484312224"/>
   3.561 +									<reference key="NSMixedImage" ref="309443010"/>
   3.562 +								</object>
   3.563 +								<object class="NSMenuItem" id="237841660">
   3.564 +									<reference key="NSMenu" ref="466310130"/>
   3.565 +									<string type="base64-UTF8" key="NSTitle">Q3VzdG9taXplIFRvb2xiYXLigKY</string>
   3.566 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.567 +									<int key="NSKeyEquivModMask">1048576</int>
   3.568 +									<int key="NSMnemonicLoc">2147483647</int>
   3.569 +									<reference key="NSOnImage" ref="484312224"/>
   3.570 +									<reference key="NSMixedImage" ref="309443010"/>
   3.571 +								</object>
   3.572 +							</object>
   3.573 +						</object>
   3.574 +					</object>
   3.575 +					<object class="NSMenuItem" id="713487014">
   3.576 +						<reference key="NSMenu" ref="649796088"/>
   3.577 +						<string key="NSTitle" id="15506412">Window</string>
   3.578 +						<reference key="NSKeyEquiv" ref="1003"/>
   3.579 +						<int key="NSKeyEquivModMask">1048576</int>
   3.580 +						<int key="NSMnemonicLoc">2147483647</int>
   3.581 +						<reference key="NSOnImage" ref="484312224"/>
   3.582 +						<reference key="NSMixedImage" ref="309443010"/>
   3.583 +						<string key="NSAction">submenuAction:</string>
   3.584 +						<object class="NSMenu" key="NSSubmenu" id="835318025">
   3.585 +							<reference key="NSTitle" ref="15506412"/>
   3.586 +							<object class="NSMutableArray" key="NSMenuItems">
   3.587 +								<bool key="EncodedWithXMLCoder">YES</bool>
   3.588 +								<object class="NSMenuItem" id="1011231497">
   3.589 +									<reference key="NSMenu" ref="835318025"/>
   3.590 +									<string key="NSTitle">Minimize</string>
   3.591 +									<string key="NSKeyEquiv">m</string>
   3.592 +									<int key="NSKeyEquivModMask">1048576</int>
   3.593 +									<int key="NSMnemonicLoc">2147483647</int>
   3.594 +									<reference key="NSOnImage" ref="484312224"/>
   3.595 +									<reference key="NSMixedImage" ref="309443010"/>
   3.596 +								</object>
   3.597 +								<object class="NSMenuItem" id="575023229">
   3.598 +									<reference key="NSMenu" ref="835318025"/>
   3.599 +									<string key="NSTitle">Zoom</string>
   3.600 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.601 +									<int key="NSKeyEquivModMask">1048576</int>
   3.602 +									<int key="NSMnemonicLoc">2147483647</int>
   3.603 +									<reference key="NSOnImage" ref="484312224"/>
   3.604 +									<reference key="NSMixedImage" ref="309443010"/>
   3.605 +								</object>
   3.606 +								<object class="NSMenuItem" id="299356726">
   3.607 +									<reference key="NSMenu" ref="835318025"/>
   3.608 +									<bool key="NSIsDisabled">YES</bool>
   3.609 +									<bool key="NSIsSeparator">YES</bool>
   3.610 +									<reference key="NSTitle" ref="1003"/>
   3.611 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.612 +									<int key="NSKeyEquivModMask">1048576</int>
   3.613 +									<int key="NSMnemonicLoc">2147483647</int>
   3.614 +									<reference key="NSOnImage" ref="484312224"/>
   3.615 +									<reference key="NSMixedImage" ref="309443010"/>
   3.616 +								</object>
   3.617 +								<object class="NSMenuItem" id="625202149">
   3.618 +									<reference key="NSMenu" ref="835318025"/>
   3.619 +									<string key="NSTitle">Bring All to Front</string>
   3.620 +									<reference key="NSKeyEquiv" ref="1003"/>
   3.621 +									<int key="NSKeyEquivModMask">1048576</int>
   3.622 +									<int key="NSMnemonicLoc">2147483647</int>
   3.623 +									<reference key="NSOnImage" ref="484312224"/>
   3.624 +									<reference key="NSMixedImage" ref="309443010"/>
   3.625 +								</object>
   3.626 +							</object>
   3.627 +							<string key="NSName">_NSWindowsMenu</string>
   3.628 +						</object>
   3.629 +					</object>
   3.630 +					<object class="NSMenuItem" id="391199113">
   3.631 +						<reference key="NSMenu" ref="649796088"/>
   3.632 +						<string key="NSTitle" id="519223894">Help</string>
   3.633 +						<reference key="NSKeyEquiv" ref="1003"/>
   3.634 +						<int key="NSKeyEquivModMask">1048576</int>
   3.635 +						<int key="NSMnemonicLoc">2147483647</int>
   3.636 +						<reference key="NSOnImage" ref="484312224"/>
   3.637 +						<reference key="NSMixedImage" ref="309443010"/>
   3.638 +						<string key="NSAction">submenuAction:</string>
   3.639 +						<object class="NSMenu" key="NSSubmenu" id="374024848">
   3.640 +							<reference key="NSTitle" ref="519223894"/>
   3.641 +							<object class="NSMutableArray" key="NSMenuItems">
   3.642 +								<bool key="EncodedWithXMLCoder">YES</bool>
   3.643 +							</object>
   3.644 +						</object>
   3.645 +					</object>
   3.646 +				</object>
   3.647 +				<string key="NSName">_NSMainMenu</string>
   3.648 +			</object>
   3.649 +			<object class="NSWindowTemplate" id="972006081">
   3.650 +				<int key="NSWindowStyleMask">7</int>
   3.651 +				<int key="NSWindowBacking">2</int>
   3.652 +				<string key="NSWindowRect">{{57, 175}, {1084, 587}}</string>
   3.653 +				<int key="NSWTFlags">1946157056</int>
   3.654 +				<reference key="NSWindowTitle" ref="101265034"/>
   3.655 +				<string key="NSWindowClass">NSWindow</string>
   3.656 +				<nil key="NSViewClass"/>
   3.657 +				<object class="NSView" key="NSWindowView" id="439893737">
   3.658 +					<reference key="NSNextResponder"/>
   3.659 +					<int key="NSvFlags">256</int>
   3.660 +					<object class="NSMutableArray" key="NSSubviews">
   3.661 +						<bool key="EncodedWithXMLCoder">YES</bool>
   3.662 +						<object class="NSCustomView" id="1060834180">
   3.663 +							<reference key="NSNextResponder" ref="439893737"/>
   3.664 +							<int key="NSvFlags">274</int>
   3.665 +							<string key="NSFrameSize">{1084, 587}</string>
   3.666 +							<reference key="NSSuperview" ref="439893737"/>
   3.667 +							<reference key="NSWindow"/>
   3.668 +							<bool key="NSViewIsLayerTreeHost">YES</bool>
   3.669 +							<string key="NSClassName">DemoBoardView</string>
   3.670 +						</object>
   3.671 +					</object>
   3.672 +					<string key="NSFrameSize">{1084, 587}</string>
   3.673 +					<reference key="NSSuperview"/>
   3.674 +					<reference key="NSWindow"/>
   3.675 +				</object>
   3.676 +				<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
   3.677 +				<reference key="NSFrameAutosaveName" ref="1003"/>
   3.678 +			</object>
   3.679 +		</object>
   3.680 +		<object class="IBObjectContainer" key="IBDocument.Objects">
   3.681 +			<object class="NSMutableArray" key="connectionRecords">
   3.682 +				<bool key="EncodedWithXMLCoder">YES</bool>
   3.683 +				<object class="IBConnectionRecord">
   3.684 +					<object class="IBActionConnection" key="connection">
   3.685 +						<string key="label">performMiniaturize:</string>
   3.686 +						<reference key="source" ref="1014"/>
   3.687 +						<reference key="destination" ref="1011231497"/>
   3.688 +					</object>
   3.689 +					<int key="connectionID">37</int>
   3.690 +				</object>
   3.691 +				<object class="IBConnectionRecord">
   3.692 +					<object class="IBActionConnection" key="connection">
   3.693 +						<string key="label">arrangeInFront:</string>
   3.694 +						<reference key="source" ref="1014"/>
   3.695 +						<reference key="destination" ref="625202149"/>
   3.696 +					</object>
   3.697 +					<int key="connectionID">39</int>
   3.698 +				</object>
   3.699 +				<object class="IBConnectionRecord">
   3.700 +					<object class="IBActionConnection" key="connection">
   3.701 +						<string key="label">print:</string>
   3.702 +						<reference key="source" ref="1014"/>
   3.703 +						<reference key="destination" ref="49223823"/>
   3.704 +					</object>
   3.705 +					<int key="connectionID">86</int>
   3.706 +				</object>
   3.707 +				<object class="IBConnectionRecord">
   3.708 +					<object class="IBActionConnection" key="connection">
   3.709 +						<string key="label">runPageLayout:</string>
   3.710 +						<reference key="source" ref="1014"/>
   3.711 +						<reference key="destination" ref="294629803"/>
   3.712 +					</object>
   3.713 +					<int key="connectionID">87</int>
   3.714 +				</object>
   3.715 +				<object class="IBConnectionRecord">
   3.716 +					<object class="IBActionConnection" key="connection">
   3.717 +						<string key="label">clearRecentDocuments:</string>
   3.718 +						<reference key="source" ref="1014"/>
   3.719 +						<reference key="destination" ref="759406840"/>
   3.720 +					</object>
   3.721 +					<int key="connectionID">127</int>
   3.722 +				</object>
   3.723 +				<object class="IBConnectionRecord">
   3.724 +					<object class="IBActionConnection" key="connection">
   3.725 +						<string key="label">orderFrontStandardAboutPanel:</string>
   3.726 +						<reference key="source" ref="1021"/>
   3.727 +						<reference key="destination" ref="238522557"/>
   3.728 +					</object>
   3.729 +					<int key="connectionID">142</int>
   3.730 +				</object>
   3.731 +				<object class="IBConnectionRecord">
   3.732 +					<object class="IBActionConnection" key="connection">
   3.733 +						<string key="label">performClose:</string>
   3.734 +						<reference key="source" ref="1014"/>
   3.735 +						<reference key="destination" ref="776162233"/>
   3.736 +					</object>
   3.737 +					<int key="connectionID">193</int>
   3.738 +				</object>
   3.739 +				<object class="IBConnectionRecord">
   3.740 +					<object class="IBActionConnection" key="connection">
   3.741 +						<string key="label">undo:</string>
   3.742 +						<reference key="source" ref="1014"/>
   3.743 +						<reference key="destination" ref="1058277027"/>
   3.744 +					</object>
   3.745 +					<int key="connectionID">223</int>
   3.746 +				</object>
   3.747 +				<object class="IBConnectionRecord">
   3.748 +					<object class="IBActionConnection" key="connection">
   3.749 +						<string key="label">copy:</string>
   3.750 +						<reference key="source" ref="1014"/>
   3.751 +						<reference key="destination" ref="860595796"/>
   3.752 +					</object>
   3.753 +					<int key="connectionID">224</int>
   3.754 +				</object>
   3.755 +				<object class="IBConnectionRecord">
   3.756 +					<object class="IBActionConnection" key="connection">
   3.757 +						<string key="label">paste:</string>
   3.758 +						<reference key="source" ref="1014"/>
   3.759 +						<reference key="destination" ref="29853731"/>
   3.760 +					</object>
   3.761 +					<int key="connectionID">226</int>
   3.762 +				</object>
   3.763 +				<object class="IBConnectionRecord">
   3.764 +					<object class="IBActionConnection" key="connection">
   3.765 +						<string key="label">stopSpeaking:</string>
   3.766 +						<reference key="source" ref="1014"/>
   3.767 +						<reference key="destination" ref="680220178"/>
   3.768 +					</object>
   3.769 +					<int key="connectionID">227</int>
   3.770 +				</object>
   3.771 +				<object class="IBConnectionRecord">
   3.772 +					<object class="IBActionConnection" key="connection">
   3.773 +						<string key="label">cut:</string>
   3.774 +						<reference key="source" ref="1014"/>
   3.775 +						<reference key="destination" ref="296257095"/>
   3.776 +					</object>
   3.777 +					<int key="connectionID">228</int>
   3.778 +				</object>
   3.779 +				<object class="IBConnectionRecord">
   3.780 +					<object class="IBActionConnection" key="connection">
   3.781 +						<string key="label">redo:</string>
   3.782 +						<reference key="source" ref="1014"/>
   3.783 +						<reference key="destination" ref="790794224"/>
   3.784 +					</object>
   3.785 +					<int key="connectionID">231</int>
   3.786 +				</object>
   3.787 +				<object class="IBConnectionRecord">
   3.788 +					<object class="IBActionConnection" key="connection">
   3.789 +						<string key="label">selectAll:</string>
   3.790 +						<reference key="source" ref="1014"/>
   3.791 +						<reference key="destination" ref="583158037"/>
   3.792 +					</object>
   3.793 +					<int key="connectionID">232</int>
   3.794 +				</object>
   3.795 +				<object class="IBConnectionRecord">
   3.796 +					<object class="IBActionConnection" key="connection">
   3.797 +						<string key="label">startSpeaking:</string>
   3.798 +						<reference key="source" ref="1014"/>
   3.799 +						<reference key="destination" ref="731782645"/>
   3.800 +					</object>
   3.801 +					<int key="connectionID">233</int>
   3.802 +				</object>
   3.803 +				<object class="IBConnectionRecord">
   3.804 +					<object class="IBActionConnection" key="connection">
   3.805 +						<string key="label">delete:</string>
   3.806 +						<reference key="source" ref="1014"/>
   3.807 +						<reference key="destination" ref="437104165"/>
   3.808 +					</object>
   3.809 +					<int key="connectionID">235</int>
   3.810 +				</object>
   3.811 +				<object class="IBConnectionRecord">
   3.812 +					<object class="IBActionConnection" key="connection">
   3.813 +						<string key="label">performZoom:</string>
   3.814 +						<reference key="source" ref="1014"/>
   3.815 +						<reference key="destination" ref="575023229"/>
   3.816 +					</object>
   3.817 +					<int key="connectionID">240</int>
   3.818 +				</object>
   3.819 +				<object class="IBConnectionRecord">
   3.820 +					<object class="IBActionConnection" key="connection">
   3.821 +						<string key="label">saveDocument:</string>
   3.822 +						<reference key="source" ref="1014"/>
   3.823 +						<reference key="destination" ref="1023925487"/>
   3.824 +					</object>
   3.825 +					<int key="connectionID">362</int>
   3.826 +				</object>
   3.827 +				<object class="IBConnectionRecord">
   3.828 +					<object class="IBActionConnection" key="connection">
   3.829 +						<string key="label">saveDocumentAs:</string>
   3.830 +						<reference key="source" ref="1014"/>
   3.831 +						<reference key="destination" ref="117038363"/>
   3.832 +					</object>
   3.833 +					<int key="connectionID">363</int>
   3.834 +				</object>
   3.835 +				<object class="IBConnectionRecord">
   3.836 +					<object class="IBActionConnection" key="connection">
   3.837 +						<string key="label">revertDocumentToSaved:</string>
   3.838 +						<reference key="source" ref="1014"/>
   3.839 +						<reference key="destination" ref="579971712"/>
   3.840 +					</object>
   3.841 +					<int key="connectionID">364</int>
   3.842 +				</object>
   3.843 +				<object class="IBConnectionRecord">
   3.844 +					<object class="IBActionConnection" key="connection">
   3.845 +						<string key="label">runToolbarCustomizationPalette:</string>
   3.846 +						<reference key="source" ref="1014"/>
   3.847 +						<reference key="destination" ref="237841660"/>
   3.848 +					</object>
   3.849 +					<int key="connectionID">365</int>
   3.850 +				</object>
   3.851 +				<object class="IBConnectionRecord">
   3.852 +					<object class="IBActionConnection" key="connection">
   3.853 +						<string key="label">toggleToolbarShown:</string>
   3.854 +						<reference key="source" ref="1014"/>
   3.855 +						<reference key="destination" ref="102151532"/>
   3.856 +					</object>
   3.857 +					<int key="connectionID">366</int>
   3.858 +				</object>
   3.859 +				<object class="IBConnectionRecord">
   3.860 +					<object class="IBActionConnection" key="connection">
   3.861 +						<string key="label">hide:</string>
   3.862 +						<reference key="source" ref="1014"/>
   3.863 +						<reference key="destination" ref="755159360"/>
   3.864 +					</object>
   3.865 +					<int key="connectionID">367</int>
   3.866 +				</object>
   3.867 +				<object class="IBConnectionRecord">
   3.868 +					<object class="IBActionConnection" key="connection">
   3.869 +						<string key="label">hideOtherApplications:</string>
   3.870 +						<reference key="source" ref="1014"/>
   3.871 +						<reference key="destination" ref="342932134"/>
   3.872 +					</object>
   3.873 +					<int key="connectionID">368</int>
   3.874 +				</object>
   3.875 +				<object class="IBConnectionRecord">
   3.876 +					<object class="IBActionConnection" key="connection">
   3.877 +						<string key="label">terminate:</string>
   3.878 +						<reference key="source" ref="1014"/>
   3.879 +						<reference key="destination" ref="632727374"/>
   3.880 +					</object>
   3.881 +					<int key="connectionID">369</int>
   3.882 +				</object>
   3.883 +				<object class="IBConnectionRecord">
   3.884 +					<object class="IBActionConnection" key="connection">
   3.885 +						<string key="label">unhideAllApplications:</string>
   3.886 +						<reference key="source" ref="1014"/>
   3.887 +						<reference key="destination" ref="908899353"/>
   3.888 +					</object>
   3.889 +					<int key="connectionID">370</int>
   3.890 +				</object>
   3.891 +				<object class="IBConnectionRecord">
   3.892 +					<object class="IBActionConnection" key="connection">
   3.893 +						<string key="label">newDocument:</string>
   3.894 +						<reference key="source" ref="1014"/>
   3.895 +						<reference key="destination" ref="705341025"/>
   3.896 +					</object>
   3.897 +					<int key="connectionID">373</int>
   3.898 +				</object>
   3.899 +				<object class="IBConnectionRecord">
   3.900 +					<object class="IBActionConnection" key="connection">
   3.901 +						<string key="label">openDocument:</string>
   3.902 +						<reference key="source" ref="1014"/>
   3.903 +						<reference key="destination" ref="722745758"/>
   3.904 +					</object>
   3.905 +					<int key="connectionID">374</int>
   3.906 +				</object>
   3.907 +				<object class="IBConnectionRecord">
   3.908 +					<object class="IBActionConnection" key="connection">
   3.909 +						<string key="label">enterFullScreen:</string>
   3.910 +						<reference key="source" ref="1060834180"/>
   3.911 +						<reference key="destination" ref="713673133"/>
   3.912 +					</object>
   3.913 +					<int key="connectionID">378</int>
   3.914 +				</object>
   3.915 +				<object class="IBConnectionRecord">
   3.916 +					<object class="IBActionConnection" key="connection">
   3.917 +						<string key="label" id="560321708">startGameFromMenu:</string>
   3.918 +						<reference key="source" ref="1060834180"/>
   3.919 +						<reference key="destination" ref="394352720"/>
   3.920 +					</object>
   3.921 +					<int key="connectionID">388</int>
   3.922 +				</object>
   3.923 +				<object class="IBConnectionRecord">
   3.924 +					<object class="IBActionConnection" key="connection">
   3.925 +						<reference key="label" ref="560321708"/>
   3.926 +						<reference key="source" ref="1060834180"/>
   3.927 +						<reference key="destination" ref="630661937"/>
   3.928 +					</object>
   3.929 +					<int key="connectionID">389</int>
   3.930 +				</object>
   3.931 +				<object class="IBConnectionRecord">
   3.932 +					<object class="IBActionConnection" key="connection">
   3.933 +						<reference key="label" ref="560321708"/>
   3.934 +						<reference key="source" ref="1060834180"/>
   3.935 +						<reference key="destination" ref="538211827"/>
   3.936 +					</object>
   3.937 +					<int key="connectionID">390</int>
   3.938 +				</object>
   3.939 +				<object class="IBConnectionRecord">
   3.940 +					<object class="IBActionConnection" key="connection">
   3.941 +						<reference key="label" ref="560321708"/>
   3.942 +						<reference key="source" ref="1060834180"/>
   3.943 +						<reference key="destination" ref="739065818"/>
   3.944 +					</object>
   3.945 +					<int key="connectionID">391</int>
   3.946 +				</object>
   3.947 +				<object class="IBConnectionRecord">
   3.948 +					<object class="IBActionConnection" key="connection">
   3.949 +						<reference key="label" ref="560321708"/>
   3.950 +						<reference key="source" ref="1060834180"/>
   3.951 +						<reference key="destination" ref="778498721"/>
   3.952 +					</object>
   3.953 +					<int key="connectionID">394</int>
   3.954 +				</object>
   3.955 +				<object class="IBConnectionRecord">
   3.956 +					<object class="IBOutletConnection" key="connection">
   3.957 +						<string key="label">initialFirstResponder</string>
   3.958 +						<reference key="source" ref="972006081"/>
   3.959 +						<reference key="destination" ref="1060834180"/>
   3.960 +					</object>
   3.961 +					<int key="connectionID">399</int>
   3.962 +				</object>
   3.963 +				<object class="IBConnectionRecord">
   3.964 +					<object class="IBOutletConnection" key="connection">
   3.965 +						<string key="label">delegate</string>
   3.966 +						<reference key="source" ref="1021"/>
   3.967 +						<reference key="destination" ref="1060834180"/>
   3.968 +					</object>
   3.969 +					<int key="connectionID">400</int>
   3.970 +				</object>
   3.971 +			</object>
   3.972 +			<object class="IBMutableOrderedSet" key="objectRecords">
   3.973 +				<object class="NSArray" key="orderedObjects">
   3.974 +					<bool key="EncodedWithXMLCoder">YES</bool>
   3.975 +					<object class="IBObjectRecord">
   3.976 +						<int key="objectID">0</int>
   3.977 +						<object class="NSArray" key="object" id="1049">
   3.978 +							<bool key="EncodedWithXMLCoder">YES</bool>
   3.979 +						</object>
   3.980 +						<reference key="children" ref="1048"/>
   3.981 +						<nil key="parent"/>
   3.982 +					</object>
   3.983 +					<object class="IBObjectRecord">
   3.984 +						<int key="objectID">-2</int>
   3.985 +						<reference key="object" ref="1021"/>
   3.986 +						<reference key="parent" ref="1049"/>
   3.987 +						<string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
   3.988 +					</object>
   3.989 +					<object class="IBObjectRecord">
   3.990 +						<int key="objectID">-1</int>
   3.991 +						<reference key="object" ref="1014"/>
   3.992 +						<reference key="parent" ref="1049"/>
   3.993 +						<string key="objectName">First Responder</string>
   3.994 +					</object>
   3.995 +					<object class="IBObjectRecord">
   3.996 +						<int key="objectID">-3</int>
   3.997 +						<reference key="object" ref="1050"/>
   3.998 +						<reference key="parent" ref="1049"/>
   3.999 +						<string key="objectName">Application</string>
  3.1000 +					</object>
  3.1001 +					<object class="IBObjectRecord">
  3.1002 +						<int key="objectID">29</int>
  3.1003 +						<reference key="object" ref="649796088"/>
  3.1004 +						<object class="NSMutableArray" key="children">
  3.1005 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1006 +							<reference ref="713487014"/>
  3.1007 +							<reference ref="694149608"/>
  3.1008 +							<reference ref="391199113"/>
  3.1009 +							<reference ref="952259628"/>
  3.1010 +							<reference ref="379814623"/>
  3.1011 +							<reference ref="586577488"/>
  3.1012 +							<reference ref="517895433"/>
  3.1013 +						</object>
  3.1014 +						<reference key="parent" ref="1049"/>
  3.1015 +						<string key="objectName">MainMenu</string>
  3.1016 +					</object>
  3.1017 +					<object class="IBObjectRecord">
  3.1018 +						<int key="objectID">19</int>
  3.1019 +						<reference key="object" ref="713487014"/>
  3.1020 +						<object class="NSMutableArray" key="children">
  3.1021 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1022 +							<reference ref="835318025"/>
  3.1023 +						</object>
  3.1024 +						<reference key="parent" ref="649796088"/>
  3.1025 +					</object>
  3.1026 +					<object class="IBObjectRecord">
  3.1027 +						<int key="objectID">56</int>
  3.1028 +						<reference key="object" ref="694149608"/>
  3.1029 +						<object class="NSMutableArray" key="children">
  3.1030 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1031 +							<reference ref="110575045"/>
  3.1032 +						</object>
  3.1033 +						<reference key="parent" ref="649796088"/>
  3.1034 +					</object>
  3.1035 +					<object class="IBObjectRecord">
  3.1036 +						<int key="objectID">103</int>
  3.1037 +						<reference key="object" ref="391199113"/>
  3.1038 +						<object class="NSMutableArray" key="children">
  3.1039 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1040 +							<reference ref="374024848"/>
  3.1041 +						</object>
  3.1042 +						<reference key="parent" ref="649796088"/>
  3.1043 +						<reference key="objectName" ref="344781584"/>
  3.1044 +					</object>
  3.1045 +					<object class="IBObjectRecord">
  3.1046 +						<int key="objectID">217</int>
  3.1047 +						<reference key="object" ref="952259628"/>
  3.1048 +						<object class="NSMutableArray" key="children">
  3.1049 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1050 +							<reference ref="789758025"/>
  3.1051 +						</object>
  3.1052 +						<reference key="parent" ref="649796088"/>
  3.1053 +					</object>
  3.1054 +					<object class="IBObjectRecord">
  3.1055 +						<int key="objectID">83</int>
  3.1056 +						<reference key="object" ref="379814623"/>
  3.1057 +						<object class="NSMutableArray" key="children">
  3.1058 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1059 +							<reference ref="720053764"/>
  3.1060 +						</object>
  3.1061 +						<reference key="parent" ref="649796088"/>
  3.1062 +					</object>
  3.1063 +					<object class="IBObjectRecord">
  3.1064 +						<int key="objectID">81</int>
  3.1065 +						<reference key="object" ref="720053764"/>
  3.1066 +						<object class="NSMutableArray" key="children">
  3.1067 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1068 +							<reference ref="1023925487"/>
  3.1069 +							<reference ref="117038363"/>
  3.1070 +							<reference ref="49223823"/>
  3.1071 +							<reference ref="722745758"/>
  3.1072 +							<reference ref="705341025"/>
  3.1073 +							<reference ref="1025936716"/>
  3.1074 +							<reference ref="294629803"/>
  3.1075 +							<reference ref="776162233"/>
  3.1076 +							<reference ref="425164168"/>
  3.1077 +							<reference ref="579971712"/>
  3.1078 +							<reference ref="1010469920"/>
  3.1079 +						</object>
  3.1080 +						<reference key="parent" ref="379814623"/>
  3.1081 +					</object>
  3.1082 +					<object class="IBObjectRecord">
  3.1083 +						<int key="objectID">75</int>
  3.1084 +						<reference key="object" ref="1023925487"/>
  3.1085 +						<reference key="parent" ref="720053764"/>
  3.1086 +						<reference key="objectName" ref="8808733"/>
  3.1087 +					</object>
  3.1088 +					<object class="IBObjectRecord">
  3.1089 +						<int key="objectID">80</int>
  3.1090 +						<reference key="object" ref="117038363"/>
  3.1091 +						<reference key="parent" ref="720053764"/>
  3.1092 +						<string key="objectName">8</string>
  3.1093 +					</object>
  3.1094 +					<object class="IBObjectRecord">
  3.1095 +						<int key="objectID">78</int>
  3.1096 +						<reference key="object" ref="49223823"/>
  3.1097 +						<reference key="parent" ref="720053764"/>
  3.1098 +						<string key="objectName">6</string>
  3.1099 +					</object>
  3.1100 +					<object class="IBObjectRecord">
  3.1101 +						<int key="objectID">72</int>
  3.1102 +						<reference key="object" ref="722745758"/>
  3.1103 +						<reference key="parent" ref="720053764"/>
  3.1104 +					</object>
  3.1105 +					<object class="IBObjectRecord">
  3.1106 +						<int key="objectID">82</int>
  3.1107 +						<reference key="object" ref="705341025"/>
  3.1108 +						<reference key="parent" ref="720053764"/>
  3.1109 +						<string key="objectName">9</string>
  3.1110 +					</object>
  3.1111 +					<object class="IBObjectRecord">
  3.1112 +						<int key="objectID">124</int>
  3.1113 +						<reference key="object" ref="1025936716"/>
  3.1114 +						<object class="NSMutableArray" key="children">
  3.1115 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1116 +							<reference ref="1065607017"/>
  3.1117 +						</object>
  3.1118 +						<reference key="parent" ref="720053764"/>
  3.1119 +					</object>
  3.1120 +					<object class="IBObjectRecord">
  3.1121 +						<int key="objectID">77</int>
  3.1122 +						<reference key="object" ref="294629803"/>
  3.1123 +						<reference key="parent" ref="720053764"/>
  3.1124 +						<reference key="objectName" ref="720655175"/>
  3.1125 +					</object>
  3.1126 +					<object class="IBObjectRecord">
  3.1127 +						<int key="objectID">73</int>
  3.1128 +						<reference key="object" ref="776162233"/>
  3.1129 +						<reference key="parent" ref="720053764"/>
  3.1130 +						<reference key="objectName" ref="344781584"/>
  3.1131 +					</object>
  3.1132 +					<object class="IBObjectRecord">
  3.1133 +						<int key="objectID">79</int>
  3.1134 +						<reference key="object" ref="425164168"/>
  3.1135 +						<reference key="parent" ref="720053764"/>
  3.1136 +						<string key="objectName">7</string>
  3.1137 +					</object>
  3.1138 +					<object class="IBObjectRecord">
  3.1139 +						<int key="objectID">112</int>
  3.1140 +						<reference key="object" ref="579971712"/>
  3.1141 +						<reference key="parent" ref="720053764"/>
  3.1142 +						<string key="objectName">10</string>
  3.1143 +					</object>
  3.1144 +					<object class="IBObjectRecord">
  3.1145 +						<int key="objectID">74</int>
  3.1146 +						<reference key="object" ref="1010469920"/>
  3.1147 +						<reference key="parent" ref="720053764"/>
  3.1148 +						<reference key="objectName" ref="5220549"/>
  3.1149 +					</object>
  3.1150 +					<object class="IBObjectRecord">
  3.1151 +						<int key="objectID">125</int>
  3.1152 +						<reference key="object" ref="1065607017"/>
  3.1153 +						<object class="NSMutableArray" key="children">
  3.1154 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1155 +							<reference ref="759406840"/>
  3.1156 +						</object>
  3.1157 +						<reference key="parent" ref="1025936716"/>
  3.1158 +					</object>
  3.1159 +					<object class="IBObjectRecord">
  3.1160 +						<int key="objectID">126</int>
  3.1161 +						<reference key="object" ref="759406840"/>
  3.1162 +						<reference key="parent" ref="1065607017"/>
  3.1163 +					</object>
  3.1164 +					<object class="IBObjectRecord">
  3.1165 +						<int key="objectID">205</int>
  3.1166 +						<reference key="object" ref="789758025"/>
  3.1167 +						<object class="NSMutableArray" key="children">
  3.1168 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1169 +							<reference ref="437104165"/>
  3.1170 +							<reference ref="583158037"/>
  3.1171 +							<reference ref="1058277027"/>
  3.1172 +							<reference ref="212016141"/>
  3.1173 +							<reference ref="296257095"/>
  3.1174 +							<reference ref="29853731"/>
  3.1175 +							<reference ref="860595796"/>
  3.1176 +							<reference ref="1040322652"/>
  3.1177 +							<reference ref="790794224"/>
  3.1178 +							<reference ref="676164635"/>
  3.1179 +						</object>
  3.1180 +						<reference key="parent" ref="952259628"/>
  3.1181 +					</object>
  3.1182 +					<object class="IBObjectRecord">
  3.1183 +						<int key="objectID">202</int>
  3.1184 +						<reference key="object" ref="437104165"/>
  3.1185 +						<reference key="parent" ref="789758025"/>
  3.1186 +					</object>
  3.1187 +					<object class="IBObjectRecord">
  3.1188 +						<int key="objectID">198</int>
  3.1189 +						<reference key="object" ref="583158037"/>
  3.1190 +						<reference key="parent" ref="789758025"/>
  3.1191 +					</object>
  3.1192 +					<object class="IBObjectRecord">
  3.1193 +						<int key="objectID">207</int>
  3.1194 +						<reference key="object" ref="1058277027"/>
  3.1195 +						<reference key="parent" ref="789758025"/>
  3.1196 +					</object>
  3.1197 +					<object class="IBObjectRecord">
  3.1198 +						<int key="objectID">214</int>
  3.1199 +						<reference key="object" ref="212016141"/>
  3.1200 +						<reference key="parent" ref="789758025"/>
  3.1201 +					</object>
  3.1202 +					<object class="IBObjectRecord">
  3.1203 +						<int key="objectID">199</int>
  3.1204 +						<reference key="object" ref="296257095"/>
  3.1205 +						<reference key="parent" ref="789758025"/>
  3.1206 +					</object>
  3.1207 +					<object class="IBObjectRecord">
  3.1208 +						<int key="objectID">203</int>
  3.1209 +						<reference key="object" ref="29853731"/>
  3.1210 +						<reference key="parent" ref="789758025"/>
  3.1211 +					</object>
  3.1212 +					<object class="IBObjectRecord">
  3.1213 +						<int key="objectID">197</int>
  3.1214 +						<reference key="object" ref="860595796"/>
  3.1215 +						<reference key="parent" ref="789758025"/>
  3.1216 +					</object>
  3.1217 +					<object class="IBObjectRecord">
  3.1218 +						<int key="objectID">206</int>
  3.1219 +						<reference key="object" ref="1040322652"/>
  3.1220 +						<reference key="parent" ref="789758025"/>
  3.1221 +					</object>
  3.1222 +					<object class="IBObjectRecord">
  3.1223 +						<int key="objectID">215</int>
  3.1224 +						<reference key="object" ref="790794224"/>
  3.1225 +						<reference key="parent" ref="789758025"/>
  3.1226 +					</object>
  3.1227 +					<object class="IBObjectRecord">
  3.1228 +						<int key="objectID">106</int>
  3.1229 +						<reference key="object" ref="374024848"/>
  3.1230 +						<object class="NSMutableArray" key="children">
  3.1231 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1232 +						</object>
  3.1233 +						<reference key="parent" ref="391199113"/>
  3.1234 +						<reference key="objectName" ref="5220549"/>
  3.1235 +					</object>
  3.1236 +					<object class="IBObjectRecord">
  3.1237 +						<int key="objectID">57</int>
  3.1238 +						<reference key="object" ref="110575045"/>
  3.1239 +						<object class="NSMutableArray" key="children">
  3.1240 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1241 +							<reference ref="238522557"/>
  3.1242 +							<reference ref="755159360"/>
  3.1243 +							<reference ref="908899353"/>
  3.1244 +							<reference ref="632727374"/>
  3.1245 +							<reference ref="646227648"/>
  3.1246 +							<reference ref="609285721"/>
  3.1247 +							<reference ref="481834944"/>
  3.1248 +							<reference ref="304266470"/>
  3.1249 +							<reference ref="1046388886"/>
  3.1250 +							<reference ref="1056857174"/>
  3.1251 +							<reference ref="342932134"/>
  3.1252 +						</object>
  3.1253 +						<reference key="parent" ref="694149608"/>
  3.1254 +					</object>
  3.1255 +					<object class="IBObjectRecord">
  3.1256 +						<int key="objectID">58</int>
  3.1257 +						<reference key="object" ref="238522557"/>
  3.1258 +						<reference key="parent" ref="110575045"/>
  3.1259 +					</object>
  3.1260 +					<object class="IBObjectRecord">
  3.1261 +						<int key="objectID">134</int>
  3.1262 +						<reference key="object" ref="755159360"/>
  3.1263 +						<reference key="parent" ref="110575045"/>
  3.1264 +					</object>
  3.1265 +					<object class="IBObjectRecord">
  3.1266 +						<int key="objectID">150</int>
  3.1267 +						<reference key="object" ref="908899353"/>
  3.1268 +						<reference key="parent" ref="110575045"/>
  3.1269 +					</object>
  3.1270 +					<object class="IBObjectRecord">
  3.1271 +						<int key="objectID">136</int>
  3.1272 +						<reference key="object" ref="632727374"/>
  3.1273 +						<reference key="parent" ref="110575045"/>
  3.1274 +						<string key="objectName">1111</string>
  3.1275 +					</object>
  3.1276 +					<object class="IBObjectRecord">
  3.1277 +						<int key="objectID">144</int>
  3.1278 +						<reference key="object" ref="646227648"/>
  3.1279 +						<reference key="parent" ref="110575045"/>
  3.1280 +					</object>
  3.1281 +					<object class="IBObjectRecord">
  3.1282 +						<int key="objectID">129</int>
  3.1283 +						<reference key="object" ref="609285721"/>
  3.1284 +						<reference key="parent" ref="110575045"/>
  3.1285 +						<string key="objectName">121</string>
  3.1286 +					</object>
  3.1287 +					<object class="IBObjectRecord">
  3.1288 +						<int key="objectID">143</int>
  3.1289 +						<reference key="object" ref="481834944"/>
  3.1290 +						<reference key="parent" ref="110575045"/>
  3.1291 +					</object>
  3.1292 +					<object class="IBObjectRecord">
  3.1293 +						<int key="objectID">236</int>
  3.1294 +						<reference key="object" ref="304266470"/>
  3.1295 +						<reference key="parent" ref="110575045"/>
  3.1296 +					</object>
  3.1297 +					<object class="IBObjectRecord">
  3.1298 +						<int key="objectID">131</int>
  3.1299 +						<reference key="object" ref="1046388886"/>
  3.1300 +						<object class="NSMutableArray" key="children">
  3.1301 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1302 +							<reference ref="752062318"/>
  3.1303 +						</object>
  3.1304 +						<reference key="parent" ref="110575045"/>
  3.1305 +					</object>
  3.1306 +					<object class="IBObjectRecord">
  3.1307 +						<int key="objectID">149</int>
  3.1308 +						<reference key="object" ref="1056857174"/>
  3.1309 +						<reference key="parent" ref="110575045"/>
  3.1310 +					</object>
  3.1311 +					<object class="IBObjectRecord">
  3.1312 +						<int key="objectID">145</int>
  3.1313 +						<reference key="object" ref="342932134"/>
  3.1314 +						<reference key="parent" ref="110575045"/>
  3.1315 +					</object>
  3.1316 +					<object class="IBObjectRecord">
  3.1317 +						<int key="objectID">130</int>
  3.1318 +						<reference key="object" ref="752062318"/>
  3.1319 +						<reference key="parent" ref="1046388886"/>
  3.1320 +					</object>
  3.1321 +					<object class="IBObjectRecord">
  3.1322 +						<int key="objectID">24</int>
  3.1323 +						<reference key="object" ref="835318025"/>
  3.1324 +						<object class="NSMutableArray" key="children">
  3.1325 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1326 +							<reference ref="299356726"/>
  3.1327 +							<reference ref="625202149"/>
  3.1328 +							<reference ref="575023229"/>
  3.1329 +							<reference ref="1011231497"/>
  3.1330 +						</object>
  3.1331 +						<reference key="parent" ref="713487014"/>
  3.1332 +					</object>
  3.1333 +					<object class="IBObjectRecord">
  3.1334 +						<int key="objectID">92</int>
  3.1335 +						<reference key="object" ref="299356726"/>
  3.1336 +						<reference key="parent" ref="835318025"/>
  3.1337 +					</object>
  3.1338 +					<object class="IBObjectRecord">
  3.1339 +						<int key="objectID">5</int>
  3.1340 +						<reference key="object" ref="625202149"/>
  3.1341 +						<reference key="parent" ref="835318025"/>
  3.1342 +					</object>
  3.1343 +					<object class="IBObjectRecord">
  3.1344 +						<int key="objectID">239</int>
  3.1345 +						<reference key="object" ref="575023229"/>
  3.1346 +						<reference key="parent" ref="835318025"/>
  3.1347 +					</object>
  3.1348 +					<object class="IBObjectRecord">
  3.1349 +						<int key="objectID">23</int>
  3.1350 +						<reference key="object" ref="1011231497"/>
  3.1351 +						<reference key="parent" ref="835318025"/>
  3.1352 +					</object>
  3.1353 +					<object class="IBObjectRecord">
  3.1354 +						<int key="objectID">295</int>
  3.1355 +						<reference key="object" ref="586577488"/>
  3.1356 +						<object class="NSMutableArray" key="children">
  3.1357 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1358 +							<reference ref="466310130"/>
  3.1359 +						</object>
  3.1360 +						<reference key="parent" ref="649796088"/>
  3.1361 +					</object>
  3.1362 +					<object class="IBObjectRecord">
  3.1363 +						<int key="objectID">296</int>
  3.1364 +						<reference key="object" ref="466310130"/>
  3.1365 +						<object class="NSMutableArray" key="children">
  3.1366 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1367 +							<reference ref="102151532"/>
  3.1368 +							<reference ref="237841660"/>
  3.1369 +							<reference ref="713673133"/>
  3.1370 +							<reference ref="30531644"/>
  3.1371 +						</object>
  3.1372 +						<reference key="parent" ref="586577488"/>
  3.1373 +					</object>
  3.1374 +					<object class="IBObjectRecord">
  3.1375 +						<int key="objectID">297</int>
  3.1376 +						<reference key="object" ref="102151532"/>
  3.1377 +						<reference key="parent" ref="466310130"/>
  3.1378 +					</object>
  3.1379 +					<object class="IBObjectRecord">
  3.1380 +						<int key="objectID">298</int>
  3.1381 +						<reference key="object" ref="237841660"/>
  3.1382 +						<reference key="parent" ref="466310130"/>
  3.1383 +					</object>
  3.1384 +					<object class="IBObjectRecord">
  3.1385 +						<int key="objectID">211</int>
  3.1386 +						<reference key="object" ref="676164635"/>
  3.1387 +						<object class="NSMutableArray" key="children">
  3.1388 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1389 +							<reference ref="785027613"/>
  3.1390 +						</object>
  3.1391 +						<reference key="parent" ref="789758025"/>
  3.1392 +					</object>
  3.1393 +					<object class="IBObjectRecord">
  3.1394 +						<int key="objectID">212</int>
  3.1395 +						<reference key="object" ref="785027613"/>
  3.1396 +						<object class="NSMutableArray" key="children">
  3.1397 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1398 +							<reference ref="680220178"/>
  3.1399 +							<reference ref="731782645"/>
  3.1400 +						</object>
  3.1401 +						<reference key="parent" ref="676164635"/>
  3.1402 +					</object>
  3.1403 +					<object class="IBObjectRecord">
  3.1404 +						<int key="objectID">195</int>
  3.1405 +						<reference key="object" ref="680220178"/>
  3.1406 +						<reference key="parent" ref="785027613"/>
  3.1407 +					</object>
  3.1408 +					<object class="IBObjectRecord">
  3.1409 +						<int key="objectID">196</int>
  3.1410 +						<reference key="object" ref="731782645"/>
  3.1411 +						<reference key="parent" ref="785027613"/>
  3.1412 +					</object>
  3.1413 +					<object class="IBObjectRecord">
  3.1414 +						<int key="objectID">371</int>
  3.1415 +						<reference key="object" ref="972006081"/>
  3.1416 +						<object class="NSMutableArray" key="children">
  3.1417 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1418 +							<reference ref="439893737"/>
  3.1419 +						</object>
  3.1420 +						<reference key="parent" ref="1049"/>
  3.1421 +					</object>
  3.1422 +					<object class="IBObjectRecord">
  3.1423 +						<int key="objectID">372</int>
  3.1424 +						<reference key="object" ref="439893737"/>
  3.1425 +						<object class="NSMutableArray" key="children">
  3.1426 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1427 +							<reference ref="1060834180"/>
  3.1428 +						</object>
  3.1429 +						<reference key="parent" ref="972006081"/>
  3.1430 +					</object>
  3.1431 +					<object class="IBObjectRecord">
  3.1432 +						<int key="objectID">375</int>
  3.1433 +						<reference key="object" ref="1060834180"/>
  3.1434 +						<reference key="parent" ref="439893737"/>
  3.1435 +					</object>
  3.1436 +					<object class="IBObjectRecord">
  3.1437 +						<int key="objectID">376</int>
  3.1438 +						<reference key="object" ref="713673133"/>
  3.1439 +						<reference key="parent" ref="466310130"/>
  3.1440 +					</object>
  3.1441 +					<object class="IBObjectRecord">
  3.1442 +						<int key="objectID">377</int>
  3.1443 +						<reference key="object" ref="30531644"/>
  3.1444 +						<reference key="parent" ref="466310130"/>
  3.1445 +					</object>
  3.1446 +					<object class="IBObjectRecord">
  3.1447 +						<int key="objectID">379</int>
  3.1448 +						<reference key="object" ref="517895433"/>
  3.1449 +						<object class="NSMutableArray" key="children">
  3.1450 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1451 +							<reference ref="330268596"/>
  3.1452 +						</object>
  3.1453 +						<reference key="parent" ref="649796088"/>
  3.1454 +					</object>
  3.1455 +					<object class="IBObjectRecord">
  3.1456 +						<int key="objectID">380</int>
  3.1457 +						<reference key="object" ref="330268596"/>
  3.1458 +						<object class="NSMutableArray" key="children">
  3.1459 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1460 +							<reference ref="394352720"/>
  3.1461 +							<reference ref="538211827"/>
  3.1462 +							<reference ref="739065818"/>
  3.1463 +							<reference ref="154289436"/>
  3.1464 +							<reference ref="778498721"/>
  3.1465 +							<reference ref="630661937"/>
  3.1466 +						</object>
  3.1467 +						<reference key="parent" ref="517895433"/>
  3.1468 +					</object>
  3.1469 +					<object class="IBObjectRecord">
  3.1470 +						<int key="objectID">381</int>
  3.1471 +						<reference key="object" ref="394352720"/>
  3.1472 +						<reference key="parent" ref="330268596"/>
  3.1473 +					</object>
  3.1474 +					<object class="IBObjectRecord">
  3.1475 +						<int key="objectID">382</int>
  3.1476 +						<reference key="object" ref="630661937"/>
  3.1477 +						<reference key="parent" ref="330268596"/>
  3.1478 +					</object>
  3.1479 +					<object class="IBObjectRecord">
  3.1480 +						<int key="objectID">383</int>
  3.1481 +						<reference key="object" ref="538211827"/>
  3.1482 +						<reference key="parent" ref="330268596"/>
  3.1483 +					</object>
  3.1484 +					<object class="IBObjectRecord">
  3.1485 +						<int key="objectID">384</int>
  3.1486 +						<reference key="object" ref="739065818"/>
  3.1487 +						<reference key="parent" ref="330268596"/>
  3.1488 +					</object>
  3.1489 +					<object class="IBObjectRecord">
  3.1490 +						<int key="objectID">387</int>
  3.1491 +						<reference key="object" ref="154289436"/>
  3.1492 +						<reference key="parent" ref="330268596"/>
  3.1493 +					</object>
  3.1494 +					<object class="IBObjectRecord">
  3.1495 +						<int key="objectID">393</int>
  3.1496 +						<reference key="object" ref="778498721"/>
  3.1497 +						<reference key="parent" ref="330268596"/>
  3.1498 +					</object>
  3.1499 +				</object>
  3.1500 +			</object>
  3.1501 +			<object class="NSMutableDictionary" key="flattenedProperties">
  3.1502 +				<bool key="EncodedWithXMLCoder">YES</bool>
  3.1503 +				<object class="NSMutableArray" key="dict.sortedKeys">
  3.1504 +					<bool key="EncodedWithXMLCoder">YES</bool>
  3.1505 +					<string>-1.IBPluginDependency</string>
  3.1506 +					<string>-2.IBPluginDependency</string>
  3.1507 +					<string>-3.IBPluginDependency</string>
  3.1508 +					<string>103.IBPluginDependency</string>
  3.1509 +					<string>103.ImportedFromIB2</string>
  3.1510 +					<string>106.IBPluginDependency</string>
  3.1511 +					<string>106.ImportedFromIB2</string>
  3.1512 +					<string>106.editorWindowContentRectSynchronizationRect</string>
  3.1513 +					<string>112.IBPluginDependency</string>
  3.1514 +					<string>112.ImportedFromIB2</string>
  3.1515 +					<string>124.IBPluginDependency</string>
  3.1516 +					<string>124.ImportedFromIB2</string>
  3.1517 +					<string>125.IBPluginDependency</string>
  3.1518 +					<string>125.ImportedFromIB2</string>
  3.1519 +					<string>125.editorWindowContentRectSynchronizationRect</string>
  3.1520 +					<string>126.IBPluginDependency</string>
  3.1521 +					<string>126.ImportedFromIB2</string>
  3.1522 +					<string>129.IBPluginDependency</string>
  3.1523 +					<string>129.ImportedFromIB2</string>
  3.1524 +					<string>130.IBPluginDependency</string>
  3.1525 +					<string>130.ImportedFromIB2</string>
  3.1526 +					<string>130.editorWindowContentRectSynchronizationRect</string>
  3.1527 +					<string>131.IBPluginDependency</string>
  3.1528 +					<string>131.ImportedFromIB2</string>
  3.1529 +					<string>134.IBPluginDependency</string>
  3.1530 +					<string>134.ImportedFromIB2</string>
  3.1531 +					<string>136.IBPluginDependency</string>
  3.1532 +					<string>136.ImportedFromIB2</string>
  3.1533 +					<string>143.IBPluginDependency</string>
  3.1534 +					<string>143.ImportedFromIB2</string>
  3.1535 +					<string>144.IBPluginDependency</string>
  3.1536 +					<string>144.ImportedFromIB2</string>
  3.1537 +					<string>145.IBPluginDependency</string>
  3.1538 +					<string>145.ImportedFromIB2</string>
  3.1539 +					<string>149.IBPluginDependency</string>
  3.1540 +					<string>149.ImportedFromIB2</string>
  3.1541 +					<string>150.IBPluginDependency</string>
  3.1542 +					<string>150.ImportedFromIB2</string>
  3.1543 +					<string>19.IBPluginDependency</string>
  3.1544 +					<string>19.ImportedFromIB2</string>
  3.1545 +					<string>195.IBPluginDependency</string>
  3.1546 +					<string>195.ImportedFromIB2</string>
  3.1547 +					<string>196.IBPluginDependency</string>
  3.1548 +					<string>196.ImportedFromIB2</string>
  3.1549 +					<string>197.IBPluginDependency</string>
  3.1550 +					<string>197.ImportedFromIB2</string>
  3.1551 +					<string>198.IBPluginDependency</string>
  3.1552 +					<string>198.ImportedFromIB2</string>
  3.1553 +					<string>199.IBPluginDependency</string>
  3.1554 +					<string>199.ImportedFromIB2</string>
  3.1555 +					<string>202.IBPluginDependency</string>
  3.1556 +					<string>202.ImportedFromIB2</string>
  3.1557 +					<string>203.IBPluginDependency</string>
  3.1558 +					<string>203.ImportedFromIB2</string>
  3.1559 +					<string>205.IBPluginDependency</string>
  3.1560 +					<string>205.ImportedFromIB2</string>
  3.1561 +					<string>205.editorWindowContentRectSynchronizationRect</string>
  3.1562 +					<string>206.IBPluginDependency</string>
  3.1563 +					<string>206.ImportedFromIB2</string>
  3.1564 +					<string>207.IBPluginDependency</string>
  3.1565 +					<string>207.ImportedFromIB2</string>
  3.1566 +					<string>211.IBPluginDependency</string>
  3.1567 +					<string>211.ImportedFromIB2</string>
  3.1568 +					<string>212.IBPluginDependency</string>
  3.1569 +					<string>212.ImportedFromIB2</string>
  3.1570 +					<string>212.editorWindowContentRectSynchronizationRect</string>
  3.1571 +					<string>214.IBPluginDependency</string>
  3.1572 +					<string>214.ImportedFromIB2</string>
  3.1573 +					<string>215.IBPluginDependency</string>
  3.1574 +					<string>215.ImportedFromIB2</string>
  3.1575 +					<string>217.IBPluginDependency</string>
  3.1576 +					<string>217.ImportedFromIB2</string>
  3.1577 +					<string>23.IBPluginDependency</string>
  3.1578 +					<string>23.ImportedFromIB2</string>
  3.1579 +					<string>236.IBPluginDependency</string>
  3.1580 +					<string>236.ImportedFromIB2</string>
  3.1581 +					<string>239.IBPluginDependency</string>
  3.1582 +					<string>239.ImportedFromIB2</string>
  3.1583 +					<string>24.IBPluginDependency</string>
  3.1584 +					<string>24.ImportedFromIB2</string>
  3.1585 +					<string>24.editorWindowContentRectSynchronizationRect</string>
  3.1586 +					<string>29.IBPluginDependency</string>
  3.1587 +					<string>29.ImportedFromIB2</string>
  3.1588 +					<string>29.WindowOrigin</string>
  3.1589 +					<string>29.editorWindowContentRectSynchronizationRect</string>
  3.1590 +					<string>295.IBPluginDependency</string>
  3.1591 +					<string>296.IBPluginDependency</string>
  3.1592 +					<string>296.editorWindowContentRectSynchronizationRect</string>
  3.1593 +					<string>297.IBPluginDependency</string>
  3.1594 +					<string>298.IBPluginDependency</string>
  3.1595 +					<string>371.IBPluginDependency</string>
  3.1596 +					<string>371.IBWindowTemplateEditedContentRect</string>
  3.1597 +					<string>371.NSWindowTemplate.visibleAtLaunch</string>
  3.1598 +					<string>371.editorWindowContentRectSynchronizationRect</string>
  3.1599 +					<string>372.IBPluginDependency</string>
  3.1600 +					<string>375.IBPluginDependency</string>
  3.1601 +					<string>376.IBPluginDependency</string>
  3.1602 +					<string>377.IBPluginDependency</string>
  3.1603 +					<string>379.IBPluginDependency</string>
  3.1604 +					<string>380.IBPluginDependency</string>
  3.1605 +					<string>380.editorWindowContentRectSynchronizationRect</string>
  3.1606 +					<string>381.IBPluginDependency</string>
  3.1607 +					<string>382.IBPluginDependency</string>
  3.1608 +					<string>383.IBPluginDependency</string>
  3.1609 +					<string>384.IBPluginDependency</string>
  3.1610 +					<string>387.IBPluginDependency</string>
  3.1611 +					<string>393.IBPluginDependency</string>
  3.1612 +					<string>5.IBPluginDependency</string>
  3.1613 +					<string>5.ImportedFromIB2</string>
  3.1614 +					<string>56.IBPluginDependency</string>
  3.1615 +					<string>56.ImportedFromIB2</string>
  3.1616 +					<string>57.IBPluginDependency</string>
  3.1617 +					<string>57.ImportedFromIB2</string>
  3.1618 +					<string>57.editorWindowContentRectSynchronizationRect</string>
  3.1619 +					<string>58.IBPluginDependency</string>
  3.1620 +					<string>58.ImportedFromIB2</string>
  3.1621 +					<string>72.IBPluginDependency</string>
  3.1622 +					<string>72.ImportedFromIB2</string>
  3.1623 +					<string>73.IBPluginDependency</string>
  3.1624 +					<string>73.ImportedFromIB2</string>
  3.1625 +					<string>74.IBPluginDependency</string>
  3.1626 +					<string>74.ImportedFromIB2</string>
  3.1627 +					<string>75.IBPluginDependency</string>
  3.1628 +					<string>75.ImportedFromIB2</string>
  3.1629 +					<string>77.IBPluginDependency</string>
  3.1630 +					<string>77.ImportedFromIB2</string>
  3.1631 +					<string>78.IBPluginDependency</string>
  3.1632 +					<string>78.ImportedFromIB2</string>
  3.1633 +					<string>79.IBPluginDependency</string>
  3.1634 +					<string>79.ImportedFromIB2</string>
  3.1635 +					<string>80.IBPluginDependency</string>
  3.1636 +					<string>80.ImportedFromIB2</string>
  3.1637 +					<string>81.IBPluginDependency</string>
  3.1638 +					<string>81.ImportedFromIB2</string>
  3.1639 +					<string>81.editorWindowContentRectSynchronizationRect</string>
  3.1640 +					<string>82.IBPluginDependency</string>
  3.1641 +					<string>82.ImportedFromIB2</string>
  3.1642 +					<string>83.IBPluginDependency</string>
  3.1643 +					<string>83.ImportedFromIB2</string>
  3.1644 +					<string>92.IBPluginDependency</string>
  3.1645 +					<string>92.ImportedFromIB2</string>
  3.1646 +				</object>
  3.1647 +				<object class="NSMutableArray" key="dict.values">
  3.1648 +					<bool key="EncodedWithXMLCoder">YES</bool>
  3.1649 +					<reference ref="248469711"/>
  3.1650 +					<reference ref="617114957"/>
  3.1651 +					<reference ref="617114957"/>
  3.1652 +					<reference ref="248469711"/>
  3.1653 +					<integer value="1" id="9"/>
  3.1654 +					<reference ref="248469711"/>
  3.1655 +					<reference ref="9"/>
  3.1656 +					<string>{{497, 828}, {64, 6}}</string>
  3.1657 +					<reference ref="248469711"/>
  3.1658 +					<reference ref="9"/>
  3.1659 +					<reference ref="248469711"/>
  3.1660 +					<reference ref="9"/>
  3.1661 +					<reference ref="248469711"/>
  3.1662 +					<reference ref="9"/>
  3.1663 +					<string>{{522, 812}, {146, 23}}</string>
  3.1664 +					<reference ref="248469711"/>
  3.1665 +					<reference ref="9"/>
  3.1666 +					<reference ref="248469711"/>
  3.1667 +					<reference ref="9"/>
  3.1668 +					<reference ref="248469711"/>
  3.1669 +					<reference ref="9"/>
  3.1670 +					<string>{{436, 809}, {64, 6}}</string>
  3.1671 +					<reference ref="248469711"/>
  3.1672 +					<reference ref="9"/>
  3.1673 +					<reference ref="248469711"/>
  3.1674 +					<reference ref="9"/>
  3.1675 +					<reference ref="248469711"/>
  3.1676 +					<reference ref="9"/>
  3.1677 +					<reference ref="248469711"/>
  3.1678 +					<reference ref="9"/>
  3.1679 +					<reference ref="248469711"/>
  3.1680 +					<reference ref="9"/>
  3.1681 +					<reference ref="248469711"/>
  3.1682 +					<reference ref="9"/>
  3.1683 +					<reference ref="248469711"/>
  3.1684 +					<reference ref="9"/>
  3.1685 +					<reference ref="248469711"/>
  3.1686 +					<reference ref="9"/>
  3.1687 +					<reference ref="248469711"/>
  3.1688 +					<reference ref="9"/>
  3.1689 +					<reference ref="248469711"/>
  3.1690 +					<reference ref="9"/>
  3.1691 +					<reference ref="248469711"/>
  3.1692 +					<reference ref="9"/>
  3.1693 +					<reference ref="248469711"/>
  3.1694 +					<reference ref="9"/>
  3.1695 +					<reference ref="248469711"/>
  3.1696 +					<reference ref="9"/>
  3.1697 +					<reference ref="248469711"/>
  3.1698 +					<reference ref="9"/>
  3.1699 +					<reference ref="248469711"/>
  3.1700 +					<reference ref="9"/>
  3.1701 +					<reference ref="248469711"/>
  3.1702 +					<reference ref="9"/>
  3.1703 +					<reference ref="248469711"/>
  3.1704 +					<reference ref="9"/>
  3.1705 +					<string>{{271, 653}, {154, 183}}</string>
  3.1706 +					<reference ref="248469711"/>
  3.1707 +					<reference ref="9"/>
  3.1708 +					<reference ref="248469711"/>
  3.1709 +					<reference ref="9"/>
  3.1710 +					<reference ref="248469711"/>
  3.1711 +					<reference ref="9"/>
  3.1712 +					<reference ref="248469711"/>
  3.1713 +					<reference ref="9"/>
  3.1714 +					<string>{{514, 573}, {167, 43}}</string>
  3.1715 +					<reference ref="248469711"/>
  3.1716 +					<reference ref="9"/>
  3.1717 +					<reference ref="248469711"/>
  3.1718 +					<reference ref="9"/>
  3.1719 +					<reference ref="248469711"/>
  3.1720 +					<reference ref="9"/>
  3.1721 +					<reference ref="248469711"/>
  3.1722 +					<reference ref="9"/>
  3.1723 +					<reference ref="248469711"/>
  3.1724 +					<reference ref="9"/>
  3.1725 +					<reference ref="248469711"/>
  3.1726 +					<reference ref="9"/>
  3.1727 +					<reference ref="248469711"/>
  3.1728 +					<reference ref="9"/>
  3.1729 +					<string>{{525, 802}, {197, 73}}</string>
  3.1730 +					<reference ref="248469711"/>
  3.1731 +					<reference ref="9"/>
  3.1732 +					<string>{74, 862}</string>
  3.1733 +					<string>{{85, 834}, {473, 20}}</string>
  3.1734 +					<reference ref="248469711"/>
  3.1735 +					<reference ref="248469711"/>
  3.1736 +					<string>{{319, 763}, {234, 73}}</string>
  3.1737 +					<reference ref="248469711"/>
  3.1738 +					<reference ref="248469711"/>
  3.1739 +					<reference ref="248469711"/>
  3.1740 +					<string>{{117, 199}, {1084, 587}}</string>
  3.1741 +					<reference ref="9"/>
  3.1742 +					<string>{{117, 199}, {1084, 587}}</string>
  3.1743 +					<reference ref="248469711"/>
  3.1744 +					<reference ref="248469711"/>
  3.1745 +					<reference ref="248469711"/>
  3.1746 +					<reference ref="248469711"/>
  3.1747 +					<reference ref="248469711"/>
  3.1748 +					<reference ref="248469711"/>
  3.1749 +					<string>{{319, 721}, {205, 113}}</string>
  3.1750 +					<reference ref="248469711"/>
  3.1751 +					<reference ref="248469711"/>
  3.1752 +					<reference ref="248469711"/>
  3.1753 +					<reference ref="248469711"/>
  3.1754 +					<reference ref="248469711"/>
  3.1755 +					<reference ref="248469711"/>
  3.1756 +					<reference ref="248469711"/>
  3.1757 +					<reference ref="9"/>
  3.1758 +					<reference ref="248469711"/>
  3.1759 +					<reference ref="9"/>
  3.1760 +					<reference ref="248469711"/>
  3.1761 +					<reference ref="9"/>
  3.1762 +					<string>{{97, 651}, {250, 183}}</string>
  3.1763 +					<reference ref="248469711"/>
  3.1764 +					<reference ref="9"/>
  3.1765 +					<reference ref="248469711"/>
  3.1766 +					<reference ref="9"/>
  3.1767 +					<reference ref="248469711"/>
  3.1768 +					<reference ref="9"/>
  3.1769 +					<reference ref="248469711"/>
  3.1770 +					<reference ref="9"/>
  3.1771 +					<reference ref="248469711"/>
  3.1772 +					<reference ref="9"/>
  3.1773 +					<reference ref="248469711"/>
  3.1774 +					<reference ref="9"/>
  3.1775 +					<reference ref="248469711"/>
  3.1776 +					<reference ref="9"/>
  3.1777 +					<reference ref="248469711"/>
  3.1778 +					<reference ref="9"/>
  3.1779 +					<reference ref="248469711"/>
  3.1780 +					<reference ref="9"/>
  3.1781 +					<reference ref="248469711"/>
  3.1782 +					<reference ref="9"/>
  3.1783 +					<string>{{233, 633}, {199, 203}}</string>
  3.1784 +					<reference ref="248469711"/>
  3.1785 +					<reference ref="9"/>
  3.1786 +					<reference ref="248469711"/>
  3.1787 +					<reference ref="9"/>
  3.1788 +					<reference ref="248469711"/>
  3.1789 +					<reference ref="9"/>
  3.1790 +				</object>
  3.1791 +			</object>
  3.1792 +			<object class="NSMutableDictionary" key="unlocalizedProperties">
  3.1793 +				<bool key="EncodedWithXMLCoder">YES</bool>
  3.1794 +				<object class="NSArray" key="dict.sortedKeys">
  3.1795 +					<bool key="EncodedWithXMLCoder">YES</bool>
  3.1796 +				</object>
  3.1797 +				<object class="NSMutableArray" key="dict.values">
  3.1798 +					<bool key="EncodedWithXMLCoder">YES</bool>
  3.1799 +				</object>
  3.1800 +			</object>
  3.1801 +			<nil key="activeLocalization"/>
  3.1802 +			<object class="NSMutableDictionary" key="localizations">
  3.1803 +				<bool key="EncodedWithXMLCoder">YES</bool>
  3.1804 +				<object class="NSArray" key="dict.sortedKeys">
  3.1805 +					<bool key="EncodedWithXMLCoder">YES</bool>
  3.1806 +				</object>
  3.1807 +				<object class="NSMutableArray" key="dict.values">
  3.1808 +					<bool key="EncodedWithXMLCoder">YES</bool>
  3.1809 +				</object>
  3.1810 +			</object>
  3.1811 +			<nil key="sourceID"/>
  3.1812 +			<int key="maxID">400</int>
  3.1813 +		</object>
  3.1814 +		<object class="IBClassDescriber" key="IBDocument.Classes">
  3.1815 +			<object class="NSMutableArray" key="referencedPartialClassDescriptions">
  3.1816 +				<bool key="EncodedWithXMLCoder">YES</bool>
  3.1817 +				<object class="IBPartialClassDescription">
  3.1818 +					<string key="className">BoardView</string>
  3.1819 +					<string key="superclassName">NSView</string>
  3.1820 +					<object class="NSMutableDictionary" key="actions">
  3.1821 +						<string key="NS.key.0">enterFullScreen:</string>
  3.1822 +						<string key="NS.object.0" id="765642758">id</string>
  3.1823 +					</object>
  3.1824 +					<object class="NSMutableDictionary" key="outlets">
  3.1825 +						<bool key="EncodedWithXMLCoder">YES</bool>
  3.1826 +						<object class="NSArray" key="dict.sortedKeys">
  3.1827 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1828 +						</object>
  3.1829 +						<object class="NSMutableArray" key="dict.values">
  3.1830 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1831 +						</object>
  3.1832 +					</object>
  3.1833 +					<object class="IBClassDescriptionSource" key="sourceIdentifier">
  3.1834 +						<string key="majorKey" id="755626269">IBProjectSource</string>
  3.1835 +						<string key="minorKey">Source/BoardView.h</string>
  3.1836 +					</object>
  3.1837 +				</object>
  3.1838 +				<object class="IBPartialClassDescription">
  3.1839 +					<string key="className">DemoBoardView</string>
  3.1840 +					<string key="superclassName">BoardView</string>
  3.1841 +					<object class="NSMutableDictionary" key="actions">
  3.1842 +						<string key="NS.key.0">startGameFromMenu:</string>
  3.1843 +						<reference key="NS.object.0" ref="765642758"/>
  3.1844 +					</object>
  3.1845 +					<object class="NSMutableDictionary" key="outlets">
  3.1846 +						<bool key="EncodedWithXMLCoder">YES</bool>
  3.1847 +						<object class="NSArray" key="dict.sortedKeys">
  3.1848 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1849 +						</object>
  3.1850 +						<object class="NSMutableArray" key="dict.values">
  3.1851 +							<bool key="EncodedWithXMLCoder">YES</bool>
  3.1852 +						</object>
  3.1853 +					</object>
  3.1854 +					<object class="IBClassDescriptionSource" key="sourceIdentifier">
  3.1855 +						<reference key="majorKey" ref="755626269"/>
  3.1856 +						<string key="minorKey">Source/DemoBoardView.h</string>
  3.1857 +					</object>
  3.1858 +				</object>
  3.1859 +			</object>
  3.1860 +		</object>
  3.1861 +		<int key="IBDocument.localizationMode">0</int>
  3.1862 +		<string key="IBDocument.LastKnownRelativeProjectPath">../../GeekGameBoard.xcodeproj</string>
  3.1863 +		<int key="IBDocument.defaultPropertyAccessControl">3</int>
  3.1864 +		<object class="NSMutableData" key="IBDocument.RunnableNib">
  3.1865 +			<bytes key="NS.bytes">YnBsaXN0MDDUAAEAAgADAAQABQAGAAkAClgkdmVyc2lvblQkdG9wWSRhcmNoaXZlclgkb2JqZWN0cxIA
  3.1866 +AYag0QAHAAhdSUIub2JqZWN0ZGF0YYABXxAPTlNLZXllZEFyY2hpdmVyrxEByQALAAwAMQA1ADYAPAA9
  3.1867 +AEIAWABZAFoAWwALAGgAbAB2AHcAeAB9AHYACwCBAIMAhACFAIgAjACzALsAzADRANIA0wDYANkA2gDd
  3.1868 +AOEA4gDlAOYA6gDuAPYA/AD9AP4BAgEJAQ0BDgEPARMBGgEeAR8BIAEkASwBMAExATIBMwE4ATkBPAFA
  3.1869 +AUcBSAFJAUoBTgFVAVkBWgFbAV8BZgFnAWgBbAF0AXkBegF7AXwBgAGHAYgBiQGKAY4BlQGWAZcBmAGd
  3.1870 +AaUBpgGnAawBtAG1AbYBugHBAcIBwwHIAc8B0AHRAdUB3AHhAeIB4wHnAe4B7wHwAfEB9QH8Af0B/gH/
  3.1871 +AgMCCgILAgwCDQIRAhoCGwIcAh0CIQIoAikCKgIuAjUCNgI3AjgCPAJDAkQCRQJGAkoCUQJSAlMCWAJZ
  3.1872 +Al0CZAJlAmYCZwJsAnMCdAJ1AnoCgQKCAoMChAKJApECkgKTApcCngKfAqACoQKlAqwCrQKuAq8CswK6
  3.1873 +ArsCvAK9AsECyALJAsoCywLPAtYC1wLYAtwC4wLkAuUC5gMwAzEDOANDA0QDRgNRA1YDVwNlA24DdQN2
  3.1874 +A3cDgAOJA1YDigOPA5IDkwOcA6UDpgOqA6sDrgO3A7gDxQPOA9cD4ANWA+ED5gPvA1YD+ANWBAEECgQT
  3.1875 +A1YEFAQdBB4EKAQxA1YEMgRABEkDVgRKBE4ETwRYA1YEWQRgBGkDVgRyBHMEdgR4BMIFDQVYBVkFWgVb
  3.1876 +BVwFXQVeBV8FYAVhBWIFYwVkBWUFZgVnBWgFaQVqBWsFbAVtBW4FbwVwBXEFcgVzBXQFdQV2BXcFeAV5
  3.1877 +BXoFewV8BX0FfgV/BYAFgQWCBYMFhAWFBYYFhwWIBYkFigWLBYwFjQWOBY8FkAWRBZIFkwWUBZUFlgWX
  3.1878 +BZgFmQWaBZsFnAWfBaIGEQaABoEGggaDBoQGhQaGBocGiAaJBooGiwaMBo0GjgaPBpAGkQaSBpMGlAaV
  3.1879 +BpYGlwaYBpkGmgabBpwGnQaeBp8GoAahBqIGowakBqUGpganBqgGqQaqBqsGrAatBq4GrwawBrEGsgaz
  3.1880 +BrQGtQa2BrcGuAa5BroGuwa8Br0Gvga/BsAGwQbCBsMGxAbFBsYGxwbIBskGygbLBswGzQbOBs8G0AbR
  3.1881 +BtIG0wbUBtUG1gbXBtgG2QbaBtsG3AbdBt4G3wbgBuEG4gbjBuQG5QbmBucG6AbpBuoG6wbsBu8G8gb1
  3.1882 +VSRudWxs3xASAA0ADgAPABAAEQASABMAFAAVABYAFwAYABkAGgAbABwAHQAeAB8AIAAhACIAIwAkACUA
  3.1883 +JgAnACgAKQAqACsALAAtAC4ALwAwVk5TUm9vdFYkY2xhc3NdTlNPYmplY3RzS2V5c18QD05TQ2xhc3Nl
  3.1884 +c1ZhbHVlc18QGU5TQWNjZXNzaWJpbGl0eU9pZHNWYWx1ZXNdTlNDb25uZWN0aW9uc1tOU05hbWVzS2V5
  3.1885 +c1tOU0ZyYW1ld29ya11OU0NsYXNzZXNLZXlzWk5TT2lkc0tleXNdTlNOYW1lc1ZhbHVlc18QGU5TQWNj
  3.1886 +ZXNzaWJpbGl0eUNvbm5lY3RvcnNdTlNGb250TWFuYWdlcl8QEE5TVmlzaWJsZVdpbmRvd3NfEA9OU09i
  3.1887 +amVjdHNWYWx1ZXNfEBdOU0FjY2Vzc2liaWxpdHlPaWRzS2V5c1lOU05leHRPaWRcTlNPaWRzVmFsdWVz
  3.1888 +gAKBAciAy4EBVoEBx4AagQEPgAWBAVWBAVeBARCBAcWAAIAGgQEOgQHGEQGSgQFY0gAOADIAMwA0W05T
  3.1889 +Q2xhc3NOYW1lgASAA11OU0FwcGxpY2F0aW9u0gA3ADgAOQA6WCRjbGFzc2VzWiRjbGFzc25hbWWiADoA
  3.1890 +O15OU0N1c3RvbU9iamVjdFhOU09iamVjdF8QEElCQ29jb2FGcmFtZXdvcmvSAA4APgA/AEBaTlMub2Jq
  3.1891 +ZWN0c4AZoQBBgAfbAEMADgBEAEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWACtcTlNX
  3.1892 +aW5kb3dWaWV3XE5TU2NyZWVuUmVjdF8QE05TRnJhbWVBdXRvc2F2ZU5hbWVdTlNXaW5kb3dUaXRsZVlO
  3.1893 +U1dURmxhZ3NdTlNXaW5kb3dDbGFzc1xOU1dpbmRvd1JlY3RfEA9OU1dpbmRvd0JhY2tpbmdfEBFOU1dp
  3.1894 +bmRvd1N0eWxlTWFza1tOU1ZpZXdDbGFzc4ALgBiAFoAXgAkSdAAAAIAKgAgQAhAHgABfEBh7ezU3LCAx
  3.1895 +NzV9LCB7MTA4NCwgNTg3fX1dR2Vla0dhbWVCb2FyZFhOU1dpbmRvd9cAXAAOAF0AXgBfAFoAYABhAGIA
  3.1896 +YwBkAGUAYQBnXxAPTlNOZXh0UmVzcG9uZGVyWk5TU3Vidmlld3NYTlN2RmxhZ3NbTlNGcmFtZVNpemVb
  3.1897 +TlNTdXBlcnZpZXeADIAVgA0RAQCAE4AMgBTSAA4APgBpAGqAEqEAa4AO2ABcAA4AXgBfAFoAMgBgAG0A
  3.1898 +TQBvAHAAcQBhAHMATQB1XxAVTlNWaWV3SXNMYXllclRyZWVIb3N0gAuAEREBEoAPgAyAEIALCVt7MTA4
  3.1899 +NCwgNTg3fV1EZW1vQm9hcmRWaWV30gA3ADgAeQB6pAB6AHsAfAA7XE5TQ3VzdG9tVmlld1ZOU1ZpZXdb
  3.1900 +TlNSZXNwb25kZXLSADcAOAB+AH+jAH8AgAA7Xk5TTXV0YWJsZUFycmF5V05TQXJyYXnSADcAOACCAHuj
  3.1901 +AHsAfAA7XxAVe3swLCAwfSwgezE0NDAsIDg3OH19UNIANwA4AIYAh6IAhwA7XxAQTlNXaW5kb3dUZW1w
  3.1902 +bGF0ZdIANwA4AIkAiqMAigCLADtcTlNNdXRhYmxlU2V0VU5TU2V00gAOAD4AaQCOgBKvECQAjwCQAJEA
  3.1903 +kgCTAJQAlQCWAJcAmACZAJoAmwCcAJ0AngCfAKAAoQCiAKMApAClAKYApwCoAKkAqgCrAKwArQCuAK8A
  3.1904 +sACxALKAG4ApgC6AM4A4gD6AQYBGgEuAT4BVgFqAX4BjgGeAa4BvgHSAeYB+gIOAiICMgJGAloCagJyA
  3.1905 +oYClgKqAroCzgLiAvYDCgMbUAA4AtAC1ALYAtwBrALkAul1OU0Rlc3RpbmF0aW9uWE5TU291cmNlV05T
  3.1906 +TGFiZWyAKIAOgByAJ9kADgC8AL0AvgC/AMAAwQDCAMMAxADFAMYAxwDIAMkAygDLAFVXTlNUaXRsZV8Q
  3.1907 +EU5TS2V5RXF1aXZNb2RNYXNrWk5TS2V5RXF1aXZdTlNNbmVtb25pY0xvY1lOU09uSW1hZ2VcTlNNaXhl
  3.1908 +ZEltYWdlVk5TTWVudVVOU1RhZ4AmgB4SABABCIAfEn////+AIIAkgB3TAA4AvADNAM4AzwDQW05TTWVu
  3.1909 +dUl0ZW1zgNCA9oD4WkhleGNoZXF1ZXJRNNMADgAyANQA1QDWANdeTlNSZXNvdXJjZU5hbWWAI4AhgCJX
  3.1910 +TlNJbWFnZV8QD05TTWVudUNoZWNrbWFya9IANwA4ANsA3KIA3AA7XxAQTlNDdXN0b21SZXNvdXJjZdMA
  3.1911 +DgAyANQA1QDWAOCAI4AhgCVfEBBOU01lbnVNaXhlZFN0YXRl0gA3ADgA4wDkogDkADtaTlNNZW51SXRl
  3.1912 +bV8QEnN0YXJ0R2FtZUZyb21NZW51OtIANwA4AOcA6KMA6ADpADtfEBVOU05pYkNvbnRyb2xDb25uZWN0
  3.1913 +b3JeTlNOaWJDb25uZWN0b3LTAA4AtQC2ALcA7ADtgCiAKoAt2AAOALwAvQC+AL8AwADBAMIAxADwAPEA
  3.1914 +UADIAMkAygD1gCaALBIAEAAAgBeAIIAkgCvUAA4AvAD3AM0AzgD5APoA+1ZOU05hbWWA0IDMgM+AzV8Q
  3.1915 +EkJyaW5nIEFsbCB0byBGcm9udF8QD2FycmFuZ2VJbkZyb250OtMADgC1ALYAtwEAAQGAKIAvgDLYAA4A
  3.1916 +vAC9AL4AvwDAAMEAwgDEAQQA8QBQAMgAyQDKAQiAJoAxgBeAIIAkgDDTAA4AvADNAM4BCwEMgNCA7IDu
  3.1917 +XlN0YXJ0IFNwZWFraW5nXnN0YXJ0U3BlYWtpbmc60wAOALUAtgC3AREBEoAogDSAN9cADgC8AL4AvwDA
  3.1918 +AMEAwgDEARUAUADIAMkAygEZgCaANoAXgCCAJIA10wAOALwAzQDOARwBHYDQgPyA/l8QD1JldmVydCB0
  3.1919 +byBTYXZlZF8QFnJldmVydERvY3VtZW50VG9TYXZlZDrTAA4AtQC2ALcBIgEjgCiAOYA92AAOALwAvQC+
  3.1920 +AL8AwADBAMIAxAEmAScBKADIAMkAygErgCaAOxIAEgAAgDyAIIAkgDrTAA4AvADNAM4BLgEvgNCA54Do
  3.1921 +VFJlZG9RWlVyZWRvOtQADgC0ALUAtgE0AGsAHwE3gECADoACgD9YZGVsZWdhdGXSADcAOAE6ATujATsA
  3.1922 +6QA7XxAUTlNOaWJPdXRsZXRDb25uZWN0b3LTAA4AtQC2ALcBPgE/gCiAQoBF2AAOALwAvQC+AL8AwADB
  3.1923 +AMIAxAFCAPEBQwDIAMkAygEZgCaAQ4BEgCCAJIA1U05ld1FuXG5ld0RvY3VtZW50OtMADgC1ALYAtwFM
  3.1924 +AU2AKIBHgErYAA4AvAC9AL4AvwDAAMEAwgDEAVAA8QBQAMgAyQDKAVSAJoBJgBeAIIAkgEjTAA4AvADN
  3.1925 +AM4BVwFYgNCBAQWBAQdvEBIAQwB1AHMAdABvAG0AaQB6AGUAIABUAG8AbwBsAGIAYQByICZfEB9ydW5U
  3.1926 +b29sYmFyQ3VzdG9taXphdGlvblBhbGV0dGU60wAOALUAtgC3AV0BXoAogEyATtgADgC8AL0AvgC/AMAA
  3.1927 +wQDCAMQBYQDxAFAAyADJAMoBK4AmgE2AF4AggCSAOlZEZWxldGVXZGVsZXRlOtMADgC1ALYAtwFqAWuA
  3.1928 +KIBQgFTYAA4AvAC9AL4AvwDAAMEAwgDEAW4BbwFwAMgAyQDKAXOAJoBSEgAYAACAU4AggCSAUdQADgC8
  3.1929 +APcAzQDOAFEBdwF4gNCACYDigNRbSGlkZSBPdGhlcnNRaF8QFmhpZGVPdGhlckFwcGxpY2F0aW9uczrT
  3.1930 +AA4AtQC2ALcBfgF/gCiAVoBZ2AAOALwAvQC+AL8AwADBAMIAxAGCAPEBgwDIAMkAygEZgCaAV4BYgCCA
  3.1931 +JIA1ZgBQAHIAaQBuAHQgJlFwVnByaW50OtMADgC1ALYAtwGMAY2AKIBbgF7YAA4AvAC9AL4AvwDAAMEA
  3.1932 +wgDEAZAA8QGRAMgAyQDKARmAJoBcgF2AIIAkgDVlAE8AcABlAG4gJlFvXW9wZW5Eb2N1bWVudDrUAA4A
  3.1933 +tAC1ALYAtwBrAZsAuoAogA6AYIAn2QAOALwAvQC+AL8AwADBAMIAwwDEAZ8AxgGgAMgAyQDKAMsBpIAm
  3.1934 +gGGAYoAggCSAHRAEUkdvUTPUAA4AtAC1ALYAtwBrAaoAuoAogA6AZIAn2QAOALwAvQC+AL8AwADBAMIA
  3.1935 +wwDEAa4AxgGvAMgAyQDKAMsBs4AmgGWAZoAggCSAHRADW1RpYy1UYWMtVG9lUTXTAA4AtQC2ALcBuAG5
  3.1936 +gCiAaIBq2AAOALwAvQC+AL8AwADBAMIAxAG8APEAUADIAMkAygD1gCaAaYAXgCCAJIArVFpvb21ccGVy
  3.1937 +Zm9ybVpvb2061AAOALQAtQC2ALcAawHGALqAKIAOgGyAJ9gADgC8AL0AvgC/AMAAwQDCAMQBygDGAcsA
  3.1938 +yADJAMoAy4AmgG2AboAggCSAHV8QFEtsb25kaWtlIChTb2xpdGFpcmUpUTHTAA4AtQC2ALcB0wHUgCiA
  3.1939 +cIBz2AAOALwAvQC+AL8AwADBAMIAxAHXAPEAUADIAMkAygHbgCaAcoAXgCCAJIBx1AAOALwA9wDNAM4B
  3.1940 +3gHfAeCA0IEBAIEBA4EBAlpDbGVhciBNZW51XxAVY2xlYXJSZWNlbnREb2N1bWVudHM60wAOALUAtgC3
  3.1941 +AeUB5oAogHWAeNgADgC8AL0AvgC/AMAAwQDCAMQB6QDxAeoAyADJAMoA9YAmgHaAd4AggCSAK1hNaW5p
  3.1942 +bWl6ZVFtXxATcGVyZm9ybU1pbmlhdHVyaXplOtMADgC1ALYAtwHzAfSAKIB6gH3YAA4AvAC9AL4AvwDA
  3.1943 +AMEAwgDEAfcA8QH4AMgAyQDKARmAJoB7gHyAIIAkgDVUU2F2ZVFzXXNhdmVEb2N1bWVudDrTAA4AtQC2
  3.1944 +ALcCAQICgCiAf4CC2AAOALwAvQC+AL8AwADBAMIAxAIFAPECBgDIAMkAygErgCaAgICBgCCAJIA6VVBh
  3.1945 +c3RlUXZWcGFzdGU60wAOALUAtgC3Ag8CEIAogISAh9kADgISALwAvQC+AL8AwADBAMIAxABQAhUBJwIW
  3.1946 +AMgAyQDKARlZTlNUb29sVGlwgCaAF4CFgIaAIIAkgDVdUGFnZSBTZXR1cC4uLlFQXnJ1blBhZ2VMYXlv
  3.1947 +dXQ60wAOALUAtgC3Ah8CIIAogImAi9gADgC8AL0AvgC/AMAAwQDCAMQCIwDxAFAAyADJAMoBCIAmgIqA
  3.1948 +F4AggCSAMF1TdG9wIFNwZWFraW5nXXN0b3BTcGVha2luZzrTAA4AtQC2ALcCLAItgCiAjYCQ2AAOALwA
  3.1949 +vQC+AL8AwADBAMIAxAIwAPECMQDIAMkAygErgCaAjoCPgCCAJIA6WlNlbGVjdCBBbGxRYVpzZWxlY3RB
  3.1950 +bGw60wAOALUAtgC3AjoCO4AogJKAldgADgC8AL0AvgC/AMAAwQDCAMQCPgDxAj8AyADJAMoBK4AmgJOA
  3.1951 +lIAggCSAOlRDb3B5UWNVY29weTrTAA4AtQC2ALcCSAJJgCiAl4CZ2AAOALwAvQC+AL8AwADBAMIAxAJM
  3.1952 +APEBcADIAMkAygFzgCaAmIBTgCCAJIBRXxASSGlkZSBHZWVrR2FtZUJvYXJkVWhpZGU61AAOALQAtQC2
  3.1953 +ATQAawBBAleAQIAOgAeAm18QFWluaXRpYWxGaXJzdFJlc3BvbmRlctMADgC1ALYAtwJbAlyAKICdgKDY
  3.1954 +AA4AvAC9AL4AvwDAAMEAwgDEAl8A8QJgAMgAyQDKARmAJoCegJ+AIIAkgDVVQ2xvc2VRd11wZXJmb3Jt
  3.1955 +Q2xvc2U61AAOALQAtQC2ALcAHwJqAmuAKIACgKKApNcADgC8AL4AvwDAAMEAwgDEAm4AUADIAMkAygFz
  3.1956 +gCaAo4AXgCCAJIBRXxATQWJvdXQgR2Vla0dhbWVCb2FyZF8QHW9yZGVyRnJvbnRTdGFuZGFyZEFib3V0
  3.1957 +UGFuZWw61AAOALQAtQC2ALcAawJ4AnmAKIAOgKaAqdgADgC8AL0AvgC/AMAAwQDCAMQCfADxAn0AyADJ
  3.1958 +AMoBVIAmgKeAqIAggCSASFtGdWxsIFNjcmVlblFmXxAQZW50ZXJGdWxsU2NyZWVuOtQADgC0ALUAtgC3
  3.1959 +AGsChwC6gCiADoCrgCfZAA4AvAC9AL4AvwDAAMEAwgDDAMQCiwDGAowAyADJAMoAywKQgCaArICtgCCA
  3.1960 +JIAdEAFYQ2hlY2tlcnNRMtMADgC1ALYAtwKVApaAKICvgLLYAA4AvAC9AL4AvwDAAMEAwgDEApkA8QKa
  3.1961 +AMgAyQDKASuAJoCwgLGAIIAkgDpUVW5kb1F6VXVuZG860wAOALUAtgC3AqMCpIAogLSAt9gADgC8AL0A
  3.1962 +vgC/AMAAwQDCAMQCpwDxAqgAyADJAMoBc4AmgLWAtoAggCSAUV8QElF1aXQgR2Vla0dhbWVCb2FyZFFx
  3.1963 +WnRlcm1pbmF0ZTrTAA4AtQC2ALcCsQKygCiAuYC82AAOALwAvQC+AL8AwADBAMIAxAK1APECtgDIAMkA
  3.1964 +ygErgCaAuoC7gCCAJIA6U0N1dFF4VGN1dDrTAA4AtQC2ALcCvwLAgCiAvoDB2AAOALwAvQC+AL8AwADB
  3.1965 +AMIAxALDAW8CxADIAMkAygFUgCaAv4DAgCCAJIBIXFNob3cgVG9vbGJhclF0XxATdG9nZ2xlVG9vbGJh
  3.1966 +clNob3duOtMADgC1ALYAtwLNAs6AKIDDgMXYAA4AvAC9AL4AvwDAAMEAwgDEAtEA8QBQAMgAyQDKAXOA
  3.1967 +JoDEgBeAIIAkgFFYU2hvdyBBbGxfEBZ1bmhpZGVBbGxBcHBsaWNhdGlvbnM60wAOALUAtgC3AtoC24Ao
  3.1968 +gMeAytgADgC8AL0AvgC/AMAAwQDCAMQC3gEnAt8AyADJAMoBGYAmgMiAyYAggCSANWgAUwBhAHYAZQAg
  3.1969 +AEEAcyAmUVNfEA9zYXZlRG9jdW1lbnRBczrSAA4APgLnAuiBAQ2vEEcA9QE+AusC7AHlAu4CLAGMAvEC
  3.1970 +8gKHASsBagHGAvcBcwKVAfMBIgEAAUwCowL/AdMBqgLaAg8COgK/AwYBfgMIAwkCeAMLAwwBXQMOAw8B
  3.1971 +GQMRAxIDEwMUAxUAuQKxAs0ATQERAEEDHAJqAh8DHwJIAGsB2wEIAbgCAQMmAMsBmwMpAVQDKwDsAy0C
  3.1972 +WwMvgCuAQoDOgNGAdYDjgI2AW4DmgNWAq4A6gFCAbIDvgFGAr4B6gDmAL4BHgLSA8IBwgGSAx4CEgJKA
  3.1973 +voDrgFaA8oDdgKaA9ID1gEyA0oDZgDWA4YEBCYEBDIDWgPuAHIC5gMOAC4A0gAeA6YCigImBAQSAl4AO
  3.1974 +gHGAMIBogH+A2oAdgGCA/4BIgQEIgCqA4ICdgOpWV2luZG930gAOAD4AaQMzgBKkAeUBuALrAOyAdYBo
  3.1975 +gM6AKtoADgC8AL0DOQC+AzoAvwDAAMEAwgDEAFAA8QB1AFAAdQDIAMkAygD1XU5TSXNTZXBhcmF0b3Jc
  3.1976 +TlNJc0Rpc2FibGVkgCaAFwmAFwmAIIAkgCteX05TV2luZG93c01lbnXSADcAOANFAMKiAMIAO9oADgNH
  3.1977 +ALwAvQC+AL8AwADBAMIDSADEAXMAUQDxAFAAyADJAMoDDgNQWU5TU3VibWVudVhOU0FjdGlvboAmgFGA
  3.1978 +CYAXgCCAJIDSgNPUAA4AvAD3AM0AzgNTA1QDVYDQgPmBAQuA+l5zdWJtZW51QWN0aW9uOtIADgA+AGkD
  3.1979 +WYASqwJqAvIDFAMPAyYDLQJIAWoCzQMRAqOAooDVgNaA2YDagOCAl4BQgMOA4YC02gAOALwAvQM5AL4D
  3.1980 +OgC/AMAAwQDCAMQAUADxAHUAUAB1AMgAyQDKAXOAJoAXCYAXCYAggCSAUdgADgC8AL0AvgC/AMAAwQDC
  3.1981 +AMQDcADxA3EAyADJAMoBc4AmgNeA2IAggCSAUWwAUAByAGUAZgBlAHIAZQBuAGMAZQBzICZRLNoADgC8
  3.1982 +AL0DOQC+AzoAvwDAAMEAwgDEAFAA8QB1AFAAdQDIAMkAygFzgCaAFwmAFwmAIIAkgFHaAA4DRwC8AL0A
  3.1983 +vgC/AMAAwQDCA0gAxAMJA4MA8QBQAMgAyQDKAXMDiIAmgN2A24AXgCCAJIBRgNxYU2VydmljZXPUAA4A
  3.1984 +vAD3AM0AzgODA40DjoDQgNuA34De0gAOAD4AaQORgBKgXxAPX05TU2VydmljZXNNZW512gAOALwAvQM5
  3.1985 +AL4DOgC/AMAAwQDCAMQAUADxAHUAUAB1AMgAyQDKAXOAJoAXCYAXCYAggCSAUdoADgC8AL0DOQC+AzoA
  3.1986 +vwDAAMEAwgDEAFAA8QB1AFAAdQDIAMkAygFzgCaAFwmAFwmAIIAkgFFcX05TQXBwbGVNZW510wAOALwA
  3.1987 +zQDOA6gDqYDQgOSA5VRIZWxw0gAOAD4AaQOtgBKg2gAOALwAvQM5AL4DOgC/AMAAwQDCAMQAUADxAHUA
  3.1988 +UAB1AMgAyQDKARmAJoAXCYAXCYAggCSANVRFZGl00gAOAD4AaQO6gBKqApUBIgMcArECOgIBAV0CLAMv
  3.1989 +AwaAr4A5gOmAuYCSgH+ATICNgOqA69oADgC8AL0DOQC+AzoAvwDAAMEAwgDEAFAA8QB1AFAAdQDIAMkA
  3.1990 +ygErgCaAFwmAFwmAIIAkgDraAA4AvAC9AzkAvgM6AL8AwADBAMIAxABQAPEAdQBQAHUAyADJAMoBK4Am
  3.1991 +gBcJgBcJgCCAJIA62gAOA0cAvAC9AL4AvwDAAMEAwgNIAMQBCAELAPEAUADIAMkAygErA9+AJoAwgOyA
  3.1992 +F4AggCSAOoDtVlNwZWVjaNIADgA+AGkD44ASogEAAh+AL4CJ2gAOALwAvQM5AL4DOgC/AMAAwQDCAMQA
  3.1993 +UADxAHUAUAB1AMgAyQDKAMuAJoAXCYAXCYAggCSAHdoADgNHALwAvQC+AL8AwADBAMIDSADEAu4DqADx
  3.1994 +AFAAyADJAMoDDgP3gCaA44DkgBeAIIAkgNKA8doADgNHALwAvQC+AL8AwADBAMIDSADEASsBLgDxAFAA
  3.1995 +yADJAMoDDgQAgCaAOoDngBeAIIAkgNKA89oADgC8AL0DOQC+AzoAvwDAAMEAwgDEAFAA8QB1AFAAdQDI
  3.1996 +AMkAygEZgCaAFwmAFwmAIIAkgDXaAA4DRwC8AL0AvgC/AMAAwQDCA0gAxADLAM8A8QBQAMgAyQDKAw4E
  3.1997 +EoAmgB2A9oAXgCCAJIDSgPdUR2FtZdIADgA+AGkEFoASpgHGAvcChwGbALkBqoBsgO+Aq4BggByAZFlB
  3.1998 +TWFpbk1lbnXSAA4APgBpBCCAEqcC7AMVAwgDDAMfAxIC/4DRgPuA8oD1gQEEgQEJgPDaAA4DRwC8AL0A
  3.1999 +vgC/AMAAwQDCA0gAxAEZARwA8QBQAMgAyQDKAw4EMIAmgDWA/IAXgCCAJIDSgP1URmlsZdIADgA+AGkE
  3.2000 +NIASqwE+AYwDKQLxAlsB8wLaAREDCwIPAX6AQoBbgP+A5oCdgHqAx4A0gPSAhIBW2gAOA0cAvAC9AL4A
  3.2001 +vwDAAMEAwgNIAMQB2wHeAPEAUADIAMkAygEZBEiAJoBxgQEAgBeAIIAkgDWBAQFbT3BlbiBSZWNlbnTS
  3.2002 +AA4APgBpBEyAEqEB04BwXxAWX05TUmVjZW50RG9jdW1lbnRzTWVuddoADgNHALwAvQC+AL8AwADBAMID
  3.2003 +SADEAVQBVwDxAFAAyADJAMoDDgRXgCaASIEBBYAXgCCAJIDSgQEGVFZpZXfSAA4APgBpBFuAEqQCeAMr
  3.2004 +Ar8BTICmgQEIgL6AR9oADgC8AL0DOQC+AzoAvwDAAMEAwgDEAFAA8QB1AFAAdQDIAMkAygFUgCaAFwmA
  3.2005 +FwmAIIAkgEjaAA4DRwC8AL0AvgC/AMAAwQDCA0gAxAD1APkA8QBQAMgAyQDKAw4EcYAmgCuAzIAXgCCA
  3.2006 +JIDSgQEKW19OU01haW5NZW510gAOADIAMwA0gASAA9IANwA4BHcAgKIAgAA70gAOAD4C5wR6gQENrxBH
  3.2007 +AxIBGQD1Aw4A9QL/ASsBGQEZAXMAywMIAXMAywDLAuwBKwEZASsBCAFUAXMDDgHbAMsBGQEZASsBVAEr
  3.2008 +ARkDDgMmAVQBGQMOASsAHwFzAxUBcwMOAB8BcwMOAMsBKwFzAEEBGQAfASsBcwEIAw4BcwBNAykDBgD1
  3.2009 +ASsBcwMMAMsBGQMfAVQA9QFzARkBK4EBCYA1gCuA0oArgPCAOoA1gDWAUYAdgPKAUYAdgB2A0YA6gDWA
  3.2010 +OoAwgEiAUYDSgHGAHYA1gDWAOoBIgDqANYDSgNqASIA1gNKAOoACgFGA+4BRgNKAAoBRgNKAHYA6gFGA
  3.2011 +B4A1gAKAOoBRgDCA0oBRgAuA/4DrgCuAOoBRgPWAHYA1gQEEgEiAK4BRgDWAOtIADgA+AucExIEBDa8Q
  3.2012 +SAD1AT4C7ALrAeUC7gIsAYwC8QLyAocBKwFqAcYC9wFzApUB8wEiAaoBTAL/AqMBAAHTAtoCDwI6Ar8D
  3.2013 +BgF+AwgDCQJ4AB8DCwMMAV0DDgEZAw8DEQMSAxMDFQMUALkCsQLNAE0BEQBBAGsDHwJqAxwCSAIfAdsB
  3.2014 +CAG4AMsDJgIBAZsDKQFUAysDLQDsAlsDL4ArgEKA0YDOgHWA44CNgFuA5oDVgKuAOoBQgGyA74BRgK+A
  3.2015 +eoA5gGSAR4DwgLSAL4BwgMeAhICSgL6A64BWgPKA3YCmgAKA9ID1gEyA0oA1gNmA4YEBCYEBDID7gNaA
  3.2016 +HIC5gMOAC4A0gAeADoEBBICigOmAl4CJgHGAMIBogB2A2oB/gGCA/4BIgQEIgOCAKoCdgOrSAA4APgLn
  3.2017 +BQ+BAQ2vEEgFEAURBRIFEwUUAowFFgUXBRgFGQUaBRsFHAUdBR4FHwUgAaAFIgUjBSQBywUmBScFKAUp
  3.2018 +Aa8FKwUsBS0FLgUvBTAFMQUyBTMFNAU1BTYFNwU4BTkFOgU7BTwFPQU+BT8FQAVBBUIFQwVEBUUFRgVH
  3.2019 +BUgFSQVKBUsFTAVNBU4FTwVQBVEFUgVTBVQFVQVWBVeBARGBARKBAROBARSBARWArYEBFoEBF4EBGIEB
  3.2020 +GYEBGoEBG4EBHIEBHYEBHoEBH4EBIIBigQEhgQEigQEjgG6BASSBASWBASaBASeAZoEBKIEBKYEBKoEB
  3.2021 +K4EBLIEBLYEBLoEBL4EBMIEBMYEBMoEBM4EBNIEBNYEBNoEBN4EBOIEBOYEBOoEBO4EBPIEBPYEBPoEB
  3.2022 +P4EBQIEBQYEBQoEBQ4EBRIEBRYEBRoEBR4EBSIEBSYEBSoEBS4EBTIEBTYEBToEBT4EBUIEBUYEBUoEB
  3.2023 +U4EBVF1NZW51IChXaW5kb3cpUTlfEBlNZW51IEl0ZW0gKEdlZWtHYW1lQm9hcmQpW1NlcGFyYXRvci03
  3.2024 +XxAUTWVudSBJdGVtIChNaW5pbWl6ZSlfEBZNZW51IEl0ZW0gKFNlbGVjdCBBbGwpbxARAE0AZQBuAHUA
  3.2025 +IABJAHQAZQBtACAAKABPAHAAZQBuICYAKVE3WVNlcGFyYXRvcl8QFE1lbnUgSXRlbSAoQ2hlY2tlcnMp
  3.2026 +W01lbnUgKEVkaXQpXxAXTWVudSBJdGVtIChIaWRlIE90aGVycylfECBNZW51IEl0ZW0gKEtsb25kaWtl
  3.2027 +IChTb2xpdGFpcmUpKVtTZXBhcmF0b3ItNl8QFE1lbnUgKEdlZWtHYW1lQm9hcmQpXxAQTWVudSBJdGVt
  3.2028 +IChVbmRvKV8QEE1lbnUgSXRlbSAoUmVkbylfEBdNZW51IEl0ZW0gKFRpYy1UYWMtVG9lKW8QHgBNAGUA
  3.2029 +bgB1ACAASQB0AGUAbQAgACgAQwB1AHMAdABvAG0AaQB6AGUAIABUAG8AbwBsAGIAYQByICYAKVQxMTEx
  3.2030 +XxAaTWVudSBJdGVtIChTdGFydCBTcGVha2luZylfEBZNZW51IEl0ZW0gKENsZWFyIE1lbnUpUThfEBBN
  3.2031 +ZW51IEl0ZW0gKENvcHkpXxAYTWVudSBJdGVtIChTaG93IFRvb2xiYXIpXxASTWVudSBJdGVtIChTcGVl
  3.2032 +Y2gpUTZfEBBNZW51IEl0ZW0gKEVkaXQpXxAPTWVudSAoU2VydmljZXMpXxAXTWVudSBJdGVtIChGdWxs
  3.2033 +IFNjcmVlbilcRmlsZSdzIE93bmVyUzItMV8QEE1lbnUgSXRlbSAoR2FtZSlfEBJNZW51IEl0ZW0gKERl
  3.2034 +bGV0ZSlYTWFpbk1lbnVbTWVudSAoRmlsZSlbU2VwYXJhdG9yLTFbU2VwYXJhdG9yLTJfEBJNZW51IEl0
  3.2035 +ZW0gKFdpbmRvdylbQXBwbGljYXRpb25fEBBNZW51IEl0ZW0gKEZpbGUpUzEyMV8QFk1lbnUgSXRlbSAo
  3.2036 +SGV4Y2hlcXVlcilfEA9NZW51IEl0ZW0gKEN1dClfEBRNZW51IEl0ZW0gKFNob3cgQWxsKVxDb250ZW50
  3.2037 +IFZpZXdSMTBfEBZXaW5kb3cgKEdlZWtHYW1lQm9hcmQpXxAPRGVtbyBCb2FyZCBWaWV3XxAQTWVudSBJ
  3.2038 +dGVtIChWaWV3KV8QH01lbnUgSXRlbSAoQWJvdXQgR2Vla0dhbWVCb2FyZClbU2VwYXJhdG9yLTRfEB5N
  3.2039 +ZW51IEl0ZW0gKEhpZGUgR2Vla0dhbWVCb2FyZClfEBlNZW51IEl0ZW0gKFN0b3AgU3BlYWtpbmcpXxAS
  3.2040 +TWVudSAoT3BlbiBSZWNlbnQpXU1lbnUgKFNwZWVjaClfEBBNZW51IEl0ZW0gKFpvb20pW01lbnUgKEdh
  3.2041 +bWUpXxAUTWVudSBJdGVtIChTZXJ2aWNlcylfEBFNZW51IEl0ZW0gKFBhc3RlKV5NZW51IEl0ZW0gKEdv
  3.2042 +KV8QF01lbnUgSXRlbSAoT3BlbiBSZWNlbnQpW01lbnUgKFZpZXcpW1NlcGFyYXRvci04W1NlcGFyYXRv
  3.2043 +ci0zXxAeTWVudSBJdGVtIChCcmluZyBBbGwgdG8gRnJvbnQpUzEtMVtTZXBhcmF0b3ItNdIADgA+AucF
  3.2044 +noEBDaDSAA4APgLnBaGBAQ2g0gAOAD4C5wWkgQENrxBsAT4AlwLuAiwBjAHGAvcAsAKVAfMBAAChAUwC
  3.2045 +owL/AKUC2gI6Ar8ApACsAX4AqAMJAJUArwMLAwwAsQFdAw4BGQCcAxIApgMTAJ0DFACqAJMAngCuAs0B
  3.2046 +EQBBAxwDHwCaAkgArQIBAMsBmwMrAOwDLQMvAPUC6wLsAeUC8QLyAocBKwFqAJ8BcwEiAaoAogHTAg8D
  3.2047 +BgCrAKkDCACQALIAowJ4AB8ApwCPAw8DEQMVALkAkgKxAJEATQCWAGsCHwJqAJkAoAHbAQgBuAMmAJgD
  3.2048 +KQFUAJQAmwJbgEKAS4DjgI2AW4BsgO+AvYCvgHqAL4B5gEeAtIDwgIyAx4CSgL6AiICqgFaAmoDdgEGA
  3.2049 +uID0gPWAwoBMgNKANYBjgQEJgJGBAQyAZ4DWgKGAOIBrgLOAw4A0gAeA6YEBBIBagJeAroB/gB2AYIEB
  3.2050 +CIAqgOCA6oArgM6A0YB1gOaA1YCrgDqAUIBvgFGAOYBkgH6AcICEgOuApYCcgPKAKYDGgIOApoACgJaA
  3.2051 +G4DZgOGA+4AcgDOAuYAugAuARoAOgImAooBVgHSAcYAwgGiA2oBPgP+ASIA+gF+AndIADgA+AucGE4EB
  3.2052 +Da8QbAYUBhUGFgYXBhgGGQYaBhsGHAYdBh4GHwYgBiEGIgYjBiQGJQYmBicGKAYpBioGKwYsBi0GLgYv
  3.2053 +BjAGMQYyBjMGNAY1BjYGNwY4BjkGOgY7BjwGPQY+Bj8GQAZBBkIGQwZEBkUGRgZHBkgGSQZKBksGTAZN
  3.2054 +Bk4GTwZQBlEGUgZTBlQGVQZWBlcGWAZZBloGWwZcBl0GXgZfBmAGYQZiBmMGZAZlBmYGZwZoBmkGagZr
  3.2055 +BmwGbQZuBm8GcAZxBnIGcwZ0BnUGdgZ3BngGeQZ6BnsGfAZ9Bn4Gf4EBWYEBWoEBW4EBXIEBXYEBXoEB
  3.2056 +X4EBYIEBYYEBYoEBY4EBZIEBZYEBZoEBZ4EBaIEBaYEBaoEBa4EBbIEBbYEBboEBb4EBcIEBcYEBcoEB
  3.2057 +c4EBdIEBdYEBdoEBd4EBeIEBeYEBeoEBe4EBfIEBfYEBfoEBf4EBgIEBgYEBgoEBg4EBhIEBhYEBhoEB
  3.2058 +h4EBiIEBiYEBioEBi4EBjIEBjYEBjoEBj4EBkIEBkYEBkoEBk4EBlIEBlYEBloEBl4EBmIEBmYEBmoEB
  3.2059 +m4EBnIEBnYEBnoEBn4EBoIEBoYEBooEBo4EBpIEBpYEBpoEBp4EBqIEBqYEBqoEBq4EBrIEBrYEBroEB
  3.2060 +r4EBsIEBsYEBsoEBs4EBtIEBtYEBtoEBt4EBuIEBuYEBuoEBu4EBvIEBvYEBvoEBv4EBwIEBwYEBwoEB
  3.2061 +w4EBxBBSEOsQahDGEEgRAX0RAYMRAW4QzxBLEMQRAWoRASoQiBBnEOgQUBDFEQEpEOMRAYUQThEBjxCC
  3.2062 +EQF1EOQQShEBexEBchDKEB0QUREBhxATEOAT//////////0Q8BCBEI4Q5xEBhBEBcRCWEHARAXMQzhEB
  3.2063 +JxEBdhCGEN8QyxEBfBEBiREBeRAFEJAQ1hAYEFwQOBAXEE8Q7BEBfhDNEJEQfxA5ENcRAYAQ4hB+EE0Q
  3.2064 +0xEBehDBENkQJxEBaxBXEQF4EQGREQFvEQGGEI8QlRBTEQF/EQFsEMcQ6REBdBEBbREBdxDDEDoQVhAl
  3.2065 +EH0Q1BDvEIMRAXAQfBEBKBEBkBEBihBJ0gAOAD4AaQbugBKg0gAOAD4C5wbxgQENoNIADgA+AucG9IEB
  3.2066 +DaDSADcAOAb2BveiBvcAO15OU0lCT2JqZWN0RGF0YQAIABkAIgAnADEAOgA/AEQAUgBUAGYD/AQCBE0E
  3.2067 +VARbBGkEewSXBKUEsQS9BMsE1gTkBQAFDgUhBTMFTQVXBWQFZgVpBWsFbgVxBXMFdgV4BXsFfgWBBYQF
  3.2068 +hgWIBYsFjgWRBZQFnQWpBasFrQW7BcQFzQXYBd0F7AX1BggGEQYcBh4GIQYjBlAGXQZqBoAGjgaYBqYG
  3.2069 +swbFBtkG5QbnBukG6wbtBu8G9Ab2BvgG+gb8Bv4HGQcnBzAHTQdfB2oHcwd/B4sHjQePB5EHlAeWB5gH
  3.2070 +mgejB6UHqAeqB8sH4wflB+cH6gfsB+4H8AfyB/MH/wgNCBYIHwgsCDMIPwhICE8IXghmCG8IdgiOCI8I
  3.2071 +mAidCLAIuQjACM0I0wjcCN4JKQkrCS0JLwkxCTMJNQk3CTkJOwk9CT8JQQlDCUUJRwlJCUsJTQlPCVEJ
  3.2072 +UwlVCVcJWQlbCV0JXwlhCWMJZQlnCWkJawltCW8JcQmCCZAJmQmhCaMJpQmnCakJzgnWCeoJ9QoDCg0K
  3.2073 +GgohCicKKQorCjAKMgo3CjkKOwo9CkoKVgpYCloKXApnCmkKdgqFCocKiQqLCpMKpQquCrMKxgrTCtUK
  3.2074 +1wrZCuwK9Qr6CwULGgsjCyoLQgtRC14LYAtiC2QLhQuHC4kLjguQC5ILlAuWC6cLrguwC7ILtAu2C8sL
  3.2075 +3QvqC+wL7gvwDBEMEwwVDBcMGQwbDB0MKgwsDC4MMAw/DE4MWwxdDF8MYQx+DIAMggyEDIYMiAyKDJcM
  3.2076 +mQybDJ0MrwzIDNUM1wzZDNsM/Az+DQANBQ0HDQkNCw0NDRoNHA0eDSANJQ0nDS0NPg1ADUINRA1GDU8N
  3.2077 +WA1fDXYNgw2FDYcNiQ2qDawNrg2wDbINtA22DboNvA3JDdYN2A3aDdwN/Q3/DgEOAw4FDgcOCQ4WDhgO
  3.2078 +Gw4eDkUOZw50DnYOeA56DpsOnQ6fDqEOow6lDqcOrg62DsMOxQ7HDskO6g7sDu4O8w71DvcO+Q77DwwP
  3.2079 +Dg8QDxIPFA8gDyIPOw9ID0oPTA9OD28PcQ9zD3UPdw95D3sPiA+KD5EPng+gD6IPpA/FD8cPyQ/LD80P
  3.2080 +zw/RD9wP3g/sD/0P/xABEAMQBRAqECwQLhAwEDIQNBA2EDgQOxA9EE4QUBBSEFQQVhB7EH0QfxCBEIMQ
  3.2081 +hRCHEIkQlRCXEKQQphCoEKoQyxDNEM8Q0RDTENUQ1xDcEOkQ+hD8EP4RABECESMRJREnESkRKxEtES8R
  3.2082 +RhFIEVURVxFZEVsRfBF+EYARghGEEYYRiBGZEZsRnhGhEaQRrxHHEdQR1hHYEdoR+xH9Ef8SARIDEgUS
  3.2083 +BxIQEhISKBI1EjcSORI7ElwSXhJgEmISZBJmEmgSbRJvEn0SihKMEo4SkBKxErMStRK3ErkSuxK9EsMS
  3.2084 +xRLMEtkS2xLdEt8TBBMOExATEhMUExYTGBMaExwTKhMsEzsTSBNKE0wTThNvE3ETcxN1E3cTeRN7E4kT
  3.2085 +lxOkE6YTqBOqE8sTzRPPE9ET0xPVE9cT4hPkE+8T/BP+FAAUAhQjFCUUJxQpFCsULRQvFDQUNhQ8FEkU
  3.2086 +SxRNFE8UcBRyFHQUdhR4FHoUfBSRFJcUqBSqFKwUrhSwFMgU1RTXFNkU2xT8FP4VABUCFQQVBhUIFQ4V
  3.2087 +EBUeFS8VMRUzFTUVNxVUFVYVWBVaFVwVXhVgFXYVlhWnFakVqxWtFa8V0BXSFdQV1hXYFdoV3BXoFeoV
  3.2088 +/RYOFhAWEhYUFhYWOxY9Fj8WQRZDFkUWRxZJFlIWVBZhFmMWZRZnFogWihaMFo4WkBaSFpQWmRabFqEW
  3.2089 +rhawFrIWtBbVFtcW2RbbFt0W3xbhFvYW+BcDFxAXEhcUFxYXNxc5FzsXPRc/F0EXQxdHF0kXThdbF10X
  3.2090 +XxdhF4IXhBeGF4gXiheMF44XmxedF7MXwBfCF8QXxhfnF+kX6xftF+8X8RfzF/wYFRgiGCQYJhgoGEkY
  3.2091 +SxhNGE8YURhTGFUYZhhoGHoYgxiGGRcZGRkbGR0ZHxkhGSMZJRknGSkZKxktGS8ZMRkzGTUZNxk5GTsZ
  3.2092 +PRk/GUEZQxlFGUcZSRlLGU0ZTxlRGVMZVRlXGVkZWxldGV8ZYRljGWUZZxlpGWwZbxlxGXMZdRl3GXkZ
  3.2093 +exl9GX8ZgRmDGYUZiBmKGYwZjhmQGZIZlBmWGZgZmhmcGZ4ZoRmjGaUZpxmpGbAZuRm7GcQZxhnIGcoZ
  3.2094 +zBn1GgMaEBoSGhQaFRoXGhgaGhocGh4aLRo2GjsaZBpuGncaeRp7Gn0afxqBGoMahRqHGpgamhqcGp8a
  3.2095 +oRqwGrkauxrSGtQa1hrYGtoa3BreGuAa4hrkGuYa6BsRGxMbFRsWGxgbGRsbGx0bHxtAG0IbRBtGG0gb
  3.2096 +ShtMG2UbZxuQG5IblBuVG5cbmBuaG5wbnhvHG8kbyxvNG88b0RvTG9Ub1xvgG/Eb8xv1G/cb+RwCHAQc
  3.2097 +BRwXHEAcQhxEHEUcRxxIHEocTBxOHHcceRx7HHwcfhx/HIEcgxyFHJIcnxyhHKMcpRyqHLMctRy2HN8c
  3.2098 +4RzjHOQc5hznHOkc6xztHPIc+xz9HRIdFB0WHRgdGh0cHR4dIB0iHSQdJh1PHVEdUx1UHVYdVx1ZHVsd
  3.2099 +XR2GHYgdih2LHY0djh2QHZIdlB29Hb8dwR3DHcUdxx3JHcsdzR3UHd0d3x3kHeYd6B4RHhMeFR4WHhge
  3.2100 +GR4bHh0eHx5IHkoeTB5OHlAeUh5UHlYeWB6BHoMehR6HHokeix6NHo8ekR66Hrwevh6/HsEewh7EHsYe
  3.2101 +yB7xHvMe9R73Hvke+x79Hv8fAR8GHw8fER8eHyAfIh8kHyYfKB8qHzQfPR8/H04fUB9SH1QfVh9ZH1wf
  3.2102 +Xh+HH4kfix+NH48fkR+TH5Uflx+cH6Ufpx++H8Afwh/EH8YfyB/KH8wfzh/QH9If1B/9H/8gASAEIAYg
  3.2103 +CCAKIAwgDyAbICQgJiApICsgRCBtIG8gcSB0IHYgeCB6IHwgfyCEII0gjyCYIJognSCfIKEgyiDMIM4g
  3.2104 +zyDRINIg1CDWINghASEDIQUhByEJIQshDSEPIRIhHiEnISkhKyE0ITkhQiFFIdYh2SHbId0h3yHhIeMh
  3.2105 +5SHnIekh6yHtIe8h8SHzIfUh9yH5Ifsh/SH/IgEiAyIFIgciCSILIg0iDyIRIhMiFSIXIhkiGyIdIh8i
  3.2106 +ISIjIiUiJyIpIisiLSIvIjEiMyI1IjciOSI7Ij0iPyJBIkMiRSJHIkkiSyJNIk8iUSJTIlUiVyJZIlwi
  3.2107 +XiJgImIiZCJmIm8iciMFIwcjCSMLIw0jDyMRIxMjFSMXIxkjGyMdIx8jISMjIyUjJyMpIysjLSMvIzEj
  3.2108 +MyM1IzcjOSM7Iz0jPyNBI0MjRSNHI0kjSyNNI08jUSNTI1UjVyNZI1wjXyNhI2MjZSNnI2kjayNtI28j
  3.2109 +cSN0I3YjeCN6I3wjfiOAI4IjhCOGI4gjiiOMI44jkSOTI5UjlyOZI6IjpSQ4JDskPiRBJEQkRyRJJEwk
  3.2110 +TyRSJFUkWCRbJF4kYSRkJGckaiRsJG8kciR1JHckeiR9JIAkgySFJIgkiySOJJEklCSXJJoknSSgJKMk
  3.2111 +piSpJKwkrySyJLUkuCS7JL4kwSTEJMckyiTNJNAk0yTWJNkk3CTfJOIk5SToJOsk7iTxJPQk9yT6JP0l
  3.2112 +ACUDJQYlCSUMJRolHCU4JUQlWyV0JZklmyWlJbwlyCXiJgUmESYoJjsmTiZoJqcmrCbJJuIm5Cb3JxIn
  3.2113 +JycpJzwnTidoJ3UneSeMJ6Enqie2J8InzifjJ+8oAigGKB8oMShIKFUoWChxKIMolii4KMQo5SkBKRYp
  3.2114 +JCk3KUMpWiluKX0plymjKa8puyncKeAp7Cn1Kfgp+SoCKgUqBioPKhIq7SrvKvEq8yr1Kvcq+Sr7Kv0q
  3.2115 +/ysBKwMrBSsHKwkrCysNKw8rESsTKxUrFysZKxsrHSsfKyErIyslKycrKSsrKy0rLysyKzQrNys5Kzsr
  3.2116 +PSs/K0ErQytFK0crSStLK04rUCtSK1QrVitYK1orXStfK2ErYytlK2craStrK20rbytxK3MrdSt3K3kr
  3.2117 +eyt9K38rgSuDK4UrhyuJK4srjSuPK5ErkyuVK5crmSubK50rnyuhK6MrpSunK6krqyutK68rsSuzK7Ur
  3.2118 +tyu5K7srvSu/K8ErwyvFK8crySvSK9UssCyzLLYsuSy8LL8swizFLMgsyyzOLNEs1CzXLNos3SzgLOMs
  3.2119 +5izpLOws7yzyLPUs+Cz7LP4tAS0ELQctCi0NLRAtEy0WLRktHC0fLSItJS0oLSstLi0xLTQtNy06LT0t
  3.2120 +QC1DLUYtSS1MLU8tUi1VLVgtWy1eLWEtZC1nLWotbS1wLXMtdi15LXwtfy2CLYUtiC2LLY4tkS2ULZct
  3.2121 +mi2dLaAtoy2mLaktrC2vLbIttS24Lbstvi3BLcQtxy3KLc0t0C3TLdYt2S3cLd8t4i3lLegt6y3uLfEt
  3.2122 +9C32Lfgt+i38Lf4uAS4ELgcuCS4LLg0uEC4TLhUuFy4ZLhsuHS4gLiIuJS4nLiouLC4vLjEuMy42Ljku
  3.2123 +Oy49Lj8uQi5ELkYuTy5RLlMuVS5XLlouXS5fLmEuZC5mLmkubC5uLnAuci51Lnguey59Ln8ugS6DLoUu
  3.2124 +hy6JLosujS6QLpIulC6WLpgumi6dLp8uoS6jLqUuqC6qLqwuri6xLrMuti65Lrwuvy7BLsMuxS7ILssu
  3.2125 +zS7PLtIu1S7YLtou3C7eLuAu4i7kLuYu6C7rLu0u8C7zLvYu+C8BLwMvBC8NLxAvES8aLx0vHi8nLywA
  3.2126 +AAAAAAACAgAAAAAAAAb4AAAAAAAAAAAAAAAAAAAvOw</bytes>
  3.2127 +		</object>
  3.2128 +	</data>
  3.2129 +</archive>
     4.1 Binary file English.lproj/MainMenu.nib/keyedobjects.nib has changed
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/GeekGameBoard.xcodeproj/project.pbxproj	Fri Mar 07 11:43:02 2008 -0800
     5.3 @@ -0,0 +1,460 @@
     5.4 +// !$*UTF8*$!
     5.5 +{
     5.6 +	archiveVersion = 1;
     5.7 +	classes = {
     5.8 +	};
     5.9 +	objectVersion = 44;
    5.10 +	objects = {
    5.11 +
    5.12 +/* Begin PBXBuildFile section */
    5.13 +		27224FA00CC29B1A00814095 /* Grid.m in Sources */ = {isa = PBXBuildFile; fileRef = 27224F9F0CC29B1A00814095 /* Grid.m */; };
    5.14 +		2722526F0CC2E86600814095 /* QuartzUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2722526E0CC2E86600814095 /* QuartzUtils.m */; };
    5.15 +		2727556A0CC3234F009C4C6C /* Dispenser.m in Sources */ = {isa = PBXBuildFile; fileRef = 272755690CC3234F009C4C6C /* Dispenser.m */; };
    5.16 +		27275A550CC6713E009C4C6C /* HexGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = 27275A540CC6713E009C4C6C /* HexGrid.m */; };
    5.17 +		27275C4B0CC700F2009C4C6C /* Game.m in Sources */ = {isa = PBXBuildFile; fileRef = 27275C4A0CC700F2009C4C6C /* Game.m */; };
    5.18 +		27275C920CC7C578009C4C6C /* TicTacToeGame.m in Sources */ = {isa = PBXBuildFile; fileRef = 27275C910CC7C578009C4C6C /* TicTacToeGame.m */; };
    5.19 +		272C90AB0CCACBA4009EE530 /* DiscPiece.m in Sources */ = {isa = PBXBuildFile; fileRef = 272C90AA0CCACBA4009EE530 /* DiscPiece.m */; };
    5.20 +		2731E0280CD430B800E6E4C8 /* Deck.m in Sources */ = {isa = PBXBuildFile; fileRef = 2731E0270CD430B800E6E4C8 /* Deck.m */; };
    5.21 +		2731E2A80CD5630600E6E4C8 /* BitHolder.m in Sources */ = {isa = PBXBuildFile; fileRef = 2731E2A70CD5630600E6E4C8 /* BitHolder.m */; };
    5.22 +		2734B2620CC7F25A0070C008 /* HexchequerGame.m in Sources */ = {isa = PBXBuildFile; fileRef = 2734B2610CC7F25A0070C008 /* HexchequerGame.m */; };
    5.23 +		2734B4F00CCA5BDB0070C008 /* CheckersGame.m in Sources */ = {isa = PBXBuildFile; fileRef = 2734B4EF0CCA5BDB0070C008 /* CheckersGame.m */; };
    5.24 +		274124060CFCCF9D00842A9B /* DemoBoardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 274124050CFCCF9D00842A9B /* DemoBoardView.m */; };
    5.25 +		276DFC410D00867000D329AE /* Green Ball.png in Resources */ = {isa = PBXBuildFile; fileRef = 276DFC400D00867000D329AE /* Green Ball.png */; };
    5.26 +		276DFC560D00890C00D329AE /* Red Ball.png in Resources */ = {isa = PBXBuildFile; fileRef = 276DFC530D00890C00D329AE /* Red Ball.png */; };
    5.27 +		276DFC570D00890C00D329AE /* Yellow Ball.png in Resources */ = {isa = PBXBuildFile; fileRef = 276DFC540D00890C00D329AE /* Yellow Ball.png */; };
    5.28 +		276DFC580D00890C00D329AE /* White Ball.png in Resources */ = {isa = PBXBuildFile; fileRef = 276DFC550D00890C00D329AE /* White Ball.png */; };
    5.29 +		2795C2B80CC278C800D7B2BD /* Piece.m in Sources */ = {isa = PBXBuildFile; fileRef = 2795C2B70CC278C800D7B2BD /* Piece.m */; };
    5.30 +		27B7543E0D08884F000516B9 /* Wood.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 27B7543D0D08884F000516B9 /* Wood.jpg */; };
    5.31 +		27C999C30D81185E005AFD4F /* GGBUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 27C999C20D81185E005AFD4F /* GGBUtils.m */; };
    5.32 +		27CCA8050CB8A3F9001CFE24 /* BoardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CCA8040CB8A3F9001CFE24 /* BoardView.m */; };
    5.33 +		27CCA95F0CB8A74D001CFE24 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27CCA95E0CB8A74D001CFE24 /* Quartz.framework */; };
    5.34 +		27CCAABD0CB92A9F001CFE24 /* Card.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CCAABC0CB92A9F001CFE24 /* Card.m */; };
    5.35 +		27CCABBF0CB9496B001CFE24 /* Bit.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CCABBE0CB9496B001CFE24 /* Bit.m */; };
    5.36 +		27CCAC750CB95C2B001CFE24 /* PlayingCard.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CCAC740CB95C2B001CFE24 /* PlayingCard.m */; };
    5.37 +		27D4F1260CCF011200923605 /* Stack.m in Sources */ = {isa = PBXBuildFile; fileRef = 27D4F1250CCF011200923605 /* Stack.m */; };
    5.38 +		27DFC4410CCD01B7005E34CE /* GoGame.m in Sources */ = {isa = PBXBuildFile; fileRef = 27DFC4400CCD01B7005E34CE /* GoGame.m */; };
    5.39 +		27F230B90CD1A61B006939C1 /* KlondikeGame.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F230B80CD1A61B006939C1 /* KlondikeGame.m */; };
    5.40 +		8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; };
    5.41 +		8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
    5.42 +		8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
    5.43 +		8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
    5.44 +/* End PBXBuildFile section */
    5.45 +
    5.46 +/* Begin PBXFileReference section */
    5.47 +		089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
    5.48 +		1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
    5.49 +		27224F9E0CC29B1A00814095 /* Grid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Grid.h; sourceTree = "<group>"; };
    5.50 +		27224F9F0CC29B1A00814095 /* Grid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Grid.m; sourceTree = "<group>"; };
    5.51 +		2722526D0CC2E86600814095 /* QuartzUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QuartzUtils.h; sourceTree = "<group>"; };
    5.52 +		2722526E0CC2E86600814095 /* QuartzUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QuartzUtils.m; sourceTree = "<group>"; };
    5.53 +		272755680CC3234F009C4C6C /* Dispenser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Dispenser.h; sourceTree = "<group>"; };
    5.54 +		272755690CC3234F009C4C6C /* Dispenser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Dispenser.m; sourceTree = "<group>"; };
    5.55 +		27275A530CC6713E009C4C6C /* HexGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HexGrid.h; sourceTree = "<group>"; };
    5.56 +		27275A540CC6713E009C4C6C /* HexGrid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HexGrid.m; sourceTree = "<group>"; };
    5.57 +		27275C490CC700F2009C4C6C /* Game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Game.h; sourceTree = "<group>"; };
    5.58 +		27275C4A0CC700F2009C4C6C /* Game.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Game.m; sourceTree = "<group>"; };
    5.59 +		27275C900CC7C578009C4C6C /* TicTacToeGame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TicTacToeGame.h; sourceTree = "<group>"; };
    5.60 +		27275C910CC7C578009C4C6C /* TicTacToeGame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TicTacToeGame.m; sourceTree = "<group>"; };
    5.61 +		272C90A90CCACBA4009EE530 /* DiscPiece.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscPiece.h; sourceTree = "<group>"; };
    5.62 +		272C90AA0CCACBA4009EE530 /* DiscPiece.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscPiece.m; sourceTree = "<group>"; };
    5.63 +		2731E0260CD430B800E6E4C8 /* Deck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Deck.h; sourceTree = "<group>"; };
    5.64 +		2731E0270CD430B800E6E4C8 /* Deck.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Deck.m; sourceTree = "<group>"; };
    5.65 +		2731E2A60CD5630600E6E4C8 /* BitHolder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitHolder.h; sourceTree = "<group>"; };
    5.66 +		2731E2A70CD5630600E6E4C8 /* BitHolder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BitHolder.m; sourceTree = "<group>"; };
    5.67 +		2734B2600CC7F25A0070C008 /* HexchequerGame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HexchequerGame.h; sourceTree = "<group>"; };
    5.68 +		2734B2610CC7F25A0070C008 /* HexchequerGame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HexchequerGame.m; sourceTree = "<group>"; };
    5.69 +		2734B4EE0CCA5BDB0070C008 /* CheckersGame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CheckersGame.h; sourceTree = "<group>"; };
    5.70 +		2734B4EF0CCA5BDB0070C008 /* CheckersGame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CheckersGame.m; sourceTree = "<group>"; };
    5.71 +		274124040CFCCF9D00842A9B /* DemoBoardView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoBoardView.h; sourceTree = "<group>"; };
    5.72 +		274124050CFCCF9D00842A9B /* DemoBoardView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoBoardView.m; sourceTree = "<group>"; };
    5.73 +		276DFC400D00867000D329AE /* Green Ball.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Green Ball.png"; path = "Resources/Green Ball.png"; sourceTree = "<group>"; };
    5.74 +		276DFC530D00890C00D329AE /* Red Ball.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Red Ball.png"; path = "Resources/Red Ball.png"; sourceTree = "<group>"; };
    5.75 +		276DFC540D00890C00D329AE /* Yellow Ball.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Yellow Ball.png"; path = "Resources/Yellow Ball.png"; sourceTree = "<group>"; };
    5.76 +		276DFC550D00890C00D329AE /* White Ball.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "White Ball.png"; path = "Resources/White Ball.png"; sourceTree = "<group>"; };
    5.77 +		2795C2B60CC278C800D7B2BD /* Piece.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Piece.h; sourceTree = "<group>"; };
    5.78 +		2795C2B70CC278C800D7B2BD /* Piece.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Piece.m; sourceTree = "<group>"; };
    5.79 +		27B7543D0D08884F000516B9 /* Wood.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = Wood.jpg; path = Resources/Wood.jpg; sourceTree = "<group>"; };
    5.80 +		27C999C10D81185E005AFD4F /* GGBUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GGBUtils.h; sourceTree = "<group>"; };
    5.81 +		27C999C20D81185E005AFD4F /* GGBUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GGBUtils.m; sourceTree = "<group>"; };
    5.82 +		27CCA8030CB8A3F9001CFE24 /* BoardView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BoardView.h; sourceTree = "<group>"; };
    5.83 +		27CCA8040CB8A3F9001CFE24 /* BoardView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BoardView.m; sourceTree = "<group>"; };
    5.84 +		27CCA95E0CB8A74D001CFE24 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = /System/Library/Frameworks/Quartz.framework; sourceTree = "<absolute>"; };
    5.85 +		27CCAABB0CB92A9F001CFE24 /* Card.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Card.h; sourceTree = "<group>"; };
    5.86 +		27CCAABC0CB92A9F001CFE24 /* Card.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Card.m; sourceTree = "<group>"; };
    5.87 +		27CCABBD0CB9496B001CFE24 /* Bit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bit.h; sourceTree = "<group>"; };
    5.88 +		27CCABBE0CB9496B001CFE24 /* Bit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Bit.m; sourceTree = "<group>"; };
    5.89 +		27CCAC730CB95C2B001CFE24 /* PlayingCard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayingCard.h; sourceTree = "<group>"; };
    5.90 +		27CCAC740CB95C2B001CFE24 /* PlayingCard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PlayingCard.m; sourceTree = "<group>"; };
    5.91 +		27D4F1240CCF011200923605 /* Stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Stack.h; sourceTree = "<group>"; };
    5.92 +		27D4F1250CCF011200923605 /* Stack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Stack.m; sourceTree = "<group>"; };
    5.93 +		27DFC43F0CCD01B7005E34CE /* GoGame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GoGame.h; sourceTree = "<group>"; };
    5.94 +		27DFC4400CCD01B7005E34CE /* GoGame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GoGame.m; sourceTree = "<group>"; };
    5.95 +		27F230B70CD1A61B006939C1 /* KlondikeGame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KlondikeGame.h; sourceTree = "<group>"; };
    5.96 +		27F230B80CD1A61B006939C1 /* KlondikeGame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KlondikeGame.m; sourceTree = "<group>"; };
    5.97 +		29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
    5.98 +		29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
    5.99 +		29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
   5.100 +		29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
   5.101 +		32CA4F630368D1EE00C91783 /* GeekGameBoard_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeekGameBoard_Prefix.pch; sourceTree = "<group>"; };
   5.102 +		8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Resources/Info.plist; sourceTree = "<group>"; };
   5.103 +		8D1107320486CEB800E47090 /* GeekGameBoard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GeekGameBoard.app; sourceTree = BUILT_PRODUCTS_DIR; };
   5.104 +/* End PBXFileReference section */
   5.105 +
   5.106 +/* Begin PBXFrameworksBuildPhase section */
   5.107 +		8D11072E0486CEB800E47090 /* Frameworks */ = {
   5.108 +			isa = PBXFrameworksBuildPhase;
   5.109 +			buildActionMask = 2147483647;
   5.110 +			files = (
   5.111 +				8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
   5.112 +				27CCA95F0CB8A74D001CFE24 /* Quartz.framework in Frameworks */,
   5.113 +			);
   5.114 +			runOnlyForDeploymentPostprocessing = 0;
   5.115 +		};
   5.116 +/* End PBXFrameworksBuildPhase section */
   5.117 +
   5.118 +/* Begin PBXGroup section */
   5.119 +		080E96DDFE201D6D7F000001 /* Source */ = {
   5.120 +			isa = PBXGroup;
   5.121 +			children = (
   5.122 +				27CCA8030CB8A3F9001CFE24 /* BoardView.h */,
   5.123 +				27CCA8040CB8A3F9001CFE24 /* BoardView.m */,
   5.124 +				27CCABBD0CB9496B001CFE24 /* Bit.h */,
   5.125 +				27CCABBE0CB9496B001CFE24 /* Bit.m */,
   5.126 +				2731E2A60CD5630600E6E4C8 /* BitHolder.h */,
   5.127 +				2731E2A70CD5630600E6E4C8 /* BitHolder.m */,
   5.128 +				27D4F1240CCF011200923605 /* Stack.h */,
   5.129 +				27D4F1250CCF011200923605 /* Stack.m */,
   5.130 +				27275C440CC70095009C4C6C /* Cards */,
   5.131 +				27275C450CC700C4009C4C6C /* Boards and Pieces */,
   5.132 +				27275C480CC700D8009C4C6C /* Games */,
   5.133 +				2722526D0CC2E86600814095 /* QuartzUtils.h */,
   5.134 +				2722526E0CC2E86600814095 /* QuartzUtils.m */,
   5.135 +				27C999C10D81185E005AFD4F /* GGBUtils.h */,
   5.136 +				27C999C20D81185E005AFD4F /* GGBUtils.m */,
   5.137 +			);
   5.138 +			path = Source;
   5.139 +			sourceTree = "<group>";
   5.140 +		};
   5.141 +		1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
   5.142 +			isa = PBXGroup;
   5.143 +			children = (
   5.144 +				1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
   5.145 +			);
   5.146 +			name = "Linked Frameworks";
   5.147 +			sourceTree = "<group>";
   5.148 +		};
   5.149 +		1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
   5.150 +			isa = PBXGroup;
   5.151 +			children = (
   5.152 +				29B97324FDCFA39411CA2CEA /* AppKit.framework */,
   5.153 +				27CCA95E0CB8A74D001CFE24 /* Quartz.framework */,
   5.154 +				29B97325FDCFA39411CA2CEA /* Foundation.framework */,
   5.155 +			);
   5.156 +			name = "Other Frameworks";
   5.157 +			sourceTree = "<group>";
   5.158 +		};
   5.159 +		19C28FACFE9D520D11CA2CBB /* Products */ = {
   5.160 +			isa = PBXGroup;
   5.161 +			children = (
   5.162 +				8D1107320486CEB800E47090 /* GeekGameBoard.app */,
   5.163 +			);
   5.164 +			name = Products;
   5.165 +			sourceTree = "<group>";
   5.166 +		};
   5.167 +		27275C440CC70095009C4C6C /* Cards */ = {
   5.168 +			isa = PBXGroup;
   5.169 +			children = (
   5.170 +				27CCAABB0CB92A9F001CFE24 /* Card.h */,
   5.171 +				27CCAABC0CB92A9F001CFE24 /* Card.m */,
   5.172 +				2731E0260CD430B800E6E4C8 /* Deck.h */,
   5.173 +				2731E0270CD430B800E6E4C8 /* Deck.m */,
   5.174 +				27CCAC730CB95C2B001CFE24 /* PlayingCard.h */,
   5.175 +				27CCAC740CB95C2B001CFE24 /* PlayingCard.m */,
   5.176 +			);
   5.177 +			name = Cards;
   5.178 +			sourceTree = "<group>";
   5.179 +		};
   5.180 +		27275C450CC700C4009C4C6C /* Boards and Pieces */ = {
   5.181 +			isa = PBXGroup;
   5.182 +			children = (
   5.183 +				2795C2B60CC278C800D7B2BD /* Piece.h */,
   5.184 +				2795C2B70CC278C800D7B2BD /* Piece.m */,
   5.185 +				272C90A90CCACBA4009EE530 /* DiscPiece.h */,
   5.186 +				272C90AA0CCACBA4009EE530 /* DiscPiece.m */,
   5.187 +				27224F9E0CC29B1A00814095 /* Grid.h */,
   5.188 +				27224F9F0CC29B1A00814095 /* Grid.m */,
   5.189 +				27275A530CC6713E009C4C6C /* HexGrid.h */,
   5.190 +				27275A540CC6713E009C4C6C /* HexGrid.m */,
   5.191 +				272755680CC3234F009C4C6C /* Dispenser.h */,
   5.192 +				272755690CC3234F009C4C6C /* Dispenser.m */,
   5.193 +			);
   5.194 +			name = "Boards and Pieces";
   5.195 +			sourceTree = "<group>";
   5.196 +		};
   5.197 +		27275C480CC700D8009C4C6C /* Games */ = {
   5.198 +			isa = PBXGroup;
   5.199 +			children = (
   5.200 +				27275C490CC700F2009C4C6C /* Game.h */,
   5.201 +				27275C4A0CC700F2009C4C6C /* Game.m */,
   5.202 +				27275C900CC7C578009C4C6C /* TicTacToeGame.h */,
   5.203 +				27275C910CC7C578009C4C6C /* TicTacToeGame.m */,
   5.204 +				2734B4EE0CCA5BDB0070C008 /* CheckersGame.h */,
   5.205 +				2734B4EF0CCA5BDB0070C008 /* CheckersGame.m */,
   5.206 +				2734B2600CC7F25A0070C008 /* HexchequerGame.h */,
   5.207 +				2734B2610CC7F25A0070C008 /* HexchequerGame.m */,
   5.208 +				27DFC43F0CCD01B7005E34CE /* GoGame.h */,
   5.209 +				27DFC4400CCD01B7005E34CE /* GoGame.m */,
   5.210 +				27F230B70CD1A61B006939C1 /* KlondikeGame.h */,
   5.211 +				27F230B80CD1A61B006939C1 /* KlondikeGame.m */,
   5.212 +			);
   5.213 +			name = Games;
   5.214 +			sourceTree = "<group>";
   5.215 +		};
   5.216 +		29B97314FDCFA39411CA2CEA /* BoardGame */ = {
   5.217 +			isa = PBXGroup;
   5.218 +			children = (
   5.219 +				080E96DDFE201D6D7F000001 /* Source */,
   5.220 +				29B97315FDCFA39411CA2CEA /* Demo Application */,
   5.221 +				29B97317FDCFA39411CA2CEA /* Resources */,
   5.222 +				29B97323FDCFA39411CA2CEA /* Frameworks */,
   5.223 +				19C28FACFE9D520D11CA2CBB /* Products */,
   5.224 +			);
   5.225 +			name = BoardGame;
   5.226 +			sourceTree = "<group>";
   5.227 +		};
   5.228 +		29B97315FDCFA39411CA2CEA /* Demo Application */ = {
   5.229 +			isa = PBXGroup;
   5.230 +			children = (
   5.231 +				274124040CFCCF9D00842A9B /* DemoBoardView.h */,
   5.232 +				274124050CFCCF9D00842A9B /* DemoBoardView.m */,
   5.233 +				32CA4F630368D1EE00C91783 /* GeekGameBoard_Prefix.pch */,
   5.234 +				29B97316FDCFA39411CA2CEA /* main.m */,
   5.235 +			);
   5.236 +			name = "Demo Application";
   5.237 +			path = Source;
   5.238 +			sourceTree = "<group>";
   5.239 +		};
   5.240 +		29B97317FDCFA39411CA2CEA /* Resources */ = {
   5.241 +			isa = PBXGroup;
   5.242 +			children = (
   5.243 +				29B97318FDCFA39411CA2CEA /* MainMenu.nib */,
   5.244 +				8D1107310486CEB800E47090 /* Info.plist */,
   5.245 +				089C165CFE840E0CC02AAC07 /* InfoPlist.strings */,
   5.246 +				276DFC400D00867000D329AE /* Green Ball.png */,
   5.247 +				276DFC530D00890C00D329AE /* Red Ball.png */,
   5.248 +				276DFC540D00890C00D329AE /* Yellow Ball.png */,
   5.249 +				276DFC550D00890C00D329AE /* White Ball.png */,
   5.250 +				27B7543D0D08884F000516B9 /* Wood.jpg */,
   5.251 +			);
   5.252 +			name = Resources;
   5.253 +			sourceTree = "<group>";
   5.254 +		};
   5.255 +		29B97323FDCFA39411CA2CEA /* Frameworks */ = {
   5.256 +			isa = PBXGroup;
   5.257 +			children = (
   5.258 +				1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
   5.259 +				1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
   5.260 +			);
   5.261 +			name = Frameworks;
   5.262 +			sourceTree = "<group>";
   5.263 +		};
   5.264 +/* End PBXGroup section */
   5.265 +
   5.266 +/* Begin PBXNativeTarget section */
   5.267 +		8D1107260486CEB800E47090 /* BoardGame */ = {
   5.268 +			isa = PBXNativeTarget;
   5.269 +			buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "BoardGame" */;
   5.270 +			buildPhases = (
   5.271 +				8D1107290486CEB800E47090 /* Resources */,
   5.272 +				8D11072C0486CEB800E47090 /* Sources */,
   5.273 +				8D11072E0486CEB800E47090 /* Frameworks */,
   5.274 +			);
   5.275 +			buildRules = (
   5.276 +			);
   5.277 +			dependencies = (
   5.278 +			);
   5.279 +			name = BoardGame;
   5.280 +			productInstallPath = "$(HOME)/Applications";
   5.281 +			productName = BoardGame;
   5.282 +			productReference = 8D1107320486CEB800E47090 /* GeekGameBoard.app */;
   5.283 +			productType = "com.apple.product-type.application";
   5.284 +		};
   5.285 +/* End PBXNativeTarget section */
   5.286 +
   5.287 +/* Begin PBXProject section */
   5.288 +		29B97313FDCFA39411CA2CEA /* Project object */ = {
   5.289 +			isa = PBXProject;
   5.290 +			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "GeekGameBoard" */;
   5.291 +			compatibilityVersion = "Xcode 3.0";
   5.292 +			hasScannedForEncodings = 1;
   5.293 +			mainGroup = 29B97314FDCFA39411CA2CEA /* BoardGame */;
   5.294 +			projectDirPath = "";
   5.295 +			projectRoot = "";
   5.296 +			targets = (
   5.297 +				8D1107260486CEB800E47090 /* BoardGame */,
   5.298 +			);
   5.299 +		};
   5.300 +/* End PBXProject section */
   5.301 +
   5.302 +/* Begin PBXResourcesBuildPhase section */
   5.303 +		8D1107290486CEB800E47090 /* Resources */ = {
   5.304 +			isa = PBXResourcesBuildPhase;
   5.305 +			buildActionMask = 2147483647;
   5.306 +			files = (
   5.307 +				8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */,
   5.308 +				8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */,
   5.309 +				276DFC410D00867000D329AE /* Green Ball.png in Resources */,
   5.310 +				276DFC560D00890C00D329AE /* Red Ball.png in Resources */,
   5.311 +				276DFC570D00890C00D329AE /* Yellow Ball.png in Resources */,
   5.312 +				276DFC580D00890C00D329AE /* White Ball.png in Resources */,
   5.313 +				27B7543E0D08884F000516B9 /* Wood.jpg in Resources */,
   5.314 +			);
   5.315 +			runOnlyForDeploymentPostprocessing = 0;
   5.316 +		};
   5.317 +/* End PBXResourcesBuildPhase section */
   5.318 +
   5.319 +/* Begin PBXSourcesBuildPhase section */
   5.320 +		8D11072C0486CEB800E47090 /* Sources */ = {
   5.321 +			isa = PBXSourcesBuildPhase;
   5.322 +			buildActionMask = 2147483647;
   5.323 +			files = (
   5.324 +				8D11072D0486CEB800E47090 /* main.m in Sources */,
   5.325 +				27CCA8050CB8A3F9001CFE24 /* BoardView.m in Sources */,
   5.326 +				27CCAABD0CB92A9F001CFE24 /* Card.m in Sources */,
   5.327 +				27CCABBF0CB9496B001CFE24 /* Bit.m in Sources */,
   5.328 +				27CCAC750CB95C2B001CFE24 /* PlayingCard.m in Sources */,
   5.329 +				2795C2B80CC278C800D7B2BD /* Piece.m in Sources */,
   5.330 +				27224FA00CC29B1A00814095 /* Grid.m in Sources */,
   5.331 +				2722526F0CC2E86600814095 /* QuartzUtils.m in Sources */,
   5.332 +				2727556A0CC3234F009C4C6C /* Dispenser.m in Sources */,
   5.333 +				27275A550CC6713E009C4C6C /* HexGrid.m in Sources */,
   5.334 +				27275C4B0CC700F2009C4C6C /* Game.m in Sources */,
   5.335 +				27275C920CC7C578009C4C6C /* TicTacToeGame.m in Sources */,
   5.336 +				2734B2620CC7F25A0070C008 /* HexchequerGame.m in Sources */,
   5.337 +				2734B4F00CCA5BDB0070C008 /* CheckersGame.m in Sources */,
   5.338 +				272C90AB0CCACBA4009EE530 /* DiscPiece.m in Sources */,
   5.339 +				27DFC4410CCD01B7005E34CE /* GoGame.m in Sources */,
   5.340 +				27D4F1260CCF011200923605 /* Stack.m in Sources */,
   5.341 +				27F230B90CD1A61B006939C1 /* KlondikeGame.m in Sources */,
   5.342 +				2731E0280CD430B800E6E4C8 /* Deck.m in Sources */,
   5.343 +				2731E2A80CD5630600E6E4C8 /* BitHolder.m in Sources */,
   5.344 +				274124060CFCCF9D00842A9B /* DemoBoardView.m in Sources */,
   5.345 +				27C999C30D81185E005AFD4F /* GGBUtils.m in Sources */,
   5.346 +			);
   5.347 +			runOnlyForDeploymentPostprocessing = 0;
   5.348 +		};
   5.349 +/* End PBXSourcesBuildPhase section */
   5.350 +
   5.351 +/* Begin PBXVariantGroup section */
   5.352 +		089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = {
   5.353 +			isa = PBXVariantGroup;
   5.354 +			children = (
   5.355 +				089C165DFE840E0CC02AAC07 /* English */,
   5.356 +			);
   5.357 +			name = InfoPlist.strings;
   5.358 +			sourceTree = "<group>";
   5.359 +		};
   5.360 +		29B97318FDCFA39411CA2CEA /* MainMenu.nib */ = {
   5.361 +			isa = PBXVariantGroup;
   5.362 +			children = (
   5.363 +				29B97319FDCFA39411CA2CEA /* English */,
   5.364 +			);
   5.365 +			name = MainMenu.nib;
   5.366 +			sourceTree = "<group>";
   5.367 +		};
   5.368 +/* End PBXVariantGroup section */
   5.369 +
   5.370 +/* Begin XCBuildConfiguration section */
   5.371 +		C01FCF4B08A954540054247B /* Debug */ = {
   5.372 +			isa = XCBuildConfiguration;
   5.373 +			buildSettings = {
   5.374 +				COPY_PHASE_STRIP = NO;
   5.375 +				GCC_DYNAMIC_NO_PIC = NO;
   5.376 +				GCC_ENABLE_FIX_AND_CONTINUE = YES;
   5.377 +				GCC_MODEL_TUNING = G5;
   5.378 +				GCC_OPTIMIZATION_LEVEL = 0;
   5.379 +				GCC_PRECOMPILE_PREFIX_HEADER = YES;
   5.380 +				GCC_PREFIX_HEADER = Source/GeekGameBoard_Prefix.pch;
   5.381 +				INFOPLIST_FILE = Resources/Info.plist;
   5.382 +				INSTALL_PATH = "$(HOME)/Applications";
   5.383 +				PRODUCT_NAME = GeekGameBoard;
   5.384 +				WRAPPER_EXTENSION = app;
   5.385 +				ZERO_LINK = YES;
   5.386 +			};
   5.387 +			name = Debug;
   5.388 +		};
   5.389 +		C01FCF4C08A954540054247B /* Release */ = {
   5.390 +			isa = XCBuildConfiguration;
   5.391 +			buildSettings = {
   5.392 +				ARCHS = (
   5.393 +					i386,
   5.394 +					ppc,
   5.395 +					ppc64,
   5.396 +					x86_64,
   5.397 +				);
   5.398 +				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
   5.399 +				GCC_MODEL_TUNING = G5;
   5.400 +				GCC_PRECOMPILE_PREFIX_HEADER = YES;
   5.401 +				GCC_PREFIX_HEADER = Source/GeekGameBoard_Prefix.pch;
   5.402 +				INFOPLIST_FILE = Resources/Info.plist;
   5.403 +				INSTALL_PATH = "$(HOME)/Applications";
   5.404 +				PRODUCT_NAME = GeekGameBoard;
   5.405 +				WRAPPER_EXTENSION = app;
   5.406 +			};
   5.407 +			name = Release;
   5.408 +		};
   5.409 +		C01FCF4F08A954540054247B /* Debug */ = {
   5.410 +			isa = XCBuildConfiguration;
   5.411 +			buildSettings = {
   5.412 +				GCC_C_LANGUAGE_STANDARD = gnu99;
   5.413 +				GCC_ENABLE_OBJC_GC = unsupported;
   5.414 +				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
   5.415 +				GCC_WARN_ABOUT_RETURN_TYPE = YES;
   5.416 +				GCC_WARN_UNUSED_VARIABLE = YES;
   5.417 +				PREBINDING = NO;
   5.418 +				WARNING_CFLAGS = "-Wall";
   5.419 +			};
   5.420 +			name = Debug;
   5.421 +		};
   5.422 +		C01FCF5008A954540054247B /* Release */ = {
   5.423 +			isa = XCBuildConfiguration;
   5.424 +			buildSettings = {
   5.425 +				ARCHS = (
   5.426 +					ppc,
   5.427 +					i386,
   5.428 +				);
   5.429 +				GCC_C_LANGUAGE_STANDARD = gnu99;
   5.430 +				GCC_ENABLE_OBJC_GC = unsupported;
   5.431 +				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
   5.432 +				GCC_WARN_ABOUT_RETURN_TYPE = YES;
   5.433 +				GCC_WARN_UNUSED_VARIABLE = YES;
   5.434 +				PREBINDING = NO;
   5.435 +				WARNING_CFLAGS = "-Wall";
   5.436 +			};
   5.437 +			name = Release;
   5.438 +		};
   5.439 +/* End XCBuildConfiguration section */
   5.440 +
   5.441 +/* Begin XCConfigurationList section */
   5.442 +		C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "BoardGame" */ = {
   5.443 +			isa = XCConfigurationList;
   5.444 +			buildConfigurations = (
   5.445 +				C01FCF4B08A954540054247B /* Debug */,
   5.446 +				C01FCF4C08A954540054247B /* Release */,
   5.447 +			);
   5.448 +			defaultConfigurationIsVisible = 0;
   5.449 +			defaultConfigurationName = Release;
   5.450 +		};
   5.451 +		C01FCF4E08A954540054247B /* Build configuration list for PBXProject "GeekGameBoard" */ = {
   5.452 +			isa = XCConfigurationList;
   5.453 +			buildConfigurations = (
   5.454 +				C01FCF4F08A954540054247B /* Debug */,
   5.455 +				C01FCF5008A954540054247B /* Release */,
   5.456 +			);
   5.457 +			defaultConfigurationIsVisible = 0;
   5.458 +			defaultConfigurationName = Release;
   5.459 +		};
   5.460 +/* End XCConfigurationList section */
   5.461 +	};
   5.462 +	rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
   5.463 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/Read Me.rtf	Fri Mar 07 11:43:02 2008 -0800
     6.3 @@ -0,0 +1,139 @@
     6.4 +{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf270
     6.5 +{\fonttbl\f0\fnil\fcharset0 Verdana;}
     6.6 +{\colortbl;\red255\green255\blue255;}
     6.7 +\margl1440\margr1440\vieww13900\viewh17120\viewkind0
     6.8 +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
     6.9 +
    6.10 +\f0\b\fs38 \cf0 GeekGameBoard
    6.11 +\b0\fs22 \
    6.12 +\
    6.13 +
    6.14 +\b by Jens Alfke
    6.15 +\b0 \
    6.16 +\
    6.17 +GeekGameBoard is an example of using Core Animation to present the user interface of a board or card game. It implements a small framework for implementing such games, with domain-specific classes like "Grid" and "Piece", and examples of several game definitions built on top of the framework.\
    6.18 +\
    6.19 +Some of the generally-useful Core Animation techniques illustrated are:\
    6.20 +\'95 Hit testing\
    6.21 +\'95 Dragging CALayers with the mouse\
    6.22 +\'95 Loading images from files and setting them as layer contents\
    6.23 +\'95 3D "card-flip" animations\
    6.24 +\
    6.25 +
    6.26 +\b\fs28 History
    6.27 +\b0 \
    6.28 +
    6.29 +\fs22 \
    6.30 +I wrote GeekGameBoard in 2007 while at Apple, which published it as sample code. Apple's sample code license allows unrestricted use of the source code, requiring only that you keep their copyright notice in an 
    6.31 +\i unmodified
    6.32 +\i0  distribution.\
    6.33 +\
    6.34 +I am no longer employed by Apple. To encourage further development of this framework, in March 2008 I created this open source project (under a BSD license) based on a slightly-evolved version of the published sample code.\
    6.35 +\
    6.36 +1.0: Original Apple sample code release (12/19/2007)\
    6.37 +2.0: First open source release. (Major version number bumped to avoid conflict with any future Apple revisions.) No longer requires garbage collection. Fixed some memory leaks of CG objects. Fixed a bug when advancing to the 8th row in the Checkers game. (3/7/2008)\
    6.38 +\
    6.39 +
    6.40 +\b\fs28 Project Description\
    6.41 +
    6.42 +\b0\fs22 \
    6.43 +
    6.44 +\b Important Classes
    6.45 +\b0 \
    6.46 +\
    6.47 +A 
    6.48 +\b Bit
    6.49 +\b0  is a moveable object in a game, either a 
    6.50 +\b Card
    6.51 +\b0  or a 
    6.52 +\b Piece
    6.53 +\b0 .\
    6.54 +A 
    6.55 +\b BitHolder
    6.56 +\b0  is a container for Bits; they can be dragged into and/or out of it. Typical BitHolders are 
    6.57 +\b GridCell
    6.58 +\b0 s (the squares/hexes in a board), 
    6.59 +\b Deck
    6.60 +\b0 s or 
    6.61 +\b Stack
    6.62 +\b0 s of cards, and 
    6.63 +\b Dispensers
    6.64 +\b0  (supplies of new pieces.)\
    6.65 +A 
    6.66 +\b Grid
    6.67 +\b0  is a regular arrangement of 
    6.68 +\b GridCell
    6.69 +\b0 s; rectangular and hex grids are implemented.\
    6.70 +
    6.71 +\b BoardView
    6.72 +\b0  is the NSView whose layer hosts all of the above. It also tracks mouse events so the user can drag Bits.\
    6.73 +
    6.74 +\b Game
    6.75 +\b0  represents the rules of a particular game. It sets up the pieces/cards/grids that make up the game, decides which moves are legal, keeps track of whose turn it is, and decides when someone's won.\
    6.76 +
    6.77 +\b Player
    6.78 +\b0  is a passive object that represents one of the players in a Game.\
    6.79 +\
    6.80 +
    6.81 +\b Class Hierarchy
    6.82 +\b0 \
    6.83 +\
    6.84 +(Underlined classes are from external frameworks; italic classes are abstract.)\
    6.85 +\
    6.86 +\ul CALayer\ulnone \
    6.87 +	
    6.88 +\i Bit
    6.89 +\i0 \
    6.90 +		Card\
    6.91 +			PlayingCard\
    6.92 +		DraggedStack\
    6.93 +		Piece\
    6.94 +			DiscPiece\
    6.95 +	
    6.96 +\i BitHolder*
    6.97 +\i0 \
    6.98 +		
    6.99 +\i GridCell
   6.100 +\i0 \
   6.101 +			Hex\
   6.102 +			Square\
   6.103 +				GoSquare\
   6.104 +		Deck\
   6.105 +		Dispenser\
   6.106 +		Stack\
   6.107 +	
   6.108 +\i Grid
   6.109 +\i0 \
   6.110 +		HexGrid\
   6.111 +		RectGrid\
   6.112 +\
   6.113 +\ul NSView\ulnone \
   6.114 +	BoardView\
   6.115 +\
   6.116 +
   6.117 +\i \ul NSObject
   6.118 +\i0 \ulnone \
   6.119 +	
   6.120 +\i Game
   6.121 +\i0 \
   6.122 +		TicTacToeGame (etc...)\
   6.123 +	Player\
   6.124 +\
   6.125 +
   6.126 +\fs20 * BitHolder is actually both a protocol, and a class that implements the protocol. I've combined them here, for simplicity.\
   6.127 +
   6.128 +\fs22 \
   6.129 +\
   6.130 +
   6.131 +\b\fs28 Related Information\
   6.132 +
   6.133 +\b0\fs22 \
   6.134 +\'95 {\field{\*\fldinst{HYPERLINK "http://developer.apple.com/samplecode/GeekGameBoard/"}}{\fldrslt Apple's original GeekGameBoard sample code}}\
   6.135 +\'95 {\field{\*\fldinst{HYPERLINK "http://developer.apple.com/documentation/Cocoa/Conceptual/CoreAnimation_guide/index.html"}}{\fldrslt 
   6.136 +\i Core Animation Programming Guide}}\
   6.137 +
   6.138 +\i \'95 {\field{\*\fldinst{HYPERLINK "http://developer.apple.com/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_images/chapter_12_section_4.html"}}{\fldrslt Quartz 2D Programming Guide: Creating Images}}\
   6.139 +\'95 {\field{\*\fldinst{HYPERLINK "http://developer.apple.com/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_patterns/chapter_7_section_1.html"}}{\fldrslt Quartz 2D Programming Guide: Patterns}}\
   6.140 +\'95 {\field{\*\fldinst{HYPERLINK "http://developer.apple.com/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_paths/chapter_4_section_1.html"}}{\fldrslt Quartz 2D Programming Guide: Paths}}
   6.141 +\i0 \
   6.142 +}
   6.143 \ No newline at end of file
     7.1 Binary file Resources/Green Ball.png has changed
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/Resources/Info.plist	Fri Mar 07 11:43:02 2008 -0800
     8.3 @@ -0,0 +1,26 @@
     8.4 +<?xml version="1.0" encoding="UTF-8"?>
     8.5 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
     8.6 +<plist version="1.0">
     8.7 +<dict>
     8.8 +	<key>CFBundleDevelopmentRegion</key>
     8.9 +	<string>English</string>
    8.10 +	<key>CFBundleExecutable</key>
    8.11 +	<string>${EXECUTABLE_NAME}</string>
    8.12 +	<key>CFBundleIdentifier</key>
    8.13 +	<string>com.apple.sample.GeekGameBoard</string>
    8.14 +	<key>CFBundleInfoDictionaryVersion</key>
    8.15 +	<string>6.0</string>
    8.16 +	<key>CFBundleName</key>
    8.17 +	<string>${PRODUCT_NAME}</string>
    8.18 +	<key>CFBundlePackageType</key>
    8.19 +	<string>APPL</string>
    8.20 +	<key>CFBundleSignature</key>
    8.21 +	<string>????</string>
    8.22 +	<key>CFBundleVersion</key>
    8.23 +	<string>1.0</string>
    8.24 +	<key>NSMainNibFile</key>
    8.25 +	<string>MainMenu</string>
    8.26 +	<key>NSPrincipalClass</key>
    8.27 +	<string>NSApplication</string>
    8.28 +</dict>
    8.29 +</plist>
     9.1 Binary file Resources/Red Ball.png has changed
    10.1 Binary file Resources/White Ball.png has changed
    11.1 Binary file Resources/Wood.jpg has changed
    12.1 Binary file Resources/Yellow Ball.png has changed
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/Source/Bit.h	Fri Mar 07 11:43:02 2008 -0800
    13.3 @@ -0,0 +1,69 @@
    13.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    13.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    13.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    13.7 +
    13.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    13.9 +    provided that the following conditions are met:
   13.10 +
   13.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   13.12 +      and the following disclaimer.
   13.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   13.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   13.15 +      with the distribution.
   13.16 +
   13.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   13.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   13.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   13.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   13.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   13.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   13.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   13.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   13.25 +*/
   13.26 +#import <Quartz/Quartz.h>
   13.27 +
   13.28 +
   13.29 +@class Game, Player;
   13.30 +@protocol BitHolder;
   13.31 +
   13.32 +
   13.33 +/** Standard Z positions */
   13.34 +enum {
   13.35 +    kBoardZ = 1,
   13.36 +    kCardZ  = 2,
   13.37 +    kPieceZ = 3,
   13.38 +    
   13.39 +    kPickedUpZ = 100
   13.40 +};
   13.41 +
   13.42 +
   13.43 +/** A moveable item in a card/board game.
   13.44 +    Abstract superclass of Card and Piece. */
   13.45 +@interface Bit : CALayer <NSCopying>
   13.46 +{
   13.47 +    @private
   13.48 +    int _restingZ;      // Original z position, saved while pickedUp
   13.49 +    Player *_owner;     // Player that owns this Bit
   13.50 +}
   13.51 +
   13.52 +/** Conveniences for getting/setting the layer's scale and rotation */
   13.53 +@property CGFloat scale;
   13.54 +@property int rotation;         // in degrees! Positive = clockwise
   13.55 +
   13.56 +/** "Picking up" a Bit makes it larger, translucent, and in front of everything else */
   13.57 +@property BOOL pickedUp;
   13.58 +
   13.59 +/** Current holder (or nil) */
   13.60 +@property (readonly) id<BitHolder> holder;
   13.61 +
   13.62 +/** Ownership of this Bit */
   13.63 +@property (assign) Player *owner;
   13.64 +
   13.65 +/** Conveniences for owner.friendly, owner.unfriendly */
   13.66 +@property (readonly, getter=isFriendly)   BOOL friendly;
   13.67 +@property (readonly, getter=isUnfriendly) BOOL unfriendly;
   13.68 +
   13.69 +/** Removes this Bit while running a explosion/fade-out animation */
   13.70 +- (void) destroy;
   13.71 +
   13.72 +@end
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/Source/Bit.m	Fri Mar 07 11:43:02 2008 -0800
    14.3 @@ -0,0 +1,172 @@
    14.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    14.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    14.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    14.7 +
    14.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    14.9 +    provided that the following conditions are met:
   14.10 +
   14.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   14.12 +      and the following disclaimer.
   14.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   14.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   14.15 +      with the distribution.
   14.16 +
   14.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   14.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   14.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   14.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   14.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   14.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   14.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   14.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   14.25 +*/
   14.26 +#import "Bit.h"
   14.27 +#import "Game.h"
   14.28 +#import "QuartzUtils.h"
   14.29 +
   14.30 +
   14.31 +@implementation Bit
   14.32 +
   14.33 +
   14.34 +- (id) copyWithZone: (NSZone*)zone
   14.35 +{
   14.36 +    // NSLayer isn't copyable, but it is archivable. So create a copy by archiving to
   14.37 +    // a temporary data block, then unarchiving a new layer from that block.
   14.38 +    
   14.39 +    // One complication is that, due to a bug in Core Animation, CALayer can't archive
   14.40 +    // a pattern-based CGColor. So as a workaround, clear the background before archiving,
   14.41 +    // then restore it afterwards.
   14.42 +    
   14.43 +    // Also, archiving a CALayer with an image in it leaks memory. (Filed as rdar://5786865 )
   14.44 +    // As a workaround, clear the contents before archiving, then restore.
   14.45 +    
   14.46 +    CGColorRef bg = CGColorRetain(self.backgroundColor);
   14.47 +    self.backgroundColor = NULL;
   14.48 +    id contents = [self.contents retain];
   14.49 +    self.contents = nil;
   14.50 +    
   14.51 +    NSData *data = [NSKeyedArchiver archivedDataWithRootObject: self];
   14.52 +    
   14.53 +    self.backgroundColor = bg;
   14.54 +    self.contents = contents;
   14.55 +
   14.56 +    Bit *clone = [NSKeyedUnarchiver unarchiveObjectWithData: data];
   14.57 +    clone.backgroundColor = bg;
   14.58 +    clone.contents = contents;
   14.59 +    CGColorRelease(bg);
   14.60 +    [contents release];
   14.61 +
   14.62 +    clone->_owner = _owner;             // _owner is not archived
   14.63 +    return [clone retain];
   14.64 +}
   14.65 +
   14.66 +
   14.67 +- (NSString*) description
   14.68 +{
   14.69 +    return [NSString stringWithFormat: @"%@[(%g,%g)]", self.class,self.position.x,self.position.y];
   14.70 +}
   14.71 +
   14.72 +
   14.73 +@synthesize owner=_owner;
   14.74 +
   14.75 +- (BOOL) isFriendly         {return _owner.friendly;}
   14.76 +- (BOOL) isUnfriendly       {return _owner.unfriendly;}
   14.77 +
   14.78 +
   14.79 +- (CGFloat) scale
   14.80 +{
   14.81 +    NSNumber *scale = [self valueForKeyPath: @"transform.scale"];
   14.82 +    return scale.floatValue;
   14.83 +}
   14.84 +
   14.85 +- (void) setScale: (CGFloat)scale
   14.86 +{
   14.87 +    [self setValue: [NSNumber numberWithFloat: scale]
   14.88 +        forKeyPath: @"transform.scale"];
   14.89 +}
   14.90 +
   14.91 +
   14.92 +- (int) rotation
   14.93 +{
   14.94 +    NSNumber *rot = [self valueForKeyPath: @"transform.rotation"];
   14.95 +    return round( rot.doubleValue * 180.0 / M_PI );
   14.96 +}
   14.97 +
   14.98 +- (void) setRotation: (int)rotation
   14.99 +{
  14.100 +    [self setValue: [NSNumber numberWithDouble: rotation*M_PI/180.0]
  14.101 +        forKeyPath: @"transform.rotation"];
  14.102 +}
  14.103 +
  14.104 +
  14.105 +- (BOOL) pickedUp
  14.106 +{
  14.107 +    return self.zPosition >= kPickedUpZ;
  14.108 +}
  14.109 +
  14.110 +- (void) setPickedUp: (BOOL)up
  14.111 +{
  14.112 +    if( up != self.pickedUp ) {
  14.113 +        CGFloat shadow, offset, radius, opacity, z, scale;
  14.114 +        if( up ) {
  14.115 +            shadow = 0.8;
  14.116 +            offset = 2;
  14.117 +            radius = 8;
  14.118 +            opacity = 0.9;
  14.119 +            scale = 1.2;
  14.120 +            z = kPickedUpZ;
  14.121 +            _restingZ = self.zPosition;
  14.122 +        } else {
  14.123 +            shadow = offset = radius = 0.0;
  14.124 +            opacity = 1.0;
  14.125 +            scale = 1.0/1.2;
  14.126 +            z = _restingZ;
  14.127 +        }
  14.128 +        
  14.129 +        self.zPosition = z;
  14.130 +        self.shadowOpacity = shadow;
  14.131 +        self.shadowOffset = CGSizeMake(offset,-offset);
  14.132 +        self.shadowRadius = radius;
  14.133 +        self.opacity = opacity;
  14.134 +        self.scale *= scale;
  14.135 +    }
  14.136 +}
  14.137 +
  14.138 +
  14.139 +- (BOOL)containsPoint:(CGPoint)p
  14.140 +{
  14.141 +    // Make picked-up pieces invisible to hit-testing.
  14.142 +    // Otherwise, while dragging a Bit, hit-testing the cursor position would always return
  14.143 +    // that Bit, since it's directly under the cursor...
  14.144 +    if( self.pickedUp )
  14.145 +        return NO;
  14.146 +    else
  14.147 +        return [super containsPoint: p];
  14.148 +}
  14.149 +
  14.150 +
  14.151 +-(id<BitHolder>) holder
  14.152 +{
  14.153 +    // Look for my nearest ancestor that's a BitHolder:
  14.154 +    for( CALayer *layer=self.superlayer; layer; layer=layer.superlayer ) {
  14.155 +        if( [layer conformsToProtocol: @protocol(BitHolder)] )
  14.156 +            return (id<BitHolder>)layer;
  14.157 +        else if( [layer isKindOfClass: [Bit class]] )
  14.158 +            return nil;
  14.159 +    }
  14.160 +    return nil;
  14.161 +}
  14.162 +
  14.163 +
  14.164 +- (void) destroy
  14.165 +{
  14.166 +    // "Pop" the Bit by expanding it 5x as it fades away:
  14.167 +    self.scale = 5;
  14.168 +    self.opacity = 0.0;
  14.169 +    // Removing the view from its superlayer right now would cancel the animations.
  14.170 +    // Instead, defer the removal until sometime shortly after the animations finish:
  14.171 +    [self performSelector: @selector(removeFromSuperlayer) withObject: nil afterDelay: 1.0];
  14.172 +}
  14.173 +
  14.174 +
  14.175 +@end
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/Source/BitHolder.h	Fri Mar 07 11:43:02 2008 -0800
    15.3 @@ -0,0 +1,73 @@
    15.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    15.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    15.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    15.7 +
    15.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    15.9 +    provided that the following conditions are met:
   15.10 +
   15.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   15.12 +      and the following disclaimer.
   15.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   15.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   15.15 +      with the distribution.
   15.16 +
   15.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   15.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   15.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   15.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   15.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   15.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   15.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   15.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   15.25 +*/
   15.26 +#import <Quartz/Quartz.h>
   15.27 +@class Bit;
   15.28 +
   15.29 +
   15.30 +/** Protocol for a layer that acts as a container for Bits. */
   15.31 +@protocol BitHolder <NSObject>
   15.32 +
   15.33 +/** Current Bit, or nil if empty */
   15.34 +@property (retain) Bit* bit;
   15.35 +
   15.36 +/** Conveniences for comparing self.bit with nil */
   15.37 +@property (readonly, getter=isEmpty) BOOL empty;
   15.38 +
   15.39 +/** BitHolders will be highlighted while the target of a drag operation */
   15.40 +@property BOOL highlighted;
   15.41 +
   15.42 +
   15.43 +/** Tests whether the bit is allowed to be dragged out of me.
   15.44 +    Returns the input bit, or possibly a different Bit to drag instead, or nil if not allowed.
   15.45 +    Either -cancelDragBit: or -draggedBit:to: must be called next. */
   15.46 +- (Bit*) canDragBit: (Bit*)bit;
   15.47 +
   15.48 +/** Cancels a pending drag (begun by -canDragBit:). */
   15.49 +- (void) cancelDragBit: (Bit*)bit;
   15.50 +
   15.51 +/** Called after a drag finishes. */
   15.52 +- (void) draggedBit: (Bit*)bit to: (id<BitHolder>)dst;
   15.53 +
   15.54 +
   15.55 +/** Tests whether the bit is allowed to be dropped into me.
   15.56 +    Either -willNotDropBit: or -dropBit:atPoint: must be called next. */
   15.57 +- (BOOL) canDropBit: (Bit*)bit atPoint: (CGPoint)point;
   15.58 +
   15.59 +/** Cancels a pending drop (after -canDropBit:atPoint: was already called.) */
   15.60 +- (void) willNotDropBit: (Bit*)bit;
   15.61 +
   15.62 +/** Finishes a drop. */
   15.63 +- (BOOL) dropBit: (Bit*)bit atPoint: (CGPoint)point;
   15.64 +
   15.65 +@end
   15.66 +
   15.67 +
   15.68 +/** A basic implementation of the BitHolder protocol. */
   15.69 +@interface BitHolder : CALayer <BitHolder>
   15.70 +{
   15.71 +    @protected
   15.72 +    Bit *_bit;
   15.73 +    BOOL _highlighted;
   15.74 +}
   15.75 +
   15.76 +@end
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/Source/BitHolder.m	Fri Mar 07 11:43:02 2008 -0800
    16.3 @@ -0,0 +1,80 @@
    16.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    16.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    16.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    16.7 +
    16.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    16.9 +    provided that the following conditions are met:
   16.10 +
   16.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   16.12 +      and the following disclaimer.
   16.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   16.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   16.15 +      with the distribution.
   16.16 +
   16.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   16.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   16.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   16.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   16.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   16.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   16.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   16.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   16.25 +*/
   16.26 +#import "BitHolder.h"
   16.27 +#import "Bit.h"
   16.28 +#import "QuartzUtils.h"
   16.29 +#import "GGBUtils.h"
   16.30 +
   16.31 +
   16.32 +@implementation BitHolder
   16.33 +
   16.34 +
   16.35 +- (void) dealloc
   16.36 +{
   16.37 +    [_bit release];
   16.38 +    [super dealloc];
   16.39 +}
   16.40 +
   16.41 +
   16.42 +- (Bit*) bit
   16.43 +{
   16.44 +    if( _bit && _bit.superlayer != self && !_bit.pickedUp )
   16.45 +        setObj(&_bit,nil);
   16.46 +    return _bit;
   16.47 +}
   16.48 +
   16.49 +- (void) setBit: (Bit*)bit
   16.50 +{
   16.51 +    if( bit != self.bit ) {
   16.52 +        if( bit && _bit )
   16.53 +            [_bit destroy];
   16.54 +        setObj(&_bit,bit);
   16.55 +        ChangeSuperlayer(bit,self,-1);
   16.56 +    }
   16.57 +}
   16.58 +
   16.59 +- (BOOL) isEmpty    {return self.bit==nil;}
   16.60 +
   16.61 +@synthesize highlighted=_highlighted;
   16.62 +
   16.63 +- (Bit*) canDragBit: (Bit*)bit
   16.64 +{
   16.65 +    if( bit.superlayer == self && ! bit.unfriendly )
   16.66 +        return bit;
   16.67 +    else
   16.68 +        return nil;
   16.69 +}
   16.70 +
   16.71 +- (void) cancelDragBit: (Bit*)bit                       { }
   16.72 +- (void) draggedBit: (Bit*)bit to: (id<BitHolder>)dst   {self.bit = nil;}
   16.73 +
   16.74 +- (BOOL) canDropBit: (Bit*)bit atPoint: (CGPoint)point  {return YES;}
   16.75 +- (void) willNotDropBit: (Bit*)bit                      { }
   16.76 +
   16.77 +- (BOOL) dropBit: (Bit*)bit atPoint: (CGPoint)point
   16.78 +{
   16.79 +    self.bit = bit;
   16.80 +    return YES;
   16.81 +}
   16.82 +
   16.83 +@end
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/Source/BoardView.h	Fri Mar 07 11:43:02 2008 -0800
    17.3 @@ -0,0 +1,60 @@
    17.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    17.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    17.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    17.7 +
    17.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    17.9 +    provided that the following conditions are met:
   17.10 +
   17.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   17.12 +      and the following disclaimer.
   17.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   17.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   17.15 +      with the distribution.
   17.16 +
   17.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   17.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   17.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   17.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   17.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   17.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   17.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   17.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   17.25 +*/
   17.26 +#import <Cocoa/Cocoa.h>
   17.27 +@class Bit, Card, Grid, Game;
   17.28 +@protocol BitHolder;
   17.29 +
   17.30 +
   17.31 +/** NSView that hosts a game. */
   17.32 +@interface BoardView : NSView
   17.33 +{
   17.34 +    @private
   17.35 +    Game *_game;                                // Current Game
   17.36 +    CALayer *_gameboard;                        // Game's main layer
   17.37 +    
   17.38 +    // Used during mouse-down tracking:
   17.39 +    NSPoint _dragStartPos;                      // Starting position of mouseDown
   17.40 +    Bit *_dragBit;                              // Bit being dragged
   17.41 +    id<BitHolder> _oldHolder;                   // Bit's original holder
   17.42 +    CALayer *_oldSuperlayer;                    // Bit's original superlayer
   17.43 +    int _oldLayerIndex;                         // Bit's original index in _oldSuperlayer.layers
   17.44 +    CGPoint _oldPos;                            // Bit's original x/y position
   17.45 +    CGPoint _dragOffset;                        // Offset of mouse position from _dragBit's origin
   17.46 +    BOOL _dragMoved;                            // Has the mouse moved more than 3 pixels since mouseDown?
   17.47 +    id<BitHolder> _dropTarget;                  // Current BitHolder the cursor is over
   17.48 +    
   17.49 +    // Used while handling incoming drags:
   17.50 +    CALayer *_viewDropTarget;                   // Current drop target during an incoming drag-n-drop
   17.51 +    NSDragOperation _viewDropOp;                // Current drag operation
   17.52 +}
   17.53 +
   17.54 +- (void) startGameNamed: (NSString*)gameClassName;
   17.55 +
   17.56 +- (IBAction) enterFullScreen: (id)sender;
   17.57 +
   17.58 +@property (readonly) Game *game;
   17.59 +@property (readonly) CALayer *gameboard;
   17.60 +
   17.61 +- (CGRect) gameBoardFrame;
   17.62 +
   17.63 +@end
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/Source/BoardView.m	Fri Mar 07 11:43:02 2008 -0800
    18.3 @@ -0,0 +1,329 @@
    18.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    18.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    18.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    18.7 +
    18.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    18.9 +    provided that the following conditions are met:
   18.10 +
   18.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   18.12 +      and the following disclaimer.
   18.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   18.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   18.15 +      with the distribution.
   18.16 +
   18.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   18.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   18.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   18.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   18.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   18.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   18.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   18.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   18.25 +*/
   18.26 +#import "BoardView.h"
   18.27 +#import "Bit.h"
   18.28 +#import "BitHolder.h"
   18.29 +#import "Game.h"
   18.30 +#import "QuartzUtils.h"
   18.31 +#import "GGBUtils.h"
   18.32 +
   18.33 +
   18.34 +@implementation BoardView
   18.35 +
   18.36 +
   18.37 +@synthesize game=_game, gameboard=_gameboard;
   18.38 +
   18.39 +
   18.40 +- (void) dealloc
   18.41 +{
   18.42 +    [_game release];
   18.43 +    [super dealloc];
   18.44 +}
   18.45 +
   18.46 +
   18.47 +- (void) startGameNamed: (NSString*)gameClassName
   18.48 +{
   18.49 +    if( _gameboard ) {
   18.50 +        [_gameboard removeFromSuperlayer];
   18.51 +        _gameboard = nil;
   18.52 +    }
   18.53 +    _gameboard = [[CALayer alloc] init];
   18.54 +    _gameboard.frame = [self gameBoardFrame];
   18.55 +    _gameboard.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
   18.56 +    [self.layer addSublayer: _gameboard];
   18.57 +    [_gameboard release];
   18.58 +    
   18.59 +    Class gameClass = NSClassFromString(gameClassName);
   18.60 +    setObj(&_game, [[gameClass alloc] initWithBoard: _gameboard]);
   18.61 +}
   18.62 +
   18.63 +
   18.64 +- (CGRect) gameBoardFrame
   18.65 +{
   18.66 +    return self.layer.bounds;
   18.67 +}
   18.68 +
   18.69 +
   18.70 +- (void)resetCursorRects
   18.71 +{
   18.72 +    [super resetCursorRects];
   18.73 +    [self addCursorRect: self.bounds cursor: [NSCursor openHandCursor]];
   18.74 +}
   18.75 +
   18.76 +
   18.77 +- (IBAction) enterFullScreen: (id)sender
   18.78 +{
   18.79 +    if( self.isInFullScreenMode ) {
   18.80 +        [self exitFullScreenModeWithOptions: nil];
   18.81 +    } else {
   18.82 +        [self enterFullScreenMode: self.window.screen 
   18.83 +                      withOptions: nil];
   18.84 +    }
   18.85 +}
   18.86 +
   18.87 +
   18.88 +#pragma mark -
   18.89 +#pragma mark KEY EVENTS:
   18.90 +
   18.91 +
   18.92 +- (void) keyDown: (NSEvent*)ev
   18.93 +{
   18.94 +    if( self.isInFullScreenMode ) {
   18.95 +        if( [ev.charactersIgnoringModifiers hasPrefix: @"\033"] )       // Esc key
   18.96 +            [self enterFullScreen: self];
   18.97 +    }
   18.98 +}
   18.99 +
  18.100 +
  18.101 +#pragma mark -
  18.102 +#pragma mark HIT-TESTING:
  18.103 +
  18.104 +
  18.105 +// Hit-testing callbacks (to identify which layers caller is interested in):
  18.106 +typedef BOOL (*LayerMatchCallback)(CALayer*);
  18.107 +
  18.108 +static BOOL layerIsBit( CALayer* layer )        {return [layer isKindOfClass: [Bit class]];}
  18.109 +static BOOL layerIsBitHolder( CALayer* layer )  {return [layer conformsToProtocol: @protocol(BitHolder)];}
  18.110 +static BOOL layerIsDropTarget( CALayer* layer ) {return [layer respondsToSelector: @selector(draggingEntered:)];}
  18.111 +
  18.112 +
  18.113 +/** Locates the layer at a given point in window coords.
  18.114 +    If the leaf layer doesn't pass the layer-match callback, the nearest ancestor that does is returned.
  18.115 +    If outOffset is provided, the point's position relative to the layer is stored into it. */
  18.116 +- (CALayer*) hitTestPoint: (NSPoint)locationInWindow
  18.117 +         forLayerMatching: (LayerMatchCallback)match
  18.118 +                   offset: (CGPoint*)outOffset
  18.119 +{
  18.120 +    CGPoint where = NSPointToCGPoint([self convertPoint: locationInWindow fromView: nil]);
  18.121 +    where = [_gameboard convertPoint: where fromLayer: self.layer];
  18.122 +    CALayer *layer = [_gameboard hitTest: where];
  18.123 +    while( layer ) {
  18.124 +        if( match(layer) ) {
  18.125 +            CGPoint bitPos = [self.layer convertPoint: layer.position 
  18.126 +                              fromLayer: layer.superlayer];
  18.127 +            if( outOffset )
  18.128 +                *outOffset = CGPointMake( bitPos.x-where.x, bitPos.y-where.y);
  18.129 +            return layer;
  18.130 +        } else
  18.131 +            layer = layer.superlayer;
  18.132 +    }
  18.133 +    return nil;
  18.134 +}
  18.135 +
  18.136 +
  18.137 +#pragma mark -
  18.138 +#pragma mark MOUSE CLICKS & DRAGS:
  18.139 +
  18.140 +
  18.141 +- (void) mouseDown: (NSEvent*)ev
  18.142 +{
  18.143 +    _dragStartPos = ev.locationInWindow;
  18.144 +    _dragBit = (Bit*) [self hitTestPoint: _dragStartPos
  18.145 +                        forLayerMatching: layerIsBit 
  18.146 +                                  offset: &_dragOffset];
  18.147 +    if( _dragBit ) {
  18.148 +        _dragMoved = NO;
  18.149 +        _dropTarget = nil;
  18.150 +        _oldHolder = _dragBit.holder;
  18.151 +        // Ask holder's and game's permission before dragging:
  18.152 +        if( _oldHolder )
  18.153 +            _dragBit = [_oldHolder canDragBit: _dragBit];
  18.154 +        if( _dragBit && ! [_game canBit: _dragBit moveFrom: _oldHolder] ) {
  18.155 +            [_oldHolder cancelDragBit: _dragBit];
  18.156 +            _dragBit = nil;
  18.157 +        }
  18.158 +        if( ! _dragBit ) {
  18.159 +            _oldHolder = nil;
  18.160 +            NSBeep();
  18.161 +            return;
  18.162 +        }
  18.163 +        // Start dragging:
  18.164 +        _oldSuperlayer = _dragBit.superlayer;
  18.165 +        _oldLayerIndex = [_oldSuperlayer.sublayers indexOfObjectIdenticalTo: _dragBit];
  18.166 +        _oldPos = _dragBit.position;
  18.167 +        ChangeSuperlayer(_dragBit, self.layer, self.layer.sublayers.count);
  18.168 +        _dragBit.pickedUp = YES;
  18.169 +        [[NSCursor closedHandCursor] push];
  18.170 +    } else
  18.171 +        NSBeep();
  18.172 +}
  18.173 +
  18.174 +- (void) mouseDragged: (NSEvent*)ev
  18.175 +{
  18.176 +    if( _dragBit ) {
  18.177 +        // Get the mouse position, and see if we've moved 3 pixels since the mouseDown:
  18.178 +        NSPoint pos = ev.locationInWindow;
  18.179 +        if( fabs(pos.x-_dragStartPos.x)>=3 || fabs(pos.y-_dragStartPos.y)>=3 )
  18.180 +            _dragMoved = YES;
  18.181 +        
  18.182 +        // Move the _dragBit (without animation -- it's unnecessary and slows down responsiveness):
  18.183 +        NSPoint where = [self convertPoint: pos fromView: nil];
  18.184 +        where.x += _dragOffset.x;
  18.185 +        where.y += _dragOffset.y;
  18.186 +        
  18.187 +        CGPoint newPos = [_dragBit.superlayer convertPoint: NSPointToCGPoint(where) 
  18.188 +                                                 fromLayer: self.layer];
  18.189 +
  18.190 +        [CATransaction flush];
  18.191 +        [CATransaction begin];
  18.192 +        [CATransaction setValue:(id)kCFBooleanTrue
  18.193 +                         forKey:kCATransactionDisableActions];
  18.194 +        _dragBit.position = newPos;
  18.195 +        [CATransaction commit];
  18.196 +
  18.197 +        // Find what it's over:
  18.198 +        id<BitHolder> target = (id<BitHolder>) [self hitTestPoint: where
  18.199 +                                                 forLayerMatching: layerIsBitHolder
  18.200 +                                                           offset: NULL];
  18.201 +        if( target == _oldHolder )
  18.202 +            target = nil;
  18.203 +        if( target != _dropTarget ) {
  18.204 +            [_dropTarget willNotDropBit: _dragBit];
  18.205 +            _dropTarget.highlighted = NO;
  18.206 +            _dropTarget = nil;
  18.207 +        }
  18.208 +        if( target ) {
  18.209 +            CGPoint targetPos = [(CALayer*)target convertPoint: _dragBit.position
  18.210 +                                                     fromLayer: _dragBit.superlayer];
  18.211 +            if( [target canDropBit: _dragBit atPoint: targetPos]
  18.212 +               && [_game canBit: _dragBit moveFrom: _oldHolder to: target] ) {
  18.213 +                _dropTarget = target;
  18.214 +                _dropTarget.highlighted = YES;
  18.215 +            }
  18.216 +        }
  18.217 +    }
  18.218 +}
  18.219 +
  18.220 +- (void) mouseUp: (NSEvent*)ev
  18.221 +{
  18.222 +    if( _dragBit ) {
  18.223 +        if( _dragMoved ) {
  18.224 +            // Update the drag tracking to the final mouse position:
  18.225 +            [self mouseDragged: ev];
  18.226 +            _dropTarget.highlighted = NO;
  18.227 +            _dragBit.pickedUp = NO;
  18.228 +
  18.229 +            // Is the move legal?
  18.230 +            if( _dropTarget && [_dropTarget dropBit: _dragBit
  18.231 +                                            atPoint: [(CALayer*)_dropTarget convertPoint: _dragBit.position 
  18.232 +                                                                            fromLayer: _dragBit.superlayer]] ) {
  18.233 +                // Yes, notify the interested parties:
  18.234 +                [_oldHolder draggedBit: _dragBit to: _dropTarget];
  18.235 +                [_game bit: _dragBit movedFrom: _oldHolder to: _dropTarget];
  18.236 +            } else {
  18.237 +                // Nope, cancel:
  18.238 +                [_dropTarget willNotDropBit: _dragBit];
  18.239 +                ChangeSuperlayer(_dragBit, _oldSuperlayer, _oldLayerIndex);
  18.240 +                _dragBit.position = _oldPos;
  18.241 +                [_oldHolder cancelDragBit: _dragBit];
  18.242 +            }
  18.243 +        } else {
  18.244 +            // Just a click, without a drag:
  18.245 +            _dropTarget.highlighted = NO;
  18.246 +            _dragBit.pickedUp = NO;
  18.247 +            ChangeSuperlayer(_dragBit, _oldSuperlayer, _oldLayerIndex);
  18.248 +            [_oldHolder cancelDragBit: _dragBit];
  18.249 +            if( ! [_game clickedBit: _dragBit] )
  18.250 +                NSBeep();
  18.251 +        }
  18.252 +        _dropTarget = nil;
  18.253 +        _dragBit = nil;
  18.254 +        [NSCursor pop];
  18.255 +    }
  18.256 +}
  18.257 +
  18.258 +
  18.259 +#pragma mark -
  18.260 +#pragma mark INCOMING DRAGS:
  18.261 +
  18.262 +
  18.263 +// subroutine to call the target
  18.264 +static int tell( id target, SEL selector, id arg, int defaultValue )
  18.265 +{
  18.266 +    if( target && [target respondsToSelector: selector] )
  18.267 +        return (ssize_t) [target performSelector: selector withObject: arg];
  18.268 +    else
  18.269 +        return defaultValue;
  18.270 +}
  18.271 +
  18.272 +
  18.273 +- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
  18.274 +{
  18.275 +    _viewDropTarget = [self hitTestPoint: [sender draggingLocation]
  18.276 +                        forLayerMatching: layerIsDropTarget
  18.277 +                                  offset: NULL];
  18.278 +    _viewDropOp = _viewDropTarget ?[_viewDropTarget draggingEntered: sender] :NSDragOperationNone;
  18.279 +    return _viewDropOp;
  18.280 +}
  18.281 +
  18.282 +- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
  18.283 +{
  18.284 +    CALayer *target = [self hitTestPoint: [sender draggingLocation]
  18.285 +                        forLayerMatching: layerIsDropTarget 
  18.286 +                                  offset: NULL];
  18.287 +    if( target == _viewDropTarget ) {
  18.288 +        if( _viewDropTarget )
  18.289 +            _viewDropOp = tell(_viewDropTarget,@selector(draggingUpdated:),sender,_viewDropOp);
  18.290 +    } else {
  18.291 +        tell(_viewDropTarget,@selector(draggingExited:),sender,0);
  18.292 +        _viewDropTarget = target;
  18.293 +        if( _viewDropTarget )
  18.294 +            _viewDropOp = [_viewDropTarget draggingEntered: sender];
  18.295 +        else
  18.296 +            _viewDropOp = NSDragOperationNone;
  18.297 +    }
  18.298 +    return _viewDropOp;
  18.299 +}
  18.300 +
  18.301 +- (BOOL)wantsPeriodicDraggingUpdates
  18.302 +{
  18.303 +    return (_viewDropTarget!=nil);
  18.304 +}
  18.305 +
  18.306 +- (void)draggingExited:(id <NSDraggingInfo>)sender
  18.307 +{
  18.308 +    tell(_viewDropTarget,@selector(draggingExited:),sender,0);
  18.309 +    _viewDropTarget = nil;
  18.310 +}
  18.311 +
  18.312 +- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
  18.313 +{
  18.314 +    return tell(_viewDropTarget,@selector(prepareForDragOperation:),sender,YES);
  18.315 +}
  18.316 +
  18.317 +- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
  18.318 +{
  18.319 +    return [_viewDropTarget performDragOperation: sender];
  18.320 +}
  18.321 +
  18.322 +- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
  18.323 +{
  18.324 +    tell(_viewDropTarget,@selector(concludeDragOperation:),sender,0);
  18.325 +}
  18.326 +
  18.327 +- (void)draggingEnded:(id <NSDraggingInfo>)sender
  18.328 +{
  18.329 +    tell(_viewDropTarget,@selector(draggingEnded:),sender,0);
  18.330 +}
  18.331 +
  18.332 +@end
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/Source/Card.h	Fri Mar 07 11:43:02 2008 -0800
    19.3 @@ -0,0 +1,66 @@
    19.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    19.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    19.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    19.7 +
    19.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    19.9 +    provided that the following conditions are met:
   19.10 +
   19.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   19.12 +      and the following disclaimer.
   19.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   19.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   19.15 +      with the distribution.
   19.16 +
   19.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   19.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   19.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   19.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   19.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   19.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   19.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   19.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   19.25 +*/
   19.26 +#import "Bit.h"
   19.27 +
   19.28 +
   19.29 +/** Hardcoded dimensions of a Card */
   19.30 +#define kCardWidth  100
   19.31 +#define kCardHeight 150
   19.32 +
   19.33 +
   19.34 +/* A card of some type (playing card, Community Chest, money, ...)
   19.35 +   Has an identifying serial number (could be in the range 1..52 for playing cards).
   19.36 +   Can be face-up or down. */
   19.37 +@interface Card : Bit 
   19.38 +{
   19.39 +    @private
   19.40 +    int _serialNumber;
   19.41 +    CALayer *_front, *_back;
   19.42 +    BOOL _faceUp;
   19.43 +}
   19.44 +
   19.45 +/** The range of serialNumbers used for this type of card. Used when instantiating Decks.
   19.46 +    Abstract; must be overridden. */
   19.47 ++ (NSRange) serialNumberRange;
   19.48 +
   19.49 +- (id) initWithSerialNumber: (int)serial position: (CGPoint)pos;
   19.50 +
   19.51 +@property (readonly) int serialNumber;
   19.52 +
   19.53 +/** Cards can be face-up or face-down, of course. */
   19.54 +@property BOOL faceUp;
   19.55 +
   19.56 +
   19.57 +//protected -- for subclasses only:
   19.58 +
   19.59 +/** Creates the sub-layer that displays the front side of the card.
   19.60 +    Subclasses should probably call the superclass method, configure the layer it returns
   19.61 +    (based on the card's serialNumber) and then return that layer. */
   19.62 +- (CALayer*) createFront;
   19.63 +
   19.64 +/** Creates the sub-layer that displays the back side of the card.
   19.65 +    Subclasses should probably call the superclass method, configure the layer it returns and
   19.66 +    return that layer. */
   19.67 +- (CALayer*) createBack;
   19.68 +
   19.69 +@end
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/Source/Card.m	Fri Mar 07 11:43:02 2008 -0800
    20.3 @@ -0,0 +1,186 @@
    20.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    20.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    20.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    20.7 +
    20.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    20.9 +    provided that the following conditions are met:
   20.10 +
   20.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   20.12 +      and the following disclaimer.
   20.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   20.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   20.15 +      with the distribution.
   20.16 +
   20.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   20.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   20.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   20.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   20.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   20.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   20.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   20.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   20.25 +*/
   20.26 +#import "Card.h"
   20.27 +#import "QuartzUtils.h"
   20.28 +
   20.29 +
   20.30 +@implementation Card
   20.31 +
   20.32 +
   20.33 +static CATransform3D kFaceUpTransform, kFaceDownTransform;
   20.34 +
   20.35 ++ (void) initialize
   20.36 +{
   20.37 +    if( self==[Card class] ) {
   20.38 +        kFaceUpTransform = kFaceDownTransform = CATransform3DIdentity;
   20.39 +        // Construct a 180-degree rotation matrix:
   20.40 +        kFaceDownTransform.m11 = kFaceDownTransform.m33 = -1;
   20.41 +        // The more obvious way to create kFaceDownTransform would be to call
   20.42 +        // CATransform3DMakeRotation(pi,0,1,0), but due to round-off errors, that transform
   20.43 +        // will have non-zero values in some other places, making it appear to CA as a true
   20.44 +        // 3D transform; this will then cause unexpected clipping behaviors when used.
   20.45 +    }
   20.46 +}
   20.47 +
   20.48 +
   20.49 ++ (NSRange) serialNumberRange;
   20.50 +{
   20.51 +    NSAssert1(NO,@"%@ forgot to override +serialNumberRange",self);
   20.52 +    return NSMakeRange(0,0);
   20.53 +}
   20.54 +
   20.55 +
   20.56 +- (id) initWithSerialNumber: (int)serial position: (CGPoint)pos
   20.57 +{
   20.58 +    self = [super init];
   20.59 +    if (self != nil) {
   20.60 +        _serialNumber = serial;
   20.61 +        self.bounds = CGRectMake(0,0,kCardWidth,kCardHeight);
   20.62 +        self.position = pos;
   20.63 +        self.edgeAntialiasingMask = 0;
   20.64 +        _back = [self createBack];
   20.65 +        [self addSublayer: _back];
   20.66 +        _front = [self createFront];
   20.67 +        _front.transform = kFaceDownTransform;
   20.68 +        [self addSublayer: _front];
   20.69 +    }
   20.70 +    return self;
   20.71 +}
   20.72 +
   20.73 +
   20.74 +- (void)encodeWithCoder:(NSCoder *)aCoder
   20.75 +{
   20.76 +    [super encodeWithCoder: aCoder];
   20.77 +    [aCoder encodeInt: _serialNumber forKey: @"serialNumber"];
   20.78 +}
   20.79 +
   20.80 +- (id)initWithCoder:(NSCoder *)aDecoder
   20.81 +{
   20.82 +    self = [super initWithCoder: aDecoder];
   20.83 +    if( self ) {
   20.84 +        _serialNumber = [aDecoder decodeIntForKey: @"serialNumber"];
   20.85 +    }
   20.86 +    return self;
   20.87 +}
   20.88 +
   20.89 +
   20.90 +- (NSString*) description
   20.91 +{
   20.92 +    return [NSString stringWithFormat: @"%@[#%i]",self.class,_serialNumber];
   20.93 +}
   20.94 +
   20.95 +
   20.96 +@synthesize serialNumber=_serialNumber;
   20.97 +
   20.98 +
   20.99 +- (BOOL) faceUp
  20.100 +{
  20.101 +    return _faceUp;
  20.102 +}
  20.103 +
  20.104 +- (void) setFaceUp: (BOOL)up
  20.105 +{
  20.106 +    if( up != _faceUp ) {
  20.107 +        // The Card has separate sub-layers for its front and back. At any time, one of them
  20.108 +        // is hidden, by having a 180 degree rotation about the Y axis.
  20.109 +        // To flip the card, both front and back layers are flipped over.
  20.110 +        CATransform3D xform;
  20.111 +        xform = up ?kFaceUpTransform :kFaceDownTransform;
  20.112 +        _front.transform = xform;
  20.113 +        
  20.114 +        xform = up ?kFaceDownTransform :kFaceUpTransform;
  20.115 +        _back.transform = xform;
  20.116 +        _faceUp = up;
  20.117 +    }
  20.118 +}
  20.119 +
  20.120 +
  20.121 +- (CALayer*) createFront
  20.122 +{
  20.123 +    CALayer *front = [[CALayer alloc] init];
  20.124 +    front.bounds = CGRectMake(0,0,kCardWidth,kCardHeight);
  20.125 +    front.position = CGPointMake(kCardWidth/2,kCardHeight/2);
  20.126 +    front.edgeAntialiasingMask = 0;
  20.127 +    front.backgroundColor = kWhiteColor;
  20.128 +    front.cornerRadius = 8;
  20.129 +    front.borderWidth = 1;
  20.130 +    front.borderColor = CGColorCreateGenericGray(0.7, 1.0);
  20.131 +    front.doubleSided = NO;         // this makes the layer invisible when it's flipped
  20.132 +    return [front autorelease];
  20.133 +}
  20.134 +
  20.135 +
  20.136 +- (CALayer*) createBack
  20.137 +{
  20.138 +    CGSize size = self.bounds.size;
  20.139 +    CALayer *back = [[CALayer alloc] init];
  20.140 +    back.bounds = CGRectMake(0,0,size.width,size.height);
  20.141 +    back.position = CGPointMake(kCardWidth/2,kCardHeight/2);
  20.142 +    back.contents = (id) GetCGImageNamed(@"/Library/Desktop Pictures/Classic Aqua Blue.jpg");
  20.143 +    back.contentsGravity = kCAGravityResize;
  20.144 +    back.masksToBounds = YES;
  20.145 +    back.borderWidth = 4;
  20.146 +    back.borderColor = kWhiteColor;
  20.147 +    back.cornerRadius = 8;
  20.148 +    back.edgeAntialiasingMask = 0;
  20.149 +    back.doubleSided = NO;          // this makes the layer invisible when it's flipped
  20.150 +    
  20.151 +    CATextLayer *label = AddTextLayer(back, @"\u2603",          // Unicode snowman character
  20.152 +                                      [NSFont systemFontOfSize: 0.9*size.width],
  20.153 +                                      kCALayerWidthSizable|kCALayerHeightSizable);
  20.154 +    label.foregroundColor = CGColorCreateGenericGray(1.0,0.5);
  20.155 +    return [back autorelease];
  20.156 +}    
  20.157 +
  20.158 +
  20.159 +#pragma mark -
  20.160 +#pragma mark DRAG-AND-DROP:
  20.161 +
  20.162 +
  20.163 +// An image from another app can be dragged onto a Card to change its background. */
  20.164 +
  20.165 +
  20.166 +- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
  20.167 +{
  20.168 +    NSPasteboard *pb = [sender draggingPasteboard];
  20.169 +    if( [NSImage canInitWithPasteboard: pb] )
  20.170 +        return NSDragOperationCopy;
  20.171 +    else
  20.172 +        return NSDragOperationNone;
  20.173 +}
  20.174 +
  20.175 +- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
  20.176 +{
  20.177 +    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
  20.178 +    if( image ) {
  20.179 +        CALayer *face = _faceUp ?_front :_back;
  20.180 +        face.contents = (id) image;
  20.181 +        face.contentsGravity = kCAGravityResizeAspectFill;
  20.182 +        face.masksToBounds = YES;
  20.183 +        return YES;
  20.184 +    } else
  20.185 +        return NO;
  20.186 +}
  20.187 +
  20.188 +
  20.189 +@end
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/Source/CheckersGame.h	Fri Mar 07 11:43:02 2008 -0800
    21.3 @@ -0,0 +1,41 @@
    21.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    21.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    21.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    21.7 +
    21.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    21.9 +    provided that the following conditions are met:
   21.10 +
   21.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   21.12 +      and the following disclaimer.
   21.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   21.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   21.15 +      with the distribution.
   21.16 +
   21.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   21.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   21.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   21.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   21.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   21.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   21.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   21.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   21.25 +*/
   21.26 +#import "Game.h"
   21.27 +@class Grid;
   21.28 +
   21.29 +
   21.30 +/** US Checkers, known as Draughts in the UK. (Other countries use similar but not identical rules.)
   21.31 +    See: http://en.wikipedia.org/wiki/Draughts */
   21.32 +@interface CheckersGame : Game 
   21.33 +{
   21.34 +    int _numPieces[2];
   21.35 +}
   21.36 +
   21.37 +// For subclasses (See HexchequerGame):
   21.38 +- (void) addPieces: (NSString*)imageName
   21.39 +            toGrid: (Grid*)grid
   21.40 +         forPlayer: (int)playerNum
   21.41 +              rows: (NSRange)rows
   21.42 +       alternating: (BOOL)alternating;
   21.43 +
   21.44 +@end
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/Source/CheckersGame.m	Fri Mar 07 11:43:02 2008 -0800
    22.3 @@ -0,0 +1,156 @@
    22.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    22.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    22.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    22.7 +
    22.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    22.9 +    provided that the following conditions are met:
   22.10 +
   22.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   22.12 +      and the following disclaimer.
   22.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   22.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   22.15 +      with the distribution.
   22.16 +
   22.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   22.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   22.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   22.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   22.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   22.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   22.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   22.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   22.25 +*/
   22.26 +#import "CheckersGame.h"
   22.27 +#import "Grid.h"
   22.28 +#import "Piece.h"
   22.29 +#import "QuartzUtils.h"
   22.30 +
   22.31 +
   22.32 +@implementation CheckersGame
   22.33 +
   22.34 +
   22.35 +- (void) addPieces: (NSString*)imageName
   22.36 +            toGrid: (Grid*)grid
   22.37 +         forPlayer: (int)playerNum
   22.38 +              rows: (NSRange)rows
   22.39 +       alternating: (BOOL)alternating
   22.40 +{
   22.41 +    Piece *prototype = [[Piece alloc] initWithImageNamed: imageName scale: floor(grid.spacing.width * 0.8)];
   22.42 +    prototype.owner = [self.players objectAtIndex: playerNum];
   22.43 +    unsigned cols=grid.columns;
   22.44 +    for( unsigned row=rows.location; row<NSMaxRange(rows); row++ )
   22.45 +        for( unsigned col=0; col<cols; col++ ) {
   22.46 +            if( !alternating || ((row+col) & 1) == 0 ) {
   22.47 +                GridCell *cell = [grid cellAtRow: row column: col];
   22.48 +                if( cell ) {
   22.49 +                    Piece *piece = [prototype copy];
   22.50 +                    cell.bit = piece;
   22.51 +                    [piece release];
   22.52 +                    //cell.bit.rotation = random() % 360; // keeps pieces from looking too samey
   22.53 +                    _numPieces[playerNum]++;
   22.54 +                }
   22.55 +            }
   22.56 +        }
   22.57 +    [prototype release];
   22.58 +}
   22.59 +
   22.60 +
   22.61 +- (Grid*) x_makeGrid
   22.62 +{
   22.63 +    RectGrid *grid = [[[RectGrid alloc] initWithRows: 8 columns: 8 frame: _board.bounds] autorelease];
   22.64 +    CGPoint pos = grid.position;
   22.65 +    pos.x = floor((_board.bounds.size.width-grid.frame.size.width)/2);
   22.66 +    [grid addAllCells];
   22.67 +    grid.position = pos;
   22.68 +    grid.allowsMoves = YES;
   22.69 +    grid.allowsCaptures = NO;
   22.70 +    grid.cellColor = CGColorCreateGenericGray(0.0, 0.25);
   22.71 +    grid.altCellColor = CGColorCreateGenericGray(1.0, 0.25);
   22.72 +    grid.lineColor = nil;
   22.73 +    [self addPieces: @"Green Ball.png" toGrid: grid forPlayer: 0 rows: NSMakeRange(0,3) alternating: YES];
   22.74 +    [self addPieces: @"Red Ball.png"   toGrid: grid forPlayer: 1 rows: NSMakeRange(5,3) alternating: YES];
   22.75 +    return grid;
   22.76 +}
   22.77 +
   22.78 +
   22.79 +- (id) initWithBoard: (CALayer*)board
   22.80 +{
   22.81 +    self = [super initWithBoard: board];
   22.82 +    if (self != nil) {
   22.83 +        [self setNumberOfPlayers: 2];
   22.84 +        [board addSublayer: [self x_makeGrid]];
   22.85 +        [self nextPlayer];
   22.86 +    }
   22.87 +    return self;
   22.88 +}
   22.89 +
   22.90 +
   22.91 +- (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
   22.92 +{
   22.93 +    Square *src=(Square*)srcHolder, *dst=(Square*)dstHolder;
   22.94 +    if( [bit valueForKey: @"King"] )
   22.95 +        if( dst==src.bl || dst==src.br || dst==src.l || dst==src.r
   22.96 +           || (src.bl.bit.unfriendly && dst==src.bl.bl) || (src.br.bit.unfriendly && dst==src.br.br) )
   22.97 +            return YES;    
   22.98 +    return dst==src.fl || dst==src.fr
   22.99 +        || (src.fl.bit.unfriendly && dst==src.fl.fl) || (src.fr.bit.unfriendly && dst==src.fr.fr);
  22.100 +}
  22.101 +
  22.102 +- (void) bit: (Bit*)bit movedFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
  22.103 +{
  22.104 +    Square *src=(Square*)srcHolder, *dst=(Square*)dstHolder;
  22.105 +    int playerIndex = self.currentPlayer.index;
  22.106 +    BOOL isKing = ([bit valueForKey: @"King"] != nil);
  22.107 +    
  22.108 +    [[NSSound soundNamed: (isKing ?@"Funk" :@"Tink")] play];
  22.109 +
  22.110 +    // "King" a piece that made it to the last row:
  22.111 +    if( dst.row == (playerIndex ?0 :7) )
  22.112 +        if( ! isKing ) {
  22.113 +            [[NSSound soundNamed: @"Blow"] play];
  22.114 +            bit.scale = 1.4;
  22.115 +            [bit setValue: @"King" forKey: @"King"];
  22.116 +            // don't set isKing flag - piece can't jump again after being kinged.
  22.117 +        }
  22.118 +
  22.119 +    // Check for a capture:
  22.120 +    Square *capture = nil;
  22.121 +    if(dst==src.fl.fl)
  22.122 +        capture = src.fl;
  22.123 +    else if(dst==src.fr.fr)
  22.124 +        capture = src.fr;
  22.125 +    else if(dst==src.bl.bl)
  22.126 +        capture = src.bl;
  22.127 +    else if(dst==src.br.br)
  22.128 +        capture = src.br;
  22.129 +    
  22.130 +    if( capture ) {
  22.131 +        [[NSSound soundNamed: @"Pop"] play];
  22.132 +        Bit *bit = capture.bit;
  22.133 +        _numPieces[bit.owner.index]--;
  22.134 +        [bit destroy];
  22.135 +        
  22.136 +        // Now check if another capture is possible. If so, don't end the turn:
  22.137 +        if( (dst.fl.bit.unfriendly && dst.fl.fl.empty) || (dst.fr.bit.unfriendly && dst.fr.fr.empty) )
  22.138 +            return;
  22.139 +        if( isKing )
  22.140 +            if( (dst.bl.bit.unfriendly && dst.bl.bl.empty) || (dst.br.bit.unfriendly && dst.br.br.empty) )
  22.141 +                return;
  22.142 +    }
  22.143 +    
  22.144 +    [self endTurn];
  22.145 +}
  22.146 +
  22.147 +- (Player*) checkForWinner
  22.148 +{
  22.149 +    // Whoever runs out of pieces loses:
  22.150 +    if( _numPieces[0]==0 )
  22.151 +        return [self.players objectAtIndex: 1];
  22.152 +    else if( _numPieces[1]==0 )
  22.153 +        return [self.players objectAtIndex: 0];
  22.154 +    else
  22.155 +        return nil;
  22.156 +}
  22.157 +
  22.158 +
  22.159 +@end
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/Source/Deck.h	Fri Mar 07 11:43:02 2008 -0800
    23.3 @@ -0,0 +1,57 @@
    23.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    23.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    23.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    23.7 +
    23.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    23.9 +    provided that the following conditions are met:
   23.10 +
   23.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   23.12 +      and the following disclaimer.
   23.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   23.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   23.15 +      with the distribution.
   23.16 +
   23.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   23.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   23.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   23.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   23.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   23.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   23.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   23.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   23.25 +*/
   23.26 +#import "BitHolder.h"
   23.27 +@class Card;
   23.28 +
   23.29 +
   23.30 +/** A pile of Cards. Unlike a Stack, only the top card is visible or accessible;
   23.31 +    so as an optimization, it's the only one that's added to the layer tree. */
   23.32 +@interface Deck : BitHolder
   23.33 +{
   23.34 +    NSMutableArray *_cards;
   23.35 +}
   23.36 +
   23.37 +/** Creates an empty Deck. */
   23.38 +- (id) init;
   23.39 +
   23.40 +/** Creates a Deck populated with a full set of cards (in order.) */
   23.41 +- (id) initWithCardsOfClass: (Class)klass;
   23.42 +
   23.43 +@property (readonly) NSArray *cards;
   23.44 +@property (readonly) Card *topCard;             // same as the -bit property
   23.45 +
   23.46 +/** Randomly shuffles all the cards in the Deck. */
   23.47 +- (void) shuffle;
   23.48 +
   23.49 +/** Flips over the Deck: Reverses the order of cards, and inverts their -faceUp flags. */
   23.50 +- (void) flip;
   23.51 +
   23.52 +- (void) addCard: (Card*)card;
   23.53 +- (void) addCardAtBottom: (Card*)card;
   23.54 +- (void) addCardAtRandom: (Card*)card;
   23.55 +- (void) addCards: (NSArray*)cards;
   23.56 +
   23.57 +- (Card*) removeTopCard;
   23.58 +- (NSArray*) removeAllCards;
   23.59 +
   23.60 +@end
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/Source/Deck.m	Fri Mar 07 11:43:02 2008 -0800
    24.3 @@ -0,0 +1,267 @@
    24.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    24.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    24.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    24.7 +
    24.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    24.9 +    provided that the following conditions are met:
   24.10 +
   24.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   24.12 +      and the following disclaimer.
   24.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   24.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   24.15 +      with the distribution.
   24.16 +
   24.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   24.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   24.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   24.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   24.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   24.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   24.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   24.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24.25 +*/
   24.26 +#import "Deck.h"
   24.27 +#import "Card.h"
   24.28 +#import "Stack.h"
   24.29 +#import "QuartzUtils.h"
   24.30 +#import "GGBUtils.h"
   24.31 +
   24.32 +
   24.33 +@interface Deck ()
   24.34 +- (void) setCards: (NSMutableArray*)cards;
   24.35 +- (void) x_showTopCard;
   24.36 +@end
   24.37 +
   24.38 +
   24.39 +@implementation Deck
   24.40 +
   24.41 +
   24.42 +- (id) init
   24.43 +{
   24.44 +    self = [super init];
   24.45 +    if (self != nil) {
   24.46 +        self.bounds = CGRectMake(0,0,kCardWidth,kCardHeight);
   24.47 +        self.cornerRadius = 8;
   24.48 +        self.backgroundColor = kAlmostInvisibleWhiteColor;
   24.49 +        self.borderColor = kHighlightColor;
   24.50 +        self.cards = [NSMutableArray array];
   24.51 +    }
   24.52 +    return self;
   24.53 +}
   24.54 +
   24.55 +- (id) initWithCardsOfClass: (Class)klass
   24.56 +{
   24.57 +    self = [self init];
   24.58 +    if (self != nil) {
   24.59 +        // Create a full deck of cards:
   24.60 +        NSRange serials = [klass serialNumberRange];
   24.61 +        for( int i=serials.location; i<NSMaxRange(serials); i++ ) {
   24.62 +            Card *card = [[klass alloc] initWithSerialNumber: i
   24.63 +                                                    position: CGPointZero];
   24.64 +            [_cards addObject: card];
   24.65 +            [card release];
   24.66 +        }
   24.67 +        [self x_showTopCard];
   24.68 +    }
   24.69 +    return self;
   24.70 +}
   24.71 +
   24.72 +
   24.73 +- (void) dealloc
   24.74 +{
   24.75 +    [_cards release];
   24.76 +    [super dealloc];
   24.77 +}
   24.78 +
   24.79 +
   24.80 +- (NSArray*) cards                          {return _cards;}
   24.81 +- (void) setCards: (NSMutableArray*)cards   {setObj(&_cards,cards);}
   24.82 +
   24.83 +- (Card*) topCard   {return (Card*)_bit;}
   24.84 +
   24.85 +
   24.86 +- (void) setBit: (Bit*)bit
   24.87 +{
   24.88 +    NSAssert(NO,@"Don't call -setBit");
   24.89 +}
   24.90 +
   24.91 +
   24.92 +- (void) x_removeObsoleteCard: (Card*)card
   24.93 +{
   24.94 +    if( [_cards containsObject: card] && card != _bit )
   24.95 +        RemoveImmediately(card);
   24.96 +}
   24.97 +
   24.98 +
   24.99 +/** Sync up my display with the _cards array. The last element of _cards should be shown,
  24.100 +    and no others (they shouldn't even be in the layer tree, for performance reasons.) */
  24.101 +- (void) x_showTopCard
  24.102 +{
  24.103 +    Card *curTopCard = [_cards lastObject];
  24.104 +    if( curTopCard != _bit ) {
  24.105 +        if( _bit ) {
  24.106 +            // Remove card that used to be the top one
  24.107 +            if( [_cards containsObject: _bit] )   // wait till new card animates on top of it
  24.108 +                [self performSelector: @selector(x_removeObsoleteCard:) withObject: _bit afterDelay: 1.0];
  24.109 +            else
  24.110 +                RemoveImmediately(_bit);
  24.111 +        }
  24.112 +        _bit = curTopCard;
  24.113 +        if( curTopCard ) {
  24.114 +            if( curTopCard.superlayer==self ) {
  24.115 +                [self addSublayer: curTopCard]; // move to top
  24.116 +                curTopCard.position = GetCGRectCenter(self.bounds);
  24.117 +            } else {
  24.118 +                if( curTopCard.superlayer )
  24.119 +                    ChangeSuperlayer(curTopCard, self, -1);
  24.120 +                curTopCard.position = GetCGRectCenter(self.bounds);
  24.121 +                if( ! curTopCard.superlayer )
  24.122 +                    [self addSublayer: curTopCard];
  24.123 +            }
  24.124 +        }
  24.125 +    }
  24.126 +}
  24.127 +
  24.128 +
  24.129 +- (void) shuffle
  24.130 +{
  24.131 +    int n = _cards.count;
  24.132 +    NSMutableArray *shuffled = [NSMutableArray arrayWithCapacity: n];
  24.133 +    for( ; n > 0; n-- ) {
  24.134 +        int i = random() % n;
  24.135 +        Card *card = [_cards objectAtIndex: i];
  24.136 +        [shuffled addObject: card];
  24.137 +        [_cards removeObjectAtIndex: i];
  24.138 +    }
  24.139 +    self.cards = shuffled;
  24.140 +    [self x_showTopCard];
  24.141 +}
  24.142 +
  24.143 +
  24.144 +- (void) flip
  24.145 +{
  24.146 +    int n = _cards.count;
  24.147 +    NSMutableArray *flipped = [NSMutableArray arrayWithCapacity: n];
  24.148 +    while( --n >= 0 ) {
  24.149 +        Card *card = [_cards objectAtIndex: n];
  24.150 +        card.faceUp = ! card.faceUp;
  24.151 +        [flipped addObject: card];
  24.152 +    }
  24.153 +    self.cards = flipped;
  24.154 +    [self x_showTopCard];
  24.155 +}
  24.156 +
  24.157 +
  24.158 +- (void) addCard: (Card*)card
  24.159 +{
  24.160 +    [_cards addObject: card];
  24.161 +    [self x_showTopCard];
  24.162 +}
  24.163 +
  24.164 +- (void) addCardAtBottom: (Card*)card
  24.165 +{
  24.166 +    [_cards insertObject: card atIndex: 0];
  24.167 +    if( _cards.count==1 )
  24.168 +        [self x_showTopCard];
  24.169 +}
  24.170 +
  24.171 +- (void) addCardAtRandom: (Card*)card
  24.172 +{
  24.173 +    // Put the card at some random location, but _not_ on top (unless the deck is empty.)
  24.174 +    int n = _cards.count;
  24.175 +    if( n==0 )
  24.176 +        [self addCard: card];
  24.177 +    else
  24.178 +        [_cards insertObject: card atIndex: (random() % (n-1))];
  24.179 +}
  24.180 +
  24.181 +
  24.182 +- (void) addCards: (NSArray*)cards
  24.183 +{
  24.184 +    [_cards addObjectsFromArray: cards];
  24.185 +    [self x_showTopCard];
  24.186 +}
  24.187 +
  24.188 +
  24.189 +- (BOOL) addBit: (Bit*)bit
  24.190 +{
  24.191 +    if( [bit isKindOfClass: [DraggedStack class]] ) {
  24.192 +        // Convert a DraggedStack back to a group of Cards:
  24.193 +        for( Bit *subBit in [(DraggedStack*)bit bits] )
  24.194 +            if( ! [self addBit: subBit] )
  24.195 +                return NO;
  24.196 +        return YES;
  24.197 +    } else if( [bit isKindOfClass: [Card class]] ) {
  24.198 +        [self addCard: (Card*)bit];
  24.199 +        return YES;
  24.200 +    } else
  24.201 +        return NO;
  24.202 +}
  24.203 +
  24.204 +
  24.205 +- (Card*) removeTopCard
  24.206 +{
  24.207 +    Card *card = [_cards lastObject];
  24.208 +    if( card ) {
  24.209 +        [[card retain] autorelease];
  24.210 +        [_cards removeLastObject];
  24.211 +        _bit = nil;   // keep it from being removed from superlayer by _showTopCard
  24.212 +        [self x_showTopCard];
  24.213 +    }
  24.214 +    return card;
  24.215 +}
  24.216 +
  24.217 +
  24.218 +- (NSArray*) removeAllCards
  24.219 +{
  24.220 +    NSArray *removedCards = [[_cards retain] autorelease];
  24.221 +    self.cards = [NSMutableArray array];
  24.222 +    [removedCards makeObjectsPerformSelector: @selector(removeFromSuperlayer)];
  24.223 +    [self x_showTopCard];
  24.224 +    return removedCards;
  24.225 +}
  24.226 +
  24.227 +
  24.228 +#pragma mark -
  24.229 +#pragma mark BITHOLDER INTERFACE:
  24.230 +
  24.231 +
  24.232 +- (Bit*) canDragBit: (Bit*)bit
  24.233 +{
  24.234 +    if( bit == _bit ) {
  24.235 +        [bit retain];
  24.236 +        [_cards removeObjectIdenticalTo: bit];
  24.237 +        _bit = nil;   // prevent the card from being removed from my layer
  24.238 +        [self x_showTopCard];
  24.239 +        return [bit autorelease];
  24.240 +    } else
  24.241 +        return nil;
  24.242 +}
  24.243 +
  24.244 +- (void) cancelDragBit: (Bit*)bit
  24.245 +{
  24.246 +    [self addCard: (Card*)bit];
  24.247 +}
  24.248 +
  24.249 +- (void) draggedBit: (Bit*)bit to: (id<BitHolder>)dst   {}
  24.250 +
  24.251 +
  24.252 +- (void) setHighlighted: (BOOL)h    
  24.253 +{
  24.254 +    [super setHighlighted: h];
  24.255 +    self.borderWidth = h ?6 :0;
  24.256 +}
  24.257 +
  24.258 +- (BOOL) canDropBit: (Bit*)bit atPoint: (CGPoint)point
  24.259 +{
  24.260 +    return [bit isKindOfClass: [Card class]] || [bit isKindOfClass: [DraggedStack class]];
  24.261 +}
  24.262 +
  24.263 +- (BOOL) dropBit: (Bit*)bit atPoint: (CGPoint)point
  24.264 +{
  24.265 +    return [self addBit: bit];
  24.266 +}
  24.267 +
  24.268 +
  24.269 +
  24.270 +@end
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/Source/DemoBoardView.h	Fri Mar 07 11:43:02 2008 -0800
    25.3 @@ -0,0 +1,35 @@
    25.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    25.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    25.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    25.7 +
    25.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    25.9 +    provided that the following conditions are met:
   25.10 +
   25.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   25.12 +      and the following disclaimer.
   25.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   25.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   25.15 +      with the distribution.
   25.16 +
   25.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   25.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   25.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   25.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   25.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   25.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   25.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   25.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25.25 +*/
   25.26 +#import "BoardView.h"
   25.27 +
   25.28 +
   25.29 +/** Simple subclass of BoardView that lets you pick a game from a menu,
   25.30 +    and displays the game status in a headline. */
   25.31 +@interface DemoBoardView : BoardView
   25.32 +{
   25.33 +    CATextLayer *_headline;
   25.34 +}
   25.35 +
   25.36 +- (IBAction) startGameFromMenu: (id)sender;
   25.37 +
   25.38 +@end
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/Source/DemoBoardView.m	Fri Mar 07 11:43:02 2008 -0800
    26.3 @@ -0,0 +1,137 @@
    26.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    26.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    26.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    26.7 +
    26.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    26.9 +    provided that the following conditions are met:
   26.10 +
   26.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   26.12 +      and the following disclaimer.
   26.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   26.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   26.15 +      with the distribution.
   26.16 +
   26.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   26.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   26.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   26.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   26.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   26.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   26.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   26.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26.25 +*/
   26.26 +#import "DemoBoardView.h"
   26.27 +#import "Game.h"
   26.28 +#import "QuartzUtils.h"
   26.29 +
   26.30 +
   26.31 +/**  WARNING: THIS CODE REQUIRES GARBAGE COLLECTION!
   26.32 + **  This sample application uses Objective-C 2.0 garbage collection.
   26.33 + **  Therefore, the source code in this file does NOT perform manual object memory management.
   26.34 + **  If you reuse any of this code in a process that isn't garbage collected, you will need to
   26.35 + **  add all necessary retain/release/autorelease calls, and implement -dealloc methods,
   26.36 + **  otherwise unpleasant leakage will occur!
   26.37 + **/
   26.38 +
   26.39 +
   26.40 +@implementation DemoBoardView
   26.41 +
   26.42 +
   26.43 +/** Class names of available games */
   26.44 +static NSString* const kMenuGameNames[] = {@"KlondikeGame", @"CheckersGame", @"HexchequerGame",
   26.45 +                                           @"TicTacToeGame", @"GoGame"};
   26.46 +
   26.47 +/** Class name of the current game. */
   26.48 +static NSString* sCurrentGameName = @"KlondikeGame";
   26.49 +
   26.50 +
   26.51 +- (void) startGameNamed: (NSString*)gameClassName
   26.52 +{
   26.53 +    [super startGameNamed: gameClassName];
   26.54 +    
   26.55 +    Game *game = self.game;
   26.56 +    [game addObserver: self 
   26.57 +           forKeyPath: @"currentPlayer"
   26.58 +              options: NSKeyValueObservingOptionInitial
   26.59 +              context: NULL];
   26.60 +    [game addObserver: self
   26.61 +           forKeyPath: @"winner"
   26.62 +              options: 0 
   26.63 +              context: NULL];
   26.64 +    
   26.65 +    self.window.title = [(id)[game class] displayName];
   26.66 +}
   26.67 +
   26.68 +
   26.69 +- (CGRect) gameBoardFrame
   26.70 +{
   26.71 +    CGRect bounds = [super gameBoardFrame];
   26.72 +    bounds.size.height -= 32;                   // Leave room for headline
   26.73 +    return CGRectInset(bounds,4,4);
   26.74 +}
   26.75 +
   26.76 +
   26.77 +- (void) awakeFromNib
   26.78 +{
   26.79 +    srandomdev();
   26.80 +    
   26.81 +    [self registerForDraggedTypes: [NSImage imagePasteboardTypes]];
   26.82 +    [self registerForDraggedTypes: [NSArray arrayWithObject: NSFilenamesPboardType]];
   26.83 +    
   26.84 +    CGRect bounds = self.layer.bounds;
   26.85 +    self.layer.backgroundColor = GetCGPatternNamed(@"/Library/Desktop Pictures/Small Ripples graphite.png");
   26.86 +        
   26.87 +    bounds.size.height -= 32;
   26.88 +    _headline = AddTextLayer(self.layer,
   26.89 +                             nil, [NSFont boldSystemFontOfSize: 24], 
   26.90 +                             kCALayerWidthSizable | kCALayerMinYMargin);
   26.91 +    
   26.92 +    [self startGameNamed: sCurrentGameName];
   26.93 +}
   26.94 +
   26.95 +
   26.96 +- (void) startGameFromMenu: (id)sender
   26.97 +{
   26.98 +    sCurrentGameName = kMenuGameNames[ [sender tag] ];
   26.99 +    [self startGameNamed: sCurrentGameName];
  26.100 +}
  26.101 +
  26.102 +
  26.103 +- (void)observeValueForKeyPath:(NSString *)keyPath 
  26.104 +                      ofObject:(id)object 
  26.105 +                        change:(NSDictionary *)change
  26.106 +                       context:(void *)context
  26.107 +{
  26.108 +    Game *game = self.game;
  26.109 +    if( object == game ) {
  26.110 +        Player *p = game.winner;
  26.111 +        NSString *msg;
  26.112 +        if( p ) {
  26.113 +            [[NSSound soundNamed: @"Sosumi"] play];
  26.114 +            msg = @"%@ wins! Congratulations!";
  26.115 +        } else {
  26.116 +            p = game.currentPlayer;
  26.117 +            msg = @"Your turn, %@";
  26.118 +        }
  26.119 +        _headline.string = [NSString stringWithFormat: msg, p.name];
  26.120 +    }
  26.121 +}
  26.122 +
  26.123 +
  26.124 +- (IBAction) enterFullScreen: (id)sender
  26.125 +{
  26.126 +    [super enterFullScreen: sender];
  26.127 +    [self startGameNamed: sCurrentGameName];        // restart game so it'll use the new size
  26.128 +}
  26.129 +
  26.130 +
  26.131 +#pragma mark -
  26.132 +#pragma mark NSAPPLICATION DELEGATE:
  26.133 +
  26.134 +
  26.135 +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
  26.136 +{
  26.137 +    return YES;
  26.138 +}
  26.139 +
  26.140 +@end
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/Source/DiscPiece.h	Fri Mar 07 11:43:02 2008 -0800
    27.3 @@ -0,0 +1,33 @@
    27.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    27.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    27.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    27.7 +
    27.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    27.9 +    provided that the following conditions are met:
   27.10 +
   27.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   27.12 +      and the following disclaimer.
   27.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   27.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   27.15 +      with the distribution.
   27.16 +
   27.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   27.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   27.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   27.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   27.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   27.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   27.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   27.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27.25 +*/
   27.26 +#import "Piece.h"
   27.27 +
   27.28 +
   27.29 +/** A Piece whose image is superimposed on a disc.
   27.30 +    Set the backgroundColor property to change the color or texture of the disc. */
   27.31 +@interface DiscPiece : Piece
   27.32 +{
   27.33 +    CALayer *_imageLayer;
   27.34 +}
   27.35 +
   27.36 +@end
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/Source/DiscPiece.m	Fri Mar 07 11:43:02 2008 -0800
    28.3 @@ -0,0 +1,57 @@
    28.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    28.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    28.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    28.7 +
    28.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    28.9 +    provided that the following conditions are met:
   28.10 +
   28.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   28.12 +      and the following disclaimer.
   28.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   28.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   28.15 +      with the distribution.
   28.16 +
   28.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   28.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   28.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   28.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   28.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   28.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   28.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   28.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28.25 +*/
   28.26 +#import "DiscPiece.h"
   28.27 +#import "QuartzUtils.h"
   28.28 +
   28.29 +
   28.30 +@implementation DiscPiece
   28.31 +
   28.32 +
   28.33 +- (void) setImage: (CGImageRef)image scale: (CGFloat)scale
   28.34 +{
   28.35 +    if( scale < 4.0 ) {
   28.36 +        int size = MAX(CGImageGetWidth(image), CGImageGetHeight(image));
   28.37 +        if( scale > 0 )
   28.38 +            scale = ceil( size * scale);
   28.39 +        else
   28.40 +            scale = size;
   28.41 +        scale *= 1.2;
   28.42 +    }
   28.43 +    self.bounds = CGRectMake(0,0,scale,scale);
   28.44 +    
   28.45 +    if( ! _imageLayer ) {
   28.46 +        _imageLayer = [[CALayer alloc] init];
   28.47 +        _imageLayer.contentsGravity = @"resizeAspect";
   28.48 +        [self addSublayer: _imageLayer];
   28.49 +        [_imageLayer release];
   28.50 +    }
   28.51 +    _imageLayer.frame = CGRectInset(self.bounds, scale*.1, scale*.1);
   28.52 +    _imageLayer.contents = (id) image;
   28.53 +    self.cornerRadius = scale/2;
   28.54 +    self.borderWidth = 3;
   28.55 +    self.borderColor = kTranslucentLightGrayColor;
   28.56 +    self.imageName = nil;
   28.57 +}
   28.58 +
   28.59 +
   28.60 +@end
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/Source/Dispenser.h	Fri Mar 07 11:43:02 2008 -0800
    29.3 @@ -0,0 +1,43 @@
    29.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    29.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    29.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    29.7 +
    29.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    29.9 +    provided that the following conditions are met:
   29.10 +
   29.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   29.12 +      and the following disclaimer.
   29.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   29.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   29.15 +      with the distribution.
   29.16 +
   29.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   29.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   29.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   29.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   29.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   29.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   29.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   29.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29.25 +*/
   29.26 +#import "BitHolder.h"
   29.27 +
   29.28 +
   29.29 +/** A Dispenser provides a supply of identical copies of a particular Bit, one at a time. */
   29.30 +
   29.31 +@interface Dispenser : BitHolder
   29.32 +{
   29.33 +    Bit *_prototype;
   29.34 +    unsigned _quantity;
   29.35 +}
   29.36 +
   29.37 +- (id) initWithPrototype: (Bit*)prototype quantity: (unsigned)quantity frame: (CGRect)frame;
   29.38 +
   29.39 +/** The Bit that will be copied. */
   29.40 +@property (retain) Bit *prototype;
   29.41 +
   29.42 +/** The number of Bits remaining; decremented whenever one is dragged out.
   29.43 +    When it hits zero, no more Bits will appear. */
   29.44 +@property unsigned quantity;
   29.45 +
   29.46 +@end
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/Source/Dispenser.m	Fri Mar 07 11:43:02 2008 -0800
    30.3 @@ -0,0 +1,194 @@
    30.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    30.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    30.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    30.7 +
    30.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    30.9 +    provided that the following conditions are met:
   30.10 +
   30.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   30.12 +      and the following disclaimer.
   30.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   30.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   30.15 +      with the distribution.
   30.16 +
   30.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   30.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   30.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   30.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   30.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   30.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   30.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   30.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30.25 +*/
   30.26 +#import "Dispenser.h"
   30.27 +#import "Piece.h"
   30.28 +#import "QuartzUtils.h"
   30.29 +#import "GGBUtils.h"
   30.30 +
   30.31 +
   30.32 +@implementation Dispenser
   30.33 +
   30.34 +
   30.35 +- (id) initWithPrototype: (Bit*)prototype quantity: (unsigned)quantity frame: (CGRect)frame
   30.36 +{
   30.37 +    self = [super init];
   30.38 +    if (self != nil) {
   30.39 +        self.backgroundColor = kTranslucentLightGrayColor;
   30.40 +        self.borderColor = kTranslucentGrayColor;
   30.41 +        self.borderWidth = 3;
   30.42 +        self.cornerRadius = 16;
   30.43 +        self.zPosition = kBoardZ;
   30.44 +        self.masksToBounds = YES;
   30.45 +        self.frame = frame;
   30.46 +        self.prototype = prototype;
   30.47 +        self.quantity = quantity;
   30.48 +    }
   30.49 +    return self;
   30.50 +}
   30.51 +
   30.52 +
   30.53 +- (void) dealloc
   30.54 +{
   30.55 +    [_prototype release];
   30.56 +    [super dealloc];
   30.57 +}
   30.58 +
   30.59 +
   30.60 +@synthesize bit=_bit;
   30.61 +
   30.62 +
   30.63 +- (Bit*) createBit
   30.64 +{
   30.65 +    if( _prototype ) {
   30.66 +        Bit *bit = [_prototype copy];
   30.67 +        CGRect bounds = self.bounds;
   30.68 +        bit.position = GetCGRectCenter(bounds);
   30.69 +        return [bit autorelease];
   30.70 +    } else
   30.71 +        return nil;
   30.72 +}
   30.73 +
   30.74 +- (void) x_regenerateCurrentBit
   30.75 +{
   30.76 +    NSAssert(_bit==nil,@"Already have a currentBit");
   30.77 +
   30.78 +    [CATransaction begin];
   30.79 +    [CATransaction setValue: (id)kCFBooleanTrue
   30.80 +                     forKey: kCATransactionDisableActions];
   30.81 +    self.bit = [self createBit];
   30.82 +    CGPoint pos = _bit.position;
   30.83 +    _bit.position = CGPointMake(pos.x, pos.y+70);
   30.84 +    [self addSublayer: _bit];
   30.85 +    [CATransaction commit];
   30.86 +    
   30.87 +    _bit.position = pos;
   30.88 +}
   30.89 +
   30.90 +
   30.91 +- (Bit*) prototype
   30.92 +{
   30.93 +    return _prototype;
   30.94 +}
   30.95 +
   30.96 +- (void) setPrototype: (Bit*)prototype
   30.97 +{
   30.98 +    setObj(&_prototype, prototype);
   30.99 +    if( _bit ) {
  30.100 +        [_bit removeFromSuperlayer];
  30.101 +        self.bit = nil;
  30.102 +        if( prototype )
  30.103 +            [self x_regenerateCurrentBit];
  30.104 +    }
  30.105 +}
  30.106 +
  30.107 +
  30.108 +- (unsigned) quantity
  30.109 +{
  30.110 +    return _quantity;
  30.111 +}
  30.112 +
  30.113 +- (void) setQuantity: (unsigned)quantity
  30.114 +{
  30.115 +    _quantity = quantity;
  30.116 +    if( quantity > 0 && !_bit )
  30.117 +        [self x_regenerateCurrentBit];
  30.118 +    else if( quantity==0 && _bit ) {
  30.119 +        [_bit removeFromSuperlayer];
  30.120 +        self.bit = nil;
  30.121 +    }
  30.122 +}
  30.123 +
  30.124 +
  30.125 +#pragma mark -
  30.126 +#pragma mark DRAGGING BITS:
  30.127 +
  30.128 +
  30.129 +- (Bit*) canDragBit: (Bit*)bit
  30.130 +{
  30.131 +    bit = [super canDragBit: bit];
  30.132 +    if( bit==_bit ) {
  30.133 +        [[bit retain] autorelease];
  30.134 +        self.bit = nil;
  30.135 +    }
  30.136 +    return bit;
  30.137 +}
  30.138 +
  30.139 +- (void) cancelDragBit: (Bit*)bit
  30.140 +{
  30.141 +    if( ! _bit )
  30.142 +        self.bit = bit;
  30.143 +    else
  30.144 +        [bit removeFromSuperlayer];
  30.145 +}
  30.146 +
  30.147 +- (void) draggedBit: (Bit*)bit to: (id<BitHolder>)dst
  30.148 +{
  30.149 +    if( --_quantity > 0 )
  30.150 +        [self performSelector: @selector(x_regenerateCurrentBit) withObject: nil afterDelay: 0.0];
  30.151 +}
  30.152 +
  30.153 +- (BOOL) canDropBit: (Bit*)bit atPoint: (CGPoint)point  
  30.154 +{
  30.155 +    return [bit isEqual: _bit];
  30.156 +}
  30.157 +
  30.158 +- (BOOL) dropBit: (Bit*)bit atPoint: (CGPoint)point
  30.159 +{
  30.160 +    [bit removeFromSuperlayer];
  30.161 +    return YES;
  30.162 +}
  30.163 +
  30.164 +
  30.165 +#pragma mark -
  30.166 +#pragma mark DRAG-AND-DROP:
  30.167 +
  30.168 +
  30.169 +// An image from another app can be dragged onto a Dispenser to change the Piece's appearance.
  30.170 +
  30.171 +
  30.172 +- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
  30.173 +{
  30.174 +    if( ! [_prototype isKindOfClass: [Piece class]] )
  30.175 +        return NSDragOperationNone;
  30.176 +    NSPasteboard *pb = [sender draggingPasteboard];
  30.177 +    if( [NSImage canInitWithPasteboard: pb] )
  30.178 +        return NSDragOperationCopy;
  30.179 +    else
  30.180 +        return NSDragOperationNone;
  30.181 +}
  30.182 +
  30.183 +- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
  30.184 +{
  30.185 +    if( ! [_prototype isKindOfClass: [Piece class]] )
  30.186 +        return NO;
  30.187 +    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
  30.188 +    if( image ) {
  30.189 +        [(Piece*)_prototype setImage: image];
  30.190 +        self.prototype = _prototype; // recreates _bit
  30.191 +        return YES;
  30.192 +    } else
  30.193 +        return NO;
  30.194 +}
  30.195 +
  30.196 +
  30.197 +@end
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/Source/GGBUtils.h	Fri Mar 07 11:43:02 2008 -0800
    31.3 @@ -0,0 +1,31 @@
    31.4 +/*  Copyright © 2008 Jens Alfke. All Rights Reserved.
    31.5 +
    31.6 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    31.7 +    provided that the following conditions are met:
    31.8 +
    31.9 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   31.10 +      and the following disclaimer.
   31.11 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   31.12 +      conditions and the following disclaimer in the documentation and/or other materials provided
   31.13 +      with the distribution.
   31.14 +
   31.15 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   31.16 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   31.17 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   31.18 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   31.19 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   31.20 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   31.21 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   31.22 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31.23 +*/
   31.24 +#import <Cocoa/Cocoa.h>
   31.25 +
   31.26 +/** Handy utility for assigning a new value to a retained instance variable. Use as:
   31.27 +        setObj(&_instanceVar, newValue);
   31.28 +    It releases the old value and retains the new one. */
   31.29 +
   31.30 +void setObj( id *variable, id newValue );
   31.31 +
   31.32 +
   31.33 +/** Just like setObj except that it _copies_ the new value. */
   31.34 +void setObjCopy( id<NSCopying> *variable, id<NSCopying> newValue );
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/Source/GGBUtils.m	Fri Mar 07 11:43:02 2008 -0800
    32.3 @@ -0,0 +1,38 @@
    32.4 +/*  Copyright © 2008 Jens Alfke. All Rights Reserved.
    32.5 +
    32.6 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    32.7 +    provided that the following conditions are met:
    32.8 +
    32.9 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   32.10 +      and the following disclaimer.
   32.11 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   32.12 +      conditions and the following disclaimer in the documentation and/or other materials provided
   32.13 +      with the distribution.
   32.14 +
   32.15 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   32.16 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   32.17 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   32.18 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   32.19 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   32.20 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   32.21 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   32.22 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32.23 +*/
   32.24 +#import "GGBUtils.h"
   32.25 +
   32.26 +
   32.27 +void setObj( id *variable, id newValue )
   32.28 +{
   32.29 +    if( *variable != newValue ) {
   32.30 +        [*variable release];
   32.31 +        *variable = [newValue retain];
   32.32 +    }
   32.33 +}
   32.34 +
   32.35 +void setObjCopy( id<NSCopying> *variable, id<NSCopying> newValue )
   32.36 +{
   32.37 +    if( *variable != newValue ) {
   32.38 +        [*variable release];
   32.39 +        *variable = [(id)newValue copy];
   32.40 +    }
   32.41 +}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/Source/Game.h	Fri Mar 07 11:43:02 2008 -0800
    33.3 @@ -0,0 +1,115 @@
    33.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    33.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    33.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    33.7 +
    33.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    33.9 +    provided that the following conditions are met:
   33.10 +
   33.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   33.12 +      and the following disclaimer.
   33.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   33.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   33.15 +      with the distribution.
   33.16 +
   33.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   33.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   33.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   33.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   33.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   33.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   33.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   33.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   33.25 +*/
   33.26 +#import <Cocoa/Cocoa.h>
   33.27 +@class Bit, Player;
   33.28 +@protocol BitHolder;
   33.29 +
   33.30 +
   33.31 +/** Abstract superclass. Keeps track of the rules and turns of a game. */
   33.32 +@interface Game : NSObject
   33.33 +{
   33.34 +    CALayer *_board;
   33.35 +    NSArray *_players;
   33.36 +    Player *_currentPlayer, *_winner;
   33.37 +}
   33.38 +
   33.39 +/** Returns the human-readable name of this game.
   33.40 +    (By default it just returns the class name with the "Game" suffix removed.) */
   33.41 ++ (NSString*) displayName;
   33.42 +
   33.43 +@property (readonly, copy) NSArray *players;
   33.44 +@property (readonly) Player *currentPlayer, *winner;
   33.45 +
   33.46 +
   33.47 +// Methods for subclasses to implement:
   33.48 +
   33.49 +/** Designated initializer. After calling the superclass implementation,
   33.50 +    it should add the necessary Grids, Pieces, Cards, Decks etc. to the board. */
   33.51 +- (id) initWithBoard: (CALayer*)board;
   33.52 +
   33.53 +/** Should return YES if it is legal for the given bit to be moved from its current holder.
   33.54 +    Default implementation always returns YES. */
   33.55 +- (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)src;
   33.56 +
   33.57 +/** Should return YES if it is legal for the given Bit to move from src to dst.
   33.58 +    Default implementation always returns YES. */
   33.59 +- (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)src to: (id<BitHolder>)dst;
   33.60 +
   33.61 +/** Should handle any side effects of a Bit's movement, such as captures or scoring.
   33.62 +    Does not need to do the actual movement! That's already happened.
   33.63 +    It should end by calling -endTurn, if the player's turn is over.
   33.64 +    Default implementation just calls -endTurn. */
   33.65 +- (void) bit: (Bit*)bit movedFrom: (id<BitHolder>)src to: (id<BitHolder>)dst;
   33.66 +
   33.67 +/** Called instead of the above if a Bit is simply clicked, not dragged.
   33.68 +    Should return NO if the click is illegal (i.e. clicking an empty draw pile in a card game.)
   33.69 +    Default implementation always returns YES. */
   33.70 +- (BOOL) clickedBit: (Bit*)bit;
   33.71 +
   33.72 +/** Should return the winning player, if the current position is a win, else nil.
   33.73 +    Default implementation returns nil. */
   33.74 +- (Player*) checkForWinner;
   33.75 +
   33.76 +
   33.77 +// Protected methods for subclasses to call:
   33.78 +
   33.79 +/** Sets the number of players in the game. Subclass initializers should call this. */
   33.80 +- (void) setNumberOfPlayers: (unsigned)n;
   33.81 +
   33.82 +/** Advance to the next player, when a turn is over. */
   33.83 +- (void) nextPlayer;
   33.84 +
   33.85 +/** Checks for a winner and advances to the next player. */
   33.86 +- (void) endTurn;
   33.87 +
   33.88 +@end
   33.89 +
   33.90 +
   33.91 +
   33.92 +/** A mostly-passive object used to represent a player. */
   33.93 +@interface Player : NSObject
   33.94 +{
   33.95 +    Game *_game;
   33.96 +    NSString *_name;
   33.97 +}
   33.98 +
   33.99 +- (id) initWithGame: (Game*)game;
  33.100 +
  33.101 +@property (readonly) Game *game;
  33.102 +@property (copy) NSString *name;
  33.103 +@property (readonly) int index;
  33.104 +@property (readonly, getter=isCurrent) BOOL current;
  33.105 +@property (readonly, getter=isFriendly) BOOL friendly;
  33.106 +@property (readonly, getter=isUnfriendly) BOOL unfriendly;
  33.107 +@property (readonly) Player *nextPlayer, *previousPlayer;
  33.108 +
  33.109 +@end
  33.110 +
  33.111 +
  33.112 +
  33.113 +@interface CALayer (Game)
  33.114 +
  33.115 +/** Called on any CALayer in the game's layer tree, will return the current Game object. */
  33.116 +@property (readonly) Game *game;
  33.117 +
  33.118 +@end
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/Source/Game.m	Fri Mar 07 11:43:02 2008 -0800
    34.3 @@ -0,0 +1,212 @@
    34.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    34.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    34.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    34.7 +
    34.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    34.9 +    provided that the following conditions are met:
   34.10 +
   34.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   34.12 +      and the following disclaimer.
   34.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   34.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   34.15 +      with the distribution.
   34.16 +
   34.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   34.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   34.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   34.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   34.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   34.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   34.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   34.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   34.25 +*/
   34.26 +#import "Game.h"
   34.27 +#import "Bit.h"
   34.28 +
   34.29 +
   34.30 +@interface Game ()
   34.31 +@property (copy) NSArray *players;
   34.32 +@property (assign) Player *currentPlayer, *winner;
   34.33 +@end
   34.34 +
   34.35 +
   34.36 +/**  WARNING: THIS CODE REQUIRES GARBAGE COLLECTION!
   34.37 + **  This sample application uses Objective-C 2.0 garbage collection.
   34.38 + **  Therefore, the source code in this file does NOT perform manual object memory management.
   34.39 + **  If you reuse any of this code in a process that isn't garbage collected, you will need to
   34.40 + **  add all necessary retain/release/autorelease calls, and implement -dealloc methods,
   34.41 + **  otherwise unpleasant leakage will occur!
   34.42 + **/
   34.43 +
   34.44 +
   34.45 +@implementation Game
   34.46 +
   34.47 +
   34.48 ++ (NSString*) displayName
   34.49 +{
   34.50 +    NSString* name = [self description];
   34.51 +    if( [name hasSuffix: @"Game"] )
   34.52 +        name = [name substringToIndex: name.length-4];
   34.53 +    return name;
   34.54 +}
   34.55 +
   34.56 +
   34.57 +- (id) initWithBoard: (CALayer*)board
   34.58 +{
   34.59 +    self = [super init];
   34.60 +    if (self != nil) {
   34.61 +        _board = [board retain];
   34.62 +        // Store a pointer to myself as the value of the "Game" property
   34.63 +        // of my root layer. (CALayers can have arbitrary KV properties stored into them.)
   34.64 +        // This is used by the -[CALayer game] category method defined below, to find the Game.
   34.65 +        [board setValue: self forKey: @"Game"];
   34.66 +    }
   34.67 +    return self;
   34.68 +}
   34.69 +
   34.70 +
   34.71 +- (void) dealloc
   34.72 +{
   34.73 +    [_board release];
   34.74 +    [_players release];
   34.75 +    [super dealloc];
   34.76 +}
   34.77 +
   34.78 +
   34.79 +@synthesize players=_players, currentPlayer=_currentPlayer, winner=_winner;
   34.80 +
   34.81 +
   34.82 +- (void) setNumberOfPlayers: (unsigned)n
   34.83 +{
   34.84 +    NSMutableArray *players = [NSMutableArray arrayWithCapacity: n];
   34.85 +    for( int i=1; i<=n; i++ ) {
   34.86 +        Player *player = [[Player alloc] initWithGame: self];
   34.87 +        player.name = [NSString stringWithFormat: @"Player %i",i];
   34.88 +        [players addObject: player];
   34.89 +        [player release];
   34.90 +    }
   34.91 +    self.winner = nil;
   34.92 +    self.currentPlayer = nil;
   34.93 +    self.players = players;
   34.94 +}
   34.95 +
   34.96 +
   34.97 +- (void) nextPlayer
   34.98 +{
   34.99 +    if( ! _currentPlayer ) {
  34.100 +        NSLog(@"*** The %@ Begins! ***", self.class);
  34.101 +        self.currentPlayer = [_players objectAtIndex: 0];
  34.102 +    } else {
  34.103 +        self.currentPlayer = _currentPlayer.nextPlayer;
  34.104 +    }
  34.105 +    NSLog(@"Current player is %@",_currentPlayer);
  34.106 +}
  34.107 +
  34.108 +
  34.109 +- (void) endTurn
  34.110 +{
  34.111 +    NSLog(@"--- End of turn");
  34.112 +    Player *winner = [self checkForWinner];
  34.113 +    if( winner ) {
  34.114 +        NSLog(@"*** The %@ Ends! The winner is %@ ! ***", self.class, winner);
  34.115 +        self.winner = winner;
  34.116 +    } else
  34.117 +        [self nextPlayer];
  34.118 +}
  34.119 +
  34.120 +
  34.121 +#pragma mark -
  34.122 +#pragma mark GAMEPLAY METHODS TO BE OVERRIDDEN:
  34.123 +
  34.124 +
  34.125 +- (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)src
  34.126 +{
  34.127 +    return YES;
  34.128 +}
  34.129 +
  34.130 +- (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)src to: (id<BitHolder>)dst
  34.131 +{
  34.132 +    return YES;
  34.133 +}
  34.134 +
  34.135 +- (void) bit: (Bit*)bit movedFrom: (id<BitHolder>)src to: (id<BitHolder>)dst
  34.136 +{
  34.137 +    [self endTurn];
  34.138 +}
  34.139 +
  34.140 +- (BOOL) clickedBit: (Bit*)bit
  34.141 +{
  34.142 +    return YES;
  34.143 +}
  34.144 +
  34.145 +- (Player*) checkForWinner
  34.146 +{
  34.147 +    return nil;
  34.148 +}
  34.149 +
  34.150 +
  34.151 +@end
  34.152 +
  34.153 +
  34.154 +
  34.155 +
  34.156 +@implementation Player
  34.157 +
  34.158 +
  34.159 +- (id) initWithGame: (Game*)game
  34.160 +{
  34.161 +    self = [super init];
  34.162 +    if (self != nil) {
  34.163 +        _game = game;
  34.164 +    }
  34.165 +    return self;
  34.166 +}
  34.167 +
  34.168 +
  34.169 +@synthesize game=_game, name=_name;
  34.170 +
  34.171 +- (BOOL) isCurrent      {return self == _game.currentPlayer;}
  34.172 +- (BOOL) isFriendly     {return self == _game.currentPlayer;}   // could be overridden for games with partners
  34.173 +- (BOOL) isUnfriendly   {return ! self.friendly;}
  34.174 +
  34.175 +- (int) index
  34.176 +{
  34.177 +    return [_game.players indexOfObjectIdenticalTo: self];
  34.178 +}
  34.179 +
  34.180 +- (Player*) nextPlayer
  34.181 +{
  34.182 +    return [_game.players objectAtIndex: (self.index+1) % _game.players.count];
  34.183 +}
  34.184 +
  34.185 +- (Player*) previousPlayer
  34.186 +{
  34.187 +    return [_game.players objectAtIndex: (self.index-1) % _game.players.count];
  34.188 +}
  34.189 +
  34.190 +- (NSString*) description
  34.191 +{
  34.192 +    return [NSString stringWithFormat: @"%@[%@]", self.class,self.name];
  34.193 +}
  34.194 +
  34.195 +@end
  34.196 +
  34.197 +
  34.198 +
  34.199 +
  34.200 +@implementation CALayer (Game)
  34.201 +
  34.202 +- (Game*) game
  34.203 +{
  34.204 +    // The Game object stores a pointer to itself as the value of the "Game" property
  34.205 +    // of its root layer. (CALayers can have arbitrary KV properties stored into them.)
  34.206 +    for( CALayer *layer = self; layer; layer=layer.superlayer ) {
  34.207 +        Game *game = [layer valueForKey: @"Game"];
  34.208 +        if( game )
  34.209 +            return game;
  34.210 +    }
  34.211 +    NSAssert1(NO,@"Couldn't look up Game from %@",self);
  34.212 +    return nil;
  34.213 +}
  34.214 +
  34.215 +@end
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/Source/GeekGameBoard_Prefix.pch	Fri Mar 07 11:43:02 2008 -0800
    35.3 @@ -0,0 +1,31 @@
    35.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    35.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    35.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    35.7 +
    35.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    35.9 +    provided that the following conditions are met:
   35.10 +
   35.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   35.12 +      and the following disclaimer.
   35.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   35.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   35.15 +      with the distribution.
   35.16 +
   35.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   35.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   35.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   35.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   35.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   35.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   35.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   35.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   35.25 +*/
   35.26 +
   35.27 +//
   35.28 +// Prefix header for all source files of the 'GeekGameBoard' target in the 'GeekGameBoard' project
   35.29 +//
   35.30 +
   35.31 +#ifdef __OBJC__
   35.32 +    #import <Cocoa/Cocoa.h>
   35.33 +    #import <Quartz/Quartz.h>
   35.34 +#endif
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/Source/GoGame.h	Fri Mar 07 11:43:02 2008 -0800
    36.3 @@ -0,0 +1,35 @@
    36.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    36.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    36.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    36.7 +
    36.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    36.9 +    provided that the following conditions are met:
   36.10 +
   36.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   36.12 +      and the following disclaimer.
   36.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   36.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   36.15 +      with the distribution.
   36.16 +
   36.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   36.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   36.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   36.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   36.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   36.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   36.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   36.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   36.25 +*/
   36.26 +#import "Game.h"
   36.27 +@class RectGrid, Stack;
   36.28 +
   36.29 +
   36.30 +/** The Asian board game Go.
   36.31 +    See: http://en.wikipedia.org/wiki/Go_%28board_game%29 */
   36.32 +@interface GoGame : Game
   36.33 +{
   36.34 +    RectGrid *_grid;
   36.35 +    Stack *_captured[2];
   36.36 +}
   36.37 +
   36.38 +@end
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/Source/GoGame.m	Fri Mar 07 11:43:02 2008 -0800
    37.3 @@ -0,0 +1,166 @@
    37.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    37.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    37.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    37.7 +
    37.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    37.9 +    provided that the following conditions are met:
   37.10 +
   37.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   37.12 +      and the following disclaimer.
   37.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   37.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   37.15 +      with the distribution.
   37.16 +
   37.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   37.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   37.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   37.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   37.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   37.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   37.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   37.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   37.25 +*/
   37.26 +#import "GoGame.h"
   37.27 +#import "Grid.h"
   37.28 +#import "Piece.h"
   37.29 +#import "Dispenser.h"
   37.30 +#import "Stack.h"
   37.31 +#import "QuartzUtils.h"
   37.32 +
   37.33 +
   37.34 +@implementation GoGame
   37.35 +
   37.36 +
   37.37 +- (void) x_createDispenser: (NSString*)imageName position: (CGPoint)position forPlayer: (unsigned)playerNo
   37.38 +{
   37.39 +    CGFloat pieceSize = (int)(_grid.spacing.width * 0.9) & ~1;  // make sure it's even
   37.40 +    Piece *stone = [[Piece alloc] initWithImageNamed: imageName scale: pieceSize];
   37.41 +    stone.owner = [self.players objectAtIndex: playerNo];
   37.42 +    CGRect frame = {position, {1.5*pieceSize,1.5*pieceSize}};
   37.43 +    Dispenser *disp = [[Dispenser alloc] initWithPrototype: stone quantity: INT_MAX frame:frame];
   37.44 +    [_board addSublayer: disp];
   37.45 +    [disp release];
   37.46 +    [stone release];
   37.47 +}    
   37.48 +
   37.49 +
   37.50 +- (id) initWithBoard: (CALayer*)board
   37.51 +{
   37.52 +    self = [super initWithBoard: board];
   37.53 +    if (self != nil) {
   37.54 +        [self setNumberOfPlayers: 2];
   37.55 +        
   37.56 +        CGSize size = board.bounds.size;
   37.57 +        RectGrid *grid = [[RectGrid alloc] initWithRows: 9 columns: 9 
   37.58 +                                                  frame: CGRectMake((size.width-size.height+16)/2,8,
   37.59 +                                                                    size.height-16,size.height-16)];
   37.60 +        _grid = grid;
   37.61 +        grid.backgroundColor = GetCGPatternNamed(@"Wood.jpg");
   37.62 +        grid.borderColor = kTranslucentLightGrayColor;
   37.63 +        grid.borderWidth = 2;
   37.64 +        grid.lineColor = kTranslucentGrayColor;
   37.65 +        grid.cellClass = [GoSquare class];
   37.66 +        [grid addAllCells];
   37.67 +        ((GoSquare*)[grid cellAtRow: 2 column: 2]).dotted = YES;
   37.68 +        ((GoSquare*)[grid cellAtRow: 6 column: 6]).dotted = YES;
   37.69 +        ((GoSquare*)[grid cellAtRow: 2 column: 6]).dotted = YES;
   37.70 +        ((GoSquare*)[grid cellAtRow: 6 column: 2]).dotted = YES;
   37.71 +        grid.usesDiagonals = grid.allowsMoves = grid.allowsCaptures = NO;
   37.72 +        [board addSublayer: grid];
   37.73 +        [grid release];
   37.74 +        
   37.75 +        CGRect gridFrame = grid.frame;
   37.76 +        CGFloat pieceSize = (int)grid.spacing.width & ~1;  // make sure it's even
   37.77 +        [self x_createDispenser: @"Red Ball.png"
   37.78 +                      position: CGPointMake(CGRectGetMinX(gridFrame)-2*pieceSize, 
   37.79 +                                            CGRectGetMinY(gridFrame))
   37.80 +                     forPlayer: 0];
   37.81 +        [self x_createDispenser: @"White Ball.png"
   37.82 +                      position: CGPointMake(CGRectGetMaxX(gridFrame)+0.5*pieceSize,
   37.83 +                                            CGRectGetMaxY(gridFrame)-1.5*pieceSize)
   37.84 +                     forPlayer: 1];
   37.85 +        
   37.86 +        CGFloat captureHeight = gridFrame.size.height-4*pieceSize;
   37.87 +        _captured[0] = [[Stack alloc] initWithStartPos: CGPointMake(2*pieceSize,0)
   37.88 +                                               spacing: CGSizeMake(0,pieceSize)
   37.89 +                                          wrapInterval: floor(captureHeight/pieceSize)
   37.90 +                                           wrapSpacing: CGSizeMake(-pieceSize,0)];
   37.91 +        _captured[0].frame = CGRectMake(CGRectGetMinX(gridFrame)-3*pieceSize, 
   37.92 +                                          CGRectGetMinY(gridFrame)+3*pieceSize,
   37.93 +                                          2*pieceSize, captureHeight);
   37.94 +        _captured[0].zPosition = kPieceZ+1;
   37.95 +        [board addSublayer: _captured[0]];
   37.96 +        [_captured[0] release];
   37.97 +        
   37.98 +        _captured[1] = [[Stack alloc] initWithStartPos: CGPointMake(0,captureHeight)
   37.99 +                                               spacing: CGSizeMake(0,-pieceSize)
  37.100 +                                          wrapInterval: floor(captureHeight/pieceSize)
  37.101 +                                           wrapSpacing: CGSizeMake(pieceSize,0)];
  37.102 +        _captured[1].frame = CGRectMake(CGRectGetMaxX(gridFrame)+pieceSize, 
  37.103 +                                          CGRectGetMinY(gridFrame)+pieceSize,
  37.104 +                                          2*pieceSize, captureHeight);
  37.105 +        _captured[1].zPosition = kPieceZ+1;
  37.106 +        [board addSublayer: _captured[1]];
  37.107 +        [_captured[1] release];
  37.108 +
  37.109 +        [self nextPlayer];
  37.110 +}
  37.111 +    return self;
  37.112 +}
  37.113 +
  37.114 +
  37.115 +- (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
  37.116 +{
  37.117 +    Square *dst=(Square*)dstHolder;
  37.118 +    
  37.119 +    // There should be a check here for a "ko" (repeated position) ... exercise for the reader!
  37.120 +    
  37.121 +    // Check for suicidal move. First an easy check for an empty adjacent space:
  37.122 +    NSArray *neighbors = dst.neighbors;
  37.123 +    for( GridCell *c in neighbors )
  37.124 +        if( c.empty )
  37.125 +            return YES;                     // there's an empty space
  37.126 +    // If the piece is surrounded, check the neighboring groups' liberties:
  37.127 +    for( GridCell *c in neighbors ) {
  37.128 +        int nLiberties;
  37.129 +        [c getGroup: &nLiberties];
  37.130 +        if( c.bit.unfriendly ) {
  37.131 +            if( nLiberties <= 1 )
  37.132 +                return YES;             // the move captures, so it's not suicidal
  37.133 +        } else {
  37.134 +            if( nLiberties > 1 )
  37.135 +                return YES;             // the stone joins a group with other liberties
  37.136 +        }
  37.137 +    }
  37.138 +    return NO;
  37.139 +}
  37.140 +
  37.141 +
  37.142 +- (void) bit: (Bit*)bit movedFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
  37.143 +{
  37.144 +    Square *dst=(Square*)dstHolder;
  37.145 +    int curIndex = _currentPlayer.index;
  37.146 +    // Check for captured enemy groups:
  37.147 +    BOOL captured = NO;
  37.148 +    for( GridCell *c in dst.neighbors )
  37.149 +        if( c.bit.unfriendly ) {
  37.150 +            int nLiberties;
  37.151 +            NSSet *group = [c getGroup: &nLiberties];
  37.152 +            if( nLiberties == 0 ) {
  37.153 +                captured = YES;
  37.154 +                for( GridCell *capture in group )
  37.155 +                    [_captured[curIndex] addBit: capture.bit];  // Moves piece to POW camp!
  37.156 +            }
  37.157 +        }
  37.158 +    if( captured )
  37.159 +        [[NSSound soundNamed: @"Pop"] play];
  37.160 +        
  37.161 +    [self nextPlayer];
  37.162 +}
  37.163 +
  37.164 +
  37.165 +// This sample code makes no attempt to detect the end of the game, or count score,
  37.166 +// both of which are rather complex to decide in Go.
  37.167 +
  37.168 +
  37.169 +@end
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/Source/Grid.h	Fri Mar 07 11:43:02 2008 -0800
    38.3 @@ -0,0 +1,139 @@
    38.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    38.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    38.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    38.7 +
    38.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    38.9 +    provided that the following conditions are met:
   38.10 +
   38.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   38.12 +      and the following disclaimer.
   38.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   38.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   38.15 +      with the distribution.
   38.16 +
   38.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   38.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   38.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   38.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   38.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   38.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   38.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   38.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   38.25 +*/
   38.26 +#import "BitHolder.h"
   38.27 +@class GridCell;
   38.28 +
   38.29 +
   38.30 +/** Abstract superclass of regular geometric grids of GridCells that Bits can be placed on. */
   38.31 +@interface Grid : CALayer
   38.32 +{
   38.33 +    unsigned _nRows, _nColumns;                         
   38.34 +    CGSize _spacing;                                    
   38.35 +    Class _cellClass;                                   
   38.36 +    CGColorRef _cellColor, _lineColor;                  
   38.37 +    BOOL _usesDiagonals, _allowsMoves, _allowsCaptures;
   38.38 +    NSMutableArray *_cells;                             // Really a 2D array, in row-major order.
   38.39 +}
   38.40 +
   38.41 +/** Initializes a new Grid with the given dimensions and cell size, and position in superview.
   38.42 +    Note that a new Grid has no cells! Either call -addAllCells, or -addCellAtRow:column:. */
   38.43 +- (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
   38.44 +            spacing: (CGSize)spacing
   38.45 +           position: (CGPoint)pos;
   38.46 +
   38.47 +/** Initializes a new Grid with the given dimensions and frame in superview.
   38.48 +    The cell size will be computed by dividing frame size by dimensions.
   38.49 +    Note that a new Grid has no cells! Either call -addAllCells, or -addCellAtRow:column:. */
   38.50 +- (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
   38.51 +              frame: (CGRect)frame;
   38.52 +
   38.53 +@property Class cellClass;                      // What kind of GridCells to create
   38.54 +@property (readonly) unsigned rows, columns;    // Dimensions of the grid
   38.55 +@property (readonly) CGSize spacing;            // x,y spacing of GridCells
   38.56 +@property CGColorRef cellColor, lineColor;      // Cell background color, line color (or nil)
   38.57 +@property BOOL usesDiagonals;                   // Affects GridCell.neighbors, for rect grids
   38.58 +@property BOOL allowsMoves, allowsCaptures;     // Can pieces be moved, and can they land on others?
   38.59 +
   38.60 +/** Returns the GridCell at the given coordinates, or nil if there is no cell there.
   38.61 +    It's OK to call this with off-the-board coordinates; it will just return nil.*/
   38.62 +- (GridCell*) cellAtRow: (unsigned)row column: (unsigned)col;
   38.63 +
   38.64 +/** Adds cells at all coordinates, creating a complete grid. */
   38.65 +- (void) addAllCells;
   38.66 +
   38.67 +/** Adds a GridCell at the given coordinates. */
   38.68 +- (GridCell*) addCellAtRow: (unsigned)row column: (unsigned)col;
   38.69 +
   38.70 +/** Removes a particular cell, leaving a blank space. */
   38.71 +- (void) removeCellAtRow: (unsigned)row column: (unsigned)col;
   38.72 +
   38.73 +
   38.74 +// protected:
   38.75 +- (GridCell*) createCellAtRow: (unsigned)row column: (unsigned)col 
   38.76 +               suggestedFrame: (CGRect)frame;
   38.77 +
   38.78 +@end
   38.79 +
   38.80 +
   38.81 +/** Abstract superclass of a single cell in a grid. */
   38.82 +@interface GridCell : BitHolder
   38.83 +{
   38.84 +    Grid *_grid;
   38.85 +    unsigned _row, _column;
   38.86 +}
   38.87 +
   38.88 +- (id) initWithGrid: (Grid*)grid 
   38.89 +                row: (unsigned)row column: (unsigned)col
   38.90 +              frame: (CGRect)frame;
   38.91 +
   38.92 +@property (readonly) Grid* grid;
   38.93 +@property (readonly) unsigned row, column;
   38.94 +@property (readonly) NSArray* neighbors;        // Dependent on grid.usesDiagonals
   38.95 +
   38.96 +/** Returns YES if 'forward' is north (increasing row#) for the current player */
   38.97 +@property (readonly) BOOL fwdIsN;
   38.98 +
   38.99 +/* Go-style group detection. Returns the set of contiguous GridCells that have pieces of the same
  38.100 +   owner as this one, and optionally a count of the number of "liberties", or adjacent empty cells. */
  38.101 +- (NSSet*) getGroup: (int*)outLiberties;
  38.102 +
  38.103 +// protected:
  38.104 +- (void) drawInParentContext: (CGContextRef)ctx fill: (BOOL)fill;
  38.105 +@end
  38.106 +
  38.107 +
  38.108 +
  38.109 +/** A rectangular grid of squares. */
  38.110 +@interface RectGrid : Grid
  38.111 +{
  38.112 +    CGColorRef _altCellColor;
  38.113 +}
  38.114 +
  38.115 +/** If non-nil, alternate cells will be drawn with this background color, in a checkerboard pattern.
  38.116 +    The precise rule is that cells whose row+column is odd use the altCellColor.*/
  38.117 +@property CGColorRef altCellColor;
  38.118 +
  38.119 +@end
  38.120 +
  38.121 +
  38.122 +
  38.123 +/* A square in a RectGrid */
  38.124 +@interface Square : GridCell
  38.125 +
  38.126 +@property (readonly) Square *nw, *n, *ne, *e, *se, *s, *sw, *w;    // Absolute directions (n = increasing row#)
  38.127 +@property (readonly) Square *fl, *f, *fr, *r, *br, *b, *bl, *l;    // Relative to player (upside-down for player 2)
  38.128 +
  38.129 +@end
  38.130 +
  38.131 +
  38.132 +/* Substitute this for Square in a RectGrid's cellClass to draw the lines through the centers
  38.133 +   of the squares, so the pieces sit on the intersections, as in a Go board. */
  38.134 +@interface GoSquare : Square
  38.135 +{
  38.136 +    BOOL _dotted;
  38.137 +}
  38.138 +
  38.139 +/** Set to YES to put a dot at the intersection, as in the handicap points of a Go board. */
  38.140 +@property BOOL dotted;
  38.141 +
  38.142 +@end
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/Source/Grid.m	Fri Mar 07 11:43:02 2008 -0800
    39.3 @@ -0,0 +1,486 @@
    39.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    39.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    39.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    39.7 +
    39.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    39.9 +    provided that the following conditions are met:
   39.10 +
   39.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   39.12 +      and the following disclaimer.
   39.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   39.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   39.15 +      with the distribution.
   39.16 +
   39.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   39.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   39.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   39.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   39.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   39.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   39.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   39.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   39.25 +*/
   39.26 +#import "Grid.h"
   39.27 +#import "Bit.h"
   39.28 +#import "Game.h"
   39.29 +#import "QuartzUtils.h"
   39.30 +
   39.31 +
   39.32 +@implementation Grid
   39.33 +
   39.34 +
   39.35 +- (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
   39.36 +            spacing: (CGSize)spacing
   39.37 +           position: (CGPoint)pos
   39.38 +{
   39.39 +    NSParameterAssert(nRows>0 && nColumns>0);
   39.40 +    self = [super init];
   39.41 +    if( self ) {
   39.42 +        _nRows = nRows;
   39.43 +        _nColumns = nColumns;
   39.44 +        _spacing = spacing;
   39.45 +        _cellClass = [GridCell class];
   39.46 +        _lineColor = kBlackColor;
   39.47 +        _allowsMoves = YES;
   39.48 +        _usesDiagonals = YES;
   39.49 +
   39.50 +        self.bounds = CGRectMake(-1, -1, nColumns*spacing.width+2, nRows*spacing.height+2);
   39.51 +        self.position = pos;
   39.52 +        self.anchorPoint = CGPointMake(0,0);
   39.53 +        self.zPosition = kBoardZ;
   39.54 +        self.needsDisplayOnBoundsChange = YES;
   39.55 +        
   39.56 +        unsigned n = nRows*nColumns;
   39.57 +        _cells = [[NSMutableArray alloc] initWithCapacity: n];
   39.58 +        id null = [NSNull null];
   39.59 +        while( n-- > 0 )
   39.60 +            [_cells addObject: null];
   39.61 +
   39.62 +        [self setNeedsDisplay];
   39.63 +    }
   39.64 +    return self;
   39.65 +}
   39.66 +
   39.67 +
   39.68 +- (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
   39.69 +              frame: (CGRect)frame
   39.70 +{
   39.71 +    CGFloat spacing = floor(MIN( (frame.size.width -2)/(CGFloat)nColumns,
   39.72 +                               (frame.size.height-2)/(CGFloat)nRows) );
   39.73 +    return [self initWithRows: nRows columns: nColumns
   39.74 +                      spacing: CGSizeMake(spacing,spacing)
   39.75 +                     position: frame.origin];
   39.76 +}
   39.77 +
   39.78 +
   39.79 +- (void) dealloc
   39.80 +{
   39.81 +    CGColorRelease(_cellColor);
   39.82 +    CGColorRelease(_lineColor);
   39.83 +    [_cells release];
   39.84 +    [super dealloc];
   39.85 +}
   39.86 +
   39.87 +
   39.88 +static void setcolor( CGColorRef *var, CGColorRef color )
   39.89 +{
   39.90 +    if( color != *var ) {
   39.91 +        CGColorRelease(*var);
   39.92 +        *var = CGColorRetain(color);
   39.93 +    }
   39.94 +}
   39.95 +
   39.96 +- (CGColorRef) cellColor                        {return _cellColor;}
   39.97 +- (void) setCellColor: (CGColorRef)cellColor    {setcolor(&_cellColor,cellColor);}
   39.98 +
   39.99 +- (CGColorRef) lineColor                        {return _lineColor;}
  39.100 +- (void) setLineColor: (CGColorRef)lineColor    {setcolor(&_lineColor,lineColor);}
  39.101 +
  39.102 +@synthesize cellClass=_cellClass, rows=_nRows, columns=_nColumns, spacing=_spacing,
  39.103 +            usesDiagonals=_usesDiagonals, allowsMoves=_allowsMoves, allowsCaptures=_allowsCaptures;
  39.104 +
  39.105 +
  39.106 +#pragma mark -
  39.107 +#pragma mark GEOMETRY:
  39.108 +
  39.109 +
  39.110 +- (GridCell*) cellAtRow: (unsigned)row column: (unsigned)col
  39.111 +{
  39.112 +    if( row < _nRows && col < _nColumns ) {
  39.113 +        id cell = [_cells objectAtIndex: row*_nColumns+col];
  39.114 +        if( cell != [NSNull null] )
  39.115 +            return cell;
  39.116 +    }
  39.117 +    return nil;
  39.118 +}
  39.119 +
  39.120 +
  39.121 +/** Subclasses can override this, to change the cell's class or frame. */
  39.122 +- (GridCell*) createCellAtRow: (unsigned)row column: (unsigned)col 
  39.123 +               suggestedFrame: (CGRect)frame
  39.124 +{
  39.125 +    return [[[_cellClass alloc] initWithGrid: self 
  39.126 +                                        row: row column: col
  39.127 +                                      frame: frame]
  39.128 +                    autorelease];
  39.129 +}
  39.130 +
  39.131 +
  39.132 +- (GridCell*) addCellAtRow: (unsigned)row column: (unsigned)col
  39.133 +{
  39.134 +    NSParameterAssert(row<_nRows);
  39.135 +    NSParameterAssert(col<_nColumns);
  39.136 +    unsigned index = row*_nColumns+col;
  39.137 +    GridCell *cell = [_cells objectAtIndex: index];
  39.138 +    if( (id)cell == [NSNull null] ) {
  39.139 +        CGRect frame = CGRectMake(col*_spacing.width, row*_spacing.height,
  39.140 +                                  _spacing.width,_spacing.height);
  39.141 +        cell = [self createCellAtRow: row column: col suggestedFrame: frame];
  39.142 +        if( cell ) {
  39.143 +            [_cells replaceObjectAtIndex: index withObject: cell];
  39.144 +            [self addSublayer: cell];
  39.145 +            [self setNeedsDisplay];
  39.146 +        }
  39.147 +    }
  39.148 +    return cell;
  39.149 +}
  39.150 +
  39.151 +
  39.152 +- (void) addAllCells
  39.153 +{
  39.154 +    for( int row=_nRows-1; row>=0; row-- )                // makes 'upper' cells be in 'back'
  39.155 +        for( int col=0; col<_nColumns; col++ ) 
  39.156 +            [self addCellAtRow: row column: col];
  39.157 +}
  39.158 +
  39.159 +
  39.160 +- (void) removeCellAtRow: (unsigned)row column: (unsigned)col
  39.161 +{
  39.162 +    NSParameterAssert(row<_nRows);
  39.163 +    NSParameterAssert(col<_nColumns);
  39.164 +    unsigned index = row*_nColumns+col;
  39.165 +    id cell = [_cells objectAtIndex: index];
  39.166 +    if( cell != [NSNull null] )
  39.167 +        [cell removeFromSuperlayer];
  39.168 +    [_cells replaceObjectAtIndex: index withObject: [NSNull null]];
  39.169 +    [self setNeedsDisplay];
  39.170 +}
  39.171 +
  39.172 +
  39.173 +#pragma mark -
  39.174 +#pragma mark DRAWING:
  39.175 +
  39.176 +
  39.177 +- (void) drawCellsInContext: (CGContextRef)ctx fill: (BOOL)fill
  39.178 +{
  39.179 +    // Subroutine of -drawInContext:. Draws all the cells, with or without a fill.
  39.180 +    for( unsigned row=0; row<_nRows; row++ )
  39.181 +        for( unsigned col=0; col<_nColumns; col++ ) {
  39.182 +            GridCell *cell = [self cellAtRow: row column: col];
  39.183 +            if( cell )
  39.184 +                [cell drawInParentContext: ctx fill: fill];
  39.185 +        }
  39.186 +}
  39.187 +
  39.188 +
  39.189 +- (void)drawInContext:(CGContextRef)ctx
  39.190 +{
  39.191 +    // Custom CALayer drawing implementation. Delegates to the cells to draw themselves
  39.192 +    // in me; this is more efficient than having each cell have its own drawing.
  39.193 +    if( _cellColor ) {
  39.194 +        CGContextSetFillColorWithColor(ctx, _cellColor);
  39.195 +        [self drawCellsInContext: ctx fill: YES];
  39.196 +    }
  39.197 +    if( _lineColor ) {
  39.198 +        CGContextSetStrokeColorWithColor(ctx,_lineColor);
  39.199 +        [self drawCellsInContext:ctx fill: NO];
  39.200 +    }
  39.201 +}
  39.202 +
  39.203 +
  39.204 +@end
  39.205 +
  39.206 +
  39.207 +
  39.208 +#pragma mark -
  39.209 +
  39.210 +@implementation GridCell
  39.211 +
  39.212 +
  39.213 +- (id) initWithGrid: (Grid*)grid 
  39.214 +                row: (unsigned)row column: (unsigned)col
  39.215 +              frame: (CGRect)frame
  39.216 +{
  39.217 +    self = [super init];
  39.218 +    if (self != nil) {
  39.219 +        _grid = grid;
  39.220 +        _row = row;
  39.221 +        _column = col;
  39.222 +        self.position = frame.origin;
  39.223 +        CGRect bounds = frame;
  39.224 +        bounds.origin.x -= floor(bounds.origin.x);  // make sure my coords fall on pixel boundaries
  39.225 +        bounds.origin.y -= floor(bounds.origin.y);
  39.226 +        self.bounds = bounds;
  39.227 +        self.anchorPoint = CGPointMake(0,0);
  39.228 +        self.borderColor = kHighlightColor;         // Used when highlighting (see -setHighlighted:)
  39.229 +    }
  39.230 +    return self;
  39.231 +}
  39.232 +
  39.233 +- (NSString*) description
  39.234 +{
  39.235 +    return [NSString stringWithFormat: @"%@(%u,%u)", [self class],_column,_row];
  39.236 +}
  39.237 +
  39.238 +@synthesize grid=_grid, row=_row, column=_column;
  39.239 +
  39.240 +
  39.241 +- (void) drawInParentContext: (CGContextRef)ctx fill: (BOOL)fill
  39.242 +{
  39.243 +    // Default implementation just fills or outlines the cell.
  39.244 +    CGRect frame = self.frame;
  39.245 +    if( fill )
  39.246 +        CGContextFillRect(ctx,frame);
  39.247 +    else
  39.248 +        CGContextStrokeRect(ctx, frame);
  39.249 +}
  39.250 +
  39.251 +
  39.252 +- (void) setBit: (Bit*)bit
  39.253 +{
  39.254 +    if( bit != self.bit ) {
  39.255 +        [super setBit: bit];
  39.256 +        if( bit ) {
  39.257 +            // Center it:
  39.258 +            CGSize size = self.bounds.size;
  39.259 +            bit.position = CGPointMake(floor(size.width/2.0),
  39.260 +                                       floor(size.height/2.0));
  39.261 +        }
  39.262 +    }
  39.263 +}
  39.264 +
  39.265 +- (Bit*) canDragBit: (Bit*)bit
  39.266 +{
  39.267 +    if( _grid.allowsMoves && bit==self.bit )
  39.268 +        return [super canDragBit: bit];
  39.269 +    else
  39.270 +        return nil;
  39.271 +}
  39.272 +
  39.273 +- (BOOL) canDropBit: (Bit*)bit atPoint: (CGPoint)point
  39.274 +{
  39.275 +    return self.bit == nil || _grid.allowsCaptures;
  39.276 +}
  39.277 +
  39.278 +
  39.279 +- (BOOL) fwdIsN 
  39.280 +{
  39.281 +    return self.game.currentPlayer.index == 0;
  39.282 +}
  39.283 +
  39.284 +
  39.285 +- (NSArray*) neighbors
  39.286 +{
  39.287 +    BOOL orthogonal = ! _grid.usesDiagonals;
  39.288 +    NSMutableArray *neighbors = [NSMutableArray arrayWithCapacity: 8];
  39.289 +    for( int dy=-1; dy<=1; dy++ )
  39.290 +        for( int dx=-1; dx<=1; dx++ )
  39.291 +            if( (dx || dy) && !(orthogonal && dx && dy) ) {
  39.292 +                GridCell *cell = [_grid cellAtRow: _row+dy column: _column+dx];
  39.293 +                if( cell )
  39.294 +                    [neighbors addObject: cell];
  39.295 +            }
  39.296 +    return neighbors;
  39.297 +}
  39.298 +
  39.299 +
  39.300 +// Recursive subroutine used by getGroup:.
  39.301 +- (void) x_addToGroup: (NSMutableSet*)group liberties: (NSMutableSet*)liberties owner: (Player*)owner
  39.302 +{
  39.303 +    Bit *bit = self.bit;
  39.304 +    if( bit == nil ) {
  39.305 +        if( [liberties containsObject: self] )
  39.306 +            return; // already traversed
  39.307 +        [liberties addObject: self];
  39.308 +    } else if( bit.owner==owner ) {
  39.309 +        if( [group containsObject: self] )
  39.310 +            return; // already traversed
  39.311 +        [group addObject: self];
  39.312 +        for( GridCell *c in self.neighbors )
  39.313 +            [c x_addToGroup: group liberties: liberties owner: owner];
  39.314 +    }
  39.315 +}
  39.316 +
  39.317 +
  39.318 +- (NSSet*) getGroup: (int*)outLiberties
  39.319 +{
  39.320 +    NSMutableSet *group=[NSMutableSet set], *liberties=nil;
  39.321 +    if( outLiberties )
  39.322 +        liberties = [NSMutableSet set];
  39.323 +    [self x_addToGroup: group liberties: liberties owner: self.bit.owner];
  39.324 +    if( outLiberties )
  39.325 +        *outLiberties = liberties.count;
  39.326 +    return group;
  39.327 +}
  39.328 +
  39.329 +
  39.330 +#pragma mark -
  39.331 +#pragma mark DRAG-AND-DROP:
  39.332 +
  39.333 +
  39.334 +// An image from another app can be dragged onto a Dispenser to change the Piece's appearance.
  39.335 +
  39.336 +
  39.337 +- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
  39.338 +{
  39.339 +    NSPasteboard *pb = [sender draggingPasteboard];
  39.340 +    if( [NSImage canInitWithPasteboard: pb] )
  39.341 +        return NSDragOperationCopy;
  39.342 +    else
  39.343 +        return NSDragOperationNone;
  39.344 +}
  39.345 +
  39.346 +- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
  39.347 +{
  39.348 +    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
  39.349 +    if( image ) {
  39.350 +        CGColorRef pattern = CreatePatternColor(image);
  39.351 +        _grid.cellColor = pattern;
  39.352 +        CGColorRelease(pattern);
  39.353 +        [_grid setNeedsDisplay];
  39.354 +        return YES;
  39.355 +    } else
  39.356 +        return NO;
  39.357 +}
  39.358 +
  39.359 +
  39.360 +@end
  39.361 +
  39.362 +
  39.363 +
  39.364 +
  39.365 +#pragma mark -
  39.366 +
  39.367 +@implementation RectGrid
  39.368 +
  39.369 +
  39.370 +- (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
  39.371 +            spacing: (CGSize)spacing
  39.372 +           position: (CGPoint)pos
  39.373 +{
  39.374 +    self = [super initWithRows: nRows columns: nColumns spacing: spacing position: pos];
  39.375 +    if( self ) {
  39.376 +        _cellClass = [Square class];
  39.377 +    }
  39.378 +    return self;
  39.379 +}
  39.380 +
  39.381 +
  39.382 +- (CGColorRef) altCellColor                         {return _altCellColor;}
  39.383 +- (void) setAltCellColor: (CGColorRef)altCellColor  {setcolor(&_altCellColor,altCellColor);}
  39.384 +
  39.385 +
  39.386 +@end
  39.387 +
  39.388 +
  39.389 +
  39.390 +#pragma mark -
  39.391 +
  39.392 +@implementation Square
  39.393 +
  39.394 +
  39.395 +- (void) drawInParentContext: (CGContextRef)ctx fill: (BOOL)fill
  39.396 +{
  39.397 +    if( fill ) {
  39.398 +        CGColorRef c = ((RectGrid*)_grid).altCellColor;
  39.399 +        if( c ) {
  39.400 +            if( ! ((_row+_column) & 1) )
  39.401 +                c = _grid.cellColor;
  39.402 +            CGContextSetFillColorWithColor(ctx, c);
  39.403 +        }
  39.404 +    }
  39.405 +    [super drawInParentContext: ctx fill: fill];
  39.406 +}
  39.407 +
  39.408 +
  39.409 +- (void) setHighlighted: (BOOL)highlighted
  39.410 +{
  39.411 +    [super setHighlighted: highlighted];
  39.412 +    self.borderWidth = (highlighted ?6 :0);
  39.413 +}
  39.414 +
  39.415 +
  39.416 +- (Square*) nw     {return (Square*)[_grid cellAtRow: _row+1 column: _column-1];}
  39.417 +- (Square*) n      {return (Square*)[_grid cellAtRow: _row+1 column: _column  ];}
  39.418 +- (Square*) ne     {return (Square*)[_grid cellAtRow: _row+1 column: _column+1];}
  39.419 +- (Square*) e      {return (Square*)[_grid cellAtRow: _row   column: _column+1];}
  39.420 +- (Square*) se     {return (Square*)[_grid cellAtRow: _row-1 column: _column+1];}
  39.421 +- (Square*) s      {return (Square*)[_grid cellAtRow: _row-1 column: _column  ];}
  39.422 +- (Square*) sw     {return (Square*)[_grid cellAtRow: _row-1 column: _column-1];}
  39.423 +- (Square*) w      {return (Square*)[_grid cellAtRow: _row   column: _column-1];}
  39.424 +
  39.425 +// Directions relative to the current player:
  39.426 +- (Square*) fl     {return self.fwdIsN ?self.nw :self.se;}
  39.427 +- (Square*) f      {return self.fwdIsN ?self.n  :self.s;}
  39.428 +- (Square*) fr     {return self.fwdIsN ?self.ne :self.sw;}
  39.429 +- (Square*) r      {return self.fwdIsN ?self.e  :self.w;}
  39.430 +- (Square*) br     {return self.fwdIsN ?self.se :self.nw;}
  39.431 +- (Square*) b      {return self.fwdIsN ?self.s  :self.n;}
  39.432 +- (Square*) bl     {return self.fwdIsN ?self.sw :self.ne;}
  39.433 +- (Square*) l      {return self.fwdIsN ?self.w  :self.e;}
  39.434 +
  39.435 +
  39.436 +- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
  39.437 +{
  39.438 +    CGImageRef image = GetCGImageFromPasteboard([sender draggingPasteboard]);
  39.439 +    if( image ) {
  39.440 +        CGColorRef color = CreatePatternColor(image);
  39.441 +        RectGrid *rectGrid = (RectGrid*)_grid;
  39.442 +        if( rectGrid.altCellColor && ((_row+_column) & 1) )
  39.443 +            rectGrid.altCellColor = color;
  39.444 +        else
  39.445 +            rectGrid.cellColor = color;
  39.446 +        CGColorRelease(color);
  39.447 +        [rectGrid setNeedsDisplay];
  39.448 +        return YES;
  39.449 +    } else
  39.450 +        return NO;
  39.451 +}
  39.452 +
  39.453 +@end
  39.454 +
  39.455 +
  39.456 +
  39.457 +#pragma mark -
  39.458 +
  39.459 +@implementation GoSquare
  39.460 +
  39.461 +@synthesize dotted=_dotted;
  39.462 +
  39.463 +- (void) drawInParentContext: (CGContextRef)ctx fill: (BOOL)fill
  39.464 +{
  39.465 +    if( fill )
  39.466 +        [super drawInParentContext: ctx fill: fill];
  39.467 +    else {
  39.468 +        CGRect frame = self.frame;
  39.469 +        const CGFloat midx=floor(CGRectGetMidX(frame))+0.5, 
  39.470 +                    midy=floor(CGRectGetMidY(frame))+0.5;
  39.471 +        CGPoint p[4] = {{CGRectGetMinX(frame),midy},
  39.472 +                        {CGRectGetMaxX(frame),midy},
  39.473 +                        {midx,CGRectGetMinY(frame)},
  39.474 +                        {midx,CGRectGetMaxY(frame)}};
  39.475 +        if( ! self.s )  p[2].y = midy;
  39.476 +        if( ! self.n )  p[3].y = midy;
  39.477 +        if( ! self.w )  p[0].x = midx;
  39.478 +        if( ! self.e )  p[1].x = midx;
  39.479 +        CGContextStrokeLineSegments(ctx, p, 4);
  39.480 +        
  39.481 +        if( _dotted ) {
  39.482 +            CGContextSetFillColorWithColor(ctx,_grid.lineColor);
  39.483 +            CGRect dot = CGRectMake(midx-2.5, midy-2.5, 5, 5);
  39.484 +            CGContextFillEllipseInRect(ctx, dot);
  39.485 +        }
  39.486 +    }
  39.487 +}
  39.488 +
  39.489 +@end
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/Source/HexGrid.h	Fri Mar 07 11:43:02 2008 -0800
    40.3 @@ -0,0 +1,47 @@
    40.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    40.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    40.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    40.7 +
    40.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    40.9 +    provided that the following conditions are met:
   40.10 +
   40.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   40.12 +      and the following disclaimer.
   40.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   40.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   40.15 +      with the distribution.
   40.16 +
   40.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   40.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   40.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   40.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   40.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   40.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   40.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   40.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   40.25 +*/
   40.26 +#import "Grid.h"
   40.27 +
   40.28 +
   40.29 +/** Hexagonal grid.
   40.30 +    The hexes are oriented with points facing up and down.
   40.31 +    The coords are still rectangular, since the hexes line up in straight horizontal rows,
   40.32 +    but every odd-numbered row of hexes is offset slightly to the right. */
   40.33 +@interface HexGrid : Grid
   40.34 +{
   40.35 +    CGFloat _side, _capHeight;
   40.36 +    CGPathRef _cellPath;
   40.37 +}
   40.38 +
   40.39 +/** Similar to -addAllCells, but only adds enough cells to create a hexagonal board. */
   40.40 +- (void) addCellsInHexagon;
   40.41 +
   40.42 +@end
   40.43 +
   40.44 +
   40.45 +@interface Hex : GridCell
   40.46 +
   40.47 +@property (readonly) Hex *nw, *ne, *e, *se, *sw, *w;    // Absolute directions (n = increasing row#)
   40.48 +@property (readonly) Hex *fl, *fr, *r, *br, *bl, *l;    // Relative to player (upside-down for player 2)
   40.49 +
   40.50 +@end
   40.51 \ No newline at end of file
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/Source/HexGrid.m	Fri Mar 07 11:43:02 2008 -0800
    41.3 @@ -0,0 +1,200 @@
    41.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    41.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    41.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    41.7 +
    41.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    41.9 +    provided that the following conditions are met:
   41.10 +
   41.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   41.12 +      and the following disclaimer.
   41.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   41.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   41.15 +      with the distribution.
   41.16 +
   41.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   41.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   41.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   41.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   41.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   41.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   41.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   41.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   41.25 +*/
   41.26 +#import "HexGrid.h"
   41.27 +#import "Game.h"
   41.28 +
   41.29 +
   41.30 +@implementation HexGrid
   41.31 +
   41.32 +
   41.33 +- (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
   41.34 +            spacing: (CGSize)spacing
   41.35 +           position: (CGPoint)pos
   41.36 +{
   41.37 +    // Ignore given spacing.height; set it to make the hexagons regular.
   41.38 +    CGFloat capHeight = spacing.height / 2 * tan(M_PI/6);
   41.39 +    CGFloat side = spacing.height / 2 / cos(M_PI/6);
   41.40 +    spacing.height = side + capHeight;
   41.41 +    
   41.42 +    self = [super initWithRows: nRows columns: nColumns
   41.43 +                       spacing: spacing
   41.44 +                      position: pos];
   41.45 +    if( self ) {
   41.46 +        _capHeight = capHeight;
   41.47 +        _side = side;
   41.48 +        self.bounds = CGRectMake(-1, -1, 
   41.49 +                                 (nColumns+0.5)*spacing.width + 2,
   41.50 +                                 nRows*spacing.height+capHeight + 2);
   41.51 +        _cellClass = [Hex class];
   41.52 +    }
   41.53 +    return self;
   41.54 +}
   41.55 +
   41.56 +
   41.57 +- (id) initWithRows: (unsigned)nRows columns: (unsigned)nColumns
   41.58 +              frame: (CGRect)frame;
   41.59 +{
   41.60 +    // Compute the horizontal spacing:
   41.61 +    CGFloat s = floor(MIN( (frame.size.width -2.0)/nColumns,
   41.62 +                         (frame.size.height-2.0)/(nRows+0.5*tan(M_PI/6)) / (0.5*(tan(M_PI/6)+1/cos(M_PI/6))) ));
   41.63 +    return [self initWithRows: nRows columns: nColumns
   41.64 +                      spacing: CGSizeMake(s,s)
   41.65 +                     position: frame.origin];
   41.66 +}
   41.67 +    
   41.68 +    
   41.69 +- (void) dealloc
   41.70 +{
   41.71 +    CGPathRelease(_cellPath);
   41.72 +    [super dealloc];
   41.73 +}
   41.74 +
   41.75 +
   41.76 +- (void) addCellsInHexagon
   41.77 +{
   41.78 +    int size = _nRows - !(_nRows & 1);      // make it odd
   41.79 +    for( int row=0; row<_nRows; row++ ) {
   41.80 +        int n;                              // # of hexes remaining in this row
   41.81 +        if( row < size )
   41.82 +            n = size - abs(row-size/2);
   41.83 +        else
   41.84 +            n = 0;
   41.85 +        int c0 = floor(((int)_nRows+1-n -(row&1))/2.0);       // col of 1st remaining hex
   41.86 +
   41.87 +        for( int col=0; col<_nColumns; col++ )
   41.88 +            if( col>=c0 && col<c0+n )
   41.89 +                [self addCellAtRow: row column: col];
   41.90 +    }
   41.91 +}
   41.92 +
   41.93 +
   41.94 +- (GridCell*) createCellAtRow: (unsigned)row column: (unsigned)col 
   41.95 +               suggestedFrame: (CGRect)frame
   41.96 +{
   41.97 +    // Overridden to stagger the odd-numbered rows
   41.98 +    if( row & 1 )
   41.99 +        frame.origin.x += _spacing.width/2;
  41.100 +    frame.size.height += _capHeight;
  41.101 +    return [super createCellAtRow: row column: col suggestedFrame: frame];
  41.102 +}
  41.103 +
  41.104 +
  41.105 +// Returns a hexagonal CG path defining a cell's outline. Used by cells when drawing & hit-testing.
  41.106 +- (CGPathRef) cellPath
  41.107 +{
  41.108 +    if( ! _cellPath ) {
  41.109 +        CGFloat x1 = _spacing.width/2;
  41.110 +        CGFloat x2 = _spacing.width;
  41.111 +        CGFloat y1 = _capHeight;
  41.112 +        CGFloat y2 = y1 + _side;
  41.113 +        CGFloat y3 = y2 + _capHeight;
  41.114 +        CGPoint p[6] = { {0,y1}, {x1,0}, {x2,y1}, {x2,y2}, {x1,y3}, {0,y2} };
  41.115 +        
  41.116 +        CGMutablePathRef path = CGPathCreateMutable();
  41.117 +        CGPathAddLines(path, NULL, p, 6);
  41.118 +        CGPathCloseSubpath(path);
  41.119 +        _cellPath = path;
  41.120 +    }
  41.121 +    return _cellPath;
  41.122 +}
  41.123 +
  41.124 +
  41.125 +@end
  41.126 +
  41.127 +
  41.128 +
  41.129 +
  41.130 +
  41.131 +#pragma mark -
  41.132 +
  41.133 +@implementation Hex
  41.134 +
  41.135 +
  41.136 +- (void) drawInParentContext: (CGContextRef)ctx fill: (BOOL)fill
  41.137 +{
  41.138 +    CGContextSaveGState(ctx);
  41.139 +    CGPoint pos = self.position;
  41.140 +    CGContextTranslateCTM(ctx, pos.x, pos.y);
  41.141 +    CGContextBeginPath(ctx);
  41.142 +    CGContextAddPath(ctx, ((HexGrid*)_grid).cellPath);
  41.143 +    CGContextDrawPath(ctx, (fill ?kCGPathFill :kCGPathStroke));
  41.144 +    
  41.145 +    if( !fill && self.highlighted ) {
  41.146 +        // Highlight by drawing my outline in the highlight color:
  41.147 +        CGContextSetStrokeColorWithColor(ctx, self.borderColor);
  41.148 +        CGContextSetLineWidth(ctx,6);
  41.149 +        CGContextBeginPath(ctx);
  41.150 +        CGContextAddPath(ctx, ((HexGrid*)_grid).cellPath);
  41.151 +        CGContextDrawPath(ctx, kCGPathStroke);
  41.152 +    }
  41.153 +    CGContextRestoreGState(ctx);
  41.154 +}
  41.155 +
  41.156 +
  41.157 +- (BOOL)containsPoint:(CGPoint)p
  41.158 +{
  41.159 +    return [super containsPoint: p]
  41.160 +        && CGPathContainsPoint( ((HexGrid*)_grid).cellPath, NULL, p, NO );
  41.161 +}
  41.162 +
  41.163 +
  41.164 +- (void) setHighlighted: (BOOL)highlighted
  41.165 +{
  41.166 +    if( highlighted != self.highlighted ) {
  41.167 +        [super setHighlighted: highlighted];
  41.168 +        [_grid setNeedsDisplay];        // So I'll be asked to redraw myself
  41.169 +    }
  41.170 +}
  41.171 +
  41.172 +
  41.173 +#pragma mark -
  41.174 +#pragma mark NEIGHBORS:
  41.175 +
  41.176 +
  41.177 +- (NSArray*) neighbors
  41.178 +{
  41.179 +    NSMutableArray *neighbors = [NSMutableArray arrayWithCapacity: 6];
  41.180 +    Hex* n[6] = {self.nw, self.ne, self.w, self.e, self.sw, self.se};
  41.181 +    for( int i=0; i<6; i++ )
  41.182 +        if( n[i] )
  41.183 +            [neighbors addObject: n[i]];
  41.184 +    return neighbors;
  41.185 +}
  41.186 +
  41.187 +- (Hex*) nw     {return (Hex*)[_grid cellAtRow: _row+1 column: _column - ((_row+1)&1)];}
  41.188 +- (Hex*) ne     {return (Hex*)[_grid cellAtRow: _row+1 column: _column + (_row&1)];}
  41.189 +- (Hex*) e      {return (Hex*)[_grid cellAtRow: _row   column: _column + 1];}
  41.190 +- (Hex*) se     {return (Hex*)[_grid cellAtRow: _row-1 column: _column + (_row&1)];}
  41.191 +- (Hex*) sw     {return (Hex*)[_grid cellAtRow: _row-1 column: _column - ((_row-1)&1)];}
  41.192 +- (Hex*) w      {return (Hex*)[_grid cellAtRow: _row   column: _column - 1];}
  41.193 +
  41.194 +// Directions relative to the current player:
  41.195 +- (Hex*) fl     {return self.fwdIsN ?self.nw :self.se;}
  41.196 +- (Hex*) fr     {return self.fwdIsN ?self.ne :self.sw;}
  41.197 +- (Hex*) r      {return self.fwdIsN ?self.e  :self.w;}
  41.198 +- (Hex*) br     {return self.fwdIsN ?self.se :self.nw;}
  41.199 +- (Hex*) bl     {return self.fwdIsN ?self.sw :self.ne;}
  41.200 +- (Hex*) l      {return self.fwdIsN ?self.w  :self.e;}
  41.201 +
  41.202 +
  41.203 +@end
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/Source/HexchequerGame.h	Fri Mar 07 11:43:02 2008 -0800
    42.3 @@ -0,0 +1,32 @@
    42.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    42.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    42.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    42.7 +
    42.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    42.9 +    provided that the following conditions are met:
   42.10 +
   42.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   42.12 +      and the following disclaimer.
   42.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   42.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   42.15 +      with the distribution.
   42.16 +
   42.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   42.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   42.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   42.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   42.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   42.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   42.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   42.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   42.25 +*/
   42.26 +#import "CheckersGame.h"
   42.27 +
   42.28 +/** A hex-grid variant of checkers, made up on a whim to test out hex boards.
   42.29 +    A much better existing hexagonal checkers is HexDame --
   42.30 +    see: http://www.mindsports.net/CompleteGames/Elimination/HexDame.html 
   42.31 +    Its implementation is left as an exercise for the reader.
   42.32 +    Hint: rotate the HexGrid 30 degrees! */
   42.33 +@interface HexchequerGame : CheckersGame 
   42.34 +
   42.35 +@end
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/Source/HexchequerGame.m	Fri Mar 07 11:43:02 2008 -0800
    43.3 @@ -0,0 +1,113 @@
    43.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    43.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    43.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    43.7 +
    43.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    43.9 +    provided that the following conditions are met:
   43.10 +
   43.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   43.12 +      and the following disclaimer.
   43.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   43.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   43.15 +      with the distribution.
   43.16 +
   43.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   43.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   43.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   43.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   43.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   43.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   43.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   43.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   43.25 +*/
   43.26 +#import "HexchequerGame.h"
   43.27 +#import "HexGrid.h"
   43.28 +#import "Piece.h"
   43.29 +#import "QuartzUtils.h"
   43.30 +
   43.31 +
   43.32 +@implementation HexchequerGame
   43.33 +
   43.34 +
   43.35 +- (Grid*) x_makeGrid
   43.36 +{
   43.37 +    HexGrid *grid = [[[HexGrid alloc] initWithRows: 9 columns: 9 frame: _board.bounds] autorelease];
   43.38 +    CGPoint pos = grid.position;
   43.39 +    pos.x = floor((_board.bounds.size.width-grid.frame.size.width)/2);
   43.40 +    grid.position = pos;
   43.41 +    [grid addCellsInHexagon];
   43.42 +    grid.allowsMoves = YES;
   43.43 +    grid.allowsCaptures = NO;      // no land-on captures, that is
   43.44 +    grid.cellColor = CGColorCreateGenericGray(1.0, 0.25);
   43.45 +    grid.lineColor = kTranslucentLightGrayColor;
   43.46 +    
   43.47 +    [self addPieces: @"Green Ball.png" toGrid: grid forPlayer: 0 rows: NSMakeRange(0,2) alternating: NO];
   43.48 +    [self addPieces: @"Red Ball.png"   toGrid: grid forPlayer: 1 rows: NSMakeRange(7,2) alternating: NO];
   43.49 +    return grid;
   43.50 +}
   43.51 +
   43.52 +
   43.53 +- (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
   43.54 +{
   43.55 +    Hex *src=(Hex*)srcHolder, *dst=(Hex*)dstHolder;
   43.56 +    if( [bit valueForKey: @"King"] )
   43.57 +        if( dst==src.bl || dst==src.br || dst==src.l || dst==src.r
   43.58 +           || (src.bl.bit.unfriendly && dst==src.bl.bl) || (src.br.bit.unfriendly && dst==src.br.br)
   43.59 +           || (src.l.bit.unfriendly  && dst==src.l.l)   || (src.r.bit.unfriendly  && dst==src.r.r) )
   43.60 +            return YES;    
   43.61 +    return dst==src.fl || dst==src.fr
   43.62 +        || (src.fl.bit.unfriendly && dst==src.fl.fl) || (src.fr.bit.unfriendly && dst==src.fr.fr);
   43.63 +}
   43.64 +
   43.65 +- (void) bit: (Bit*)bit movedFrom: (id<BitHolder>)srcHolder to: (id<BitHolder>)dstHolder
   43.66 +{
   43.67 +    Hex *src=(Hex*)srcHolder, *dst=(Hex*)dstHolder;
   43.68 +    int playerIndex = self.currentPlayer.index;
   43.69 +    BOOL isKing = ([bit valueForKey: @"King"] != nil);
   43.70 +    
   43.71 +    [[NSSound soundNamed: (isKing ?@"Funk" :@"Tink")] play];
   43.72 +
   43.73 +    // "King" a piece that made it to the last row:
   43.74 +    if( dst.row == (playerIndex ?0 :8) )
   43.75 +        if( ! isKing ) {
   43.76 +            [[NSSound soundNamed: @"Blow"] play];
   43.77 +            bit.scale = 1.4;
   43.78 +            [bit setValue: @"King" forKey: @"King"];
   43.79 +            // don't set isKing flag - piece can't capture again after being kinged.
   43.80 +        }
   43.81 +
   43.82 +    // Check for a capture:
   43.83 +    Hex *capture = nil;
   43.84 +    if(dst==src.fl.fl)
   43.85 +        capture = src.fl;
   43.86 +    else if(dst==src.fr.fr)
   43.87 +        capture = src.fr;
   43.88 +    else if(dst==src.bl.bl)
   43.89 +        capture = src.bl;
   43.90 +    else if(dst==src.br.br)
   43.91 +        capture = src.br;
   43.92 +    else if(dst==src.l.l)
   43.93 +        capture = src.l;
   43.94 +    else if(dst==src.r.r)
   43.95 +        capture = src.r;
   43.96 +    
   43.97 +    if( capture ) {
   43.98 +        [[NSSound soundNamed: @"Pop"] play];
   43.99 +        Bit *bit = capture.bit;
  43.100 +        _numPieces[bit.owner.index]--;
  43.101 +        [bit destroy];
  43.102 +        
  43.103 +        // Now check if another capture is possible. If so, don't end the turn:
  43.104 +        if( (dst.fl.bit.unfriendly && dst.fl.fl.empty) || (dst.fr.bit.unfriendly && dst.fr.fr.empty) )
  43.105 +            return;
  43.106 +        if( isKing )
  43.107 +            if( (dst.bl.bit.unfriendly && dst.bl.bl.empty) || (dst.br.bit.unfriendly && dst.br.br.empty)
  43.108 +                    || (dst.l.bit.unfriendly && dst.l.l.empty) || (dst.r.bit.unfriendly && dst.r.r.empty))
  43.109 +                return;
  43.110 +    }
  43.111 +    
  43.112 +    [self endTurn];
  43.113 +}
  43.114 +
  43.115 +
  43.116 +@end
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/Source/KlondikeGame.h	Fri Mar 07 11:43:02 2008 -0800
    44.3 @@ -0,0 +1,34 @@
    44.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    44.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    44.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    44.7 +
    44.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    44.9 +    provided that the following conditions are met:
   44.10 +
   44.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   44.12 +      and the following disclaimer.
   44.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   44.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   44.15 +      with the distribution.
   44.16 +
   44.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   44.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   44.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   44.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   44.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   44.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   44.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   44.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   44.25 +*/
   44.26 +#import "Game.h"
   44.27 +@class Deck, Stack;
   44.28 +
   44.29 +
   44.30 +/** The classic card solitaire game Klondike.
   44.31 +    See: http://en.wikipedia.org/wiki/Klondike_(solitaire) */
   44.32 +@interface KlondikeGame : Game {
   44.33 +    Deck *_deck, *_sink;
   44.34 +    Deck *_aces[4];
   44.35 +}
   44.36 +
   44.37 +@end
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/Source/KlondikeGame.m	Fri Mar 07 11:43:02 2008 -0800
    45.3 @@ -0,0 +1,181 @@
    45.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    45.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    45.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    45.7 +
    45.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    45.9 +    provided that the following conditions are met:
   45.10 +
   45.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   45.12 +      and the following disclaimer.
   45.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   45.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   45.15 +      with the distribution.
   45.16 +
   45.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   45.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   45.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   45.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   45.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   45.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   45.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   45.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   45.25 +*/
   45.26 +#import "KlondikeGame.h"
   45.27 +#import "Deck.h"
   45.28 +#import "PlayingCard.h"
   45.29 +#import "Stack.h"
   45.30 +
   45.31 +
   45.32 +#define kStackHeight 500
   45.33 +
   45.34 +
   45.35 +/**  WARNING: THIS CODE REQUIRES GARBAGE COLLECTION!
   45.36 + **  This sample application uses Objective-C 2.0 garbage collection.
   45.37 + **  Therefore, the source code in this file does NOT perform manual object memory management.
   45.38 + **  If you reuse any of this code in a process that isn't garbage collected, you will need to
   45.39 + **  add all necessary retain/release/autorelease calls, and implement -dealloc methods,
   45.40 + **  otherwise unpleasant leakage will occur!
   45.41 + **/
   45.42 +
   45.43 +
   45.44 +@implementation KlondikeGame
   45.45 +
   45.46 +
   45.47 +- (id) initWithBoard: (CALayer*)board
   45.48 +{
   45.49 +    self = [super initWithBoard: board];
   45.50 +    if (self != nil) {
   45.51 +        [self setNumberOfPlayers: 1];
   45.52 +        
   45.53 +        _deck = [[Deck alloc] initWithCardsOfClass: [PlayingCard class]];
   45.54 +        [_deck shuffle];
   45.55 +        _deck.position = CGPointMake(kCardWidth/2+16,kCardHeight/2+16);
   45.56 +        [board addSublayer: _deck];
   45.57 +        
   45.58 +        _sink = [[Deck alloc] init];
   45.59 +        _sink.position = CGPointMake(3*kCardWidth/2+32,kCardHeight/2+16);
   45.60 +        [board addSublayer: _sink];
   45.61 +        
   45.62 +        for( CardSuit suit=kSuitClubs; suit<=kSuitSpades; suit++ ) {
   45.63 +            Deck *aces = [[Deck alloc] init];
   45.64 +            aces.position = CGPointMake(kCardWidth/2+16+(kCardWidth+16)*(suit%2),
   45.65 +                                        120+kCardHeight+(kCardHeight+16)*(suit/2));
   45.66 +            [board addSublayer: aces];
   45.67 +            _aces[suit] = aces;
   45.68 +        }
   45.69 +        
   45.70 +        for( int s=0; s<7; s++ ) {
   45.71 +            Stack *stack = [[Stack alloc] initWithStartPos: CGPointMake(kCardWidth/2,
   45.72 +                                                                        kStackHeight-kCardHeight/2.0)
   45.73 +                                                   spacing: CGSizeMake(0,-22)];
   45.74 +            stack.frame = CGRectMake(260+s*(kCardWidth+16),16, kCardWidth,kStackHeight);
   45.75 +            stack.backgroundColor = nil;
   45.76 +            stack.dragAsStacks = YES;
   45.77 +            [board addSublayer: stack];
   45.78 +            
   45.79 +            // According to the rules, one card should be added to each stack in turn, instead
   45.80 +            // of populating entire stacks one at a time. However, if one trusts the Deck's
   45.81 +            // -shuffle method (which uses the random() function, seeded with a high-entropy
   45.82 +            // cryptographically-strong value), it shouldn't make any difference :-)
   45.83 +            for( int c=0; c<=s; c++ )
   45.84 +                [stack addBit: [_deck removeTopCard]];
   45.85 +            ((Card*)stack.bits.lastObject).faceUp = YES;
   45.86 +        }
   45.87 +        
   45.88 +        [self nextPlayer];
   45.89 +    }
   45.90 +    return self;
   45.91 +}
   45.92 +
   45.93 +
   45.94 +- (BOOL) clickedBit: (Bit*)bit
   45.95 +{
   45.96 +    if( [bit isKindOfClass: [Card class]] ) {
   45.97 +        Card *card = (Card*)bit;
   45.98 +        if( card.holder == _deck ) {
   45.99 +            // Click on deck deals 3 cards to the sink:
  45.100 +            for( int i=0; i<3; i++ ) {
  45.101 +                Card *card = [_deck removeTopCard];
  45.102 +                if( card ) {
  45.103 +                    [_sink addCard: card];
  45.104 +                    card.faceUp = YES;
  45.105 +                }
  45.106 +            }
  45.107 +            [self endTurn];
  45.108 +            return YES;
  45.109 +        } else if( card.holder == _sink ) {
  45.110 +            // Clicking the sink when the deck is empty re-deals:
  45.111 +            if( _deck.empty ) {
  45.112 +                [_deck addCards: [_sink removeAllCards]];
  45.113 +                [_deck flip];
  45.114 +                [self endTurn];
  45.115 +                return YES;
  45.116 +            }
  45.117 +        } else {
  45.118 +            // Click on a card elsewhere turns it face-up:
  45.119 +            if( ! card.faceUp ) {
  45.120 +                card.faceUp = YES;
  45.121 +                return YES;
  45.122 +            }
  45.123 +        }
  45.124 +    }
  45.125 +    return NO;
  45.126 +}
  45.127 +
  45.128 +
  45.129 +- (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)src
  45.130 +{
  45.131 +    if( [bit isKindOfClass: [DraggedStack class]] ) {
  45.132 +        Card *bottomSrc = [[(DraggedStack*)bit bits] objectAtIndex: 0];
  45.133 +        if( ! bottomSrc.faceUp )
  45.134 +            return NO;
  45.135 +    }
  45.136 +    return YES;
  45.137 +}
  45.138 +
  45.139 +
  45.140 +- (BOOL) canBit: (Bit*)bit moveFrom: (id<BitHolder>)src to: (id<BitHolder>)dst
  45.141 +{
  45.142 +    if( src==_deck || dst==_deck || dst==_sink )
  45.143 +        return NO;
  45.144 +    
  45.145 +    // Find the bottom card being moved, and the top card it's moving onto:
  45.146 +    PlayingCard *bottomSrc;
  45.147 +    if( [bit isKindOfClass: [DraggedStack class]] )
  45.148 +        bottomSrc = [[(DraggedStack*)bit bits] objectAtIndex: 0];
  45.149 +    else
  45.150 +        bottomSrc = (PlayingCard*)bit;
  45.151 +    
  45.152 +    PlayingCard *topDst;
  45.153 +    if( [dst isKindOfClass: [Deck class]] ) {
  45.154 +        // Dragging to an ace pile:
  45.155 +        if( ! [bit isKindOfClass: [Card class]] )
  45.156 +            return NO;
  45.157 +        topDst = (PlayingCard*) ((Deck*)dst).topCard;
  45.158 +        if( topDst == nil )
  45.159 +            return bottomSrc.rank == kRankAce;
  45.160 +        else
  45.161 +            return bottomSrc.suit == topDst.suit && bottomSrc.rank == topDst.rank+1;
  45.162 +        
  45.163 +    } else {
  45.164 +        // Dragging to a card stack:
  45.165 +        topDst = (PlayingCard*) ((Stack*)dst).topBit;
  45.166 +        if( topDst == nil )
  45.167 +            return bottomSrc.rank == kRankKing;
  45.168 +        else
  45.169 +            return bottomSrc.color != topDst.color && bottomSrc.rank == topDst.rank-1;
  45.170 +    }
  45.171 +}
  45.172 +
  45.173 +
  45.174 +- (Player*) checkForWinner
  45.175 +{
  45.176 +    for( CardSuit suit=kSuitClubs; suit<=kSuitSpades; suit++ )
  45.177 +        if( _aces[suit].cards.count < 13 )
  45.178 +            return nil;
  45.179 +    return _currentPlayer;
  45.180 +}
  45.181 +
  45.182 +
  45.183 +
  45.184 +@end
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/Source/Piece.h	Fri Mar 07 11:43:02 2008 -0800
    46.3 @@ -0,0 +1,47 @@
    46.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    46.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    46.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    46.7 +
    46.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    46.9 +    provided that the following conditions are met:
   46.10 +
   46.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   46.12 +      and the following disclaimer.
   46.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   46.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   46.15 +      with the distribution.
   46.16 +
   46.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   46.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   46.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   46.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   46.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   46.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   46.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   46.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   46.25 +*/
   46.26 +#import "Bit.h"
   46.27 +
   46.28 +
   46.29 +/** A playing piece. A concrete subclass of Bit that displays an image. */
   46.30 +@interface Piece : Bit
   46.31 +{
   46.32 +    @private
   46.33 +    NSString *_imageName;
   46.34 +}
   46.35 +
   46.36 +/** Initialize a Piece from an image file.
   46.37 +    imageName can be a resource name from the app bundle, or an absolute path.
   46.38 +    If scale is 0.0, the image's natural size will be used.
   46.39 +    If 0.0 < scale < 4.0, the image will be scaled by that factor.
   46.40 +    If scale >= 4.0, it will be used as the size to scale the maximum dimension to. */
   46.41 +- (id) initWithImageNamed: (NSString*)imageName
   46.42 +                    scale: (CGFloat)scale;
   46.43 +
   46.44 +- (void) setImage: (CGImageRef)image scale: (CGFloat)scale;
   46.45 +- (void) setImage: (CGImageRef)image;
   46.46 +- (void) setImageNamed: (NSString*)name;
   46.47 +
   46.48 +@property (copy) NSString* imageName;
   46.49 +
   46.50 +@end
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/Source/Piece.m	Fri Mar 07 11:43:02 2008 -0800
    47.3 @@ -0,0 +1,132 @@
    47.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    47.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    47.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    47.7 +
    47.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    47.9 +    provided that the following conditions are met:
   47.10 +
   47.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   47.12 +      and the following disclaimer.
   47.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   47.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   47.15 +      with the distribution.
   47.16 +
   47.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   47.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   47.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   47.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   47.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   47.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   47.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   47.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   47.25 +*/
   47.26 +#import "Piece.h"
   47.27 +#import "QuartzUtils.h"
   47.28 +
   47.29 +
   47.30 +@implementation Piece
   47.31 +
   47.32 +
   47.33 +- (id) initWithImageNamed: (NSString*)imageName
   47.34 +                    scale: (CGFloat)scale
   47.35 +{
   47.36 +    self = [super init];
   47.37 +    if (self != nil) {
   47.38 +        self.imageName = imageName;
   47.39 +        [self setImage: GetCGImageNamed(imageName) scale: scale];
   47.40 +        self.zPosition = kPieceZ;
   47.41 +    }
   47.42 +    return self;
   47.43 +}
   47.44 +
   47.45 +
   47.46 +- (id) initWithCoder: (NSCoder*)decoder
   47.47 +{
   47.48 +    self = [super initWithCoder: decoder];
   47.49 +    if( self ) {
   47.50 +        self.imageName = [decoder decodeObjectForKey: @"imageName"];
   47.51 +        // (actual image (self.contents) was already restord by superclass)
   47.52 +    }
   47.53 +    return self;
   47.54 +}
   47.55 +
   47.56 +- (void) encodeWithCoder: (NSCoder*)coder
   47.57 +{
   47.58 +    [super encodeWithCoder: coder];
   47.59 +    [coder encodeObject: _imageName forKey: @"imageName"];
   47.60 +}
   47.61 +
   47.62 +
   47.63 +- (void) dealloc
   47.64 +{
   47.65 +    [_imageName release];
   47.66 +    [super dealloc];
   47.67 +}
   47.68 +
   47.69 +
   47.70 +- (NSString*) description
   47.71 +{
   47.72 +    return [NSString stringWithFormat: @"%@[%@]", 
   47.73 +            [self class],
   47.74 +            _imageName.lastPathComponent.stringByDeletingPathExtension];
   47.75 +}
   47.76 +
   47.77 +
   47.78 +@synthesize imageName=_imageName;
   47.79 +
   47.80 +
   47.81 +- (void) setImage: (CGImageRef)image scale: (CGFloat)scale
   47.82 +{
   47.83 +    self.contents = (id) image;
   47.84 +    self.contentsGravity = @"resize";
   47.85 +    self.minificationFilter = kCAFilterLinear;
   47.86 +    int width = CGImageGetWidth(image), height = CGImageGetHeight(image);
   47.87 +    if( scale > 0 ) {
   47.88 +        if( scale >= 4.0 )
   47.89 +            scale /= MAX(width,height);             // interpret scale as target dimensions
   47.90 +        width = ceil( width * scale);
   47.91 +        height= ceil( height* scale);
   47.92 +    }
   47.93 +    self.bounds = CGRectMake(0,0,width,height);
   47.94 +    self.imageName = nil;
   47.95 +}
   47.96 +
   47.97 +- (void) setImage: (CGImageRef)image
   47.98 +{
   47.99 +    CGSize size = self.bounds.size;
  47.100 +    [self setImage: image scale: MAX(size.width,size.height)];
  47.101 +}
  47.102 +
  47.103 +- (void) setImageNamed: (NSString*)name
  47.104 +{
  47.105 +    [self setImage: GetCGImageNamed(name)];
  47.106 +    self.imageName = name;
  47.107 +}
  47.108 +
  47.109 +
  47.110 +- (BOOL)containsPoint:(CGPoint)p
  47.111 +{
  47.112 +    // Overrides CGLayer's implementation,
  47.113 +    // returning YES only for pixels at which this layer's alpha is at least 0.5.
  47.114 +    // This takes into account the opacity, bg color, and background image's alpha channel.
  47.115 +    if( ! [super containsPoint: p] )
  47.116 +        return NO;
  47.117 +    float opacity = self.opacity;
  47.118 +    if( opacity < 0.5 )
  47.119 +        return NO;
  47.120 +    float thresholdAlpha = 0.5 / self.opacity;
  47.121 +    
  47.122 +    CGColorRef bg = self.backgroundColor;
  47.123 +    float alpha = bg ?CGColorGetAlpha(bg) :0.0;
  47.124 +    if( alpha < thresholdAlpha ) {
  47.125 +        CGImageRef image = (CGImageRef)self.contents;
  47.126 +        if( image ) {
  47.127 +            // Note: This makes the convenient assumption that the image entirely fills the bounds.
  47.128 +            alpha = MAX(alpha, GetPixelAlpha(image, self.bounds.size, p));
  47.129 +        }
  47.130 +    }
  47.131 +    return alpha >= thresholdAlpha;
  47.132 +}
  47.133 +
  47.134 +
  47.135 +@end
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/Source/PlayingCard.h	Fri Mar 07 11:43:02 2008 -0800
    48.3 @@ -0,0 +1,55 @@
    48.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    48.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    48.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    48.7 +
    48.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    48.9 +    provided that the following conditions are met:
   48.10 +
   48.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   48.12 +      and the following disclaimer.
   48.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   48.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   48.15 +      with the distribution.
   48.16 +
   48.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   48.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   48.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   48.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   48.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   48.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   48.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   48.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   48.25 +*/
   48.26 +#import "Card.h"
   48.27 +
   48.28 +typedef enum {
   48.29 +    kSuitClubs,
   48.30 +    kSuitDiamonds,
   48.31 +    kSuitHearts,
   48.32 +    kSuitSpades
   48.33 +} CardSuit;
   48.34 +
   48.35 +typedef enum {
   48.36 +    kColorRed = 0,
   48.37 +    kColorBlack = 1
   48.38 +} CardColor;
   48.39 +
   48.40 +typedef enum {
   48.41 +    kRankAce = 1,
   48.42 +    kRankJack = 11,
   48.43 +    kRankQueen = 12,
   48.44 +    kRankKing = 13
   48.45 +} CardRank;
   48.46 +
   48.47 +
   48.48 +/* A standard Western playing card. Serial numbers go from 1..52. */
   48.49 +@interface PlayingCard : Card
   48.50 +
   48.51 +@property (readonly) CardSuit suit;
   48.52 +@property (readonly) CardColor color;
   48.53 +@property (readonly) CardRank rank;
   48.54 +
   48.55 +@property (readonly) NSString *suitString, *rankString, *faceSymbol;
   48.56 +@property (readonly) CGColorRef suitColor;
   48.57 +
   48.58 +@end
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/Source/PlayingCard.m	Fri Mar 07 11:43:02 2008 -0800
    49.3 @@ -0,0 +1,111 @@
    49.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    49.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    49.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    49.7 +
    49.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    49.9 +    provided that the following conditions are met:
   49.10 +
   49.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   49.12 +      and the following disclaimer.
   49.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   49.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   49.15 +      with the distribution.
   49.16 +
   49.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   49.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   49.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   49.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   49.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   49.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   49.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   49.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   49.25 +*/
   49.26 +#import "PlayingCard.h"
   49.27 +#import "QuartzUtils.h"
   49.28 +
   49.29 +
   49.30 +@implementation PlayingCard
   49.31 +
   49.32 +
   49.33 ++ (NSRange) serialNumberRange;
   49.34 +{
   49.35 +    return NSMakeRange(1,52);
   49.36 +}
   49.37 +
   49.38 +
   49.39 +- (CALayer*) createFront
   49.40 +{
   49.41 +    CALayer *front = [super createFront];
   49.42 +    NSString *name = [NSString stringWithFormat: @"%@%@",
   49.43 +                      self.rankString, self.suitString];
   49.44 +    
   49.45 +    CGColorRef suitColor = self.suitColor;
   49.46 +    CATextLayer *label;
   49.47 +    label = AddTextLayer(front, name, [NSFont systemFontOfSize: 18],
   49.48 +                         kCALayerMaxXMargin | kCALayerMinYMargin);
   49.49 +    label.foregroundColor = suitColor;
   49.50 +    label = AddTextLayer(front, name, [NSFont systemFontOfSize: 18],
   49.51 +                         kCALayerMaxXMargin | kCALayerMaxYMargin);
   49.52 +    label.foregroundColor = suitColor;
   49.53 +    label.anchorPoint = CGPointMake(1,1);
   49.54 +    [label setValue: [NSNumber numberWithFloat: M_PI] forKeyPath: @"transform.rotation"];
   49.55 +    
   49.56 +    label = AddTextLayer(front, self.faceSymbol, [NSFont systemFontOfSize: 80],
   49.57 +                         kCALayerWidthSizable | kCALayerHeightSizable);
   49.58 +    label.foregroundColor = suitColor;
   49.59 +    return front;
   49.60 +}
   49.61 +
   49.62 +
   49.63 +- (CardRank) rank       {return (self.serialNumber-1)%13 + 1;}
   49.64 +- (CardSuit) suit       {return (self.serialNumber-1)/13;}
   49.65 +
   49.66 +- (CardColor) color
   49.67 +{
   49.68 +    CardSuit suit = self.suit;
   49.69 +    return suit==kSuitDiamonds || suit==kSuitHearts ?kColorRed :kColorBlack;
   49.70 +}
   49.71 +
   49.72 +
   49.73 +- (NSString*) suitString
   49.74 +{
   49.75 +    return [@"\u2663\u2666\u2665\u2660" substringWithRange: NSMakeRange(self.suit,1)];
   49.76 +}
   49.77 +
   49.78 +- (NSString*) rankString
   49.79 +{
   49.80 +    CardRank rank = self.rank;
   49.81 +    if( rank == 10 )
   49.82 +        return @"10";
   49.83 +    else
   49.84 +        return [@"A234567890JQK" substringWithRange: NSMakeRange(rank-1,1)];
   49.85 +}
   49.86 +
   49.87 +- (CGColorRef) suitColor
   49.88 +{
   49.89 +    static CGColorRef kSuitColor[4];
   49.90 +    if( ! kSuitColor[0] ) {
   49.91 +        kSuitColor[0] = kSuitColor[3] = kBlackColor;
   49.92 +        kSuitColor[1] = kSuitColor[2] = CGColorCreateGenericRGB(1, 0, 0, 1);
   49.93 +    }
   49.94 +    return kSuitColor[self.suit];
   49.95 +}
   49.96 +
   49.97 +
   49.98 +- (NSString*) faceSymbol
   49.99 +{
  49.100 +    int rank = self.rank;
  49.101 +    if( rank < kRankJack )
  49.102 +        return self.suitString;
  49.103 +    else
  49.104 +        return [@"\u265E\u265B\u265A" substringWithRange: NSMakeRange(rank-kRankJack,1)]; // actually chess symbols
  49.105 +}
  49.106 +
  49.107 +
  49.108 +- (NSString*) description
  49.109 +{
  49.110 +    return [NSString stringWithFormat: @"%@[%@%@]",self.class,self.rankString,self.suitString];
  49.111 +}
  49.112 +
  49.113 +
  49.114 +@end
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/Source/QuartzUtils.h	Fri Mar 07 11:43:02 2008 -0800
    50.3 @@ -0,0 +1,70 @@
    50.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    50.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    50.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    50.7 +
    50.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    50.9 +    provided that the following conditions are met:
   50.10 +
   50.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   50.12 +      and the following disclaimer.
   50.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   50.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   50.15 +      with the distribution.
   50.16 +
   50.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   50.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   50.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   50.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   50.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   50.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   50.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   50.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   50.25 +*/
   50.26 +#import <Quartz/Quartz.h>
   50.27 +
   50.28 +
   50.29 +/** Constants for various commonly used colors. */
   50.30 +extern CGColorRef kBlackColor, kWhiteColor, 
   50.31 +                  kTranslucentGrayColor, kTranslucentLightGrayColor, 
   50.32 +                  kAlmostInvisibleWhiteColor,
   50.33 +                  kHighlightColor;
   50.34 +
   50.35 +
   50.36 +/** Moves a layer from one superlayer to another, without changing its position onscreen. */
   50.37 +void ChangeSuperlayer( CALayer *layer, CALayer *newSuperlayer, int index );
   50.38 +
   50.39 +/** Removes a layer from its superlayer without any fade-out animation. */
   50.40 +void RemoveImmediately( CALayer *layer );
   50.41 +
   50.42 +/** Convenience for creating a CATextLayer. */
   50.43 +CATextLayer* AddTextLayer( CALayer *superlayer,
   50.44 +                           NSString *text, NSFont* font,
   50.45 +                           enum CAAutoresizingMask align );
   50.46 +
   50.47 +
   50.48 +/** Loads an image or pattern file into a CGImage or CGPattern.
   50.49 +    If the name begins with "/", it's interpreted as an absolute filesystem path.
   50.50 +    Otherwise, it's the name of a resource that's looked up in the app bundle.
   50.51 +    The image must exist, or an assertion-failure exception will be raised!
   50.52 +    Loaded images/patterns are cached in memory, so subsequent calls with the same name
   50.53 +    are very fast.
   50.54 +    The caller must NOT release the result, since it's retained in the cache. */
   50.55 +CGImageRef GetCGImageNamed( NSString *name );
   50.56 +CGColorRef GetCGPatternNamed( NSString *name );
   50.57 +
   50.58 +/** Loads image data from the pasteboard into a CGImage. */
   50.59 +CGImageRef GetCGImageFromPasteboard( NSPasteboard *pb );
   50.60 +
   50.61 +/** Creates a CGPattern from a CGImage. Caller must release it. */
   50.62 +CGPatternRef CreateImagePattern( CGImageRef image );
   50.63 +
   50.64 +/** Creates a CGColor that draws the given CGImage as a pattern. Caller must release it. */
   50.65 +CGColorRef CreatePatternColor( CGImageRef image );
   50.66 +
   50.67 +/** Returns the alpha value of a single pixel in a CGImage, scaled to a particular size. */
   50.68 +float GetPixelAlpha( CGImageRef image, CGSize imageSize, CGPoint pt );
   50.69 +
   50.70 +/** Returns the center point of a CGRect. */
   50.71 +static inline CGPoint GetCGRectCenter( CGRect rect ) {
   50.72 +    return CGPointMake(CGRectGetMidX(rect),CGRectGetMidY(rect));
   50.73 +}
   50.74 \ No newline at end of file
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/Source/QuartzUtils.m	Fri Mar 07 11:43:02 2008 -0800
    51.3 @@ -0,0 +1,273 @@
    51.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    51.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    51.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    51.7 +
    51.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    51.9 +    provided that the following conditions are met:
   51.10 +
   51.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   51.12 +      and the following disclaimer.
   51.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   51.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   51.15 +      with the distribution.
   51.16 +
   51.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   51.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   51.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   51.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   51.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   51.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   51.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   51.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   51.25 +*/
   51.26 +#import "QuartzUtils.h"
   51.27 +
   51.28 +
   51.29 +CGColorRef kBlackColor, kWhiteColor, 
   51.30 +           kTranslucentGrayColor, kTranslucentLightGrayColor,
   51.31 +           kAlmostInvisibleWhiteColor,
   51.32 +           kHighlightColor;
   51.33 +
   51.34 +
   51.35 +__attribute__((constructor))        // Makes this function run when the app loads
   51.36 +static void InitQuartzUtils()
   51.37 +{
   51.38 +    kBlackColor = CGColorCreateGenericGray(0.0, 1.0);
   51.39 +    kWhiteColor = CGColorCreateGenericGray(1.0, 1.0);
   51.40 +    kTranslucentGrayColor = CGColorCreateGenericGray(0.0, 0.5);
   51.41 +    kTranslucentLightGrayColor = CGColorCreateGenericGray(0.0, 0.25);
   51.42 +    kAlmostInvisibleWhiteColor = CGColorCreateGenericGray(1, 0.05);
   51.43 +    kHighlightColor = CGColorCreateGenericRGB(1, 1, 0, 0.5);
   51.44 +}
   51.45 +
   51.46 +
   51.47 +void ChangeSuperlayer( CALayer *layer, CALayer *newSuperlayer, int index )
   51.48 +{
   51.49 +    // Disable actions, else the layer will move to the wrong place and then back!
   51.50 +    [CATransaction flush];
   51.51 +    [CATransaction begin];
   51.52 +    [CATransaction setValue:(id)kCFBooleanTrue
   51.53 +                     forKey:kCATransactionDisableActions];
   51.54 +
   51.55 +    CGPoint pos = [newSuperlayer convertPoint: layer.position 
   51.56 +                      fromLayer: layer.superlayer];
   51.57 +    [layer retain];
   51.58 +    [layer removeFromSuperlayer];
   51.59 +    if( index >= 0 )
   51.60 +        [newSuperlayer insertSublayer: layer atIndex: index];
   51.61 +    else
   51.62 +        [newSuperlayer addSublayer: layer];
   51.63 +    layer.position = pos;
   51.64 +    [layer release];
   51.65 +
   51.66 +    [CATransaction commit];
   51.67 +}
   51.68 +
   51.69 +
   51.70 +void RemoveImmediately( CALayer *layer )
   51.71 +{
   51.72 +    [CATransaction flush];
   51.73 +    [CATransaction begin];
   51.74 +    [CATransaction setValue:(id)kCFBooleanTrue
   51.75 +                     forKey:kCATransactionDisableActions];
   51.76 +    [layer removeFromSuperlayer];
   51.77 +    [CATransaction commit];
   51.78 +}    
   51.79 +
   51.80 +
   51.81 +CATextLayer* AddTextLayer( CALayer *superlayer,
   51.82 +                           NSString *text, NSFont* font,
   51.83 +                           enum CAAutoresizingMask align )
   51.84 +{
   51.85 +    CATextLayer *label = [[CATextLayer alloc] init];
   51.86 +    label.string = text;
   51.87 +    label.font = font;
   51.88 +    label.fontSize = font.pointSize;
   51.89 +    label.foregroundColor = kBlackColor;
   51.90 +    
   51.91 +    NSString *mode;
   51.92 +    if( align & kCALayerWidthSizable )
   51.93 +        mode = @"center";
   51.94 +    else if( align & kCALayerMinXMargin )
   51.95 +        mode = @"right";
   51.96 +    else
   51.97 +        mode = @"left";
   51.98 +    align |= kCALayerWidthSizable;
   51.99 +    label.alignmentMode = mode;
  51.100 +    
  51.101 +    CGFloat inset = superlayer.borderWidth + 3;
  51.102 +    CGRect bounds = CGRectInset(superlayer.bounds, inset, inset);
  51.103 +    CGFloat height = font.ascender;
  51.104 +    CGFloat y = bounds.origin.y;
  51.105 +    if( align & kCALayerHeightSizable )
  51.106 +        y += (bounds.size.height-height)/2.0;
  51.107 +    else if( align & kCALayerMinYMargin )
  51.108 +        y += bounds.size.height - height;
  51.109 +    align &= ~kCALayerHeightSizable;
  51.110 +    label.bounds = CGRectMake(0, font.descender,
  51.111 +                              bounds.size.width, height - font.descender);
  51.112 +    label.position = CGPointMake(bounds.origin.x,y+font.descender);
  51.113 +    label.anchorPoint = CGPointMake(0,0);
  51.114 +    
  51.115 +    label.autoresizingMask = align;
  51.116 +    [superlayer addSublayer: label];
  51.117 +    [label release];
  51.118 +    return label;
  51.119 +}
  51.120 +
  51.121 +
  51.122 +CGImageRef CreateCGImageFromFile( NSString *path )
  51.123 +{
  51.124 +    CGImageRef image = NULL;
  51.125 +    CFURLRef url = (CFURLRef) [NSURL fileURLWithPath: path];
  51.126 +    CGImageSourceRef src = CGImageSourceCreateWithURL(url, NULL);
  51.127 +    if( src ) {
  51.128 +        image = CGImageSourceCreateImageAtIndex(src, 0, NULL);
  51.129 +        CFRelease(src);
  51.130 +        if(!image) NSLog(@"Warning: CGImageSourceCreateImageAtIndex failed on file %@ (ptr size=%u)",path,sizeof(void*));
  51.131 +    }
  51.132 +    return image;
  51.133 +}
  51.134 +
  51.135 +
  51.136 +CGImageRef GetCGImageNamed( NSString *name )
  51.137 +{
  51.138 +    // For efficiency, loaded images are cached in a dictionary by name.
  51.139 +    static NSMutableDictionary *sMap;
  51.140 +    if( ! sMap )
  51.141 +        sMap = [[NSMutableDictionary alloc] init];
  51.142 +    
  51.143 +    CGImageRef image = (CGImageRef) [sMap objectForKey: name];
  51.144 +    if( ! image ) {
  51.145 +        // Hasn't been cached yet, so load it:
  51.146 +        NSString *path;
  51.147 +        if( [name hasPrefix: @"/"] )
  51.148 +            path = name;
  51.149 +        else {
  51.150 +            path = [[NSBundle mainBundle] pathForResource: name ofType: nil];
  51.151 +            NSCAssert1(path,@"Couldn't find bundle image resource '%@'",name);
  51.152 +        }
  51.153 +        image = CreateCGImageFromFile(path);
  51.154 +        NSCAssert1(image,@"Failed to load image from %@",path);
  51.155 +        [sMap setObject: (id)image forKey: name];
  51.156 +        CGImageRelease(image);
  51.157 +    }
  51.158 +    return image;
  51.159 +}
  51.160 +
  51.161 +
  51.162 +CGColorRef GetCGPatternNamed( NSString *name )         // can be resource name or abs. path
  51.163 +{
  51.164 +    // For efficiency, loaded patterns are cached in a dictionary by name.
  51.165 +    static NSMutableDictionary *sMap;
  51.166 +    if( ! sMap )
  51.167 +        sMap = [[NSMutableDictionary alloc] init];
  51.168 +    
  51.169 +    CGColorRef pattern = (CGColorRef) [sMap objectForKey: name];
  51.170 +    if( ! pattern ) {
  51.171 +        pattern = CreatePatternColor( GetCGImageNamed(name) );
  51.172 +        [sMap setObject: (id)pattern forKey: name];
  51.173 +        CGColorRelease(pattern);
  51.174 +    }
  51.175 +    return pattern;
  51.176 +}
  51.177 +
  51.178 +
  51.179 +CGImageRef GetCGImageFromPasteboard( NSPasteboard *pb )
  51.180 +{
  51.181 +    CGImageSourceRef src = NULL;
  51.182 +    NSArray *paths = [pb propertyListForType: NSFilenamesPboardType];
  51.183 +    if( paths.count==1 ) {
  51.184 +        // If a file is being dragged, read it:
  51.185 +        CFURLRef url = (CFURLRef) [NSURL fileURLWithPath: [paths objectAtIndex: 0]];
  51.186 +        src = CGImageSourceCreateWithURL(url, NULL);
  51.187 +    } else {
  51.188 +        // Else look for an image type:
  51.189 +        NSString *type = [pb availableTypeFromArray: [NSImage imageUnfilteredPasteboardTypes]];
  51.190 +        if( type ) {
  51.191 +            NSData *data = [pb dataForType: type];
  51.192 +            src = CGImageSourceCreateWithData((CFDataRef)data, NULL);
  51.193 +        }
  51.194 +    }
  51.195 +    if(src) {
  51.196 +        CGImageRef image = CGImageSourceCreateImageAtIndex(src, 0, NULL);
  51.197 +        CFRelease(src);
  51.198 +        return image;
  51.199 +    } else
  51.200 +        return NULL;
  51.201 +}    
  51.202 +
  51.203 +
  51.204 +float GetPixelAlpha( CGImageRef image, CGSize imageSize, CGPoint pt )
  51.205 +{
  51.206 +    // Trivial reject:
  51.207 +    if( pt.x<0 || pt.x>=imageSize.width || pt.y<0 || pt.y>=imageSize.height )
  51.208 +        return 0.0;
  51.209 +    
  51.210 +    // sTinyContext is a 1x1 CGBitmapContext whose pixmap stores only alpha.
  51.211 +    static UInt8 sPixel[1];
  51.212 +    static CGContextRef sTinyContext;
  51.213 +    if( ! sTinyContext ) {
  51.214 +        sTinyContext = CGBitmapContextCreate(sPixel, 1, 1, 
  51.215 +                                             8, 1,     // bpp, rowBytes
  51.216 +                                             NULL,
  51.217 +                                             kCGImageAlphaOnly);
  51.218 +        CGContextSetBlendMode(sTinyContext, kCGBlendModeCopy);
  51.219 +    }
  51.220 +    
  51.221 +    // Draw the image into sTinyContext, positioned so the desired point is at
  51.222 +    // (0,0), then examine the alpha value in the pixmap:
  51.223 +    CGContextDrawImage(sTinyContext, 
  51.224 +                       CGRectMake(-pt.x,-pt.y, imageSize.width,imageSize.height),
  51.225 +                       image);
  51.226 +    return sPixel[0] / 255.0;
  51.227 +}
  51.228 +
  51.229 +
  51.230 +#pragma mark -
  51.231 +#pragma mark PATTERNS:
  51.232 +
  51.233 +
  51.234 +// callback for CreateImagePattern.
  51.235 +static void drawPatternImage (void *info, CGContextRef ctx)
  51.236 +{
  51.237 +    CGImageRef image = (CGImageRef) info;
  51.238 +    CGContextDrawImage(ctx, 
  51.239 +                       CGRectMake(0,0, CGImageGetWidth(image),CGImageGetHeight(image)),
  51.240 +                       image);
  51.241 +}
  51.242 +
  51.243 +// callback for CreateImagePattern.
  51.244 +static void releasePatternImage( void *info )
  51.245 +{
  51.246 +    CGImageRelease( (CGImageRef)info );
  51.247 +}
  51.248 +
  51.249 +
  51.250 +CGPatternRef CreateImagePattern( CGImageRef image )
  51.251 +{
  51.252 +    NSCParameterAssert(image);
  51.253 +    int width = CGImageGetWidth(image);
  51.254 +    int height = CGImageGetHeight(image);
  51.255 +    static const CGPatternCallbacks callbacks = {0, &drawPatternImage, &releasePatternImage};
  51.256 +    return CGPatternCreate (image,
  51.257 +                            CGRectMake (0, 0, width, height),
  51.258 +                            CGAffineTransformMake (1, 0, 0, 1, 0, 0),
  51.259 +                            width,
  51.260 +                            height,
  51.261 +                            kCGPatternTilingConstantSpacing,
  51.262 +                            true,
  51.263 +                            &callbacks);
  51.264 +}
  51.265 +
  51.266 +
  51.267 +CGColorRef CreatePatternColor( CGImageRef image )
  51.268 +{
  51.269 +    CGPatternRef pattern = CreateImagePattern(image);
  51.270 +    CGColorSpaceRef space = CGColorSpaceCreatePattern(NULL);
  51.271 +    CGFloat components[1] = {1.0};
  51.272 +    CGColorRef color = CGColorCreateWithPattern(space, pattern, components);
  51.273 +    CGColorSpaceRelease(space);
  51.274 +    CGPatternRelease(pattern);
  51.275 +    return color;
  51.276 +}
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/Source/Stack.h	Fri Mar 07 11:43:02 2008 -0800
    52.3 @@ -0,0 +1,68 @@
    52.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    52.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    52.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    52.7 +
    52.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    52.9 +    provided that the following conditions are met:
   52.10 +
   52.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   52.12 +      and the following disclaimer.
   52.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   52.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   52.15 +      with the distribution.
   52.16 +
   52.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   52.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   52.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   52.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   52.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   52.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   52.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   52.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   52.25 +*/
   52.26 +#import "Bit.h"
   52.27 +#import "BitHolder.h"
   52.28 +
   52.29 +
   52.30 +/** A holder for multiple Bits that lines them up in stacks or rows.
   52.31 +    For example, this is used in solitaire card games for each pile in the "tableau". */
   52.32 +@interface Stack : BitHolder
   52.33 +{
   52.34 +    CGPoint _startPos;                      // see properties below for descriptions
   52.35 +    CGSize _spacing;       
   52.36 +    CGSize _wrapSpacing;   
   52.37 +    int _wrapInterval;     
   52.38 +    NSMutableArray *_bits; 
   52.39 +    BOOL _dragAsStacks;    
   52.40 +}
   52.41 +
   52.42 +- (id) initWithStartPos: (CGPoint)startPos spacing: (CGSize)spacing;
   52.43 +
   52.44 +- (id) initWithStartPos: (CGPoint)startPos spacing: (CGSize)spacing
   52.45 +           wrapInterval: (int)wrapInterval wrapSpacing: (CGSize)wrapSpacing;
   52.46 +
   52.47 +@property CGPoint startPos;                 // Position where first Bit should go
   52.48 +@property CGSize spacing;                   // Spacing between successive Bits
   52.49 +@property CGSize wrapSpacing;               // Spacing between wrapped-around sub-piles
   52.50 +@property int wrapInterval;                 // How many Bits to add before wrapping
   52.51 +@property BOOL dragAsStacks;                // If set to YES, dragging a Bit drags a DraggedStack
   52.52 +@property (readonly) NSArray *bits;         // The Bits, in order
   52.53 +@property (readonly) Bit *topBit;           // The topmost Bit (last item in self.bits)
   52.54 +
   52.55 +/** Adds a Bit to the end */
   52.56 +- (void) addBit: (Bit*)bit;
   52.57 +
   52.58 +@end
   52.59 +
   52.60 +
   52.61 +/** A subset of a Stack, dragged out of it if its dragAsStacks flag is set.
   52.62 +    This is used in typical card solitaire games.
   52.63 +    A DraggedStack exists only during a drag; afterwards, its Cards
   52.64 +    are incorporated into the destination Stack. */
   52.65 +@interface DraggedStack : Bit
   52.66 +
   52.67 +- (id) initWithBits: (NSArray*)bits;
   52.68 +
   52.69 +@property (readonly) NSArray *bits;
   52.70 +
   52.71 +@end
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/Source/Stack.m	Fri Mar 07 11:43:02 2008 -0800
    53.3 @@ -0,0 +1,185 @@
    53.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    53.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    53.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    53.7 +
    53.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    53.9 +    provided that the following conditions are met:
   53.10 +
   53.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   53.12 +      and the following disclaimer.
   53.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   53.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   53.15 +      with the distribution.
   53.16 +
   53.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   53.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   53.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   53.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   53.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   53.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   53.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   53.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   53.25 +*/
   53.26 +#import "Stack.h"
   53.27 +#import "QuartzUtils.h"
   53.28 +
   53.29 +
   53.30 +@implementation Stack
   53.31 +
   53.32 +
   53.33 +- (id) initWithStartPos: (CGPoint)startPos spacing: (CGSize)spacing
   53.34 +           wrapInterval: (int)wrapInterval wrapSpacing: (CGSize)wrapSpacing
   53.35 +{
   53.36 +    self = [super init];
   53.37 +    if (self != nil) {
   53.38 +        _startPos = startPos;
   53.39 +        _spacing = spacing;
   53.40 +        _wrapInterval = wrapInterval;
   53.41 +        _wrapSpacing = wrapSpacing;
   53.42 +        self.cornerRadius = 8;
   53.43 +        self.backgroundColor = kAlmostInvisibleWhiteColor;
   53.44 +        self.borderColor = kHighlightColor;
   53.45 +        _bits = [[NSMutableArray alloc] init];
   53.46 +    }
   53.47 +    return self;
   53.48 +}
   53.49 +
   53.50 +- (id) initWithStartPos: (CGPoint)startPos spacing: (CGSize)spacing;
   53.51 +{
   53.52 +    return [self initWithStartPos: startPos spacing: spacing 
   53.53 +                     wrapInterval: INT_MAX wrapSpacing: CGSizeZero];
   53.54 +}
   53.55 +
   53.56 +
   53.57 +- (void) dealloc
   53.58 +{
   53.59 +    [_bits release];
   53.60 +    [super dealloc];
   53.61 +}
   53.62 +
   53.63 +
   53.64 +@synthesize spacing=_spacing, wrapSpacing=_wrapSpacing, startPos=_startPos, wrapInterval=_wrapInterval;
   53.65 +@synthesize dragAsStacks=_dragAsStacks;
   53.66 +@synthesize bits=_bits;
   53.67 +
   53.68 +
   53.69 +- (Bit*) topBit
   53.70 +{
   53.71 +    return [_bits lastObject];
   53.72 +}
   53.73 +
   53.74 +
   53.75 +- (void) dump
   53.76 +{
   53.77 +    printf("Stack = ");
   53.78 +    for( CALayer *layer in self.sublayers )
   53.79 +        printf("%s @z=%g   ", [[layer description] UTF8String],layer.zPosition);
   53.80 +    printf("\n");
   53.81 +}
   53.82 +
   53.83 +
   53.84 +- (void) x_repositionBit: (Bit*)bit forIndex: (int)i
   53.85 +{
   53.86 +    bit.position = CGPointMake(_startPos.x + _spacing.width *(i%_wrapInterval) + _wrapSpacing.width *(i/_wrapInterval),
   53.87 +                               _startPos.y + _spacing.height*(i%_wrapInterval) + _wrapSpacing.height*(i/_wrapInterval));
   53.88 +}
   53.89 +
   53.90 +- (void) addBit: (Bit*)bit
   53.91 +{
   53.92 +    if( [bit isKindOfClass: [DraggedStack class]] ) {
   53.93 +        for( Bit *subBit in [(DraggedStack*)bit bits] )
   53.94 +            [self addBit: subBit];
   53.95 +    } else {
   53.96 +        int n = _bits.count;
   53.97 +        [_bits addObject: bit];
   53.98 +        ChangeSuperlayer(bit, self, n);
   53.99 +        [self x_repositionBit: bit forIndex: n];
  53.100 +    }
  53.101 +}
  53.102 +
  53.103 +
  53.104 +- (void) setHighlighted: (BOOL)highlighted
  53.105 +{
  53.106 +    [super setHighlighted: highlighted];
  53.107 +    self.borderWidth = (highlighted ?6 :0);
  53.108 +}
  53.109 +
  53.110 +
  53.111 +- (Bit*) canDragBit: (Bit*)bit
  53.112 +{
  53.113 +    NSInteger index = [_bits indexOfObjectIdenticalTo: bit];
  53.114 +    if( index==NSNotFound )
  53.115 +        return nil;
  53.116 +    if( _dragAsStacks && index < _bits.count-1 ) {
  53.117 +        // Move bit and those above it into a temporary DraggedStack:
  53.118 +        NSRange r = NSMakeRange(index,_bits.count-index);
  53.119 +        NSArray *bitsToDrag = [_bits subarrayWithRange: r];
  53.120 +        [_bits removeObjectsInRange: r];
  53.121 +        DraggedStack *stack = [[DraggedStack alloc] initWithBits: bitsToDrag];
  53.122 +        [self addSublayer: stack];
  53.123 +        [stack release];
  53.124 +        stack.anchorPoint = CGPointMake( bit.position.x/stack.bounds.size.width,
  53.125 +                                         bit.position.y/stack.bounds.size.height );
  53.126 +        stack.position = bit.position;
  53.127 +        return stack;
  53.128 +    } else {
  53.129 +        [bit retain];
  53.130 +        [_bits removeObjectIdenticalTo: bit];
  53.131 +        return [bit autorelease];
  53.132 +    }
  53.133 +}
  53.134 +
  53.135 +
  53.136 +- (void) cancelDragBit: (Bit*)bit
  53.137 +{
  53.138 +    [self addBit: bit];
  53.139 +    if( [bit isKindOfClass: [DraggedStack class]] ) {
  53.140 +        [bit removeFromSuperlayer];
  53.141 +    }
  53.142 +}
  53.143 +
  53.144 +
  53.145 +- (void) draggedBit: (Bit*)bit to: (id<BitHolder>)dst
  53.146 +{
  53.147 +    int i=0;
  53.148 +    for( Bit *bit in self.sublayers )
  53.149 +        [self x_repositionBit: bit forIndex: i++];
  53.150 +}
  53.151 +
  53.152 +
  53.153 +- (BOOL) dropBit: (Bit*)bit atPoint: (CGPoint)point
  53.154 +{
  53.155 +    [self addBit: bit];
  53.156 +    return YES;
  53.157 +}
  53.158 +
  53.159 +@end
  53.160 +
  53.161 +
  53.162 +
  53.163 +
  53.164 +@implementation DraggedStack
  53.165 +
  53.166 +
  53.167 +- (id) initWithBits: (NSArray*)bits
  53.168 +{
  53.169 +    self = [super init];
  53.170 +    if( self ) {
  53.171 +        CGRect bounds = CGRectZero;
  53.172 +        for( Bit *bit in bits ) {
  53.173 +            bounds = CGRectUnion(bounds, bit.frame);
  53.174 +            [self addSublayer: bit];
  53.175 +        }
  53.176 +        self.bounds = bounds;
  53.177 +        self.anchorPoint = CGPointZero;
  53.178 +        self.position = CGPointZero;
  53.179 +    }
  53.180 +    return self;
  53.181 +}
  53.182 +
  53.183 +- (NSArray*) bits
  53.184 +{
  53.185 +    return [self.sublayers.copy autorelease];
  53.186 +}
  53.187 +
  53.188 +@end
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/Source/TicTacToeGame.h	Fri Mar 07 11:43:02 2008 -0800
    54.3 @@ -0,0 +1,34 @@
    54.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    54.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    54.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    54.7 +
    54.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    54.9 +    provided that the following conditions are met:
   54.10 +
   54.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   54.12 +      and the following disclaimer.
   54.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   54.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   54.15 +      with the distribution.
   54.16 +
   54.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   54.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   54.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   54.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   54.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   54.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   54.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   54.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   54.25 +*/
   54.26 +#import "Game.h"
   54.27 +@class RectGrid, Dispenser;
   54.28 +
   54.29 +
   54.30 +/** Officially the world's second-lamest board game.
   54.31 +    See: http://en.wikipedia.org/wiki/Tic-tac-toe */
   54.32 +@interface TicTacToeGame : Game {
   54.33 +    RectGrid *_grid;
   54.34 +    Dispenser *_dispenser[2];
   54.35 +}
   54.36 +
   54.37 +@end
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/Source/TicTacToeGame.m	Fri Mar 07 11:43:02 2008 -0800
    55.3 @@ -0,0 +1,95 @@
    55.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    55.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    55.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    55.7 +
    55.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    55.9 +    provided that the following conditions are met:
   55.10 +
   55.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   55.12 +      and the following disclaimer.
   55.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   55.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   55.15 +      with the distribution.
   55.16 +
   55.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   55.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   55.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   55.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   55.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   55.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   55.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   55.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   55.25 +*/
   55.26 +#import "TicTacToeGame.h"
   55.27 +#import "Grid.h"
   55.28 +#import "Dispenser.h"
   55.29 +#import "Piece.h"
   55.30 +#import "QuartzUtils.h"
   55.31 +
   55.32 +
   55.33 +@implementation TicTacToeGame
   55.34 +
   55.35 +- (void) x_createDispenser: (NSString*)imageName forPlayer: (int)playerNumber x: (int)x
   55.36 +{
   55.37 +    Piece *p = [[Piece alloc] initWithImageNamed: imageName scale: 80];
   55.38 +    p.owner = [self.players objectAtIndex: playerNumber];
   55.39 +    _dispenser[playerNumber] = [[Dispenser alloc] initWithPrototype: p quantity: 0
   55.40 +                                                        frame: CGRectMake(x,16, 120,120)];
   55.41 +    [_board addSublayer: _dispenser[playerNumber]];
   55.42 +}
   55.43 +
   55.44 +- (id) initWithBoard: (CALayer*)board
   55.45 +{
   55.46 +    self = [super initWithBoard: board];
   55.47 +    if (self != nil) {
   55.48 +        [self setNumberOfPlayers: 2];
   55.49 +        
   55.50 +        // Create a 3x3 grid:
   55.51 +        CGFloat center = floor(CGRectGetMidX(board.bounds));
   55.52 +        _grid = [[RectGrid alloc] initWithRows: 3 columns: 3 frame: CGRectMake(center-150,16, 300,300)];
   55.53 +        [_grid addAllCells];
   55.54 +        _grid.allowsMoves = _grid.allowsCaptures = NO;
   55.55 +        _grid.cellColor = CGColorCreateGenericGray(1.0, 0.25);
   55.56 +        _grid.lineColor = kTranslucentLightGrayColor;
   55.57 +        [board addSublayer: _grid];
   55.58 +        
   55.59 +        // Create piece dispensers for the two players:
   55.60 +        [self x_createDispenser: @"/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ToolbarUtilitiesFolderIcon.icns"
   55.61 +                     forPlayer: 0 x: center-290];
   55.62 +        [self x_createDispenser: @"/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ToolbarAdvanced.icns"
   55.63 +                     forPlayer: 1 x: center+170];
   55.64 +        
   55.65 +        // And they're off!
   55.66 +        [self nextPlayer];
   55.67 +    }
   55.68 +    return self;
   55.69 +}
   55.70 +
   55.71 +- (void) nextPlayer
   55.72 +{
   55.73 +    [super nextPlayer];
   55.74 +    // Give the next player another piece to put down:
   55.75 +    _dispenser[self.currentPlayer.index].quantity = 1;
   55.76 +}
   55.77 +
   55.78 +static Player* ownerAt( Grid *grid, int index )
   55.79 +{
   55.80 +    return [grid cellAtRow: index/3 column: index%3].bit.owner;
   55.81 +}
   55.82 +
   55.83 +/** Should return the winning player, if the current position is a win. */
   55.84 +- (Player*) checkForWinner
   55.85 +{
   55.86 +    static const int kWinningTriples[8][3] =  { {0,1,2}, {3,4,5}, {6,7,8},  // rows
   55.87 +                                                {0,3,6}, {1,4,7}, {2,5,8},  // cols
   55.88 +                                                {0,4,8}, {2,4,6} };         // diagonals
   55.89 +    for( int i=0; i<8; i++ ) {
   55.90 +        const int *triple = kWinningTriples[i];
   55.91 +        Player *p = ownerAt(_grid,triple[0]);
   55.92 +        if( p && p == ownerAt(_grid,triple[1]) && p == ownerAt(_grid,triple[2]) )
   55.93 +            return p;
   55.94 +    }
   55.95 +    return nil;
   55.96 +}
   55.97 +
   55.98 +@end
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/Source/main.m	Fri Mar 07 11:43:02 2008 -0800
    56.3 @@ -0,0 +1,28 @@
    56.4 +/*  This code is based on Apple's "GeekGameBoard" sample code, version 1.0.
    56.5 +    http://developer.apple.com/samplecode/GeekGameBoard/
    56.6 +    Copyright © 2007 Apple Inc. Copyright © 2008 Jens Alfke. All Rights Reserved.
    56.7 +
    56.8 +    Redistribution and use in source and binary forms, with or without modification, are permitted
    56.9 +    provided that the following conditions are met:
   56.10 +
   56.11 +    * Redistributions of source code must retain the above copyright notice, this list of conditions
   56.12 +      and the following disclaimer.
   56.13 +    * Redistributions in binary form must reproduce the above copyright notice, this list of
   56.14 +      conditions and the following disclaimer in the documentation and/or other materials provided
   56.15 +      with the distribution.
   56.16 +
   56.17 +    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   56.18 +    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   56.19 +    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   56.20 +    BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   56.21 +    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   56.22 +    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   56.23 +    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   56.24 +    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   56.25 +*/
   56.26 +#import <Cocoa/Cocoa.h>
   56.27 +
   56.28 +int main(int argc, char *argv[])
   56.29 +{
   56.30 +    return NSApplicationMain(argc,  (const char **) argv);
   56.31 +}