From 067f67d8b3d5b4a05c406f23e8129eb08413eb2f Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Sat, 12 Jan 2008 13:11:26 -0800 Subject: [PATCH] Add initial Set implementation (not hooked up to jabber yet) --- .gitignore | 1 + Makefile | 2 +- lg-set.c | 348 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 lg-set.c diff --git a/.gitignore b/.gitignore index 1cc3118..17ea798 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *~ *.o lg-echo +lg-set lg-test Makefile.dep diff --git a/Makefile b/Makefile index 6ac3b61..d74c04b 100644 --- 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 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 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#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; +} -- 2.43.0