Add initial Set implementation (not hooked up to jabber yet)
authorCarl Worth <cworth@cworth.org>
Sat, 12 Jan 2008 21:11:26 +0000 (13:11 -0800)
committerCarl Worth <cworth@cworth.org>
Sat, 12 Jan 2008 21:11:26 +0000 (13:11 -0800)
.gitignore
Makefile
lg-set.c [new file with mode: 0644]

index 1cc31181e40d95a81db338de3f03f2a9042b8562..17ea798c92222321923ec0184feedb56b61ec2c5 100644 (file)
@@ -1,6 +1,7 @@
 *~
 *.o
 lg-echo
+lg-set
 lg-test
 Makefile.dep
 
index 6ac3b61cc0ed5a9a2949b150c0ff375df52d5fa1..d74c04ba8a3ca9964db26520328c02234cf76a18 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-ALL=lg-echo lg-test
+ALL=lg-echo lg-test lg-set
 MYCFLAGS=-Wall `pkg-config --cflags loudmouth-1.0`
 MYLDFLAGS=`pkg-config --libs loudmouth-1.0`
 
diff --git a/lg-set.c b/lg-set.c
new file mode 100644 (file)
index 0000000..1451200
--- /dev/null
+++ b/lg-set.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2008 Carl Worth
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see http://www.gnu.org/licenses/ .
+ *
+ * Author: Carl Worth <cworth@cworth.org>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+#include <time.h>
+
+#include <assert.h>
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+#define NUM_ATTRIBUTES 4
+#define NUM_VALUES 3
+
+char *attribute_names[NUM_ATTRIBUTES] = {
+    "number", "color", "shading", "symbol"
+};
+
+typedef enum { ATTRIBUTE_INDEX_NUMBER,
+              ATTRIBUTE_INDEX_COLOR,
+              ATTRIBUTE_INDEX_SHADING,
+              ATTRIBUTE_INDEX_SYMBOL } attribute_index_t;
+
+char *attribute_values[NUM_ATTRIBUTES][NUM_VALUES] = {
+    { "1", "2", "3" },
+    { "red", "green", "purple" },
+    { "solid", "open", "striped" },
+    { "oval", "squiggle", "diamond" }
+};
+
+typedef enum { COLOR_RED, COLOR_GREEN, COLOR_PURPLE } color_t;
+typedef enum { SHADING_OPEN, SHADING_STRIPED, SHADING_SOLID } shading_t;
+typedef enum { SYMBOL_OVAL, SYMBOL_SQUIGGLE, SYMBOL_DIAMOND } symbol_t;
+
+typedef struct card {
+    int attributes[NUM_ATTRIBUTES];
+} card_t;
+
+#define DECK_MAX_CARDS ((int) (pow (NUM_VALUES, NUM_ATTRIBUTES)))
+typedef struct deck {
+    int num_cards;
+    card_t cards[DECK_MAX_CARDS];
+} deck_t;
+
+typedef struct slot {
+    int has_card;
+    card_t card;
+    int selected;
+} slot_t;
+
+#define BOARD_COLS 3
+#define BOARD_ROWS 4
+#define BOARD_MAX_SLOTS (BOARD_COLS * BOARD_ROWS)
+typedef struct board {
+    int num_slots;
+    slot_t slots[BOARD_MAX_SLOTS];
+    int needs_deal;
+    int sets_possible;
+    int display_sets_possible;
+} board_t;
+
+typedef struct game {
+    deck_t deck;
+    board_t board;
+} game_t;
+
+static void game_init (game_t *game);
+static void game_fini (game_t *game);
+
+static void
+board_count_sets_possible (board_t *board);
+
+static int
+attribute_all_same (card_t *cards, int num_cards, int attr)
+{
+    int i, value;
+
+    if (num_cards == 0)
+       return 1;
+
+    value = cards[0].attributes[attr];
+
+    for (i = 1; i < num_cards; i++)
+       if (cards[i].attributes[attr] != value)
+           return 0;
+
+    return 1;
+}
+
+static int
+attribute_all_different (card_t *cards, int num_cards, int attr)
+{
+    int i, seen[NUM_VALUES];
+
+    if (num_cards == 0)
+       return 1;
+
+    memset (seen, 0, sizeof (seen));
+
+    for (i = 0; i < num_cards; i++) {
+       if (seen[cards[i].attributes[attr]])
+           return 0;
+       seen[cards[i].attributes[attr]] = 1;
+    }
+
+    return 1;
+}
+
+static int
+is_set (card_t *cards, int num_cards)
+{
+    int attr;
+
+    for (attr = 0; attr < NUM_ATTRIBUTES; attr++)
+       if (! attribute_all_same (cards, num_cards, attr) &&
+           ! attribute_all_different (cards, num_cards, attr))
+       {
+           return 0;
+       }
+
+    return 1;
+}
+
+static int
+check_selected_for_set (board_t *board)
+{
+    int i, num_selected;
+    card_t cards[3];
+
+    num_selected = 0;
+    for (i=0; i < board->num_slots; i++) {
+       if (board->slots[i].selected) {
+           if (num_selected >= 3)
+               return 0;
+           cards[num_selected++] = board->slots[i].card;
+       }
+    }
+
+    if (num_selected !=3)
+       return 0;
+
+    if (! is_set (cards, num_selected))
+       return 0;
+
+    board_count_sets_possible (board);
+
+    board->needs_deal = 1;
+
+    return 1;
+}
+
+static void
+deck_shuffle (deck_t *deck)
+{
+    int i, r;
+    card_t tmp;
+
+    assert (deck->num_cards <= DECK_MAX_CARDS);
+
+    for (i=deck->num_cards - 1; i>=0; i--) {
+       r = (int) i * (rand() / (RAND_MAX + 1.0));
+       assert (r >= 0);
+       assert (r <= i);
+       tmp = deck->cards[i];
+       deck->cards[i] = deck->cards[r];
+       deck->cards[r] = tmp;
+    }
+}
+
+static void
+deck_init (deck_t *deck)
+{
+    int card;
+    int number;
+    color_t color;
+    shading_t shading;
+    symbol_t symbol;
+
+    card = 0;
+    for (number = 0; number < NUM_VALUES; number++)
+       for (color = 0; color < NUM_VALUES; color++)
+           for (shading = 0; shading < NUM_VALUES; shading++)
+               for (symbol = 0; symbol < NUM_VALUES; symbol++) {
+                   deck->cards[card].attributes[ATTRIBUTE_INDEX_NUMBER] = number;
+                   deck->cards[card].attributes[ATTRIBUTE_INDEX_COLOR] = color;
+                   deck->cards[card].attributes[ATTRIBUTE_INDEX_SHADING] = shading;
+                   deck->cards[card].attributes[ATTRIBUTE_INDEX_SYMBOL] = symbol;
+                   card++;
+               }
+    deck->num_cards = card;
+
+    deck_shuffle (deck);
+}
+
+static void
+board_count_sets_possible (board_t *board)
+{
+    int i, j, k;
+    int sets_possible = 0;
+    card_t cards[3];
+
+    for (i = 0; i < board->num_slots; i++) {
+       if (! board->slots[i].has_card)
+           continue;
+       for (j = i+1; j < board->num_slots; j++) {
+           if (! board->slots[j].has_card)
+               continue;
+           for (k = j+1; k < board->num_slots; k++) {
+               if (! board->slots[k].has_card)
+                   continue;
+               cards[0] = board->slots[i].card;
+               cards[1] = board->slots[j].card;
+               cards[2] = board->slots[k].card;
+               if (is_set (cards, 3))
+                   sets_possible++;
+           }
+       }
+    }
+
+    board->sets_possible = sets_possible;
+}
+
+static void
+board_init (board_t *board)
+{
+    int i;
+    board->num_slots = BOARD_MAX_SLOTS;
+    for (i=0; i < board->num_slots; i++) {
+       board->slots[i].has_card = 0;
+       board->slots[i].selected = 0;
+    }
+    board->needs_deal = 0;
+
+    board_count_sets_possible (board);
+}
+
+static void
+board_print (board_t *board)
+{
+    int i, j;
+
+    printf ("Sets possible: %d\n", board->sets_possible);
+
+    for  (i = 0; i < board->num_slots; i++) {
+       if (! board->slots[i].has_card)
+           for (j = 0; j < NUM_ATTRIBUTES; j++)
+               printf (" ");
+       else
+           for (j = 0; j < NUM_ATTRIBUTES; j++)
+               printf ("%d", board->slots[i].card.attributes[j]);
+       if ((i + 1) % 3 == 0)
+           printf ("\n");
+       else
+           printf (" ");
+    }
+}
+
+static void
+deal (deck_t *deck, board_t *board)
+{
+    int i;
+
+    for (i=0; i < board->num_slots; i++)
+       if (! board->slots[i].has_card) {
+           if (deck->num_cards > 0) {
+               board->slots[i].card = deck->cards[deck->num_cards-- -1];
+               board->slots[i].has_card = 1;
+           }
+       }
+
+    board_count_sets_possible (board);
+
+    board->needs_deal = 0;
+}
+
+/* Begin a new game */
+static void
+game_init (game_t *game)
+{
+    deck_init (&game->deck);
+    board_init (&game->board);
+    deal (&game->deck, &game->board);
+}
+
+static void
+game_fini (game_t *game)
+{
+    /* Nothing to do. */
+}
+
+/* Return the dealt cards to the deck, reshuffle, and deal again. */
+static int
+reshuffle (deck_t *deck, board_t *board)
+{
+    int i;
+
+    if (board->sets_possible) {
+       return 0;
+    }
+
+    for (i=0; i < board->num_slots; i++) {
+       if (board->slots[i].has_card) {
+           deck->cards[++deck->num_cards - 1] = board->slots[i].card;
+           board->slots[i].has_card = 0;
+           board->slots[i].selected = 0;
+       }
+    }
+
+    deck_shuffle (deck);
+    deal (deck, board);
+
+    return 1;
+}
+
+int
+main (void)
+{
+    game_t game;
+
+    srand (time(0));
+
+    game_init (&game);
+
+    board_print (&game.board);
+
+    game_fini (&game);
+
+    return 0;
+}