This is Chess.m in view mode; [Download] [Up]
#include <stdio.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/times.h>
#include <sys/file.h>
#include <pwd.h>
#import <appkit/appkit.h>
#import "chess_strings.h"
#import "Chess.h"
#import "gnuchess.h"
#import "gnuglue.h"
#import "Clock.h"
#import "Board.h"
#import "Board3D.h"
#import "ResponseMeter.h"
extern id NXWait, NXArrow;
extern short PieceList[2][16];
extern short PieceCnt[2];
extern gnuchess_main_init();
extern NewGame();
extern algbr();
/* extern getsectdata(); */
extern VerifyMove();
extern SelectMoveStart();
extern SelectMoveEnd();
extern SelectLoop();
short GameQueens[240];
#ifdef NeXT_DEBUG
#define chess_debug(x) { printf x; }
#else
#define chess_debug(x)
#endif
@implementation Chess
static void Counter();
+ initialize
{
gnuchess_main_init();
}
+ new
{
self = [super new];
pwen = getpwuid( getuid() );
pref.time_control_minutes = 5;
pref.time_control_moves = 60;
pref.opponent = white;
pref.computer = black;
pref.bothsides = false;
pref.cheat = YES;
pref.white_name = pwen->pw_gecos;
pref.black_name = (char *)COMPUTER;
return self;
}
/*
Get InterfaceBuilder outlets.
*/
- setClockWindow: anObject { clockWindow = anObject; }
- clockWindow { return clockWindow; }
- setWhiteSideMatrix: anObject { whiteSideMatrix = anObject; }
- setBlackSideMatrix: anObject { blackSideMatrix = anObject; }
- setForceButton: anObject { forceButton = anObject; }
- setStartButton: anObject { startButton = anObject; }
- setSetButton: anObject { setButton = anObject; }
- setWhiteName: anObject { whiteName = anObject; }
- setBlackName: anObject { blackName = anObject; }
- setInfoPanel: anObject { infoPanel = anObject; }
- setInfoScroll: anObject { infoScroll = anObject; }
- setWhiteClock: anObject { whiteClock = anObject; }
- whiteClock { return whiteClock; }
- setBlackClock: anObject { blackClock = anObject; }
- blackClock { return blackClock; }
- setWhiteClockText: anObject { whiteClockText = anObject; }
- setBlackClockText: anObject { blackClockText = anObject; }
- setBoardWindow: anObject { boardWindow = anObject; }
- setLevelText: anObject { levelText = anObject; }
- setWhiteMeter: anObject { whiteMeter = anObject; }
- whiteMeter { return whiteMeter; }
- setBlackMeter: anObject { blackMeter = anObject; }
- blackMeter { return blackMeter; }
- setLevelSlider: anObject { levelSlider = anObject; }
- setBoard3D: anObject { gameBoard = board3D = anObject; }
- setBoard2D: anObject { board2D = anObject; [board2D removeFromSuperview]; }
/*
Action methods for InterfaceBuilder objects.
*/
- print: sender
{
[gameBoard printPSCode: sender];
return self;
}
- (int) openFile:(char const *)s ok:(int *)flag {
GetGame( s );
*flag = YES;
return 0;
}
- plastic: sender
{
id plastic;
if( gameBoard == board2D )
return self;
plastic = [Bitmap findBitmapFor: "3d_plastic.tiff"];
[gameBoard setBackgroundBitmap: plastic];
[gameBoard display];
}
- granite: sender
{
id granite;
if( gameBoard == board2D )
return self;
granite = [Bitmap findBitmapFor: "3d_board.tiff"];
[gameBoard setBackgroundBitmap: granite];
[gameBoard display];
}
- gameBoard { return gameBoard; }
- view2D: sender
{
NXRect b;
id v;
if( gameBoard == board2D )
return self;
v = [gameBoard superview];
[v getBounds: &b];
[v lockFocus];
PSgsave();
PSsetgray( NX_BLACK );
PSrectfill( 0, 0, b.size.width, b.size.height );
PSgrestore();
[v unlockFocus];
[gameBoard removeFromSuperview];
[v addSubview: board2D];
gameBoard = board2D;
[gameBoard layoutBoard: board color: color];
[gameBoard display];
NXPing();
}
- view3D: sender
{
id v;
if( gameBoard == board3D )
return self;
v = [gameBoard superview];
[gameBoard removeFromSuperview];
[v addSubview: board3D];
gameBoard = board3D;
[gameBoard layoutBoard: board color: color];
[gameBoard display];
NXPing();
}
- levelSliding: sender
/*
Change the text displayed below the level slider to indicate
what the level means.
*/
{
char buf[32];
int moves, minutes;
Level = [levelSlider intValue];
switch (Level){
case 1 : moves = 60; minutes = 5; break;
case 2 : moves = 60; minutes = 15; break;
case 3 : moves = 60; minutes = 30; break;
case 4 : moves = 40; minutes = 30; break;
case 5 : moves = 40; minutes = 60; break;
case 6 : moves = 40; minutes = 120; break;
case 7 : moves = 40; minutes = 240; break;
case 8 : moves = 1; minutes = 15; break;
case 9 : moves = 1; minutes = 60; break;
case 10 : moves = 1; minutes = 600; break;
}
if( moves > 1 )
sprintf( buf, "%d moves in %d minutes", moves, minutes );
else
sprintf( buf, "%d move in %d minutes", moves, minutes );
[levelText setStringValue: buf];
}
- setPreferences: sender
/*
Actually set the preferences.
*/
{
int whiteSide = [whiteSideMatrix selectedRow];
int blackSide = [blackSideMatrix selectedRow];
int change = NO;
int button;
button = NXRunAlertPanel( 0,
"Start a new game with these Preferences?", "Yes", "No", 0
);
switch( (Level = [levelSlider intValue]) ){
case 1 : pref.time_control_moves = 60; pref.time_control_minutes = 5; break;
case 2 : pref.time_control_moves = 60; pref.time_control_minutes = 15; break;
case 3 : pref.time_control_moves = 60; pref.time_control_minutes = 30; break;
case 4 : pref.time_control_moves = 40; pref.time_control_minutes = 30; break;
case 5 : pref.time_control_moves = 40; pref.time_control_minutes = 60; break;
case 6 : pref.time_control_moves = 40; pref.time_control_minutes = 120; break;
case 7 : pref.time_control_moves = 40; pref.time_control_minutes = 240; break;
case 8 : pref.time_control_moves = 1; pref.time_control_minutes = 15; break;
case 9 : pref.time_control_moves = 1; pref.time_control_minutes = 60; break;
case 10 : pref.time_control_moves = 1; pref.time_control_minutes = 600; break;
}
if( whiteSide == 0 && blackSide == 0 ){
pref.bothsides = 1;
pref.opponent = white;
pref.computer = black;
}
else if( whiteSide == 1 && blackSide == 0 ){
pref.bothsides = 0;
pref.opponent = white;
pref.computer = black;
}
else if( whiteSide == 0 && blackSide == 1 ){
pref.bothsides = 0;
pref.opponent = black;
pref.computer = white;
}
else
chess_debug(( "Unsupported combination\n" ));
pref.white_name = (char *)[whiteName stringValue];
pref.black_name = (char *)[blackName stringValue];
if ( button == NX_ALERTDEFAULT ) {
[self newGame: self];
}
}
- usePreferences
/*
Use current preferences
*/
{
TCmoves = pref.time_control_moves;
TCminutes = pref.time_control_minutes;
TCflag = (TCmoves > 1);
SetTimeControl();
bothsides = pref.bothsides;
opponent = pref.opponent;
computer = pref.computer;
if( bothsides ){
[startButton setEnabled: YES];
[startButton display];
}
else{
[startButton setEnabled: NO];
[startButton display];
}
[self setWhiteName: pref.white_name blackName: pref.black_name];
}
- openGame: sender
/*
Read a saved game.
*/
{
id op = [OpenPanel new];
const char *types[2];
types[0] = "chess";
types[1] = 0;
finished = 0;
[op setRequiredFileType: "chess"];
if( [op runModalForTypes: types] ){
if( filename )
free( filename );
filename = (char *)malloc( strlen( [op filename] ) + 1 );
strcpy( filename, [op filename] );
GetGame( filename );
}
}
- saveAsGame: sender
/*
Save a game.
*/
{
id sp = [SavePanel new];
[sp setRequiredFileType: "chess"];
if( [sp runModal] ){
if( filename )
free( filename );
filename = (char *)malloc( strlen( [sp filename] ) + 1 );
strcpy( filename, [sp filename] );
SaveGame( filename );
}
}
- saveGame: sender
{
if( filename )
SaveGame( filename );
else
[self saveAsGame: sender];
}
- listGame: sender
/*
Save a game.
*/
{
id sp = [SavePanel new];
[sp setRequiredFileType: 0];
if( [sp runModal] )
ListGame( [sp filename] );
}
- newGame: sender
/*
Start a new game.
*/
{
forceCount = hintCount = undoCount = 0;
finished = 0;
NewGame();
[self setTitle];
[self usePreferences];
if( bothsides ){
[startButton setEnabled: YES];
[startButton display];
}
else{
[startButton setEnabled: NO];
[startButton display];
if( computer == white && !mate && !quit )
[self selectMove: computer iop: 1];
}
}
- chooseSide: sender
/*
Set the text fields next to the side matrices.
*/
{
int whiteSide = [whiteSideMatrix selectedRow];
int blackSide = [blackSideMatrix selectedRow];
if( whiteSide == 1 && blackSide == 0 ){
[whiteName setStringValue: pwen->pw_gecos];
[blackName setStringValue: "Computer"];
}
else if( whiteSide == 0 && blackSide == 1 ){
[blackName setStringValue: pwen->pw_gecos];
[whiteName setStringValue: "Computer"];
}
else if( whiteSide == 1 && blackSide == 1 ){
[blackName setStringValue: pwen->pw_gecos];
[whiteName setStringValue: pwen->pw_gecos];
}
else{
[blackName setStringValue: "Computer"];
[whiteName setStringValue: "Computer"];
}
return self;
}
-forceMove: sender
{
timeout = true;
}
BOOL playing = NO;
- startGame: sender
{
id menuList = [[self mainMenu] itemList];
int i, r, c;
[menuList getNumRows: &r numCols: &c];
if( [sender state] == 1 && playing == NO ){
quit = false;
playing = YES;
/* This is the loop that makes the computer play. It can be terminated */
/* by several conditions. The "Stop" button may be clicked, cmd-. may */
/* be pressed, or the game may end. */
while( !mate && !quit && !finished && playing )
[self selectMove: player iop: 1];
quit = true;
timeout = true;
playing = NO;
for( i = 0; i < r; i++ )
[[menuList cellAt: i :0] setEnabled: YES];
[[self mainMenu] display];
[sender setState: 0];
}
else if( [sender state] == 0 && playing == YES ){
quit = true;
timeout = true;
playing = NO;
for( i = 0; i < r; i++ )
[[menuList cellAt: i :0] setEnabled: YES];
[[self mainMenu] display];
}
}
- hint: sender
/*
Give the player a hint.
*/
{
short from = hint>>8;
short to = hint & 0xff;
int row, col;
if( hint ){
algbr( (short)(hint>>8), (short)(hint & 0xff), false );
chess_debug(( "hint: %s\n", mvstr1 ));
hintCount++;
row = (int)(from / 8);
col = (int)(from % 8);
[gameBoard highlightSquareAt: row : col];
row = (int)(to / 8);
col = (int)(to % 8);
[gameBoard highlightSquareAt: row : col];
[self setTitle];
}
else
NXRunAlertPanel( 0, "I don't have a hint.", 0, 0, 0 );
}
- undoMove: sender
/*
Undo last two half moves.
*/
{
if( GameCnt >= 0 ){
Undo(); Undo();
undoCount++;
// mate = false; /* Glenn Reid (NeXT) Mon Apr 16 00:39:35 PDT 1990 */
[self setTitle];
}
else
NXRunAlertPanel( 0, "No more moves to undo.", 0, 0, 0 );
}
- info: sender
{
char *copyright;
int copy_size;
NXStream *copy_stream;
id text;
copyright = (char *)getsectdata( "__COPYRIGHT", "COPYING", ©_size);
if( copyright != NULL ){
copy_stream = NXOpenMemory( copyright, copy_size, NX_READONLY );
text = [infoScroll docView];
[text readText: copy_stream];
[text sizeToFit];
[text setFont: [Font newFont: "Times" size: 14.0]];
[infoScroll display];
}
[infoPanel makeKeyAndOrderFront: sender];
}
/*
Support methods.
*/
- setFinished: (int) f { finished = f; [self finishedAlert]; return self; }
- (int)finished { return finished; }
- (int)bothsides { return pref.bothsides; }
- storePosition: (int) row : (int) col {
currentRow = row;
currentCol = col;
}
- showPosition: sender
{
[gameBoard highlightSquareAt: currentRow : currentCol];
[gameBoard flashSquareAt: currentRow : currentCol];
return self;
}
- finishedAlert
{
printf( "opponent %d, computer %d\n", opponent, computer );
switch( finished ){
case DRAW_GAME:
NXRunAlertPanel( 0, "The game is a draw.", 0, 0, 0 );
break;
case WHITE_MATE:
NXRunAlertPanel( 0, "The game is over. Black wins.", 0, 0, 0 );
break;
case BLACK_MATE:
NXRunAlertPanel( 0, "The game is over. White wins.", 0, 0, 0 );
break;
case OPPONENT_MATE:
NXRunAlertPanel( 0, "The game is over.\nCongratulations, you win.", 0, 0, 0 );
break;
default:
break;
}
}
- (int)makeMoveFrom: (int)r1 : (int)c1 to: (int)r2 : (int)c2
{
unsigned short mv;
char *move;
short oldguy, newguy;
oldguy = [gameBoard typeAt: r1 : c1];
move = convert_rc( r1, c1, r2, c2, [gameBoard typeAt: r1 : c1] );
player = opponent;
if( !VerifyMove( move, 0, &mv ) ){
ShowMessage( "Illegal move" );
NXBeep();
return( 0 );
}
else {
/* if your pawn is promoted to queen and then you Undo, the queen
should turn back into a pawn.
Glenn Reid (NeXT) Mon Apr 16 00:49:26 PDT 1990
*/
newguy = [gameBoard typeAt: r2 : c2];
if ( (newguy == queen) && (oldguy == pawn) ) {
fprintf ( stderr, "pawn becomes queen...\n" );
GameQueens[GameCnt] = oldguy;
} else {
GameQueens[GameCnt] = 0;
}
chess_debug(( "opponent move time %d move %s\n",
GameList[GameCnt].time, move ));
[self updateClocks: opponent];
InCheck();
NXPing();
[gameBoard layoutBoard: board color: color];
[gameBoard display];
NXPing();
Sdepth = 0;
ft = 0;
if( !(quit || mate || force) )
[self selectMove: computer iop: 1];
}
return( 1 );
}
- selectMove: (int)side iop: (int)iop
{
id menuList = [[self mainMenu] itemList];
int i, r, c;
if( side == black ) {
ShowMessage( "Black's move" );
} else {
ShowMessage( "White's move" );
}
[forceButton setEnabled: YES];
[forceButton display];
NXPing();
[menuList getNumRows: &r numCols: &c];
for( i = 0; i < r-1; i++ )
[[menuList cellAt: i :0] setEnabled: NO];
[[self mainMenu] display];
if( !bothsides )
[setButton setEnabled: NO];
[gameBoard setEnabled: NO];
bzero( &move_info, sizeof( struct MoveInfo ) );
move_info.iop = iop;
move_info.side = side;
Sdepth = 0;
SelectMoveStart( &move_info );
while (!timeout && Sdepth < MaxSearchDepth)
SelectLoop( &move_info );
[self selectMoveEnd];
[self setTitle];
InCheck();
NXPing();
return self;
}
- selectMoveEnd
{
id menuList = [[self mainMenu] itemList];
int i, r, c;
SelectMoveEnd( &move_info );
[self updateClocks: computer];
chess_debug(("computer move time %d, move %s\n",
GameList[GameCnt].time, mvstr1 ));
InCheck();
NXPing();
[menuList getNumRows: &r numCols: &c];
if( !bothsides )
for( i = 0; i < r; i++ )
[[menuList cellAt: i :0] setEnabled: YES];
[[self mainMenu] display];
[setButton setEnabled: YES];
[gameBoard setEnabled: YES];
NXPing();
[forceButton setEnabled: NO];
[forceButton display];
NXPing();
return;
}
- setWhiteName: (char *)wname blackName: (char *)bname
{
[whiteClockText setStringValue: wname];
[blackClockText setStringValue: bname];
if( [whiteSideMatrix selectedRow] == 1 ){
[whiteName setStringValue: wname];
}
else{
[whiteName setStringValue: COMPUTER];
}
if( [blackSideMatrix selectedRow] == 1 ){
[blackName setStringValue: bname];
}
else{
[blackName setStringValue: COMPUTER];
}
}
- (int)whiteTime { return wtime; }
- (int)blackTime { return btime; }
- updateClocks: (int)side
{
if( !blackClock || !whiteClock )
return self;
if( side == white ){
wtime += GameList[GameCnt].time;
if( [clockWindow isVisible] ){
[whiteClock setSeconds: wtime];
[whiteClock display];
}
}
else{
btime += GameList[GameCnt].time;
if( [clockWindow isVisible] ){
[blackClock setSeconds: wtime];
[blackClock display];
}
}
}
- updateClocks: (int)side seconds: (int) seconds
{
if( side == white ){
if( [clockWindow isVisible] ){
[whiteClock setSeconds: wtime];
[whiteClock display];
}
}
else{
if( [clockWindow isVisible] ){
[blackClock setSeconds: wtime];
[blackClock display];
}
}
}
- setTitle
/*
Change the board windows title to display the number of cheat commands
issued.
*/
{
char buf[64];
if( undoCount || hintCount ){
sprintf( buf, "Chess: " );
if( undoCount ){
if( undoCount == 1 )
sprintf( buf+strlen(buf), "1 Undo " );
else
sprintf( buf+strlen(buf), "%d Undos ", undoCount );
}
if( hintCount ){
if( hintCount == 1 )
sprintf( buf+strlen(buf), "1 Hint" );
else
sprintf( buf+strlen(buf), "%d Hints", hintCount );
}
}
else
sprintf( buf, "Chess" );
[boardWindow setTitle: buf];
}
- setTitleMessage: (char *)m
{
char *om;
char buf[128];
[self setTitle];
om = (char *)[boardWindow title];
strcpy( buf, om );
strcat( buf, " : " );
strcat( buf, m );
[boardWindow setTitle: buf];
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.