WIP commit for 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 "\
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
542/*
543 * Generate the computer move.
544 */
545
546static int
6c3e8b62 547computer_move(Gameinfo* gameinfo, int* passes, int transmit_fifo_fd, int receive_fifo_fd)
de03db18
AT
548{
549 int move;
550 float move_value;
551 int resign;
552 int resignation_declined = 0;
553 float upper_bound, lower_bound;
554
555 init_sgf(gameinfo);
556
557 /* Generate computer move. */
558 if (autolevel_on)
559 adjust_level_offset(gameinfo->to_move);
560 move = genmove(gameinfo->to_move, &move_value, &resign);
561 if (resignation_allowed && resign) {
562 int state = twoplayer_endgame(gameinfo, 2);
563 if (state != -1)
564 return state;
565
566 /* The opponent declined resignation. Remember not to resign again. */
567 resignation_allowed = 0;
568 resignation_declined = 1;
569 }
570
571 if (showscore) {
572 gnugo_estimate_score(&upper_bound, &lower_bound);
573 current_score_estimate = (int)((lower_bound + upper_bound) / 2.0);
574 }
575
576 mprintf("%s(%d): %1m\n", color_to_string(gameinfo->to_move),
577 movenum + 1, move);
578 if (is_pass(move))
579 (*passes)++;
580 else
581 *passes = 0;
582
583 gnugo_play_move(move, gameinfo->to_move);
584 sgffile_add_debuginfo(sgftree.lastnode, move_value);
585 sgftreeAddPlay(&sgftree, gameinfo->to_move, I(move), J(move));
586 if (resignation_declined)
587 sgftreeAddComment(&sgftree, "GNU Go resignation was declined");
588 sgffile_output(&sgftree);
589
590 gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
591 return 0;
592}
593
594/*
595 * Make a move.
596 */
597
598static int
6c3e8b62
AT
599do_move(Gameinfo* gameinfo, char* command, int* passes, int force,
600 int transmit_fifo_fd, int receive_fifo_fd)
de03db18
AT
601{
602 int move = string_to_location(board_size, command);
603
604 if (move == NO_MOVE) {
605 printf("\nInvalid move: %s\n", command);
606 return 0;
607 }
608
609 if (!is_allowed_move(move, gameinfo->to_move)) {
610 printf("\nIllegal move: %s", command);
611 return 0;
612 }
613
614 *passes = 0;
615 TRACE("\nyour move: %1m\n\n", move);
616 init_sgf(gameinfo);
617 gnugo_play_move(move, gameinfo->to_move);
618 sgffile_add_debuginfo(sgftree.lastnode, 0.0);
619 sgftreeAddPlay(&sgftree, gameinfo->to_move, I(move), J(move));
620 sgffile_output(&sgftree);
621
622 if (opt_showboard) {
623 twoplayer_showboard();
624 printf("GNU Go is thinking...\n");
625 }
626
627 if (force) {
628 gameinfo->computer_player = OTHER_COLOR(gameinfo->computer_player);
629 gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
630 sgftreeAddComment(&sgftree, "forced");
631 return 0;
632 }
633
634 gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
6c3e8b62 635 return computer_move(gameinfo, passes, transmit_fifo_fd, receive_fifo_fd);
de03db18
AT
636}
637
638/*
639 * Make a pass.
640 */
641
642static int
6c3e8b62
AT
643do_pass(Gameinfo* gameinfo, int* passes, int force,
644 int transmit_fifo_fd, int receive_fifo_fd)
de03db18
AT
645{
646 (*passes)++;
647 init_sgf(gameinfo);
648 gnugo_play_move(PASS_MOVE, gameinfo->to_move);
649 sgffile_add_debuginfo(sgftree.lastnode, 0.0);
650 sgftreeAddPlay(&sgftree, gameinfo->to_move, -1, -1);
651 sgffile_output(&sgftree);
652
653 gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
654 if (force) {
655 gameinfo->computer_player = OTHER_COLOR(gameinfo->computer_player);
656 sgftreeAddComment(&sgftree, "forced");
657 return 0;
658 }
659
6c3e8b62 660 return computer_move(gameinfo, passes, transmit_fifo_fd, receive_fifo_fd);
de03db18
AT
661}
662
663/*
664 * Play a game using ANSI client.
665 */
666
667void play_twoplayer(SGFTree* tree, Gameinfo* gameinfo, char* filename, char* until)
668{
669 int sz;
670
b0d6e9e5
AT
671 int transmit_fifo_fd, receive_fifo_fd;
672 printf("DEBUG: Attempting to setup connection with other player.\n");
673 if (mknod(MASTER_FIFO_NAME, S_IFIFO | 0666, 0) == 0) {
674 printf("DEBUG: We are the master. Created %s.\n", MASTER_FIFO_NAME);
6c3e8b62 675 gameinfo->computer_player = WHITE; // We are black, so our opponent is white.
b0d6e9e5
AT
676 printf("DEBUG: Waiting for other player to connect.\n");
677 transmit_fifo_fd = open(MASTER_FIFO_NAME, O_WRONLY);
678 printf("DEBUG: Slave connected to our FIFO. Now we connect to the slave's FIFO.\n");
679 receive_fifo_fd = open(SLAVE_FIFO_NAME, O_RDONLY);
680 printf("DEBUG: Bidirectional communication established.\n");
681 } else {
682 printf("DEBUG: Failed to create master FIFO. Perhaps we are the slave?\n");
6c3e8b62 683 gameinfo->computer_player = BLACK; // We are white, so our opponent is black.
b0d6e9e5
AT
684 if (mknod(SLAVE_FIFO_NAME, S_IFIFO | 0666, 0) == 0) {
685 printf("DEBUG: We are the slave. Created %s.\n", SLAVE_FIFO_NAME);
686 receive_fifo_fd = open(MASTER_FIFO_NAME, O_RDONLY);
687 printf("DEBUG: We connected to master's FIFO. Now we wait for master's connection to our FIFO.\n");
688 transmit_fifo_fd = open(SLAVE_FIFO_NAME, O_WRONLY);
689 printf("DEBUG: Bidirectional communication established.\n");
690 } else {
691 printf("DEBUG: Failed to create slave FIFO. This is an unrecoverable error.\n");
692 exit(EXIT_FAILURE);
693 }
694 }
695 // Allow both master and slave to attempt removal. Ignore error code since
696 // this is a best-effort situation for now.
697 unlink(MASTER_FIFO_NAME);
698 unlink(SLAVE_FIFO_NAME);
699while(1){sleep(1);}
700exit(EXIT_SUCCESS);
701
de03db18
AT
702 setvbuf(stdout, (char*)NULL, _IONBF, 0); /* No buffering. */
703
704 sgftree = *tree;
705
706 if (filename) {
707 /* No need to check for failure here since that was already done
708 * when it was loaded in main().
709 *
710 * FIXME: Why do we load the game again?
711 */
712 gameinfo_play_sgftree(gameinfo, &sgftree, until);
713 sgf_initialized = 1;
714 } else {
715 if (sgfGetIntProperty(sgftree.root, "SZ", &sz))
716 gnugo_clear_board(sz);
717 if (gameinfo->handicap == 0)
718 gameinfo->to_move = BLACK;
719 else {
720 gameinfo->handicap = place_fixed_handicap(gameinfo->handicap);
721 gameinfo->to_move = WHITE;
722 }
723 sgf_initialized = 0;
724 }
725
6c3e8b62 726 do_play_twoplayer(gameinfo, transmit_fifo_fd, receive_fifo_fd);
de03db18
AT
727 printf("\nThanks! for playing GNU Go.\n\n");
728
b0d6e9e5
AT
729 close(transmit_fifo_fd);
730 close(receive_fifo_fd);
731
de03db18
AT
732 /* main() frees the tree and we might have changed it. */
733 *tree = sgftree;
734}
735
6c3e8b62 736void do_play_twoplayer(Gameinfo* gameinfo, int transmit_fifo_fd, int receive_fifo_fd)
de03db18 737{
6c3e8b62
AT
738 //int m;
739 int num;
740 //float fnum;
de03db18 741 int passes = 0; /* two passes and its over */
6c3e8b62 742 //int tmp;
de03db18
AT
743 char line[80];
744 char* line_ptr = line;
745 char* command;
746 char* tmpstring;
747 int state = 1;
748
749 if (have_time_settings())
750 clock_on = 1;
751
752 while (state == 1) {
753 state = 0;
754
755 /* No score is estimated yet. */
756 current_score_estimate = NO_SCORE;
757
758 /* Allow resignation at interface level (the engine may still be not
6c3e8b62
AT
759 * allowed to resign.
760 */
de03db18
AT
761 resignation_allowed = 1;
762
763 printf("\nBeginning two player game.\n\n");
764 gameinfo_print(gameinfo);
765
766 /* Does the computer play first? If so, make a move. */
767 if (gameinfo->computer_player == gameinfo->to_move)
6c3e8b62 768 state = computer_move(gameinfo, &passes, transmit_fifo_fd, receive_fifo_fd);
de03db18
AT
769
770 /* main ANSI Play loop */
771 while (state == 0) {
772 /* Display game board. */
773 if (opt_showboard)
774 twoplayer_showboard();
775
776#if !READLINE
777 /* Print the prompt */
778 mprintf("%s(%d): ", color_to_string(gameinfo->to_move), movenum + 1);
779
780 /* Read a line of input. */
781 line_ptr = line;
782 if (!fgets(line, 80, stdin))
783 return;
784#else
785 snprintf(line, 79, "%s(%d): ",
786 color_to_string(gameinfo->to_move), movenum + 1);
787 if (!(line_ptr = readline(line)))
788 return;
789
790 add_history(line_ptr);
791#endif
792
793 while (state == 0
794 && (command = strtok(line_ptr, ";"), line_ptr = 0, command)) {
795 /* Get the command or move. */
796 switch (get_command(command)) {
797 case RESIGN:
798 state = twoplayer_endgame(gameinfo, 1);
799 break;
800
801 case END:
802 case EXIT:
803 case QUIT:
804 return;
805
806 case HELP:
807 show_commands();
808 break;
809
810 case CMD_HELPDEBUG:
811 printf(DEBUG_COMMANDS);
812 break;
813
814 case SHOWBOARD:
815 opt_showboard = !opt_showboard;
816 break;
817
818 case INFO:
819 printf("\n");
820 gameinfo_print(gameinfo);
821 break;
822
823 case SETBOARDSIZE:
6c3e8b62
AT
824 printf("Board size modification prohibited in two player mode.\n");
825 //if (sgf_initialized) {
826 // printf("Boardsize cannot be changed after record is started!\n");
827 // break;
828 //}
829 //command += 10;
830 //if (sscanf(command, "%d", &num) != 1) {
831 // printf("\nInvalid command syntax!\n");
832 // break;
833 //}
834 //if (!check_boardsize(num, stdout))
835 // break;
836 ///* Init board. */
837 //board_size = num;
838 //clear_board();
839 ///* In case max handicap changes on smaller board. */
840 //gameinfo->handicap = place_fixed_handicap(gameinfo->handicap);
841 //sgfOverwritePropertyInt(sgftree.root, "SZ", board_size);
842 //sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
de03db18
AT
843 break;
844
845 case SETHANDICAP:
6c3e8b62
AT
846 printf("Handicap modification prohibited in two player mode.\n");
847 //if (sgf_initialized) {
848 // printf("Handicap cannot be changed after game is started!\n");
849 // break;
850 //}
851 //command += 9;
852 //if (sscanf(command, "%d", &num) != 1) {
853 // printf("\nInvalid command syntax!\n");
854 // break;
855 //}
856 //if (num < 0 || num > MAX_HANDICAP) {
857 // printf("\nInvalid handicap: %d\n", num);
858 // break;
859 //}
860 ///* Init board. */
861 //clear_board();
862 ///* Place stones on board but don't record sgf
863 // * in case we change more info. */
864 //gameinfo->handicap = place_fixed_handicap(num);
865 //printf("\nSet handicap to %d\n", gameinfo->handicap);
866 //gameinfo->to_move = (gameinfo->handicap ? WHITE : BLACK);
de03db18
AT
867 break;
868
869 case FREEHANDICAP:
6c3e8b62
AT
870 printf("Handicap modification prohibited in two player mode.\n");
871 //if (sgf_initialized) {
872 // printf("Handicap cannot be changed after game is started!\n");
873 // break;
874 //}
875 //while (*command && *command != ' ')
876 // command++;
877 //twoplayer_free_handicap(gameinfo, command);
de03db18
AT
878 break;
879
880 case SETKOMI:
6c3e8b62
AT
881 printf("Komi modification prohibited in two player mode.\n");
882 //if (sgf_initialized) {
883 // printf("Komi cannot be modified after game record is started!\n");
884 // break;
885 //}
886 //command += 5;
887 //if (sscanf(command, "%f", &fnum) != 1) {
888 // printf("\nInvalid command syntax!\n");
889 // break;
890 //}
891 //komi = fnum;
892 //printf("\nSet Komi to %.1f\n", komi);
de03db18
AT
893 break;
894
895 case SETDEPTH:
896 command += 6;
897 if (sscanf(command, "%d", &num) != 1) {
898 printf("\nInvalid command syntax!\n");
899 break;
900 }
901 mandated_depth = num;
902 printf("\nSet depth to %d\n", mandated_depth);
903 break;
904
905 case SETLEVEL:
906 command += 6;
907 if (sscanf(command, "%d", &num) != 1) {
908 printf("\nInvalid command syntax!\n");
909 break;
910 }
911 set_level(num);
912 printf("\nSet level to %d\n", num);
913 break;
914
915 case DISPLAY:
916 if (!opt_showboard)
917 twoplayer_showboard();
918 break;
919
920 case FORCE:
6c3e8b62
AT
921 printf("No!\n");
922 //command += 6; /* skip the force part... */
923 //switch (get_command(command)) {
924 //case MOVE:
925 // state = do_move(gameinfo, command, &passes, 1);
926 // break;
927 //case PASS:
928 // state = do_pass(gameinfo, &passes, 1);
929 // break;
930 //default:
931 // printf("Illegal forced move: %s %d\n", command,
932 // get_command(command));
933 // break;
934 //}
de03db18
AT
935 break;
936
937 case MOVE:
6c3e8b62 938 state = do_move(gameinfo, command, &passes, 0, transmit_fifo_fd, receive_fifo_fd);
de03db18
AT
939 break;
940
941 case PASS:
6c3e8b62 942 state = do_pass(gameinfo, &passes, 0, transmit_fifo_fd, receive_fifo_fd);
de03db18
AT
943 break;
944
945 case PLAY:
6c3e8b62
AT
946 printf("Invalid command in two player mode.\n");
947 //command += 5;
948 //if (sscanf(command, "%d", &num) != 1) {
949 // printf("\nInvalid command syntax!\n");
950 // break;
951 //}
952 //if (num >= 0)
953 // for (m = 0; m < num; m++) {
954 // gameinfo->computer_player
955 // = OTHER_COLOR(gameinfo->computer_player);
956 // state = computer_move(gameinfo, &passes);
957 // if (state)
958 // break;
959 // if (passes >= 2)
960 // break;
961 // }
962 //else {
963 // printf("\nInvalid number of moves specified: %d\n", num);
964 // break;
965 //}
de03db18
AT
966 break;
967
968 case PLAYBLACK:
6c3e8b62
AT
969 printf("Invalid command in two player mode.\n");
970 //if (gameinfo->computer_player == WHITE)
971 // gameinfo->computer_player = BLACK;
972 //if (gameinfo->computer_player == gameinfo->to_move)
973 // state = computer_move(gameinfo, &passes);
de03db18
AT
974 break;
975
976 case PLAYWHITE:
6c3e8b62
AT
977 printf("Invalid command in two player mode.\n");
978 //if (gameinfo->computer_player == BLACK)
979 // gameinfo->computer_player = WHITE;
980 //if (gameinfo->computer_player == gameinfo->to_move)
981 // state = computer_move(gameinfo, &passes);
de03db18
AT
982 break;
983
984 case SWITCH:
6c3e8b62
AT
985 printf("Invalid command in two player mode.\n");
986 //gameinfo->computer_player = OTHER_COLOR(gameinfo->computer_player);
987 //state = computer_move(gameinfo, &passes);
de03db18
AT
988 break;
989
990 case UNDO:
991 case CMD_BACK:
6c3e8b62
AT
992 printf("No undo in two player mode.\n");
993 //if (undo_move(1)) {
994 // sgftreeAddComment(&sgftree, "undone");
995 // sgftreeBack(&sgftree);
996 // gameinfo->to_move = OTHER_COLOR(gameinfo->to_move);
997 //} else
998 // printf("\nCan't undo.\n");
de03db18
AT
999 break;
1000
1001 case CMD_FORWARD:
6c3e8b62
AT
1002 printf("Invalid command in two player mode.\n");
1003 //if (sgftreeForward(&sgftree))
1004 // gameinfo->to_move = gnugo_play_sgfnode(sgftree.lastnode,
1005 // gameinfo->to_move);
1006 //else
1007 // printf("\nEnd of game tree.\n");
de03db18
AT
1008 break;
1009
1010 case CMD_LAST:
6c3e8b62
AT
1011 printf("Invalid command in two player mode.\n");
1012 //while (sgftreeForward(&sgftree))
1013 // gameinfo->to_move = gnugo_play_sgfnode(sgftree.lastnode,
1014 // gameinfo->to_move);
de03db18
AT
1015 break;
1016
1017 case COMMENT:
1018 printf("\nEnter comment. Press ENTER when ready.\n");
1019 fgets(line, 80, stdin);
1020 sgftreeAddComment(&sgftree, line);
1021 break;
1022
1023 case SCORE:
1024 showscore = !showscore;
1025 if (!showscore)
1026 current_score_estimate = NO_SCORE;
1027 break;
1028
1029 case CMD_DEAD:
6c3e8b62
AT
1030 printf("Invalid command in two player mode.\n");
1031 //silent_examine_position(FULL_EXAMINE_DRAGONS);
1032 //showdead = !showdead;
de03db18
AT
1033 break;
1034
1035 case CMD_CAPTURE:
6c3e8b62
AT
1036 printf("Invalid command in two player mode.\n");
1037 //strtok(command, " ");
1038 //showcapture(strtok(NULL, " "));
de03db18
AT
1039 break;
1040
1041 case CMD_DEFEND:
6c3e8b62
AT
1042 printf("Invalid command in two player mode.\n");
1043 //strtok(command, " ");
1044 //showdefense(strtok(NULL, " "));
de03db18
AT
1045 break;
1046
1047 case CMD_SHOWMOYO:
6c3e8b62
AT
1048 printf("Invalid command in two player mode.\n");
1049 //tmp = printmoyo;
1050 //printmoyo = PRINTMOYO_MOYO;
1051 //silent_examine_position(EXAMINE_DRAGONS);
1052 //printmoyo = tmp;
de03db18
AT
1053 break;
1054
1055 case CMD_SHOWTERRI:
6c3e8b62
AT
1056 printf("Invalid command in two player mode.\n");
1057 //tmp = printmoyo;
1058 //printmoyo = PRINTMOYO_TERRITORY;
1059 //silent_examine_position(EXAMINE_DRAGONS);
1060 //printmoyo = tmp;
de03db18
AT
1061 break;
1062
1063 case CMD_SHOWAREA:
6c3e8b62
AT
1064 printf("Invalid command in two player mode.\n");
1065 //tmp = printmoyo;
1066 //printmoyo = PRINTMOYO_AREA;
1067 //silent_examine_position(EXAMINE_DRAGONS);
1068 //printmoyo = tmp;
de03db18
AT
1069 break;
1070
1071 case CMD_SHOWDRAGONS:
6c3e8b62
AT
1072 printf("Invalid command in two player mode.\n");
1073 //silent_examine_position(EXAMINE_DRAGONS);
1074 //showboard(1);
de03db18
AT
1075 break;
1076
1077 case CMD_GOTO:
6c3e8b62
AT
1078 printf("Invalid command in two player mode.\n");
1079 //strtok(command, " ");
1080 //twoplayer_goto(gameinfo, strtok(NULL, " "));
de03db18
AT
1081 break;
1082
1083 case CMD_SAVE:
1084 strtok(command, " ");
1085 tmpstring = strtok(NULL, " ");
1086 if (tmpstring) {
1087 /* discard newline */
1088 tmpstring[strlen(tmpstring) - 1] = 0;
1089 /* make sure we are saving proper handicap */
1090 init_sgf(gameinfo);
1091 writesgf(sgftree.root, tmpstring);
6c3e8b62
AT
1092 printf("Game saved at %s for offline use.\n", tmpstring);
1093 //printf("You may resume the game");
1094 //printf(" with -l %s --mode twoplayer\n", tmpstring);
1095 //printf("or load %s\n", tmpstring);
de03db18
AT
1096 } else
1097 printf("Please specify filename\n");
1098 break;
1099
1100 case CMD_LOAD:
6c3e8b62
AT
1101 printf("Invalid command in two player mode.\n");
1102 //strtok(command, " ");
1103 //tmpstring = strtok(NULL, " ");
1104 //if (tmpstring) {
1105 // /* discard newline */
1106 // tmpstring[strlen(tmpstring) - 1] = 0;
1107 // if (!sgftree_readfile(&sgftree, tmpstring)) {
1108 // fprintf(stderr, "Cannot open or parse '%s'\n", tmpstring);
1109 // break;
1110 // }
1111 // /* to avoid changing handicap etc. */
1112 // if (gameinfo_play_sgftree(gameinfo, &sgftree, NULL) == EMPTY)
1113 // fprintf(stderr, "Cannot load '%s'\n", tmpstring);
1114 // else {
1115 // sgf_initialized = 1;
1116 // sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap);
1117 // }
1118 //} else
1119 // printf("Please specify a filename\n");
de03db18
AT
1120 break;
1121
1122 case CMD_LISTDRAGONS:
6c3e8b62
AT
1123 printf("Invalid command in two player mode.\n");
1124 //silent_examine_position(EXAMINE_DRAGONS);
1125 //show_dragons();
de03db18
AT
1126 break;
1127
1128 default:
1129 printf("\nInvalid command: %s", command);
1130 break;
1131 }
1132
1133 if (passes >= 2)
1134 state = twoplayer_endgame(gameinfo, 0);
1135 }
1136#if READLINE
1137 free(line_ptr);
1138#endif
1139 }
1140
1141 sgffile_output(&sgftree);
1142 passes = 0;
1143
1144 /* Play a different game next time. */
1145 update_random_seed();
1146
1147 /* Free the sgf tree and prepare for a new game. */
1148 sgfFreeNode(sgftree.root);
1149 sgftree_clear(&sgftree);
1150 sgftreeCreateHeaderNode(&sgftree, board_size, komi, gameinfo->handicap);
1151 sgf_initialized = 0;
1152
1153 gameinfo_clear(gameinfo);
1154 }
1155}
1156
1157/* Communicates with user after a game has ended. */
1158static int
1159twoplayer_endgame(Gameinfo* gameinfo, int reason)
1160{
1161 char line[80];
1162 char* line_ptr;
1163 char* command;
1164 char* tmpstring;
1165 int state = 0;
1166
1167 if (reason == 0) { /* Two passes, game is over. */
1168 who_wins(gameinfo->computer_player, stdout);
1169 printf("\nIf you disagree, we may count the game together.\n");
1170
1171 sgftreeWriteResult(&sgftree, (white_score + black_score) / 2.0, 1);
1172 } else {
1173 int color = OTHER_COLOR(gameinfo->to_move);
1174
1175 if (reason == 1) /* Our opponent has resigned. */
1176 printf("GNU Go wins by resignation.\n");
1177 else /* We have resigned. */
1178 printf("You win by resignation.\n");
1179
1180 printf("Result: %c+Resign\n\n", color == WHITE ? 'W' : 'B');
1181 sgftreeWriteResult(&sgftree, color == WHITE ? 1000.0 : -1000.0, 1);
1182 }
1183
1184 while (state == 0) {
1185 printf("You may optionally save the game as an SGF file.\n\n");
1186 printf("Type \"save <filename>\" to save,\n");
1187 if (reason == 0)
1188 printf(" \"count\" to recount,\n");
1189 else if (reason == 2)
1190 printf(" \"continue\" to decline resignation and continue the game,\n");
1191 printf(" \"quit\" to quit\n");
1192 printf(" or \"game\" to play again\n");
1193
1194 line_ptr = line;
1195 if (!fgets(line, 80, stdin))
1196 break;
1197
1198 command = strtok(line_ptr, "");
1199 switch (get_command(command)) {
1200 case CMD_SAVE:
1201 strtok(command, " ");
1202 tmpstring = strtok(NULL, " ");
1203 if (tmpstring) {
1204 /* discard newline */
1205 tmpstring[strlen(tmpstring) - 1] = 0;
1206 init_sgf(gameinfo);
1207 writesgf(sgftree.root, tmpstring);
1208 } else
1209 printf("Please specify filename\n");
1210 break;
1211
1212 case COUNT:
1213 if (reason == 0)
1214 twoplayer_count(gameinfo);
1215 break;
1216
1217 case CONTINUE:
1218 state = -1;
1219 break;
1220
1221 case NEW:
1222 state = 1;
1223 break;
1224
1225 case QUIT:
1226 state = 2;
1227 break;
1228
1229 default:
1230 state = 0;
1231 }
1232 }
1233
1234 return state;
1235}
1236
1237/* twoplayer_count() scores the game.
1238 */
1239static void
1240twoplayer_count(Gameinfo* gameinfo)
1241{
1242 char line[12];
1243 int done = 0;
1244 int i;
1245 int xyzzy = 1;
1246
1247 printf("\nGame over. Let's count!.\n");
1248 showdead = 1;
1249 twoplayer_showboard();
1250 while (!done) {
1251 printf("Dead stones are marked with small letters (x,o).\n");
1252 printf("\nIf you don't agree, enter the location of a group\n");
1253 printf("to toggle its state or \"done\".\n");
1254
1255 if (!fgets(line, 12, stdin))
1256 return; /* EOF or some error */
1257
1258 for (i = 0; i < 12; i++)
1259 line[i] = tolower((int)line[i]);
1260 if (!strncmp(line, "done", 4))
1261 done = 1;
1262 else if (!strncmp(line, "quit", 4))
1263 return;
1264 else if (!strncmp(line, "xyzzy", 5)) {
1265 if (xyzzy) {
1266 printf("\nYou are in a debris room filled with stuff washed in from the\n");
1267 printf("surface. A low wide passage with cobbles becomes plugged\n");
1268 printf("with mud and debris here, but an awkward canyon leads\n");
1269 printf("upward and west. A note on the wall says:\n");
1270 printf(" Magic Word \"XYZZY\"\n\n");
1271 xyzzy = 0;
1272 } else {
1273 printf("You are inside a building, a well house for a large spring.\n\n");
1274 xyzzy = 1;
1275 }
1276 } else if (!strncmp(line, "help", 4)) {
1277 printf("\nIf there are dead stones on the board I will remove them.\n");
1278 printf("You must tell me where they are. Type the coordinates of a\n");
1279 printf("dead group, or type \"done\"\n");
1280 } else if (!strncmp(line, "undo", 4)) {
1281 printf("UNDO not allowed anymore. The status of the stones now\n");
1282 printf("toggles after entering the location of it.\n");
1283 twoplayer_showboard();
1284 } else {
1285 int pos = string_to_location(board_size, line);
1286 if (pos == NO_MOVE || board[pos] == EMPTY)
1287 printf("\ninvalid!\n");
1288 else {
1289 enum dragon_status status = dragon_status(pos);
1290 status = (status == DEAD) ? ALIVE : DEAD;
1291 change_dragon_status(pos, status);
1292 twoplayer_showboard();
1293 }
1294 }
1295 }
1296 who_wins(gameinfo->computer_player, stdout);
1297}
1298
6c3e8b62
AT
1299//static void
1300//showcapture(char* line)
1301//{
1302// int str;
1303// int move;
1304//
1305// gg_assert(line);
1306// str = string_to_location(board_size, line);
1307// if (str == NO_MOVE || board[str] == EMPTY) {
1308// printf("\ninvalid point!\n");
1309// return;
1310// }
1311//
1312// if (attack(str, &move))
1313// mprintf("\nSuccessful attack of %1m at %1m\n", str, move);
1314// else
1315// mprintf("\n%1m cannot be attacked\n", str);
1316//}
1317
1318//static void
1319//showdefense(char* line)
1320//{
1321// int str;
1322// int move;
1323//
1324// gg_assert(line);
1325// str = string_to_location(board_size, line);
1326// if (str == NO_MOVE || board[str] == EMPTY) {
1327// printf("\ninvalid point!\n");
1328// return;
1329// }
1330//
1331// if (attack(str, NULL)) {
1332// if (find_defense(str, &move))
1333// mprintf("\nSuccessful defense of %1m at %1m\n", str, move);
1334// else
1335// mprintf("\n%1m cannot be defended\n", str);
1336// } else
1337// mprintf("\nThere is no need to defend %1m\n", str);
1338//}
1339
1340//static void
1341//twoplayer_goto(Gameinfo* gameinfo, char* line)
1342//{
1343// const char* movenumber = line;
1344//
1345// if (!line)
1346// return;
1347//
1348// if (!strncmp(line, "last", 4))
1349// movenumber = "9999";
1350// else if (!strncmp(line, "first", 4))
1351// movenumber = "1";
1352//
1353// printf("goto %s\n", movenumber);
1354// gameinfo_play_sgftree(gameinfo, &sgftree, movenumber);
1355//}
1356
1357//static void
1358//twoplayer_free_handicap(Gameinfo* gameinfo, char* handicap_string)
1359//{
1360// int handi;
1361// int i;
1362// char line[80];
1363// int stones[MAX_BOARD * MAX_BOARD];
1364//
1365// if (sscanf(handicap_string, "%d", &handi) == 1) {
1366// /* GNU Go is to place handicap */
1367// if (handi < 0 || handi == 1) {
1368// printf("\nInvalid command syntax!\n");
1369// return;
1370// }
1371//
1372// clear_board();
1373// handi = place_free_handicap(handi);
1374// printf("\nPlaced %d stones of free handicap.\n", handi);
1375// } else { /* User is to place handicap */
1376// clear_board();
1377// handi = 0;
1378//
1379// while (1) {
1380// twoplayer_showboard();
1381// printf("\nType in coordinates of next handicap stone, or one of the following commands:\n");
1382// printf(" undo take back the last stone placed\n");
1383// printf(" clear remove all the stones placed so far\n");
1384// printf(" done finish placing handicap\n\n");
1385// printf("You have placed %d handicap stone(s) so far.\n\n", handi);
1386//
1387// if (!fgets(line, 80, stdin))
1388// return; /* EOF or some error */
1389// for (i = 0; i < 80; i++)
1390// line[i] = tolower((int)line[i]);
1391//
1392// if (!strncmp(line, "undo", 4)) {
1393// if (!handi)
1394// printf("\nNothing to undo.\n");
1395// else {
1396// remove_stone(stones[--handi]);
1397// gprintf("\nRemoved the stone at %m.\n", I(stones[handi]),
1398// J(stones[handi]));
1399// }
1400// } else if (!strncmp(line, "clear", 5)) {
1401// clear_board();
1402// handi = 0;
1403// } else if (!strncmp(line, "done", 4)) {
1404// if (handi == 1) /* Don't bother with checks later */
1405// printf("\nHandicap cannot be one stone. Either add "
1406// "some more, or delete the only stone.\n");
1407// else
1408// break;
1409// } else {
1410// int pos = string_to_location(board_size, line);
1411// if (pos != NO_MOVE) {
1412// if (board[pos] != EMPTY)
1413// printf("\nThere's already a stone there.\n");
1414// else {
1415// add_stone(pos, BLACK);
1416// stones[handi++] = pos;
1417// }
1418// } else
1419// printf("\nInvalid command: %s", line);
1420// }
1421// }
1422// }
1423// gameinfo->handicap = handi;
1424// gameinfo->to_move = (handi ? WHITE : BLACK);
1425//}
de03db18
AT
1426
1427/*
1428 * Local Variables:
1429 * tab-width: 4
1430 * c-basic-offset: 4
1431 * End:
1432 */