Commit | Line | Data |
---|---|---|
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 | #include "liberty.h" | |
26 | ||
c150f57c | 27 | #include <assert.h> |
7eeb782e AT |
28 | #include <stdio.h> |
29 | #include <stdlib.h> | |
7eeb782e | 30 | |
c150f57c | 31 | #include "gg_utils.h" |
7eeb782e | 32 | #include "gmp.h" |
c150f57c | 33 | #include "interface.h" |
7eeb782e | 34 | #include "sgftree.h" |
7eeb782e AT |
35 | |
36 | /* --------------------------------------------------------------*/ | |
37 | /* Play a game against a go-modem-protocol (GMP) client. */ | |
38 | /* --------------------------------------------------------------*/ | |
c150f57c | 39 | void play_gmp(Gameinfo* gameinfo, int simplified) |
7eeb782e | 40 | { |
c150f57c AT |
41 | SGFTree sgftree; |
42 | ||
43 | Gmp* ge; | |
44 | GmpResult message; | |
45 | const char* error; | |
7eeb782e | 46 | |
c150f57c AT |
47 | int i, j; |
48 | int passes = 0; /* two passes and its over */ | |
49 | int to_move; /* who's turn is next ? */ | |
7eeb782e | 50 | |
c150f57c AT |
51 | int mycolor = -1; /* who has which color */ |
52 | int yourcolor; | |
7eeb782e | 53 | |
c150f57c AT |
54 | if (gameinfo->computer_player == WHITE) |
55 | mycolor = 1; | |
56 | else if (gameinfo->computer_player == BLACK) | |
57 | mycolor = 0; | |
7eeb782e | 58 | |
c150f57c AT |
59 | sgftree_clear(&sgftree); |
60 | sgftreeCreateHeaderNode(&sgftree, board_size, komi, gameinfo->handicap); | |
7eeb782e | 61 | |
c150f57c AT |
62 | ge = gmp_create(0, 1); |
63 | TRACE("board size=%d\n", board_size); | |
7eeb782e | 64 | |
c150f57c | 65 | /* |
7eeb782e AT |
66 | * The specification of the go modem protocol doesn't even discuss |
67 | * komi. So we have to guess the komi. If the komi is set on the | |
68 | * command line, keep it. Otherwise, its value will be 0.0 and we | |
69 | * use 5.5 in an even game, 0.5 otherwise. | |
70 | */ | |
c150f57c AT |
71 | if (komi == 0.0) { |
72 | if (gameinfo->handicap == 0) | |
73 | komi = 5.5; | |
74 | else | |
75 | komi = 0.5; | |
76 | } | |
7eeb782e | 77 | |
c150f57c AT |
78 | if (!simplified) { |
79 | /* Leave all the -1's so the client can negotiate the game parameters. */ | |
80 | if (chinese_rules) | |
81 | gmp_startGame(ge, -1, -1, 5.5, -1, mycolor, 0); | |
82 | else | |
83 | gmp_startGame(ge, -1, -1, 5.5, 0, mycolor, 0); | |
84 | } else { | |
85 | gmp_startGame(ge, board_size, gameinfo->handicap, | |
86 | komi, chinese_rules, mycolor, 1); | |
87 | } | |
88 | ||
89 | do { | |
90 | message = gmp_check(ge, 1, NULL, NULL, &error); | |
91 | } while (message == gmp_nothing || message == gmp_reset); | |
92 | ||
93 | if (message == gmp_err) { | |
94 | fprintf(stderr, "gnugo-gmp: Error \"%s\" occurred.\n", error); | |
95 | exit(EXIT_FAILURE); | |
96 | } else if (message != gmp_newGame) { | |
97 | fprintf(stderr, "gnugo-gmp: Expecting a newGame, got %s\n", | |
98 | gmp_resultString(message)); | |
99 | exit(EXIT_FAILURE); | |
100 | } | |
101 | ||
102 | gameinfo->handicap = gmp_handicap(ge); | |
103 | if (!check_boardsize(gmp_size(ge), stderr)) | |
104 | exit(EXIT_FAILURE); | |
105 | ||
106 | gnugo_clear_board(gmp_size(ge)); | |
107 | ||
108 | /* Let's pretend GMP knows about komi in case something will ever change. */ | |
109 | komi = gmp_komi(ge); | |
7eeb782e AT |
110 | |
111 | #if ORACLE | |
c150f57c AT |
112 | if (metamachine && oracle_exists) |
113 | oracle_clear_board(board_size); | |
7eeb782e AT |
114 | #endif |
115 | ||
c150f57c AT |
116 | sgfOverwritePropertyInt(sgftree.root, "SZ", board_size); |
117 | ||
118 | TRACE("size=%d, handicap=%d, komi=%f\n", board_size, | |
119 | gameinfo->handicap, komi); | |
7eeb782e | 120 | |
c150f57c AT |
121 | if (gameinfo->handicap) |
122 | to_move = WHITE; | |
123 | else | |
124 | to_move = BLACK; | |
125 | ||
126 | if (gmp_iAmWhite(ge)) { | |
127 | mycolor = WHITE; /* computer white */ | |
128 | yourcolor = BLACK; /* human black */ | |
129 | } else { | |
130 | mycolor = BLACK; | |
131 | yourcolor = WHITE; | |
7eeb782e | 132 | } |
c150f57c AT |
133 | |
134 | gameinfo->computer_player = mycolor; | |
135 | sgf_write_header(sgftree.root, 1, get_random_seed(), komi, | |
136 | gameinfo->handicap, get_level(), chinese_rules); | |
137 | gameinfo->handicap = gnugo_sethand(gameinfo->handicap, sgftree.root); | |
138 | sgfOverwritePropertyInt(sgftree.root, "HA", gameinfo->handicap); | |
139 | ||
140 | /* main GMP loop */ | |
141 | while (passes < 2) { | |
142 | ||
143 | if (to_move == yourcolor) { | |
144 | int move; | |
145 | /* Get opponent's move from gmp client. */ | |
146 | message = gmp_check(ge, 1, &j, &i, &error); | |
147 | ||
148 | if (message == gmp_err) { | |
149 | fprintf(stderr, "GNU Go: Sorry, error from gmp client\n"); | |
150 | sgftreeAddComment(&sgftree, "got error from gmp client"); | |
151 | sgffile_output(&sgftree); | |
152 | return; | |
153 | } | |
154 | ||
155 | if (message == gmp_undo) { | |
156 | int k; | |
157 | assert(j > 0); | |
158 | ||
159 | for (k = 0; k < j; k++) { | |
160 | if (!undo_move(1)) { | |
161 | fprintf(stderr, "GNU Go: play_gmp UNDO: can't undo %d moves\n", | |
162 | j - k); | |
163 | break; | |
164 | } | |
165 | sgftreeAddComment(&sgftree, "undone"); | |
166 | sgftreeBack(&sgftree); | |
167 | to_move = OTHER_COLOR(to_move); | |
168 | } | |
169 | continue; | |
170 | } | |
171 | ||
172 | if (message == gmp_pass) { | |
173 | passes++; | |
174 | move = PASS_MOVE; | |
175 | } else { | |
176 | passes = 0; | |
177 | move = POS(i, j); | |
178 | } | |
179 | ||
180 | TRACE("\nyour move: %1m\n\n", move); | |
181 | sgftreeAddPlay(&sgftree, to_move, I(move), J(move)); | |
182 | gnugo_play_move(move, yourcolor); | |
183 | sgffile_output(&sgftree); | |
184 | ||
185 | } else { | |
186 | /* Generate my next move. */ | |
187 | float move_value; | |
188 | int move; | |
189 | if (autolevel_on) | |
190 | adjust_level_offset(mycolor); | |
191 | move = genmove(mycolor, &move_value, NULL); | |
192 | gnugo_play_move(move, mycolor); | |
193 | sgffile_add_debuginfo(sgftree.lastnode, move_value); | |
194 | ||
195 | if (is_pass(move)) { | |
196 | /* pass */ | |
197 | sgftreeAddPlay(&sgftree, to_move, -1, -1); | |
198 | gmp_sendPass(ge); | |
199 | ++passes; | |
200 | } else { | |
201 | /* not pass */ | |
202 | sgftreeAddPlay(&sgftree, to_move, I(move), J(move)); | |
203 | gmp_sendMove(ge, J(move), I(move)); | |
204 | passes = 0; | |
205 | TRACE("\nmy move: %1m\n\n", move); | |
206 | } | |
207 | sgffile_add_debuginfo(sgftree.lastnode, 0.0); | |
208 | sgffile_output(&sgftree); | |
209 | } | |
210 | ||
211 | to_move = OTHER_COLOR(to_move); | |
7eeb782e | 212 | } |
c150f57c AT |
213 | |
214 | /* two passes: game over */ | |
215 | gmp_sendPass(ge); | |
216 | ||
217 | if (!quiet) | |
218 | fprintf(stderr, "Game over - waiting for client to shut us down\n"); | |
219 | who_wins(mycolor, stderr); | |
220 | ||
221 | if (showtime) { | |
222 | gprintf("\nSLOWEST MOVE: %d at %1m ", slowest_movenum, slowest_move); | |
223 | fprintf(stderr, "(%.2f seconds)\n", slowest_time); | |
224 | fprintf(stderr, "\nAVERAGE TIME: %.2f seconds per move\n", | |
225 | total_time / movenum); | |
226 | fprintf(stderr, "\nTOTAL TIME: %.2f seconds\n", | |
227 | total_time); | |
228 | } | |
229 | ||
230 | /* play_gmp() does not return to main(), therefore the score | |
7eeb782e AT |
231 | * writing code is here. |
232 | */ | |
c150f57c AT |
233 | { |
234 | float score = gnugo_estimate_score(NULL, NULL); | |
235 | sgfWriteResult(sgftree.root, score, 1); | |
236 | } | |
237 | sgffile_output(&sgftree); | |
238 | ||
239 | if (!simplified) { | |
240 | /* We hang around here until cgoban asks us to go, since | |
7eeb782e AT |
241 | * sometimes cgoban crashes if we exit first. |
242 | * | |
243 | * FIXME: Check if this is still needed. I made it dependand on | |
244 | * `simplifed' just to avoid changes in GMP mode. | |
245 | */ | |
c150f57c AT |
246 | while (1) { |
247 | message = gmp_check(ge, 1, &j, &i, &error); | |
248 | if (!quiet) | |
249 | fprintf(stderr, "Message %d from gmp\n", message); | |
250 | if (message == gmp_err) | |
251 | break; | |
252 | } | |
7eeb782e | 253 | } |
7eeb782e AT |
254 | |
255 | #if ORACLE | |
c150f57c AT |
256 | if (metamachine && oracle_exists) |
257 | dismiss_oracle(); | |
7eeb782e AT |
258 | #endif |
259 | ||
c150f57c AT |
260 | if (!quiet) |
261 | fprintf(stderr, "gnugo going down\n"); | |
7eeb782e AT |
262 | } |
263 | ||
264 | /* | |
265 | * Local Variables: | |
c150f57c AT |
266 | * tab-width: 4 |
267 | * c-basic-offset: 4 | |
7eeb782e AT |
268 | * End: |
269 | */ |