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];
272 loudgame_send (&game->lg, peer, board_str);
276 set_game_handle_hint (set_game_t *game,
279 loudgame_sendf (&game->lg, peer, "Sets possible: %d",
280 game->board.sets_possible);
284 set_game_handle_shuffle (set_game_t *game,
287 if (game->board.sets_possible) {
288 loudgame_sendf (&game->lg, peer,
289 "There are %d sets, refusing to shuffle.",
290 game->board.sets_possible);
294 if (game->deck.num_cards == 0) {
295 loudgame_sendf (&game->lg, peer,
296 "Deck exhausted, starting a new game.");
297 set_game_new_game (game);
299 set_game_shuffle (game);
304 set_game_handle_set (set_game_t *game,
316 while (*s && i < 3) {
317 slots[i++] = strtoul (s, &end, 10);
319 loudgame_sendf (&game->lg, peer,
320 "Error: Not an integer: %s", s);
326 while (end && *end && isspace (*end))
329 if (i != 3 || *end != '\0') {
330 loudgame_sendf (&game->lg, peer,
331 "Error: The 'set' command requires exactly 3 integers");
335 for (i = 0; i < 3; i++) {
336 if (slots[i] < 0 || slots[i] > BOARD_MAX_SLOTS) {
337 loudgame_sendf (&game->lg, peer,
338 "Error: Value %d is out of range (0-%d)",
339 slots[i], BOARD_MAX_SLOTS);
344 if (slots[0] == slots[1] ||
345 slots[0] == slots[2] ||
346 slots[1] == slots[2])
348 loudgame_sendf (&game->lg, peer,
349 "Error: All 3 values must be unique");
353 for (i=0; i < 3; i++) {
354 if (game->board.slots[slots[i]].has_card) {
355 cards[i] = game->board.slots[slots[i]].card;
357 loudgame_sendf (&game->lg, peer,
358 "Error: There's no card at position %d", i);
363 if (! is_set (cards, 3)) {
364 loudgame_sendf (&game->lg, peer,
365 "Sorry, that's not a set");
369 loudgame_sendf (&game->lg, peer,
370 "Yes, that's a set!");
372 for (i = 0; i < 3; i++)
373 game->board.slots[slots[i]].has_card = 0;
375 board_count_sets_possible (&game->board);
377 deal (&game->deck, &game->board);
381 set_game_handle_message (loudgame_t *lg,
385 set_game_t *game = (set_game_t*) lg;
387 if (strcmp (message, "show") == 0)
388 set_game_handle_show (game, peer);
389 else if (strcmp (message, "hint") == 0)
390 set_game_handle_hint (game, peer);
391 else if (strcmp (message, "shuffle") == 0)
392 set_game_handle_shuffle (game, peer);
393 else if (strncmp (message, "set", 3) == 0)
394 set_game_handle_set (game, peer, message + 3);
396 loudgame_sendf (lg, peer, "Unknown command: '%s'", message);
399 /* Begin a new game */
401 set_game_new_game (set_game_t *game)
403 deck_init (&game->deck);
404 board_init (&game->board);
405 deal (&game->deck, &game->board);
409 set_game_init (set_game_t *game, int argc, char *argv[])
413 err = loudgame_init (&game->lg, argc, argv);
417 set_game_new_game (game);
422 /* Return the dealt cards to the deck, reshuffle, and deal again. */
424 set_game_shuffle (set_game_t *game)
426 board_t *board = &game->board;
427 deck_t *deck = &game->deck;
430 for (i=0; i < board->num_slots; i++) {
431 if (board->slots[i].has_card) {
432 deck->cards[++deck->num_cards - 1] = board->slots[i].card;
433 board->slots[i].has_card = 0;
434 board->slots[i].selected = 0;
445 main (int argc, char *argv[])
452 err = set_game_init (&game, argc, argv);
456 game.lg.handle_message = set_game_handle_message;
458 err = loudgame_run (&game.lg);