source: roaraudio/plugins/universal/tic-tac-toe.c @ 5461:3726177a7bae

Last change on this file since 5461:3726177a7bae was 5461:3726177a7bae, checked in by phi, 12 years ago

Bring Telnet in right mode.

File size: 8.2 KB
Line 
1//tic-tac-toe.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2012
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include <roard/include/roard.h>
27
28#define _FREE     ' '
29#define _PLAYER   'X'
30#define _COMPUTER 'O'
31#define _NOBODY   '#'
32
33#define _DISPLAY \
34/* Bring Telnet in right mode: */ \
35/* IAC WILL ECHO IAC WILL SUPPRESS_GO_AHEAD IAC WONT LINEMODE */ \
36/* 255  251    1 255  251                 3 255  252       34 */ \
37"\377\373\001\377\373\003\377\374\042" \
38"\e[2J\e[H" \
39" Tic Tac Toe\r\n" \
40" (running: roard " ROAR_VERSION_STRING ")\r\n" \
41"\r\n" \
42"Game board:     IDs:\r\n"        \
43" %c | %c | %c      7 | 8 | 9\r\n"   \
44"---+---+---     ---+---+---\r\n" \
45" %c | %c | %c      4 | 5 | 6\r\n"   \
46"---+---+---     ---+---+---\r\n" \
47" %c | %c | %c      1 | 2 | 3\r\n"   \
48"\r\n" \
49"%s\r\n"
50#define _DISPLAY_BUFFER_LEN 1024
51
52#define MSG__YOUR_TURN       "It's your turn. -- press any ID or q to quit --"
53#define MSG__CANNOT_PUT_HERE "You can not put your mark here. -- try again another position --"
54#define MSG__WON_PLAYER      "You won. -- press any key to continue or q to quit --"
55#define MSG__WON_COMPUTER    "I won. -- press any key to continue or q to quit --"
56#define MSG__WON_NOBODY      "Nobody won. -- press any key to continue or q to quit --"
57
58typedef char game_state[9];
59
60struct test_result {
61 int score_player, score_computer;
62 int free;
63};
64
65struct stats {
66 int free;
67 struct test_result results[9];
68};
69
70static void new_game(game_state * state) {
71 memset(state, _FREE, sizeof(game_state));
72}
73
74static int try_put(game_state * state, int id, char player) {
75 if ( id < 0 || id > 8 )
76  return -1;
77
78 if ( (*state)[id] == _FREE ) {
79  (*state)[id] = player;
80  return 0;
81 } else {
82  return -1;
83 }
84};
85
86static void analyze(struct stats * stats, game_state * state) {
87 static const int textvec[3][3][2] = {
88  {{0, 3}, {1, 3}, {2,  3}},
89  {{0, 1}, {3, 1}, {6,  1}},
90  {{0, 1}, {4, 0}, {8, -1}}
91 };
92 struct test_result * res;
93 int i, j;
94 int test;
95
96 stats->free = 0;
97
98 for (i = 0; i < 9; i++)
99  if ( (*state)[i] == _FREE )
100   stats->free++;
101
102 for (test = 0; test < 3; test++) {
103  for (i = 0; i < 3; i++) {
104   res = &(stats->results[i+test*3]);
105   res->score_player = 0;
106   res->score_computer = 0;
107   res->free = -1;
108   for (j = 0; j < 3; j++) {
109    switch ((*state)[textvec[test][j][0] + textvec[test][j][1]*i]) {
110     case _PLAYER: res->score_player++; break;
111     case _COMPUTER: res->score_computer++; break;
112     case _FREE: res->free = textvec[test][j][0] + textvec[test][j][1]*i; break;
113    }
114   }
115  }
116 }
117}
118
119static char check_won(game_state * state) {
120 struct stats stats;
121 int i;
122
123 analyze(&stats, state);
124
125 for (i = 0; i < 9; i++) {
126  if ( stats.results[i].score_player == 3 )
127   return _PLAYER;
128  if ( stats.results[i].score_computer == 3 )
129   return _COMPUTER;
130 }
131
132 if ( stats.free == 0)
133  return _NOBODY;
134
135 return 0;
136}
137
138static void auto_move(game_state * state, int player_move) {
139 static const int corner[4] = {0, 2, 6, 8};
140 static const int side[4]   = {1, 3, 5, 7};
141 struct stats stats;
142 struct test_result * res;
143 int i;
144
145 analyze(&stats, state);
146
147 // step 0: try to win.
148 for (i = 0; i < 9; i++) {
149  res = &(stats.results[i]);
150  if ( res->score_computer == 2 && res->free != -1 ) {
151   if ( try_put(state, res->free, _COMPUTER) == 0 )
152    return;
153  }
154 }
155
156 // step 1: block winning
157 for (i = 0; i < 9; i++) {
158  res = &(stats.results[i]);
159  if ( res->score_player == 2 && res->free != -1 ) {
160   if ( try_put(state, res->free, _COMPUTER) == 0 )
161    return;
162  }
163 }
164
165 // step 2: fork
166 // TODO: implement
167
168 // step 3: block forking
169 // TODO: implement
170
171 // step 4: play center
172 if ( try_put(state, 4, _COMPUTER) == 0 )
173  return;
174
175 // step 5: "Opposite corner"
176 for (i = 0; i < 4; i++)
177  if ( player_move == corner[i] )
178   if ( try_put(state, 8 - player_move, _COMPUTER) == 0 )
179    return;
180
181 // step 6: Empty corner
182 for (i = 0; i < 4; i++)
183  if ( try_put(state, corner[i], _COMPUTER) == 0 )
184   return;
185
186 // step 7: Empty side
187 for (i = 0; i < 4; i++)
188  if ( try_put(state, side[i], _COMPUTER) == 0 )
189   return;
190}
191
192static void draw_game(int client, game_state * state, const char * info) {
193 struct roar_buffer * buf;
194 ssize_t len = 0;
195 void * data;
196
197 if ( roar_buffer_new_data(&buf, _DISPLAY_BUFFER_LEN, &data) == -1 )
198  return;
199
200 snprintf(data, _DISPLAY_BUFFER_LEN, _DISPLAY,
201          (*state)[0], (*state)[1], (*state)[2],
202          (*state)[3], (*state)[4], (*state)[5],
203          (*state)[6], (*state)[7], (*state)[8],
204          info);
205
206 len = roar_mm_strlen(data);
207
208 if ( roar_buffer_set_len(buf, len) == -1 ) {
209  roar_buffer_free(buf);
210  clients_delete(client);
211 }
212
213 clients_add_output(client, &buf);
214}
215
216int new_client(int client, struct roar_vio_calls * vio, struct roard_listen * lsock) {
217 struct roar_client_server * cs;
218 game_state * state;
219
220 (void)vio, (void)lsock;
221
222 if ( clients_get_server(client, &cs) == -1 )
223  return -1;
224
225 state = roar_mm_malloc(sizeof(game_state));
226 if ( state == NULL )
227  return -1;
228
229 new_game(state);
230
231 cs->protoinst = state;
232
233 draw_game(client, state, MSG__YOUR_TURN);
234 return 0;
235}
236
237static char input2id(char c) {
238 if ( c > '9' )
239  return c;
240 if ( c >= '7' )
241  return c - 7;
242 if ( c >= '4' )
243  return c - 1;
244 if ( c >= '1' )
245  return c + 5;
246 return c;
247}
248
249static int check_client(int client, struct roar_vio_calls * vio) {
250 struct roar_client_server * cs;
251 char buf[32];
252 ssize_t len;
253 ssize_t i;
254 const char * msg = MSG__YOUR_TURN;
255 char won;
256 int player_move = -1;
257 char c;
258
259 ROAR_DBG("check_client(client=%i, vio=%p) = ?", client, vio);
260
261 if ( clients_get_server(client, &cs) == -1 )
262  return -1;
263
264 len = roar_vio_read(vio, buf, sizeof(buf));
265
266 if ( len < 1 ) {
267  clients_delete(client);
268  return -1;
269 }
270
271 if ( check_won(cs->protoinst) ) {
272  for (i = 0; i < len; i++) {
273   if ( buf[i] == 'q' ) {
274    clients_delete(client);
275    return -1;
276   } else {
277    new_game(cs->protoinst);
278    draw_game(client, cs->protoinst, MSG__YOUR_TURN);
279    return 0;
280   }
281  }
282 }
283
284 for (i = 0; i < len; i++) {
285  c = input2id(buf[i]);
286  switch (c) {
287   case 'q':
288     clients_delete(client);
289     return -1;
290    break;
291   case '0': case '1': case '2': case '3': case '4':
292   case '5': case '6': case '7': case '8':
293     if ( try_put(cs->protoinst, c - '0', _PLAYER) == -1 ) {
294      msg = MSG__CANNOT_PUT_HERE;
295      draw_game(client, cs->protoinst, msg);
296      return 0;
297     } else {
298      msg = MSG__YOUR_TURN;
299      i = len; // end the loop.
300      player_move = c - '0';
301     }
302    break;
303  }
304 }
305
306 won = check_won(cs->protoinst);
307
308 if ( !won && player_move != -1 ) {
309  auto_move(cs->protoinst, player_move);
310  won = check_won(cs->protoinst);
311 }
312
313 switch (won) {
314  case _PLAYER: msg = MSG__WON_PLAYER; break;
315  case _COMPUTER: msg = MSG__WON_COMPUTER; break;
316  case _NOBODY: msg = MSG__WON_NOBODY; break;
317 }
318
319 draw_game(client, cs->protoinst, msg);
320
321 ROAR_DBG("check_client(client=%i, vio=%p) = 0", client, vio);
322 return 0;
323}
324
325
326static struct roard_proto proto[1] = {
327 {ROAR_PROTO_GAME, ROAR_SUBSYS_NONE, "Simple Tic-Tac-Toe game", NULL, new_client, NULL, check_client, NULL, NULL}
328};
329
330ROARD_DL_REG_PROTO(proto)
331
332ROAR_DL_PLUGIN_START(protocol_tic_tac_toe) {
333 ROARD_DL_CHECK_VERSIONS();
334
335 ROAR_DL_PLUGIN_META_PRODUCT_NIV("protocol-tic-tac-toe", ROAR_VID_ROARAUDIO, ROAR_VNAME_ROARAUDIO);
336 ROAR_DL_PLUGIN_META_VERSION(ROAR_VERSION_STRING);
337 ROAR_DL_PLUGIN_META_LICENSE_TAG(GPLv3_0);
338 ROAR_DL_PLUGIN_META_CONTACT_FLNE("Philipp", "Schafft", "ph3-der-loewe", "lion@lion.leolix.org");
339 ROAR_DL_PLUGIN_META_DESC("Implementation of a the well known game Tic-Tac-Toe");
340
341 ROARD_DL_REGFN_PROTO();
342} ROAR_DL_PLUGIN_END
343
344//ll
Note: See TracBrowser for help on using the repository browser.