home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Education Sampler 1992 [NeXTSTEP]
/
Education_1992_Sampler.iso
/
NeXT
/
GnuSource
/
Chess-9
/
Chess.m
< prev
next >
Wrap
Text File
|
1992-05-08
|
20KB
|
862 lines
#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
+ initialize
{
gnuchess_main_init();
return self;
}
+ 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;
white_color = NX_COLORWHITE;
black_color = NX_COLORWHITE;
[self newGame: self];
return self;
}
/*
Get InterfaceBuilder outlets.
*/
- clockWindow { return clockWindow; return self; }
- whiteClock { return whiteClock; }
- blackClock { return blackClock; }
- whiteMeter { return whiteMeter; }
- blackMeter { return blackMeter; }
- setBoard3D: anObject { gameBoard = board3D = anObject; return self; }
- setBoard2D: anObject { board2D = anObject; [board2D removeFromSuperview]; return self; }
/*
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;
}
- setBlackColor:sender
{
float sat;
black_color = [sender color];
black_color = NXChangeAlphaComponent(black_color,1.0);
black_color = NXChangeBrightnessComponent(black_color,1.0);
sat = NXSaturationComponent(black_color);
if(sat > .21 ) black_color = NXChangeSaturationComponent(black_color,.21);
[self renderPreview];
return self;
}
- setWhiteColor:sender
{
float sat;
white_color = [sender color];
white_color = NXChangeAlphaComponent(white_color,1.0);
white_color = NXChangeBrightnessComponent(white_color,1.0);
sat = NXSaturationComponent(white_color);
if(sat > .21 ) white_color = NXChangeSaturationComponent(white_color,.21);
[self renderPreview];
return self;
}
- renderPreview
{
NXRect r;
NXPoint pt = {0.0,0.0};
static id blacky = nil;
static id whitey = nil;
static id image1 = nil;
static id image2 = nil;
if(!whitey) whitey = [NXImage newFromSection: "3d_white_sample.tiff"];
if(!blacky) blacky = [NXImage newFromSection: "3d_black_sample.tiff"];
if(!image1) image1 = [NXImage newFromSection: "3d_black_sample.tiff"];
if(!image2) image2 = [NXImage newFromSection: "3d_black_sample.tiff"];
[whitey getSize:&r.size];
r.origin.x = r.origin.y = 0.0;
[image2 lockFocus];
[whitey composite:NX_COPY fromRect:&r toPoint:&pt];
[image2 unlockFocus];
[image1 lockFocus];
[whitey composite:NX_COPY fromRect:&r toPoint:&pt];
[image1 unlockFocus];
[image1 lockFocus];
NXSetColor(white_color);
PScompositerect(0.0,0.0,r.size.width,r.size.height, NX_PLUSD);
[image1 unlockFocus];
[image2 lockFocus];
[image1 composite:NX_SATOP fromRect:&r toPoint:&pt];
[image2 unlockFocus];
[[whitesample image] lockFocus];
[image2 composite:NX_COPY fromRect:&r toPoint:&pt];
[[whitesample image] unlockFocus];
[image2 lockFocus];
[blacky composite:NX_COPY fromRect:&r toPoint:&pt];
[image2 unlockFocus];
[image1 lockFocus];
[blacky composite:NX_COPY fromRect:&r toPoint:&pt];
[image1 unlockFocus];
[image1 lockFocus];
NXSetColor(black_color);
PScompositerect(0.0,0.0,r.size.width,r.size.height, NX_PLUSD);
[image1 unlockFocus];
[image2 lockFocus];
[image1 composite:NX_SATOP fromRect:&r toPoint:&pt];
[image2 unlockFocus];
[[blacksample image] lockFocus];
[image2 composite:NX_COPY fromRect:&r toPoint:&pt];
[[blacksample image] unlockFocus];
[blacksample display];
[whitesample display];
return self;
}
- renderColors:sender
{
id image2;
id image1;
NXRect r;
NXPoint pt = {0.0,0.0};
if( gameBoard != board3D ) return self;
image1 = [NXImage newFromSection: "3d_pieces.tiff"];
image2 = [gameBoard backgroundBitmap];
[image2 getSize:&r.size];
r.origin.x = r.origin.y = 0.0;
[image2 lockFocus];
[image1 composite:NX_COPY fromRect:&r toPoint:&pt];
[image2 unlockFocus];
[image1 lockFocus];
NXSetColor(white_color);
PScompositerect(0.0,0.0,336.0,r.size.height, NX_PLUSD);
NXSetColor(black_color);
PScompositerect(336.0,0.0,336.0,r.size.height, NX_PLUSD);
[image1 unlockFocus];
[image2 lockFocus];
[image1 composite:NX_SATOP fromRect:&r toPoint:&pt];
[image2 unlockFocus];
[gameBoard display];
if (image1) [image1 free];
return self;
}
- plastic: sender
{
id plastic;
if( gameBoard == board2D )
return self;
plastic = [NXImage newFromSection: "3d_board.tiff"];
[gameBoard setBackgroundBitmap: plastic];
[gameBoard display];
return self;
}
- 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();
return self;
}
- 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();
return self;
}
- levelSliding: sender
/*
Change the text displayed below the level slider to indicate
what the level means.
*/
{
char buf[32];
int moves = 0, minutes = 0;
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];
return self;
}
- 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];
}
return 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];
return self;
}
- 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 );
}
return self;
}
- 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 );
}
return self;
}
- saveGame: sender
{
if( filename )
SaveGame( filename );
else
[self saveAsGame: sender];
return self;
}
- listGame: sender
/*
Save a game.
*/
{
id sp = [SavePanel new];
[sp setRequiredFileType: 0];
if( [sp runModal] )
ListGame( [sp filename] );
return self;
}
- 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];
}
return self;
}
- 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;
return self;
}
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];
}
return self;
}
- 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 );
return self;
}
- 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 );
return self;
}
- 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];
return self;
}
/*
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;
return self;
}
- 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;
}
return self;
}
- (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 self;
}
- 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];
}
return self;
}
- (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];
}
}
return self;
}
- 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];
}
}
return self;
}
- 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];
return self;
}
- 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];
return self;
}
@end