RosettaCodeData/Task/Set-puzzle/AutoHotkey/set-puzzle.ahk
2023-07-01 13:44:08 -04:00

104 lines
2.7 KiB
AutoHotkey

; Generate deck; card encoding from Raku
Loop, 81
deck .= ToBase(A_Index-1, 3)+1111 ","
deck := RegExReplace(deck, "3", "4")
; Shuffle
deck := shuffle(deck)
msgbox % clipboard := allValidSets(9, 4, deck)
msgbox % clipboard := allValidSets(12, 6, deck)
; Render a hand (or any list) of cards
PrettyHand(hand) {
Color1:="red",Color2:="green",Color4:="purple"
,Symbl1:="oval",Symbl2:="squiggle",Symbl4:="diamond"
,Numbr1:="one",Numbr2:="two",Numbr4:="three"
,Shape1:="solid",Shape2:="open",Shape4:="striped"
Loop, Parse, hand, `,
{
StringSplit, i, A_LoopField
s .= "`t" Color%i1% "`t" Symbl%i2% "`t" Numbr%i3% "`t" Shape%i4% "`n"
}
Return s
}
; Get all unique valid sets of three cards in a hand.
allValidSets(n, m, deck) {
While j != m
{
j := 0
,hand := draw(n, deck)
,s := "Dealt " n " cards:`n" . prettyhand(hand)
StringSplit, set, hand, `,
comb := comb(n,3)
Loop, Parse, comb, `n
{
StringSplit, i, A_LoopField, %A_Space%
If isValidSet(set%i1%, set%i2%, set%i3%)
s .= "`nSet " ++j ":`n" . prettyhand(set%i1% "," set%i2% "," set%i3%)
}
}
Return s
}
; Convert n to arbitrary base using recursion
toBase(n,b) { ; n >= 0, 1 < b < StrLen(t), t = digits
Static t := "0123456789ABCDEF"
Return (n < b ? "" : ToBase(n//b,b)) . SubStr(t,mod(n,b)+1,1)
}
; Knuth shuffle from http://rosettacode.org/wiki/Knuth_Shuffle#AutoHotkey
shuffle(list) { ; shuffle comma separated list, converted to array
StringSplit a, list, `, ; make array (length = a0)
Loop % a0-1 {
Random i, A_Index, a0 ; swap item 1,2... with a random item to the right of it
t := a%i%, a%i% := a%A_Index%, a%A_Index% := t
}
Loop % a0 ; construct string from sorted array
s .= "," . a%A_Index%
Return SubStr(s,2) ; drop leading comma
}
; Randomly pick a hand of cards from the deck
draw(n, deck) {
Loop, % n
{
Random, i, 1, 81
cards := deck
Loop, Parse, cards, `,
(A_Index = i) ? (hand .= A_LoopField ",") : (cards .= A_LoopField ",")
deck := cards
}
Return SubStr(hand, 1, -1)
}
; Test if a particular group of three cards is a valid set
isValidSet(a, b, c) {
StringSplit, a, a
StringSplit, b, b
StringSplit, c, c
Return !((a1|b1|c1 ~= "[3,5,6]") + (a2|b2|c2 ~= "[3,5,6]") + (a3|b3|c3 ~= "[3,5,6]") + (a4|b4|c4 ~= "[3,5,6]"))
}
; Get all combinations, from http://rosettacode.org/wiki/Combinations#AutoHotkey
comb(n,t) { ; Generate all n choose t combinations of 1..n, lexicographically
IfLess n,%t%, Return
Loop %t%
c%A_Index% := A_Index
i := t+1, c%i% := n+1
Loop {
Loop %t%
i := t+1-A_Index, c .= c%i% " "
c .= "`n" ; combinations in new lines
j := 1, i := 2
Loop
If (c%j%+1 = c%i%)
c%j% := j, ++j, ++i
Else Break
If (j > t)
Return c
c%j% += 1
}
}