How to resolve the algorithm Set puzzle step by step in the Tcl programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Set puzzle step by step in the Tcl programming language

Table of Contents

Problem Statement

Set Puzzles are created with a deck of cards from the 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. Three cards form a set if each feature is either the same on each card, or is different on each card. For instance: all 3 cards are red, all 3 cards have a different symbol, all 3 cards have a different number of symbols, all 3 cards are striped. There are two degrees of difficulty: basic and advanced. The basic mode deals 9 cards, that contain 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.

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: DEALT 9 CARDS:

CONTAINING 4 SETS:

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Set puzzle step by step in the Tcl programming language

Source code in the tcl programming language

# Generate random integer uniformly on range [0..$n-1]
proc random n {expr {int(rand() * $n)}}

# Generate a shuffled deck of all cards; the card encoding was stolen from the
# Perl6 solution. This is done once and then used as a constant. Note that the
# rest of the code assumes that all cards in the deck are unique.
set ::AllCards [apply {{} {
    set cards {}
    foreach color {1 2 4} {
	foreach symbol {1 2 4} {
	    foreach number {1 2 4} {
		foreach shading {1 2 4} {
		    lappend cards [list $color $symbol $number $shading]
		}
	    }
	}
    }
    # Knuth-Morris-Pratt shuffle (not that it matters)
    for {set i [llength $cards]} {$i > 0} {} {
	set j [random $i]
	set tmp [lindex $cards [incr i -1]]
	lset cards $i [lindex $cards $j]
	lset cards $j $tmp
    }
    return $cards
}}]

# Randomly pick a hand of cards from the deck (itself in a global for
# convenience).
proc drawCards n {
    set cards $::AllCards;    # Copies...
    for {set i 0} {$i < $n} {incr i} {
	set idx [random [llength $cards]]
	lappend hand [lindex $cards $idx]
	set cards [lreplace $cards $idx $idx]
    }
    return $hand
}

# Test if a particular group of three cards is a valid set
proc isValidSet {a b c} {
    expr {
	  ([lindex $a 0]|[lindex $b 0]|[lindex $c 0]) in {1 2 4 7} &&
	  ([lindex $a 1]|[lindex $b 1]|[lindex $c 1]) in {1 2 4 7} &&
	  ([lindex $a 2]|[lindex $b 2]|[lindex $c 2]) in {1 2 4 7} &&
	  ([lindex $a 3]|[lindex $b 3]|[lindex $c 3]) in {1 2 4 7}
    }
}

# Get all unique valid sets of three cards in a hand.
proc allValidSets {hand} {
    set sets {}
    for {set i 0} {$i < [llength $hand]} {incr i} {
	set a [lindex $hand $i]
	set hand [set cards2 [lreplace $hand $i $i]]
	for {set j 0} {$j < [llength $cards2]} {incr j} {
	    set b [lindex $cards2 $j]
	    set cards2 [set cards3 [lreplace $cards2 $j $j]]
	    foreach c $cards3 {
		if {[isValidSet $a $b $c]} {
		    lappend sets [list $a $b $c]
		}
	    }
	}
    }
    return $sets
}

# Solve a particular version of the set puzzle, by picking random hands until
# one is found that satisfies the constraints. This is usually much faster
# than a systematic search. On success, returns the hand found and the card
# sets within that hand.
proc SetPuzzle {numCards numSets} {
    while 1 {
	set hand [drawCards $numCards]
	set sets [allValidSets $hand]
	if {[llength $sets] == $numSets} {
	    break
	}
    }
    return [list $hand $sets]
}


# Render a hand (or any list) of cards (the "."s are just placeholders).
proc PrettyHand {hand {separator \n}} {
    set Co {. red green . purple}
    set Sy {. oval squiggle . diamond}
    set Nu {. one two . three}
    set Sh {. solid open . striped}
    foreach card $hand {
	lassign $card co s n sh
	lappend result [format "(%s,%s,%s,%s)" \
		[lindex $Co $co] [lindex $Sy $s] [lindex $Nu $n] [lindex $Sh $sh]]
    }
    return $separator[join $result $separator]
}

# Render the output of the Set Puzzle solver.
proc PrettyOutput {setResult} {
    lassign $setResult hand sets
    set sep "\n   "
    puts "Hand (with [llength $hand] cards) was:[PrettyHand $hand $sep]"
    foreach s $sets {
	puts "Found set [incr n]:[PrettyHand $s $sep]"
    }
}

# Demonstrate on the two cases
puts "=== BASIC PUZZLE ========="
PrettyOutput [SetPuzzle 9 4]
puts "=== ADVANCED PUZZLE ======"
PrettyOutput [SetPuzzle 12 6]


  

You may also check:How to resolve the algorithm Loops/While step by step in the EchoLisp programming language
You may also check:How to resolve the algorithm Number reversal game step by step in the jq programming language
You may also check:How to resolve the algorithm Benford's law step by step in the Elixir programming language
You may also check:How to resolve the algorithm Polymorphic copy step by step in the Lua programming language
You may also check:How to resolve the algorithm Arbitrary-precision integers (included) step by step in the Dart programming language