> 6) { case 0: $shape = "S"; break; case 1: $shape = "O"; break; case 2: $shape = "X"; break; default: $shape = "Z"; } switch (($card >> 4) & 0x3) { case 0: $returnString .= ""; break; case 1: $returnString .= ""; break; case 2: $returnString .= ""; break; default: $returnString .= ""; break; } switch (($card >> 2) & 0x3) { case 0: $returnString .= ""; break; case 1: $returnString .= ""; break; case 2: $returnString .= ""; break; default: $returnString .= ""; break; } switch ($card & 0x3) { case 0: $returnString .= $shape; break; case 1: $returnString .= $shape . $shape; break; case 2: $returnString .= $shape . $shape . $shape; break; default: $returnString .= $shape . $shape . $shape . $shape; break; } $returnString .= ""; return $returnString; } function miniCheck ($a, $b, $c) { return ($a == $b && $b == $c) || (($a ^ $b ^ $c) == 0x3); } //$doOnce=true; function setCheck($a, $b, $c) { return miniCheck($a >> 6, $b >> 6, $c >> 6) && miniCheck(($a >> 4) & 0x3, ($b >> 4) & 0x3, ($c >> 4) & 0x3) && miniCheck(($a >> 2) & 0x3, ($b >> 2) & 0x3, ($c >> 2) & 0x3) && miniCheck($a & 0x3, $b & 0x3, $c & 0x3); /* global $doOnce; $tempBool= miniCheck($a >> 6, $b >> 6, $c >> 6) && miniCheck(($a >> 4) & 0x3, ($b >> 4) & 0x3, ($c >> 4) & 0x3) && miniCheck(($a >> 2) & 0x3, ($b >> 2) & 0x3, ($c >> 2) & 0x3) && miniCheck($a & 0x3, $b & 0x3, $c & 0x3); if ($tempBool && $doOnce) { echo "(".($a >> 6).", ".($b >> 6).", ". ($c >> 6).") ". "(".(($a >> 4) & 0x3).", ".(($b >> 4) & 0x3).", ".(($c >> 4) & 0x3).") ". "(".(($a >> 2) & 0x3).", ".(($b >> 2) & 0x3).", ".(($c >> 2) & 0x3).") ". "(".($a & 0x3).", ".($b & 0x3).", ".($c & 0x3).")
\n"; $doOnce=false; } return $tempBool; */ } // setCheck() $maxBoard = 0; function boardCheck($newCard) { global $board; global $debugOutput; global $maxBoard; $setFound = false; for ($i = count($board) - 1; $i > 0; $i--) { for ($j = $i - 1; $j >= 0; $j--) { if (setCheck($newCard, $board[$i], $board[$j])) { $setFound = true; break 2; } } } if ($setFound) { $debugOutput .= "Set: $board[$i]:".printCard($board[$i])."   ". $board[$j].":".printCard($board[$j])."   ". $newCard.":".printCard($newCard)."
\n"; // remove the matching cards. Since we can't remove both cards simultaneously, // and $i is always larger, we must remove $i first, which shouldn't affect the key $j array_splice($board, $i, 1); array_splice($board, $j, 1); // don't add the new card } // add the new card else { $board[] = $newCard; if (count($board) > $maxBoard) { $maxBoard++; } } return $setFound; } ?>

A Set simulation with trials

0; $c--) { /* $tempCard = dealCard(); echo $c.":".printCard($tempCard)."  \n"; boardCheck($tempCard); */ boardCheck(dealCard()); } //echo "
".$debugOutput."
\nMax Board: $maxBoard
\n"; $debugOutput = ""; $outcomes[count($board)]++; if ($PRINT_HANDS && $g == 0) { $finalOutput .= "The features are Letter (S/X/O), ". "Size (Small/Medium/Large)
\n". "Color (Red/Green/Purple), ". "and Number (1/22/333)
\n"; } if ($g < $PRINT_HANDS) { $finalOutput .= "Board ".($g+1).": "; for ($i = 0; $i < count($board); $i++) { $finalOutput .= printCard($board[$i]); $finalOutput .= "   "; } $finalOutput .= "
\n"; } } // for each game ?>

Leftover Board Cards Frequency

Highest Board Size:

Games
Boards to Print

This simulation is currently hardcoded to use exactly 4 features and exactly 3 variations (per standard Set rules.) Perhaps in the future I will expand it to deal with a wider range of features and variations.