DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T i

⟦37a7f2a26⟧ TextFile

    Length: 22583 (0x5837)
    Types: TextFile
    Names: »init.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Cchess/init.c« 

TextFile

/* CCHESS CHALLENGE ROUTINES					version 1.00
 *
 *    (C) Copyright - Jan D. Wolter - Apr 1986
 *
 *    Mostly routines to make and accept game challenges.
 */

#include "cchess.h"

#ifndef NOTERMCAP
extern char *DL;
#endif NOTERMCAP

/* CHALLENGE()
 *
 *   Make a challenge.  User is prompted for options.  Challenge line is
 *   written in the game file.  The flag counter is set if this is a
 *   counter challenge to a previous challenge.
 */

dochallenge(counter)
boolean counter;
{
register int i;
char ch,var;
	
    /* Choose colors */

    wprint("\nWhat color would you like ");
    if (counter)
    {
	wprintf("[%s]? ",pcol(mycolor));
	ch = enterd("WB",(mycolor==WHITE)?'W':'B');
    }
    else
    {
	wprint("(B/W)? ");
	ch = enter("WB");
    }
    if (ch == 'W')
    {
	wprint("hite");
	mycolor = WHITE;
    }
    else
    {
	wprint("lack");
	mycolor = BLACK;
    }
    if (order == (schar) -1)
	Firstwhite = (ch == 'B');
    else
	Firstwhite = (ch == 'W');

    wprint("\nDo you wish to play a variant game ");
    if (counter)
    {
	ch = (Game_type != TY_CHESS);
	wprintf("[%s]? ",yorn(ch));
	ch = enterdyn(ch);
    }
    else
    {
	wprint("(Y/N)? ");
	ch = enteryn();
    }

    if (ch)
    {
	wprint("\nVariants games are:\n");
	wprint("  (A) Chess            - Standard modern game\n");
	wprint("  (B) Kriegspiel       - Other player's moves hidden\n");
	wprint("  (C) Shatranj         - 6th century Persian game\n");
	wprint("  (D) Courier          - 13th century 12x8 board game\n");
	wprint("  (E) Halfboard        - Standard game on 4x8 board\n");
	wprint("  (F) Karma Chess      - Capturing men promoted to victim's rank\n");
	wprint("  (G) Rifle Chess      - Capture without moving\n");
	wprint("  (H) Kamikazi Chess   - Capturing men lost\n");
	wprint("  (I) Double Chess     - Make two moves per turn\n");
	wprint("  (J) Steamroller      - White pawns and king move twice\n");
	wprint("  (K) Progressive      - One more move every turn\n");
	wprint("  (L) Maharajah        - White has only maharajah piece\n");
	wprint("  (M) Losing Chess     - First one to lose all his men wins.\n");
	wprint("  (N) Conversion Chess - Combination of Karma and Rifle Chess\n");
	/* If you add to the menu above, add letter to string below */
	if (counter && Game_type == TY_MIXED)
	    wprint("  (Z) Mixed Game     - Same custom game you were challenged to\n");
	wprintf("\nWhich would you like to play [%s]? ",
	    typename[counter ? Game_type : TY_CHESS]);
	ch = xenterd("ZABCDEFGHIJKLMN" + (!counter || Game_type != TY_MIXED),
	    counter?((Game_type == TY_MIXED)? 'Z': Game_type+'A'-1):'A');

	var = (ch == 'Z') ? TY_MIXED : ch - 'A' + 1;
	wprintf("%c - %s",ch,typename[var]);

	if (var != TY_MIXED)
	{
	    /* Set up default options */
	    for (i=1;i<OPTIONS;i++)
		option[i] = defopt[var][i];

	    /* Make the initial board */
	    setup(b);
	}

	wprint("\nWould you like to customize the game? ");
	if (enterdyn(counter?(Game_type==TY_MIXED):FALSE))
	{
	    customize();
	    goto skip;
	}
    }
    else
    {
	/* Copy in the default options */
	for (i=1;i<OPTIONS;i++)
	    option[i] = defopt[1][i];
	setup(b);
    }

    /* Ask about the basic stuff */

    wprint("Would you like the game to be private (Y/N)? ");
    Private = enterdyn(Kriegspiel);

    if (!Musttake && !Kriegspiel && !Musttake &&
	Capture == CA_NORMAL && Kcapture == CA_NORMAL)
    {
	wprint("Would you like the computer to kibitz (Y/N)? ");
	Help_me = enterdyn(Help_me);
    }
    else
	Help_me = FALSE;

    /* write challenge line to game file */

skip:if (newgame)
    {
	if ((wfp=fopen(fname,"w"))==NULL)
	{
	    wprintf("Cchess error:  Unable to create gamefile %s\n",fname);
	    done(1);
	}
	chmod(fname,0700);
        fprintf(wfp,"%5ld:V %s\n",day(),version);
    }

    /* Save the challenge */
    fprintf(wfp,"%5ld:C ",day());
    saveopts(wfp);
    placeboard(b);
    fflush(wfp);

    /* send a challenge message */
    sprintf(cbuffer,"You have been challenged to a game of chess by %s.\nRun \042%s %s\042 to respond.\n",myid,RUN_CMD,myid);
    mesg("Cchess Challenge",cbuffer);

}

/* CUSTOMIZE
 *
 *   Fiddle with low-level game options.  This does run in visual mode.
 *   The use of the goofy loop here is to make suspends work correctly.
 */

customize()
{
schar ob[R_SIZE][C_SIZE];
register int question;
register int i;
boolean progress;
int v,r,c,tmparea;

    hidden = FALSE;
    question = 0;
#ifndef LSIGNAL
    susp1_flg = TRUE;
    setjmp(susp_env);
#endif LSIGNAL
    scrolled = TRUE;

    for ( ; question >= 0 ; question++)
    {
	if (scrolled)
	{
	    disp(b,WHITE);
	    if (question != 9)
	    {
		tmparea = (cy + 1 >= LINES) ? LINES - 1 : cy + 1;
		cprint("[default answers shown in brackets]");
	    }
	    wputchar('\n');
	    msgarea = (cy >= LINES) ? LINES - 1 : cy;
	}
	switch(question)
	{
	case 0:		/* Get the board size */
	    wprintf("Board Size [%dx%d]:",Rows+1,Cols+1);
	    wprintf("\nRows     (1-%d)? ", HI_ROWS+1);
	    v = readdint(HI_ROWS+1,Rows+1)-1;
	    wputchar('\n');
	    if (v != Rows) scrolled = TRUE;
	    Rows = v;
	    break;
	case 1:
	    wprintf("Columns (1-%d)? ", HI_COLS+1);
	    v = readdint(HI_COLS+1,Cols+1)-1;
	    wputchar('\n');
	    if (v != Cols) scrolled = TRUE;
	    Cols = v;
	    if (Cols == 0 && Rows == 0)
	    {
		wprint("You got to be kidding!\n");
		scrolled = FALSE;
		question -=2;
	    }
	    break;

	case 2:
	    wprintf("Is the board checkered [%s]? ",yorn(!Plain));
	    v = !enterdyn(!Plain);
	    if (v != Plain) scrolled = TRUE;
	    Plain = v;
	    break;

	case 3:		/* Piece names */
	    initmore();
	    mprintf("What names should the pieces be given");
	    Language = enterone(langname,HI_NAMES,Language);
	    piecename = chessname[Language];
	    break;

	case 4:		/* White King piece */
	    wprintf("Should white have a mateable piece [%s]? ",
		yorn(Whiteking != SQ));
	    if (!enterdyn(Whiteking != SQ))
	    {
		Whiteking = SQ;
		question++;	
	    }
	    break;
	case 5:
	    wprintf("Which is the white mateable piece [%s]? ",
		    (Whiteking != SQ)? pman(Whiteking) : "");
	    while ((v = xenterd(pc,pc[PIECES-Whiteking])) == ' ')
		bell();
	    Whiteking = PIECES - (index(pc,v)-pc);
	    wprintf("%s\n",pman(Whiteking));
	    break;

	case 6:		/* Black King piece */
	    wprintf("Should black have a mateable piece [%s]? ",
		yorn(Blackking != SQ));
	    if (!enterdyn(Blackking != SQ))
	    {
		Blackking = SQ;
		question++;
	    }
	    break;
	case 7:
	    wprintf("Which is the black mateable piece [%s]? ",
		    (Blackking != SQ)? pman(Blackking) : "");
	    while ((v = xenterd(pc,pc[PIECES-Blackking])) == ' ')
		bell();
	    Blackking = PIECES - (index(pc,v)-pc);
	    wprintf("%s\n",pman(Blackking));
	    break;


	case 8:	/* Edit the board - If board is illegal keep asking till ok */
	    wprintf("Would you like to edit the initial placement [No]? ");
	    if (enterdyn(FALSE))
	    {
		/* Set things up for the editor */
		copy(b,bc);
		copy(b,ob);
#ifndef NOTERMCAP
		/* Clear scrolling area */
		if (cleardown)
		{
		    cursor(1,tmparea);
		    msgarea = tmparea;
		    clbot();
		}
		else
#endif NOTERMCAP
		    scrolled = TRUE;

		break;
	    }
	    else
	    {
#ifndef NOTERMCAP
		if (!DL && cy == LINES) wputchar('\n');
#endif NOTERMCAP
		/* If he says not to edit, make sure board is OK */
		if (!checkbd(b,WHITE) || !checkbd(b,BLACK))
		    question--;
		else
		    question++;
	    }
	    break;

	case 9:		/* Take an editor command */
	    if (editbd(b,ob))
		question--;
	    else
	    {
#ifndef NOTERMCAP
		if (cleardown)
		{
		    cursor(1,msgarea);
		    clbot();
		    cprint("[default answers shown in brackets]");
		    wputchar('\n');
		    msgarea = (cy >= LINES) ? LINES - 1 : cy;
		}
		else
#endif NOTERMCAP
		    scrolled = TRUE;
	    }
	    break;

	case 10:	/* Enter Capture Rules */
	    initmore();
	    mprint("What is the rule for pieces capturing");
	    Capture = enterone(captname,HI_CAPTURE,Capture);
	    break;
	case 11:
	    if (Whiteking != SQ || Blackking != SQ)
	    {
		initmore();
		mprint("What is the rule for ");
		pkings(mprintf);
		mprint(" capturing");
		Kcapture = enterone(captname,HI_KCAPTURE,Kcapture);
	    }
	    break;

	case 12:	/* Is this Kriegspiel? */
	    wprintf("Are enemy pieces visible to player [%s]? ",
		yorn(!Kriegspiel));
	    Kriegspiel = !enterdyn(!Kriegspiel);
	    break;

	case 13:	/* May both players castle? */
	    if (cancastle(b,WHITE) || cancastle(b,BLACK))
	    {
		wprintf("Is castling allowed [%s]? ", yorn(!Oldcastle));
		Oldcastle = !enterdyn(!Oldcastle);
	    }
	    /* if not possible to castle, just leave option with default */
	    break;

	case 14:	/* Old fashioned pawns? */
	    /* Ask if there are any pawns, ask about pawn moves */
	    if ((find(b,WP,&r,&c),r != -1) || (find(b,BP,&r,&c),r != -1))
	    {
		wprintf("Can Pawn move double on their first moves [%s]? ",
		    yorn(!Oldpawn));
		Oldpawn = (!enterdyn(!Oldpawn));
	    }
	    else
		question++;
	    break;
	case 15:
	    if (Whiteking != WP && Blackking != WP)
	    {
		wprintf("Pawn promotion to %s, %s, %s or %s [%s]? ",
		    piecename[WQ], piecename[WR], piecename[WB],
		    piecename[WN], yorn(Promotion==PR_QRBN));
		if (enterdyn(Promotion==PR_QRBN))
		{
		    Promotion = PR_QRBN;
		    question++;
		}
	    }
	    else
	    {
		Promotion = PR_NONE;
		question++;
	    }
	    break;
	case 16:
	    if (Whiteking != WM && Blackking != WM)
	    {
		wprintf("Pawn promotion to %s only [%s]? ",
		    piecename[WM], yorn(Promotion!=PR_NONE));
		if (enterdyn(Promotion!=PR_NONE))
		    Promotion = PR_MINISTER;
		else
		    Promotion = PR_NONE;
	    }
	    else
		Promotion = PR_NONE;
	    break;

	case 17:	/* Select Multiple moves */
	    if (Capture == CA_CONVERSION || Kcapture == CA_CONVERSION)
	    {
		Whitemoves = Blackmoves = Winitmoves = Binitmoves = 1;
		question += 4;
	    }
	    else
	    {
		wprintf("Is this a Progressive chess game [%s]? ",
			yorn(!Whitemoves));
		progress = enterdyn(!Whitemoves);
	    }
	    break;
	case 18:
	    wprintf("How many moves on White's first turn [%d]? ",Winitmoves);
	    Winitmoves = readdint(HI_WIMOVES,Winitmoves);
	    wputchar('\n');
	    if (progress)
	    {
		Binitmoves = Whitemoves = Blackmoves = MO_PROGRESS;
		question += 3;
	    }
	    break;
	case 19:
	    wprintf("How many moves on White's later turns [%d]? ",
		Whitemoves);
	    Whitemoves = readdint(HI_WMOVES,Whitemoves);
	    wputchar('\n');
	    break;
	case 20:
	    wprintf("How many moves on Black's first turn [%d]? ",
		Binitmoves);
	    Binitmoves = readdint(HI_BIMOVES,Binitmoves);
	    wputchar('\n');
	    break;
	case 21:
	    wprintf("How many moves on Black's later turns [%d]? ",
		Blackmoves);
	    Blackmoves = readdint(HI_BMOVES,Blackmoves);
	    wputchar('\n');
	    break;
	case 22:
	    if (Winitmoves > 1 || Binitmoves > 1)
	    {
		wprintf("Must players stay on their own sides on the first turns [%s]? ",yorn(Tabiyat));
		Tabiyat = enterdyn(Tabiyat);
	    }
	    else
		Tabiyat = FALSE;
	    break;
	case 23:
	    if ((Winitmoves > 1 || Binitmoves > 1 ||
		 Whitemoves > 1 || Blackmoves > 1 ||
		 Whitemoves == MO_PROGRESS) &&
		(Whiteking != SQ || Blackking != SQ))
	    {
		wprintf("May ");
		pkings(wprintf);
		wprintf(" move through check [%s]? ",
		    yorn(Thrucheck));
		Thrucheck = enterdyn(Thrucheck);
	    }
	    break;

	case 24:	/* Enter results */
	   initmore();
	   mprint("What is the effect of being stalemated");
	   Staleresult = enterone(resltname,HI_STALE,Staleresult);
	   break;
	case 25:
	   initmore();
	   mprint("What is the effect of losing all forces");
	   if (Blackking != SQ || Whiteking != SQ)
	       mprint(" except your mateable piece");
	   Stripresult = enterone(resltname,HI_STRIP,Stripresult);
	   break;

	case 26:	/* Must take? */
	    if (Capture != CA_NONE || Kcapture != CA_NONE)
	    {
		wprintf("Must pieces be captured whenever possible [%s]? ",
			yorn(Musttake));
		Musttake = enterdyn(Musttake);
	    }
	    else
		Musttake = FALSE;
	    break;

	case 27:	/* Privacy */
	    if (Kriegspiel)
		wprint("To prevent peeking, Kriegspiel games should be private:\n");

	    wprintf("Would you like the game to be private [%s]? ",
		yorn(Kriegspiel));
	    Private = enterdyn(Kriegspiel);
	    break;

	case 28:	/* Computer Kibitzing */
	    if (!Musttake && !Kriegspiel &&
		Capture == CA_NORMAL && Kcapture == CA_NORMAL)
	    {
		wprintf("Would you like the computer to kibitz [Yes]? ");
		Help_me = enterdyn(TRUE);
	    }
	    else
		Help_me = FALSE;
	    break;

	case 29:	/* Give him a chance to make another pass */

	    /* Figure out if anything really got changed */
	    for (i=4;i<OPTIONS;i++)
		if (i != OP_NAMES && i != OP_BOARD &&
		    option[i] != defopt[Game_type][i])
		{
		    Game_type = TY_MIXED;
		    break;
		}

	    /* Print out the options */
	    initmore();
	    mprint("Options selected:\n");
	    printopts(mprintf);

	    mprint("Are these correct? ");
	    if (enteryn())
		question = -100;	/* Exit loop */
	    else
		question = -1;		/* Restart loop */
	    break;

	default:
	    wprint("Lost in customization\n");
	    question = -100;
	    break;
	}
    }
#ifndef LSIGNAL
    susp1_flg = FALSE;
#endif LSIGNAL
}

int enterone(name,hi,def)
int hi;
char *name[];
int def;
{
register int i;
register char ch;
	mprintf(" [%s]:\n",name[def]);
	for (i = 0; i <= hi; i++)
		mprintf("   (%c) %s\n",i+'A',name[i]);
	mprintf("enter (A-%c)? ",hi+'A');
	for (;;)
	{
		if ((ch = getchar()) == '\n' || ch == '\r')
			i = def;
		else
			i = (ch <= 'Z') ? ch - 'A' : ch - 'a';

		if (i > hi || i < 0)
			bell();
		else
			break;
	}

	mprintf("%c - %s\n",i+'A',name[i]);
	return(i);
}

/* PKINGS()
 *
 *   Print names of mateable pieces.  Don't call this if there are none.
 *   prtf is the function to print with.  mprintf or wprintf or printf.
 */

pkings(prtf)
int (*prtf)();
{
    if (Whiteking != SQ)
    {
	(*prtf)("%ss",pman(Whiteking));
	if (Whiteking != Blackking && Blackking != SQ)
	    (*prtf)(" and %ss",pcolman(-Blackking));
    }
    else
	(*prtf)("%ss", pcolman(-Blackking));
}

/*  ACCEPT()
 *
 *    Accept Challange mode.  Print options.  Accept, Reject or
 *    Counter-challenge.  Write appropriate selection in game file.
 *    Not in visual mode.
 */

doaccept()
{
boolean first = TRUE;
boolean washidden;

    /* Some initialization stuff */
    washidden = hidden;
    hidden = FALSE;
#ifndef LSIGNAL
    susp1_flg = TRUE;
    setjmp(susp_env);
#endif LSIGNAL
    scrolled = TRUE;

    for (;;)
    {
	if (scrolled)
	{
	    disp(b,kibitz?WHITE:mycolor);
	    wputchar('\n');
	    msgarea = (cy >= LINES) ? LINES - 1 : cy;
	}

	if (first)
	{
	    initmore();
	    if (kibitz)
	    {
		if (moveok)
		    mprintf("%s has been challenged by %s",myid,hisid);
		else
		    mprintf("%s has been challenged by %s",hisid,myid);
	    }
	    else
	    {
		if (moveok)
		    mprintf("You have been challenged by %s",hisid);
		else 
		    mprintf("You have challenged %s",hisid);
	    }

	    mprint(" to a game of correspondence chess\nwith the following options:\n\n");
	    printopts(mprintf);
	    if (!moveok)
	    {
#ifndef LSIGNAL
		susp1_flg = FALSE;
#endif LSIGNAL
		hidden = washidden;
		return;
	    }
	    mprint("Help, ");
	    first = FALSE;
	}

	mprint("Accept, Reject or Counter-Challenge? ");
	switch (xenter("LACRVOH?EQ\014"))
	{
	case 'H': /* Offer help */
	case '?':
		wprint("Help\n");
		initmore();
		mprint(" A - Accept this cchess challenge\n");
		mprint(" R - Reject this cchess challenge\n");
		mprint(" C - Counter-challenge with different options\n");
		mprint(" O - Print the options again\n");
		mprint(" L - Print date of challenge\n");
		mprint("^L - Redraw display\n");
		mprint(" Q - Quit the program without doing anything\n");
		break;

	case '\014':
		wprint("Redraw\n");
		scrolled = TRUE;
		break;
	case 'L':
		wprintf("Last challenge made on %s\n",cday(lastday));
		break;

	case 'O':	/* Redisplay the options */
		wprint("Options\n");
		initmore();
		printopts(mprintf);
		break;

	case 'Q':	/* Quit */
		wprint("Quit\n");
		return;
	case 'E':	/* Exit */
		wprint("Exit\n");
		return;

	case 'A':	/* challenge accepted */
		wprint("Accept\n");
#ifndef LSIGNAL
		susp1_flg = FALSE;
#endif LSIGNAL
		status = 3;
		fprintf(wfp,"%5ld:A      \n",day());
		/* mail message */
		sprintf(cbuffer,
		    "Your challenge has been accepted.  Run \042%s %s\042.\n",
		    RUN_CMD,myid);
		mesg("Cchess Challenge Accepted",cbuffer);
		hidden = washidden;
		return;

	case 'R': /* challenge rejected */
		wprint("Reject\n");
#ifndef LSIGNAL
		susp1_flg = FALSE;
#endif LSIGNAL
		unlink(fname);
		mesg("Cchess Challenge Rejected",
		    "Your challenge has been rejected.\n");
		return;

	case 'C': /* counter challenge */
		wprint("Challenge\n");
#ifndef LSIGNAL
		susp1_flg = FALSE;
#endif LSIGNAL
		clr();
		dochallenge(TRUE);
		return;

	case 'V': /* version command */
		versprint();
		break;
	}
    }
}


/* EDITBD()
 *
 * Edit a board set up.  Board ob is passed in with the original arrangment.
 * Board nb is the current set up.  Upon return, it contains the edited set up.
 * The global board, bc should be a copy of nb.  This reads just one command.
 * It returns FALSE if the last command was a quit.
 */

boolean editbd(nb,ob)
schar nb[R_SIZE][C_SIZE];
schar ob[R_SIZE][C_SIZE];
{
short ox, oy;
int row,col,i;
char buf[40],*name;
char ch,cmd;
schar piece;
char *tp;

    /* Prompt for a command */

    wprint("Place, Delete or Quit? ");
    cmd = xenter("PDUEQVH?\014");

    switch (cmd)
    {
    case 'H':
    case '?':
	wprint("Help\n");

	wprint("Would you like a list of commands? ");
	if (enteryn())
	{
	    initmore();
	    mprint("Place -    Put a piece on a square\n");
	    mprint("Delete -   Remove a piece from board\n");
	    mprint("Undo -     Undo all changes to board\n");
	    mprint("Quit -     Exit board edit mode\n");
	    mprint("^L -       Redraw the screen\n");
	}

	wprint("Would you like a list of pieces? ");
	if (enteryn())
	{
	    initmore();
	    for (i=1;i<PIECES;i+=2)
		mprintf(" %c = %-9.9s  %c = %-9.9s\n",
		    pc[PIECES-i],piecename[i],
		    pc[PIECES-i-1],piecename[i+1]);
#if (PIECES % 2) == 1
	    mprintf(" %c = %-9.9s\n",
		pc[0],piecename[PIECES]);
#endif
	}
	break;

    case 'P':
	wprint("Place\n");

	/* Get the piece */
	wprint("What Type of Piece (upper case for black)? ");
	for (;;)
	{
	    ch = getchar();
	    if (ch == '\n' || ch == '\r') break;
	    if (ch == 'p') ch = 'i';
	    else if (ch == 'P') ch = 'I';
	    if ((tp = index(pc,ch)) != 0) break;
	    bell();
	}
	if (ch == '\n' || ch == '\r')
	{
	    wputchar('\n');
	    break;
	}
	piece = (tp-pc)-PIECES;
	wprint(name = pcolman(piece));

	/* Get the position */
	wprintf("\nWhere should the %s be placed? ",name);
    
    case 'D':
	if (cmd == 'D')
	{
	    piece = SQ;
	    wprint("Delete\nFrom what position? ");
	}
	if (!pread(buf)) break;
	col = buf[0] - 'A';
	row = buf[1] - '1';
	wputchar('\n');

	if (cmd == 'D' && nb[row][col] == SQ)
	{
	    wprintf("No piece at %2.2s\n",buf);
	    break;
	}

	/* Make the change to the board copy */
	bc[row][col] = piece;

	/* Display the new position */
#ifndef NOTERMCAP
	if (!scrolled && issmart)
	{
	    ox = cx; oy = cy;
	    update(nb,bc);
	    cursor(ox,oy);
	}
	else
	{
#endif NOTERMCAP
	    disp(bc, kibitz ? WHITE : mycolor);
	    wputchar('\n');
#ifndef NOTERMCAP
	}
#endif NOTERMCAP
	/* Make the change to the real board */
	nb[row][col] = piece;
	break;

    case 'U':
	wprint("Undo\n");
	if (compare(nb,ob))
	{
	    wprint("No changes have been made\n");
	    break;
	}
	wprint("Do you want to undo all changes? ");
	if (!enteryn()) break;
#ifndef NOTERMCAP
	if (!scrolled && issmart)
	{
	    ox = cx; oy = cy;
	    update(nb,ob);
	    cursor(ox,oy);
	}
	else
#endif NOTERMCAP
	    scrolled = TRUE;

	copy(ob,nb);
	copy(ob,bc);
	break;

    case 'Q': /* Quit */
	wprint("Quit\n");
    case 'E': /* Exit */
	if (cmd == 'E') wprint("Exit\n");
#ifndef NOTERMCAP
	if (!DL && cy == LINES) wputchar('\n');
#endif NOTERMCAP
	/* Make sure we got a sane board */
	if (!(checkbd(nb,WHITE) && checkbd(nb,BLACK))) break;

	/* Confirm that he is really done */
	wprint("Are you sure you're done editing? ");
	if (!enteryn()) break;
	return(FALSE);

    case '\014': /* Control-L redraws the screen */
	wprint("Redraw\n");
	scrolled = TRUE;
	break;

    case 'V':  /* Version */
	versprint();
	break;
    }
    return(TRUE);
}


/* CHECKBD()
 *
 * Check if an edited board is a reasonable one.  This is currently
 * a bit too strict.  It should really only check if the second player
 * is in check, or the first player is stalemated.
 */

boolean checkbd(nb,color)
schar nb[R_SIZE][C_SIZE];
schar color;
{
int row,col;
register int r,c;
schar myking = Kingpiece(color);

    if (myking != SQ)
    {
	/* Find a King */
	switch (piececount(nb,myking,&row,&col))
	{
	case 0:
	    wprintf("No %s on board\n",pcolman(myking));
	    return(FALSE);
	case 2:
	    wprintf("Too many %ss on the board\n",pcolman(myking));
	    return(FALSE);
	}

	if (check(nb,-color,row,col))
	{
	    wprintf("%s is in check\n",pcolman(myking));
	    return(FALSE);
	}
    }
    else
    {
	/* Make sure you have at least some sort of piece */
	for (r=0;r<=Rows;r++)
	    for (c=0;c<=Cols;c++)
		if (nb[r][c]*color > 0)
		    goto ok;
	wprintf("No %s pieces on board\n",pcol(color));
	return(FALSE);
    }

ok: if(!canmove(nb,color,FALSE))
    {
	wprintf("%s cannot move\n",pcol(color));
	return(FALSE);
    }

    return(TRUE);
}

/* PIECECOUNT
 *
 *   Return 0 if there are no pieces of the type, 1 if there is exactly one,
 *   or 2 if there are more than one.  The location of the first one found
 *	is returned in the last two.
 */

int piececount(nb,piece,row,col)
schar nb[R_SIZE][C_SIZE];
schar piece;
int *row,*col;
{
register int r,c,tcol;

    /* Find one Piece */
    find(nb,piece,row,col);
    if (*row == -1)
	return(0);

    /* Any more of them? */
    tcol = *col;
    for (r = *row;r <= Rows;r++)
    {
	for (c=tcol+1; c<=Cols; c++)
	    if (nb[r][c] == piece)
		    return(2);
	tcol = -1;
    }
    return(1);
}

/* CANCASTLE
 *
 *   If there is a sensible way to castle on the current board?
 */

cancastle(nb,color)
schar nb[R_SIZE][C_SIZE];
schar color;
{
int row,col;

    /* There is exactly one king of this color */
    if (piececount(nb,color*WK,&row,&col) != 1)
	return(FALSE);

    /* There is a rook of the same color at one of the margins */
    return (nb[row][0] == color*WR || nb[row][Cols] == color*WR);
}

versprint()
{
	wprintf("Version %s %s\n",version,copyright);
}