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())) });