COLORS   = %i(red green purple) 
SYMBOLS  = %i(oval squiggle diamond)
NUMBERS  = %i(one two three)
SHADINGS = %i(solid open striped)
DECK = COLORS.product(SYMBOLS, NUMBERS, SHADINGS)

def get_all_sets(hand) 
  hand.combination(3).select do |candidate|
    grouped_features = candidate.flatten.group_by{|f| f}
    grouped_features.values.none?{|v| v.size == 2}
  end
end

def get_puzzle_and_answer(hand_size, num_sets_goal)
  begin
    hand = DECK.sample(hand_size)
    sets = get_all_sets(hand)
  end until sets.size == num_sets_goal
  [hand, sets]
end

def print_cards(cards)
  puts cards.map{|card|  * 4 % card}
  puts
end

def set_puzzle(deal, goal=deal/2)
  puzzle, sets = get_puzzle_and_answer(deal, goal)
  puts 
  print_cards(puzzle)
  puts 
  sets.each{|set| print_cards(set)}
end

set_puzzle(9)
set_puzzle(12)