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