use strict;
use warnings;






my $fmt = '%4o';
my @deck = grep sprintf($fmt, $_) !~ tr/124//c, 01111 .. 04444;



my @features = map [split ' '], split /\n/,<<'';
! red   green    ! purple
! one   two      ! three
! oval  squiggle ! diamond
! solid open     ! striped

81 == @deck or die "There are ".@deck." cards (should be 81)";



my $draw = shift(@ARGV) || 9;
my $goal = int($draw/2);


my @combinations = combine(3, 0 .. $draw-1);

my @sets;

do {
	
	for my $i ( 0 .. $draw-1 ) {
		my $j = $i + int rand(@deck - $i);
		@deck[$i, $j] = @deck[$j, $i];
	}

	
	@sets = grep {
		my $or = 0;
		$or |= $_ for @deck[@$_];
		
		
		
		
		sprintf($fmt, $or) !~ tr/1247//c;
	} @combinations;

	
} until @sets == $goal;

print "Drew $draw cards:\n";
for my $i ( 0 .. $
	print "Set ", $i+1, ":\n";
	my @cards = @deck[ @{$sets[$i]} ];
	for my $card ( @cards ) {
		my @octal = split //, sprintf '%4o', $card;
		my @f = map $features[$_][$octal[$_]], 0 .. 3;
		printf "   %-6s%-5s%-8s%s\n", @f;
	}
}

exit;



sub combine {
	my $n = shift;
	return unless @_;
	return map [$_], @_ if $n == 1;
	my $head = shift;
	my @result = combine( $n-1, @_ );
	unshift @$_, $head for @result;
	@result, combine( $n, @_ );
}

__END__