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