I made two solutions, both of which use the same basic algorithm of
applying weights (where smaller is better) to the cards and then
sorting by weight. The comments in the first "normal" version should
explain things.
The second version is my highly golfed version which I think is about
as small as my algorithm can get. It is 242 bytes. I would be very
interested to see if anyone can go smaller, either by tweaking mine
more, or more likely, by golfing another algorithm. Obviously the
golfed code has zero error handling, so it will probably choke on any
bad input.
Normal code:
class String
def to_suit
self[0..0].downcase
end
end
class EuchreSort
# These represent preferred sorting order
SUITS = %w{Diamonds Clubs Hearts Spades} # Alphabetical, then by color
CARDS = %w{A K Q J T 9} # Highest to lowest
def initialize(trump)
@trump = trump
trump_index = SUITS.index(trump)
raise "Invalid trump suit: #{trump}" unless trump_index
@right_bower = "J#{trump.to_suit}"
# The ordering used in SUITS ensures this works
@left_bower = "J#{SUITS[(trump_index+2)%4].to_suit}"
# Apply weights to suits starting from the trump, wrapping
# around as needed
@suit_weights = {}
weight = 10
trump_index.upto(trump_index+3) do |i|
@suit_weights[SUITS[i%4].to_suit] = weight
weight += 10
end
end
def sort(hand)
weights = {}
hand.each do |card|
raise "Invalid card: #{card}" if card !~ /\A[#{CARDS.join}]{1}[dchs]{1}\z/
weights[card] =
case card
when @right_bower: 0
when @left_bower: 1
else
@suit_weights[card[1..1]] + CARDS.index(card[0..0])
end
end
hand.sort_by {|c| weights[c]}
end
end
if $0 == __FILE__
hand = STDIN.collect {|i|i.chomp}
trump = hand.shift
es = EuchreSort.new(trump)
puts trump
puts es.sort(hand)
end
Golfed code (I'm not sure how Gmail will wrap this, but it should be
all on one line):
a=$<.read.split("\n");s=%w{d c h
s};c='AKQJT9';t=a.shift;u=(t[0]+32).chr;i=s.index(u);v=s[(i+2)%4];w=[1];i.upto(i+3){|j|w<<s[j%4]};m={};a.each{|k|m[k]=k=~/(J#{u})|(J#{v})/?$1?0:1:w.index(k[1..1])*10+c.index(k[0..0])};puts
t,a.sort_by{|k|m[k]}
Ryan