Set puzzle: Difference between revisions

120,280 bytes added ,  3 months ago
m
(Updated D entry)
m (→‎{{header|Wren}}: Minor tidy)
 
(77 intermediate revisions by 33 users not shown)
Line 1:
{{task|Cards}} [[Category:Puzzles]]
{{omit from|GUISS}}
 
Set Puzzles are created with a deck of cards from the [[wp:Set (game)|Set Game™]]. 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 unique variation of the following four features: ''color, symbol, number and shading''.<br><br>
There are 81 cards in a deck.
Each card contains a unique variation of the following four features: ''color, symbol, number and shading''.
 
;* there are three colors:<br> '&nbsp;&nbsp;&nbsp;''red''', '''green''', or '''purple'''<br><br>
 
;* there are three symbols:<br> '&nbsp;&nbsp;&nbsp;''oval''', '''squiggle''', or '''diamond'''<br><br>
 
;* there is a number of symbols on the card:<br> '&nbsp;&nbsp;&nbsp;''one''', '''two''', or '''three'''<br><br>
 
;* there are three shadings:<br> '&nbsp;&nbsp;&nbsp;''solid''', '''open''', or '''striped'''<br><br>
 
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: [http://www.setgame.com/set/rules_basic.htm ''basic''] and [http://www.setgame.com/set/rules_advanced.htm ''advanced'']. The basic mode deals 9 cards, that contain exactly 4 sets; the advanced mode deals 12 cards that contain exactly 6 sets. When creating sets you may use the same card more than once.
 
When creating sets you may use the same card more than once.
;The task:
<br><br>
Is to write code that deals the cards (9 or 12, depending on selected mode) from a shuffled deck in which the total number of sets that could be found is 4 (or 6, respectively); and print the contents of the cards and the sets. For instance:
 
;Task
Write code that deals the cards (9 or 12, depending on selected mode) from a shuffled deck in which the total number of sets that could be found is 4 (or 6, respectively); and print the contents of the cards and the sets.
 
For instance:<br><br>
 
'''DEALT 9 CARDS:'''
Line 37 ⟶ 45:
 
:red, three, diamond, solid
<br>
 
'''CONTAINING 4 SETS:'''
 
Line 66 ⟶ 74:
 
:purple, three, oval, open
<br><br>
 
=={{header|Acornsoft Lisp}}==
 
<syntaxhighlight lang="lisp">
(setq numbers '(one two three))
(setq shadings '(solid open striped))
(setq colours '(red green purple))
(setq symbols '(oval squiggle diamond))
 
(defun play ((n-cards . 9))
(find-enough-sets n-cards (quotient n-cards 2)))
 
(defun find-enough-sets (n-cards enough (deal) (sets))
(loop
(setq deal (random-sample n-cards (deck)))
(setq sets (find-sets deal))
(while (lessp (length sets) enough)
(show-cards deal)
(printc)
(show-sets sets))))
 
(defun show-cards (cards)
(printc (length cards) '! cards)
(map printc cards))
 
(defun show-sets (sets)
(printc (length sets) '! sets)
(map '(lambda (set)
(printc)
(map printc set))
sets))
 
(defun find-sets (deal)
(keep-if is-set (combinations 3 deal)))
 
(defun is-set (cards)
(every feature-makes-set (transpose cards)))
 
(defun feature-makes-set (feature-values)
(or (all-same feature-values)
(all-different feature-values)))
 
(defun combinations (n items)
(cond
((zerop n) '(()))
((null items) '())
(t (append
(mapc '(lambda (c) (cons (car items) c))
(combinations (sub1 n) (cdr items)))
(combinations n (cdr items))))))
 
'( Making a deck )
 
(defun deck ()
' ( The deck has to be made only once )
(cond ((get 'deck 'cards))
(t (put 'deck 'cards (make-deck)))))
 
(defun make-deck ()
(add-feature numbers
(add-feature shadings
(add-feature colours
(add-feature symbols
(list '()))))))
 
(defun add-feature (values deck)
(flatmap '(lambda (value)
(mapc '(lambda (card) (cons value card))
deck))
values))
 
'( Utilities )
 
(defun all-same (values)
(every '(lambda (v) (eq v (car values)))
values))
 
(defun all-different (values)
(every '(lambda (v) (onep (count v values)))
values))
 
(defun count (v values (n . 0))
(loop (until (null values) n)
(cond ((eq (car values) v) (setq n (add1 n))))
(setq values (cdr values))))
(defun every (test suspects)
(or (null suspects)
(and (test (car suspects))
(every test (cdr suspects)))))
 
(defun transpose (rows)
(apply mapc (cons list rows)))
 
(defun reverse (list (result . ()))
(map '(lambda (e) (setq result (cons e result)))
list)
result)
 
(defun append (a b)
(reverse (reverse a) b))
 
(defun flatmap (_f_ _list_)
(cond ((null _list_) '())
(t (append (_f_ (car _list_))
(flatmap _f_ (cdr _list_))))))
 
(defun keep-if (_p_ _items_ (_to_keep_))
(map '(lambda (_i_)
(cond ((_p_ _i_)
(setq _to_keep_ (cons _i_ _to_keep_)))))
_items_)
(reverse _to_keep_))
</syntaxhighlight>
 
{{Out}}
 
Calling <code>(play)</code> will output:
 
<pre>
9 cards
(three open red oval)
(three solid green diamond)
(two solid red squiggle)
(one open red oval)
(two striped green oval)
(one striped red diamond)
(three solid purple oval)
(one solid purple oval)
(three solid purple diamond)
 
4 sets
 
(three open red oval)
(two solid red squiggle)
(one striped red diamond)
 
(three open red oval)
(two striped green oval)
(one solid purple oval)
 
(three solid green diamond)
(two solid red squiggle)
(one solid purple oval)
 
(one open red oval)
(two striped green oval)
(three solid purple oval)
</pre>
 
=={{header|Ada}}==
Line 71 ⟶ 229:
We start with the specification of a package "Set_Puzzle.
 
<langsyntaxhighlight Adalang="ada">package Set_Puzzle is
type Three is range 1..3;
Line 88 ⟶ 246:
-- calls Do_Something once for each set it finds.
end Set_Puzzle;</langsyntaxhighlight>
 
Now we implement the package "Set_Puzzle".
 
<langsyntaxhighlight Adalang="ada">with Ada.Numerics.Discrete_Random;
 
package body Set_Puzzle is
Line 169 ⟶ 327:
begin
Rand.Reset(R);
end Set_Puzzle;</langsyntaxhighlight>
 
Finally, we write the main program, using the above package. It reads two parameters from the command line. The first parameter describes the number of cards, the second one the number of sets. Thus, for the basic mode one has to call "puzzle 9 4", for the advanced mode "puzzle 12 6", but the program would support any other combination of parameters just as well.
 
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO, Set_Puzzle, Ada.Command_Line;
 
procedure Puzzle is
Line 222 ⟶ 380:
Print_Sets(Cards); -- print the sets
end Puzzle;</langsyntaxhighlight>
 
{{out}}
Line 254 ⟶ 412:
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight lang="autohotkey">; Generate deck; card encoding from Perl6Raku
Loop, 81
deck .= ToBase(A_Index-1, 3)+1111 ","
Line 357 ⟶ 515:
c%j% += 1
}
}</langsyntaxhighlight>
{{out|Sample output}}
<pre>Dealt 9 cards:
Line 437 ⟶ 595:
=={{header|C}}==
Brute force. Each card is a unique number in the range of [0,81]. Randomly deal a hand of cards until exactly the required number of sets are found.
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
 
Line 531 ⟶ 689:
 
return 0;
}</langsyntaxhighlight>
 
=={{header|C sharp}}==
{{works with|C sharp|8}}
<syntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using static System.Linq.Enumerable;
 
public static class SetPuzzle
{
static readonly Feature[] numbers = { (1, "One"), (2, "Two"), (3, "Three") };
static readonly Feature[] colors = { (1, "Red"), (2, "Green"), (3, "Purple") };
static readonly Feature[] shadings = { (1, "Open"), (2, "Striped"), (3, "Solid") };
static readonly Feature[] symbols = { (1, "Oval"), (2, "Squiggle"), (3, "Diamond") };
 
private readonly struct Feature
{
public Feature(int value, string name) => (Value, Name) = (value, name);
public int Value { get; }
public string Name { get; }
public static implicit operator int(Feature f) => f.Value;
public static implicit operator Feature((int value, string name) t) => new Feature(t.value, t.name);
public override string ToString() => Name;
}
 
private readonly struct Card : IEquatable<Card>
{
public Card(Feature number, Feature color, Feature shading, Feature symbol) =>
(Number, Color, Shading, Symbol) = (number, color, shading, symbol);
 
public Feature Number { get; }
public Feature Color { get; }
public Feature Shading { get; }
public Feature Symbol { get; }
 
public override string ToString() => $"{Number} {Color} {Shading} {Symbol}(s)";
public bool Equals(Card other) => Number == other.Number && Color == other.Color && Shading == other.Shading && Symbol == other.Symbol;
}
 
public static void Main() {
Card[] deck = (
from number in numbers
from color in colors
from shading in shadings
from symbol in symbols
select new Card(number, color, shading, symbol)
).ToArray();
var random = new Random();
 
Deal(deck, 9, 4, random);
Console.WriteLine();
Console.WriteLine();
Deal(deck, 12, 6, random);
}
 
static void Deal(Card[] deck, int size, int target, Random random) {
List<(Card a, Card b, Card c)> sets;
do {
Shuffle(deck, random.Next);
sets = (
from i in 0.To(size - 2)
from j in (i + 1).To(size - 1)
from k in (j + 1).To(size)
select (deck[i], deck[j], deck[k])
).Where(IsSet).ToList();
} while (sets.Count != target);
Console.WriteLine("The board:");
foreach (Card card in deck.Take(size)) Console.WriteLine(card);
Console.WriteLine();
Console.WriteLine("Sets:");
foreach (var s in sets) Console.WriteLine(s);
}
 
static void Shuffle<T>(T[] array, Func<int, int, int> rng) {
for (int i = 0; i < array.Length; i++) {
int r = rng(i, array.Length);
(array[r], array[i]) = (array[i], array[r]);
}
}
 
static bool IsSet((Card a, Card b, Card c) t) =>
AreSameOrDifferent(t.a.Number, t.b.Number, t.c.Number) &&
AreSameOrDifferent(t.a.Color, t.b.Color, t.c.Color) &&
AreSameOrDifferent(t.a.Shading, t.b.Shading, t.c.Shading) &&
AreSameOrDifferent(t.a.Symbol, t.b.Symbol, t.c.Symbol);
 
static bool AreSameOrDifferent(int a, int b, int c) => (a + b + c) % 3 == 0;
static IEnumerable<int> To(this int start, int end) => Range(start, end - start - 1);
}</syntaxhighlight>
{{out}}
<pre style="height:30ex;overflow:scroll">
The board:
Two Green Open Oval(s)
Three Green Open Diamond(s)
Two Red Open Oval(s)
One Purple Solid Oval(s)
Two Green Striped Squiggle(s)
Two Purple Open Oval(s)
Two Red Striped Squiggle(s)
Two Purple Solid Diamond(s)
Three Green Solid Diamond(s)
 
Sets:
(Two Green Open Oval(s), Two Red Open Oval(s), Two Purple Open Oval(s))
(Two Green Open Oval(s), Two Red Striped Squiggle(s), Two Purple Solid Diamond(s))
(Three Green Open Diamond(s), One Purple Solid Oval(s), Two Red Striped Squiggle(s))
(Two Red Open Oval(s), Two Green Striped Squiggle(s), Two Purple Solid Diamond(s))
 
 
The board:
One Purple Open Squiggle(s)
One Red Striped Diamond(s)
One Purple Solid Oval(s)
Three Purple Striped Squiggle(s)
Three Green Open Oval(s)
Two Purple Solid Squiggle(s)
One Red Open Diamond(s)
Two Purple Open Diamond(s)
Three Red Solid Diamond(s)
One Green Open Oval(s)
One Purple Solid Squiggle(s)
One Purple Solid Diamond(s)
 
Sets:
(One Purple Open Squiggle(s), Three Purple Striped Squiggle(s), Two Purple Solid Squiggle(s))
(One Purple Open Squiggle(s), One Red Open Diamond(s), One Green Open Oval(s))
(One Red Striped Diamond(s), Three Green Open Oval(s), Two Purple Solid Squiggle(s))
(One Red Striped Diamond(s), One Green Open Oval(s), One Purple Solid Squiggle(s))
(One Purple Solid Oval(s), Three Purple Striped Squiggle(s), Two Purple Open Diamond(s))
(Three Purple Striped Squiggle(s), Three Green Open Oval(s), Three Red Solid Diamond(s))</pre>
 
=={{header|C++}}==
{{trans|Java}}
<syntaxhighlight lang="cpp">
#include <time.h>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
 
enum color {
red, green, purple
};
enum symbol {
oval, squiggle, diamond
};
enum number {
one, two, three
};
enum shading {
solid, open, striped
};
class card {
public:
card( color c, symbol s, number n, shading h ) {
clr = c; smb = s; nbr = n; shd = h;
}
color getColor() {
return clr;
}
symbol getSymbol() {
return smb;
}
number getNumber() {
return nbr;
}
shading getShading() {
return shd;
}
std::string toString() {
std::string str = "[";
str += clr == red ? "red " : clr == green ? "green " : "purple ";
str += nbr == one ? "one " : nbr == two ? "two " : "three ";
str += smb == oval ? "oval " : smb == squiggle ? "squiggle " : "diamond ";
str += shd == solid ? "solid" : shd == open ? "open" : "striped";
return str + "]";
}
private:
color clr;
symbol smb;
number nbr;
shading shd;
};
typedef struct {
std::vector<size_t> index;
} set;
class setPuzzle {
public:
setPuzzle() {
for( size_t c = red; c <= purple; c++ ) {
for( size_t s = oval; s <= diamond; s++ ) {
for( size_t n = one; n <= three; n++ ) {
for( size_t h = solid; h <= striped; h++ ) {
card crd( static_cast<color> ( c ),
static_cast<symbol> ( s ),
static_cast<number> ( n ),
static_cast<shading>( h ) );
_cards.push_back( crd );
}
}
}
}
}
void create( size_t countCards, size_t countSets, std::vector<card>& cards, std::vector<set>& sets ) {
while( true ) {
sets.clear();
cards.clear();
std::random_shuffle( _cards.begin(), _cards.end() );
for( size_t f = 0; f < countCards; f++ ) {
cards.push_back( _cards.at( f ) );
}
for( size_t c1 = 0; c1 < cards.size() - 2; c1++ ) {
for( size_t c2 = c1 + 1; c2 < cards.size() - 1; c2++ ) {
for( size_t c3 = c2 + 1; c3 < cards.size(); c3++ ) {
if( testSet( &cards.at( c1 ), &cards.at( c2 ), &cards.at( c3 ) ) ) {
set s;
s.index.push_back( c1 ); s.index.push_back( c2 ); s.index.push_back( c3 );
sets.push_back( s );
}
}
}
}
if( sets.size() == countSets ) return;
}
}
private:
bool testSet( card* c1, card* c2, card* c3 ) {
int
c = ( c1->getColor() + c2->getColor() + c3->getColor() ) % 3,
s = ( c1->getSymbol() + c2->getSymbol() + c3->getSymbol() ) % 3,
n = ( c1->getNumber() + c2->getNumber() + c3->getNumber() ) % 3,
h = ( c1->getShading() + c2->getShading() + c3->getShading() ) % 3;
return !( c + s + n + h );
}
std::vector<card> _cards;
};
void displayCardsSets( std::vector<card>& cards, std::vector<set>& sets ) {
size_t cnt = 1;
std::cout << " ** DEALT " << cards.size() << " CARDS: **\n";
for( std::vector<card>::iterator i = cards.begin(); i != cards.end(); i++ ) {
std::cout << std::setw( 2 ) << cnt++ << ": " << ( *i ).toString() << "\n";
}
std::cout << "\n ** CONTAINING " << sets.size() << " SETS: **\n";
for( std::vector<set>::iterator i = sets.begin(); i != sets.end(); i++ ) {
for( size_t j = 0; j < ( *i ).index.size(); j++ ) {
std::cout << " " << std::setiosflags( std::ios::left ) << std::setw( 34 )
<< cards.at( ( *i ).index.at( j ) ).toString() << " : "
<< std::resetiosflags( std::ios::left ) << std::setw( 2 ) << ( *i ).index.at( j ) + 1 << "\n";
}
std::cout << "\n";
}
std::cout << "\n\n";
}
int main( int argc, char* argv[] ) {
srand( static_cast<unsigned>( time( NULL ) ) );
setPuzzle p;
std::vector<card> v9, v12;
std::vector<set> s4, s6;
p.create( 9, 4, v9, s4 );
p.create( 12, 6, v12, s6 );
displayCardsSets( v9, s4 );
displayCardsSets( v12, s6 );
return 0;
}
</syntaxhighlight>
{{out}}
<pre>
** DEALT 9 CARDS: **
1: [red three squiggle solid]
2: [purple three squiggle solid]
3: [red two diamond open]
4: [purple three oval striped]
5: [green one squiggle solid]
6: [green two diamond open]
7: [red one oval striped]
8: [green one diamond striped]
9: [purple one diamond open]
 
** CONTAINING 4 SETS: **
[red three squiggle solid] : 1
[red two diamond open] : 3
[red one oval striped] : 7
 
[purple three squiggle solid] : 2
[green two diamond open] : 6
[red one oval striped] : 7
 
[red two diamond open] : 3
[purple three oval striped] : 4
[green one squiggle solid] : 5
 
[green one squiggle solid] : 5
[red one oval striped] : 7
[purple one diamond open] : 9
 
 
 
** DEALT 12 CARDS: **
1: [green one diamond striped]
2: [red two squiggle solid]
3: [red three oval striped]
4: [red two diamond open]
5: [green three squiggle striped]
6: [red three squiggle striped]
7: [green two squiggle solid]
8: [purple two squiggle striped]
9: [purple one squiggle open]
10: [green one squiggle striped]
11: [purple three squiggle solid]
12: [red three squiggle open]
 
** CONTAINING 6 SETS: **
[green one diamond striped] : 1
[red three oval striped] : 3
[purple two squiggle striped] : 8
 
[red two squiggle solid] : 2
[green three squiggle striped] : 5
[purple one squiggle open] : 9
 
[green three squiggle striped] : 5
[purple three squiggle solid] : 11
[red three squiggle open] : 12
 
[red three squiggle striped] : 6
[green two squiggle solid] : 7
[purple one squiggle open] : 9
 
[red three squiggle striped] : 6
[purple two squiggle striped] : 8
[green one squiggle striped] : 10
 
[purple two squiggle striped] : 8
[purple one squiggle open] : 9
[purple three squiggle solid] : 11
</pre>
 
=={{header|Ceylon}}==
Add import ceylon.random "1.3.3" to your module.ceylon file
<syntaxhighlight lang="ceylon">import ceylon.random {
Random,
DefaultRandom
}
 
abstract class Feature() of Color | Symbol | NumberOfSymbols | Shading {}
 
abstract class Color()
of red | green | purple
extends Feature() {}
object red extends Color() {
string => "red";
}
object green extends Color() {
string => "green";
}
object purple extends Color() {
string => "purple";
}
 
abstract class Symbol()
of oval | squiggle | diamond
extends Feature() {}
object oval extends Symbol() {
string => "oval";
}
object squiggle extends Symbol() {
string => "squiggle";
}
object diamond extends Symbol() {
string => "diamond";
}
 
abstract class NumberOfSymbols()
of one | two | three
extends Feature() {}
object one extends NumberOfSymbols() {
string => "one";
}
object two extends NumberOfSymbols() {
string => "two";
}
object three extends NumberOfSymbols() {
string => "three";
}
 
abstract class Shading()
of solid | open | striped
extends Feature() {}
object solid extends Shading() {
string => "solid";
}
object open extends Shading() {
string => "open";
}
object striped extends Shading() {
string => "striped";
}
 
class Card(color, symbol, number, shading) {
shared Color color;
shared Symbol symbol;
shared NumberOfSymbols number;
shared Shading shading;
 
value plural => number == one then "" else "s";
string => "``number`` ``shading`` ``color`` ``symbol````plural``";
}
 
{Card*} deck = {
for(color in `Color`.caseValues)
for(symbol in `Symbol`.caseValues)
for(number in `NumberOfSymbols`.caseValues)
for(shading in `Shading`.caseValues)
Card(color, symbol, number, shading)
};
 
alias CardSet => [Card+];
 
Boolean validSet(CardSet cards) {
 
function allOrOne({Feature*} features) =>
let(uniques = features.distinct.size)
uniques == 3 || uniques == 1;
 
return allOrOne(cards*.color) &&
allOrOne(cards*.number) &&
allOrOne(cards*.shading) &&
allOrOne(cards*.symbol);
}
 
{CardSet*} findSets(Card* cards) =>
cards
.sequence()
.combinations(3)
.filter(validSet);
 
Random random = DefaultRandom();
 
class Mode of basic | advanced {
 
shared Integer numberOfCards;
shared Integer numberOfSets;
 
shared new basic {
numberOfCards = 9;
numberOfSets = 4;
}
 
shared new advanced {
numberOfCards = 12;
numberOfSets = 6;
}
}
 
[{Card*}, {CardSet*}] deal(Mode mode) {
value randomStream = random.elements(deck);
while(true) {
value cards = randomStream.distinct.take(mode.numberOfCards).sequence();
value sets = findSets(*cards);
if(sets.size == mode.numberOfSets) {
return [cards, sets];
}
}
}
 
shared void run() {
value [cards, sets] = deal(Mode.basic);
print("The cards dealt are:
");
cards.each(print);
print("
Containing the sets:
");
for(cardSet in sets) {
cardSet.each(print);
print("");
}
 
}</syntaxhighlight>
 
=={{header|Common Lisp}}==
{{trans|Acornsoft Lisp}}
 
<syntaxhighlight lang="lisp">
(defparameter numbers '(one two three))
(defparameter shadings '(solid open striped))
(defparameter colours '(red green purple))
(defparameter symbols '(oval squiggle diamond))
 
(defun play (&optional (n-cards 9))
(find-enough-sets n-cards (floor n-cards 2)))
 
(defun find-enough-sets (n-cards enough)
(loop
(let* ((deal (random-sample n-cards (deck)))
(sets (find-sets deal)))
(when (>= (length sets) enough)
(show-cards deal)
(show-sets sets)
(return t)))))
 
(defun show-cards (cards)
(format t "~D cards~%~{~(~{~10S~}~)~%~}~%"
(length cards) cards))
 
(defun show-sets (sets)
(format t "~D sets~2%~:{~(~@{~{~8S~}~%~}~)~%~}"
(length sets) sets))
 
(defun find-sets (deal)
(remove-if-not #'is-set (combinations 3 deal)))
 
(defun is-set (cards)
(every #'feature-makes-set (transpose cards)))
 
(defun feature-makes-set (feature-values)
(or (all-same feature-values)
(all-different feature-values)))
 
(defun combinations (n items)
(cond
((zerop n) '(()))
((null items) '())
(t (append
(mapcar (lambda (c) (cons (car items) c))
(combinations (1- n) (cdr items)))
(combinations n (cdr items))))))
 
;;; Making a deck
 
(defun deck ()
;; The deck has to be made only once
(or (get 'deck 'cards)
(setf (get 'deck 'cards) (make-deck))))
 
(defun make-deck ()
(add-feature numbers
(add-feature shadings
(add-feature colours
(add-feature symbols
(list '()))))))
 
(defun add-feature (values deck)
(mapcan (lambda (value)
(mapcar (lambda (card) (cons value card))
deck))
values))
 
;;; Utilities
 
(defun random-sample (n items)
(let ((len (length items))
(taken '()))
(dotimes (_ n)
(loop
(let ((i (random len)))
(unless (find i taken)
(setq taken (cons i taken))
(return)))))
(mapcar (lambda (i) (nth i items)) taken)))
 
(defun all-same (values)
(every #'eql values (rest values)))
 
(defun all-different (values)
(every (lambda (v) (= (count v values) 1))
values))
 
(defun transpose (rows)
(apply #'mapcar #'list rows))
</syntaxhighlight>
 
{{Out}}
 
Calling <code>(play 12)</code> will output:
 
<pre>
12 cards
two open red oval
three solid red squiggle
one striped red oval
three solid green squiggle
three solid green diamond
three solid red oval
one open purple squiggle
two solid red diamond
three open red squiggle
two striped green diamond
two striped red squiggle
three solid purple oval
 
6 sets
 
two open red oval
one striped red oval
three solid red oval
 
two open red oval
two solid red diamond
two striped red squiggle
 
three solid red squiggle
three solid green diamond
three solid purple oval
 
one striped red oval
two solid red diamond
three open red squiggle
 
three solid green squiggle
one open purple squiggle
two striped red squiggle
 
three solid red oval
one open purple squiggle
two striped green diamond
</pre>
 
=={{header|D}}==
===Basic Version===
<lang d>import std.stdio, std.random, std.array, std.conv, std.traits,
<syntaxhighlight lang="d">import std.stdio, std.random, std.array, std.conv, std.traits,
std.exception, std.range;
std.exception, std.range, std.algorithm;
 
const class SetDealer {
Line 629 ⟶ 1,405:
writefln("\nFOUND %d SET%s:", len, len == 1 ? "" : "S");
writefln("%(%(%s\n%)\n\n%)", sets);
}</langsyntaxhighlight>
{{out|Sample output}}
<pre>DEALT 9 CARDS:
Line 658 ⟶ 1,434:
immutable(Card)(purple, two, squiggle, solid)
immutable(Card)(purple, three, oval, open)</pre>
 
===Short Version===
This requires the third solution module of the Combinations Task.
<syntaxhighlight lang="d">void main() {
import std.stdio, std.algorithm, std.range, std.random, combinations3;
 
enum nDraw = 9, nGoal = nDraw / 2;
auto deck = cartesianProduct("red green purple".split,
"one two three".split,
"oval squiggle diamond".split,
"solid open striped".split).array;
 
retry:
auto draw = deck.randomSample(nDraw).map!(t => [t[]]).array;
const sets = draw.combinations(3).filter!(cs => cs.dup
.transposed.all!(t => t.array.sort().uniq.count % 2)).array;
if (sets.length != nGoal)
goto retry;
 
writefln("Dealt %d cards:\n%(%-(%8s %)\n%)\n", draw.length, draw);
writefln("Containing:\n%(%(%-(%8s %)\n%)\n\n%)", sets);
}</syntaxhighlight>
{{out}}
<pre>Dealt 9 cards:
purple one oval solid
red three squiggle solid
purple three diamond solid
green one squiggle open
green two squiggle open
red two oval striped
purple one squiggle striped
purple two squiggle striped
green three diamond striped
 
Containing:
purple three diamond solid
green one squiggle open
red two oval striped
 
red three squiggle solid
green two squiggle open
purple one squiggle striped
 
red three squiggle solid
green one squiggle open
purple two squiggle striped
 
red two oval striped
purple one squiggle striped
green three diamond striped</pre>
 
=={{header|EasyLang}}==
<syntaxhighlight>
attr$[][] &= [ "one " "two " "three" ]
attr$[][] &= [ "solid " "striped" "open " ]
attr$[][] &= [ "red " "green " "purple" ]
attr$[][] &= [ "diamond" "oval" "squiggle" ]
#
subr init
for card = 0 to 80
pack[] &= card
.
.
proc card2attr card . attr[] .
attr[] = [ ]
for i to 4
attr[] &= card mod 3 + 1
card = card div 3
.
.
proc printcards cards[] . .
for card in cards[]
card2attr card attr[]
for i to 4
write attr$[i][attr[i]] & " "
.
print ""
.
print ""
.
proc getsets . cards[] set[] .
set[] = [ ]
for i to len cards[]
card2attr cards[i] a[]
for j = i + 1 to len cards[]
card2attr cards[j] b[]
for k = j + 1 to len cards[]
card2attr cards[k] c[]
ok = 1
for at to 4
s = a[at] + b[at] + c[at]
if s <> 3 and s <> 6 and s <> 9
ok = 0
.
.
if ok = 1
set[] &= cards[i]
set[] &= cards[j]
set[] &= cards[k]
.
.
.
.
.
proc run ncards nsets . .
#
repeat
init
cards[] = [ ]
for i to ncards
ind = random len pack[]
cards[] &= pack[ind]
pack[ind] = pack[len pack[]]
len pack[] -1
.
getsets cards[] set[]
until len set[] = 3 * nsets
.
print "Cards:"
printcards cards[]
print "Sets:"
for i = 1 step 3 to 3 * nsets - 2
printcards [ set[i] set[i + 1] set[i + 2] ]
.
.
run 9 4
print " --------------------------"
run 12 6
</syntaxhighlight>
 
=={{header|EchoLisp}}==
<syntaxhighlight lang="scheme">
(require 'list)
 
;; a card is a vector [id color number symb shading], 0 <= id < 81
(define (make-deck (id -1))
(for*/vector(
[ color '(red green purple)]
[ number '(one two three)]
[ symb '( oval squiggle diamond)]
[ shading '(solid open striped)]) (++ id) (vector id color number symb shading)))
(define DECK (make-deck))
 
;; pre-generate 531441 ordered triples, among which 6561 are winners
(define TRIPLES (make-vector (* 81 81 81)))
(define (make-triples )
(for* ((i 81)(j 81)(k 81))
(vector-set! TRIPLES (+ i (* 81 j) (* 6561 k))
(check-set [DECK i] [DECK j] [DECK k]))))
;; a deal is a list of cards id's.
(define (show-deal deal)
(for ((card deal)) (writeln [DECK card]))
(for ((set (combinations deal 3)))
(when
(check-set [DECK (first set)] [DECK (second set)][DECK (third set)])
(writeln 'winner set))))
;; rules of game here
(define (check-set cards: a b c)
(for ((i (in-range 1 5))) ;; each feature
#:continue (and (= [a i] [b i]) (= [a i] [c i]))
#:continue (and (!= [a i] [b i]) (!= [a i] [c i]) (!= [b i][c i]))
#:break #t => #f ))
;; sets = list of triples (card-id card-id card-id)
(define (count-sets sets )
(for/sum ((s sets))
(if [TRIPLES ( + (first s) (* 81 (second s)) (* 6561 (third s)))]
1 0)))
 
;; task
(make-triples)
 
(define (play (n 9) (cmax 4) (sets) (deal))
(while #t
(set! deal (take (shuffle (iota 81)) n))
(set! sets (combinations deal 3))
#:break (= (count-sets sets) cmax) => (show-deal deal)
))
 
</syntaxhighlight>
{{out}}
<pre>
(play) ;; The 9-4 game by default
#( 13 red two squiggle open)
#( 54 purple one oval solid)
#( 2 red one oval striped)
#( 15 red two diamond solid)
#( 53 green three diamond striped)
#( 48 green three squiggle solid)
#( 41 green two squiggle striped)
#( 66 purple two squiggle solid)
#( 64 purple two oval open)
winner (13 54 53)
winner (13 41 66)
winner (54 15 48)
winner (15 41 64)
;; 10 deals
 
(play 12 6)
#( 43 green two diamond open)
#( 16 red two diamond open)
#( 79 purple three diamond open)
#( 63 purple two oval solid)
#( 60 purple one diamond solid)
#( 75 purple three squiggle solid)
#( 64 purple two oval open)
#( 71 purple two diamond striped)
#( 67 purple two squiggle open)
#( 34 green one diamond open)
#( 59 purple one squiggle striped)
#( 54 purple one oval solid)
winner (16 79 34)
winner (79 63 59)
winner (79 60 71)
winner (63 60 75)
winner (63 71 67)
winner (75 67 59)
;; 31 deals
 
;; the (9 6) game is more difficult
#( 11 red two oval striped)
#( 9 red two oval solid)
#( 26 red three diamond striped)
#( 5 red one squiggle striped)
#( 60 purple one diamond solid)
#( 43 green two diamond open)
#( 10 red two oval open)
#( 67 purple two squiggle open)
#( 48 green three squiggle solid)
winner (11 9 10)
winner (11 26 5)
winner (9 60 48)
winner (26 60 43)
winner (5 67 48)
winner (43 10 67)
;; 17200 deals
</pre>
 
=={{header|Elixir}}==
{{trans|Ruby}}
<syntaxhighlight lang="elixir">defmodule RC do
def set_puzzle(deal, goal) do
{puzzle, sets} = get_puzzle_and_answer(deal, goal, produce_deck)
IO.puts "Dealt #{length(puzzle)} cards:"
print_cards(puzzle)
IO.puts "Containing #{length(sets)} sets:"
Enum.each(sets, fn set -> print_cards(set) end)
end
defp get_puzzle_and_answer(hand_size, num_sets_goal, deck) do
hand = Enum.take_random(deck, hand_size)
sets = get_all_sets(hand)
if length(sets) == num_sets_goal do
{hand, sets}
else
get_puzzle_and_answer(hand_size, num_sets_goal, deck)
end
end
defp get_all_sets(hand) do
Enum.filter(comb(hand, 3), fn candidate ->
List.flatten(candidate)
|> Enum.group_by(&(&1))
|> Map.values
|> Enum.all?(fn v -> length(v) != 2 end)
end)
end
defp print_cards(cards) do
Enum.each(cards, fn card ->
:io.format " ~-8s ~-8s ~-8s ~-8s~n", card
end)
IO.puts ""
end
@colors ~w(red green purple)a
@symbols ~w(oval squiggle diamond)a
@numbers ~w(one two three)a
@shadings ~w(solid open striped)a
defp produce_deck do
for color <- @colors, symbol <- @symbols, number <- @numbers, shading <- @shadings,
do: [color, symbol, number, shading]
end
defp comb(_, 0), do: [[]]
defp comb([], _), do: []
defp comb([h|t], m) do
(for l <- comb(t, m-1), do: [h|l]) ++ comb(t, m)
end
end
 
RC.set_puzzle(9, 4)
RC.set_puzzle(12, 6)</syntaxhighlight>
 
{{out}}
<pre>
Dealt 9 cards:
green oval one open
red oval one open
red oval two open
green diamond two striped
green diamond three open
green diamond one open
purple squiggle one open
red oval three solid
red oval three open
 
Containing 4 sets:
red oval one open
red oval two open
red oval three open
 
red oval one open
green diamond one open
purple squiggle one open
 
red oval two open
green diamond three open
purple squiggle one open
 
green diamond two striped
purple squiggle one open
red oval three solid
 
Dealt 12 cards:
purple oval one open
purple diamond two open
red oval three striped
purple diamond three striped
purple oval one solid
red oval two open
green diamond three open
green squiggle one solid
green oval three striped
red diamond two solid
red diamond one solid
green squiggle three striped
 
Containing 6 sets:
purple oval one open
red diamond two solid
green squiggle three striped
 
purple diamond two open
red oval three striped
green squiggle one solid
 
red oval three striped
purple diamond three striped
green squiggle three striped
 
purple diamond three striped
red oval two open
green squiggle one solid
 
purple oval one solid
red oval two open
green oval three striped
 
purple oval one solid
green squiggle one solid
red diamond one solid
</pre>
 
=={{header|Erlang}}==
Until a better solution is found this is one.
<syntaxhighlight lang="erlang">
<lang Erlang>
-module( set ).
 
Line 745 ⟶ 1,888:
make_sets_acc( true, Set, Sets ) -> [Set | Sets];
make_sets_acc( false, _Set, Sets ) -> Sets.
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 805 ⟶ 1,948:
 
=={{header|F Sharp|F#}}==
<langsyntaxhighlight lang="fsharp">open System
 
type Number = One | Two | Three
Line 886 ⟶ 2,029:
solve 12 6
 
playGame()</langsyntaxhighlight>
Output:
<pre>
Line 955 ⟶ 2,098:
Two Red Oval Open
Three Red Oval Solid</pre>
 
=={{header|Factor}}==
<syntaxhighlight lang="factor">USING: arrays backtrack combinators.short-circuit formatting
fry grouping io kernel literals math.combinatorics math.matrices
prettyprint qw random sequences sets ;
IN: rosetta-code.set-puzzle
 
CONSTANT: deck $[
[
qw{ red green purple } amb-lazy
qw{ one two three } amb-lazy
qw{ oval squiggle diamond } amb-lazy
qw{ solid open striped } amb-lazy 4array
] bag-of
]
 
: valid-category? ( seq -- ? )
{ [ all-equal? ] [ all-unique? ] } 1|| ;
 
: valid-set? ( seq -- ? )
[ valid-category? ] column-map t [ and ] reduce ;
 
: find-sets ( seq -- seq )
3 <combinations> [ valid-set? ] filter ;
 
: deal-hand ( m n -- seq valid? )
[ deck swap sample ] dip over find-sets length = ;
 
: find-valid-hand ( m n -- seq )
[ f ] 2dip '[ drop _ _ deal-hand not ] loop ;
 
: set-puzzle ( m n -- )
[ find-valid-hand ] 2keep
[ "Dealt %d cards:\n" printf simple-table. nl ]
[
"Containing %d sets:\n" printf find-sets
{ { " " " " " " " " } } join simple-table. nl
] bi-curry* bi ;
 
: main ( -- )
9 4 set-puzzle
12 6 set-puzzle ;
 
MAIN: main</syntaxhighlight>
{{out}}
<pre style="height:65ex">
Dealt 9 cards:
purple one diamond striped
purple three squiggle open
purple one oval solid
green two squiggle striped
red one oval striped
green three oval solid
purple three diamond striped
red two oval striped
purple two diamond striped
 
Containing 4 sets:
purple one diamond striped
purple three diamond striped
purple two diamond striped
purple three squiggle open
purple one oval solid
purple two diamond striped
green two squiggle striped
red one oval striped
purple three diamond striped
green two squiggle striped
red two oval striped
purple two diamond striped
 
Dealt 12 cards:
green one oval striped
red two squiggle striped
red two diamond open
purple two oval solid
green three squiggle open
purple one squiggle striped
purple two squiggle open
red two squiggle solid
red three oval open
purple one oval solid
red one diamond striped
red two oval striped
 
Containing 6 sets:
green one oval striped
purple two oval solid
red three oval open
green one oval striped
purple one squiggle striped
red one diamond striped
red two diamond open
red two squiggle solid
red two oval striped
purple two oval solid
green three squiggle open
red one diamond striped
green three squiggle open
purple one squiggle striped
red two squiggle solid
red two squiggle solid
red three oval open
red one diamond striped
</pre>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 965 ⟶ 2,221:
)
 
varconst (
number = [3]string{"1", "2", "3"}
color = [3]string{"red", "green", "purple"}
shade = [3]string{"solid", "open", "striped"}
shape = [3]string{"oval", "squiggle", "diamond"}
)
 
Line 984 ⟶ 2,240:
func main() {
rand.Seed(time.Now().Unix())
basic()
advanced()
}
 
func basic() {
game("Basic", 9, 4)
}
 
func advanced() {
game("Advanced", 12, 6)
}
Line 1,018 ⟶ 2,266:
for _, c3 := range d[:j] {
for f := card(1); f < 81; f *= 3 {
if (c1/f%3 + c2/f%3 + c3/f%3) % 3 != 0 {
continue l3 // not a set
}
Line 1,036 ⟶ 2,284:
fmt.Println("Sets:")
for _, s := range found {
fmt.PrintlnPrintf(" %s\n %s\n %s\n", s[0],s[1],s[2])
fmt.Println(" ", s[1])
fmt.Println(" ", s[2])
fmt.Println()
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 1,110 ⟶ 2,355:
1 green striped squiggle
1 red open oval
</pre>
 
=={{header|Haskell}}==
<syntaxhighlight lang="haskell">import Control.Monad.State
(State, evalState, replicateM, runState, state)
import System.Random (StdGen, newStdGen, randomR)
import Data.List (find, nub, sort)
 
combinations :: Int -> [a] -> [[a]]
combinations 0 _ = [[]]
combinations _ [] = []
combinations k (y:ys) = map (y :) (combinations (k - 1) ys) ++ combinations k ys
 
data Color
= Red
| Green
| Purple
deriving (Show, Enum, Bounded, Ord, Eq)
 
data Symbol
= Oval
| Squiggle
| Diamond
deriving (Show, Enum, Bounded, Ord, Eq)
 
data Count
= One
| Two
| Three
deriving (Show, Enum, Bounded, Ord, Eq)
 
data Shading
= Solid
| Open
| Striped
deriving (Show, Enum, Bounded, Ord, Eq)
 
data Card = Card
{ color :: Color
, symbol :: Symbol
, count :: Count
, shading :: Shading
} deriving (Show)
 
-- Identify a set of three cards by counting all attribute types.
-- if each count is 3 or 1 ( not 2 ) the the cards compose a set.
isSet :: [Card] -> Bool
isSet cs =
let total = length . nub . sort . flip map cs
in notElem 2 [total color, total symbol, total count, total shading]
 
-- Get a random card from a deck. Returns the card and removes it from the deck.
getCard :: State (StdGen, [Card]) Card
getCard =
state $
\(gen, cs) ->
let (i, newGen) = randomR (0, length cs - 1) gen
(a, b) = splitAt i cs
in (head b, (newGen, a ++ tail b))
 
-- Get a hand of cards. Starts with new deck and then removes the
-- appropriate number of cards from that deck.
getHand :: Int -> State StdGen [Card]
getHand n =
state $
\gen ->
let az = [minBound .. maxBound]
deck =
[ Card co sy ct sh
| co <- az
, sy <- az
, ct <- az
, sh <- az ]
(a, (newGen, _)) = runState (replicateM n getCard) (gen, deck)
in (a, newGen)
 
-- Get an unbounded number of hands of the appropriate number of cards.
getManyHands :: Int -> State StdGen [[Card]]
getManyHands n = (sequence . repeat) (getHand n)
 
-- Deal out hands of the appropriate size until one with the desired number
-- of sets is found. then print the hand and the sets.
showSolutions :: Int -> Int -> IO ()
showSolutions cardCount solutionCount = do
putStrLn $
"Showing hand of " ++
show cardCount ++ " cards with " ++ show solutionCount ++ " solutions."
gen <- newStdGen
let Just z =
find ((solutionCount ==) . length . filter isSet . combinations 3) $
evalState (getManyHands cardCount) gen
mapM_ print z
putStrLn ""
putStrLn "Solutions:"
mapM_ putSet $ filter isSet $ combinations 3 z
where
putSet st = do
mapM_ print st
putStrLn ""
 
-- Show a hand of 9 cards with 4 solutions
-- and a hand of 12 cards with 6 solutions.
main :: IO ()
main = do
showSolutions 9 4
showSolutions 12 6</syntaxhighlight>
{{out}}
<pre style="font-size:80%">Showing hand of 9 cards with 4 solutions.
Card {color = Red, symbol = Diamond, count = Two, shading = Open}
Card {color = Purple, symbol = Diamond, count = Two, shading = Open}
Card {color = Red, symbol = Oval, count = Two, shading = Open}
Card {color = Green, symbol = Squiggle, count = Two, shading = Striped}
Card {color = Red, symbol = Squiggle, count = Two, shading = Open}
Card {color = Red, symbol = Diamond, count = One, shading = Striped}
Card {color = Green, symbol = Diamond, count = Three, shading = Solid}
Card {color = Purple, symbol = Squiggle, count = One, shading = Solid}
Card {color = Purple, symbol = Oval, count = Three, shading = Striped}
 
Solutions:
Card {color = Red, symbol = Diamond, count = Two, shading = Open}
Card {color = Red, symbol = Oval, count = Two, shading = Open}
Card {color = Red, symbol = Squiggle, count = Two, shading = Open}
 
Card {color = Purple, symbol = Diamond, count = Two, shading = Open}
Card {color = Red, symbol = Diamond, count = One, shading = Striped}
Card {color = Green, symbol = Diamond, count = Three, shading = Solid}
 
Card {color = Purple, symbol = Diamond, count = Two, shading = Open}
Card {color = Purple, symbol = Squiggle, count = One, shading = Solid}
Card {color = Purple, symbol = Oval, count = Three, shading = Striped}
 
Card {color = Green, symbol = Squiggle, count = Two, shading = Striped}
Card {color = Red, symbol = Diamond, count = One, shading = Striped}
Card {color = Purple, symbol = Oval, count = Three, shading = Striped}
 
Showing hand of 12 cards with 6 solutions.
Card {color = Purple, symbol = Oval, count = Two, shading = Solid}
Card {color = Green, symbol = Squiggle, count = Two, shading = Striped}
Card {color = Purple, symbol = Diamond, count = Two, shading = Open}
Card {color = Green, symbol = Squiggle, count = One, shading = Open}
Card {color = Green, symbol = Oval, count = Two, shading = Open}
Card {color = Green, symbol = Oval, count = One, shading = Open}
Card {color = Green, symbol = Squiggle, count = Three, shading = Solid}
Card {color = Red, symbol = Diamond, count = Two, shading = Open}
Card {color = Green, symbol = Diamond, count = Two, shading = Open}
Card {color = Green, symbol = Oval, count = One, shading = Solid}
Card {color = Red, symbol = Squiggle, count = Two, shading = Open}
Card {color = Green, symbol = Oval, count = Three, shading = Open}
 
Solutions:
Card {color = Purple, symbol = Oval, count = Two, shading = Solid}
Card {color = Green, symbol = Squiggle, count = Two, shading = Striped}
Card {color = Red, symbol = Diamond, count = Two, shading = Open}
 
Card {color = Green, symbol = Squiggle, count = Two, shading = Striped}
Card {color = Green, symbol = Squiggle, count = One, shading = Open}
Card {color = Green, symbol = Squiggle, count = Three, shading = Solid}
 
Card {color = Purple, symbol = Diamond, count = Two, shading = Open}
Card {color = Green, symbol = Oval, count = Two, shading = Open}
Card {color = Red, symbol = Squiggle, count = Two, shading = Open}
 
Card {color = Purple, symbol = Diamond, count = Two, shading = Open}
Card {color = Red, symbol = Diamond, count = Two, shading = Open}
Card {color = Green, symbol = Diamond, count = Two, shading = Open}
 
Card {color = Green, symbol = Squiggle, count = One, shading = Open}
Card {color = Green, symbol = Diamond, count = Two, shading = Open}
Card {color = Green, symbol = Oval, count = Three, shading = Open}
 
Card {color = Green, symbol = Oval, count = Two, shading = Open}
Card {color = Green, symbol = Oval, count = One, shading = Open}
Card {color = Green, symbol = Oval, count = Three, shading = Open}
 
</pre>
 
=={{header|J}}==
'''Solution:'''
<langsyntaxhighlight lang="j">require 'stats/base'
 
Number=: ;:'one two three'
Line 1,125 ⟶ 2,544:
drawRandom=: ] {~ (? #)
isSet=: *./@:(1 3 e.~ [: #@~."1 |:)"2
getSets=: ([: (] #~ isSet) ] {~ 3 comb #)
countSets=: #@:getSets
 
Line 1,137 ⟶ 2,556:
echo LF,'Found ',(":target),' Sets:'
echo sayCards sort"2 getSets Hand
)</langsyntaxhighlight>
 
'''Example:'''
<langsyntaxhighlight lang="j"> set_puzzle 9
Dealt 9 Cards:
one, red, solid, oval
Line 1,167 ⟶ 2,586:
three, red, open, oval
three, green, solid, oval
three, purple, striped, oval </langsyntaxhighlight>
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">import java.util.*;
import org.apache.commons.lang3.ArrayUtils;
 
public class SetPuzzle {
 
enum Color {
 
GREEN(0), PURPLE(1), RED(2);
 
Line 1,185 ⟶ 2,604:
 
enum Number {
 
ONE(0), TWO(1), THREE(2);
 
Line 1,194 ⟶ 2,614:
 
enum Symbol {
 
OVAL(0), DIAMOND(1), SQUIGGLE(2);
 
Line 1,203 ⟶ 2,624:
 
enum Fill {
 
OPEN(0), STRIPED(1), SOLID(2);
 
Line 1,212 ⟶ 2,634:
 
private static class Card implements Comparable<Card> {
 
Color c;
Number n;
Line 1,217 ⟶ 2,640:
Fill f;
 
@Override
public String toString() {
return String.format("[Card: %s, %s, %s, %s]", c, n, s, f);
}
 
@Override
public int compareTo(Card o) {
return (c.val - o.c.val) * 10 + (n.val - o.n.val);
}
}
 
private static Card[] deck;
 
Line 1,251 ⟶ 2,675:
do {
Collections.shuffle(Arrays.asList(deck));
cards = ArrayUtilsArrays.subarraycopyOfRange(deck, 0, numCards);
cnt = 0;
 
Line 1,295 ⟶ 2,719:
return tot == 0;
}
}</langsyntaxhighlight>
<pre>GIVEN 12 CARDS:
 
Line 1,336 ⟶ 2,760:
[Card: RED, THREE, OVAL, STRIPED]
[Card: PURPLE, TWO, SQUIGGLE, SOLID]</pre>
 
=={{header|Julia}}==
Plays one basic game and one advanced game.
<syntaxhighlight lang="julia">using Random, IterTools, Combinatorics
 
function SetGameTM(basic = true)
drawsize = basic ? 9 : 12
setsneeded = div(drawsize, 2)
setsof3 = Vector{Vector{NTuple{4, String}}}()
draw = Vector{NTuple{4, String}}()
deck = collect(Iterators.product(["red", "green", "purple"], ["one", "two", "three"],
["oval", "squiggle", "diamond"], ["solid", "open", "striped"]))
while length(setsof3) != setsneeded
empty!(draw)
empty!(setsof3)
map(x -> push!(draw, x), shuffle(deck)[1:drawsize])
for threecards in combinations(draw, 3)
canuse = true
for i in 1:4
u = length(unique(map(x->x[i], threecards)))
if u != 3 && u != 1
canuse = false
end
end
if canuse
push!(setsof3, threecards)
end
end
end
println("Dealt $drawsize cards:")
for card in draw
println(" $card")
end
println("\nFormed these cards into $setsneeded sets:")
for set in setsof3
for card in set
println(" $card")
end
println()
end
end
 
SetGameTM()
SetGameTM(false)
</syntaxhighlight> {{output}} <pre>
Dealt 9 cards:
("green", "one", "oval", "open")
("green", "three", "diamond", "open")
("purple", "one", "diamond", "striped")
("purple", "three", "oval", "solid")
("red", "two", "diamond", "open")
("red", "one", "oval", "striped")
("green", "one", "squiggle", "striped")
("green", "two", "oval", "solid")
("purple", "two", "squiggle", "open")
Formed these cards into 4 sets:
("green", "three", "diamond", "open")
("green", "one", "squiggle", "striped")
("green", "two", "oval", "solid")
("purple", "one", "diamond", "striped")
("purple", "three", "oval", "solid")
("purple", "two", "squiggle", "open")
("purple", "one", "diamond", "striped")
("red", "one", "oval", "striped")
("green", "one", "squiggle", "striped")
("purple", "three", "oval", "solid")
("red", "two", "diamond", "open")
("green", "one", "squiggle", "striped")
Dealt 12 cards:
("red", "one", "squiggle", "open")
("green", "one", "diamond", "striped")
("red", "two", "oval", "solid")
("green", "three", "squiggle", "striped")
("green", "three", "squiggle", "open")
("red", "one", "oval", "solid")
("purple", "two", "oval", "striped")
("green", "two", "oval", "striped")
("green", "three", "oval", "open")
("purple", "two", "diamond", "open")
("purple", "three", "diamond", "striped")
("purple", "two", "squiggle", "solid")
Formed these cards into 6 sets:
("red", "one", "squiggle", "open")
("green", "three", "squiggle", "striped")
("purple", "two", "squiggle", "solid")
("red", "one", "squiggle", "open")
("green", "three", "oval", "open")
("purple", "two", "diamond", "open")
("green", "one", "diamond", "striped")
("green", "three", "squiggle", "striped")
("green", "two", "oval", "striped")
("green", "three", "squiggle", "striped")
("red", "one", "oval", "solid")
("purple", "two", "diamond", "open")
("red", "one", "oval", "solid")
("purple", "two", "oval", "striped")
("green", "three", "oval", "open")
("purple", "two", "oval", "striped")
("purple", "two", "diamond", "open")
("purple", "two", "squiggle", "solid")
</pre>
 
=={{header|Kotlin}}==
<syntaxhighlight lang="scala">// version 1.1.3
 
import java.util.Collections.shuffle
 
enum class Color { RED, GREEN, PURPLE }
enum class Symbol { OVAL, SQUIGGLE, DIAMOND }
enum class Number { ONE, TWO, THREE }
enum class Shading { SOLID, OPEN, STRIPED }
enum class Degree { BASIC, ADVANCED }
 
class Card(
val color: Color,
val symbol: Symbol,
val number: Number,
val shading: Shading
) : Comparable<Card> {
 
private val value =
color.ordinal * 27 + symbol.ordinal * 9 + number.ordinal * 3 + shading.ordinal
override fun compareTo(other: Card) = value.compareTo(other.value)
 
override fun toString() = (
color.name.padEnd(8) +
symbol.name.padEnd(10) +
number.name.padEnd(7) +
shading.name.padEnd(7)
).toLowerCase()
 
companion object {
val zero = Card(Color.RED, Symbol.OVAL, Number.ONE, Shading.SOLID)
}
}
 
fun createDeck() =
List<Card>(81) {
val col = Color.values() [it / 27]
val sym = Symbol.values() [it / 9 % 3]
val num = Number.values() [it / 3 % 3]
val shd = Shading.values()[it % 3]
Card(col, sym, num, shd)
}
 
fun playGame(degree: Degree) {
val deck = createDeck()
val nCards = if (degree == Degree.BASIC) 9 else 12
val nSets = nCards / 2
val sets = Array(nSets) { Array(3) { Card.zero } }
var hand: Array<Card>
outer@ while (true) {
shuffle(deck)
hand = deck.take(nCards).toTypedArray()
var count = 0
for (i in 0 until hand.size - 2) {
for (j in i + 1 until hand.size - 1) {
for (k in j + 1 until hand.size) {
val trio = arrayOf(hand[i], hand[j], hand[k])
if (isSet(trio)) {
sets[count++] = trio
if (count == nSets) break@outer
}
}
}
}
}
hand.sort()
println("DEALT $nCards CARDS:\n")
println(hand.joinToString("\n"))
println("\nCONTAINING $nSets SETS:\n")
for (s in sets) {
s.sort()
println(s.joinToString("\n"))
println()
}
}
 
fun isSet(trio: Array<Card>): Boolean {
val r1 = trio.sumBy { it.color.ordinal } % 3
val r2 = trio.sumBy { it.symbol.ordinal } % 3
val r3 = trio.sumBy { it.number.ordinal } % 3
val r4 = trio.sumBy { it.shading.ordinal } % 3
return (r1 + r2 + r3 + r4) == 0
}
 
fun main(args: Array<String>) {
playGame(Degree.BASIC)
println()
playGame(Degree.ADVANCED)
}</syntaxhighlight>
 
Sample output:
<pre>
DEALT 9 CARDS:
 
red oval three solid
red diamond two solid
green oval one open
green oval three open
green squiggle one open
green diamond one open
purple oval three striped
purple squiggle three solid
purple diamond two striped
 
CONTAINING 4 SETS:
 
red oval three solid
green squiggle one open
purple diamond two striped
 
red oval three solid
green oval three open
purple oval three striped
 
green oval one open
green squiggle one open
green diamond one open
 
red diamond two solid
green squiggle one open
purple oval three striped
 
 
DEALT 12 CARDS:
 
red squiggle two solid
red diamond two solid
red diamond two open
red diamond two striped
green oval one open
green oval three solid
green oval three open
green squiggle one solid
green diamond one striped
purple oval one solid
purple oval three open
purple squiggle one striped
 
CONTAINING 6 SETS:
 
red diamond two open
green oval three solid
purple squiggle one striped
 
red diamond two solid
red diamond two open
red diamond two striped
 
red diamond two solid
green oval three open
purple squiggle one striped
 
red squiggle two solid
green diamond one striped
purple oval three open
 
green oval one open
green squiggle one solid
green diamond one striped
 
red diamond two striped
green squiggle one solid
purple oval three open
</pre>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
A simple brute force approach. This code highlights two things: 1) a few of Mathematica's "higher-level" functions such as Tuples and Subsets and 2) the straightforwardness enabled by the language's "dynamic typing" (more precisely, its symbolic semantics) and its usage of lists for everything (in this particular example, the fact that functions such as Tuples and Entropy can be used on lists with arbitrary content).
 
<syntaxhighlight lang="mathematica">colors = {Red, Green, Purple};
symbols = {"0", "\[TildeTilde]", "\[Diamond]"};
numbers = {1, 2, 3};
shadings = {"\[FilledSquare]", "\[Square]", "\[DoublePrime]"};
 
validTripleQ[l_List] := Entropy[l] != Entropy[{1, 1, 2}];
validSetQ[cards_List] := And @@ (validTripleQ /@ Transpose[cards]);
 
allCards = Tuples[{colors, symbols, numbers, shadings}];
 
deal[{numDeal_, setNum_}] := Module[{cards, count = 0},
While[count != setNum,
cards = RandomSample[allCards, numDeal];
count = Count[Subsets[cards, {3}], _?validSetQ]];
cards];
Row[{Style[#2, #1], #3, #4}] & @@@ deal[{9, 4}]</syntaxhighlight>
 
=={{header|Nim}}==
<syntaxhighlight lang="nim">import algorithm, math, random, sequtils, strformat, strutils
 
type
 
# Card features.
Number {.pure.} = enum One, Two, Three
Color {.pure.} = enum Red, Green, Purple
Symbol {.pure.} = enum Oval, Squiggle, Diamond
Shading {.pure.} = enum Solid, Open, Striped
 
# Cards and list of cards.
Card = tuple[number: Number; color: Color; symbol: Symbol; shading: Shading]
Triplet = array[3, Card]
Deck = array[81, Card]
 
# Game level.
Level {.pure.} = enum Basic = "basic", Advanced = "advanced"
 
 
proc `$`(card: Card): string =
## Return the string representation of a card.
toLowerAscii(&"{card.number:<5} {card.color:<6} {card.symbol:<8} {card.shading:<7}")
 
 
proc initDeck(): Deck =
## Create a new deck.
var i = 0
for num in Number.low..Number.high:
for col in Color.low..Color.high:
for sym in Symbol.low..Symbol.high:
for sh in Shading.low..Shading.high:
result[i] = (number: num, color: col, symbol: sym, shading: sh)
inc i
 
 
proc isSet(triplet: Triplet): bool =
## Check if a triplets of cards is a set.
sum(triplet.mapIt(ord(it.number))) mod 3 == 0 and
sum(triplet.mapIt(ord(it.color))) mod 3 == 0 and
sum(triplet.mapIt(ord(it.symbol))) mod 3 == 0 and
sum(triplet.mapIt(ord(it.shading))) mod 3 == 0
 
 
proc playGame(level: Level) =
## Play the game at given level.
 
var deck = initDeck()
let (nCards, nSets) = if level == Basic: (9, 4) else: (12, 6)
var sets: seq[Triplet]
var hand: seq[Card]
echo &"Playing {level} game: {nCards} cards, {nSets} sets."
 
block searchHand:
while true:
sets.setLen(0)
deck.shuffle()
hand = deck[0..<nCards]
block countSets:
for i in 0..(nCards - 3):
for j in (i + 1)..(nCards - 2):
for k in (j + 1)..(nCards - 1):
let triplet = [hand[i], hand[j], hand[k]]
if triplet.isSet():
sets.add triplet
if sets.len > nSets:
break countSets # Too much sets. Try with a new hand.
if sets.len == nSets:
break searchHand # Found: terminate search.
 
# Display the hand and the sets.
echo "\nCards:"
for card in sorted(hand): echo " ", card
echo "\nSets:"
for s in sets:
for card in sorted(s): echo " ", card
echo()
 
 
randomize()
playGame(Basic)
echo()
playGame(Advanced)</syntaxhighlight>
 
{{out}}
<pre>Playing basic game: 9 cards, 4 sets.
 
Cards:
one purple oval solid
one purple diamond open
two red squiggle open
two green diamond open
two green diamond striped
two purple oval open
three red diamond solid
three red diamond open
three purple squiggle open
 
Sets:
one purple diamond open
two purple oval open
three purple squiggle open
 
one purple diamond open
two green diamond striped
three red diamond solid
 
two red squiggle open
two green diamond open
two purple oval open
 
one purple diamond open
two green diamond open
three red diamond open
 
 
Playing advanced game: 12 cards, 6 sets.
 
Cards:
one green diamond striped
one purple diamond striped
two red oval open
two red diamond open
two green oval solid
two green oval striped
three red squiggle striped
three green oval solid
three green squiggle solid
three green squiggle open
three green squiggle striped
three purple diamond open
 
Sets:
one green diamond striped
two green oval striped
three green squiggle striped
 
one purple diamond striped
two green oval striped
three red squiggle striped
 
one green diamond striped
two green oval solid
three green squiggle open
 
one purple diamond striped
two red oval open
three green squiggle solid
 
three green squiggle solid
three green squiggle open
three green squiggle striped
 
three red squiggle striped
three green oval solid
three purple diamond open</pre>
 
=={{header|PARI/GP}}==
<langsyntaxhighlight lang="parigp">dealraw(cards)=vector(cards,i,vector(4,j,1<<random(3)));
howmany(a,b,c)=hammingweight(bitor(a,bitor(b,c)));
name(v)=Str(["red","green",0,"purple"][v[1]],", ",["oval","squiggle",0,"diamond"][v[2]],", ",["one","two",0,"three"][v[3]],", ",["solid","open",0,"striped"][v[4]]);
Line 1,365 ⟶ 3,246:
};
deal(9,4)
deal(12,6)</langsyntaxhighlight>
{{output}}
<pre>green, diamond, one, open
Line 1,430 ⟶ 3,311:
green, diamond, three, solid
purple, oval, one, open</pre>
 
 
=={{header|Perl}}==
{{trans|Perl6Raku}}
It's actually slightly simplified, since generating Enum classes
and objects would be overkill for this particular task.
<langsyntaxhighlight lang="perl">#!perl
use strict;
use warnings;
 
# This code was adapted from the perl6Raku solution for this task.
 
# Each element of the deck is an integer, which, when written
Line 1,515 ⟶ 3,395:
 
__END__
</syntaxhighlight>
</lang>
{{out}}
<pre>Drew 12 cards:
Line 1,543 ⟶ 3,423:
red one oval striped</pre>
 
=={{header|Perl 6Phix}}==
Converts cards 1..81 (that idea from C) to 1/2/4 [/7] (that idea from Perl) but inverts the validation
The trick here is to allocate three different bits for each enum, with the result that the cards of a matching set OR together to produce a 4-digit octal number that contains only the digits 1, 2, 4, or 7. This OR is done by funny looking <tt>[+|]</tt>, which is the reduction form of <tt>+|</tt>, which is the numeric bitwise OR. (Because Perl 6 stole the bare <tt>|</tt> operator for composing junctions instead.)
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang perl6>enum Color (red => 0o1000, green => 0o2000, purple => 0o4000);
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
enum Count (one => 0o100, two => 0o200, three => 0o400);
<span style="color: #008080;">function</span> <span style="color: #000000;">comb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">pool</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">needed</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">={},</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">done</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">chosen</span><span style="color: #0000FF;">={})</span>
enum Shape (oval => 0o10, squiggle => 0o20, diamond => 0o40);
<span style="color: #008080;">if</span> <span style="color: #000000;">needed</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- got a full set</span>
enum Style (solid => 0o1, open => 0o2, striped => 0o4);
<span style="color: #004080;">sequence</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">c</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">chosen</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find_any</span><span style="color: #0000FF;">({</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">},</span><span style="color: #7060A8;">flatten</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_or_bits</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_or_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">),</span><span style="color: #000000;">c</span><span style="color: #0000FF;">)))</span> <span style="color: #008080;">then</span>
my @deck := (Color.enums X Count.enums X Shape.enums X Style.enums).tree;
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">chosen</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
sub MAIN($DRAW = 9, $GOAL = $DRAW div 2) {
<span style="color: #008080;">elsif</span> <span style="color: #000000;">done</span><span style="color: #0000FF;">+</span><span style="color: #000000;">needed</span><span style="color: #0000FF;"><=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pool</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
sub show-cards(@c) { printf " %-6s %-5s %-8s %s\n", $_».key for @c }
<span style="color: #000080;font-style:italic;">-- get all combinations with and without the next item:</span>
<span style="color: #000000;">done</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">comb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pool</span><span style="color: #0000FF;">,</span><span style="color: #000000;">needed</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">done</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">chosen</span><span style="color: #0000FF;">),</span><span style="color: #000000;">pool</span><span style="color: #0000FF;">[</span><span style="color: #000000;">done</span><span style="color: #0000FF;">]))</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">comb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pool</span><span style="color: #0000FF;">,</span><span style="color: #000000;">needed</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">done</span><span style="color: #0000FF;">,</span><span style="color: #000000;">chosen</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">m124</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">card</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--returns the nth card (n is 1..81, res is length 4 of 1/2/4)</span>
<span style="color: #000000;">n</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">m124</span><span style="color: #0000FF;">[</span><span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">/</span><span style="color: #000000;">3</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">colours</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"red"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"green"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"purple"</span><span style="color: #0000FF;">},</span>
<span style="color: #000000;">symbols</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"oval"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"squiggle"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"diamond"</span><span style="color: #0000FF;">},</span>
<span style="color: #000000;">numbers</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"one"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"two"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"three"</span><span style="color: #0000FF;">},</span>
<span style="color: #000000;">shades</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"solid"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"open"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"striped"</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">print_cards</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">hand</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">cards</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cards</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">m</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">g</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cards</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">id</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cards</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">hand</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%3d: %-7s %-9s %-6s %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">id</span><span style="color: #0000FF;">,</span><span style="color: #000000;">colours</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">],</span><span style="color: #000000;">symbols</span><span style="color: #0000FF;">[</span><span style="color: #000000;">m</span><span style="color: #0000FF;">],</span><span style="color: #000000;">numbers</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">],</span><span style="color: #000000;">shades</span><span style="color: #0000FF;">[</span><span style="color: #000000;">g</span><span style="color: #0000FF;">]})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">play</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">cards</span><span style="color: #0000FF;">=</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">sets</span><span style="color: #0000FF;">=</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">deals</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">deck</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">shuffle</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">81</span><span style="color: #0000FF;">))</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">hand</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">deck</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">cards</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hand</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">hand</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">card</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hand</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">comb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hand</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">sets</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"dealt %d cards (%d deals)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">cards</span><span style="color: #0000FF;">,</span><span style="color: #000000;">deals</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">print_cards</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hand</span><span style="color: #0000FF;">,</span><span style="color: #000000;">hand</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"with %d sets\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">sets</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">sets</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">print_cards</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hand</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">deals</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">play</span><span style="color: #0000FF;">()</span>
<span style="color: #000080;font-style:italic;">--play(12,6)
--play(9,6)</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
dealt 9 cards (172 deals)
1: red oval two open
2: green oval one solid
3: purple diamond two striped
4: green diamond one striped
5: green oval one striped
6: purple squiggle three solid
7: green diamond two solid
8: red diamond two open
9: green squiggle one striped
 
with 4 sets
my @combinations = [^$DRAW].combinations(3);
1: red oval two open
4: green diamond one striped
6: purple squiggle three solid
 
3: purple diamond two striped
my @draw;
7: green diamond two solid
repeat until (my @sets) == $GOAL {
8: red @drawdiamond = @deck.pick($DRAW); two open
my @bits = @draw.map: { [+] @^enums».value }
@sets = gather for @combinations -> @c {
take @draw[@c].item when /^ <[1247]>+ $/ given ( [+|] @bits[@c] ).base(8);
}
}
 
4: green diamond one striped
say "Drew $DRAW cards:";
5: green oval one striped
show-cards @draw;
9: green squiggle one striped
for @sets.kv -> $i, @cards {
 
say "\nSet {$i+1}:";
5: green oval one striped
show-cards @cards;
6: purple squiggle three solid
}
8: red diamond two open
}</lang>
</pre>
 
=={{header|Picat}}==
The problem generator check that it problem has exactly one solution, so that step can take a little time (some seconds). <code>fail/0</code> is used to check for unicity of the solution.
<syntaxhighlight lang="picat">import util.
import cp.
 
%
% Solve the task in the description.
%
go ?=>
sets(1,Sets,SetLen,NumSets),
print_cards(Sets),
set_puzzle(Sets,SetLen,NumSets,X),
print_sol(Sets,X),
nl,
fail, % check for other solutions
nl.
go => true.
 
%
% Generate and solve a random instance with NumCards cards,
% giving exactly NumSets sets.
%
go2 =>
_ = random2(),
NumCards = 9, NumSets = 4, SetLen = 3,
generate_and_solve(NumCards,NumSets,SetLen),
fail, % prove unicity
nl.
 
go3 =>
_ = random2(),
NumCards = 12, NumSets = 6, SetLen = 3,
generate_and_solve(NumCards,NumSets,SetLen),
fail, % prove unicity)
nl.
 
%
% Solve a Set Puzzle.
%
set_puzzle(Cards,SetLen,NumWanted, X) =>
Len = Cards.length,
NumFeatures = Cards[1].length,
 
X = new_list(NumWanted),
foreach(I in 1..NumWanted)
Y = new_array(SetLen),
foreach(J in 1..SetLen)
member(Y[J], 1..Len)
end,
% unicity and symmetry breaking of Y
increasing2(Y),
% ensure unicity of the selected cards in X
if I > 1 then
foreach(J in 1..I-1) X[J] @< Y end
end,
foreach(F in 1..NumFeatures)
Z = [Cards[Y[J],F] : J in 1..SetLen],
(allequal(Z) ; alldiff(Z))
end,
X[I] = Y
end.
 
% (Strictly) increasing
increasing2(List) =>
foreach(I in 1..List.length-1)
List[I] @< List[I+1]
end.
 
% All elements must be equal
allequal(List) =>
foreach(I in 1..List.length-1)
List[I] = List[I+1]
end.
 
% All elements must be different
alldiff(List) =>
Len = List.length,
foreach(I in 1..Len, J in 1..I-1)
List[I] != List[J]
end.
 
% Print a solution
print_sol(Sets,X) =>
println("Solution:"),
println(x=X),
foreach(R in X)
println([Sets[R[I]] : I in 1..3])
end,
nl.
 
% Print the cards
print_cards(Cards) =>
println("Cards:"),
foreach({Card,I} in zip(Cards,1..Cards.len))
println([I,Card])
end,
nl.
 
%
% Generate a problem instance with NumSets sets (a unique solution).
%
% Note: not all random combinations of cards give a unique solution so
% it might generate a number of deals.
%
generate_instance(NumCards,NumSets,SetLen, Cards) =>
println([numCards=NumCards,numWantedSets=NumSets,setLen=SetLen]),
Found = false,
% Check that this instance has a unique solution.
while(Found = false)
if Cards = random_deal(NumCards),
count_all(set_puzzle(Cards,SetLen,NumSets,_X)) = 1
then
Found := true
end
end.
 
%
% Generate a random problem instance of N cards.
%
random_deal(N) = Deal.sort() =>
all_combinations(Combinations),
Deal = [],
foreach(_I in 1..N)
Len = Combinations.len,
Rand = random(1,Len),
Comb = Combinations[Rand],
Deal := Deal ++ [Comb],
Combinations := delete_all(Combinations, Comb)
end.
 
%
% Generate a random instance and solve it.
%
generate_and_solve(NumCards,NumSets,SetLen) =>
generate_instance(NumCards,NumSets,SetLen, Cards),
print_cards(Cards),
set_puzzle(Cards,SetLen,NumSets,X), % solve it
print_sol(Cards,X),
nl.
 
 
%
% All the 81 possible combinations (cards)
%
table
all_combinations(All) =>
Colors = [red, green, purple],
Symbols = [oval, squiggle, diamond],
Numbers = [one, two, three],
Shadings = [solid, open, striped],
All = findall([Color,Symbol,Number,Shading],
(member(Color,Colors),
member(Symbol,Symbols),
member(Number,Numbers),
member(Shading,Shadings))).
 
%
% From the task description.
%
% Solution: [[1,6,9],[2,3,4],[2,6,8],[5,6,7]]
%
sets(1,Sets,SetLen,Wanted) =>
Sets =
[
[green, one, oval, striped], % 1
[green, one, diamond, open], % 2
[green, one, diamond, striped], % 3
[green, one, diamond, solid], % 4
[purple, one, diamond, open], % 5
[purple, two, squiggle, open], % 6
[purple, three, oval, open], % 7
[red, three, oval, open], % 8
[red, three, diamond, solid] % 9
],
SetLen = 3,
Wanted = 4.</syntaxhighlight>
 
 
Solving the instance in the task description (<code>go/0</code>):
{{out}}
<pre>[1,[green,one,oval,striped]]
<pre>Drew 9 cards:
red two [2,[green,one,diamond striped,open]]
[3,[green,one,diamond,striped]]
purple one squiggle solid
[4,[green,one,diamond,solid]]
purple three squiggle solid
[5,[purple,one,diamond,open]]
red two squiggle striped
[6,[purple,two,squiggle,open]]
red two oval striped
[7,[purple,three,oval,open]]
green one diamond open
[8,[red ,three diamond solid,oval,open]]
[9,[red,three,diamond,solid]]
green three squiggle open
purple two diamond striped
 
Solution:
Set 1:
x = [{1,6,9},{2,3,4},{2,6,8},{5,6,7}]
red two diamond striped
[[green,one,oval,striped],[purple,two,squiggle,open],[red,three,diamond,solid]]
red two squiggle striped
[[green,one,diamond,open],[green,one,diamond,striped],[green,one,diamond,solid]]
red two oval striped
[[green,one,diamond,open],[purple,two,squiggle,open],[red,three,oval,open]]
[[purple,one,diamond,open],[purple,two,squiggle,open],[purple,three,oval,open]]</pre>
 
Solving the two random tasks (<code>go2/0</code>) and <code>go3/0</code>):
Set 2:
{{out}::
purple one squiggle solid
<pre>[numCards = 9,numWantedSets = 4,setLen = 3]
red two squiggle striped
Cards:
green three squiggle open
[1,[green,squiggle,one,solid]]
[2,[green,squiggle,two,solid]]
[3,[purple,diamond,three,striped]]
[4,[purple,oval,two,striped]]
[5,[purple,squiggle,one,striped]]
[6,[purple,squiggle,three,solid]]
[7,[purple,squiggle,three,striped]]
[8,[red,squiggle,one,open]]
[9,[red,squiggle,three,open]]
 
Solution:
Set 3:
x = [{1,5,8},{2,5,9},{2,7,8},{3,4,5}]
purple three squiggle solid
[[green,squiggle,one,solid],[purple,squiggle,one,striped],[red,squiggle,one,open]]
red two oval striped
[[green,squiggle,two,solid],[purple,squiggle,one,striped],[red,squiggle,three,open]]
green one diamond open
[[green,squiggle,two,solid],[purple,squiggle,three,striped],[red,squiggle,one,open]]
[[purple,diamond,three,striped],[purple,oval,two,striped],[purple,squiggle,one,striped]]
 
[numCards = 12,numWantedSets = 6,setLen = 3]
Set 4:
Cards:
green one diamond open
red three [1,[green,diamond ,one,solid]]
[2,[green,diamond,two,solid]]
purple two diamond striped</pre>
[3,[green,oval,one,open]]
[4,[purple,oval,one,solid]]
[5,[purple,squiggle,one,open]]
[6,[purple,squiggle,one,solid]]
[7,[purple,squiggle,one,striped]]
[8,[red,diamond,one,solid]]
[9,[red,diamond,two,striped]]
[10,[red,oval,one,striped]]
[11,[red,squiggle,three,solid]]
[12,[red,squiggle,three,striped]]
 
Solution:
x = [{1,5,10},{2,4,11},{3,4,10},{3,7,8},{5,6,7},{9,10,12}]
[[green,diamond,one,solid],[purple,squiggle,one,open],[red,oval,one,striped]]
[[green,diamond,two,solid],[purple,oval,one,solid],[red,squiggle,three,solid]]
[[green,oval,one,open],[purple,oval,one,solid],[red,oval,one,striped]]
[[green,oval,one,open],[purple,squiggle,one,striped],[red,diamond,one,solid]]
[[purple,squiggle,one,open],[purple,squiggle,one,solid],[purple,squiggle,one,striped]]
[[red,diamond,two,striped],[red,oval,one,striped],[red,squiggle,three,striped]]</pre>
 
===Constraint model===
Here is the additional code for a '''constraint model'''. Note that the constraint solver only handles integers so the features must be converted to integers. To simplify, the random instance generator does not check for unicity of the problem instance, so it can have (and often have) a lot of solutions.
<syntaxhighlight lang="picat">go4 =>
NumCards = 18,
NumWanted = 9,
SetLen = 3,
time(generate_instance2(NumCards,NumWanted, SetLen,Sets)),
 
print_cards(Sets),
println(setLen=SetLen),
println(numWanted=NumWanted),
SetsConv = convert_sets_to_num(Sets),
 
set_puzzle_cp(SetsConv,SetLen,NumWanted, X),
 
println(x=X),
foreach(Row in X)
println([Sets[I] : I in Row])
end,
nl,
fail, % more solutions?
nl.
 
set_puzzle_cp(Cards,SetLen,NumWanted, X) =>
NumFeatures = Cards[1].len,
NumSets = Cards.len,
X = new_array(NumWanted,SetLen),
X :: 1..NumSets,
 
foreach(I in 1..NumWanted)
% ensure unicity of the selected sets
all_different(X[I]),
increasing_strict(X[I]), % unicity and symmetry breaking of Y
 
foreach(F in 1..NumFeatures)
Z = $[ S : J in 1..SetLen, matrix_element(Cards, X[I,J],F, S) ],
% all features are different or all equal
(
(sum([ Z[J] #!= Z[K] : J in 1..SetLen, K in 1..SetLen, J != K ])
#= SetLen*SetLen - SetLen)
#\/
(sum([ Z[J-1] #= Z[J] : J in 2..SetLen]) #= SetLen-1)
)
end
end,
 
% Symmetry breaking (lexicographic ordered rows)
lex2(X),
 
solve($[ff,split],X).
 
%
% Symmetry breaking
% Ensure that the rows in X are lexicographic ordered
%
lex2(X) =>
Len = X[1].length,
foreach(I in 2..X.length)
lex_lt([X[I-1,J] : J in 1..Len], [X[I,J] : J in 1..Len])
end.
 
%
% Convert sets of "verbose" instances to integer
% representations.
%
convert_sets_to_num(Sets) = NewSets =>
Maps = new_map([
red=1,green=2,purple=3,
1=1,2=2,3=3,
one=1,two=2,three=3,
oval=1,squiggle=2,squiggles=2,diamond=3,
solid=1,open=2,striped=3
]),
NewSets1 = [],
foreach(S in Sets)
NewSets1 := NewSets1 ++ [[Maps.get(T) : T in S]]
end,
NewSets = NewSets1.
 
 
%
% Plain random problem instance, no check of solvability.
%
generate_instance2(NumCards,_NumSets,_SetLen, Cards) =>
Cards = random_deal(NumCards).</syntaxhighlight>
 
{{out}}
This problem instance happens to have 10 solutions.
<pre>Cards:
[1,[green,diamond,one,open]]
[2,[green,diamond,one,solid]]
[3,[green,oval,one,open]]
[4,[green,oval,three,solid]]
[5,[green,oval,two,solid]]
[6,[green,squiggle,three,striped]]
[7,[green,squiggle,two,striped]]
[8,[purple,diamond,one,solid]]
[9,[purple,diamond,two,striped]]
[10,[purple,oval,one,solid]]
[11,[purple,oval,two,open]]
[12,[purple,squiggle,two,open]]
[13,[red,diamond,two,solid]]
[14,[red,oval,one,open]]
[15,[red,oval,three,solid]]
[16,[red,oval,two,solid]]
[17,[red,oval,two,striped]]
[18,[red,squiggle,one,striped]]
 
setLen = 3
numWanted = 9
x = {{1,4,7},{1,5,6},{1,10,18},{3,8,18},{4,10,16},{5,10,15},{5,11,17},{7,9,17},{7,11,13}}
[[green,diamond,one,open],[green,oval,three,solid],[green,squiggle,two,striped]]
[[green,diamond,one,open],[green,oval,two,solid],[green,squiggle,three,striped]]
[[green,diamond,one,open],[purple,oval,one,solid],[red,squiggle,one,striped]]
[[green,oval,one,open],[purple,diamond,one,solid],[red,squiggle,one,striped]]
[[green,oval,three,solid],[purple,oval,one,solid],[red,oval,two,solid]]
[[green,oval,two,solid],[purple,oval,one,solid],[red,oval,three,solid]]
[[green,oval,two,solid],[purple,oval,two,open],[red,oval,two,striped]]
[[green,squiggle,two,striped],[purple,diamond,two,striped],[red,oval,two,striped]]
[[green,squiggle,two,striped],[purple,oval,two,open],[red,diamond,two,solid]]
 
x = {{1,4,7},{1,5,6},{1,10,18},{3,8,18},{4,10,16},{5,10,15},{5,11,17},{7,9,17},{14,15,17}}
[[green,diamond,one,open],[green,oval,three,solid],[green,squiggle,two,striped]]
[[green,diamond,one,open],[green,oval,two,solid],[green,squiggle,three,striped]]
[[green,diamond,one,open],[purple,oval,one,solid],[red,squiggle,one,striped]]
[[green,oval,one,open],[purple,diamond,one,solid],[red,squiggle,one,striped]]
[[green,oval,three,solid],[purple,oval,one,solid],[red,oval,two,solid]]
[[green,oval,two,solid],[purple,oval,one,solid],[red,oval,three,solid]]
[[green,oval,two,solid],[purple,oval,two,open],[red,oval,two,striped]]
[[green,squiggle,two,striped],[purple,diamond,two,striped],[red,oval,two,striped]]
[[red,oval,one,open],[red,oval,three,solid],[red,oval,two,striped]]
 
...</pre>
 
=={{header|Prolog}}==
 
<syntaxhighlight lang="prolog">do_it(N) :-
card_sets(N, Cards, Sets),
!,
format('Cards: ~n'),
maplist(print_card, Cards),
format('~nSets: ~n'),
maplist(print_set, Sets).
print_card(Card) :- format(' ~p ~p ~p ~p~n', Card).
print_set(Set) :- maplist(print_card, Set), nl.
 
n(9,4).
n(12,6).
 
card_sets(N, Cards, Sets) :-
n(N,L),
repeat,
random_deal(N, Cards),
setof(Set, is_card_set(Cards, Set), Sets),
length(Sets, L).
 
random_card([C,S,N,Sh]) :-
random_member(C, [red, green, purple]),
random_member(S, [oval, squiggle, diamond]),
random_member(N, [one, two, three]),
random_member(Sh, [solid, open, striped]).
random_deal(N, Cards) :-
length(Cards, N),
maplist(random_card, Cards).
is_card_set(Cards, Result) :-
select(C1, Cards, Rest),
select(C2, Rest, Rest2),
select(C3, Rest2, _),
match(C1, C2, C3),
sort([C1,C2,C3], Result).
match([],[],[]).
match([A|T1],[A|T2],[A|T3]) :-
match(T1,T2,T3).
match([A|T1],[B|T2],[C|T3]) :-
dif(A,B), dif(B,C), dif(A,C),
match(T1,T2,T3).</syntaxhighlight>
{{out}}
<pre>
?- do_it(12).
Cards:
red squiggle two solid
red squiggle three open
purple diamond two striped
red oval two striped
green oval one solid
purple squiggle one open
purple squiggle two solid
green oval two striped
purple squiggle three striped
green diamond one solid
purple diamond two open
red diamond two open
 
Sets:
green oval one solid
purple diamond two striped
red squiggle three open
 
green oval one solid
purple squiggle three striped
red diamond two open
 
green oval two striped
purple diamond two open
red squiggle two solid
 
green oval two striped
purple squiggle two solid
red diamond two open
 
purple squiggle one open
purple squiggle three striped
purple squiggle two solid
 
red diamond two open
red oval two striped
red squiggle two solid
 
true.
 
?- do_it(9).
Cards:
purple squiggle two solid
green diamond one striped
red diamond two solid
green oval two open
red diamond two striped
purple diamond three striped
green diamond two open
green diamond three solid
purple oval one open
 
Sets:
green diamond one striped
green diamond three solid
green diamond two open
 
green diamond one striped
purple diamond three striped
red diamond two striped
 
green oval two open
purple squiggle two solid
red diamond two striped
 
purple diamond three striped
purple oval one open
purple squiggle two solid
 
true.
</pre>
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">#!/usr/bin/python
from itertools import product, combinations
Line 1,652 ⟶ 4,071:
break
printit(deal, sets)
</syntaxhighlight>
</lang>
<small>Note: You could remove the inner square brackets of the <code>'if all( [...] )'</code> part of the sets computation in the getsets function. It is a remnant of Python 2.7 debugging which gives access to the name <code>feature</code>. The code works on Python 3.X too, but not that access.</small>
 
Line 1,683 ⟶ 4,102:
green one diamond solid
red three oval solid</pre>
 
===Short Version===
{{trans|D}}
<syntaxhighlight lang="python">import random, pprint
from itertools import product, combinations
 
N_DRAW = 9
N_GOAL = N_DRAW // 2
 
deck = list(product("red green purple".split(),
"one two three".split(),
"oval squiggle diamond".split(),
"solid open striped".split()))
 
sets = []
while len(sets) != N_GOAL:
draw = random.sample(deck, N_DRAW)
sets = [cs for cs in combinations(draw, 3)
if all(len(set(t)) in [1, 3] for t in zip(*cs))]
 
print "Dealt %d cards:" % len(draw)
pprint.pprint(draw)
print "\nContaining %d sets:" % len(sets)
pprint.pprint(sets)</syntaxhighlight>
{{out}}
<pre>Dealt 9 cards:
[('purple', 'three', 'squiggle', 'striped'),
('red', 'one', 'squiggle', 'solid'),
('red', 'three', 'diamond', 'striped'),
('red', 'two', 'oval', 'open'),
('purple', 'three', 'squiggle', 'open'),
('green', 'three', 'oval', 'open'),
('purple', 'three', 'squiggle', 'solid'),
('green', 'two', 'squiggle', 'open'),
('purple', 'two', 'oval', 'open')]
 
Containing 4 sets:
[(('purple', 'three', 'squiggle', 'striped'),
('red', 'one', 'squiggle', 'solid'),
('green', 'two', 'squiggle', 'open')),
(('purple', 'three', 'squiggle', 'striped'),
('purple', 'three', 'squiggle', 'open'),
('purple', 'three', 'squiggle', 'solid')),
(('red', 'one', 'squiggle', 'solid'),
('red', 'three', 'diamond', 'striped'),
('red', 'two', 'oval', 'open')),
(('red', 'three', 'diamond', 'striped'),
('green', 'three', 'oval', 'open'),
('purple', 'three', 'squiggle', 'solid'))]</pre>
 
=={{header|Quackery}}==
 
<code>cards</code>, <code>sets</code>, and <code>echocard</code> are defined at [[Set, the card game#Quackery]].
 
<syntaxhighlight lang="Quackery"> [ temp put
[ dup cards dup
sets dup size
temp share != while
2drop again ]
swap
say "Cards:" cr
witheach echocard
cr
say "Sets:" cr
witheach
[ witheach echocard cr ]
drop
temp release ] is task ( n n --> )
 
basic task
cr
advanced task</syntaxhighlight>
 
{{out}}
 
<pre>BASIC
 
Cards:
three striped purple ovals
two solid green squiggles
two open green squiggles
one open purple squiggle
three striped red squiggles
two striped red ovals
one solid purple squiggle
two solid red diamonds
two open purple diamonds
 
Sets:
two open green squiggles
three striped red squiggles
one solid purple squiggle
 
two solid green squiggles
two striped red ovals
two open purple diamonds
 
two solid green squiggles
one open purple squiggle
three striped red squiggles
 
three striped purple ovals
one solid purple squiggle
two open purple diamonds
 
 
ADVANCED
 
Cards:
one open green oval
two solid purple squiggles
one striped red diamond
three solid purple diamonds
two solid green squiggles
two open purple squiggles
two open green ovals
two striped red squiggles
two open green diamonds
two striped red ovals
three open purple ovals
one open red oval
 
Sets:
two open green ovals
three open purple ovals
one open red oval
 
two solid green squiggles
two open purple squiggles
two striped red squiggles
 
one striped red diamond
two solid green squiggles
three open purple ovals
 
one striped red diamond
three solid purple diamonds
two open green diamonds
 
two solid purple squiggles
two open green diamonds
two striped red ovals
 
one open green oval
three solid purple diamonds
two striped red squiggles
</pre>
 
=={{header|Racket}}==
<syntaxhighlight lang="racket">
<lang Racket>
#lang racket
 
Line 1,722 ⟶ 4,288:
(deal 9 4)
(deal 12 6)
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
 
The trick here is to allocate three different bits for each enum, with the result that the cards of a matching set OR together to produce a 4-digit octal number that contains only the digits 1, 2, 4, or 7. This OR is done by funny looking <tt>[+|]</tt>, which is the reduction form of <tt>+|</tt>, which is the numeric bitwise OR. (Because Raku stole the bare <tt>|</tt> operator for composing junctions instead.)
<syntaxhighlight lang="raku" line>enum Color (red => 0o1000, green => 0o2000, purple => 0o4000);
enum Count (one => 0o100, two => 0o200, three => 0o400);
enum Shape (oval => 0o10, squiggle => 0o20, diamond => 0o40);
enum Style (solid => 0o1, open => 0o2, striped => 0o4);
my @deck = Color.enums X Count.enums X Shape.enums X Style.enums;
sub MAIN($DRAW = 9, $GOAL = $DRAW div 2) {
sub show-cards(@c) { { printf "%9s%7s%10s%9s\n", @c[$_;*]».key } for ^@c }
 
my @combinations = [^$DRAW].combinations(3);
 
my @draw;
repeat until (my @sets) == $GOAL {
@draw = @deck.pick($DRAW);
my @bits = @draw.map: { [+] @^enums».value }
@sets = gather for @combinations -> @c {
take @draw[@c].item when /^ <[1247]>+ $/ given ( [+|] @bits[@c] ).base(8);
}
}
 
say "Drew $DRAW cards:";
show-cards @draw;
for @sets.kv -> $i, @cards {
say "\nSet {$i+1}:";
show-cards @cards;
}
}</syntaxhighlight>
{{out}}
<pre>Drew 9 cards:
purple two diamond open
red two squiggle striped
purple three squiggle open
purple two squiggle striped
red three oval striped
red one diamond striped
purple two oval solid
green three diamond solid
red two squiggle open
 
Set 1:
purple two diamond open
purple two squiggle striped
purple two oval solid
 
Set 2:
purple two diamond open
red one diamond striped
green three diamond solid
 
Set 3:
red two squiggle striped
red three oval striped
red one diamond striped
 
Set 4:
purple three squiggle open
red three oval striped
green three diamond solid</pre>
 
=={{header|REXX}}==
Language note: &nbsp; each REXX implementation has its own method of determining a starter ''seed'' for generating
<br>pseudo-random numbers, and in addition, that starter seed may be dependent upon operating system factors,
<br>hardware architecture, and other things like the (local) date and time-of-day, and other such variables.
<br>The algorithm is also not the same for all REXX implementations.
 
The particular set of cards dealt (show below) used Regina 3.9.3 under a Windows/XP environment.
<syntaxhighlight lang="rexx">/*REXX program finds and displays "sets" (solutions) for the SET puzzle (game). */
parse arg game seed . /*get optional # cards to deal and seed*/
if game=='' | game=="," then game= 9 /*Not specified? Then use the default.*/
if seed=='' | seed=="," then seed= 77 /* " " " " " " */
call aGame 0 /*with tell=0: suppress the output. */
call aGame 1 /*with tell=1: display " " */
exit sets /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
aGame: parse arg tell; good= game % 2 /*enable/disable the showing of output.*/
/* [↑] the GOOD var is the right #sets*/
do seed=seed until good==sets /*generate deals until good # of sets.*/
call random ,,seed /*repeatability for the RANDOM invokes.*/
call genFeatures /*generate various card game features. */
call genDeck /* " a deck (with 81 "cards").*/
call dealer game /*deal a number of cards for the game. */
call findSets game%2 /*find # of sets from the dealt cards. */
end /*until*/ /* [↓] when leaving, SETS is right #.*/
return /*return to invoker of this subroutine.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
dealer: call sey 'dealing' game "cards:", , . /*shuffle and deal the cards. */
 
do cards=1 until cards==game /*keep dealing until finished. */
_= random(1, words(##) ) /*pick a card. */
##= delword(##, _, 1) /*delete " " */
@.cards= deck._ /*add the card to the tableau. */
call sey right('card' cards, 30) " " @.cards /*display a card to terminal.*/
 
do j=1 for words(@.cards) /* [↓] define cells for cards. */
@.cards.j= word(@.cards, j) /*define a cell for a card. */
end /*j*/
end /*cards*/
 
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
defFeatures: parse arg what,v; _= words(v) /*obtain what is to be defined. */
 
if _\==values then do; call sey 'error,' what "features ¬=" values, ., .
exit -1
end /* [↑] check for typos and/or errors. */
 
do k=1 for words(values) /*define all the possible values. */
call value what'.'k, word(values, k) /*define a card feature. */
end /*k*/
 
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
findSets: parse arg n; call genPoss /*N: the number of sets to be found. */
call sey /*find any sets that were generated [↑]*/
 
do j=1 for p /*P: is the number of possible sets. */
do f=1 for features
do g=1 for groups; !!.j.f.g= word(!.j.f, g)
end /*g*/
end /*f*/
 
ok= 1 /*everything is peachy─kean (OK) so far*/
 
do g=1 for groups
_= !!.j.1.g /*build strings to hold possibilities. */
equ= 1 /* [↓] handles all the equal features.*/
 
do f=2 to features while equ; equ= equ & _==!!.j.f.g
end /*f*/
 
dif= 1
__= !!.j.1.g /* [↓] handles all unequal features.*/
do f=2 to features while \equ
dif= dif & (wordpos(!!.j.f.g, __)==0)
__= __ !!.j.f.g /*append to string for next test*/
end /*f*/
 
ok=ok & (equ | dif) /*now, see if all are equal or unequal.*/
end /*g*/
 
if \ok then iterate /*Is this set OK? Nope, then skip it.*/
sets= sets + 1 /*bump the number of the sets found. */
call sey right('set' sets": ", 15) !.j.1 sep !.j.2 sep !.j.3
end /*j*/
 
call sey sets 'sets found.', .
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
genDeck: #= 0; ##= /*#: cards in deck; ##: shuffle aid.*/
 
do num=1 for values; xnum = word(numbers, num)
do col=1 for values; xcol = word(colors, col)
do sym=1 for values; xsym = word(symbols, sym)
do sha=1 for values; xsha = word(shadings, sha)
#= # + 1; ##= ## #;
deck.#= xnum xcol xsym xsha /*create a card. */
end /*sha*/
end /*num*/
end /*sym*/
end /*col*/
 
return /*#: the number of cards in the deck. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
genFeatures: features= 3; groups= 4; values= 3 /*define # features, groups, values. */
numbers = 'one two three' ; call defFeatures 'number', numbers
colors = 'red green purple' ; call defFeatures 'color', colors
symbols = 'oval squiggle diamond' ; call defFeatures 'symbol', symbols
shadings= 'solid open striped' ; call defFeatures 'shading', shadings
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
genPoss: p= 0; sets= 0; sep=' ───── ' /*define some REXX variables. */
!.=
do i=1 for game /* [↓] the IFs eliminate duplicates.*/
do j=i+1 to game
do k=j+1 to game
p= p + 1; !.p.1= @.i; !.p.2= @.j; !.p.3= @.k
end /*k*/
end /*j*/
end /*i*/ /* [↑] generate the permutation list. */
 
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
sey: if \tell then return /*¬ tell? Then suppress the output. */
if arg(2)==. then say; say arg(1); if arg(3)==. then say; return</syntaxhighlight>
'''output''' when using the default input:
<pre>
dealing 9 cards:
 
card 1 one green oval open
card 2 two purple squiggle striped
card 3 one green diamond solid
card 4 three red diamond open
card 5 two purple squiggle striped
card 6 two purple oval striped
card 7 two purple diamond striped
card 8 three red squiggle open
card 9 two red oval solid
 
set 1: two purple squiggle striped ───── two purple oval striped ───── two purple diamond striped
set 2: one green diamond solid ───── three red diamond open ───── two purple diamond striped
set 3: one green diamond solid ───── two purple oval striped ───── three red squiggle open
set 4: two purple squiggle striped ───── two purple oval striped ───── two purple diamond striped
 
4 sets found.
</pre>
{{out|output|text=&nbsp; when using the input of: &nbsp; &nbsp; <tt> 12 </tt>}}
<pre>
dealing 12 cards:
 
card 1 one purple diamond striped
card 2 one green diamond striped
card 3 one purple squiggle solid
card 4 one red oval solid
card 5 two green oval open
card 6 one green diamond open
card 7 two green squiggle striped
card 8 three green squiggle solid
card 9 three green squiggle open
card 10 one purple diamond open
card 11 three green squiggle open
card 12 two red oval open
 
set 1: one purple diamond striped ───── three green squiggle solid ───── two red oval open
set 2: one green diamond striped ───── two green oval open ───── three green squiggle solid
set 3: two green oval open ───── one green diamond open ───── three green squiggle open
set 4: two green oval open ───── one green diamond open ───── three green squiggle open
set 5: three green squiggle open ───── one purple diamond open ───── two red oval open
set 6: one purple diamond open ───── three green squiggle open ───── two red oval open
 
6 sets found.
</pre>
 
=={{header|Ruby}}==
Brute force.
<langsyntaxhighlight lang="ruby">COLORS = %i(red green purple) #use [:red, :green, :purple] in Ruby < 2.0
SYMBOLS = %i(oval squiggle diamond)
NUMBERS = %i(one two three)
Line 1,761 ⟶ 4,564:
 
set_puzzle(9)
set_puzzle(12)</langsyntaxhighlight>
{{out}}
<pre>
Line 1,830 ⟶ 4,633:
green oval two open
red diamond two striped
</pre>
=={{header|Rust}}==
<syntaxhighlight lang="rust">
use itertools::Itertools;
use rand::Rng;
 
const DECK_SIZE: usize = 81;
const NUM_ATTRIBUTES: usize = 4;
const ATTRIBUTES: [&[&str]; NUM_ATTRIBUTES] = [
&["red", "green", "purple"],
&["one", "two", "three"],
&["oval", "squiggle", "diamond"],
&["solid", "open", "striped"],
];
 
fn get_random_card_indexes(num_of_cards: usize) -> Vec<usize> {
let mut selected_cards: Vec<usize> = Vec::with_capacity(num_of_cards);
let mut rng = rand::thread_rng();
loop {
let idx = rng.gen_range(0..DECK_SIZE);
if !selected_cards.contains(&idx) {
selected_cards.push(idx);
}
if selected_cards.len() == num_of_cards {
break;
}
}
 
selected_cards
}
 
fn run_game(num_of_cards: usize, minimum_number_of_sets: usize) {
println!(
"\nGAME: # of cards: {} # of sets: {}",
num_of_cards, minimum_number_of_sets
);
 
// generate the deck with 81 unique cards
let deck = (0..NUM_ATTRIBUTES)
.map(|_| (0..=2_usize))
.multi_cartesian_product()
.collect::<Vec<_>>();
 
// closure to return true if the three attributes are the same, or each of them is different
let valid_attribute =
|a: usize, b: usize, c: usize| -> bool { a == b && b == c || (a != b && b != c && a != c) };
 
// closure to test all attributes, each of them should be true to have a valid set
let valid_set = |t: &Vec<&Vec<usize>>| -> bool {
for attr in 0..NUM_ATTRIBUTES {
if !valid_attribute(t[0][attr], t[1][attr], t[2][attr]) {
return false;
}
}
true
};
 
loop {
// select the required # of cards from the deck randomly
let selected_cards = get_random_card_indexes(num_of_cards)
.iter()
.map(|idx| deck[*idx].clone())
.collect::<Vec<_>>();
 
// generate all combinations, and filter/keep only which are valid sets
let valid_sets = selected_cards
.iter()
.combinations(3)
.filter(|triplet| valid_set(triplet))
.collect::<Vec<_>>();
 
// if the # of the sets is matching the requirement, print it and finish
if valid_sets.len() == minimum_number_of_sets {
print!("SELECTED CARDS:");
for card in &selected_cards {
print!("\ncard: ");
for attr in 0..NUM_ATTRIBUTES {
print!("{}, ", ATTRIBUTES[attr][card[attr]]);
}
}
 
print!("\nSets:");
for triplet in &valid_sets {
print!("\nSet: ");
for card in triplet {
for attr in 0..NUM_ATTRIBUTES {
print!("{}, ", ATTRIBUTES[attr][card[attr]]);
}
print!(" | ");
}
}
 
break;
}
 
//otherwise generate again
}
}
fn main() {
run_game(9, 4);
run_game(12, 6);
}
 
</syntaxhighlight>
{{out}}
<pre>
GAME: # of cards: 9 # of sets: 4
SELECTED CARDS:
card: green, two, diamond, striped,
card: green, two, oval, solid,
card: red, one, oval, striped,
card: red, three, oval, striped,
card: purple, three, squiggle, striped,
card: green, three, diamond, solid,
card: red, three, oval, open,
card: purple, two, squiggle, open,
card: red, two, oval, striped,
Sets:
Set: green, two, diamond, striped, | red, one, oval, striped, | purple, three, squiggle, striped, |
Set: red, one, oval, striped, | red, three, oval, striped, | red, two, oval, striped, |
Set: red, one, oval, striped, | green, three, diamond, solid, | purple, two, squiggle, open, |
Set: purple, three, squiggle, striped, | green, three, diamond, solid, | red, three, oval, open, |
GAME: # of cards: 12 # of sets: 6
SELECTED CARDS:
card: purple, three, squiggle, solid,
card: purple, three, squiggle, striped,
card: green, three, diamond, striped,
card: purple, three, oval, solid,
card: green, two, oval, open,
card: green, one, diamond, solid,
card: red, three, oval, open,
card: green, one, squiggle, solid,
card: red, three, oval, solid,
card: purple, three, diamond, open,
card: red, two, oval, open,
card: red, three, oval, striped,
Sets:
Set: purple, three, squiggle, solid, | green, three, diamond, striped, | red, three, oval, open, |
Set: purple, three, squiggle, striped, | green, three, diamond, striped, | red, three, oval, striped, |
Set: purple, three, squiggle, striped, | purple, three, oval, solid, | purple, three, diamond, open, |
Set: purple, three, squiggle, striped, | green, one, diamond, solid, | red, two, oval, open, |
Set: green, three, diamond, striped, | green, two, oval, open, | green, one, squiggle, solid, |
Set: red, three, oval, open, | red, three, oval, solid, | red, three, oval, striped, |
</pre>
 
=={{header|Tailspin}}==
Dealing cards at random to the size of the desired hand, then trying again if the desired set count is not achieved.
<syntaxhighlight lang="tailspin">
def deck: [ { by 1..3 -> (colour: $),
by 1..3 -> (symbol: $),
by 1..3 -> (number: $),
by 1..3 -> (shading: $)}
];
 
templates deal
@: $deck;
[ 1..$ -> \($@deal::length -> SYS::randomInt -> ^@deal($ + 1) !\)] !
end deal
 
templates isSet
def set : $;
[ $(1).colour::raw + $(2).colour::raw + $(3).colour::raw, $(1).symbol::raw + $(2).symbol::raw + $(3).symbol::raw,
$(1).number::raw + $(2).number::raw + $(3).number::raw, $(1).shading::raw + $(2).shading::raw + $(3).shading::raw ] -> #
// if it is an array where all elements of 3, 6 or 9, it is a set
when <[<=3|=6|=9>+ VOID]> do $set !
end isSet
 
templates findSets
def hand: $;
[ 1..$hand::length - 2 -> \(def a: $;
$a+1..$hand::length - 1 -> \(def b: $;
$b+1..$hand::length -> $hand([$a, $b, $]) !
\) !
\) -> isSet ] !
end findSets
 
templates setPuzzle
def nCards: $(1);
def nSets: $(2);
{sets: []} -> #
when <{sets: <[]($nSets..)>}> do $ !
otherwise
def hand: $nCards -> deal;
{hand: $hand, sets: $hand -> findSets} -> #
end setPuzzle
 
templates formatCard
def colours: colour´1:['red', 'green', 'purple'];
def symbols: symbol´1:['oval', 'squiggle', 'diamond'];
def numbers: number´1:['one', 'two', 'three'];
def shadings: shading´1:['solid', 'open', 'striped'];
$ -> '$colours($.colour);-$symbols($.symbol);-$numbers($.number);-$shadings($.shading);' !
end formatCard
 
templates formatSets
$ -> 'hand:
$.hand... -> '$ -> formatCard;
';
sets:
$.sets... -> '[$... -> ' $ -> formatCard; ';]
';' !
end formatSets
 
[9,4] -> setPuzzle -> formatSets -> !OUT::write</syntaxhighlight>
{{out}}
<pre>
hand:
green-squiggle-three-open
green-oval-three-striped
red-diamond-three-striped
red-oval-one-open
purple-squiggle-three-striped
red-oval-two-striped
purple-diamond-one-solid
red-squiggle-three-solid
purple-diamond-two-open
 
sets:
[ green-squiggle-three-open red-oval-one-open purple-diamond-two-open ]
[ green-squiggle-three-open purple-squiggle-three-striped red-squiggle-three-solid ]
[ green-squiggle-three-open red-oval-two-striped purple-diamond-one-solid ]
[ green-oval-three-striped red-diamond-three-striped purple-squiggle-three-striped ]
</pre>
 
Twelve cards with six sets
<syntaxhighlight lang="tailspin">
[12,6] -> setPuzzle -> formatSets -> !OUT::write
</syntaxhighlight>
{{out}}
<pre>
hand:
red-oval-one-striped
red-squiggle-one-open
purple-diamond-two-striped
purple-oval-two-open
red-diamond-one-solid
green-oval-three-solid
green-diamond-one-open
green-diamond-three-open
red-diamond-three-solid
green-diamond-three-solid
green-squiggle-one-open
red-oval-one-open
 
sets:
[ red-oval-one-striped red-squiggle-one-open red-diamond-one-solid ]
[ red-oval-one-striped purple-oval-two-open green-oval-three-solid ]
[ red-squiggle-one-open purple-diamond-two-striped green-oval-three-solid ]
[ red-squiggle-one-open purple-oval-two-open green-diamond-three-open ]
[ purple-diamond-two-striped red-diamond-one-solid green-diamond-three-open ]
[ purple-diamond-two-striped green-diamond-one-open red-diamond-three-solid ]
</pre>
 
=={{header|Tcl}}==
The principle behind this code is that the space of possible solutions is a substantial proportion of the space of possible hands, so picking a random hand and verifying that it is a solution, repeating until that verification succeeds, is a much quicker way to find a solution than a systematic search. It also makes the code substantially simpler.
It also makes the code substantially simpler.
<lang tcl># Generate random integer uniformly on range [0..$n-1]
<syntaxhighlight lang="tcl"># Generate random integer uniformly on range [0..$n-1]
proc random n {expr {int(rand() * $n)}}
 
Line 1,915 ⟶ 4,970:
}
return [list $hand $sets]
}</langsyntaxhighlight>
Demonstrating:
<langsyntaxhighlight lang="tcl"># Render a hand (or any list) of cards (the "."s are just placeholders).
proc PrettyHand {hand {separator \n}} {
set Co {. red green . purple}
Line 1,945 ⟶ 5,000:
PrettyOutput [SetPuzzle 9 4]
puts "=== ADVANCED PUZZLE ======"
PrettyOutput [SetPuzzle 12 6]</langsyntaxhighlight>
{{out|Sample output}}
<pre>
Line 2,015 ⟶ 5,070:
</pre>
 
=={{omit fromheader|GUISSWren}}==
{{trans|Kotlin}}
{{libheader|Wren-dynamic}}
{{libheader|Wren-trait}}
{{libheader|Wren-fmt}}
{{libheader|Wren-str}}
{{libheader|Wren-math}}
{{libheader|Wren-sort}}
<syntaxhighlight lang="wren">import "./dynamic" for Enum
import "./trait" for Comparable
import "./fmt" for Fmt
import "./str" for Str
import "./math" for Nums
import "./sort" for Sort
import "random" for Random
 
var Color = Enum.create("Color", ["RED", "GREEN", "PURPLE"])
[[Category:Cards]]
var Symbol = Enum.create("Symbol", ["OVAL", "SQUIGGLE", "DIAMOND"])
[[Category:Puzzles]]
var Number = Enum.create("Number", ["ONE", "TWO", "THREE"])
var Shading = Enum.create("Shading", ["SOLID", "OPEN", "STRIPED"])
var Degree = Enum.create("Degree", ["BASIC", "ADVANCED"])
 
class Card is Comparable {
static zero { Card.new(Color.RED, Symbol.OVAL, Number.ONE, Shading.SOLID) }
 
construct new(color, symbol, number, shading) {
_color = color
_symbol = symbol
_number = number
_shading = shading
_value = color * 27 + symbol * 9 + number * 3 + shading
}
 
color { _color }
symbol { _symbol }
number { _number }
shading { _shading }
value { _value }
 
compare(other) { (_value - other.value).sign }
 
toString {
return Str.lower(Fmt.swrite("$-8s$-10s$-7s$-7s",
Color.members [_color],
Symbol.members [_symbol],
Number.members [_number],
Shading.members[_shading]
))
}
}
 
var createDeck = Fn.new {
var deck = List.filled(81, null)
for (i in 0...81) {
var col = (i/27).floor
var sym = (i/ 9).floor % 3
var num = (i/ 3).floor % 3
var shd = i % 3
deck[i] = Card.new(col, sym, num, shd)
}
return deck
}
 
var rand = Random.new()
 
var isSet = Fn.new { |trio|
var r1 = Nums.sum(trio.map { |c| c.color }) % 3
var r2 = Nums.sum(trio.map { |c| c.symbol }) % 3
var r3 = Nums.sum(trio.map { |c| c.number }) % 3
var r4 = Nums.sum(trio.map { |c| c.shading }) % 3
return r1 + r2 + r3 + r4 == 0
}
 
var playGame = Fn.new { |degree|
var deck = createDeck.call()
var nCards = (degree == Degree.BASIC) ? 9 : 12
var nSets = (nCards/2).floor
var sets = List.filled(nSets, null)
for (i in 0...nSets) sets[i] = [Card.zero, Card.zero, Card.zero]
var hand = []
while (true) {
rand.shuffle(deck)
hand = deck.take(nCards).toList
var count = 0
var hSize = hand.count
var outer = false
for (i in 0...hSize-2) {
for (j in i+1...hSize-1) {
for (k in j+1...hSize) {
var trio = [hand[i], hand[j], hand[k]]
if (isSet.call(trio)) {
sets[count] = trio
count = count + 1
if (count == nSets) {
outer = true
break
}
}
}
if (outer) break
}
if (outer) break
}
if (outer) break
}
Sort.quick(hand)
System.print("DEALT %(nCards) CARDS:\n")
System.print(hand.join("\n"))
System.print("\nCONTAINING %(nSets) SETS:\n")
for (s in sets) {
Sort.quick(s)
System.print(s.join("\n"))
System.print()
}
}
 
playGame.call(Degree.BASIC)
System.print()
playGame.call(Degree.ADVANCED)</syntaxhighlight>
 
{{out}}
Sample output:
<pre>
DEALT 9 CARDS:
 
red oval one open
red oval two open
green oval three striped
green squiggle one open
green squiggle two solid
green diamond one open
purple oval one solid
purple diamond three open
purple diamond three striped
 
CONTAINING 4 SETS:
 
red oval one open
green squiggle two solid
purple diamond three striped
 
red oval two open
green squiggle one open
purple diamond three open
 
red oval two open
green oval three striped
purple oval one solid
 
green oval three striped
green squiggle two solid
green diamond one open
 
 
DEALT 12 CARDS:
 
red oval one solid
red squiggle two solid
red squiggle three open
red diamond two solid
red diamond two striped
green oval two solid
green squiggle two striped
green diamond two open
green diamond two striped
purple oval two striped
purple diamond one solid
purple diamond two striped
 
CONTAINING 6 SETS:
 
red diamond two solid
green diamond two open
purple diamond two striped
 
red diamond two striped
green diamond two striped
purple diamond two striped
 
green oval two solid
green squiggle two striped
green diamond two open
 
red diamond two striped
green squiggle two striped
purple oval two striped
 
red oval one solid
red squiggle three open
red diamond two striped
 
red squiggle two solid
green diamond two open
purple oval two striped
</pre>
 
=={{header|zkl}}==
{{trans|D}}
<syntaxhighlight lang="zkl">const nDraw=9, nGoal=(nDraw/2); // Basic
var [const] UH=Utils.Helpers; // baked in stash of goodies
deck:=Walker.cproduct("red green purple".split(), // Cartesian product of 4 lists of lists
"one two three".split(), // T(1,2,3) (ie numbers) also works
"oval squiggle diamond".split(),
"solid open striped".split()).walk();
reg draw,sets,N=0;
do{ N+=1;
draw=deck.shuffle()[0,nDraw]; // one draw per shuffle
sets=UH.pickNFrom(3,draw) // 84 sets of 3 cards (each with 4 features)
.filter(fcn(set){ // list of 12 items (== 3 cards)
set[0,4].zip(set[4,4],set[8,4]) // -->4 tuples of 3 features
.pump(List,UH.listUnique,"len", // 1,3 (good) or 2 (bad)
'==(2)) // (F,F,F,F)==good
.sum(0) == 0 // all 4 feature sets good
});
}while(sets.len()!=nGoal);
println("Dealt %d cards %d times:".fmt(draw.len(),N));
draw.pump(Void,fcn(card){ println(("%8s "*4).fmt(card.xplode())) });
println("\nContaining:");
sets.pump(Void,fcn(card){ println((("%8s "*4 + "\n")*3).fmt(card.xplode())) });</syntaxhighlight>
{{out}}
<pre>
Dealt 9 cards 271 times:
red one oval solid
green one diamond striped
red two oval open
purple two squiggle striped
green three diamond open
purple three squiggle solid
purple one diamond striped
green three squiggle solid
green one squiggle open
 
Containing:
red one oval solid
purple two squiggle striped
green three diamond open
 
red one oval solid
purple one diamond striped
green one squiggle open
 
green one diamond striped
red two oval open
purple three squiggle solid
 
red two oval open
purple one diamond striped
green three squiggle solid
</pre>
9,476

edits