Set, the card game: Difference between revisions

From Rosetta Code
Content added Content deleted
(Add Python)
(Added Wren)
Line 297: Line 297:


-----</pre>
-----</pre>

=={{header|Wren}}==
{{libheader|Wren-ioutil}}
{{libheader|Wren-fmt}}
{{libheader|Wren-perm}}
Note that entering 81 for the number of cards to deal confirms that there are 1080 possible sets.
<syntaxhighlight lang="ecmascript">import "random" for Random
import "./ioutil" for Input
import "./fmt" for Fmt
import "./perm" for Comb

var nums = ["one", "two", "three"]
var shas = ["solid", "striped", "open"]
var cols = ["red", "green", "purple"]
var syms = ["diamond", "oval", "squiggle"]

var pack = List.filled(81, null)
var i = 0
for (num in 0..2) {
for (sha in 0..2) {
for (col in 0..2) {
for (sym in 0..2) {
pack[i] = [nums[num], shas[sha], cols[col], syms[sym]]
i = i + 1
}
}
}
}

var printCards = Fn.new { |cards|
for (card in cards) {
var cstr = card.toString
var pl = card[0] != "one" ? "s" : ""
Fmt.print("$s $s $s $s$s", card[0], card[1], card[2], card[3], pl)
}
}

var findSets = Fn.new { |cards|
var sets = []
var trios = Comb.list(cards, 3)
for (trio in trios) {
var t1 = trio[0]
var t2 = trio[1]
var t3 = trio[2]
var found = true
for (i in 0..3) {
if (t1[i] == t2[i] && t2[i] == t3[i]) continue
if (t1[i] != t2[i] && t2[i] != t3[i] && t1[i] != t3[i]) continue
found = false
break
}
if (found) sets.add(trio)
}
Fmt.print("Sets present: $d\n", sets.count)
if (sets.count > 0) {
for (set in sets) {
printCards.call(set)
System.print()
}
}
}

var prompt = "Enter number of cards to deal - 3 to 81 or 2 to exit: "
while(true) {
Random.new().shuffle(pack) // shuffle for each deal
var i = Input.integer(prompt, 2, 81)
if (i == 2) return
var dealt = pack[0...i]
System.print()
printCards.call(dealt)
System.print()
findSets.call(dealt)
}</syntaxhighlight>

{{out}}
Sample run:
<pre>
Enter number of cards to deal - 3 to 81 or 2 to exit: 4

three solid green diamonds
one solid red diamond
one solid green oval
three striped purple squiggles

Sets present: 0

Enter number of cards to deal - 3 to 81 or 2 to exit: 8

one open green squiggle
one open purple squiggle
one solid green squiggle
three solid purple squiggles
three open green squiggles
one striped red diamond
one striped green oval
one striped green squiggle

Sets present: 1

one open green squiggle
one solid green squiggle
one striped green squiggle

Enter number of cards to deal - 3 to 81 or 2 to exit: 12

three open green ovals
three striped green diamonds
one solid purple oval
one striped purple diamond
two open green diamonds
three solid red diamonds
three solid red ovals
three solid green diamonds
three striped red ovals
three striped red squiggles
two open red squiggles
one solid green oval

Sets present: 3

three striped green diamonds
one solid purple oval
two open red squiggles

one solid purple oval
two open green diamonds
three striped red squiggles

one striped purple diamond
two open green diamonds
three solid red diamonds

Enter number of cards to deal - 3 to 81 or 2 to exit: 2
</pre>

Revision as of 14:06, 27 August 2023

Task
Set, the card game
You are encouraged to solve this task according to the task description, using any language you may know.
File:Fifteen set cards.jpg
twelve Set cards

The card game, Set, is played with a pack of 81 cards, each of which depicts either one, two, or three diamonds, ovals, or squiggles. The symbols are coloured red, green, or purple, and the shading is either solid, striped, or open. No two cards are identical.

In the game a number of cards are layed out face up and the players try to identify "sets" within the cards.

A set is three cards where either the symbols on the cards are the same or they are all different, the number of symbols on the cards are all the same or all different, the colours are all the same or all different, and the shadings are all the same or all different.

For example, this is a set:

two solid green ovals
one open green squiggle
three striped green diamonds

because each card depicts a different symbol, the number of symbols on each card is different, the colours are all the same, and the shadings are all different.

This is not a set:

two solid purple ovals
one open green squiggle
three striped green diamonds

because two of the cards are green and one is purple, so the colours are neither all the same nor all different.

task
  • Create a representation of a pack of Set cards, shuffle it, select a specified number of cards from the pack and list them in the output.
  • Identify the sets in the selected cards and list them.
Also see

Python

from itertools import combinations
from itertools import product
from random import shuffle
from typing import Iterable
from typing import List
from typing import NamedTuple
from typing import Tuple

NUMBERS = ("one", "two", "three")
SHAPES = ("diamond", "squiggle", "oval")
SHADING = ("solid", "striped", "open")
COLORS = ("red", "green", "purple")


class Card(NamedTuple):
    number: str
    shading: str
    color: str
    shape: str

    def __str__(self) -> str:
        s = " ".join(self)
        if self.number != "one":
            s += "s"
        return s


Cards = List[Card]


def new_deck() -> Cards:
    """Return a new shuffled deck of 81 unique cards."""
    deck = [Card(*features) for features in product(NUMBERS, SHADING, COLORS, SHAPES)]
    shuffle(deck)
    return deck


def deal(deck: Cards, n: int) -> Tuple[Cards, Cards]:
    """Return _n_ cards from the top of the deck and what remains of the deck."""
    return deck[:n], deck[n:]


def is_set(cards: Tuple[Card, Card, Card]) -> bool:
    """Return _True_ if _cards_ forms a set."""
    return (
        same_or_different(c.number for c in cards)
        and same_or_different(c.shape for c in cards)
        and same_or_different(c.shading for c in cards)
        and same_or_different(c.color for c in cards)
    )


def same_or_different(features: Iterable[str]) -> bool:
    """Return _True_ if _features_ are all the same or all different."""
    return len(set(features)) in (1, 3)


def print_sets_from_new_deck(n: int) -> None:
    """Display sets found in _n_ cards dealt from a new shuffled deck."""
    table, _ = deal(new_deck(), n)
    print(f"Cards dealt: {n}\n")
    print("\n".join(str(card) for card in table), end="\n\n")

    sets = [comb for comb in combinations(table, 3) if is_set(comb)]
    print(f"Sets present: {len(sets)}\n")
    for _set in sets:
        print("\n".join(str(card) for card in _set), end="\n\n")

    print("----")


if __name__ == "__main__":
    for n in (4, 8, 12):
        print_sets_from_new_deck(n)
Output:
Cards dealt: 4

two open green diamonds
three striped green ovals
two open purple ovals
two open red squiggles

Sets present: 1

two open green diamonds
two open purple ovals
two open red squiggles

----
Cards dealt: 8

three striped purple diamonds
one solid purple oval
two open purple diamonds
three solid purple diamonds
one solid green squiggle
three open green squiggles
three open purple squiggles
three solid purple ovals

Sets present: 1

three striped purple diamonds
three open purple squiggles
three solid purple ovals

----
Cards dealt: 12

two open green squiggles
three solid purple ovals
three open red diamonds
two open red squiggles
three open purple ovals
three open red squiggles
three striped red squiggles
two open purple diamonds
three solid red squiggles
one solid red squiggle
two striped purple diamonds
one solid red diamond

Sets present: 2

two open red squiggles
three striped red squiggles
one solid red squiggle

three open red squiggles
three striped red squiggles
three solid red squiggles

----

Quackery

transpose is defined at Matrix transposition#Quackery.

comb and arrange are defined at Combinations#Quackery.

  [ true swap transpose
    witheach
      [ 0 swap witheach +
        3 mod 0 > if
          [ not conclude ] ] ]     is isset    ( [ --> b )

  [ [ [] 81 times
      [ i 4 times
          [ 3 /mod swap ]
          drop
        3 times join
        nested join ] ] constant
    shuffle swap split drop ]      is cards    ( n --> [ )

  [ [] swap
    dup size swap
    3 rot comb
    witheach
      [ dip dup arrange
        dup isset iff
          [ nested rot
            join swap ]
        else drop ]
    drop ]                         is sets     ( [ --> [ )

  [ unpack dup dip
      [ [ table
          $ "one"
          $ "two"
          $ "three" ] do echo$ sp
        [ table
          $ "solid"
          $ "striped"
          $ "open" ] do echo$ sp
        [ table
          $ "red"
          $ "green"
          $ "purple" ] do echo$ sp
        [ table
          $ "diamond"
          $ "squiggle"
          $ "oval" ] do echo$ ]
    0 > if [ say "s" ]
    cr ]                              is echocard ( [ -->   )

  [ dup cards swap
    cr say "Cards dealt: " echo cr cr
    dup witheach echocard
    cr
    sets dup size
    say "Sets present: " echo cr cr
    witheach
       [ witheach echocard
         cr ] ]                       is play     ( n -->   )

  ' [ 4 8 12 ] witheach [ play say "-----" ]
Output:
Cards dealt: 4

two striped green squiggles
one open purple oval
one solid purple diamond
three open red diamonds

Sets present: 0

-----
Cards dealt: 8

three open purple squiggles
two open purple ovals
three solid purple ovals
three solid red squiggles
two striped purple diamonds
two solid green squiggles
one striped green oval
one open purple diamond

Sets present: 1

three open purple squiggles
two open purple ovals
one open purple diamond

-----
Cards dealt: 12

one solid green diamond
one striped red diamond
one open purple squiggle
two solid green diamonds
two striped green squiggles
two solid red ovals
two solid green squiggles
one open green squiggle
two solid green ovals
two solid red diamonds
one open purple diamond
three striped purple diamonds

Sets present: 3

two solid red ovals
one open green squiggle
three striped purple diamonds

two solid green diamonds
two solid green squiggles
two solid green ovals

one solid green diamond
one striped red diamond
one open purple diamond

-----

Wren

Library: Wren-ioutil
Library: Wren-fmt
Library: Wren-perm

Note that entering 81 for the number of cards to deal confirms that there are 1080 possible sets.

import "random" for Random
import "./ioutil" for Input
import "./fmt" for Fmt
import "./perm" for Comb

var nums = ["one", "two", "three"]
var shas = ["solid", "striped", "open"]
var cols = ["red", "green", "purple"]
var syms = ["diamond", "oval", "squiggle"]

var pack = List.filled(81, null)
var i = 0
for (num in 0..2) {
    for (sha in 0..2) {
        for (col in 0..2) {
            for (sym in 0..2) {
                pack[i] = [nums[num], shas[sha], cols[col], syms[sym]]
                i = i + 1
            }
        }
    }
}

var printCards = Fn.new { |cards|
    for (card in cards) {
        var cstr = card.toString
        var pl = card[0] != "one" ? "s" : ""
        Fmt.print("$s $s $s $s$s", card[0], card[1], card[2], card[3], pl)
    }
}

var findSets = Fn.new { |cards|
    var sets = []
    var trios = Comb.list(cards, 3)
    for (trio in trios) {
        var t1 = trio[0]
        var t2 = trio[1]
        var t3 = trio[2]
        var found = true
        for (i in 0..3) {
            if (t1[i] == t2[i] && t2[i] == t3[i]) continue
            if (t1[i] != t2[i] && t2[i] != t3[i] && t1[i] != t3[i]) continue
            found = false
            break
        }
        if (found) sets.add(trio)
    }
    Fmt.print("Sets present: $d\n", sets.count)
    if (sets.count > 0) {
        for (set in sets) {
            printCards.call(set)
            System.print()
        }
    }
}

var prompt = "Enter number of cards to deal - 3 to 81 or 2 to exit: "
while(true) {
    Random.new().shuffle(pack) // shuffle for each deal
    var i = Input.integer(prompt, 2, 81)
    if (i == 2) return
    var dealt = pack[0...i]
    System.print()
    printCards.call(dealt)
    System.print()
    findSets.call(dealt)
}
Output:

Sample run:

Enter number of cards to deal - 3 to 81 or 2 to exit: 4

three solid green diamonds
one solid red diamond 
one solid green oval 
three striped purple squiggles

Sets present: 0

Enter number of cards to deal - 3 to 81 or 2 to exit: 8

one open green squiggle 
one open purple squiggle 
one solid green squiggle 
three solid purple squiggles
three open green squiggles
one striped red diamond 
one striped green oval 
one striped green squiggle 

Sets present: 1

one open green squiggle 
one solid green squiggle 
one striped green squiggle 

Enter number of cards to deal - 3 to 81 or 2 to exit: 12

three open green ovals
three striped green diamonds
one solid purple oval 
one striped purple diamond 
two open green diamonds
three solid red diamonds
three solid red ovals
three solid green diamonds
three striped red ovals
three striped red squiggles
two open red squiggles
one solid green oval 

Sets present: 3

three striped green diamonds
one solid purple oval 
two open red squiggles

one solid purple oval 
two open green diamonds
three striped red squiggles

one striped purple diamond 
two open green diamonds
three solid red diamonds

Enter number of cards to deal - 3 to 81 or 2 to exit: 2