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