source: roaraudio/plugins/universal/tic-tac-toe.c @ 5454:2ab8612a9401

Last change on this file since 5454:2ab8612a9401 was 5454:2ab8612a9401, checked in by phi, 10 years ago

use numblock encoding as requested

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