Add initial Set implementation (not hooked up to jabber yet)
[loudgame] / lg-set.c
1 /*
2  * Copyright (C) 2008 Carl Worth
3  *
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.
8  *
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.
13  *
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/ .
16  *
17  * Author: Carl Worth <cworth@cworth.org>
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <math.h>
25 #include <time.h>
26
27 #include <assert.h>
28
29 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
30
31 #define NUM_ATTRIBUTES 4
32 #define NUM_VALUES 3
33
34 char *attribute_names[NUM_ATTRIBUTES] = {
35     "number", "color", "shading", "symbol"
36 };
37
38 typedef enum { ATTRIBUTE_INDEX_NUMBER,
39                ATTRIBUTE_INDEX_COLOR,
40                ATTRIBUTE_INDEX_SHADING,
41                ATTRIBUTE_INDEX_SYMBOL } attribute_index_t;
42
43 char *attribute_values[NUM_ATTRIBUTES][NUM_VALUES] = {
44     { "1", "2", "3" },
45     { "red", "green", "purple" },
46     { "solid", "open", "striped" },
47     { "oval", "squiggle", "diamond" }
48 };
49
50 typedef enum { COLOR_RED, COLOR_GREEN, COLOR_PURPLE } color_t;
51 typedef enum { SHADING_OPEN, SHADING_STRIPED, SHADING_SOLID } shading_t;
52 typedef enum { SYMBOL_OVAL, SYMBOL_SQUIGGLE, SYMBOL_DIAMOND } symbol_t;
53
54 typedef struct card {
55     int attributes[NUM_ATTRIBUTES];
56 } card_t;
57
58 #define DECK_MAX_CARDS ((int) (pow (NUM_VALUES, NUM_ATTRIBUTES)))
59 typedef struct deck {
60     int num_cards;
61     card_t cards[DECK_MAX_CARDS];
62 } deck_t;
63
64 typedef struct slot {
65     int has_card;
66     card_t card;
67     int selected;
68 } slot_t;
69
70 #define BOARD_COLS 3
71 #define BOARD_ROWS 4
72 #define BOARD_MAX_SLOTS (BOARD_COLS * BOARD_ROWS)
73 typedef struct board {
74     int num_slots;
75     slot_t slots[BOARD_MAX_SLOTS];
76     int needs_deal;
77     int sets_possible;
78     int display_sets_possible;
79 } board_t;
80
81 typedef struct game {
82     deck_t deck;
83     board_t board;
84 } game_t;
85
86 static void game_init (game_t *game);
87 static void game_fini (game_t *game);
88
89 static void
90 board_count_sets_possible (board_t *board);
91
92 static int
93 attribute_all_same (card_t *cards, int num_cards, int attr)
94 {
95     int i, value;
96
97     if (num_cards == 0)
98         return 1;
99
100     value = cards[0].attributes[attr];
101
102     for (i = 1; i < num_cards; i++)
103         if (cards[i].attributes[attr] != value)
104             return 0;
105
106     return 1;
107 }
108
109 static int
110 attribute_all_different (card_t *cards, int num_cards, int attr)
111 {
112     int i, seen[NUM_VALUES];
113
114     if (num_cards == 0)
115         return 1;
116
117     memset (seen, 0, sizeof (seen));
118
119     for (i = 0; i < num_cards; i++) {
120         if (seen[cards[i].attributes[attr]])
121             return 0;
122         seen[cards[i].attributes[attr]] = 1;
123     }
124
125     return 1;
126 }
127
128 static int
129 is_set (card_t *cards, int num_cards)
130 {
131     int attr;
132
133     for (attr = 0; attr < NUM_ATTRIBUTES; attr++)
134         if (! attribute_all_same (cards, num_cards, attr) &&
135             ! attribute_all_different (cards, num_cards, attr))
136         {
137             return 0;
138         }
139
140     return 1;
141 }
142
143 static int
144 check_selected_for_set (board_t *board)
145 {
146     int i, num_selected;
147     card_t cards[3];
148
149     num_selected = 0;
150     for (i=0; i < board->num_slots; i++) {
151         if (board->slots[i].selected) {
152             if (num_selected >= 3)
153                 return 0;
154             cards[num_selected++] = board->slots[i].card;
155         }
156     }
157
158     if (num_selected !=3)
159         return 0;
160
161     if (! is_set (cards, num_selected))
162         return 0;
163
164     board_count_sets_possible (board);
165
166     board->needs_deal = 1;
167
168     return 1;
169 }
170
171 static void
172 deck_shuffle (deck_t *deck)
173 {
174     int i, r;
175     card_t tmp;
176
177     assert (deck->num_cards <= DECK_MAX_CARDS);
178
179     for (i=deck->num_cards - 1; i>=0; i--) {
180         r = (int) i * (rand() / (RAND_MAX + 1.0));
181         assert (r >= 0);
182         assert (r <= i);
183         tmp = deck->cards[i];
184         deck->cards[i] = deck->cards[r];
185         deck->cards[r] = tmp;
186     }
187 }
188
189 static void
190 deck_init (deck_t *deck)
191 {
192     int card;
193     int number;
194     color_t color;
195     shading_t shading;
196     symbol_t symbol;
197
198     card = 0;
199     for (number = 0; number < NUM_VALUES; number++)
200         for (color = 0; color < NUM_VALUES; color++)
201             for (shading = 0; shading < NUM_VALUES; shading++)
202                 for (symbol = 0; symbol < NUM_VALUES; symbol++) {
203                     deck->cards[card].attributes[ATTRIBUTE_INDEX_NUMBER] = number;
204                     deck->cards[card].attributes[ATTRIBUTE_INDEX_COLOR] = color;
205                     deck->cards[card].attributes[ATTRIBUTE_INDEX_SHADING] = shading;
206                     deck->cards[card].attributes[ATTRIBUTE_INDEX_SYMBOL] = symbol;
207                     card++;
208                 }
209     deck->num_cards = card;
210
211     deck_shuffle (deck);
212 }
213
214 static void
215 board_count_sets_possible (board_t *board)
216 {
217     int i, j, k;
218     int sets_possible = 0;
219     card_t cards[3];
220
221     for (i = 0; i < board->num_slots; i++) {
222         if (! board->slots[i].has_card)
223             continue;
224         for (j = i+1; j < board->num_slots; j++) {
225             if (! board->slots[j].has_card)
226                 continue;
227             for (k = j+1; k < board->num_slots; k++) {
228                 if (! board->slots[k].has_card)
229                     continue;
230                 cards[0] = board->slots[i].card;
231                 cards[1] = board->slots[j].card;
232                 cards[2] = board->slots[k].card;
233                 if (is_set (cards, 3))
234                     sets_possible++;
235             }
236         }
237     }
238
239     board->sets_possible = sets_possible;
240 }
241
242 static void
243 board_init (board_t *board)
244 {
245     int i;
246     board->num_slots = BOARD_MAX_SLOTS;
247     for (i=0; i < board->num_slots; i++) {
248         board->slots[i].has_card = 0;
249         board->slots[i].selected = 0;
250     }
251     board->needs_deal = 0;
252
253     board_count_sets_possible (board);
254 }
255
256 static void
257 board_print (board_t *board)
258 {
259     int i, j;
260
261     printf ("Sets possible: %d\n", board->sets_possible);
262
263     for  (i = 0; i < board->num_slots; i++) {
264         if (! board->slots[i].has_card)
265             for (j = 0; j < NUM_ATTRIBUTES; j++)
266                 printf (" ");
267         else
268             for (j = 0; j < NUM_ATTRIBUTES; j++)
269                 printf ("%d", board->slots[i].card.attributes[j]);
270         if ((i + 1) % 3 == 0)
271             printf ("\n");
272         else
273             printf (" ");
274     }
275 }
276
277 static void
278 deal (deck_t *deck, board_t *board)
279 {
280     int i;
281
282     for (i=0; i < board->num_slots; i++)
283         if (! board->slots[i].has_card) {
284             if (deck->num_cards > 0) {
285                 board->slots[i].card = deck->cards[deck->num_cards-- -1];
286                 board->slots[i].has_card = 1;
287             }
288         }
289
290     board_count_sets_possible (board);
291
292     board->needs_deal = 0;
293 }
294
295 /* Begin a new game */
296 static void
297 game_init (game_t *game)
298 {
299     deck_init (&game->deck);
300     board_init (&game->board);
301     deal (&game->deck, &game->board);
302 }
303
304 static void
305 game_fini (game_t *game)
306 {
307     /* Nothing to do. */
308 }
309
310 /* Return the dealt cards to the deck, reshuffle, and deal again. */
311 static int
312 reshuffle (deck_t *deck, board_t *board)
313 {
314     int i;
315
316     if (board->sets_possible) {
317         return 0;
318     }
319
320     for (i=0; i < board->num_slots; i++) {
321         if (board->slots[i].has_card) {
322             deck->cards[++deck->num_cards - 1] = board->slots[i].card;
323             board->slots[i].has_card = 0;
324             board->slots[i].selected = 0;
325         }
326     }
327
328     deck_shuffle (deck);
329     deal (deck, board);
330
331     return 1;
332 }
333
334 int
335 main (void)
336 {
337     game_t game;
338
339     srand (time(0));
340
341     game_init (&game);
342
343     board_print (&game.board);
344
345     game_fini (&game);
346
347     return 0;
348 }