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>
31 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
33 #define NUM_ATTRIBUTES 4
36 char *attribute_names[NUM_ATTRIBUTES] = {
37 "number", "color", "shading", "symbol"
40 typedef enum { ATTRIBUTE_INDEX_NUMBER,
41 ATTRIBUTE_INDEX_COLOR,
42 ATTRIBUTE_INDEX_SHADING,
43 ATTRIBUTE_INDEX_SYMBOL } attribute_index_t;
45 char *attribute_values[NUM_ATTRIBUTES][NUM_VALUES] = {
47 { "red", "green", "purple" },
48 { "solid", "open", "striped" },
49 { "oval", "squiggle", "diamond" }
52 typedef enum { COLOR_RED, COLOR_GREEN, COLOR_PURPLE } color_t;
53 typedef enum { SHADING_OPEN, SHADING_STRIPED, SHADING_SOLID } shading_t;
54 typedef enum { SYMBOL_OVAL, SYMBOL_SQUIGGLE, SYMBOL_DIAMOND } symbol_t;
57 int attributes[NUM_ATTRIBUTES];
60 #define DECK_MAX_CARDS ((int) (pow (NUM_VALUES, NUM_ATTRIBUTES)))
63 card_t cards[DECK_MAX_CARDS];
74 #define BOARD_MAX_SLOTS (BOARD_COLS * BOARD_ROWS)
75 typedef struct board {
77 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 attribute_all_same (card_t *cards, int num_cards, int attr)
102 value = cards[0].attributes[attr];
104 for (i = 1; i < num_cards; i++)
105 if (cards[i].attributes[attr] != value)
112 attribute_all_different (card_t *cards, int num_cards, int attr)
114 int i, seen[NUM_VALUES];
119 memset (seen, 0, sizeof (seen));
121 for (i = 0; i < num_cards; i++) {
122 if (seen[cards[i].attributes[attr]])
124 seen[cards[i].attributes[attr]] = 1;
131 is_set (card_t *cards, int num_cards)
135 for (attr = 0; attr < NUM_ATTRIBUTES; attr++)
136 if (! attribute_all_same (cards, num_cards, attr) &&
137 ! attribute_all_different (cards, num_cards, attr))
146 check_selected_for_set (board_t *board)
152 for (i=0; i < board->num_slots; i++) {
153 if (board->slots[i].selected) {
154 if (num_selected >= 3)
156 cards[num_selected++] = board->slots[i].card;
160 if (num_selected !=3)
163 if (! is_set (cards, num_selected))
166 board_count_sets_possible (board);
168 board->needs_deal = 1;
174 deck_shuffle (deck_t *deck)
179 assert (deck->num_cards <= DECK_MAX_CARDS);
181 for (i=deck->num_cards - 1; i>=0; i--) {
182 r = (int) i * (rand() / (RAND_MAX + 1.0));
185 tmp = deck->cards[i];
186 deck->cards[i] = deck->cards[r];
187 deck->cards[r] = tmp;
192 deck_init (deck_t *deck)
201 for (number = 0; number < NUM_VALUES; number++)
202 for (color = 0; color < NUM_VALUES; color++)
203 for (shading = 0; shading < NUM_VALUES; shading++)
204 for (symbol = 0; symbol < NUM_VALUES; symbol++) {
205 deck->cards[card].attributes[ATTRIBUTE_INDEX_NUMBER] = number;
206 deck->cards[card].attributes[ATTRIBUTE_INDEX_COLOR] = color;
207 deck->cards[card].attributes[ATTRIBUTE_INDEX_SHADING] = shading;
208 deck->cards[card].attributes[ATTRIBUTE_INDEX_SYMBOL] = symbol;
211 deck->num_cards = card;
217 board_count_sets_possible (board_t *board)
220 int sets_possible = 0;
223 for (i = 0; i < board->num_slots; i++) {
224 if (! board->slots[i].has_card)
226 for (j = i+1; j < board->num_slots; j++) {
227 if (! board->slots[j].has_card)
229 for (k = j+1; k < board->num_slots; k++) {
230 if (! board->slots[k].has_card)
232 cards[0] = board->slots[i].card;
233 cards[1] = board->slots[j].card;
234 cards[2] = board->slots[k].card;
235 if (is_set (cards, 3))
241 board->sets_possible = sets_possible;
245 board_init (board_t *board)
248 board->num_slots = BOARD_MAX_SLOTS;
249 for (i=0; i < board->num_slots; i++) {
250 board->slots[i].has_card = 0;
251 board->slots[i].selected = 0;
253 board->needs_deal = 0;
255 board_count_sets_possible (board);
259 deal (deck_t *deck, board_t *board)
263 for (i=0; i < board->num_slots; i++)
264 if (! board->slots[i].has_card) {
265 if (deck->num_cards > 0) {
266 board->slots[i].card = deck->cards[deck->num_cards-- -1];
267 board->slots[i].has_card = 1;
271 board_count_sets_possible (board);
273 board->needs_deal = 0;
277 set_game_handle_show (set_game_t *game,
280 board_t *board = &game->board;
281 char board_str[BOARD_MAX_SLOTS * (NUM_ATTRIBUTES + 1)];
286 for (i = 0; i < board->num_slots; i++)
287 if (board->slots[i].has_card) {
288 for (j = 0; j < NUM_ATTRIBUTES; j++)
289 *s++ = '0' + board->slots[i].card.attributes[j];
294 loudgame_send (&game->lg, peer, board_str);
298 set_game_handle_hint (set_game_t *game,
301 loudgame_sendf (&game->lg, peer, "Sets possible: %d",
302 game->board.sets_possible);
306 set_game_handle_shuffle (set_game_t *game,
309 if (game->board.sets_possible) {
310 loudgame_sendf (&game->lg, peer,
311 "There are %d sets, refusing to shuffle.",
312 game->board.sets_possible);
316 set_game_shuffle (game);
320 set_game_handle_message (loudgame_t *lg,
324 set_game_t *game = (set_game_t*) lg;
326 if (strcmp (message, "show") == 0)
327 set_game_handle_show (game, peer);
328 else if (strcmp (message, "hint") == 0)
329 set_game_handle_hint (game, peer);
330 else if (strcmp (message, "shuffle") == 0)
331 set_game_handle_shuffle (game, peer);
333 loudgame_sendf (lg, peer, "Unknown command: '%s'", message);
336 /* Begin a new game */
338 set_game_init (set_game_t *game, int argc, char *argv[])
342 err = loudgame_init (&game->lg, argc, argv);
346 deck_init (&game->deck);
347 board_init (&game->board);
348 deal (&game->deck, &game->board);
353 /* Return the dealt cards to the deck, reshuffle, and deal again. */
355 set_game_shuffle (set_game_t *game)
357 board_t *board = &game->board;
358 deck_t *deck = &game->deck;
361 for (i=0; i < board->num_slots; i++) {
362 if (board->slots[i].has_card) {
363 deck->cards[++deck->num_cards - 1] = board->slots[i].card;
364 board->slots[i].has_card = 0;
365 board->slots[i].selected = 0;
376 main (int argc, char *argv[])
383 err = set_game_init (&game, argc, argv);
387 game.lg.handle_message = set_game_handle_message;
389 err = loudgame_run (&game.lg);