source: roaraudio/plugins/universal/tic-tac-toe.c @ 5449:c4827557d495

Last change on this file since 5449:c4827557d495 was 5449:c4827557d495, checked in by phi, 12 years ago

implemented tic-tac-toe as roard proto plugin.

File size: 7.7 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"\e[2J\e[H" \
35"Game board:     IDs:\n"        \
36" %c | %c | %c      0 | 1 | 2\n"   \
37"---+---+---     ---+---+---\n" \
38" %c | %c | %c      3 | 4 | 5\n"   \
39"---+---+---     ---+---+---\n" \
40" %c | %c | %c      6 | 7 | 8\n"   \
41"\n" \
42"%s\n"
43#define _DISPLAY_BUFFER_LEN 1024
44
45#define MSG__YOUR_TURN       "It's your turn. -- press any ID or q to quit --"
46#define MSG__CANNOT_PUT_HERE "You can not put your mark here. -- try again another position --"
47#define MSG__WON_PLAYER      "You won. -- press any key to continue or q to quit --"
48#define MSG__WON_COMPUTER    "I won. -- press any key to continue or q to quit --"
49#define MSG__WON_NOBODY      "Nobody won. -- press any key to continue or q to quit --"
50
51typedef char game_state[9];
52
53struct test_result {
54 int score_player, score_computer;
55 int free;
56};
57
58struct stats {
59 int free;
60 struct test_result results[9];
61};
62
63static void new_game(game_state * state) {
64 memset(state, _FREE, sizeof(game_state));
65}
66
67static int try_put(game_state * state, int id, char player) {
68 if ( id < 0 || id > 8 )
69  return -1;
70
71 if ( (*state)[id] == _FREE ) {
72  (*state)[id] = player;
73  return 0;
74 } else {
75  return -1;
76 }
77};
78
79static void analyze(struct stats * stats, game_state * state) {
80 static const int textvec[3][3][2] = {
81  {{0, 3}, {1, 3}, {2,  3}},
82  {{0, 1}, {3, 1}, {6,  1}},
83  {{0, 1}, {4, 0}, {8, -1}}
84 };
85 struct test_result * res;
86 int i, j;
87 int test;
88
89 stats->free = 0;
90
91 for (i = 0; i < 9; i++)
92  if ( (*state)[i] == _FREE )
93   stats->free++;
94
95 for (test = 0; test < 3; test++) {
96  for (i = 0; i < 3; i++) {
97   res = &(stats->results[i+test*3]);
98   res->score_player = 0;
99   res->score_computer = 0;
100   res->free = -1;
101   for (j = 0; j < 3; j++) {
102    switch ((*state)[textvec[test][j][0] + textvec[test][j][1]*i]) {
103     case _PLAYER: res->score_player++; break;
104     case _COMPUTER: res->score_computer++; break;
105     case _FREE: res->free = textvec[test][j][0] + textvec[test][j][1]*i; break;
106    }
107   }
108  }
109 }
110}
111
112static char check_won(game_state * state) {
113 struct stats stats;
114 int i;
115
116 analyze(&stats, state);
117
118 for (i = 0; i < 9; i++) {
119  if ( stats.results[i].score_player == 3 )
120   return _PLAYER;
121  if ( stats.results[i].score_computer == 3 )
122   return _COMPUTER;
123 }
124
125 if ( stats.free == 0)
126  return _NOBODY;
127
128 return 0;
129}
130
131static void auto_move(game_state * state, int player_move) {
132 static const int corner[4] = {0, 2, 6, 8};
133 static const int side[4]   = {1, 3, 5, 7};
134 struct stats stats;
135 struct test_result * res;
136 int i;
137
138 analyze(&stats, state);
139
140 // step 0: try to win.
141 for (i = 0; i < 9; i++) {
142  res = &(stats.results[i]);
143  if ( res->score_computer == 2 && res->free != -1 ) {
144   if ( try_put(state, res->free, _COMPUTER) == 0 )
145    return;
146  }
147 }
148
149 // step 1: block winning
150 for (i = 0; i < 9; i++) {
151  res = &(stats.results[i]);
152  if ( res->score_player == 2 && res->free != -1 ) {
153   if ( try_put(state, res->free, _COMPUTER) == 0 )
154    return;
155  }
156 }
157
158 // step 2: fork
159 // TODO: implement
160
161 // step 3: block forking
162 // TODO: implement
163
164 // step 4: play center
165 if ( try_put(state, 4, _COMPUTER) == 0 )
166  return;
167
168 // step 5: "Opposite corner"
169 for (i = 0; i < 4; i++)
170  if ( player_move == corner[i] )
171   if ( try_put(state, 8 - player_move, _COMPUTER) == 0 )
172    return;
173
174 // step 6: Empty corner
175 for (i = 0; i < 4; i++)
176  if ( try_put(state, corner[i], _COMPUTER) == 0 )
177   return;
178
179 // step 7: Empty side
180 for (i = 0; i < 4; i++)
181  if ( try_put(state, side[i], _COMPUTER) == 0 )
182   return;
183}
184
185static void draw_game(int client, game_state * state, const char * info) {
186 struct roar_buffer * buf;
187 ssize_t len = 0;
188 void * data;
189
190 if ( roar_buffer_new_data(&buf, _DISPLAY_BUFFER_LEN, &data) == -1 )
191  return;
192
193 snprintf(data, _DISPLAY_BUFFER_LEN, _DISPLAY,
194          (*state)[0], (*state)[1], (*state)[2],
195          (*state)[3], (*state)[4], (*state)[5],
196          (*state)[6], (*state)[7], (*state)[8],
197          info);
198
199 len = roar_mm_strlen(data);
200
201 if ( roar_buffer_set_len(buf, len) == -1 ) {
202  roar_buffer_free(buf);
203  clients_delete(client);
204 }
205
206 clients_add_output(client, &buf);
207}
208
209int new_client(int client, struct roar_vio_calls * vio, struct roard_listen * lsock) {
210 struct roar_client_server * cs;
211 game_state * state;
212
213 (void)vio, (void)lsock;
214
215 if ( clients_get_server(client, &cs) == -1 )
216  return -1;
217
218 state = roar_mm_malloc(sizeof(game_state));
219 if ( state == NULL )
220  return -1;
221
222 new_game(state);
223
224 cs->protoinst = state;
225
226 draw_game(client, state, MSG__YOUR_TURN);
227 return 0;
228}
229
230static int check_client(int client, struct roar_vio_calls * vio) {
231 struct roar_client_server * cs;
232 char buf[32];
233 ssize_t len;
234 ssize_t i;
235 const char * msg = MSG__YOUR_TURN;
236 char won;
237 int player_move = -1;
238
239 ROAR_DBG("check_client(client=%i, vio=%p) = ?", client, vio);
240
241 if ( clients_get_server(client, &cs) == -1 )
242  return -1;
243
244 len = roar_vio_read(vio, buf, sizeof(buf));
245
246 if ( len < 1 ) {
247  clients_delete(client);
248  return -1;
249 }
250
251 if ( check_won(cs->protoinst) ) {
252  for (i = 0; i < len; i++) {
253   if ( buf[i] == 'q' ) {
254    clients_delete(client);
255    return -1;
256   } else {
257    new_game(cs->protoinst);
258    draw_game(client, cs->protoinst, MSG__YOUR_TURN);
259    return 0;
260   }
261  }
262 }
263
264 for (i = 0; i < len; i++) {
265  switch (buf[i]) {
266   case 'q':
267     clients_delete(client);
268     return -1;
269    break;
270   case '0': case '1': case '2': case '3': case '4':
271   case '5': case '6': case '7': case '8':
272     if ( try_put(cs->protoinst, buf[i] - '0', _PLAYER) == -1 ) {
273      msg = MSG__CANNOT_PUT_HERE;
274      draw_game(client, cs->protoinst, msg);
275      return 0;
276     } else {
277      msg = MSG__YOUR_TURN;
278      i = len; // end the loop.
279      player_move = buf[i] - '0';
280     }
281    break;
282  }
283 }
284
285 won = check_won(cs->protoinst);
286
287 if ( !won && player_move != -1 ) {
288  auto_move(cs->protoinst, player_move);
289  won = check_won(cs->protoinst);
290 }
291
292 switch (won) {
293  case _PLAYER: msg = MSG__WON_PLAYER; break;
294  case _COMPUTER: msg = MSG__WON_COMPUTER; break;
295  case _NOBODY: msg = MSG__WON_NOBODY; break;
296 }
297
298 draw_game(client, cs->protoinst, msg);
299
300 ROAR_DBG("check_client(client=%i, vio=%p) = 0", client, vio);
301 return 0;
302}
303
304
305static struct roard_proto proto[1] = {
306 {ROAR_PROTO_GAME, ROAR_SUBSYS_NONE, "Simple Tic-Tac-Toe game", NULL, new_client, NULL, check_client, NULL, NULL}
307};
308
309ROARD_DL_REG_PROTO(proto)
310
311ROAR_DL_PLUGIN_START(protocol_tic_tac_toe) {
312 ROARD_DL_CHECK_VERSIONS();
313
314 ROAR_DL_PLUGIN_META_PRODUCT_NIV("protocol-tic-tac-toe", ROAR_VID_ROARAUDIO, ROAR_VNAME_ROARAUDIO);
315 ROAR_DL_PLUGIN_META_VERSION(ROAR_VERSION_STRING);
316 ROAR_DL_PLUGIN_META_LICENSE_TAG(GPLv3_0);
317 ROAR_DL_PLUGIN_META_CONTACT_FLNE("Philipp", "Schafft", "ph3-der-loewe", "lion@lion.leolix.org");
318 ROAR_DL_PLUGIN_META_DESC("Implementation of a the well known game Tic-Tac-Toe");
319
320 ROARD_DL_REGFN_PROTO();
321} ROAR_DL_PLUGIN_END
322
323//ll
Note: See TracBrowser for help on using the repository browser.