-
Notifications
You must be signed in to change notification settings - Fork 3
/
BoardController.m
1304 lines (1171 loc) · 36.3 KB
/
BoardController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
Stockfish, a OS X GUI for the UCI chess engine with the same name.
Copyright (C) 2004-2011 Marco Costalba, Joona Kiiski, Tord Romstad
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#import "BoardController.h"
#import "BoardView.h"
#import "Book.h"
#import "CommentWindowController.h"
#import "CustomLevelController.h"
#import "Game.h"
#import "position.h"
#import "ChessClock.h"
#import "Engine.h"
#import "EngineConfigController.h"
#import "EngineController.h"
#import "MatchController.h"
#import "NewEngineMatchController.h"
#import "SearchLogController.h"
#import "SetupR64WindowController.h"
#import "UCIOption.h"
@implementation BoardController
-(id)init {
[super init];
guiBook = [[Book alloc] initWithFilename: [[NSBundle mainBundle]
pathForResource: @"guibook.bin"
ofType: nil]];
game = [[Game alloc] init];
[game setWhitePlayer: NSFullUserName()];
timer = [[NSTimer scheduledTimerWithTimeInterval: 1.0
target: self
selector: @selector(timerWasFired:)
userInfo: nil
repeats: YES]
retain];
gameMode = COMPUTER_BLACK;
displayVariations = YES;
allowVariationEntry = YES;
displayComments = YES;
boardIsFlipped = NO;
levelType = FISCHER_LEVEL;
levelTime = 5;
levelIncrement = 1;
playerNamesWereEdited = NO;
tournamentMode = NO;
beep = [[NSUserDefaults standardUserDefaults]
boolForKey: @"Beep when Making Moves"];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(boardColorsChanged:)
name: @"BoardColorsChanged"
object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(toggleBeep:)
name: @"BeepWhenMakingMovesChanged"
object: nil];
ec1 = [[EngineController alloc] initWithBoardController: self];
[ec1 showWindow: self];
/*
searchLogController = [[SearchLogController alloc] init];
[searchLogController showWindow: self];
[searchLogController setFont];
*/
// Remember position and size of board window. This doesn't work, so
// it's commented out.
/*
[[boardWindow windowController] setShouldCascadeWindows: NO];
[boardWindow setFrameUsingName: [boardWindow representedFilename]];
[boardWindow setAutosaveName: [boardWindow representedFilename]];
*/
return self;
}
-(void)raiseBoardWindow {
[boardWindow makeKeyAndOrderFront: nil];
}
-(int)pieceAtSquare:(int)squareIndex {
[moveListWindow setFloatingPanel: NO]; // UGLY HACK! MOVE ME LATER!!
if(boardIsFlipped)
return [game pieceAtSquare: 63-squareIndex];
else
return [game pieceAtSquare: squareIndex];
}
-(void)destinationSquaresFrom:(int)sqIndex storeIn:(int *)sqArray {
if(boardIsFlipped) {
int *sq;
[[game currentPosition] destinationSquaresFrom: 63-sqIndex
storeIn: sqArray];
for(sq = sqArray; *sq != -1; sq++) *sq = 63 - *sq;
}
else
[[game currentPosition] destinationSquaresFrom: sqIndex storeIn: sqArray];
}
-(void)gameOver {
if(gameMode == ENGINE_MATCH) {
[ec1 stopThinking];
[ec2 stopThinking];
if([[game currentPosition] isMate]) {
if([game whiteToMove]) [game setResult: BLACK_WINS];
else [game setResult: WHITE_WINS];
}
else [game setResult: DRAW];
[engineMatchController gameFinished: game];
}
else {
[ec1 stopThinking];
if([[game currentPosition] isMate]) {
if([game whiteToMove]) {
[game setResult: BLACK_WINS];
NSRunAlertPanel(@"Checkmate", @"Black wins", @"OK", nil, nil);
}
else {
[game setResult: WHITE_WINS];
NSRunAlertPanel(@"Checkmate", @"White wins", @"OK", nil, nil);
}
}
else { // Draw
[game setResult: DRAW];
if([[game currentPosition] isMaterialDraw])
NSRunAlertPanel(@"Draw", @"Insufficient material", @"OK", nil, nil);
else if([[game currentPosition] isRule50Draw])
NSRunAlertPanel(@"Draw", @"50 Moves", @"OK", nil, nil);
else if([[game currentPosition] isRepetitionDraw])
NSRunAlertPanel(@"Draw", @"Third Repetition", @"OK", nil, nil);
else if([[game currentPosition] isStalemate])
NSRunAlertPanel(@"Draw", @"Stalemate", @"OK", nil, nil);
}
[ec1 setRole: IDLE];
gameMode = BOTH;
}
}
-(NSString *)moveListString {
return [game moveListStringWithComments: displayComments
variations: displayVariations];
}
-(NSAttributedString *)moveListAttributedString {
return [game moveListAttributedStringWithComments: displayComments
variations: displayVariations];
}
-(void)displayMoveList {
[[moveListView textStorage] setAttributedString:
[self moveListAttributedString]];
}
-(void)animateMove:(ChessMove *)move {
int from = COMPRESS(MvFrom([move move])), to = COMPRESS(MvTo([move move]));
int remainingTime;
NSTimeInterval duration;
if(boardIsFlipped) {
from = 63 - from;
to = 63 - to;
}
remainingTime = [game whiteToMove]?
[game whiteRemainingTime] : [game blackRemainingTime];
if(remainingTime <= 15000)
// Less than 15 seconds left, skip animation
return;
else if(remainingTime > 300000)
// More than five minutes left, use slow animation
duration = 0.25;
else
// Between 15 seconds and 5 minutes left. Let the speed of animation
// depend linearly on the remaining time.
duration = 0.05 + 0.2 * (remainingTime - 15000.0) / 285000.0;
[boardView animateMoveFrom: from to: to time: duration];
}
-(void)finishMakeMove:(ChessMove *)move {
[self animateMove: move];
if(allowVariationEntry)
[game insertMove: move];
else
[game makeMove: move];
// [moveListView setString: [self moveListString]];
// [moveListView setAttributedString: [self moveListAttributedString]];
// [[moveListView textStorage] setAttributedString:
// [self moveListAttributedString]];
[self displayMoveList];
[boardView setNeedsDisplay: YES];
// Game Over?
if([[game currentPosition] isTerminal]) {
[self gameOver];
[self displayMoveList];
}
else { // Game not over!
// Should we use the GUI opening book?
if(gameMode != BOTH && gameMode != ANALYSIS &&
[[ec1 engine] shouldUseGUIBook]) {
ChessMove *bookMove =
[guiBook pickMoveForPosition: [game currentPosition]
withVariety: 0];
if(bookMove != nil)
[self engineMadeMove: bookMove comment: nil];
else [ec1 moveWasMade];
}
else [ec1 moveWasMade];
}
}
-(void)madeMoveFrom:(int)fromSq to:(int)toSq {
int fsq = boardIsFlipped? 63-fromSq : fromSq;
int tsq = boardIsFlipped? 63-toSq : toSq;
ChessMove *move = [[game generateMoveFrom: fsq to: tsq] retain];
if([move isNullMove]) { // Must be a promotion
int promotion;
[move release];
promotion = QUEEN - [NSApp runModalForWindow: promotionWindow];
[promotionWindow close];
move = [[game generateMoveFrom: fsq to: tsq promotion: promotion] retain];
}
[self finishMakeMove: move];
[move release];
}
-(BOOL)isAtBeginningOfGame {
return [game isAtBeginningOfGame];
}
-(BOOL)isAtEndOfGame {
return [game isAtEndOfGame];
}
-(void)engineMadeMove:(ChessMove *)move comment:(NSString *)comment {
// NSLog(@"inEngineMadeMove:, move is %@", move);
[self animateMove: move];
[game makeMove: move];
if(comment)
[game addComment: comment];
[self displayMoveList];
[boardView setNeedsDisplay: YES];
if(tournamentMode)
[game saveToFile: @"/Users/tord/CurrentGame.pgn"];
// Game Over?
if([[game currentPosition] isTerminal]) {
[self gameOver];
[self displayMoveList];
}
else { // Game not over!
if(tournamentMode) {
[[NSSound soundNamed: @"Glass"] play];
[boardView highlightBoard];
}
else if(beep)
[[NSSound soundNamed: @"Pop"] play];
// NSBeep();
if(gameMode == ENGINE_MATCH) {
if(([game whiteToMove] && [ec1 role] == PLAYING_WHITE) ||
([game blackToMove] && [ec1 role] == PLAYING_BLACK)) {
// Should we use the GUI opening book?
if([[ec1 engine] shouldUseGUIBook]) {
ChessMove *bookMove =
[guiBook pickMoveForPosition: [game currentPosition]
withVariety: 0];
if(bookMove != nil)
[self engineMadeMove: bookMove comment: nil];
else [ec1 moveWasMade];
}
else [ec1 moveWasMade];
}
else if(([game whiteToMove] && [ec2 role] == PLAYING_WHITE) ||
([game blackToMove] && [ec2 role] == PLAYING_BLACK)) {
if([[ec2 engine] shouldUseGUIBook]) {
ChessMove *bookMove =
[guiBook pickMoveForPosition: [game currentPosition]
withVariety: 0];
if(bookMove != nil)
[self engineMadeMove: bookMove comment: nil];
else [ec2 moveWasMade];
}
else [ec2 moveWasMade];
}
}
}
}
-(void)engineResigns {
if([game whiteToMove]) [game setResult: BLACK_WINS];
else [game setResult: WHITE_WINS];
[self displayMoveList];
if(gameMode == ENGINE_MATCH) {
[ec1 stopThinking];
[ec2 stopThinking];
[engineMatchController gameFinished: game];
}
else {
NSString *s = [NSString stringWithFormat: @"%@ resigns", [ec1 engineName]];
[ec1 stopThinking];
NSRunAlertPanel(s, @"Well done!", @"OK", nil, nil);
[ec1 setRole: IDLE];
gameMode = BOTH;
}
}
-(void)displayPlayerNames {
[playersTextField setStringValue: [NSString stringWithFormat: @"%@ - %@",
[game whitePlayer],
[game blackPlayer]]];
}
-(void)timerWasFired:(NSTimer *)timer {
[clockTextField setStringValue: [game clockString]];
if(gameMode == COMPUTER_WHITE) {
if([[game whitePlayer] isEqualToString: @"?"]) {
[game setWhitePlayer: [ec1 engineName]];
[self displayPlayerNames];
}
}
else if(gameMode == COMPUTER_BLACK) {
if([[game blackPlayer] isEqualToString: @"?"] ||
[game blackPlayer] == nil) {
[game setBlackPlayer: [ec1 engineName]];
[self displayPlayerNames];
}
}
}
-(void)setCurrentPositionFromFEN:(NSString *)fen {
[ec1 startNewGame];
[game release];
game = [[Game alloc] initWithFEN: fen];
if([game whiteToMove]) {
[game setWhitePlayer: NSFullUserName()];
[game setBlackPlayer: [ec1 engineName]];
gameMode = COMPUTER_BLACK;
[ec1 setRole: PLAYING_BLACK];
} else {
[game setBlackPlayer: NSFullUserName()];
[game setWhitePlayer: [ec1 engineName]];
gameMode = COMPUTER_WHITE;
[ec1 setRole: PLAYING_WHITE];
}
boardIsFlipped = NO;
playerNamesWereEdited = NO;
[boardView setNeedsDisplay: YES];
[moveListView setString: @""];
}
-(void)setGame:(Game *)newGame {
[newGame retain];
[ec1 startNewGame];
[game release];
game = newGame;
if([game whiteToMove]) {
[game setWhitePlayer: NSFullUserName()];
[game setBlackPlayer: [ec1 engineName]];
gameMode = COMPUTER_BLACK;
[ec1 setRole: PLAYING_BLACK];
} else {
[game setBlackPlayer: NSFullUserName()];
[game setWhitePlayer: [ec1 engineName]];
gameMode = COMPUTER_WHITE;
[ec1 setRole: PLAYING_WHITE];
}
boardIsFlipped = NO;
playerNamesWereEdited = NO;
[boardView setNeedsDisplay: YES];
[self displayPlayerNames];
[self displayMoveList];
// [moveListView setString: [self moveListString]];
}
-(void)newGameWithPGNString:(NSString *)string {
Game *newGame;
@try {
newGame = [[Game alloc] initWithPGNString: string];
[newGame goToBeginningOfGame];
}
@catch (NSException *e) {
NSRunAlertPanel(@"Error while parsing game",
[e reason], nil, nil, nil, nil);
return;
}
@finally {
}
[ec1 startNewGame];
if(ec2) [ec2 startNewGame];
[game release];
game = newGame;
gameMode = BOTH;
[ec1 setRole: IDLE];
boardIsFlipped = NO;
playerNamesWereEdited = NO;
[boardView setNeedsDisplay: YES];
[self displayPlayerNames];
[self displayMoveList];
// [moveListView setString: [self moveListString]];
// [[game currentPosition] display];
}
-(IBAction)newGame:(id)sender {
[ec1 startNewGame];
if(ec2) [ec2 startNewGame];
[game release];
game = [[Game alloc] init];
[game setWhitePlayer: NSFullUserName()];
gameMode = COMPUTER_BLACK;
[ec1 setRole: PLAYING_BLACK];
boardIsFlipped = NO;
playerNamesWereEdited = NO;
[boardView setNeedsDisplay: YES];
[moveListView setString: @""];
}
-(void)newGameWithFRCId:(int)FRCId {
[ec1 startNewGame];
if(ec2) [ec2 startNewGame];
[game release];
game = [[Game alloc] initWithFRCid: FRCId];
[game setWhitePlayer: NSFullUserName()];
gameMode = COMPUTER_BLACK;
[ec1 setRole: PLAYING_BLACK];
boardIsFlipped = NO;
playerNamesWereEdited = NO;
[boardView setNeedsDisplay: YES];
[moveListView setString: @""];
}
-(IBAction)newFRCGame:(id)sender {
[NSApp beginSheet: frcSheet
modalForWindow: boardWindow
modalDelegate: self
didEndSelector: @selector(frcSheetDidEnd:returnCode:contextInfo:)
contextInfo: nil];
}
-(IBAction)frcSheetOKPressed:(id)sender {
[frcSheet orderOut: sender];
[NSApp endSheet: frcSheet returnCode: 1];
}
-(IBAction)frcSheetCancelPressed:(id)sender {
[frcSheet orderOut: sender];
[NSApp endSheet: frcSheet returnCode: 0];
}
-(IBAction)frcSheetRandomPressed:(id)sender {
[frcIdTextField setIntValue: abs([ChessClock currentSystemTime]) % 960];
}
-(void)frcSheetDidEnd:(NSWindow *)sheet
returnCode:(int)returnCode
contextInfo:(void *)contextInfo {
if(returnCode == 1)
[self newGameWithFRCId: [frcIdTextField intValue]];
}
-(IBAction)saveGame:(id)sender {
NSSavePanel *panel = [NSSavePanel savePanel];
[panel setRequiredFileType: @"pgn"];
if([panel runModal] == NSOKButton)
[game saveToFile: [panel filename]];
}
-(IBAction)addGameToFile:(id)sender {
NSOpenPanel *panel = [NSOpenPanel openPanel];
NSArray *fileTypes = [NSArray arrayWithObjects: @"pgn", nil];
if([panel runModalForTypes: fileTypes] == NSOKButton)
[game saveToFile: [panel filename]];
}
-(IBAction)castleKingside:(id)sender {
[self finishMakeMove: [[game currentPosition] generateOO]];
}
-(IBAction)castleQueenside:(id)sender {
[self finishMakeMove: [[game currentPosition] generateOOO]];
}
-(IBAction)editPGNTags:(id)sender {
[whiteTextField setStringValue: [game whitePlayer]];
[blackTextField setStringValue: [game blackPlayer]];
[eventTextField setStringValue: [game event]];
[siteTextField setStringValue: [game site]];
[dateTextField setStringValue: [game date]];
[roundTextField setStringValue: [game round]];
[resultPopup removeAllItems];
[resultPopup addItemWithTitle: @"Unknown"];
[resultPopup addItemWithTitle: @"1-0"];
[resultPopup addItemWithTitle: @"0-1"];
[resultPopup addItemWithTitle: @"1/2-1/2"];
switch([game result]) {
case UNKNOWN: [resultPopup selectItemAtIndex: 0]; break;
case WHITE_WINS: [resultPopup selectItemAtIndex: 1]; break;
case BLACK_WINS: [resultPopup selectItemAtIndex: 2]; break;
case DRAW: [resultPopup selectItemAtIndex: 3]; break;
}
[NSApp beginSheet: pgnTagsSheet
modalForWindow: boardWindow
modalDelegate: self
didEndSelector: @selector(pgnTagsSheetDidEnd:returnCode:contextInfo:)
contextInfo:nil];
}
-(IBAction)pgnTagsOKPressed:(id)sender {
[pgnTagsSheet orderOut: sender];
if(![[game whitePlayer] isEqualToString: [whiteTextField stringValue]]) {
playerNamesWereEdited = YES;
[game setWhitePlayer: [whiteTextField stringValue]];
}
if(![[game blackPlayer] isEqualToString: [blackTextField stringValue]]) {
playerNamesWereEdited = YES;
[game setBlackPlayer: [blackTextField stringValue]];
}
[game setEvent: [eventTextField stringValue]];
[game setSite: [siteTextField stringValue]];
[game setRound: [roundTextField stringValue]];
switch([resultPopup indexOfSelectedItem]) {
case 1: [game setResult: WHITE_WINS]; break;
case 2: [game setResult: BLACK_WINS]; break;
case 3: [game setResult: DRAW]; break;
default: [game setResult: UNKNOWN];
}
[self displayPlayerNames];
[NSApp endSheet: pgnTagsSheet returnCode: 1];
}
-(IBAction)pgnTagsCancelPressed:(id)sender {
[pgnTagsSheet orderOut: sender];
[NSApp endSheet: pgnTagsSheet returnCode: 0];
}
-(void)pgnTagsSheetDidEnd:(NSWindow *)sheet
returnCode:(int)returnCode
contextInfo:(void *)contextInfo {
}
-(IBAction)flipBoard:(id)sender {
boardIsFlipped = !boardIsFlipped;
[boardView setNeedsDisplay: YES];
}
-(IBAction)takeBack:(id)sender {
[game unmakeMove];
[ec1 abortThinking];
[ec1 setPositionFromGame: game];
[boardView setNeedsDisplay: YES];
[self displayMoveList];
if(gameMode == ANALYSIS) [ec1 startAnalyseMode];
}
-(IBAction)stepForward:(id)sender {
[game stepForward];
[ec1 abortThinking];
[ec1 setPositionFromGame: game];
[boardView setNeedsDisplay: YES];
[self displayMoveList];
if(gameMode == ANALYSIS) [ec1 startAnalyseMode];
}
-(IBAction)beginningOfGame:(id)sender {
[game goToBeginningOfGame];
[ec1 abortThinking];
[ec1 setPositionFromGame: game];
[boardView setNeedsDisplay: YES];
[self displayMoveList];
if(gameMode == ANALYSIS) [ec1 startAnalyseMode];
}
-(IBAction)endOfGame:(id)sender {
[game goToEndOfGame];
[ec1 abortThinking];
[ec1 setPositionFromGame: game];
[boardView setNeedsDisplay: YES];
[self displayMoveList];
if(gameMode == ANALYSIS) [ec1 startAnalyseMode];
}
-(IBAction)displayVariations:(id)sender {
displayVariations = !displayVariations;
if(!displayVariations)
allowVariationEntry = NO;
[self displayMoveList];
// [moveListView setString: [self moveListString]];
}
-(IBAction)displayComments:(id)sender {
displayComments = !displayComments;
[self displayMoveList];
// [moveListView setString: [self moveListString]];
}
-(IBAction)allowVariationEntry:(id)sender {
allowVariationEntry = !allowVariationEntry;
if(allowVariationEntry)
displayVariations = YES;
[self displayMoveList];
// [moveListView setString: [self moveListString]];
}
-(IBAction)nextVariation:(id)sender {
[game goToNextVariation];
[ec1 abortThinking];
[ec1 setPositionFromGame: game];
[boardView setNeedsDisplay: YES];
[self displayMoveList];
if(gameMode == ANALYSIS) [ec1 startAnalyseMode];
}
-(IBAction)previousVariation:(id)sender {
[game goToPreviousVariation];
[ec1 abortThinking];
[ec1 setPositionFromGame: game];
[boardView setNeedsDisplay: YES];
[self displayMoveList];
if(gameMode == ANALYSIS) [ec1 startAnalyseMode];
}
-(IBAction)moveVariationUp:(id)sender {
[game moveVariationUp];
// [moveListView setString: [self moveListString]];
[self displayMoveList];
}
-(IBAction)moveVariationDown:(id)sender {
[game moveVariationDown];
// [moveListView setString: [self moveListString]];
[self displayMoveList];
}
-(IBAction)beginningOfVariation:(id)sender {
[game goToBeginningOfVariation];
[ec1 abortThinking];
[ec1 setPositionFromGame: game];
[boardView setNeedsDisplay: YES];
[self displayMoveList];
if(gameMode == ANALYSIS) [ec1 startAnalyseMode];
}
-(IBAction)endOfVariation:(id)sender {
[game goToEndOfVariation];
[ec1 abortThinking];
[ec1 setPositionFromGame: game];
[boardView setNeedsDisplay: YES];
[self displayMoveList];
if(gameMode == ANALYSIS) [ec1 startAnalyseMode];
}
-(IBAction)backToBranchPoint:(id)sender {
[game goBackToBranchPoint];
[ec1 abortThinking];
[ec1 setPositionFromGame: game];
[boardView setNeedsDisplay: YES];
[self displayMoveList];
if(gameMode == ANALYSIS) [ec1 startAnalyseMode];
}
-(IBAction)forwardToBranchPoint:(id)sender {
[game goForwardToBranchPoint];
[ec1 abortThinking];
[ec1 setPositionFromGame: game];
[boardView setNeedsDisplay: YES];
[self displayMoveList];
if(gameMode == ANALYSIS) [ec1 startAnalyseMode];
}
-(IBAction)deleteVariation:(id)sender {
if(NSRunAlertPanel(@"Delete variation?",
@"You cannot undo this action.",
@"OK", @"Cancel", nil, nil)
== NSAlertDefaultReturn) {
[game deleteVariation];
[boardView setNeedsDisplay: YES];
// [moveListView setString: [self moveListString]];
[self displayMoveList];
}
}
-(IBAction)addComment:(id)sender {
if(commentWindowController)
[commentWindowController release];
commentWindowController =
[[CommentWindowController alloc]
initWithMove: [[game currentNode] move]
boardController: self];
[commentWindowController showWindow: self];
}
-(IBAction)deleteComment:(id)sender {
if(NSRunAlertPanel(@"Delete comment?",
@"You cannot undo this action.",
@"OK", @"Cancel", nil, nil)
== NSAlertDefaultReturn) {
[game deleteComment];
// [moveListView setString: [self moveListString]];
[self displayMoveList];
}
}
-(void)setUpPositionWithFEN:(NSString *)fen {
if(setupController) [setupController release];
setupController = [[SetupR64WindowController alloc]
initWithBoardController: self
FEN: fen];
[setupController showWindow: self];
}
-(IBAction)setUpPosition:(id)sender {
[self setUpPositionWithFEN: [[game currentPosition] FENString]];
/*
if(setupController) [setupController release];
setupController = [[SetupR64WindowController alloc]
initWithBoardController: self
FEN: [[game currentPosition] FENString]];
[setupController showWindow: self];
*/
}
-(IBAction)configureEngine:(id)sender {
if(engineConfigController)
[engineConfigController release];
engineConfigController =
[[EngineConfigController alloc] initWithEngine: [ec1 engine]];
[engineConfigController showWindow: self];
}
-(void)setLevelType:(int)newLevelType {
levelType = newLevelType;
}
-(void)setTimeControlWithWhiteTime:(int)wtime
blackTime:(int)btime
whiteIncrement:(int)winc
blackIncrement:(int)binc {
[game setTimeControlWithWhiteTime: wtime
blackTime: btime
whiteIncrement: winc
blackIncrement: binc];
}
-(void)setTimeControlWithWhiteTime:(int)wtime
forMoves:(int)wmoves
blackTime:(int)btime
forMoves:(int)bmoves {
[game setTimeControlWithWhiteTime: wtime
forMoves: wmoves
blackTime: btime
forMoves: bmoves];
}
-(IBAction)gameInX:(id)sender {
levelType = BLITZ_LEVEL;
levelTime = [sender tag];
levelIncrement = 0;
[self setTimeControlWithWhiteTime: levelTime * 60000
blackTime: levelTime * 60000
whiteIncrement: 0
blackIncrement: 0];
}
-(IBAction)gameInXPlusY:(id)sender {
levelType = FISCHER_LEVEL;
levelTime = [sender tag];
switch(levelTime) {
case 1: case 2: case 5: levelIncrement = 1; break;
case 10: levelIncrement = 2; break;
default: levelIncrement = 5; break;
}
[self setTimeControlWithWhiteTime: levelTime * 60000
blackTime: levelTime * 60000
whiteIncrement: levelIncrement * 1000
blackIncrement: levelIncrement * 1000];
}
-(IBAction)fourtyMovesInXMinutes:(id)sender {
levelType = OLDFASHIONED_LEVEL;
levelTime = [sender tag];
levelIncrement = 0;
[self setTimeControlWithWhiteTime: levelTime * 60000
forMoves: 40
blackTime: levelTime * 60000
forMoves: 40];
}
-(IBAction)customLevel:(id)sender {
if(customLevelController)
[customLevelController release];
customLevelController =
[[CustomLevelController alloc] initWithBoardController: self];
[customLevelController showWindow: self];
}
-(BOOL)validateMenuItem:(id <NSMenuItem>)menuItem {
SEL action = [menuItem action];
if(NO) {
}
else if(action == @selector(castleKingside:)) {
if([[game currentPosition] sideToMoveCanCastleKingsideImmediately])
return YES;
else
return NO;
}
else if(action == @selector(castleQueenside:)) {
if([[game currentPosition] sideToMoveCanCastleQueensideImmediately])
return YES;
else
return NO;
}
else if(action == @selector(takeBack:) ||
action == @selector(beginningOfGame:))
return ![self isAtBeginningOfGame];
else if(action == @selector(stepForward:) || action == @selector(endOfGame:))
return ![self isAtEndOfGame];
else if(action == @selector(allowVariationEntry:)) {
if(allowVariationEntry)
[menuItem setTitle: @"Disable Variation Entry"];
else
[menuItem setTitle: @"Enable Variation Entry"];
return YES;
}
else if(action == @selector(displayVariations:)) {
if(displayVariations)
[menuItem setTitle: @"Hide Variations"];
else
[menuItem setTitle: @"Show Variations"];
return ![game isInAVariation];
}
else if(action == @selector(displayComments:)) {
if(displayComments)
[menuItem setTitle: @"Hide Comments"];
else
[menuItem setTitle: @"Show Comments"];
return YES;
}
else if(action == @selector(nextVariation:)) {
if(!displayVariations) return NO;
if(![game nextVariationExists]) return NO;
return YES;
}
else if(action == @selector(previousVariation:)) {
if(!displayVariations) return NO;
if(![game previousVariationExists]) return NO;
return YES;
}
else if(action == @selector(backToBranchPoint:)) {
// if(!displayVariations) return NO;
if(![game branchPointExistsUp]) return NO;
return YES;
}
else if(action == @selector(forwardToBranchPoint:)) {
// if(!displayVariations) return NO;
if(![game branchPointExistsDown]) return NO;
return YES;
}
else if(action == @selector(beginningOfVariation:)) {
if([game isAtBeginningOfVariation]) return NO;
return YES;
}
else if(action == @selector(endOfVariation:)) {
if([game isAtEndOfVariation]) return NO;
return YES;
}
else if(action == @selector(moveVariationUp:)) {
if(!displayVariations) return NO;
if(!allowVariationEntry) return NO;
if(![game previousVariationExists]) return NO;
return YES;
}
else if(action == @selector(moveVariationDown:)) {
if(!displayVariations) return NO;
if(!allowVariationEntry) return NO;
if(![game nextVariationExists]) return NO;
return YES;
}
else if(action == @selector(deleteComment:)) {
if([game commentExistsForCurrentMove]) return YES;
return NO;
}
else if(action == @selector(configureEngine:)) {
[menuItem setTitle: [NSString stringWithFormat: @"Configure %@...",
[ec1 engineName]]];
return YES;
}
else if(action == @selector(gameInX:)) {
if(levelType == BLITZ_LEVEL) {
int tag = [menuItem tag];
if(tag == levelTime) [menuItem setState: NSOnState];
else [menuItem setState: NSOffState];
}
else [menuItem setState: NSOffState];
}
else if(action == @selector(gameInXPlusY:)) {
if(levelType == FISCHER_LEVEL) {
int tag = [menuItem tag];
if(tag == levelTime) [menuItem setState: NSOnState];
else [menuItem setState: NSOffState];
}
else [menuItem setState: NSOffState];
}
else if(action == @selector(fourtyMovesInXMinutes:)) {
if(levelType == OLDFASHIONED_LEVEL) {
int tag = [menuItem tag];
if(tag == levelTime) [menuItem setState: NSOnState];
else [menuItem setState: NSOffState];
}
else [menuItem setState: NSOffState];
return YES;
}
else if(action == @selector(customLevel:)) {
if(levelType == CUSTOM_LEVEL) [menuItem setState: NSOnState];
else [menuItem setState: NSOffState];
}
else if(action == @selector(limitStrength:)) {
if([[ec1 engine] supportsLimitStrength])
return YES;
else
return NO;
}
return YES;
}
-(Game *)game {
return game;
}
-(IBAction)analysisMode:(id)sender {
gameMode = ANALYSIS;
[ec1 abortThinking];
[ec1 setPositionFromGame: game];
[ec1 startAnalyseMode];
}
-(IBAction)computerPlaysBlack:(id)sender {
gameMode = COMPUTER_BLACK;
if(!playerNamesWereEdited) {
[game setBlackPlayer: [ec1 engineName]];
[game setWhitePlayer: NSFullUserName()];
[self displayPlayerNames];
}
[ec1 setRole: PLAYING_BLACK];
if([game blackToMove]) {
[game pushClock];
if([[ec1 engine] shouldUseGUIBook]) {
ChessMove *bookMove = [guiBook pickMoveForPosition: [game currentPosition]
withVariety: 0];
if(bookMove != nil) {
[self animateMove: bookMove];
[game makeMove: bookMove];
[self displayMoveList];
[boardView setNeedsDisplay: YES];
}
else [ec1 moveWasMade];
}
else [ec1 moveWasMade];
}
}
-(IBAction)computerPlaysWhite:(id)sender {
gameMode = COMPUTER_WHITE;
if(!playerNamesWereEdited) {
[game setWhitePlayer: [ec1 engineName]];
[game setBlackPlayer: NSFullUserName()];
[self displayPlayerNames];
}
[ec1 setRole: PLAYING_WHITE];
if([game whiteToMove]) {
[game pushClock];
if([[ec1 engine] shouldUseGUIBook]) {
ChessMove *bookMove = [guiBook pickMoveForPosition: [game currentPosition]
withVariety: 0];
if(bookMove != nil) {
[self animateMove: bookMove];
[game makeMove: bookMove];
[self displayMoveList];
[boardView setNeedsDisplay: YES];