/* a 3D chess set

   Andrew.Tridgell@anu.edu.au January 1997 */

#include "includes.h"
#include "trackball.h"
#include "knightcap.h"

static int window_size = 500;

#define SLEEP_TIME 100000 /* microseconds */
#define REFRESH_TIME 20 /* in seconds */
#define SEEK_WAIT_TIME 120 /* in seconds */
#ifndef MULL_WAIT_TIME
#define MULL_WAIT_TIME 0
#endif

struct state *state;

int seeking=0;
int seek_answering=0;
int demo_mode = 0;

static int opponent;
static int always_think;
static int no_display;
static int ascii_display;
static int use_mulling = USE_PBRAIN;
static int display_position=0;
static int brain_inserting=0;
static int ics_mode;
static int move_pid;
int display_pid;
static int match_remaining;
static int match_total;
static int def_hash_table_size = DEFAULT_HASH_TABLE_SIZE;
static float match_points;
int color_display=1;
int auto_exit=0;

int bad_eval_fd;
char noplay_list[5000];
char opponents_list[5000];

extern int need_redraw;

#if LEARN_EVAL
int learning=1;
#else
int learning=0;
#endif

static float default_move_time = DEFAULT_MOVE_TIME;

char *ics_name = "KnightCap";
char *ics_master = NULL;
char *coeffs_file = NULL;
char *bad_eval_file = "bad_eval.dat";
char *tb_path = "../EGTB";

char play_target[100];

#ifndef SHM_R
#define SHM_R 0400
#endif

#ifndef SHM_W
#define SHM_W 0200
#endif

void sig_wake_up(int dum)
{
	signal(SIGUSR1, sig_wake_up);
}

void wake_up(void)
{
	kill(display_pid, SIGUSR1);
}

/* setup a standard chess starting position */
void reset_board(void)
{
	setup_board(&state->position);
	state->computer = 0;
	state->moved = 0;
	state->always_think = always_think;
	state->use_mulling = use_mulling;
	state->need_reset = 1;
	state->moves_mulled = 0;
	if (state->always_think)
		lprintf(0,"Thinking on opponents time\n");
	timer_reset();
	state->analysed = 0;
	state->first_book_move = 1;
	estimate_game_stage(&state->position, 1);
#if LEARN_EVAL
	learning=1;
	state->won = UNKNOWN;
#endif
#if STORE_LEAF_POS
	state->stored_move_num = 0;
	memset(state->predicted_move, 0, MAX_GAME_MOVES*sizeof(state->predicted_move[0]));
#endif
}

static void display_move(Move *move)
{
	print_move(&state->position, move);
	do_move(&state->position, &state->position, move);
	redraw();
}

int player_moved(Square from, Square to)
{
	Move move;

	move.from = from;
	move.to = to;
	move.v = INFINITY;

	if (!legal_move(&state->position, &move)) {
		lprintf(0, "Illegal move %s\n",
			short_movestr(&state->position, &move));
		return 0;
	}

	state->game_record[state->position.move_num] = move;
	if (state->display_position)
		dump_ppn(&state->position);
	display_move(&move);

	return 1;
}


static void about(void)
{
	lprintf(0,"\nThe author of KnightCap is Andrew Tridgell. He can be contacted\n" \
"via email Andrew.Tridgell@anu.edu.au.\n" \
"\n" \
"The ftp site for KnightCap is ftp://samba.anu.edu.au/pub/KnightCap/\n" \
"\n" \
"KnightCap is free software distributed under the GNU Public License\n" \
"\n" \
);
}

static void help(void)
{
	lprintf(0,"\n" \
"go                              start searching\n" \
"black                           computer plays black\n" \
"white                           computer plays white\n" \
"new                             reset the board\n" \
"time <hsecs>                    update computers time in hundredths of a second\n" \
"otim <hsecs>                    update oppenents time in hundredths of a second\n" \
"mtim <mins> <increment>         update computers time in minutes\n" \
"level x <mins> <inc>            xboard compat command\n" \
"load <file>                     load a saved game\n" \
"save <file>                     save a game\n" \
"quit                            quit!\n" \
"demo <1|0>                      enable/disable demo mode\n" \
"seek <1|0>                      enable/disable seeks (ics)\n" \
"answer <1|0>                    enable/disable seek answering (ics)\n" \
"ponder <1|0>                    enable/disable thinking on oppenents time\n" \
"robot <1|0>                     enable/disable ICS robot\n" \
"autoplay <1|0>                  enable/disable ICS autoplay\n" \
"mtime <move time>               set time per move in seconds\n" \
"undo <ply>                      take back <ply> half moves\n" \
"redo <ply>                      replay <ply> half moves\n" \
"eval                            static evaluation debug\n" \
"ppn                             display the ppn of the current position\n" \
"ppnset                          set the current position to a ppn\n" \
"espeed  <loops>                 measure eval fn speed\n" \
"testfin <file>                  load a .fin test file and test each position\n" \
"print                           print the current board\n" \
"about                           show some info on KnightCap\n" \
"target <opponent>               try challenging <opponent> when bored\n" \
"notarget                        undo the target command\n" \
"mm  <n>                         play n games against another computer\n" \
"color <1|0>                     enable/disable color ascii board display\n" \
"bclean                          clean the brain\n" \
"");

}


int parse_stdin(char *line)
{
	char *p;
	Move move;
	char tok[1000];
	int hsecs, level, mins;
	static int increment;
	char load_file[100];
	int on, i;
	int done = 0;

	p = line;

	while (next_token(&p, tok, "\n\r")) {
		/* is it a move? */
		if (parse_move(tok, &state->position, &move)) {
			if (player_moved(move.from, move.to))
				done = 1;
		}

		if (strcmp(tok,"go") == 0) {
			state->computer = next_to_play(&state->position);
			done = 1;
		}

		if (strcmp(tok,"black") == 0) {
			state->computer = -1;
			state->colour = -1;
			done = 1;
		}

		if (strcmp(tok,"white") == 0) {
			state->computer = 1;
			state->colour = 1;
			done = 1;
		}

		if (strcmp(tok,"new") == 0) {
			reset_board();
			redraw();
			done = 1;
		}

		if (sscanf(tok, "time %d", &hsecs) == 1) {
			timer_estimate(hsecs/100, hsecs/100, increment);
			done = 1;
		}

		if (sscanf(tok, "mtim %d %d", &hsecs, &increment) == 2) {
			timer_estimate((60*hsecs), (60*hsecs), increment);
			done = 1;
		}


		if (sscanf(tok, "otim %d", &hsecs) == 1) {
			if (hsecs <= 0)
				lprintf(0, "win on time!\n");
			done = 1;
		}

		if (sscanf(tok, "level %d %d %d", &level, &mins, &increment) == 3) {
			lprintf(0,"setting increment to %d\n", increment);
			if (opponent)
				prog_printf("level %d %d %d\n", 
					    level, mins, increment);
			done = 1;
		}

		if (sscanf(tok, "testfin %s", load_file) == 1) {
			test_fin(load_file);
			done = 1;
		}

		if (sscanf(tok, "load %s", load_file) == 1) {
			restore_game(load_file);
			done = 1;
		}

		if (sscanf(tok, "save %s", load_file) == 1) {
			save_game(load_file);
			done = 1;
		}

		if (sscanf(tok, "target %s", play_target) == 1) {
			done = 1;
		}

		if (strcmp(tok, "notarget") == 0) {
			play_target[0] = 0;
			done = 1;
		}

		if (strcmp(tok, "quit") == 0) {
			if (!state->auto_exit) {
				state->quit = 1;
				state->stop_search = 2;
				prog_printf("quit\n");
				prog_exit();
				exit(0);		
			} else {
				/* xboard doesn't tell us the outcome, so we do
				   it manually */
				state->won = STALEMATE;
				state->stop_search = 2;
				state->computer = 0;
			} 
			done = 1;
		}

		if (strcmp(tok, "print") == 0) {
			print_board(state->position.board);
			done = 1;
		}

		if (sscanf(tok,"demo %d", &on) == 1) {
			demo_mode = on;
			done = 1;
		}

		if (sscanf(tok,"seek %d", &on) == 1) {
			seeking = on;
			done = 1;
		}

		if (sscanf(tok,"answer %d", &on) == 1) {
			seek_answering = on;
			done = 1;
		}

		if (sscanf(tok,"color %d", &on) == 1) {
			color_display = on;
			done = 1;
		}

		if (sscanf(tok,"mm %d", &match_remaining) == 1) {
			match_points = 0;
			match_total = 0;
			done = 1;
		}

		if (sscanf(tok,"robot %d", &on) == 1) {
			state->ics_robot = on;
			done = 1;
		}

		if (sscanf(tok,"autoplay %d", &on) == 1) {
			state->autoplay = on;
			done = 1;
		}

		if (sscanf(tok,"display %d", &on) == 1) {
			no_display = !on;
			done = 1;
		}

		if (sscanf(tok,"mull %d", &on) == 1) {
			state->use_mulling = on;
			if (opponent == KNIGHTCAP)
				prog_printf("mull %d\n", on);
			done = 1;
		}

		if (sscanf(tok,"pbrain %d", &on) == 1) {
			state->use_pbrain = on;
			done = 1;
		}

		if (sscanf(tok,"ponder %d", &on) == 1) {
			always_think = state->always_think = on;
			if (opponent == CRAFTY)
				if (on == 1) {
					prog_printf("ponder on\n");
				} else if (on == 0) {
					prog_printf("ponder off\n");
				}
			else if (opponent == KNIGHTCAP)
				prog_printf("ponder %d\n", on);
			done = 1;
		}

		if (sscanf(tok,"mtime %d", &i) == 1) {
			state->move_time = i;
			if (opponent == CRAFTY)
				prog_printf("st %d\n", i);
			else if (opponent == KNIGHTCAP)
				prog_printf("mtime %d\n", i);
			done = 1;
		}

		if (sscanf(tok,"undo %d", &i) == 1) {
			undo_menu(i);
			done = 1;
		}

		if (sscanf(tok,"redo %d", &i) == 1) {
			undo_menu(-i);
			done = 1;
		}

		if (strcmp(tok, "eval") == 0) {
			eval_debug(&state->position);
			done = 1;
		}

		if (strcmp(tok,"grad") == 0) {
#if LEARN_EVAL
			float grad[__TOTAL_COEFFS__];

			state->stored_move_num = 0;
			td_store_pos(&state->position);
			state->td_comp = next_to_play(&state->position);
			td_gradient(grad);
#endif
			done = 1;
		}

		if (strcmp(tok, "ppn") == 0) {
			lprintf(0,"%s\n", position_to_ppn(&state->position));
			done = 1;
		}

		if (strncmp(tok, "ppnset", 6) == 0) {
			char *p2 = strchr(tok,' ');
			if (p2) {
				while ((*p2) == ' ') p2++;
				ppn_to_position(p2, &state->position);
			}
			done = 1;
		}

		if (sscanf(tok,"espeed %d", &i) == 1) {
			eval_speed(&state->position, i);
			done = 1;
		}

		if (strcmp(tok, "help") == 0) {
			help();
			done = 1;
		}

		if (strcmp(tok, "about") == 0) {
			about();
			done = 1;
		}

		if (strcmp(tok, "bclean") == 0) {
			brain_clean();
			done = 1;
		}
	}

	return done;
}


/* users can send us moves and commands on stdin */
static void check_stdin(void)
{
	char line[200];
	int n;
	fd_set set;
	struct timeval tval;
	static int nostdin;

	if (nostdin)
		return;

	FD_ZERO(&set);
	FD_SET(0, &set);

	tval.tv_sec = 0;
	tval.tv_usec = 0;

	if (select(1, &set, NULL, NULL, &tval) != 1)
		return;

	n = read(0, line, sizeof(line)-1);

	if (n <= 0) {
		lprintf(0,"disabling stdin\n");
		nostdin = 1;
		if (state->auto_exit) {
			/* xboard often doesn't tell us the outcome, so we 
			   set state->won to STALEMATE and then work it out manually */
			state->won = STALEMATE;
			state->stop_search = 2;
			state->computer = 0;
		}
		close(0);
		return;
	}

	line[n] = 0;

	if (!parse_stdin(line)) {
		if (prog_running()) {
			prog_printf("%s", line);
		}
	}
}


void update_display(void)
{
	if (!no_display) {
		if (ascii_display)
			print_board(state->position.board);
		else
			draw_all();
	}
}


void match_hook(void)
{
	static int player = 1;

	if (match_remaining <= 0) return;

	/* perhaps we are already playing */
	if (state->computer && !state->position.winner) return;

	if (state->position.winner) {
		if (state->position.winner == STALEMATE) {
			state->won = STALEMATE;
			match_points += 0.5;
		} else if (state->position.winner == player) {
			match_points += 1;
			state->won = 1;
		} else 
			state->won = 0;
		
		state->position.winner = 0;

		match_total++;
		match_remaining--;

		lprintf(0,"match %1.1f points out of %d games\n", 
			match_points, match_total);

		player = -player;

	}


	if (match_remaining <= 0) return;
	
	state->computer = 0;

	/* Give time to analyse last game */
	if (state->use_mulling) {
		sleep(30);
	} else {
#if LEARN_EVAL
		td_update();
		td_dump("coeffs.dat");
#endif
	}
	reset_board();
	prog_printf("new\n");
	if (player == 1) {
		if (opponent == CRAFTY) 
			prog_printf("white\n");
		else if (opponent == KNIGHTCAP)
			prog_printf("black\n");
		state->computer = 1;
	} else {
		if (opponent == CRAFTY) {
			prog_printf("white\n");
			prog_printf("go\n");
		} else if (opponent == KNIGHTCAP)
			prog_printf("white\n");
		state->computer = -1;
	}
}

void idle_func(void)
{
	int i;
	Move m1;
	static uint32 hash;
	static int loops;
	static int seek_loops;
	static int try_target=1;
	static int computer;

	check_stdin();

	if (prog_check_move(&m1, next_to_play(&state->position))) {
		player_moved(m1.from, m1.to);
	}

	if (state->computer != 0) {
		computer = state->computer;
		state->colour = state->computer;
	}


	if (state->moved) {
		if (next_to_play(&state->position) == state->computer) {
			m1 = state->game_record[state->position.move_num];
			if (legal_move(&state->position, &m1)) {
				prog_tell_move(&state->position, &m1);
				if (state->display_position)
					dump_ppn(&state->position);
				display_move(&m1);
				if (!state->ics_robot &&
				    (state->position.flags & FLAG_ACCEPT_DRAW))
					prog_printf("draw\n");
				if (state->position.winner) {
					state->computer = 0;
					if (state->position.winner == STALEMATE)
						prog_printf("draw\n");
					if (state->ics_robot) {
						/* make sure we are right! */
						prog_printf("refresh\n");
					}
				}
				if (!state->ics_robot && !state->demo_mode)
					save_game("current.save");
			}
			state->stop_search = 0;
		}
		state->moved = 0;
	}

	if (state->auto_exit && (state->position.winner || state->won == STALEMATE) && 
	    !state->analysed && !state->use_mulling) {
		FILE *f = fopen("results","a");
		float res;

		/* work out who won (or was winning when it ended) */
		if (!state->position.winner) {
			for (i=state->position.move_num-1;i>=0;i--) {
				if (state->game_record[i].v != INFINITY) {
					if (state->game_record[i].v > 2*PAWN_VALUE) {
						state->position.winner = 1;
					} else if (state->game_record[i].v < -2*PAWN_VALUE) {
						state->position.winner = -1;
					} else {
						state->position.winner = STALEMATE;
					}
					break;
				}
			}
		}


		if (computer == state->position.winner) {
			res = 1;
			state->won = 1;
		} else if (computer == -state->position.winner) {
			res = 0;
			state->won = 0;
		} else if (state->position.winner == STALEMATE) {
			res = 0.5;
			state->won = STALEMATE;
		} else {
			res = 0;
		}
		if (f) {
			fprintf(f,"%g\n", res);
			fclose(f);
		}

#if LEARN_EVAL
		if (!state->analysed) {
			if (!state->use_pbrain) {
				td_update();
				td_dump("coeffs.dat");
			} else {
				state->moves_mulled = 0;
				state->use_mulling = 1;
			}
		}

#endif

	}

	if (state->auto_exit && state->moves_mulled >= MAX_MOVES_MULLED && state->open) {
		lprintf(0,"***%d\n", state->moves_mulled);
		state->use_mulling=0;
		state->stop_search=1;
		sleep(5);
		system("killall sleep");
		sleep(5);
		system("killall sleep");
		exit(0);
	}

	if (need_redraw || hash != state->position.hash1) {
		need_redraw = 0;
		hash = state->position.hash1;
		update_display();
		loops=0;
	}

	if (state->demo_mode && !state->position.winner &&
	    next_to_play(&state->position) != state->computer) {
		state->stop_search = 1;
		state->computer = next_to_play(&state->position);
	}

	if (!process_exists(move_pid) ||
	    (state->ics_robot && !prog_running())) {
			state->quit = 1;
			state->stop_search = 2;
			prog_printf("quit\n");
			prog_exit();
			exit(0);					
	}

	if (state->computer)
		try_target = 1;

	if (state->ics_robot &&
	    state->computer == 0 && *play_target && 
	    try_target && state->open && state->analysed) {
		try_target = 0;
		prog_printf("match %s\n", play_target);
	}

	if (state->computer != 0)
		seek_loops = 0;

	if (++seek_loops > SEEK_WAIT_TIME*(1000*1000/SLEEP_TIME)) {
		if (state->open && state->ics_robot && 
		    state->computer == 0 && seeking && state->autoplay) {
			prog_printf("seeks\n");
			seek_loops = 0;
		}
	}

#if 1
	if (++loops > REFRESH_TIME*(1000*1000/SLEEP_TIME)) {
		if (state->ics_robot && 
		    state->computer &&
		    state->computer != next_to_play(&state->position))
			prog_printf("refresh\n");
		loops=0;
		if (state->ics_robot &&
		    state->computer == 0 && *play_target && 
		    (random() % 1) == 0) {
			try_target = 1;
		}
	}
#endif
	match_hook();

	usleep(SLEEP_TIME);
}


void save_game(char *fname)
{
	int fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
	if (fd == -1) {
		perror(fname);
		return;
	}
	write(fd, state, sizeof(*state));
	close(fd);
}

void restore_game(char *fname)
{
	int fd = open(fname, O_RDONLY);
	if (fd == -1) {
		perror(fname);
		return;
	}
	read(fd, state, sizeof(*state));
	close(fd);
}


/* undo the last n ply of the game 
 Passing a negative number gives redo */
void undo_menu(int n)
{
	int i;

	state->computer = 0;
	state->stop_search = 1;
	state->demo_mode = 0;

	n = state->position.move_num - n;
	if (n < 0) n = 0;

	setup_board(&state->position);

	for (i=0;i<n;i++) {
		Move *move = &state->game_record[i];
		if (!legal_move(&state->position, move))
			break;
		do_move(&state->position, &state->position, move);
	}

	state->stop_search = 1;

	redraw();
}

static void move_thread(void)
{
	int pondered = 0;
	unsigned mull_counter=0;
	
#if USE_PBRAIN
	if (state->use_pbrain) 
		state->use_pbrain = brain_open(BRAIN_FILE);
	else 
		brain_open(BRAIN_FILE);
#endif

#if TPROF
	tprof_init();
#endif

#if 0
	chdir("prof");
#endif

#if APLINUX
	if (getcid() != 0) {
		move_slave();
		exit();
	}
#endif

	while (!state->quit) {
		Move move;
		
		if (!process_exists(display_pid)) {
#if USE_PBRAIN
			brain_close();
#endif

			exit(0);					
		}

		if (state->need_reset) {
			hash_reset();
			order_reset();
			state->need_reset = 0;
		}
		
#if LEARN_EVAL
		if (state->computer == 0 && !state->analysed && !state->ics_robot
		    && !state->demo_mode && !state->use_mulling && !state->auto_exit) {
			td_update();
			td_dump("coeffs.dat");
			state->analysed = 1;
			state->colour = 0;
		}
#endif			


		if (state->computer == 0 && !state->analysed) {
			/* if we get bored waiting then start to mull on
			   our brain */
			analyse_game();
		}
		if (state->computer == 0 && state->use_mulling) {
			if (mull_counter++ > 
			    MULL_WAIT_TIME*(1000*1000/SLEEP_TIME))
				brain_mull();
		} else {
			mull_counter = 0;
		}

		if (next_to_play(&state->position) != state->computer ||
		    state->moved || state->position.winner) {
			if (state->always_think && 
			    !state->position.winner &&
			    !pondered &&
			    state->computer == -next_to_play(&state->position)) {
				zero_move(&move);
				ponder_move(&state->position, &move);
				if (!is_zero_move(&move) &&
				    legal_move(&state->position, &move)) {
					state->game_record[state->position.move_num] = move;
					if (state->display_position)
						dump_ppn(&state->position);
					state->moved = 1;
					wake_up();
					pondered = 0;
				} else {
					pondered = 1;
				}
			}
			
			if (!pondered || !state->computer)
				usleep(SLEEP_TIME);
			continue;
		}

		if (!pondered) 
			usleep(SLEEP_TIME);

		pondered = 0;

		if (make_move(&state->position, &move)) {
			if (next_to_play(&state->position) == state->computer &&
			    legal_move(&state->position, &move)) {
				state->game_record[state->position.move_num] = move;
				state->moved = 1;
				wake_up();
			}
		} else {
			state->computer = 0;
		}
	}

#if USE_PBRAIN
	brain_close();
#endif

#if TPROF
	tprof_end();
#endif

	sleep(1);

	exit(0);
}


static void create_threads(void)
{
	int page_size;
	int len, shmid;
	int pid1, pid2;

	page_size = getpagesize();
	len = sizeof(*state);
	len = (len + page_size) & ~(page_size-1);

	shmid = shmget(IPC_PRIVATE, len, SHM_R | SHM_W);
	if (shmid == -1) {
		printf("can't get shared memory\n");
		exit(1);
	}
	state = (struct state *)shmat(shmid, 0, 0);
	if (!state || state == (struct state *)-1) {
		printf("can't attach to shared memory\n");
		exit(1);
	}
	shmctl(shmid, IPC_RMID, 0);
	memset(state, 0, len);
	state->move_time = default_move_time;
	state->use_mulling = USE_PBRAIN;
	state->use_pbrain = 1;
	state->hash_table_size = def_hash_table_size;

	reset_board();
	init_movements();

	signal(SIGCLD, SIG_IGN);

	pid1 = getpid();

#ifdef APLINUX
	move_pid = getpid();
	if (getcid() != 0 || fork() != 0) {
		log_close();
		move_thread();
		exit(0);
	}
#else
	if ((pid2=fork()) != 0) {
		if (getpid() == pid1) {
			display_pid = pid2;
		} else {
			display_pid = pid1;
		}
		move_thread();
		exit(0);
	}
#endif

	if (getpid() == pid1) {
		move_pid = pid2;
	} else {
		move_pid = pid1;
	}
}


static void usage(void)
{
	printf("\n" \
"-w <window size>\n" \
"-c <external chess program>\n" \
"-s <seed>\n" \
"-n                  no display\n" \
"-a                  ascii display\n" \
"-B                  b&w ascii display\n" \
"-e                  issue seeks in ICS mode\n" \
"-z                  answer computer seeks in ICS mode\n" \
"-d                  demo mode\n" \
"-m <n>              play n games against another computer\n"\
"-I <icsname>        ICS mode\n" \
"-M <icsmaster>      set ICS master\n" \
"-t <time>           default move time\n" \
"-X                  catch sigint for xboard\n" \
"-A                  always think\n" \
"-H <size>           set hash table size in MB\n" \
"-f <file>           get eval coefficients from this file\n" \
"-g <file>           EGTB directory\n" \
"-T <name>           target ICS opponent\n" \
"-G <file>           endgame tablebsae directory\n" \
"-y                  don't mull\n" \
"\n");
}


static void parse_options(int argc,char *argv[])
{
	FILE *f;
#ifdef SUNOS4
	extern char *optarg;
#endif
	char *opt = "c:s:w:nI:t:hXAD:l:aH:M:ezdm:f:g:ByEpT:";
	int c;
	int seed = getpid();

	while ((c = getopt(argc, argv, opt)) != EOF) {
		switch (c) {
		case 'D':
			{
				char disp[100];
				sprintf(disp,"DISPLAY=%s", optarg);
				putenv(disp);
				printf("display set to %s\n", getenv("DISPLAY"));
			}
			break;

		case 'w':
#if APLINUX
			if (getcid()) break;
#endif
			window_size = atoi(optarg);
			break;

		case 'c':
#if APLINUX
			if (getcid()) break;
#endif
			prog_start(optarg);
			if (strstr(optarg, "crafty")) {
				opponent = CRAFTY;
				lprintf(0, "Playing crafty\n");
			}
			if (strstr(optarg, "KnightCap")) {
				opponent = KNIGHTCAP;
				lprintf(0, "Playing KnightCap\n");
			}
			break;

		case 'H':
			def_hash_table_size = atoi(optarg);
			break;

		case 's':
			seed = atoi(optarg);
			break;

		case 'n':
			no_display = 1;
			break;

		case 'E':
			auto_exit = 1;
			break;

		case 'a':
			ascii_display = 1;
			break;

		case 'e':
			seeking = 1;
			break;

		case 'z':
			seek_answering = 1;
			f = (FILE *)fopen("opponents.dat", "r");
			if (f != NULL) {
				fscanf(f, "%s", opponents_list);
			}
			if (f != NULL)
				fclose(f);
			f = (FILE *)fopen("noplay.dat", "r");
			if (f != NULL) {
				fscanf(f,"%s", noplay_list);
			}	
			if (f != NULL)
				fclose(f);
			lprintf(0, "answering computer seeks %s %s\n",
				opponents_list, noplay_list);
			break;

		case 'd':
			demo_mode = 1;
			break;

		case 'y':
			use_mulling = 0;
			break;

		case 'm':
			match_remaining = atoi(optarg);
			lprintf(0,"%d game match\n", match_remaining);
			match_points = 0;
			match_total = 0;
			break;

		case 'B':
			color_display = 0;
			ascii_display = 1;
			break;
				
		case 'f':
			coeffs_file = optarg;
			break;

		case 'I':
			ics_mode = 1;
			ics_name = optarg;
			break;

		case 'M':
			ics_master = optarg;
			break;

		case 't':
			default_move_time = atoi(optarg);
			if (opponent == CRAFTY)
				prog_printf("st %d\n", (int)default_move_time);
			else if (opponent == KNIGHTCAP)
				prog_printf("mtime %d\n", (int)default_move_time);
			break;

		case 'h':
			usage();
			exit(0);
			break;

		case 'X':
			signal(SIGINT, SIG_IGN);
			break;

		case 'A':
			always_think = 1;
			break;
		case 'p':
			display_position = 1;
			break;     
	        case 'T':
			strcpy(play_target, optarg);
			break;
		case 'g':
			tb_path = optarg;
			break;
		}
	}

	srandom(seed); 
}


static void nodisp_loop(void)
{
	while (1) {
		idle_func();
		usleep(100000);
	}
}

int main(int argc,char *argv[])
{

#ifdef APLINUX
	ap_init();
#endif

	lprintf(0,"KnightCap starting\ntype \"help\" for commands or use the right button\n");

	parse_options(argc, argv);

	create_threads();

	state->ics_robot = ics_mode;
	state->autoplay = ics_mode;
	state->demo_mode = demo_mode;
	state->display_position = display_position; 
	state->auto_exit = auto_exit;
	state->use_mulling = use_mulling;
	state->brain_inserting = brain_inserting;
	state->open = 1;
	state->mulling = 0;
	state->notified = 0;
	reset_board();
	init_eval_tables();
	sig_wake_up(0);

#if RENDERED_DISPLAY
	if (!no_display && !ascii_display) {
		start_display(argc, argv);
		return 0;
	}
#endif

	nodisp_loop();

	return 0;
}
