Set puzzle: Difference between revisions

From Rosetta Code
Content added Content deleted
(add draft task)
 
(→‎{{header|D}}: added D)
Line 68: Line 68:


purple, three, oval, open
purple, three, oval, open


=={{header|D}}==
<lang d>import std.stdio, std.traits, std.random, std.conv, std.exception,
std.array;

class SetDealer {
protected {
enum Color : ubyte {green, purple, red}
enum Number : ubyte {one, two, three}
enum Symbol : ubyte {oval, diamond, squiggle}
enum Fill : ubyte {open, striped, solid}

static struct Card {
Color c;
Number n;
Symbol s;
Fill f;
}

Card[81] deck;
}

this() nothrow {
auto colors = [EnumMembers!Color];
auto numbers = [EnumMembers!Number];
auto symbols = [EnumMembers!Symbol];
auto fill = [EnumMembers!Fill];

foreach (immutable i; 0 .. deck.length) {
auto c = colors[i / 27];
auto n = numbers[(i / 9) % 3];
auto s = symbols[(i / 3) % 3];
auto f = fill[i % 3];
deck[i] = Card(c, n, s, f);
}
}


// randomSample produces a sorted output that's convenient in our case
// because we're printing to stout. Normally you would want to shuffle.
immutable(Card)[] deal(in uint numCards) {
enforce(numCards < deck.length, "number of cards too large");
return assumeUnique(randomSample(deck[], numCards).array());
}

// The summed enums of valid sets are always zero or a multiple of 3
bool validSet(in ref Card c1, in ref Card c2, in ref Card c3)
pure nothrow {
return !((c1.c + c2.c + c3.c) % 3 || (c1.n + c2.n + c3.n) % 3 ||
(c1.s + c2.s + c3.s) % 3 || (c1.f + c2.f + c3.f) % 3);
}

immutable(Card)[3][] findSets(in Card[] cards) pure nothrow {
auto len = cards.length;
if (len >= 3) {
typeof(return) sets;
for (int i = 0; i < len - 2; i++) {
for (int j = i + 1; j < len - 1; j++)
for (int k = j + 1; k < len; k++)
if (validSet(cards[i], cards[j], cards[k]))
sets ~= [cards[i], cards[j], cards[k]];
}
return assumeUnique(sets);
}
return null;
}
}

class SetPuzzleDealer : SetDealer {
enum NumCards {basic = 9, advanced = 12}

override immutable(Card)[] deal(in uint numCards = NumCards.basic) {
auto numSets = numCards / 2;
typeof(return) cards;
do {
cards = super.deal(numCards);
} while (findSets(cards).length != numSets);

return assumeUnique(cards);
}
}

void main() {
auto dealer = new SetPuzzleDealer();
auto cards = dealer.deal();

writefln("\nDEALT %d CARDS:\n", cards.length);
foreach (Unqual!(typeof(cards[0])) c; cards)
writeln(c);

auto sets = dealer.findSets(cards);
auto len = sets.length;
writefln("\nFOUND %d %s:\n", len, len == 1 ? "SET" : "SETS");
foreach (set; sets) {
foreach (Unqual!(typeof(set[0])) c; set)
writeln(c);
writeln();
}
}</lang>
<pre>DEALT 9 CARDS:

Card(green, one, oval, solid)
Card(green, one, diamond, solid)
Card(green, one, squiggle, solid)
Card(green, two, squiggle, open)
Card(green, three, oval, open)
Card(green, three, diamond, solid)
Card(green, three, squiggle, striped)
Card(purple, two, squiggle, solid)
Card(red, one, squiggle, open)

FOUND 4 SETS:

Card(green, one, oval, solid)
Card(green, one, diamond, solid)
Card(green, one, squiggle, solid)

Card(green, one, squiggle, solid)
Card(green, two, squiggle, open)
Card(green, three, squiggle, striped)

Card(green, three, oval, open)
Card(green, three, diamond, solid)
Card(green, three, squiggle, striped)

Card(green, three, squiggle, striped)
Card(purple, two, squiggle, solid)
Card(red, one, squiggle, open)</pre>

Revision as of 23:10, 9 February 2013

Set puzzle is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Set Puzzles are created with a deck of cards from the Set Game(TM). The object of the puzzle is to find sets of 3 cards in a rectangle of cards that have been dealt face up. There are 81 cards in a deck. Each card contains a variation of the following four features: color, symbol, number and shading.

there are three colors
red, green, or purple
there are three symbols
oval, squiggle, or diamond
there is a number of symbols on the card
one, two, or three
there are three shadings
solid, open, or striped


Three cards form a set if each feature is either the same on each card, or is different on each card. For instance: all 3 cards are red, all 3 cards have a different symbol, all 3 cards have a different number of symbols, all 3 cards are striped.


There are two degrees of difficulty: basic and advanced. The basic mode deals 9 cards, that contain 4 sets; the advanced mode deals 12 cards that contain 6 sets. The task is to write code that deals the cards, 9 or 12, depending on selected mode, and print the contents of the cards and the sets. For instance:


DEALT 9 CARDS:

green, one, oval, striped

green, one, diamond, open

green, one, diamond, striped

green, one, diamond, solid

purple, one, diamond, open

purple, two, squiggle, open

purple, three, oval, open

red, three, oval, open

red, three, diamond, solid


CONTAINING 4 SETS:

green, one, oval, striped

purple, two, squiggle, open

red, three, diamond, solid


green, one, diamond, open

green, one, diamond, striped

green, one, diamond, solid


green, one, diamond, open

purple, two, squiggle, open

red, three, oval, open


purple, one, diamond, open

purple, two, squiggle, open

purple, three, oval, open


D

<lang d>import std.stdio, std.traits, std.random, std.conv, std.exception,

       std.array;

class SetDealer {

   protected {
       enum Color : ubyte {green, purple, red}
       enum Number : ubyte {one, two, three}
       enum Symbol : ubyte {oval, diamond, squiggle}
       enum Fill : ubyte {open, striped, solid}
       static struct Card {
           Color c;
           Number n;
           Symbol s;
           Fill f;
       }
       Card[81] deck;
   }
   this() nothrow {
       auto colors = [EnumMembers!Color];
       auto numbers = [EnumMembers!Number];
       auto symbols = [EnumMembers!Symbol];
       auto fill = [EnumMembers!Fill];
       foreach (immutable i; 0 .. deck.length) {
           auto c = colors[i / 27];
           auto n = numbers[(i / 9) % 3];
           auto s = symbols[(i / 3) % 3];
           auto f = fill[i % 3];
           deck[i] = Card(c, n, s, f);
       }
   }


   // randomSample produces a sorted output that's convenient in our case
   // because we're printing to stout. Normally you would want to shuffle.
   immutable(Card)[] deal(in uint numCards) {
       enforce(numCards < deck.length, "number of cards too large");
       return assumeUnique(randomSample(deck[], numCards).array());
   }
   // The summed enums of valid sets are always zero or a multiple of 3
   bool validSet(in ref Card c1, in ref Card c2, in ref Card c3)
           pure nothrow {
        return !((c1.c + c2.c + c3.c) % 3 || (c1.n + c2.n + c3.n) % 3 ||
               (c1.s + c2.s + c3.s) % 3 || (c1.f + c2.f + c3.f) % 3);
   }
   immutable(Card)[3][] findSets(in Card[] cards) pure nothrow {
       auto len = cards.length;
       if (len >= 3) {
           typeof(return) sets;
           for (int i = 0; i < len - 2; i++) {
               for (int j = i + 1; j < len - 1; j++)
                   for (int k = j + 1; k < len; k++)
                       if (validSet(cards[i], cards[j], cards[k]))
                           sets ~= [cards[i], cards[j], cards[k]];
           }
           return assumeUnique(sets);
       }
       return null;
   }

}

class SetPuzzleDealer : SetDealer {

   enum NumCards {basic = 9, advanced = 12}
   override immutable(Card)[] deal(in uint numCards = NumCards.basic) {
       auto numSets = numCards / 2;
       typeof(return) cards;
       do {
           cards = super.deal(numCards);
       } while (findSets(cards).length != numSets);
       return assumeUnique(cards);
   }

}

void main() {

   auto dealer = new SetPuzzleDealer();
   auto cards = dealer.deal();
   writefln("\nDEALT %d CARDS:\n", cards.length);
   foreach (Unqual!(typeof(cards[0])) c; cards)
       writeln(c);
   auto sets = dealer.findSets(cards);
   auto len = sets.length;
   writefln("\nFOUND %d %s:\n", len, len == 1 ? "SET" : "SETS");
   foreach (set; sets) {
       foreach (Unqual!(typeof(set[0])) c; set)
           writeln(c);
       writeln();
   }

}</lang>

DEALT 9 CARDS:

Card(green, one, oval, solid)
Card(green, one, diamond, solid)
Card(green, one, squiggle, solid)
Card(green, two, squiggle, open)
Card(green, three, oval, open)
Card(green, three, diamond, solid)
Card(green, three, squiggle, striped)
Card(purple, two, squiggle, solid)
Card(red, one, squiggle, open)

FOUND 4 SETS:

Card(green, one, oval, solid)
Card(green, one, diamond, solid)
Card(green, one, squiggle, solid)

Card(green, one, squiggle, solid)
Card(green, two, squiggle, open)
Card(green, three, squiggle, striped)

Card(green, three, oval, open)
Card(green, three, diamond, solid)
Card(green, three, squiggle, striped)

Card(green, three, squiggle, striped)
Card(purple, two, squiggle, solid)
Card(red, one, squiggle, open)