2 * Copyright (C) 2008 Carl Worth
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see http://www.gnu.org/licenses/ .
17 * Author: Carl Worth <cworth@cworth.org>
32 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
34 #define NUM_ATTRIBUTES 4
37 char *attribute_names[NUM_ATTRIBUTES] = {
38 "number", "color", "shading", "symbol"
41 typedef enum { ATTRIBUTE_INDEX_NUMBER,
42 ATTRIBUTE_INDEX_COLOR,
43 ATTRIBUTE_INDEX_SHADING,
44 ATTRIBUTE_INDEX_SYMBOL } attribute_index_t;
46 char *attribute_values[NUM_ATTRIBUTES][NUM_VALUES] = {
48 { "red", "green", "purple" },
49 { "solid", "open", "striped" },
50 { "oval", "squiggle", "diamond" }
53 typedef enum { COLOR_RED, COLOR_GREEN, COLOR_PURPLE } color_t;
54 typedef enum { SHADING_OPEN, SHADING_STRIPED, SHADING_SOLID } shading_t;
55 typedef enum { SYMBOL_OVAL, SYMBOL_SQUIGGLE, SYMBOL_DIAMOND } symbol_t;
58 int attributes[NUM_ATTRIBUTES];
61 #define DECK_MAX_CARDS ((int) (pow (NUM_VALUES, NUM_ATTRIBUTES)))
64 card_t cards[DECK_MAX_CARDS];
75 #define BOARD_MAX_SLOTS (BOARD_COLS * BOARD_ROWS)
76 typedef struct board {
78 slot_t slots[BOARD_MAX_SLOTS];
82 typedef struct _set_game {
89 board_count_sets_possible (board_t *board);
92 set_game_shuffle (set_game_t *game);
95 set_game_new_game (set_game_t *game);
98 attribute_all_same (card_t *cards, int num_cards, int attr)
105 value = cards[0].attributes[attr];
107 for (i = 1; i < num_cards; i++)
108 if (cards[i].attributes[attr] != value)
115 attribute_all_different (card_t *cards, int num_cards, int attr)
117 int i, seen[NUM_VALUES];
122 memset (seen, 0, sizeof (seen));
124 for (i = 0; i < num_cards; i++) {
125 if (seen[cards[i].attributes[attr]])
127 seen[cards[i].attributes[attr]] = 1;
134 is_set (card_t *cards, int num_cards)
138 for (attr = 0; attr < NUM_ATTRIBUTES; attr++)
139 if (! attribute_all_same (cards, num_cards, attr) &&
140 ! attribute_all_different (cards, num_cards, attr))
149 deck_shuffle (deck_t *deck)
154 assert (deck->num_cards <= DECK_MAX_CARDS);
156 for (i=deck->num_cards - 1; i>=0; i--) {
157 r = (int) i * (rand() / (RAND_MAX + 1.0));
160 tmp = deck->cards[i];
161 deck->cards[i] = deck->cards[r];
162 deck->cards[r] = tmp;
167 deck_init (deck_t *deck)
176 for (number = 0; number < NUM_VALUES; number++)
177 for (color = 0; color < NUM_VALUES; color++)
178 for (shading = 0; shading < NUM_VALUES; shading++)
179 for (symbol = 0; symbol < NUM_VALUES; symbol++) {
180 deck->cards[card].attributes[ATTRIBUTE_INDEX_NUMBER] = number;
181 deck->cards[card].attributes[ATTRIBUTE_INDEX_COLOR] = color;
182 deck->cards[card].attributes[ATTRIBUTE_INDEX_SHADING] = shading;
183 deck->cards[card].attributes[ATTRIBUTE_INDEX_SYMBOL] = symbol;
186 deck->num_cards = card;
192 board_count_sets_possible (board_t *board)
195 int sets_possible = 0;
198 for (i = 0; i < board->num_slots; i++) {
199 if (! board->slots[i].has_card)
201 for (j = i+1; j < board->num_slots; j++) {
202 if (! board->slots[j].has_card)
204 for (k = j+1; k < board->num_slots; k++) {
205 if (! board->slots[k].has_card)
207 cards[0] = board->slots[i].card;
208 cards[1] = board->slots[j].card;
209 cards[2] = board->slots[k].card;
210 if (is_set (cards, 3))
216 board->sets_possible = sets_possible;
220 board_init (board_t *board)
223 board->num_slots = BOARD_MAX_SLOTS;
224 for (i=0; i < board->num_slots; i++) {
225 board->slots[i].has_card = 0;
226 board->slots[i].selected = 0;
229 board_count_sets_possible (board);
233 deal (deck_t *deck, board_t *board)
237 for (i=0; i < board->num_slots; i++)
238 if (! board->slots[i].has_card) {
239 if (deck->num_cards > 0) {
240 board->slots[i].card = deck->cards[deck->num_cards-- -1];
241 board->slots[i].has_card = 1;
245 board_count_sets_possible (board);
249 set_game_handle_show (set_game_t *game,
252 board_t *board = &game->board;
253 char board_str[BOARD_MAX_SLOTS * (NUM_ATTRIBUTES + 1)];
258 for (i = 0; i < board->num_slots; i++)
259 if (board->slots[i].has_card) {
260 for (j = 0; j < NUM_ATTRIBUTES; j++)
261 *s++ = '0' + board->slots[i].card.attributes[j];
266 loudgame_send (&game->lg, peer, board_str);
270 set_game_handle_hint (set_game_t *game,
273 loudgame_sendf (&game->lg, peer, "Sets possible: %d",
274 game->board.sets_possible);
278 set_game_handle_shuffle (set_game_t *game,
281 if (game->board.sets_possible) {
282 loudgame_sendf (&game->lg, peer,
283 "There are %d sets, refusing to shuffle.",
284 game->board.sets_possible);
288 if (game->deck.num_cards == 0) {
289 loudgame_sendf (&game->lg, peer,
290 "Deck exhausted, starting a new game.");
291 set_game_new_game (game);
293 set_game_shuffle (game);
298 set_game_handle_set (set_game_t *game,
310 while (*s && i < 3) {
311 slots[i++] = strtoul (s, &end, 10);
313 loudgame_sendf (&game->lg, peer,
314 "Error: Not an integer: %s", s);
320 while (end && *end && isspace (*end))
323 if (i != 3 || *end != '\0') {
324 loudgame_sendf (&game->lg, peer,
325 "Error: The 'set' command requires exactly 3 integers");
329 for (i = 0; i < 3; i++) {
330 if (slots[i] < 0 || slots[i] > BOARD_MAX_SLOTS) {
331 loudgame_sendf (&game->lg, peer,
332 "Error: Value %d is out of range (0-%d)",
333 slots[i], BOARD_MAX_SLOTS);
338 if (slots[0] == slots[1] ||
339 slots[0] == slots[2] ||
340 slots[1] == slots[2])
342 loudgame_sendf (&game->lg, peer,
343 "Error: All 3 values must be unique");
347 for (i=0; i < 3; i++) {
348 if (game->board.slots[slots[i]].has_card) {
349 cards[i] = game->board.slots[slots[i]].card;
351 loudgame_sendf (&game->lg, peer,
352 "Error: There's no card at position %d", i);
357 if (! is_set (cards, 3)) {
358 loudgame_sendf (&game->lg, peer,
359 "Sorry, that's not a set");
363 loudgame_sendf (&game->lg, peer,
364 "Yes, that's a set!");
366 for (i = 0; i < 3; i++)
367 game->board.slots[slots[i]].has_card = 0;
369 board_count_sets_possible (&game->board);
371 deal (&game->deck, &game->board);
375 set_game_handle_message (loudgame_t *lg,
379 set_game_t *game = (set_game_t*) lg;
381 if (strcmp (message, "show") == 0)
382 set_game_handle_show (game, peer);
383 else if (strcmp (message, "hint") == 0)
384 set_game_handle_hint (game, peer);
385 else if (strcmp (message, "shuffle") == 0)
386 set_game_handle_shuffle (game, peer);
387 else if (strncmp (message, "set", 3) == 0)
388 set_game_handle_set (game, peer, message + 3);
390 loudgame_sendf (lg, peer, "Unknown command: '%s'", message);
393 /* Begin a new game */
395 set_game_new_game (set_game_t *game)
397 deck_init (&game->deck);
398 board_init (&game->board);
399 deal (&game->deck, &game->board);
403 set_game_init (set_game_t *game, int argc, char *argv[])
407 err = loudgame_init (&game->lg, argc, argv);
411 set_game_new_game (game);
416 /* Return the dealt cards to the deck, reshuffle, and deal again. */
418 set_game_shuffle (set_game_t *game)
420 board_t *board = &game->board;
421 deck_t *deck = &game->deck;
424 for (i=0; i < board->num_slots; i++) {
425 if (board->slots[i].has_card) {
426 deck->cards[++deck->num_cards - 1] = board->slots[i].card;
427 board->slots[i].has_card = 0;
428 board->slots[i].selected = 0;
439 main (int argc, char *argv[])
446 err = set_game_init (&game, argc, argv);
450 game.lg.handle_message = set_game_handle_message;
452 err = loudgame_run (&game.lg);