Updated help commands to only display allowed subset in two player mode.
[sgk-go] / interface / play_twoplayer.c
CommitLineData
de03db18
AT
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * This is GNU Go, a Go program. Contact gnugo@gnu.org, or see *
3 * http://www.gnu.org/software/gnugo/ for more information. *
4 * *
5 * Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
6 * 2008 and 2009 by the Free Software Foundation. *
7 * *
8 * This program is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU General Public License as *
10 * published by the Free Software Foundation - version 3 or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License in file COPYING for more details. *
17 * *
18 * You should have received a copy of the GNU General Public *
19 * License along with this program; if not, write to the Free *
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
21 * Boston, MA 02111, USA. *
22\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
23
24#include "gnugo.h"
25
26#include <ctype.h>
b0d6e9e5 27#include <fcntl.h>
de03db18
AT
28#include <stdbool.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
b0d6e9e5
AT
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <unistd.h>
35
36#define _XOPEN_SOURCE 500
de03db18
AT
37
38#if READLINE
39#include <readline/history.h>
40#include <readline/readline.h>
41#endif
42
43#include "gg_utils.h"
44#include "interface.h"
45#include "liberty.h"
46#include "sgftree.h"
47
48#define DEBUG_COMMANDS "\
c541f89a 49No debug commands in two player mode\n\
de03db18
AT
50"
51
b0d6e9e5
AT
52#define MASTER_FIFO_NAME "/tmp/sgkgo-fifo-master"
53#define SLAVE_FIFO_NAME "/tmp/sgkgo-fifo-slave"
54
de03db18
AT
55/* ANSI color codes */
56#define RESETCOLOR "\x1B[0m"
57#define WHITECOLOR "\x1B[41m"
58#define BLACKCOLOR "\x1B[44m"
59#define TILE1COLOR "\x1B[47m"
60#define TILE2COLOR "\x1B[107m"
61#define TILE3COLOR "\x1B[43m"
62
63/* some options for the twoplayer interface */
64static int opt_showboard = 1;
65static int showdead = 0;
66static SGFTree sgftree;
67static int resignation_allowed;
68
69static int clock_on = 0;
70
71/* Unreasonable score used to detect missing information. */
72#define NO_SCORE 4711
73/* Keep track of the score estimated before the last computer move. */
74static int current_score_estimate = NO_SCORE;
75
6c3e8b62 76static void do_play_twoplayer(Gameinfo* gameinfo, int transmit_fifo_fd, int receive_fifo_fd);
de03db18
AT
77static int twoplayer_endgame(Gameinfo* gameinfo, int reason);
78static void twoplayer_count(Gameinfo* gameinfo);
6c3e8b62
AT
79//static void showcapture(char* line);
80//static void showdefense(char* line);
81//static void twoplayer_goto(Gameinfo* gameinfo, char* line);
82//static void twoplayer_free_handicap(Gameinfo* gameinfo, char* handicap_string);
de03db18
AT
83
84/* If sgf game info is written can't reset parameters like handicap, etc. */
85static int sgf_initialized;
86
87/*
88 * Create letterbar for the top and bottom of the ANSI board.
89 */
90
91static void
92make_letterbar(int boardsize, char* letterbar)
93{
94 int i, letteroffset;
95 char spaces[64];
96 char letter[64];
97
98 if (boardsize <= 25)
99 strcpy(spaces, " ");
100 strcpy(letterbar, " ");
101
102 for (i = 0; i < boardsize; i++) {
103 letteroffset = 'A';
104 if (i + letteroffset >= 'I')
105 letteroffset++;
106 strcat(letterbar, spaces);
107 sprintf(letter, "%c", i + letteroffset);
108 strcat(letterbar, letter);
109 }
110}
111
112/* This array contains +'s and -'s for the empty board positions.
113 * hspot_size contains the board size that the grid has been
114 * initialized to.
115 */
116
117static int hspot_size;
118static char hspots[MAX_BOARD][MAX_BOARD];
119
120/*
121 * Mark the handicap spots on the board.
122 */
123
124static void
125set_handicap_spots(int boardsize)
126{
127 if (hspot_size == boardsize)
128 return;
129
130 hspot_size = boardsize;
131
132 memset(hspots, '.', sizeof(hspots));
133
134 if (boardsize == 5) {
135 /* place the outer 4 */
136 hspots[1][1] = '+';
137 hspots[boardsize - 2][1] = '+';
138 hspots[1][boardsize - 2] = '+';
139 hspots[boardsize - 2][boardsize - 2] = '+';
140 /* and the middle one */
141 hspots[boardsize / 2][boardsize / 2] = '+';
142 return;
143 }
144
145 if (!(boardsize % 2)) {
146 /* If the board size is even, no center handicap spots. */
147 if (boardsize > 2 && boardsize < 12) {
148 /* Place the outer 4 only. */
149 hspots[2][2] = '+';
150 hspots[boardsize - 3][2] = '+';
151 hspots[2][boardsize - 3] = '+';
152 hspots[boardsize - 3][boardsize - 3] = '+';
153 } else {
154 /* Place the outer 4 only. */
155 hspots[3][3] = '+';
156 hspots[boardsize - 4][3] = '+';
157 hspots[3][boardsize - 4] = '+';
158 hspots[boardsize - 4][boardsize - 4] = '+';
159 }
160 } else {
161 /* Uneven board size */
162 if (boardsize > 2 && boardsize < 12) {
163 /* Place the outer 4... */
164 hspots[2][2] = '+';
165 hspots[boardsize - 3][2] = '+';
166 hspots[2][boardsize - 3] = '+';
167 hspots[boardsize - 3][boardsize - 3] = '+';
168
169 /* ...and the middle one. */
170 hspots[boardsize / 2][boardsize / 2] = '+';
171 } else if (boardsize > 12) {
172 /* Place the outer 4... */
173 hspots[3][3] = '+';
174 hspots[boardsize - 4][3] = '+';
175 hspots[3][boardsize - 4] = '+';
176 hspots[boardsize - 4][boardsize - 4] = '+';
177
178 /* ...and the inner 4... */
179 hspots[3][boardsize / 2] = '+';
180 hspots[boardsize / 2][3] = '+';
181 hspots[boardsize / 2][boardsize - 4] = '+';
182 hspots[boardsize - 4][boardsize / 2] = '+';
183
184 /* ...and the middle one. */
185 hspots[boardsize / 2][boardsize / 2] = '+';
186 }
187 }
188
189 return;
190}
191
192/*
193 * Display the board position when playing in ANSI.
194 */
195
196static void
197twoplayer_showboard(void)
198{
199 int i, j;
200 char letterbar[64];
201 int last_pos_was_move;
202 int pos_is_move;
203 int dead;
204 int last_move = get_last_move();
205
206 make_letterbar(board_size, letterbar);
207 set_handicap_spots(board_size);
208
209 printf("\n");
210 printf(" White (" WHITECOLOR " " RESETCOLOR ") has captured %d pieces\n", black_captured);
211 printf(" Black (" BLACKCOLOR " " RESETCOLOR ") has captured %d pieces\n", white_captured);
212 if (showscore) {
213 if (current_score_estimate == NO_SCORE)
214 printf(" No score estimate is available yet.\n");
215 else if (current_score_estimate < 0)
216 printf(" Estimated score: Black is ahead by %d\n",
217 -current_score_estimate);
218 else if (current_score_estimate > 0)
219 printf(" Estimated score: White is ahead by %d\n",
220 current_score_estimate);
221 else
222 printf(" Estimated score: Even!\n");
223 }
224
225 printf("\n");
226
227 fflush(stdout);
228 printf("%s", letterbar);
229
230 if (get_last_player() != EMPTY) {
231 gfprintf(stdout, " Last move: %s %1m",
232 get_last_player() == WHITE ? "White" : "Black",
233 last_move);
234 }
235
236 printf("\n");
237 fflush(stdout);
238
239 for (i = 0; i < board_size; i++) {
240 printf(" %2d", board_size - i);
241 last_pos_was_move = 0;
242 for (j = 0; j < board_size; j++) {
243 if (POS(i, j) == last_move)
244 pos_is_move = 128;
245 else
246 pos_is_move = 0;
247 dead = (dragon_status(POS(i, j)) == DEAD) && showdead;
248 switch (BOARD(i, j) + pos_is_move + last_pos_was_move) {
249 case BLACK:
250 case BLACK + 256:
251 printf(BLACKCOLOR " " RESETCOLOR);
252 last_pos_was_move = 0;
253 break;
254 case WHITE:
255 case WHITE + 256:
256 printf(WHITECOLOR " " RESETCOLOR);
257 last_pos_was_move = 0;
258 break;
259 case BLACK + 128:
260 printf(BLACKCOLOR "()" RESETCOLOR);
261 last_pos_was_move = 0;
262 break;
263 case WHITE + 128:
264 printf(WHITECOLOR "()" RESETCOLOR);
265 last_pos_was_move = 0;
266 break;
267 case EMPTY:
268 case EMPTY + 128:
269 case EMPTY + 256:
270 if (i % 2 == 0) {
271 if (j % 2 == 0) {
272 printf(TILE1COLOR " " RESETCOLOR);
273 } else {
274 printf(TILE2COLOR " " RESETCOLOR);
275 }
276 } else {
277 if (j % 2 == 0) {
278 printf(TILE2COLOR " " RESETCOLOR);
279 } else {
280 printf(TILE1COLOR " " RESETCOLOR);
281 }
282 }
283 last_pos_was_move = 0;
284 break;
285 default:
286 fprintf(stderr, "Illegal board value %d\n", (int)BOARD(i, j));
287 exit(EXIT_FAILURE);
288 break;
289 }
290 }
291
292 if (last_pos_was_move == 0) {
293 if (board_size > 10)
294 printf(" %2d", board_size - i);
295 else
296 printf(" %1d", board_size - i);
297 } else {
298 if (board_size > 10)
299 printf("%2d", board_size - i);
300 else
301 printf("%1d", board_size - i);
302 }
303 printf("\n");
304 }
305
306 fflush(stdout);
307 printf("%s\n\n", letterbar);
308 fflush(stdout);
309
310 if (clock_on) {
311 clock_print(WHITE);
312 clock_print(BLACK);
313 }
314
315} /* end twoplayer_showboard */
316
317/*
318 * command help
319 */
320
321static void
322show_commands(void)
323{
324 printf("\nCommands:\n");
de03db18
AT
325 printf(" comment Write a comment to outputfile\n");
326 printf(" depth <num> Set depth for reading\n");
327 printf(" display Display game board\n");
328 printf(" exit Exit GNU Go\n");
de03db18 329 printf(" level <amount> Playing level (default = 10)\n");
de03db18
AT
330 printf(" help Display this help menu\n");
331 printf(" helpdebug Display debug help menu\n");
332 printf(" info Display program settings\n");
de03db18 333 printf(" pass Pass on your move\n");
de03db18 334 printf(" quit Exit GNU Go\n");
de03db18 335 printf(" save <file> Save the current game\n");
de03db18
AT
336 printf(" score Toggle display of score On/Off\n");
337 printf(" showboard Toggle display of board On/Off\n");
de03db18
AT
338 printf(" <move> A move of the format <letter><number>");
339 printf("\n");
340}
341
342enum commands { INVALID = -1,
343 END,
344 EXIT,
345 QUIT,
346 RESIGN,
347 PASS,
348 MOVE,
349 FORCE,
350 SWITCH,
351 PLAY,
352 PLAYBLACK,
353 PLAYWHITE,
354 SETHANDICAP,
355 FREEHANDICAP,
356 SETBOARDSIZE,
357 SETKOMI,
358 SETDEPTH,
359 INFO,
360 DISPLAY,
361 SHOWBOARD,
362 HELP,
363 UNDO,
364 COMMENT,
365 SCORE,
366 CMD_DEAD,
367 CMD_BACK,
368 CMD_FORWARD,
369 CMD_LAST,
370 CMD_CAPTURE,
371 CMD_DEFEND,
372 CMD_HELPDEBUG,
373 CMD_SHOWAREA,
374 CMD_SHOWMOYO,
375 CMD_SHOWTERRI,
376 CMD_GOTO,
377 CMD_SAVE,
378 CMD_LOAD,
379 CMD_SHOWDRAGONS,
380 CMD_LISTDRAGONS,
381 SETLEVEL,
382 NEW,
383 COUNT,
384 CONTINUE
385};
386
387/*
388 * Check if we have a valid command.
389 */
390
391static int
392get_command(char* command)
393{
394 char c;
395 int d;
396
397 /* Check to see if a move was input. */
398 if (!((sscanf(command, "%c%d", &c, &d) != 2)
399 || ((c = toupper((int)c)) < 'A')
400 || ((c = toupper((int)c)) > 'Z')
401 || (c == 'I')))
402 return MOVE;
403
404 /* help shortcut */
405 if (command[0] == '?')
406 return HELP;
407
408 /* Kill leading spaces. */
409 while (command[0] == ' ')
410 command++;
411
412 if (!strncmp(command, "playblack", 9))
413 return PLAYBLACK;
414 if (!strncmp(command, "playwhite", 9))
415 return PLAYWHITE;
416 if (!strncmp(command, "showboard", 9))
417 return SHOWBOARD;
418 if (!strncmp(command, "showdragons", 9))
419 return CMD_SHOWDRAGONS;
420 if (!strncmp(command, "listdragons", 9))
421 return CMD_LISTDRAGONS;
422 if (!strncmp(command, "boardsize", 9))
423 return SETBOARDSIZE;
424 if (!strncmp(command, "freehandicap", 9))
425 return FREEHANDICAP;
426 if (!strncmp(command, "handicap", 5))
427 return SETHANDICAP;
428 if (!strncmp(command, "display", 7))
429 return DISPLAY;
430 if (!strncmp(command, "helpdebug", 7))
431 return CMD_HELPDEBUG;
432 if (!strncmp(command, "resign", 6))
433 return RESIGN;
434 if (!strncmp(command, "showmoyo", 6))
435 return CMD_SHOWMOYO;
436 if (!strncmp(command, "showterri", 6))
437 return CMD_SHOWTERRI;
438 if (!strncmp(command, "showarea", 6))
439 return CMD_SHOWAREA;
440 if (!strncmp(command, "depth", 5))
441 return SETDEPTH;
442 if (!strncmp(command, "switch", 5))
443 return SWITCH;
444 if (!strncmp(command, "komi", 4))
445 return SETKOMI;
446 if (!strncmp(command, "play", 4))
447 return PLAY;
448 if (!strncmp(command, "info", 4))
449 return INFO;
450 if (!strncmp(command, "force", 4))
451 return FORCE;
452 if (!strncmp(command, "level", 5))
453 return SETLEVEL;
454 if (!strncmp(command, "pass", 4))
455 return PASS;
456 if (!strncmp(command, "save", 3))
457 return CMD_SAVE;
458 if (!strncmp(command, "load", 3))
459 return CMD_LOAD;
460 if (!strncmp(command, "end", 3))
461 return END;
462 if (!strncmp(command, "move", 3))
463 return MOVE;
464 if (!strncmp(command, "undo", 3))
465 return UNDO;
466 if (!strncmp(command, "comment", 3))
467 return COMMENT;
468 if (!strncmp(command, "score", 3))
469 return SCORE;
470 if (!strncmp(command, "dead", 3))
471 return CMD_DEAD;
472 if (!strncmp(command, "capture", 3))
473 return CMD_CAPTURE;
474 if (!strncmp(command, "defend", 3))
475 return CMD_DEFEND;
476 if (!strncmp(command, "exit", 4))
477 return EXIT;
478 if (!strncmp(command, "quit", 4))
479 return QUIT;
480 if (!strncmp(command, "help", 1))
481 return HELP;
482 if (!strncmp(command, "back", 2))
483 return CMD_BACK;
484 if (!strncmp(command, "forward", 2))
485 return CMD_FORWARD;
486 if (!strncmp(command, "last", 2))
487 return CMD_LAST;
488 if (!strncmp(command, "goto", 2))
489 return CMD_GOTO;
490 if (!strncmp(command, "game", 2))
491 return NEW;
492 if (!strncmp(command, "count", 3))
493 return COUNT;
494 if (!strncmp(command, "continue", 4))
495 return CONTINUE;
496
497 /* No valid command was found. */
498 return INVALID;
499}
500
501/*
502 * Write sgf root node.
503 */
504
505static void
506init_sgf(Gameinfo* ginfo)
507{
508 if (sgf_initialized)
509 return;
510 sgf_initialized = 1;
511
512 sgf_write_header(sgftree.root, 1, get_random_seed(), komi,
513 ginfo->handicap, get_level(), chinese_rules);
514 if (ginfo->handicap > 0)
515 sgffile_recordboard(sgftree.root);
516}
517
0cb00f5b
AT
518/*
519 * Communication with second player.
520 */
521
522static int
523twoplayer_recv_move(int fd)
524{
525 int move;
526 printf("\nWaiting to receive move from other player...\n");
527 if (read(fd, &move, sizeof(move)) != sizeof(int)) {
528 printf("\n");
529 printf(WHITECOLOR " " RESETCOLOR);
530 printf("\n");
531 printf(WHITECOLOR " " RESETCOLOR);
532 printf("Unrecoverable error. Save game if desired, then quit.");
533 printf(WHITECOLOR " " RESETCOLOR);
534 printf("\n");
535 printf(WHITECOLOR " " RESETCOLOR);
536 printf("\n");
537 printf("\n");
538 move = NO_MOVE;
539 }
540 return move;
541}
542
543static void
544twoplayer_send_move(int move, int fd)
545{
546 write(fd, &move, sizeof(move));
547}
548
de03db18
AT
549/*
550 * Generate the computer move.
551 */
552
553static int
0cb00f5b 554computer_move(Gameinfo* gameinfo, int* passes, int receive_fifo_fd)
de03db18
AT
555{
556 int move;
de03db18
AT
557 int resignation_declined = 0;
558 float upper_bound, lower_bound;
559
560 init_sgf(gameinfo);
561
0cb00f5b 562 move = twoplayer_recv_move(receive_fifo_fd);
de03db18
AT
563
564 if (showscore) {
565 gnugo_estimate_score(&upper_bound, &lower_bound);
566 current_score_estimate = (int)((lower_bound + upper_bound) / 2.0);
567 }
568
569 mprintf("%s(%d): %1m\n", color_to_string(gameinfo->to_move),
570 movenum + 1, move);
571 if (is_pass(move))
572 (*passes)++;
573 else
574 *passes = 0;
575
576 gnugo_play_move(move, gameinfo->to_move);
de03db18
AT
577 sgftreeAddPlay(&sgftree, gameinfo->to_move, I(move), J(move));
578 if (resignation_declined)
579 sgftreeAddComment(&sgftree, "GNU Go resignation was declined");
580 sgffile_output(&sgftree);
581
582 gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
583 return 0;
584}
585
586/*
587 * Make a move.
588 */
589
590static int
6c3e8b62
AT
591do_move(Gameinfo* gameinfo, char* command, int* passes, int force,
592 int transmit_fifo_fd, int receive_fifo_fd)
de03db18
AT
593{
594 int move = string_to_location(board_size, command);
595
596 if (move == NO_MOVE) {
597 printf("\nInvalid move: %s\n", command);
598 return 0;
599 }
600
601 if (!is_allowed_move(move, gameinfo->to_move)) {
602 printf("\nIllegal move: %s", command);
603 return 0;
604 }
605
0cb00f5b
AT
606 twoplayer_send_move(move,transmit_fifo_fd);
607
de03db18
AT
608 *passes = 0;
609 TRACE("\nyour move: %1m\n\n", move);
610 init_sgf(gameinfo);
611 gnugo_play_move(move, gameinfo->to_move);
612 sgffile_add_debuginfo(sgftree.lastnode, 0.0);
613 sgftreeAddPlay(&sgftree, gameinfo->to_move, I(move), J(move));
614 sgffile_output(&sgftree);
615
616 if (opt_showboard) {
617 twoplayer_showboard();
de03db18
AT
618 }
619
620 if (force) {
621 gameinfo->computer_player = OTHER_COLOR(gameinfo->computer_player);
622 gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
623 sgftreeAddComment(&sgftree, "forced");
624 return 0;
625 }
626
627 gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
0cb00f5b 628 return computer_move(gameinfo, passes, receive_fifo_fd);
de03db18
AT
629}
630
631/*
632 * Make a pass.
633 */
634
635static int
6c3e8b62
AT
636do_pass(Gameinfo* gameinfo, int* passes, int force,
637 int transmit_fifo_fd, int receive_fifo_fd)
de03db18 638{
0cb00f5b
AT
639 twoplayer_send_move(NO_MOVE,transmit_fifo_fd);
640
de03db18
AT
641 (*passes)++;
642 init_sgf(gameinfo);
643 gnugo_play_move(PASS_MOVE, gameinfo->to_move);
644 sgffile_add_debuginfo(sgftree.lastnode, 0.0);
645 sgftreeAddPlay(&sgftree, gameinfo->to_move, -1, -1);
646 sgffile_output(&sgftree);
647
648 gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
649 if (force) {
650 gameinfo->computer_player = OTHER_COLOR(gameinfo->computer_player);
651 sgftreeAddComment(&sgftree, "forced");
652 return 0;
653 }
654
0cb00f5b 655 return computer_move(gameinfo, passes, receive_fifo_fd);
de03db18
AT
656}
657
658/*
659 * Play a game using ANSI client.
660 */
661
662void play_twoplayer(SGFTree* tree, Gameinfo* gameinfo, char* filename, char* until)
663{
664 int sz;
665
b0d6e9e5 666 int transmit_fifo_fd, receive_fifo_fd;
b0d6e9e5 667 if (mknod(MASTER_FIFO_NAME, S_IFIFO | 0666, 0) == 0) {
6c3e8b62 668 gameinfo->computer_player = WHITE; // We are black, so our opponent is white.
0cb00f5b 669 printf("Waiting for other player to connect.\n");
b0d6e9e5 670 transmit_fifo_fd = open(MASTER_FIFO_NAME, O_WRONLY);
b0d6e9e5 671 receive_fifo_fd = open(SLAVE_FIFO_NAME, O_RDONLY);
b0d6e9e5 672 } else {
6c3e8b62 673 gameinfo->computer_player = BLACK; // We are white, so our opponent is black.
b0d6e9e5 674 if (mknod(SLAVE_FIFO_NAME, S_IFIFO | 0666, 0) == 0) {
b0d6e9e5 675 receive_fifo_fd = open(MASTER_FIFO_NAME, O_RDONLY);
b0d6e9e5 676 transmit_fifo_fd = open(SLAVE_FIFO_NAME, O_WRONLY);
b0d6e9e5 677 } else {
0cb00f5b 678 printf("ERROR: Failed to create both master and slave FIFO.\n");
b0d6e9e5
AT
679 exit(EXIT_FAILURE);
680 }
681 }
682 // Allow both master and slave to attempt removal. Ignore error code since
683 // this is a best-effort situation for now.
684 unlink(MASTER_FIFO_NAME);
685 unlink(SLAVE_FIFO_NAME);
b0d6e9e5 686
de03db18
AT
687 setvbuf(stdout, (char*)NULL, _IONBF, 0); /* No buffering. */
688
689 sgftree = *tree;
690
691 if (filename) {
692 /* No need to check for failure here since that was already done
693 * when it was loaded in main().
694 *
695 * FIXME: Why do we load the game again?
696 */
697 gameinfo_play_sgftree(gameinfo, &sgftree, until);
698 sgf_initialized = 1;
699 } else {
700 if (sgfGetIntProperty(sgftree.root, "SZ", &sz))
701 gnugo_clear_board(sz);
702 if (gameinfo->handicap == 0)
703 gameinfo->to_move = BLACK;
704 else {
705 gameinfo->handicap = place_fixed_handicap(gameinfo->handicap);
706 gameinfo->to_move = WHITE;
707 }
708 sgf_initialized = 0;
709 }
710
6c3e8b62 711 do_play_twoplayer(gameinfo, transmit_fifo_fd, receive_fifo_fd);
de03db18
AT
712 printf("\nThanks! for playing GNU Go.\n\n");
713
b0d6e9e5
AT
714 close(transmit_fifo_fd);
715 close(receive_fifo_fd);
716
de03db18
AT
717 /* main() frees the tree and we might have changed it. */
718 *tree = sgftree;
719}
720
6c3e8b62 721void do_play_twoplayer(Gameinfo* gameinfo, int transmit_fifo_fd, int receive_fifo_fd)
de03db18 722{
6c3e8b62
AT
723 //int m;
724 int num;
725 //float fnum;
de03db18 726 int passes = 0; /* two passes and its over */
6c3e8b62 727 //int tmp;
de03db18
AT
728 char line[80];
729 char* line_ptr = line;
730 char* command;
731 char* tmpstring;
732 int state = 1;
733
734 if (have_time_settings())
735 clock_on = 1;
736
737 while (state == 1) {
738 state = 0;
739
740 /* No score is estimated yet. */
741 current_score_estimate = NO_SCORE;
742
743 /* Allow resignation at interface level (the engine may still be not
6c3e8b62
AT
744 * allowed to resign.
745 */
de03db18
AT
746 resignation_allowed = 1;
747
748 printf("\nBeginning two player game.\n\n");
749 gameinfo_print(gameinfo);
750
751 /* Does the computer play first? If so, make a move. */
752 if (gameinfo->computer_player == gameinfo->to_move)
0cb00f5b 753 state = computer_move(gameinfo, &passes, receive_fifo_fd);
de03db18
AT
754
755 /* main ANSI Play loop */
756 while (state == 0) {
757 /* Display game board. */
758 if (opt_showboard)
759 twoplayer_showboard();
760
761#if !READLINE
762 /* Print the prompt */
763 mprintf("%s(%d): ", color_to_string(gameinfo->to_move), movenum + 1);
764
765 /* Read a line of input. */
766 line_ptr = line;
767 if (!fgets(line, 80, stdin))
768 return;
769#else
770 snprintf(line, 79, "%s(%d): ",
771 color_to_string(gameinfo->to_move), movenum + 1);
772 if (!(line_ptr = readline(line)))
773 return;
774
775 add_history(line_ptr);
776#endif
777
778 while (state == 0
779 && (command = strtok(line_ptr, ";"), line_ptr = 0, command)) {
780 /* Get the command or move. */
781 switch (get_command(command)) {
782 case RESIGN:
0cb00f5b 783 //state = twoplayer_endgame(gameinfo, 1);
de03db18
AT
784 break;
785
786 case END:
787 case EXIT:
788 case QUIT:
789 return;
790
791 case HELP:
792 show_commands();
793 break;
794
795 case CMD_HELPDEBUG:
796 printf(DEBUG_COMMANDS);
797 break;
798
799 case SHOWBOARD:
800 opt_showboard = !opt_showboard;
801 break;
802
803 case INFO:
804 printf("\n");
805 gameinfo_print(gameinfo);
806 break;
807
808 case SETBOARDSIZE:
6c3e8b62
AT
809 printf("Board size modification prohibited in two player mode.\n");
810 //if (sgf_initialized) {
811 // printf("Boardsize cannot be changed after record is started!\n");
812 // break;
813 //}
814 //command += 10;
815 //if (sscanf(command, "%d", &num) != 1) {
816 // printf("\nInvalid command syntax!\n");
817 // break;
818 //}
819 //if (!check_boardsize(num, stdout))
820 // break;
821 ///* Init board. */
822 //board_size = num;
823 //clear_board();
824 ///* In case max handicap changes on smaller board. */
825 //gameinfo->handicap = place_fixed_handicap(gameinfo->handicap);
826 //sgfOverwritePropertyInt(sgftree.root, "SZ", board_size);
827 //sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
de03db18
AT
828 break;
829
830 case SETHANDICAP:
6c3e8b62
AT
831 printf("Handicap modification prohibited in two player mode.\n");
832 //if (sgf_initialized) {
833 // printf("Handicap cannot be changed after game is started!\n");
834 // break;
835 //}
836 //command += 9;
837 //if (sscanf(command, "%d", &num) != 1) {
838 // printf("\nInvalid command syntax!\n");
839 // break;
840 //}
841 //if (num < 0 || num > MAX_HANDICAP) {
842 // printf("\nInvalid handicap: %d\n", num);
843 // break;
844 //}
845 ///* Init board. */
846 //clear_board();
847 ///* Place stones on board but don't record sgf
848 // * in case we change more info. */
849 //gameinfo->handicap = place_fixed_handicap(num);
850 //printf("\nSet handicap to %d\n", gameinfo->handicap);
851 //gameinfo->to_move = (gameinfo->handicap ? WHITE : BLACK);
de03db18
AT
852 break;
853
854 case FREEHANDICAP:
6c3e8b62
AT
855 printf("Handicap modification prohibited in two player mode.\n");
856 //if (sgf_initialized) {
857 // printf("Handicap cannot be changed after game is started!\n");
858 // break;
859 //}
860 //while (*command && *command != ' ')
861 // command++;
862 //twoplayer_free_handicap(gameinfo, command);
de03db18
AT
863 break;
864
865 case SETKOMI:
6c3e8b62
AT
866 printf("Komi modification prohibited in two player mode.\n");
867 //if (sgf_initialized) {
868 // printf("Komi cannot be modified after game record is started!\n");
869 // break;
870 //}
871 //command += 5;
872 //if (sscanf(command, "%f", &fnum) != 1) {
873 // printf("\nInvalid command syntax!\n");
874 // break;
875 //}
876 //komi = fnum;
877 //printf("\nSet Komi to %.1f\n", komi);
de03db18
AT
878 break;
879
880 case SETDEPTH:
881 command += 6;
882 if (sscanf(command, "%d", &num) != 1) {
883 printf("\nInvalid command syntax!\n");
884 break;
885 }
886 mandated_depth = num;
887 printf("\nSet depth to %d\n", mandated_depth);
888 break;
889
890 case SETLEVEL:
891 command += 6;
892 if (sscanf(command, "%d", &num) != 1) {
893 printf("\nInvalid command syntax!\n");
894 break;
895 }
896 set_level(num);
897 printf("\nSet level to %d\n", num);
898 break;
899
900 case DISPLAY:
901 if (!opt_showboard)
902 twoplayer_showboard();
903 break;
904
905 case FORCE:
6c3e8b62
AT
906 printf("No!\n");
907 //command += 6; /* skip the force part... */
908 //switch (get_command(command)) {
909 //case MOVE:
910 // state = do_move(gameinfo, command, &passes, 1);
911 // break;
912 //case PASS:
913 // state = do_pass(gameinfo, &passes, 1);
914 // break;
915 //default:
916 // printf("Illegal forced move: %s %d\n", command,
917 // get_command(command));
918 // break;
919 //}
de03db18
AT
920 break;
921
922 case MOVE:
6c3e8b62 923 state = do_move(gameinfo, command, &passes, 0, transmit_fifo_fd, receive_fifo_fd);
de03db18
AT
924 break;
925
926 case PASS:
6c3e8b62 927 state = do_pass(gameinfo, &passes, 0, transmit_fifo_fd, receive_fifo_fd);
de03db18
AT
928 break;
929
930 case PLAY:
6c3e8b62
AT
931 printf("Invalid command in two player mode.\n");
932 //command += 5;
933 //if (sscanf(command, "%d", &num) != 1) {
934 // printf("\nInvalid command syntax!\n");
935 // break;
936 //}
937 //if (num >= 0)
938 // for (m = 0; m < num; m++) {
939 // gameinfo->computer_player
940 // = OTHER_COLOR(gameinfo->computer_player);
941 // state = computer_move(gameinfo, &passes);
942 // if (state)
943 // break;
944 // if (passes >= 2)
945 // break;
946 // }
947 //else {
948 // printf("\nInvalid number of moves specified: %d\n", num);
949 // break;
950 //}
de03db18
AT
951 break;
952
953 case PLAYBLACK:
6c3e8b62
AT
954 printf("Invalid command in two player mode.\n");
955 //if (gameinfo->computer_player == WHITE)
956 // gameinfo->computer_player = BLACK;
957 //if (gameinfo->computer_player == gameinfo->to_move)
958 // state = computer_move(gameinfo, &passes);
de03db18
AT
959 break;
960
961 case PLAYWHITE:
6c3e8b62
AT
962 printf("Invalid command in two player mode.\n");
963 //if (gameinfo->computer_player == BLACK)
964 // gameinfo->computer_player = WHITE;
965 //if (gameinfo->computer_player == gameinfo->to_move)
966 // state = computer_move(gameinfo, &passes);
de03db18
AT
967 break;
968
969 case SWITCH:
6c3e8b62
AT
970 printf("Invalid command in two player mode.\n");
971 //gameinfo->computer_player = OTHER_COLOR(gameinfo->computer_player);
972 //state = computer_move(gameinfo, &passes);
de03db18
AT
973 break;
974
975 case UNDO:
976 case CMD_BACK:
6c3e8b62
AT
977 printf("No undo in two player mode.\n");
978 //if (undo_move(1)) {
979 // sgftreeAddComment(&sgftree, "undone");
980 // sgftreeBack(&sgftree);
981 // gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
982 //} else
983 // printf("\nCan't undo.\n");
de03db18
AT
984 break;
985
986 case CMD_FORWARD:
6c3e8b62
AT
987 printf("Invalid command in two player mode.\n");
988 //if (sgftreeForward(&sgftree))
989 // gameinfo->to_move = gnugo_play_sgfnode(sgftree.lastnode,
990 // gameinfo->to_move);
991 //else
992 // printf("\nEnd of game tree.\n");
de03db18
AT
993 break;
994
995 case CMD_LAST:
6c3e8b62
AT
996 printf("Invalid command in two player mode.\n");
997 //while (sgftreeForward(&sgftree))
998 // gameinfo->to_move = gnugo_play_sgfnode(sgftree.lastnode,
999 // gameinfo->to_move);
de03db18
AT
1000 break;
1001
1002 case COMMENT:
1003 printf("\nEnter comment. Press ENTER when ready.\n");
1004 fgets(line, 80, stdin);
1005 sgftreeAddComment(&sgftree, line);
1006 break;
1007
1008 case SCORE:
1009 showscore = !showscore;
1010 if (!showscore)
1011 current_score_estimate = NO_SCORE;
1012 break;
1013
1014 case CMD_DEAD:
6c3e8b62
AT
1015 printf("Invalid command in two player mode.\n");
1016 //silent_examine_position(FULL_EXAMINE_DRAGONS);
1017 //showdead = !showdead;
de03db18
AT
1018 break;
1019
1020 case CMD_CAPTURE:
6c3e8b62
AT
1021 printf("Invalid command in two player mode.\n");
1022 //strtok(command, " ");
1023 //showcapture(strtok(NULL, " "));
de03db18
AT
1024 break;
1025
1026 case CMD_DEFEND:
6c3e8b62
AT
1027 printf("Invalid command in two player mode.\n");
1028 //strtok(command, " ");
1029 //showdefense(strtok(NULL, " "));
de03db18
AT
1030 break;
1031
1032 case CMD_SHOWMOYO:
6c3e8b62
AT
1033 printf("Invalid command in two player mode.\n");
1034 //tmp = printmoyo;
1035 //printmoyo = PRINTMOYO_MOYO;
1036 //silent_examine_position(EXAMINE_DRAGONS);
1037 //printmoyo = tmp;
de03db18
AT
1038 break;
1039
1040 case CMD_SHOWTERRI:
6c3e8b62
AT
1041 printf("Invalid command in two player mode.\n");
1042 //tmp = printmoyo;
1043 //printmoyo = PRINTMOYO_TERRITORY;
1044 //silent_examine_position(EXAMINE_DRAGONS);
1045 //printmoyo = tmp;
de03db18
AT
1046 break;
1047
1048 case CMD_SHOWAREA:
6c3e8b62
AT
1049 printf("Invalid command in two player mode.\n");
1050 //tmp = printmoyo;
1051 //printmoyo = PRINTMOYO_AREA;
1052 //silent_examine_position(EXAMINE_DRAGONS);
1053 //printmoyo = tmp;
de03db18
AT
1054 break;
1055
1056 case CMD_SHOWDRAGONS:
6c3e8b62
AT
1057 printf("Invalid command in two player mode.\n");
1058 //silent_examine_position(EXAMINE_DRAGONS);
1059 //showboard(1);
de03db18
AT
1060 break;
1061
1062 case CMD_GOTO:
6c3e8b62
AT
1063 printf("Invalid command in two player mode.\n");
1064 //strtok(command, " ");
1065 //twoplayer_goto(gameinfo, strtok(NULL, " "));
de03db18
AT
1066 break;
1067
1068 case CMD_SAVE:
1069 strtok(command, " ");
1070 tmpstring = strtok(NULL, " ");
1071 if (tmpstring) {
1072 /* discard newline */
1073 tmpstring[strlen(tmpstring) - 1] = 0;
1074 /* make sure we are saving proper handicap */
1075 init_sgf(gameinfo);
1076 writesgf(sgftree.root, tmpstring);
6c3e8b62
AT
1077 printf("Game saved at %s for offline use.\n", tmpstring);
1078 //printf("You may resume the game");
1079 //printf(" with -l %s --mode twoplayer\n", tmpstring);
1080 //printf("or load %s\n", tmpstring);
de03db18
AT
1081 } else
1082 printf("Please specify filename\n");
1083 break;
1084
1085 case CMD_LOAD:
6c3e8b62
AT
1086 printf("Invalid command in two player mode.\n");
1087 //strtok(command, " ");
1088 //tmpstring = strtok(NULL, " ");
1089 //if (tmpstring) {
1090 // /* discard newline */
1091 // tmpstring[strlen(tmpstring) - 1] = 0;
1092 // if (!sgftree_readfile(&sgftree, tmpstring)) {
1093 // fprintf(stderr, "Cannot open or parse '%s'\n", tmpstring);
1094 // break;
1095 // }
1096 // /* to avoid changing handicap etc. */
1097 // if (gameinfo_play_sgftree(gameinfo, &sgftree, NULL) == EMPTY)
1098 // fprintf(stderr, "Cannot load '%s'\n", tmpstring);
1099 // else {
1100 // sgf_initialized = 1;
1101 // sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
1102 // }
1103 //} else
1104 // printf("Please specify a filename\n");
de03db18
AT
1105 break;
1106
1107 case CMD_LISTDRAGONS:
6c3e8b62
AT
1108 printf("Invalid command in two player mode.\n");
1109 //silent_examine_position(EXAMINE_DRAGONS);
1110 //show_dragons();
de03db18
AT
1111 break;
1112
1113 default:
1114 printf("\nInvalid command: %s", command);
1115 break;
1116 }
1117
0cb00f5b
AT
1118 if (passes >= 2) {
1119 twoplayer_send_move(NO_MOVE,transmit_fifo_fd);
de03db18 1120 state = twoplayer_endgame(gameinfo, 0);
0cb00f5b 1121 }
de03db18
AT
1122 }
1123#if READLINE
1124 free(line_ptr);
1125#endif
1126 }
1127
1128 sgffile_output(&sgftree);
1129 passes = 0;
1130
1131 /* Play a different game next time. */
1132 update_random_seed();
1133
1134 /* Free the sgf tree and prepare for a new game. */
1135 sgfFreeNode(sgftree.root);
1136 sgftree_clear(&sgftree);
1137 sgftreeCreateHeaderNode(&sgftree, board_size, komi, gameinfo->handicap);
1138 sgf_initialized = 0;
1139
1140 gameinfo_clear(gameinfo);
1141 }
1142}
1143
1144/* Communicates with user after a game has ended. */
1145static int
1146twoplayer_endgame(Gameinfo* gameinfo, int reason)
1147{
1148 char line[80];
1149 char* line_ptr;
1150 char* command;
1151 char* tmpstring;
1152 int state = 0;
1153
1154 if (reason == 0) { /* Two passes, game is over. */
1155 who_wins(gameinfo->computer_player, stdout);
1156 printf("\nIf you disagree, we may count the game together.\n");
1157
1158 sgftreeWriteResult(&sgftree, (white_score + black_score) / 2.0, 1);
1159 } else {
1160 int color = OTHER_COLOR(gameinfo->to_move);
1161
1162 if (reason == 1) /* Our opponent has resigned. */
1163 printf("GNU Go wins by resignation.\n");
1164 else /* We have resigned. */
1165 printf("You win by resignation.\n");
1166
1167 printf("Result: %c+Resign\n\n", color == WHITE ? 'W' : 'B');
1168 sgftreeWriteResult(&sgftree, color == WHITE ? 1000.0 : -1000.0, 1);
1169 }
1170
1171 while (state == 0) {
1172 printf("You may optionally save the game as an SGF file.\n\n");
1173 printf("Type \"save <filename>\" to save,\n");
1174 if (reason == 0)
1175 printf(" \"count\" to recount,\n");
1176 else if (reason == 2)
1177 printf(" \"continue\" to decline resignation and continue the game,\n");
1178 printf(" \"quit\" to quit\n");
1179 printf(" or \"game\" to play again\n");
1180
1181 line_ptr = line;
1182 if (!fgets(line, 80, stdin))
1183 break;
1184
1185 command = strtok(line_ptr, "");
1186 switch (get_command(command)) {
1187 case CMD_SAVE:
1188 strtok(command, " ");
1189 tmpstring = strtok(NULL, " ");
1190 if (tmpstring) {
1191 /* discard newline */
1192 tmpstring[strlen(tmpstring) - 1] = 0;
1193 init_sgf(gameinfo);
1194 writesgf(sgftree.root, tmpstring);
1195 } else
1196 printf("Please specify filename\n");
1197 break;
1198
1199 case COUNT:
1200 if (reason == 0)
1201 twoplayer_count(gameinfo);
1202 break;
1203
1204 case CONTINUE:
1205 state = -1;
1206 break;
1207
1208 case NEW:
1209 state = 1;
1210 break;
1211
1212 case QUIT:
1213 state = 2;
1214 break;
1215
1216 default:
1217 state = 0;
1218 }
1219 }
1220
1221 return state;
1222}
1223
1224/* twoplayer_count() scores the game.
1225 */
1226static void
1227twoplayer_count(Gameinfo* gameinfo)
1228{
1229 char line[12];
1230 int done = 0;
1231 int i;
1232 int xyzzy = 1;
1233
1234 printf("\nGame over. Let's count!.\n");
1235 showdead = 1;
1236 twoplayer_showboard();
1237 while (!done) {
1238 printf("Dead stones are marked with small letters (x,o).\n");
1239 printf("\nIf you don't agree, enter the location of a group\n");
1240 printf("to toggle its state or \"done\".\n");
1241
1242 if (!fgets(line, 12, stdin))
1243 return; /* EOF or some error */
1244
1245 for (i = 0; i < 12; i++)
1246 line[i] = tolower((int)line[i]);
1247 if (!strncmp(line, "done", 4))
1248 done = 1;
1249 else if (!strncmp(line, "quit", 4))
1250 return;
1251 else if (!strncmp(line, "xyzzy", 5)) {
1252 if (xyzzy) {
1253 printf("\nYou are in a debris room filled with stuff washed in from the\n");
1254 printf("surface. A low wide passage with cobbles becomes plugged\n");
1255 printf("with mud and debris here, but an awkward canyon leads\n");
1256 printf("upward and west. A note on the wall says:\n");
1257 printf(" Magic Word \"XYZZY\"\n\n");
1258 xyzzy = 0;
1259 } else {
1260 printf("You are inside a building, a well house for a large spring.\n\n");
1261 xyzzy = 1;
1262 }
1263 } else if (!strncmp(line, "help", 4)) {
1264 printf("\nIf there are dead stones on the board I will remove them.\n");
1265 printf("You must tell me where they are. Type the coordinates of a\n");
1266 printf("dead group, or type \"done\"\n");
1267 } else if (!strncmp(line, "undo", 4)) {
1268 printf("UNDO not allowed anymore. The status of the stones now\n");
1269 printf("toggles after entering the location of it.\n");
1270 twoplayer_showboard();
1271 } else {
1272 int pos = string_to_location(board_size, line);
1273 if (pos == NO_MOVE || board[pos] == EMPTY)
1274 printf("\ninvalid!\n");
1275 else {
1276 enum dragon_status status = dragon_status(pos);
1277 status = (status == DEAD) ? ALIVE : DEAD;
1278 change_dragon_status(pos, status);
1279 twoplayer_showboard();
1280 }
1281 }
1282 }
1283 who_wins(gameinfo->computer_player, stdout);
1284}
1285
6c3e8b62
AT
1286//static void
1287//showcapture(char* line)
1288//{
1289// int str;
1290// int move;
1291//
1292// gg_assert(line);
1293// str = string_to_location(board_size, line);
1294// if (str == NO_MOVE || board[str] == EMPTY) {
1295// printf("\ninvalid point!\n");
1296// return;
1297// }
1298//
1299// if (attack(str, &move))
1300// mprintf("\nSuccessful attack of %1m at %1m\n", str, move);
1301// else
1302// mprintf("\n%1m cannot be attacked\n", str);
1303//}
1304
1305//static void
1306//showdefense(char* line)
1307//{
1308// int str;
1309// int move;
1310//
1311// gg_assert(line);
1312// str = string_to_location(board_size, line);
1313// if (str == NO_MOVE || board[str] == EMPTY) {
1314// printf("\ninvalid point!\n");
1315// return;
1316// }
1317//
1318// if (attack(str, NULL)) {
1319// if (find_defense(str, &move))
1320// mprintf("\nSuccessful defense of %1m at %1m\n", str, move);
1321// else
1322// mprintf("\n%1m cannot be defended\n", str);
1323// } else
1324// mprintf("\nThere is no need to defend %1m\n", str);
1325//}
1326
1327//static void
1328//twoplayer_goto(Gameinfo* gameinfo, char* line)
1329//{
1330// const char* movenumber = line;
1331//
1332// if (!line)
1333// return;
1334//
1335// if (!strncmp(line, "last", 4))
1336// movenumber = "9999";
1337// else if (!strncmp(line, "first", 4))
1338// movenumber = "1";
1339//
1340// printf("goto %s\n", movenumber);
1341// gameinfo_play_sgftree(gameinfo, &sgftree, movenumber);
1342//}
1343
1344//static void
1345//twoplayer_free_handicap(Gameinfo* gameinfo, char* handicap_string)
1346//{
1347// int handi;
1348// int i;
1349// char line[80];
1350// int stones[MAX_BOARD * MAX_BOARD];
1351//
1352// if (sscanf(handicap_string, "%d", &handi) == 1) {
1353// /* GNU Go is to place handicap */
1354// if (handi < 0 || handi == 1) {
1355// printf("\nInvalid command syntax!\n");
1356// return;
1357// }
1358//
1359// clear_board();
1360// handi = place_free_handicap(handi);
1361// printf("\nPlaced %d stones of free handicap.\n", handi);
1362// } else { /* User is to place handicap */
1363// clear_board();
1364// handi = 0;
1365//
1366// while (1) {
1367// twoplayer_showboard();
1368// printf("\nType in coordinates of next handicap stone, or one of the following commands:\n");
1369// printf(" undo take back the last stone placed\n");
1370// printf(" clear remove all the stones placed so far\n");
1371// printf(" done finish placing handicap\n\n");
1372// printf("You have placed %d handicap stone(s) so far.\n\n", handi);
1373//
1374// if (!fgets(line, 80, stdin))
1375// return; /* EOF or some error */
1376// for (i = 0; i < 80; i++)
1377// line[i] = tolower((int)line[i]);
1378//
1379// if (!strncmp(line, "undo", 4)) {
1380// if (!handi)
1381// printf("\nNothing to undo.\n");
1382// else {
1383// remove_stone(stones[--handi]);
1384// gprintf("\nRemoved the stone at %m.\n", I(stones[handi]),
1385// J(stones[handi]));
1386// }
1387// } else if (!strncmp(line, "clear", 5)) {
1388// clear_board();
1389// handi = 0;
1390// } else if (!strncmp(line, "done", 4)) {
1391// if (handi == 1) /* Don't bother with checks later */
1392// printf("\nHandicap cannot be one stone. Either add "
1393// "some more, or delete the only stone.\n");
1394// else
1395// break;
1396// } else {
1397// int pos = string_to_location(board_size, line);
1398// if (pos != NO_MOVE) {
1399// if (board[pos] != EMPTY)
1400// printf("\nThere's already a stone there.\n");
1401// else {
1402// add_stone(pos, BLACK);
1403// stones[handi++] = pos;
1404// }
1405// } else
1406// printf("\nInvalid command: %s", line);
1407// }
1408// }
1409// }
1410// gameinfo->handicap = handi;
1411// gameinfo->to_move = (handi ? WHITE : BLACK);
1412//}
de03db18
AT
1413
1414/*
1415 * Local Variables:
1416 * tab-width: 4
1417 * c-basic-offset: 4
1418 * End:
1419 */