Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa07dfa48b | ||
|
|
c864cf5cdb | ||
|
|
9a87aca70c | ||
|
|
60b003181e | ||
|
|
c148da33bc | ||
|
|
38a2f3de9c | ||
|
|
74e225b229 | ||
|
|
d33d08fc03 | ||
|
|
701d78a818 | ||
|
|
33da302968 |
No files matched your search
@@ -0,0 +1,375 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'pp'
|
||||
|
||||
# RULE 1. Orange cards have a basic value of 4 and are equal to a red card and a yellow card.
|
||||
# RULE 2. White cards have the highest basic value and are equal to a red card and a blue card.
|
||||
# RULE 3. Blue cards have a basic value of twice that of yellow and half that of orange.
|
||||
# yellow = 1, blue = 2, red = 3, orange = 4, and white = 5
|
||||
|
||||
BaseValues = { :yellow => 1, :blue => 2, :red => 3, :orange => 4, :white => 5 }
|
||||
|
||||
class Card
|
||||
include Comparable
|
||||
attr_reader :color
|
||||
|
||||
def initialize(color)
|
||||
@color = color
|
||||
@multiplier = 1
|
||||
end
|
||||
|
||||
def double!
|
||||
@multiplier *= 2
|
||||
end
|
||||
|
||||
def quadruple!
|
||||
@multiplier *= 4
|
||||
end
|
||||
|
||||
def is_doubled?
|
||||
@multiplier == 2
|
||||
end
|
||||
|
||||
def is_quadrupled?
|
||||
@multiplier == 4
|
||||
end
|
||||
|
||||
def zero!
|
||||
@multiplier = 0
|
||||
end
|
||||
|
||||
def to_s
|
||||
@color.to_s
|
||||
end
|
||||
|
||||
def value
|
||||
BaseValues[@color] * @multiplier
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
# sort by color's base value (i.e. by color), then value
|
||||
# note default is a reverse sort (high to low)
|
||||
[BaseValues[other.color],other.value] <=> [BaseValues[@color],value]
|
||||
end
|
||||
end
|
||||
|
||||
class Hand
|
||||
|
||||
# TODO
|
||||
# attributes: flags (most of a color, etc.), bonuses, suit values, hand multiplier, card multiplier
|
||||
attr_reader :name
|
||||
attr_reader :score
|
||||
|
||||
def initialize(name,yellow,blue,red,orange,white)
|
||||
@name = name
|
||||
@hand_multiplier = 1
|
||||
@bonus = 0
|
||||
@blue_hits = 0
|
||||
@score = nil
|
||||
|
||||
# RULE 5. A player can score only as many orange cards as he has blue cards.
|
||||
if orange > blue
|
||||
puts "*** RULE 5 *** can only score as many orange cards as blue cards"
|
||||
puts "#{@name} lost #{orange - blue} orange cards."
|
||||
orange = blue
|
||||
puts
|
||||
end
|
||||
|
||||
# create hands
|
||||
@cards = []
|
||||
yellow.times { @cards << Card.new(:yellow) }
|
||||
blue.times { @cards << Card.new(:blue) }
|
||||
red.times { @cards << Card.new(:red) }
|
||||
orange.times { @cards << Card.new(:orange) }
|
||||
white.times { @cards << Card.new(:white) }
|
||||
|
||||
#
|
||||
# RULE 15. No more than thirteen cards in a hand can be scored. If more are handed in, the excess will be removed at random.
|
||||
#
|
||||
# check rule 15 straight away.. 13 card limit, excess deleted at random
|
||||
if size > 13
|
||||
puts "*** RULE 15 *** hand size too big (13 max)"
|
||||
puts "#{@name} has too many cards (#{size})."
|
||||
(size-13).times { puts " lost a #{rand_delete} card at random."}
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
# double hand
|
||||
def double!
|
||||
@hand_multiplier *= 2
|
||||
puts "#{@name}'s hand is doubled."
|
||||
end
|
||||
|
||||
# convert to a string
|
||||
def to_s
|
||||
"#{yellow} yellow, #{blue} blue, #{red} red, #{orange} orange, #{white} white"
|
||||
end
|
||||
|
||||
# individual color counts
|
||||
def count_color(color)
|
||||
@cards.count { |x| x.color == color }
|
||||
end
|
||||
def yellow; count_color(:yellow); end
|
||||
def blue; count_color(:blue); end
|
||||
def red; count_color(:red); end
|
||||
def orange; count_color(:orange); end
|
||||
def white; count_color(:white); end
|
||||
|
||||
# removes one randome card
|
||||
def rand_delete
|
||||
# return randomly deleted card (or nil if array is empty)
|
||||
@cards.slice!(Kernel.rand(@cards.size))
|
||||
end
|
||||
|
||||
# total number of cards
|
||||
def size
|
||||
@cards.size
|
||||
end
|
||||
|
||||
def counts
|
||||
[yellow,blue,red,orange,white]
|
||||
end
|
||||
|
||||
def is_pyramid?
|
||||
counts.sort == [0,1,2,3,4]
|
||||
end
|
||||
|
||||
def sets_of_all_five_colors
|
||||
counts.min
|
||||
end
|
||||
|
||||
def num_sets(color,set_size)
|
||||
count_color(color) / set_size
|
||||
end
|
||||
|
||||
def largest_color
|
||||
counts.max
|
||||
end
|
||||
|
||||
def add_bonus!(amount)
|
||||
puts "#{@name} got a bonus of #{amount}."
|
||||
@bonus += amount
|
||||
end
|
||||
|
||||
def blue_hit!(hitter = "")
|
||||
puts "#{hitter} hit #{@name} for 10 points."
|
||||
@blue_hits += 1
|
||||
end
|
||||
|
||||
def double_red!
|
||||
puts "#{@name} now has all red cards doubled in value."
|
||||
@cards.select {|h| h.color == :red }.each(&:double!)
|
||||
end
|
||||
|
||||
def calculate_score!
|
||||
|
||||
# return if we already calculated this!
|
||||
return @score unless @score.nil?
|
||||
|
||||
# otherwise start at 0
|
||||
@score = 0
|
||||
|
||||
# print a little summary
|
||||
puts "Scoring #{@name}"
|
||||
puts "========" + "=" * @name.size
|
||||
puts "* has #{to_s}"
|
||||
puts "* starts with a bonus of #{@bonus}."
|
||||
puts "* starts with a hand multiplier of #{@hand_multiplier}."
|
||||
puts "* has been hit #{@blue_hits} times for -10 points each (#{-10 * @blue_hits} total)."
|
||||
puts
|
||||
|
||||
# RULE 4. If a player has more than three white cards, all of his white cards lose their value.
|
||||
if white > 3
|
||||
puts "*** RULE 4 *** if a player has more than 3 white, all white lose their value"
|
||||
puts "#{@name} has #{white} white cards. setting all to 0."
|
||||
@cards.select { |c| c.color == :white }.each(&:zero!)
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 7. A set of three red cards protects you from one set of five blue cards.
|
||||
if num_sets(:red,3) > 0
|
||||
puts "*** RULE 7 *** A set of three red protects you from one hit of five blue"
|
||||
puts "#{@name} has a set of red; reducing hits from blue by one (+10 points)."
|
||||
@blue_hits -= 1
|
||||
@blue_hits = 0 if @blue_hits < 0
|
||||
puts "after reduction, #{@name} has been hit #{@blue_hits} times for -10 points each (#{-10 * @blue_hits} total)."
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 10. Each set of five different colors gives a bonus of 10 points.
|
||||
if sets_of_all_five_colors > 0
|
||||
puts "*** RULE 10 *** each set of all five colors gives a bonus of 10"
|
||||
sets_of_all_five_colors.times { add_bonus!(10) }
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 11. If a "pyramid" is handed in with no other cards, the value of the hand is doubled. A pyramid consists of four cards of one color, three cards of a second color, two cards of a third color, and one card of a fourth color.
|
||||
if is_pyramid?
|
||||
@hand_multiplier *= 2
|
||||
puts "*** RULE 11 *** 'pyramid' hands are doubled"
|
||||
puts "#{@name} has a pyramid; new hand multiplier is #{@hand_multiplier}."
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 13. Each set of two yellow cards doubles the value of one white card.
|
||||
yellow_sets = num_sets(:yellow,2)
|
||||
if yellow_sets > 0
|
||||
puts "*** RULE 13 *** each set of 2 yellow doubles 1 white"
|
||||
whites_to_double = [white,yellow_sets].min
|
||||
puts "#{@name} has #{yellow_sets} sets; doubling #{whites_to_double} white cards."
|
||||
@cards.select{ |x| x.color == :white }.take(yellow_sets).each(&:double!)
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 14. Each set of three blue cards quadruples the value of one orange card.
|
||||
blue_sets = num_sets(:blue,3)
|
||||
if blue_sets > 0
|
||||
puts "*** RULE 14 *** each set of 3 blue doubles 1 orange"
|
||||
oranges_to_double = [orange,blue_sets].min
|
||||
puts "#{@name} has #{blue_sets} sets; quadrupling #{oranges_to_double} orange cards."
|
||||
@cards.select{ |x| x.color == :orange }.take(blue_sets).each(&:quadruple!)
|
||||
puts
|
||||
end
|
||||
|
||||
# add up score
|
||||
@score = @cards.inject(0) { |sum,x| sum + x.value } + @bonus + @blue_hits * -10
|
||||
|
||||
puts "Final Tally for #{@name}"
|
||||
puts "================" + "=" * @name.size
|
||||
# compute score based on all the scoring attributes set by the scorer
|
||||
@cards.sort.each { |x| puts " %4d %s" % [x.value,x] }
|
||||
puts " %4d [bonus]" % [@bonus]
|
||||
puts "+ %4d [hits]" % [@blue_hits * -10]
|
||||
puts "--------------------"
|
||||
puts " %4d subtotal" % [@score]
|
||||
puts "x %4d [multiplier]" % [@hand_multiplier]
|
||||
puts "--------------------"
|
||||
@score *= @hand_multiplier
|
||||
puts " %4d TOTAL" % [@score]
|
||||
puts
|
||||
|
||||
puts
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
# default is reverse sort (high to low)
|
||||
other.score <=> score
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
puts "***************************"
|
||||
puts "*** V A L I D A T I O N ***"
|
||||
puts "***************************"
|
||||
puts
|
||||
|
||||
@hands = []
|
||||
@hands << Hand.new("Hand #1",0,6,1,3,1) # 56 + other players -10
|
||||
@hands << Hand.new("Hand #2",3,2,2,3,3) # 51 (includes -10 for Hand #1)
|
||||
@hands << Hand.new("Hand #3",0,2,5,2,2) # 52 (Hand #1's -10 is deflected)
|
||||
@hands << Hand.new("Hand #4",4,2,3,0,1) # 54
|
||||
@hands << Hand.new("Hand #5",6,0,1,0,2) # 55
|
||||
|
||||
|
||||
####
|
||||
#### Global Rules Arbitration
|
||||
####
|
||||
|
||||
puts "***********************************"
|
||||
puts "*** G L O B A L S C O R I N G ***"
|
||||
puts "***********************************"
|
||||
puts
|
||||
|
||||
# RULE 9. If a player hands in seven or more cards of the same color, he is eliminated from the game.
|
||||
@hands.each do |h|
|
||||
if h.largest_color >= 7
|
||||
puts "*** RULE 9 *** seven or more cards of one suit causes elimination"
|
||||
puts "#{h.name} is eliminated (#{h})!"
|
||||
puts
|
||||
end
|
||||
end
|
||||
@hands.reject! { |h| h.largest_color >= 7 } # do the actual elimination
|
||||
|
||||
# RULE 8. The player with the most yellow cards gets a bonus of the number of cards squared.
|
||||
# (For example, if most yellow cards are 5, bonus is 25.) If two or more players tie for most
|
||||
# yellow, they are eliminated and bonus goes to the next highest.
|
||||
|
||||
# figure out the highest yellow count
|
||||
max_yellow = @hands.map(&:yellow).max
|
||||
|
||||
# now select the players with that amount
|
||||
max_yellow_hands = @hands.select{ |h| h.yellow == max_yellow }
|
||||
|
||||
# now apply rule
|
||||
if max_yellow_hands.size > 1
|
||||
puts "*** RULE 8 *** players tied for most yellow are eliminated!"
|
||||
max_yellow_hands.each { |h| puts "#{h.name} is eliminated (#{h})!" }
|
||||
@hands = @hands - max_yellow_hands
|
||||
puts
|
||||
elsif max_yellow_hands.size == 1
|
||||
puts "*** RULE 8 *** player with most yellow gets a bonus of number of cards squared"
|
||||
max_yellow_hands[0].add_bonus!(max_yellow_hands[0].yellow ** 2)
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 12. The player with the most red cards doubles their value. In case of a tie, no player collects the extra value.
|
||||
|
||||
# first get the guy(s) with the most red
|
||||
max_red = @hands.map(&:red).max
|
||||
max_red_hands = @hands.select { |h| h.red == max_red }
|
||||
|
||||
# apply rule
|
||||
if max_red_hands.size > 1
|
||||
puts "*** RULE 12 *** in case of a tie (for most red), no player collects the extra value"
|
||||
max_red_hands.each { |h| puts "#{h.name} is tied (#{h.red} red cards)."}
|
||||
puts
|
||||
elsif max_red_hands.size == 1
|
||||
puts "*** RULE 12 *** player with most red cards doubles their value"
|
||||
max_red_hands[0].double_red!
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 6. If a player has five or more blue cards, 10 points are deducted from every other player's score.
|
||||
@hands.each do |h|
|
||||
if h.blue >= 5
|
||||
puts "*** RULE 6 *** a player with 5 or more blue deducts 10 points from all other players score"
|
||||
(@hands - [h]).each { |x| x.blue_hit!(h.name) }
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
####
|
||||
#### Summary, after eliminations, eliminated cards, etc.
|
||||
####
|
||||
puts "*********************************"
|
||||
puts "*** F I N A L E N T R I E S ***"
|
||||
puts "*********************************"
|
||||
puts
|
||||
@hands.sort_by(&:name).each { |h| puts "#{h.name}: #{h}"}
|
||||
puts
|
||||
|
||||
####
|
||||
#### Local Rules
|
||||
####
|
||||
|
||||
# second, iterate through each hand and count up local scoring rules; apply to each hand
|
||||
puts "*******************************"
|
||||
puts "*** H A N D S C O R I N G ***"
|
||||
puts "*******************************"
|
||||
puts
|
||||
@hands.sort_by(&:name).each(&:calculate_score!)
|
||||
|
||||
|
||||
####
|
||||
#### Final ranking
|
||||
####
|
||||
puts "*******************************"
|
||||
puts "*** F I N A L S C O R E S ***"
|
||||
puts "*******************************"
|
||||
puts
|
||||
@hands.sort.each_with_index { |h,i| puts "#{i+1}. #{h.name}: #{h.score} points" }
|
||||
puts
|
||||
|
||||
|
||||
@@ -0,0 +1,501 @@
|
||||
#!/usr/bin/env ruby -w
|
||||
|
||||
####
|
||||
#### Haggle scoring script
|
||||
#### =====================
|
||||
####
|
||||
#### Using Haggle rules (and test cases) from "A Gamut of Games", by Sid Sackson
|
||||
####
|
||||
|
||||
|
||||
#################################################################################
|
||||
### raw user data goes here! ####################################################
|
||||
#################################################################################
|
||||
|
||||
PlayerData = [
|
||||
|
||||
|
||||
##
|
||||
## test cases from "A Gamut of Games", by Sid Sackson
|
||||
##
|
||||
# +---------------+--------+--------+--------+--------+--------+
|
||||
# | NAME | YELLOW | PURPLE | PINK | ORANGE | WHITE |
|
||||
# +---------------+--------+--------+--------+--------+--------+
|
||||
#%w( hand_1 0 6 1 3 1 ), # test case, 56 pts.
|
||||
#%w( hand_2 3 2 2 3 3 ), # test case, 51 pts.
|
||||
#%w( hand_3 0 2 5 2 2 ), # test case, 52 pts.
|
||||
#%w( hand_4 4 2 3 0 1 ), # test case, 54 pts.
|
||||
#%w( hand_5 6 0 1 0 2 ), # test case, 55 pts.
|
||||
|
||||
##
|
||||
## played on July 31st, 2010
|
||||
##
|
||||
# +---------------+--------+--------+--------+--------+--------+
|
||||
# | NAME | YELLOW | PURPLE | PINK | ORANGE | WHITE |
|
||||
# +---------------+--------+--------+--------+--------+--------+
|
||||
%w( darla 4 6 3 3 3 ),
|
||||
%w( randy_y 1 3 2 0 4 ),
|
||||
%w( dundee 0 5 3 1 1 ),
|
||||
%w( casey 2 0 3 2 4 ),
|
||||
%w( vince 0 2 3 3 1 ),
|
||||
%w( matt 2 1 4 2 0 ),
|
||||
%w( josh 6 1 3 0 3 ),
|
||||
%w( bill 0 5 0 5 0 ),
|
||||
%w( fred 0 0 0 0 0 ),
|
||||
%w( aaron 0 0 0 0 0 ),
|
||||
%w( jacob 1 2 0 3 0 ),
|
||||
%w( shioui 0 2 3 2 6 ),
|
||||
%w( susan 1 4 1 3 2 ),
|
||||
%w( derek 1 0 0 0 0 ),
|
||||
%w( ratdogg 2 0 2 0 6 ),
|
||||
%w( eileen 3 3 4 3 0 ),
|
||||
%w( sarah_n 2 3 3 1 4 ),
|
||||
%w( tj 2 3 3 2 3 ),
|
||||
%w( ann 3 0 2 3 0 ),
|
||||
%w( randy_s 2 0 5 0 6 ),
|
||||
%w( adam 5 4 1 4 1 ),
|
||||
%w( steven 4 1 2 0 3 ),
|
||||
%w( sarah_w 1 0 0 0 0 ),
|
||||
%w( chris 0 5 0 5 0 ),
|
||||
%w( katie 2 3 3 4 1 ),
|
||||
%w( bonnie 2 5 3 2 2 ),
|
||||
|
||||
]
|
||||
|
||||
|
||||
#################################################################################
|
||||
### script begin ################################################################
|
||||
#################################################################################
|
||||
|
||||
# seed random number generator for consistent results across runs (using my birthday)
|
||||
Kernel.srand(032472)
|
||||
|
||||
# RULE 1. Orange cards have a basic value of 4 and are equal to a pink card and a yellow card.
|
||||
# RULE 2. White cards have the highest basic value and are equal to a pink card and a purple card.
|
||||
# RULE 3. Purple cards have a basic value of twice that of yellow and half that of orange.
|
||||
# yellow = 1, purple = 2, pink = 3, orange = 4, and white = 5
|
||||
BaseValues = { :yellow => 1, :purple => 2, :pink => 3, :orange => 4, :white => 5 }
|
||||
|
||||
|
||||
####
|
||||
#### a single card
|
||||
####
|
||||
class Card
|
||||
include Comparable
|
||||
attr_reader :color
|
||||
|
||||
# constructor
|
||||
def initialize(color)
|
||||
@color = color
|
||||
@multiplier = 1
|
||||
end
|
||||
|
||||
# double value of this card
|
||||
def double!
|
||||
@multiplier *= 2
|
||||
end
|
||||
|
||||
# quadruple value of this card
|
||||
def quadruple!
|
||||
@multiplier *= 4
|
||||
end
|
||||
|
||||
# test if card is doubled
|
||||
def is_doubled?
|
||||
@multiplier == 2
|
||||
end
|
||||
|
||||
# test if card is quadrupled
|
||||
def is_quadrupled?
|
||||
@multiplier == 4
|
||||
end
|
||||
|
||||
# zero out a card's value
|
||||
def zero!
|
||||
@multiplier = 0
|
||||
end
|
||||
|
||||
# create a string description of this card
|
||||
def to_s
|
||||
base = BaseValues[@color]
|
||||
comment_str =
|
||||
if is_doubled?
|
||||
" (doubled, was #{base})"
|
||||
elsif is_quadrupled?
|
||||
" (quadrupled, was #{base})"
|
||||
elsif ( value == 0 )
|
||||
" (zeroed, was #{base})"
|
||||
else
|
||||
""
|
||||
end
|
||||
@color.to_s + comment_str
|
||||
end
|
||||
|
||||
# get card's current value
|
||||
def value
|
||||
BaseValues[@color] * @multiplier
|
||||
end
|
||||
|
||||
# comparison (for sorting)
|
||||
def <=>(other)
|
||||
# sort by color's base value (i.e. by color), then value
|
||||
# note default is a reverse sort (high to low)
|
||||
[BaseValues[other.color],other.value] <=> [BaseValues[@color],value]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
####
|
||||
#### a single hand (contains cards)
|
||||
####
|
||||
class Hand
|
||||
|
||||
attr_reader :name
|
||||
attr_reader :score
|
||||
|
||||
# constructor
|
||||
def initialize(name,yellow,purple,pink,orange,white)
|
||||
@name = name
|
||||
@hand_multiplier = 1
|
||||
@bonus = 0
|
||||
@blue_hits = 0
|
||||
@score = nil
|
||||
|
||||
# RULE 5. A player can score only as many orange cards as he has purple cards.
|
||||
if orange > purple
|
||||
puts "*** RULE 5 *** can only score as many orange cards as purple cards"
|
||||
puts "#{@name} lost #{orange - purple} orange cards."
|
||||
orange = purple
|
||||
puts
|
||||
end
|
||||
|
||||
# populate hand with Card objects
|
||||
@cards = []
|
||||
yellow.times { @cards << Card.new(:yellow) }
|
||||
purple.times { @cards << Card.new(:purple) }
|
||||
pink.times { @cards << Card.new(:pink) }
|
||||
orange.times { @cards << Card.new(:orange) }
|
||||
white.times { @cards << Card.new(:white) }
|
||||
|
||||
#
|
||||
# RULE 15. No more than thirteen cards in a hand can be scored. If more are handed in,
|
||||
# the excess will be removed at random.
|
||||
#
|
||||
# check rule 15 straight away.. 13 card limit, excess deleted at random
|
||||
if size > 13
|
||||
puts "*** RULE 15 *** hand size too big (13 max)"
|
||||
puts "#{@name} has too many cards (#{size})."
|
||||
(size-13).times { puts " lost a #{rand_delete} card at random."}
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
# double hand
|
||||
def double!
|
||||
@hand_multiplier *= 2
|
||||
puts "#{@name}'s hand is doubled."
|
||||
end
|
||||
|
||||
# convert to a string
|
||||
def to_s
|
||||
"#{yellow} yellow, #{purple} purple, #{pink} pink, #{orange} orange, #{white} white"
|
||||
end
|
||||
|
||||
# get individual color counts
|
||||
def count_color(color)
|
||||
@cards.count { |x| x.color == color }
|
||||
end
|
||||
def yellow; count_color(:yellow); end
|
||||
def purple; count_color(:purple); end
|
||||
def pink; count_color(:pink); end
|
||||
def orange; count_color(:orange); end
|
||||
def white; count_color(:white); end
|
||||
|
||||
# removes one randome card
|
||||
def rand_delete
|
||||
# return randomly deleted card (or nil if array is empty)
|
||||
@cards.slice!(Kernel.rand(@cards.size))
|
||||
end
|
||||
|
||||
# total number of cards
|
||||
def size
|
||||
@cards.size
|
||||
end
|
||||
|
||||
# create an array of counts in specific order (used for sorting, various measurement fn's)
|
||||
def counts
|
||||
[yellow,purple,pink,orange,white]
|
||||
end
|
||||
|
||||
# test for a "pyramid"
|
||||
def is_pyramid?
|
||||
counts.sort == [0,1,2,3,4]
|
||||
end
|
||||
|
||||
# count sets of all five colors
|
||||
def sets_of_all_five_colors
|
||||
counts.min
|
||||
end
|
||||
|
||||
# count for sets (of size X) in color Y.. i.e. "sets of 2 in blue (i.e. pairs)"
|
||||
def num_sets(color,set_size)
|
||||
count_color(color) / set_size
|
||||
end
|
||||
|
||||
# return the size of the largest color
|
||||
def largest_color
|
||||
counts.max
|
||||
end
|
||||
|
||||
# add bonus points to this hand
|
||||
def add_bonus!(amount)
|
||||
puts "#{@name} got a bonus of #{amount}."
|
||||
@bonus += amount
|
||||
end
|
||||
|
||||
# add a "blue hit" (i.e. purple in our game) to this hand
|
||||
def blue_hit!(hitter = "")
|
||||
puts "#{hitter} hit #{@name} for 10 points."
|
||||
@blue_hits += 1
|
||||
end
|
||||
|
||||
# double the value of all red (pink on our game) cards
|
||||
def double_red!
|
||||
puts "#{@name} now has all pink cards doubled in value."
|
||||
@cards.select {|h| h.color == :pink }.each(&:double!)
|
||||
end
|
||||
|
||||
# figure out this hand's score (meant to be called once)
|
||||
def calculate_score!
|
||||
|
||||
# return if we already calculated this!
|
||||
return @score unless @score.nil?
|
||||
|
||||
# otherwise start at 0
|
||||
@score = 0
|
||||
|
||||
# print a little summary
|
||||
puts "Scoring #{@name}"
|
||||
puts "========" + "=" * @name.size
|
||||
puts "* has #{to_s}"
|
||||
puts "* starts with a bonus of #{@bonus}."
|
||||
puts "* starts with a hand multiplier of #{@hand_multiplier}."
|
||||
puts "* has been hit #{@blue_hits} times for -10 points each (#{-10 * @blue_hits} total)."
|
||||
puts
|
||||
|
||||
# RULE 4. If a player has more than three white cards, all of his white cards lose their value.
|
||||
if white > 3
|
||||
puts "*** RULE 4 *** if a player has more than 3 white, all white lose their value"
|
||||
puts "#{@name} has #{white} white cards. setting all to 0."
|
||||
@cards.select { |c| c.color == :white }.each(&:zero!)
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 7. A set of three pink cards protects you from one set of five purple cards.
|
||||
if num_sets(:pink,3) > 0
|
||||
puts "*** RULE 7 *** A set of three pink protects you from one hit of five purple"
|
||||
puts "#{@name} has a set of pink; reducing hits from purple by one (+10 points)."
|
||||
@blue_hits -= 1
|
||||
@blue_hits = 0 if @blue_hits < 0
|
||||
puts "after reduction, #{@name} has been hit #{@blue_hits} times for -10 points each (#{-10 * @blue_hits} total)."
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 10. Each set of five different colors gives a bonus of 10 points.
|
||||
if sets_of_all_five_colors > 0
|
||||
puts "*** RULE 10 *** each set of all five colors gives a bonus of 10"
|
||||
sets_of_all_five_colors.times { add_bonus!(10) }
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 11. If a "pyramid" is handed in with no other cards, the value of the hand is
|
||||
# doubled. A pyramid consists of four cards of one color, three cards of a second color,
|
||||
# two cards of a third color, and one card of a fourth color.
|
||||
if is_pyramid?
|
||||
@hand_multiplier *= 2
|
||||
puts "*** RULE 11 *** 'pyramid' hands are doubled"
|
||||
puts "#{@name} has a pyramid; new hand multiplier is #{@hand_multiplier}."
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 13. Each set of two yellow cards doubles the value of one white card.
|
||||
yellow_sets = num_sets(:yellow,2)
|
||||
if yellow_sets > 0
|
||||
puts "*** RULE 13 *** each set of 2 yellow doubles 1 white"
|
||||
whites_to_double = [white,yellow_sets].min
|
||||
puts "#{@name} has #{yellow_sets} sets; doubling #{whites_to_double} white cards."
|
||||
@cards.select{ |x| x.color == :white }.take(yellow_sets).each(&:double!)
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 14. Each set of three purple cards quadruples the value of one orange card.
|
||||
blue_sets = num_sets(:purple,3)
|
||||
if blue_sets > 0
|
||||
puts "*** RULE 14 *** each set of 3 purple quadruples 1 orange"
|
||||
oranges_to_double = [orange,blue_sets].min
|
||||
puts "#{@name} has #{blue_sets} sets; quadrupling #{oranges_to_double} orange cards."
|
||||
@cards.select{ |x| x.color == :orange }.take(blue_sets).each(&:quadruple!)
|
||||
puts
|
||||
end
|
||||
|
||||
# add up score
|
||||
@score = @cards.inject(0) { |sum,x| sum + x.value } + @bonus + @blue_hits * -10
|
||||
|
||||
# output
|
||||
puts "Final Tally for #{@name}"
|
||||
puts "================" + "=" * @name.size
|
||||
# compute score based on all the scoring attributes set by the scorer
|
||||
@cards.sort.each { |x| puts " %4d %s" % [x.value,x] }
|
||||
puts " %4d [bonus]" % [@bonus]
|
||||
puts "+ %4d [hits]" % [@blue_hits * -10]
|
||||
puts "----------------------"
|
||||
puts " %4d SUBTOTAL" % [@score]
|
||||
puts "x %4d [multiplier]" % [@hand_multiplier]
|
||||
puts "----------------------"
|
||||
@score *= @hand_multiplier
|
||||
puts " %4d TOTAL" % [@score]
|
||||
puts
|
||||
|
||||
puts
|
||||
end
|
||||
|
||||
# comparison, for sorting against other hands
|
||||
def <=>(other)
|
||||
# default is reverse sort (high to low)
|
||||
other.score <=> score
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
####
|
||||
#### initialize and validate hands
|
||||
####
|
||||
|
||||
puts "***************************"
|
||||
puts "*** V A L I D A T I O N ***"
|
||||
puts "***************************"
|
||||
puts
|
||||
|
||||
# create hands from PlayerData (at the top of this file)
|
||||
player_hands = []
|
||||
PlayerData.each do |r|
|
||||
# note some validation occurs in Hand creation
|
||||
player_hands << Hand.new(r.shift,r.shift.to_i,r.shift.to_i,r.shift.to_i,r.shift.to_i,r.shift.to_i)
|
||||
end
|
||||
|
||||
|
||||
####
|
||||
#### Global Rules Arbitration
|
||||
####
|
||||
|
||||
puts "***********************************"
|
||||
puts "*** G L O B A L S C O R I N G ***"
|
||||
puts "***********************************"
|
||||
puts
|
||||
|
||||
# RULE 1. Orange cards have a basic value of 4 and are equal to a pink card and a yellow card.
|
||||
# RULE 2. White cards have the highest basic value and are equal to a pink card and a purple card.
|
||||
# RULE 3. Purple cards have a basic value of twice that of yellow and half that of orange.
|
||||
# yellow = 1, purple = 2, pink = 3, orange = 4, and white = 5
|
||||
puts "*** RULES 1, 2, and 3 *** basic values"
|
||||
puts "yellow = 1, purple = 2, pink = 3, orange = 4, and white = 5"
|
||||
puts
|
||||
|
||||
# RULE 9. If a player hands in seven or more cards of the same color, he is eliminated from
|
||||
# the game.
|
||||
player_hands.each do |h|
|
||||
if h.largest_color >= 7
|
||||
puts "*** RULE 9 *** seven or more cards of one suit causes elimination"
|
||||
puts "#{h.name} is eliminated (#{h})!"
|
||||
puts
|
||||
end
|
||||
end
|
||||
player_hands.reject! { |h| h.largest_color >= 7 } # do the actual elimination
|
||||
|
||||
# RULE 8. The player with the most yellow cards gets a bonus of the number of cards squared.
|
||||
# (For example, if most yellow cards are 5, bonus is 25.) If two or more players tie for most
|
||||
# yellow, they are eliminated and bonus goes to the next highest.
|
||||
|
||||
# figure out the highest yellow count
|
||||
max_yellow = player_hands.map(&:yellow).max
|
||||
|
||||
# now select the players with that amount
|
||||
max_yellow_hands = player_hands.select{ |h| h.yellow == max_yellow }
|
||||
|
||||
# now apply rule
|
||||
if max_yellow_hands.size > 1
|
||||
puts "*** RULE 8 *** players tied for most yellow are eliminated!"
|
||||
max_yellow_hands.each { |h| puts "#{h.name} is eliminated (#{h})!" }
|
||||
player_hands = player_hands - max_yellow_hands
|
||||
puts
|
||||
elsif max_yellow_hands.size == 1
|
||||
puts "*** RULE 8 *** player with most yellow gets a bonus of number of cards squared"
|
||||
max_yellow_hands[0].add_bonus!(max_yellow_hands[0].yellow ** 2)
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 12. The player with the most pink cards doubles their value. In case of a tie, no
|
||||
# player collects the extra value.
|
||||
|
||||
# first get the guy(s) with the most pink
|
||||
max_red = player_hands.map(&:pink).max
|
||||
max_red_hands = player_hands.select { |h| h.pink == max_red }
|
||||
|
||||
# apply rule
|
||||
if max_red_hands.size > 1
|
||||
puts "*** RULE 12 *** in case of a tie (for most pink), no player collects the extra value"
|
||||
max_red_hands.each { |h| puts "#{h.name} is tied (#{h.pink} pink cards)."}
|
||||
puts
|
||||
elsif max_red_hands.size == 1
|
||||
puts "*** RULE 12 *** player with most pink cards doubles their value"
|
||||
max_red_hands[0].double_red!
|
||||
puts
|
||||
end
|
||||
|
||||
# RULE 6. If a player has five or more purple cards, 10 points are deducted from every other
|
||||
# player's score.
|
||||
player_hands.each do |h|
|
||||
if h.purple >= 5
|
||||
puts "*** RULE 6 *** five or more purple deducts 10 points from all other players"
|
||||
(player_hands - [h]).each { |x| x.blue_hit!(h.name) }
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
####
|
||||
#### output final hand summaries, after eliminations, eliminated cards, etc.
|
||||
####
|
||||
|
||||
puts "*********************************"
|
||||
puts "*** F I N A L E N T R I E S ***"
|
||||
puts "*********************************"
|
||||
puts
|
||||
player_hands.sort_by(&:name).each { |h| puts "#{h.name}: #{h}"}
|
||||
puts
|
||||
|
||||
|
||||
####
|
||||
#### Local Rules (i.e. global scoring is complete, now score each hand)
|
||||
####
|
||||
|
||||
puts "*******************************"
|
||||
puts "*** H A N D S C O R I N G ***"
|
||||
puts "*******************************"
|
||||
puts
|
||||
# iterate through each hand and count up local scoring rules; apply to each hand
|
||||
player_hands.sort_by(&:name).each(&:calculate_score!)
|
||||
|
||||
|
||||
####
|
||||
#### output final ranking
|
||||
####
|
||||
|
||||
puts "*******************************"
|
||||
puts "*** F I N A L S C O R E S ***"
|
||||
puts "*******************************"
|
||||
puts
|
||||
player_hands.sort.each_with_index { |h,i| puts "#{i+1}. #{h.name}: #{h.score} points" }
|
||||
puts
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
======================================================
|
||||
Steve turned in {"witnesses"=>5, "tips"=>5, "fingerprints"=>5, "suspects"=>5, "bullets"=>5}.
|
||||
Hand too big... discarding 1 suspects.
|
||||
Hand too big... discarding 1 suspects.
|
||||
Hand too big... discarding 1 witnesses.
|
||||
Hand too big... discarding 1 fingerprints.
|
||||
Hand too big... discarding 1 suspects.
|
||||
Hand too big... discarding 1 fingerprints.
|
||||
Hand too big... discarding 1 witnesses.
|
||||
Hand too big... discarding 1 suspects.
|
||||
Hand too big... discarding 1 bullets.
|
||||
Hand too big... discarding 1 fingerprints.
|
||||
Hand too big... discarding 1 tips.
|
||||
Hand too big... discarding 1 tips.
|
||||
New hand is {"witnesses"=>3, "tips"=>3, "fingerprints"=>2, "suspects"=>1, "bullets"=>4}.
|
||||
+5 points for 1 witnesses card.
|
||||
+5 points for 1 witnesses card.
|
||||
+5 points for 1 witnesses card.
|
||||
+3 points for 1 tips card.
|
||||
+3 points for 1 tips card.
|
||||
+3 points for 1 tips card.
|
||||
+2 points for 1 fingerprints card.
|
||||
+2 points for 1 fingerprints card.
|
||||
+4 points for 1 suspects card.
|
||||
+1 points for 1 bullets card.
|
||||
+1 points for 1 bullets card.
|
||||
+1 points for 1 bullets card.
|
||||
+1 points for 1 bullets card.
|
||||
Total for Steve: 36
|
||||
======================================================
|
||||
======================================================
|
||||
Steve turned in {"witnesses"=>4, "tips"=>2, "fingerprints"=>3, "suspects"=>1, "bullets"=>0}.
|
||||
+10 points for being the first entry.
|
||||
+10 points for being turned in by a girl.
|
||||
Detected a set of 3 fingerprints, 1 tip will be doubled.
|
||||
+5 points for 1 witnesses card.
|
||||
+5 points for 1 witnesses card.
|
||||
+5 points for 1 witnesses card.
|
||||
+5 points for 1 witnesses card.
|
||||
+6 points for 1 tips card multiplied by 2.
|
||||
+3 points for 1 tips card.
|
||||
+2 points for 1 fingerprints card.
|
||||
+2 points for 1 fingerprints card.
|
||||
+2 points for 1 fingerprints card.
|
||||
+4 points for 1 suspects card.
|
||||
You have a pyramid, hand value will double.
|
||||
Total for Steve: 118
|
||||
======================================================
|
||||
|
||||
|
After Width: | Height: | Size: 275 KiB |
|
After Width: | Height: | Size: 226 B |
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
|
||||
|
||||
class MurderHaggleHand
|
||||
def initialize(player, bullets, fingerprints, tips, suspects, witnesses, first_entry=false, girl_entered=false)
|
||||
# build a hand
|
||||
@player = player
|
||||
@original_hand = {
|
||||
'bullets' => bullets,
|
||||
'fingerprints' => fingerprints,
|
||||
'tips' => tips,
|
||||
'suspects' => suspects,
|
||||
'witnesses' => witnesses,
|
||||
}
|
||||
@first_entry = first_entry
|
||||
@girl_entered = girl_entered
|
||||
end
|
||||
|
||||
def score(quiet=true)
|
||||
|
||||
# seed the same so we always get the same results!
|
||||
srand(32472)
|
||||
|
||||
# track the total score
|
||||
hand_total = 0
|
||||
card_multipliers = { "bullets" => [], "fingerprints" => [], "tips" => [], "suspects" => [], "witnesses" => [] }
|
||||
|
||||
puts "======================================================" unless quiet
|
||||
puts "#{@player} turned in #{@original_hand.inspect}." unless quiet
|
||||
|
||||
# copy the hand so we can mess with it
|
||||
hand = @original_hand.dup
|
||||
|
||||
# not allowed more suspects than witnesses
|
||||
if hand["suspects"] > hand["witnesses"]
|
||||
diff = hand["suspects"] - hand["witnesses"]
|
||||
puts "Discarding #{diff} suspects." unless quiet
|
||||
hand["suspects"] = hand["witnesses"]
|
||||
end
|
||||
|
||||
# no more than 13 cards allowed
|
||||
hand_size = hand.values.inject(0) { |sum,n| sum+n }
|
||||
discarded = 0
|
||||
(hand_size-13).times do
|
||||
hand_array = hand.collect { |k,v| [k]*v }.flatten
|
||||
i = rand(hand_array.size)
|
||||
puts "Hand too big... discarding 1 #{hand_array[i]}." unless quiet
|
||||
hand[hand_array[i]] = hand[hand_array[i]] - 1;
|
||||
discarded += 1
|
||||
end
|
||||
puts "New hand is #{hand.inspect}." if discarded > 0 unless quiet
|
||||
|
||||
# base scores
|
||||
base_scores = { "bullets" => 1, "fingerprints" => 2, "tips" => 3, "suspects" => 4, "witnesses" => 5 }
|
||||
|
||||
# +10 points for first envelope turned in
|
||||
if @first_entry
|
||||
puts "+10 points for being the first entry." unless quiet
|
||||
hand_total += 10
|
||||
end
|
||||
|
||||
# +10 points for envelope turned in by girls
|
||||
if @girl_entered
|
||||
puts "+10 points for being turned in by a girl." unless quiet
|
||||
hand_total += 10
|
||||
end
|
||||
|
||||
# 8 or more tips is 25 points
|
||||
if hand["tips"] >= 8
|
||||
puts "+25 points for having 8 or more tips." unless quiet
|
||||
hand_total += 25
|
||||
end
|
||||
|
||||
# each set of 3 suspects and 1 witness score 10 points
|
||||
x = [ hand["suspects"]/3, hand["witnesses"] ].min
|
||||
if x > 0
|
||||
puts "+#{x*10} points for #{x} set(s) of 3 suspects/1 witness" unless quiet
|
||||
hand_total += x*10
|
||||
end
|
||||
|
||||
# each set of 3 fingerprints doubles one tip
|
||||
(hand["fingerprints"]/3).times do
|
||||
card_multipliers["tips"] << 2
|
||||
puts "Detected a set of 3 fingerprints, one tip will be doubled." unless quiet
|
||||
end
|
||||
|
||||
# each set of 2 suspects quadruples the value of one bullet casing
|
||||
(hand["suspects"]/2).times do
|
||||
card_multipliers["bullets"] << 4
|
||||
puts "Detected a set of 2 suspects, one bullet will be quadrupled." unless quiet
|
||||
end
|
||||
|
||||
# now sum up score
|
||||
hand.each do |k,v|
|
||||
v.times do
|
||||
multiplier = card_multipliers[k].shift || 1
|
||||
base = base_scores[k]
|
||||
points = base * multiplier
|
||||
mult_string = multiplier > 1 ? " multiplied by #{multiplier}." : "."
|
||||
puts "+#{points} points for 1 #{k} card#{mult_string}" unless quiet
|
||||
hand_total += points
|
||||
end
|
||||
end
|
||||
|
||||
# pyramid
|
||||
sorted_counts = hand.values.sort.select { |x| x > 0 }
|
||||
if sorted_counts == [1,2,3,4]
|
||||
hand_total *= 2
|
||||
puts "You have a pyramid, hand value will double." unless quiet
|
||||
end
|
||||
|
||||
# input total
|
||||
puts "Total for #{@player}: #{hand_total}" unless quiet
|
||||
puts "======================================================" unless quiet
|
||||
puts "" unless quiet
|
||||
|
||||
hand_total
|
||||
end
|
||||
end
|
||||
|
||||
#best = 0
|
||||
#14.times do |f|
|
||||
# 14.times do |t|
|
||||
# 14.times do |w|
|
||||
# 14.times do |s|
|
||||
# 14.times do |b|
|
||||
# hand = MurderHaggleHand.new("Test",b,f,t,s,w,true,true)
|
||||
# score = hand.score
|
||||
# if score > best
|
||||
# hand.score(false)
|
||||
# best = score
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#end
|
||||
|
||||
# (player, bullets, fingerprints, tips, suspects, witnesses, first_entry=false, girl_entered=false)
|
||||
hands = [
|
||||
MurderHaggleHand.new("Abe",2,0,0,2,1,false,false),
|
||||
MurderHaggleHand.new("Casey",0,3,5,0,0,false,false),
|
||||
MurderHaggleHand.new("Craig",1,2,0,3,4,false,false),
|
||||
MurderHaggleHand.new("Dundee",2,2,2,3,3,false,false),
|
||||
MurderHaggleHand.new("Eddy",6,3,2,2,0,false,true),
|
||||
MurderHaggleHand.new("Francois",2,2,2,1,1,false,true),
|
||||
MurderHaggleHand.new("Jon",9,1,0,0,0,false,false),
|
||||
MurderHaggleHand.new("Josh",0,3,2,4,1,false,false),
|
||||
MurderHaggleHand.new("Lonna",0,1,2,3,4,true,true),
|
||||
MurderHaggleHand.new("Mary Tess",0,2,1,3,4,false,true),
|
||||
MurderHaggleHand.new("Mike",1,0,0,0,0,false,false),
|
||||
MurderHaggleHand.new("Nate",0,3,1,3,3,false,false),
|
||||
MurderHaggleHand.new("PJ",0,3,8,0,2,false,false),
|
||||
MurderHaggleHand.new("Shae",0,2,3,4,4,false,true),
|
||||
]
|
||||
|
||||
hands.sort { |a,b| b.score <=> a.score }.each do |h|
|
||||
h.score(false)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
|
||||
|
||||
class MurderHaggleHand
|
||||
def initialize(player, bullets, fingerprints, tips, suspects, witnesses, first_entry=false, girl_entered=false)
|
||||
# build a hand
|
||||
@player = player
|
||||
@original_hand = {
|
||||
'bullets' => bullets,
|
||||
'fingerprints' => fingerprints,
|
||||
'tips' => tips,
|
||||
'suspects' => suspects,
|
||||
'witnesses' => witnesses,
|
||||
}
|
||||
@first_entry = first_entry
|
||||
@girl_entered = girl_entered
|
||||
end
|
||||
|
||||
def score
|
||||
|
||||
# seed the same so we always get the same results!
|
||||
srand(32472)
|
||||
|
||||
# track the total score
|
||||
hand_total = 0
|
||||
card_multipliers = { "bullets" => [], "fingerprints" => [], "tips" => [], "suspects" => [], "witnesses" => [] }
|
||||
|
||||
puts "======================================================"
|
||||
puts "#{@player} turned in #{@original_hand.inspect}."
|
||||
|
||||
# copy the hand so we can mess with it
|
||||
hand = @original_hand.dup
|
||||
|
||||
# no more than 13 cards allowed
|
||||
hand_size = hand.values.inject(0) { |sum,n| sum+n }
|
||||
discarded = 0
|
||||
(hand_size-13).times do
|
||||
hand_array = hand.collect { |k,v| [k]*v }.flatten
|
||||
i = rand(hand_array.size)
|
||||
puts "Hand too big... discarding 1 #{hand_array[i]}."
|
||||
hand[hand_array[i]] = hand[hand_array[i]] - 1;
|
||||
discarded += 1
|
||||
end
|
||||
puts "New hand is #{hand.inspect}." if discarded > 0
|
||||
|
||||
# base scores
|
||||
base_scores = { "bullets" => 1, "fingerprints" => 2, "tips" => 3, "suspects" => 4, "witnesses" => 5 }
|
||||
|
||||
# not allowed more suspects than witnesses
|
||||
if hand["suspects"] > hand["witnesses"]
|
||||
diff = hand["suspects"] - hand["witnesses"]
|
||||
puts "Discarding #{diff} suspects."
|
||||
hand["suspects"] = hand["witnesses"]
|
||||
end
|
||||
|
||||
# +10 points for first envelope turned in
|
||||
if @first_entry
|
||||
puts "+10 points for being the first entry."
|
||||
hand_total += 10
|
||||
end
|
||||
|
||||
# +10 points for envelope turned in by girls
|
||||
if @girl_entered
|
||||
puts "+10 points for being turned in by a girl."
|
||||
hand_total += 10
|
||||
end
|
||||
|
||||
# 8 or more tips is 25 points
|
||||
if hand["tips"] >= 8
|
||||
puts "+25 points for having 8 or more tips."
|
||||
hand_total += 25
|
||||
end
|
||||
|
||||
# each set of 4 suspects and 1 witness score 10 points
|
||||
x = [ hand["suspects"]/4, hand["witnesses"] ].min
|
||||
if x > 0
|
||||
puts "+#{x*10} points for #{x} set(s) of 4 suspects/1 witness"
|
||||
hand_total += x*10
|
||||
end
|
||||
|
||||
# each set of 3 fingerprints doubles one tip
|
||||
(hand["fingerprints"]/3).times do
|
||||
card_multipliers["tips"] << 2
|
||||
puts "Detected a set of 3 fingerprints, 1 tip will be doubled."
|
||||
end
|
||||
|
||||
# each set of 2 suspects quadruples the value of one bullet casing
|
||||
(hand["suspects"]/2).times do
|
||||
card_multipliers["bullets"] << 4
|
||||
puts "Detected a set of 2 suspects, 1 bullet will be quadrupled."
|
||||
end
|
||||
|
||||
# now sum up score
|
||||
hand.each do |k,v|
|
||||
v.times do
|
||||
multiplier = card_multipliers[k].shift || 1
|
||||
base = base_scores[k]
|
||||
points = base * multiplier
|
||||
mult_string = multiplier > 1 ? " multiplied by #{multiplier}." : "."
|
||||
puts "+#{points} points for 1 #{k} card#{mult_string}"
|
||||
hand_total += points
|
||||
end
|
||||
end
|
||||
|
||||
# pyramid
|
||||
sorted_counts = hand.values.sort.select { |x| x > 0 }
|
||||
if sorted_counts == [1,2,3,4]
|
||||
hand_total *= 2
|
||||
puts "You have a pyramid, hand value will double."
|
||||
end
|
||||
|
||||
# input total
|
||||
puts "Total for #{@player}: #{hand_total}"
|
||||
puts "======================================================"
|
||||
print ""
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
MurderHaggleHand.new("Steve",5,5,5,5,5).score
|
||||
MurderHaggleHand.new("Steve",0,3,2,1,4,true,true).score
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'hand'
|
||||
require 'combinations'
|
||||
|
||||
def score(hand_string, verbose=false)
|
||||
# split into an array of two character strings (each representing a card)
|
||||
cards = hand_string.scan(/../)
|
||||
|
||||
# a place to store all of our scores
|
||||
best_hands = nil
|
||||
best_score = -1
|
||||
|
||||
# create and score all permutations of two 5 card hands
|
||||
cards.combinations(5).each do |c|
|
||||
# create each hand from two 10 character strings
|
||||
hand_a = Hand.new(c.join)
|
||||
hand_b = Hand.new((cards-c).join)
|
||||
score = hand_a.score + hand_b.score
|
||||
|
||||
# save the hand if it's the best
|
||||
best_hands,best_score = [hand_a,hand_b],score if score > best_score
|
||||
end
|
||||
|
||||
# now create and score the 10 card hand
|
||||
ten_card_hand = Hand.new(cards.join)
|
||||
best_hands,best_score = [ten_card_hand],ten_card_hand.score if ten_card_hand.score > best_score
|
||||
|
||||
# DEBUG
|
||||
if verbose then
|
||||
best_hands.each do |h|
|
||||
puts "#{h.score} points for a #{h.score_name}"
|
||||
puts h
|
||||
puts
|
||||
end
|
||||
puts "#{best_score} TOTAL POINTS"
|
||||
end
|
||||
|
||||
# return score
|
||||
best_score
|
||||
end
|
||||
|
||||
score('tsjsqsksastcjcqckcac',true)
|
||||
puts
|
||||
puts
|
||||
score('3d8c6s7d8h9s9dkdqd5d',true)
|
||||
puts
|
||||
puts
|
||||
score('2s3s4s5s6s7s8s9stsjs',true)
|
||||
puts
|
||||
puts
|
||||
score('2c3s4c5d6h7s8d9sthjs',true)
|
||||
puts
|
||||
puts
|
||||
score('as3s4s5s6s7s8s9stsjs',true)
|
||||
puts
|
||||
puts
|
||||
score('asadacah6s7s8s9stsjs',true)
|
||||
puts
|
||||
puts
|
||||
score('asadackskd7s8s9stsjs',true)
|
||||
puts
|
||||
puts
|
||||
|
||||
@@ -1,65 +1,71 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
class Card
|
||||
|
||||
attr_reader :rank, :suit
|
||||
|
||||
def initialize(str)
|
||||
r = str[0,1].downcase
|
||||
s = str[1,1].downcase
|
||||
@suit = case s
|
||||
when 's' then :spades
|
||||
when 'h' then :hearts
|
||||
when 'd' then :diamonds
|
||||
when 'c' then :clubs
|
||||
end
|
||||
@rank = case r
|
||||
when '2'..'9' then r.to_i
|
||||
when 't' then 10
|
||||
when 'j' then 11
|
||||
when 'q' then 12
|
||||
when 'k' then 13
|
||||
when 'a' then 14
|
||||
end
|
||||
end
|
||||
|
||||
def rank_s
|
||||
case @rank
|
||||
when 2..10 then @rank.to_s
|
||||
when 11 then "Jack"
|
||||
when 12 then "Queen"
|
||||
when 13 then "King"
|
||||
when 14 then "Ace"
|
||||
end
|
||||
end
|
||||
|
||||
def suit_s
|
||||
@suit.to_s.capitalize
|
||||
end
|
||||
|
||||
def to_s
|
||||
rank_s + "-" + suit_s
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
@rank == other.rank && @suit == other.suit
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
if @rank != other.rank
|
||||
@rank <=> other.rank
|
||||
else
|
||||
# order is Spades, Hearts, Diamonds, Clubs (conveniently reverse alphabetical)
|
||||
other.suit_s <=> suit_s
|
||||
end
|
||||
end
|
||||
|
||||
def eql?(other)
|
||||
self == other
|
||||
end
|
||||
|
||||
def hash
|
||||
to_s.hash
|
||||
end
|
||||
end
|
||||
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
class Card
|
||||
|
||||
attr_reader :rank, :suit
|
||||
|
||||
def initialize(str)
|
||||
r = str[0,1].downcase
|
||||
s = str[1,1].downcase
|
||||
@suit = case s
|
||||
when 's' then :spades
|
||||
when 'h' then :hearts
|
||||
when 'd' then :diamonds
|
||||
when 'c' then :clubs
|
||||
end
|
||||
@rank = case r
|
||||
when '2'..'9' then r.to_i
|
||||
when 't' then 10
|
||||
when 'j' then 11
|
||||
when 'q' then 12
|
||||
when 'k' then 13
|
||||
when 'a' then 14
|
||||
end
|
||||
end
|
||||
|
||||
def rank_long_s
|
||||
['2','3','4','5','6','7','8','9','10','Jack','Queen','King','Ace'][@rank-2]
|
||||
end
|
||||
|
||||
def suit_long_s
|
||||
@suit.to_s.capitalize
|
||||
end
|
||||
|
||||
def rank_s
|
||||
['2','3','4','5','6','7','8','9','t','j','q','k','a'][@rank-2]
|
||||
end
|
||||
|
||||
def suit_s
|
||||
{:spades => 's', :hearts => 'h', :diamonds => 'd', :clubs => 'c'}[@suit]
|
||||
end
|
||||
|
||||
def to_s
|
||||
rank_s + suit_s
|
||||
end
|
||||
|
||||
def to_long_s
|
||||
rank_long_s + '-' + suit_long_s
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
@rank == other.rank && @suit == other.suit
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
if @rank != other.rank
|
||||
@rank <=> other.rank
|
||||
else
|
||||
# order is Spades, Hearts, Diamonds, Clubs (conveniently reverse alphabetical)
|
||||
other.suit_s <=> suit_s
|
||||
end
|
||||
end
|
||||
|
||||
def eql?(other)
|
||||
self == other
|
||||
end
|
||||
|
||||
def hash
|
||||
to_s.hash
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
class Array
|
||||
def combinations n
|
||||
result = Array.new
|
||||
if n > 0
|
||||
(0 .. self.length - n).each do |i|
|
||||
combs = self[i + 1 .. -1].combinations(n - 1)
|
||||
combs = [[]] if combs.empty?
|
||||
combs.collect {|comb| [self[i]] + comb}.each {|x| result << x}
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
class Array
|
||||
def combinations n
|
||||
result = Array.new
|
||||
if n > 0
|
||||
(0 .. self.length - n).each do |i|
|
||||
combs = self[i + 1 .. -1].combinations(n - 1)
|
||||
combs = [[]] if combs.empty?
|
||||
combs.collect {|comb| [self[i]] + comb}.each {|x| result << x}
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Tripoli is a generic CSS standard for HTML rendering.
|
||||
* Copyright (C) 2007-2008 David Hellsing
|
||||
*
|
||||
* http://devkick.com/lab/tripoli/
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
_______________________________
|
||||
RESET */
|
||||
*{text-decoration:none;font-size:1em;outline:none;margin:0;padding:0}code,kbd,samp,pre,tt,var,textarea,input,select,isindex,listing,xmp,plaintext{font:inherit;white-space:normal}a,img,a img,iframe,form,abbr,acronym,object,applet,table,a abbr,a acronym{border-width:0}dfn,i,cite,var,address,em{font-style:normal}th,b,strong,h1,h2,h3,h4,h5,h6,dt{font-weight:400}caption,th,td{text-align:left}html{background:#FFF;color:#000;line-height:1;font-family:arial, sans-serif}/* \*/html{font-family:sans-serif}/* */q{quotes:"\201C""\201D""\2018""\2019"}ul,ol,dir,menu{list-style:none}sub,sup{vertical-align:baseline}a{color:inherit}/*
|
||||
_______________________________
|
||||
DISABLE DEPRECATED HTML */
|
||||
font,basefont{color:inherit;font:inherit;font-size:100%}center,*[align]{text-align:inherit}s,strike,u{text-decoration:inherit}img{border:none;margin:0}ol{list-style-type:decimal}body{background-color:transparent}tr,th,td{width:auto;height:auto;background-color:transparent;vertical-align:inherit;border:none}table[border],.content table[border]{border-collapse:separate;border-spacing:0}nobr{white-space:normal}marquee{overflow:visible;-moz-binding:none}blink{text-decoration:none}/*
|
||||
_______________________________
|
||||
GENERAL */
|
||||
html{font-size:125%}body{font-size:50%}a{text-decoration:underline}strong,th,thead td,h1,h2,h3,h4,h5,h6,dt{font-weight:700}cite,em,dfn{font-style:italic}code,kbd,samp,pre,tt,var,input[type='text'],input[type='password'],textarea{font-size:100%;font-family:mono-space,monospace}pre{white-space:pre}pre *{font-size:100%;white-space:pre}del{text-decoration:line-through}ins,dfn{border-bottom:1px solid #000}small,sup,sub{font-size:85%}big{font-size:125%;line-height:80%}abbr,acronym{text-transform:uppercase;font-size:85%;letter-spacing:.1em}abbr[title],acronym[title],dfn[title]{cursor:help;border-bottom:1px dotted #000}sup{vertical-align:super}sub{vertical-align:sub}blockquote{padding-left:2.2em}hr{display:none/* We will re-reset it later for content */}:lang(af),:lang(nl),:lang(pl){quotes:'\201E' '\201D' '\201A' '\2019'}:lang(bg),:lang(cs),:lang(de),:lang(is),:lang(lt),:lang(sk),:lang(sr),:lang(ro){quotes:'\201E' '\201C' '\201A' '\2018'}:lang(da),:lang(hr){quotes:'\00BB' '\00AB' '\203A' '\2039'}:lang(el),:lang(es),:lang(sq),:lang(tr){quotes:'\00AB' '\00BB' '\2039' '\203A'}:lang(en-GB){quotes:'\2018' '\2019' '\201C' '\201D'}:lang(fi),:lang(sv){quotes:'\201D' '\201D' '\2019' '\2019'}:lang(fr){quotes:'\ab\2005' '\2005\bb' '\2039\2005' '\2005\203a'}*[lang|='en'] q:before{content:'\201C'}*[lang|='en'] q:after{content:'\201D'}*[lang|='en'] q q:before{content:'\2018'}*[lang|='en'] q q:after{content:'\2019'}input,select,button{cursor:pointer}input[type='text'],input[type='password']{cursor:text}input[type='hidden']{display:none}/*
|
||||
_______________________________
|
||||
CONTENT */
|
||||
.content{font-size:1.2em;line-height:1.6em}.content h1{font-size:1.6em;line-height:1;margin:1em 0 .5em}.content h2{font-size:1.5em;line-height:1;margin:1.07em 0 .535em}.content h3{font-size:1.4em;line-height:1;margin:1.14em 0 .57em}.content h4{font-size:1.3em;line-height:1;margin:1.23em 0 .615em}.content h5{font-size:1.2em;line-height:1;margin:1.33em 0 .67em}.content h6{font-size:1em;line-height:1;margin:1.6em 0 .8em}.content hr{display:block;background:#000;color:#000;width:100%;height:1px;border:none}.content ul{list-style:disc outside}.content ol{list-style:decimal outside}.content table{border-collapse:collapse}.content hr,.content p,.content ul,.content ol,.content dl,.content pre,.content address,.content table,.content form{margin-bottom:1.6em}.content p+p{margin-top:-.8em}.content fieldset{margin:1.6em 0;padding:1.6em}/* \*/.content legend{padding-left:.8em;padding-right:.8em}/* *//* for Opera 8 */@media all and min-width 0px{.content legend{margin-bottom:1.6em}.content fieldset{margin-top:0}.content[class^='content'] fieldset{margin-top:1.6em}}.content fieldset>*:first-child{margin-top:0}.content textarea,.content input[type='text']{padding:.1em .2em}.content input{padding:.2em .1em}.content select{padding:.2em .1em 0}.content select[multiple]{margin-bottom:.8em}.content option{padding:0 .4em .1em}.content button{padding:.3em .5em}.content input[type='radio']{position:relative;bottom:-.2em}.content dt{margin-top:.8em;margin-bottom:.4em}.content ul,.content ol{margin-left:2.2em}.content caption,.content form div{padding-bottom:.8em}.content ul ul,content ol ul,.content ul ol,content ol ol{margin-bottom:0}/*
|
||||
_______________________________
|
||||
VISUAL PLUG */
|
||||
blockquote{color:#666}blockquote > *:first-child:before /* Tripoli bonus: pure CSS blockquote */{content:"\201C";font-size:2.5em;margin-left:-.62em;font-family:georgia,serif;padding-right:.2em;color:#aaa;line-height:0}abbr[title],acronym[title],dfn[title]{border-bottom:1px solid #ccc}ins,dfn{border-bottom-color:#666}del{color:#666}fieldset{border-color:#ccc}textarea,input[type='text'],input[type='password'],select{border:1px solid #ccc;background:#fff}fieldset{border:1px solid #ccc}textarea:hover,input[type='text']:hover,input[type='password']:hover,select:hover{border-color:#aaa}textarea:focus,input[type='text']:focus,input[type='password']:focus,select:focus{outline:2px solid #e4e4e4;border-color:#888}.content hr{background:#aaa;color:#aaa}.content table{border-top:1px solid #ccc;border-left:1px solid #ccc}.content th,.content td{border-bottom:1px solid #ddd;border-right:1px solid #ccc}.content th,.content td{padding:.8em}a:link{color:#36c}a:visited{color:#99c}a:hover,code,pre{color:#c33}a:active,.a:focus{color:#000}/*
|
||||
_______________________________
|
||||
TYPE PLUG */
|
||||
.alt{font-family:"baskerville italic","Warnock Pro","Goudy Old Style","Palatino","palatino linotype","Book Antiqua",Georgia, serif;font-style:italic;font-weight:400}.dquo{margin-left:-.55em}/*
|
||||
_______________________________
|
||||
END */
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Tripoli is a generic CSS standard for HTML rendering.
|
||||
* Copyright (C) 2007-2008 David Hellsing
|
||||
*
|
||||
* http://devkick.com/lab/tripoli/
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
**
|
||||
_______________________________
|
||||
BASE.IE */
|
||||
textarea{white-space:pre}.content legend{margin-bottom:1.6em}.content fieldset{padding-top:0}sup,sub{font-size:100%}.content legend:first-child{margin-top:0}a abbr,a acronym{text-decoration:underline}* html .content blockquote *{margin:.8em 0}* html input{cursor:expression(this.type=='text' || this.type=='password' ? 'text' : 'pointer');display:expression(this.type=='hidden' ? 'none' : 'inline')}* html .content textarea,* html .content input,.content input[type='submit'],.content input[type='button']{padding:0}/*
|
||||
_______________________________
|
||||
END */
|
||||
@@ -0,0 +1,100 @@
|
||||
fred,2h2c2cacahqcts9d7d4h
|
||||
aaron,4h7h7s7sjsjdjdjhkhks
|
||||
steven,tsksqsjsas2dtckc9c6d
|
||||
eileen,5h6s7s2s3c4d8d9dtcjh
|
||||
randy,qsqhqc6d6h2s2sth9d3d
|
||||
cathy,5c5s5d5s7h8h9hthqckd
|
||||
josh,as8sks7s5s3c3hqcqhqh
|
||||
jen,9s9sahacac4h4s4c4c7d
|
||||
jen,4d4s4cah6h6s6s9c9c
|
||||
jen,2h3s4s5c6dtdtcth3c3c
|
||||
aaron,thtstc6c6hjsjdjs9dtd
|
||||
casey,4h3h2hah5h3dqcqsts8d
|
||||
steven,3s2sas4s9s3s2d8h7d7s
|
||||
steven,tsqs9s5stskhah3h9h2h
|
||||
steven,kckd6d6c6h5c7hqdqsjh
|
||||
francois,5d6d7d8d9d6c7c8c9ctc
|
||||
jeff,5h5d3s3h3casts9s8s3s
|
||||
dundee,ah2h3h4h5hadadas2c2c
|
||||
stephanie,7c2ctc5c6cjh4h2h6hth
|
||||
stephanie,qcqsqd3c3dkhkdkstdtc
|
||||
eddy,ackcqcjctc5sjs8s3sts
|
||||
randy,2s3s4ckdksactdjcqhkh
|
||||
francois,5s6s7h8s9ctdjsqcksas
|
||||
fred,5h4c3d6s2dqh3h3d3hqd
|
||||
fred,jcjhjdqdqsts7d5c2h3c
|
||||
cynthia,qsqhqd4s4h8c8s8hkhkc
|
||||
fred,6s7c8c8skhqhjhth9h5h
|
||||
josh,2d3d4d5d6djdjcjh7h7c
|
||||
jen,4h4s4c4c6h6d2sjcjsjd
|
||||
josh,3s3c3d3h5cahac2h2s2c
|
||||
steven,7s7h7h7hqsqdqs5d5c3s
|
||||
steven,9c6c5c2cjcjh9dad2dqc
|
||||
steven,6hkhqdjcts9c8dac7s5h
|
||||
jen,3d3c3skcqdqckskdtstd
|
||||
josh,6s6c5h5s5stcjcqckcac
|
||||
randy,ahas2h2s3s3d4d4h5c5s
|
||||
jen,4c4c4c4d9d9d3c3h3sts
|
||||
jeff,2s3d9c9h9skdqd6d4s2d
|
||||
jeff,thadkdqhjd7d7s7h2c2d
|
||||
jeff,6c6s6h9d9c2s4d3c5d6s
|
||||
dundee,2h3h4h5h6h7h8h9hthah
|
||||
mike,asksqsjstskh4d4h4s4c
|
||||
fred,8s7s6s5s4s8s2ckcqd3c
|
||||
jen,6c6d6d6h4s5s6s7c8d7d
|
||||
randy,as2c3s4c5h6h7s8s9stc
|
||||
cynthia,7h6d5d4h3h8h9s9d9c9h
|
||||
aaron,8s8d8hkskcacadthtc9h
|
||||
josh,2c7d7c7h7s3s3hadacah
|
||||
francois,3stcthtdacah8sqsks9s
|
||||
aaron,qcjctc9c8c7h7d7s4s4h
|
||||
mike,6h7h8h9h9skcad5h7d5h
|
||||
mike,4h6hqh7c7cjh3h3s3d3c
|
||||
rob,kskckhkd8c8h8d5d5cqd
|
||||
rob,ad2d3d4d5d9d3hqsjh7h
|
||||
rob,5c4c3d2dahadkcqdjctc
|
||||
rob,jdjsjcjd4ckhqs4h3h2s
|
||||
jen,3d4d5s6c7d8d9ctcjdqc
|
||||
rob,tcjcqckcacadac7d7d7h
|
||||
josh,5h8h8s7s4c3s7s8s9sts
|
||||
jeff,5s4s3s2sas3c4c5c6c9c
|
||||
fred,6h2d6h2d5d8s9dthqdkd
|
||||
steven,3h3c2s2h2dackcqcjctc
|
||||
steven,8c7c4c4c8c6h6d6s4h4s
|
||||
steven,7h2h7dkc9s3c3s3sahah
|
||||
jen,9sqcadaskskhjdjsjcjh
|
||||
stephanie,9c9s2c6s6d5s4s3s2sas
|
||||
stephanie,2c3s4d5s6c7s8h9dtsjh
|
||||
stephanie,3c3sqhqctcthtd9c9h9s
|
||||
eileen,qsjs5s6s4std8d7d4dad
|
||||
eileen,5d8d2h2d2h2sadasacah
|
||||
eileen,asadtstctd2s2c2hkdkh
|
||||
eileen,kskdkhkcqh3d9htdthts
|
||||
eileen,jc9c8c6c3ckhqh7h6h4h
|
||||
eddy,9stsjsqsks5d5s5h5c7h
|
||||
eddy,9d8h8c9s9h2d2h3d3h3c
|
||||
eddy,3h5h8h9hjh3cqcqsqdqh
|
||||
jonathan,jcjsjh8s8hkdqdjdtd9d
|
||||
adam,ackcqcjctc9c8c7c6c5c
|
||||
adam,5h4d4c7s7h7h2h2c2d2s
|
||||
shaelagh,2c9c7h6d6skhqhth7h9h
|
||||
shaelagh,6d5h4s3s2s9h8s7s6d5c
|
||||
shaelagh,8dtdtctsthjdjs6d6h6c
|
||||
shaelagh,6d2h7c7s5s9dtd8d4d3d
|
||||
jonathan,ahksqhjdthqc6c5c2cac
|
||||
jonathan,qhjh8h5h4h3c3d3h3sjc
|
||||
jonathan,ahasackskdjdtd9d8d7d
|
||||
jonathan,9d8d7d6h5dkdqdkc4s4s
|
||||
aaron,6h6c6s9d9c9hasacqdqs
|
||||
dundee,5h4h3h2hahtsjsqsksas
|
||||
jen,thts7d7d7c6hjsac4hkc
|
||||
lonna,6s6d4d5dkd6c5h4h3c2s
|
||||
lonna,8c7s6s5d4cahadas5c5s
|
||||
lonna,khqhjdtd9d8h7c6s5s4s
|
||||
lonna,ahkhqhjhtc9d8c7c6c5d
|
||||
francois,qc9s7d6s4s5c4cqc9c8c
|
||||
randy,5c4d3d2cahqdqsqdtsth
|
||||
cathy,2d2c2h2s8dkckdjhjdjh
|
||||
cynthia,2d3d4d5d6d8skd9cjcqd
|
||||
cathy,4c6s7s8s9stsjsqsksas
|
||||
mike,5h4s8s8sadacadks9h7s
|
||||
@@ -1,93 +1,97 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'card'
|
||||
|
||||
class Hand
|
||||
def initialize(hand_string)
|
||||
@cards = hand_string.scan(/../).collect { |s| Card.new(s) }.sort
|
||||
end
|
||||
|
||||
def legal?
|
||||
@cards.size == @cards.sort.uniq.size && [5,10].include?(@cards.size)
|
||||
end
|
||||
|
||||
def illegal?
|
||||
!(legal?)
|
||||
end
|
||||
|
||||
def rank
|
||||
return nil if illegal?
|
||||
|
||||
# array of suits, ranks
|
||||
suits = @cards.collect { |c| c.suit_s }
|
||||
ranks = @cards.collect { |c| c.rank }
|
||||
|
||||
# count of suits
|
||||
suit_counts = Hash.new(0)
|
||||
suits.each { |s| suit_counts[s] += 1 }
|
||||
|
||||
# count of ranks
|
||||
rank_counts = Hash.new(0)
|
||||
ranks.each { |s| rank_counts[s] += 1 }
|
||||
|
||||
# test for straight & flush
|
||||
straight = (ranks.sort == (ranks.min .. ranks.max).to_a)
|
||||
flush = (suits.sort.uniq.size == 1)
|
||||
|
||||
# rank hand
|
||||
return :royal_flush if straight && flush && ranks.min == 10
|
||||
return :straight_flush if straight && flush
|
||||
return :four_of_a_kind if [1,4] == rank_counts.values.sort
|
||||
return :full_house if [2,3] == rank_counts.values.sort
|
||||
return :flush if flush
|
||||
return :straight if straight
|
||||
|
||||
# nothing
|
||||
nil
|
||||
end
|
||||
|
||||
|
||||
def score
|
||||
r = rank
|
||||
|
||||
return 0 if r.nil?
|
||||
|
||||
# ten card hands
|
||||
return 80 if @cards.size == 10 && r == :straight_flush
|
||||
return 40 if @cards.size == 10 && r == :flush
|
||||
return 20 if @cards.size == 10 && r == :straight
|
||||
|
||||
# five card hands
|
||||
return 21 if r == :royal_flush
|
||||
return 20 if r == :straight_flush
|
||||
return 15 if r == :four_of_a_kind
|
||||
return 10 if r == :full_house
|
||||
return 7 if r == :flush
|
||||
return 5 if r == :straight
|
||||
|
||||
# nothing
|
||||
return 0
|
||||
end
|
||||
|
||||
def score_name
|
||||
rank.to_s.gsub(/_/,' ') if rank
|
||||
end
|
||||
|
||||
def to_s
|
||||
@cards.collect { |c| c.to_s }.join(', ')
|
||||
end
|
||||
|
||||
def hash
|
||||
to_s.hash
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
to_s <=> other.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'card'
|
||||
|
||||
class Hand
|
||||
def initialize(hand_string)
|
||||
@cards = hand_string.scan(/../).collect { |s| Card.new(s) }.sort
|
||||
end
|
||||
|
||||
def legal?
|
||||
@cards.size == @cards.sort.uniq.size && [5,10].include?(@cards.size)
|
||||
end
|
||||
|
||||
def illegal?
|
||||
!(legal?)
|
||||
end
|
||||
|
||||
def rank
|
||||
return nil if illegal?
|
||||
|
||||
# array of suits, ranks
|
||||
suits = @cards.collect { |c| c.suit_s }
|
||||
ranks = @cards.collect { |c| c.rank }
|
||||
|
||||
# count of suits
|
||||
suit_counts = Hash.new(0)
|
||||
suits.each { |s| suit_counts[s] += 1 }
|
||||
|
||||
# count of ranks
|
||||
rank_counts = Hash.new(0)
|
||||
ranks.each { |s| rank_counts[s] += 1 }
|
||||
|
||||
# test for straight & flush
|
||||
straight =
|
||||
ranks.sort == (ranks.min .. ranks.max).to_a ||
|
||||
ranks.sort == [2,3,4,5,14] ||
|
||||
ranks.sort == [2,3,4,5,6,7,8,9,10,14]
|
||||
|
||||
flush = (suits.sort.uniq.size == 1)
|
||||
|
||||
# rank hand
|
||||
return :royal_flush if straight && flush && ranks.min == 10
|
||||
return :straight_flush if straight && flush
|
||||
return :four_of_a_kind if [1,4] == rank_counts.values.sort
|
||||
return :full_house if [2,3] == rank_counts.values.sort
|
||||
return :flush if flush
|
||||
return :straight if straight
|
||||
|
||||
# nothing
|
||||
nil
|
||||
end
|
||||
|
||||
|
||||
def score
|
||||
r = rank
|
||||
|
||||
return 0 if r.nil?
|
||||
|
||||
# ten card hands
|
||||
return 80 if @cards.size == 10 && r == :straight_flush
|
||||
return 40 if @cards.size == 10 && r == :flush
|
||||
return 20 if @cards.size == 10 && r == :straight
|
||||
|
||||
# five card hands
|
||||
return 21 if r == :royal_flush
|
||||
return 20 if r == :straight_flush
|
||||
return 15 if r == :four_of_a_kind
|
||||
return 10 if r == :full_house
|
||||
return 7 if r == :flush
|
||||
return 5 if r == :straight
|
||||
|
||||
# nothing
|
||||
return 0
|
||||
end
|
||||
|
||||
def score_name
|
||||
rank.to_s.gsub(/_/,' ') if rank
|
||||
end
|
||||
|
||||
def to_s
|
||||
@cards.collect { |c| c.to_s }.join(', ')
|
||||
end
|
||||
|
||||
def hash
|
||||
to_s.hash
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
to_s <=> other.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 465 B |
|
After Width: | Height: | Size: 443 B |
|
After Width: | Height: | Size: 474 B |
|
After Width: | Height: | Size: 384 B |
|
After Width: | Height: | Size: 482 B |
|
After Width: | Height: | Size: 476 B |
|
After Width: | Height: | Size: 492 B |
|
After Width: | Height: | Size: 468 B |
|
After Width: | Height: | Size: 515 B |
|
After Width: | Height: | Size: 503 B |
|
After Width: | Height: | Size: 533 B |
|
After Width: | Height: | Size: 504 B |
|
After Width: | Height: | Size: 546 B |
|
After Width: | Height: | Size: 524 B |
|
After Width: | Height: | Size: 549 B |
|
After Width: | Height: | Size: 516 B |
|
After Width: | Height: | Size: 573 B |
|
After Width: | Height: | Size: 552 B |
|
After Width: | Height: | Size: 579 B |
|
After Width: | Height: | Size: 541 B |
|
After Width: | Height: | Size: 590 B |
|
After Width: | Height: | Size: 552 B |
|
After Width: | Height: | Size: 609 B |
|
After Width: | Height: | Size: 573 B |
|
After Width: | Height: | Size: 619 B |
|
After Width: | Height: | Size: 571 B |
|
After Width: | Height: | Size: 648 B |
|
After Width: | Height: | Size: 590 B |
|
After Width: | Height: | Size: 647 B |
|
After Width: | Height: | Size: 593 B |
|
After Width: | Height: | Size: 664 B |
|
After Width: | Height: | Size: 621 B |
|
After Width: | Height: | Size: 440 B |
|
After Width: | Height: | Size: 436 B |
|
After Width: | Height: | Size: 443 B |
|
After Width: | Height: | Size: 497 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 666 B |
|
After Width: | Height: | Size: 629 B |
|
After Width: | Height: | Size: 699 B |
|
After Width: | Height: | Size: 650 B |
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
while [ 1 ]
|
||||
do
|
||||
./score.rb hands.txt > /Volumes/share/score.html
|
||||
sleep 5
|
||||
done
|
||||
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'hand'
|
||||
require 'combinations'
|
||||
|
||||
def score(hand_string)
|
||||
# split into an array of two character strings (each representing a card)
|
||||
cards = hand_string.scan(/../)
|
||||
|
||||
# a place to store all of our scores
|
||||
best_hands = nil
|
||||
best_score = -1
|
||||
|
||||
# create and score all permutations of two 5 card hands
|
||||
cards.combinations(5).each do |c|
|
||||
# create each hand from two 10 character strings
|
||||
hand_a = Hand.new(c.join)
|
||||
hand_b = Hand.new((cards-c).join)
|
||||
score = hand_a.score + hand_b.score
|
||||
|
||||
# save the hand if it's the best
|
||||
best_hands,best_score = [hand_a,hand_b],score if score > best_score
|
||||
end
|
||||
|
||||
# now create and score the 10 card hand
|
||||
ten_card_hand = Hand.new(cards.join)
|
||||
best_hands,best_score = [ten_card_hand],ten_card_hand.score if ten_card_hand.score > best_score
|
||||
|
||||
# return score
|
||||
[best_score, best_hands]
|
||||
end
|
||||
|
||||
PlayerNames = {
|
||||
'aaron' => 'Aaron Dickinson',
|
||||
'adam' => 'Adam Dickinson',
|
||||
'angel' => 'Angel Madigan',
|
||||
'casey' => 'Casey Lowe',
|
||||
'cathy' => 'Cathy Waits',
|
||||
'dundee' => 'Dundee Reyno',
|
||||
'eddy' => 'Eddy Cramm',
|
||||
'eileen' => 'Eileen Gher',
|
||||
'eryn' => 'Eryn Roston',
|
||||
'francois' => 'François Bertrand',
|
||||
'fred' => 'Fred Thompson',
|
||||
'george' => 'George Rothrock',
|
||||
'jeff' => 'Jeff Curley',
|
||||
'jen' => 'Jen Gratz',
|
||||
'john' => 'John Yuill',
|
||||
'jonathan' => 'Jonathan Leghart',
|
||||
'josh' => 'Josh Hart',
|
||||
'lonna' => 'Lonna Leghart',
|
||||
'mike' => 'Mike Skinner',
|
||||
'peter' => 'Peter Heino',
|
||||
'ramana' => 'Ramana Prakash',
|
||||
'randy' => 'Randy Yumul',
|
||||
'rob' => 'Rob Whyte',
|
||||
'ryan' => 'Ryan Mack',
|
||||
'shaelagh' => 'Shaelagh Skinner',
|
||||
'stephanie' => 'Stéphanie Plante',
|
||||
'steven' => 'Steven Gher',
|
||||
'swaits' => 'Stephen Waits',
|
||||
'tim' => 'Tim Flier',
|
||||
'tj' => 'TJ Madigan',
|
||||
}
|
||||
|
||||
|
||||
total = Hash.new(0)
|
||||
|
||||
puts '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
|
||||
puts '<html><head>'
|
||||
puts '<title>Super Babel Scoring</title>'
|
||||
puts '<meta http-equiv="content-type" content="text/html; charset=UTF-8">'
|
||||
puts '<link href="css/tripoli.simple.css" type="text/css" rel="stylesheet">'
|
||||
puts '<!--[if IE]><link rel="stylesheet" type="text/css" href="css/tripoli.simple.ie.css"><![endif]-->'
|
||||
puts ' <style type="text/css">
|
||||
tr.even td {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
tr.odd td {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
</style>'
|
||||
puts '</head><body>'
|
||||
puts '<div class="content" style="text-align:left;margin:20px auto;padding:20px">'
|
||||
puts '<h1>Hand Log</h1>'
|
||||
puts '<table>'
|
||||
puts '<tr><th>Player</th><th colspan=2>Hands</th><th>Score</th><th>Total</th></tr>'
|
||||
even = false
|
||||
IO.readlines(ARGV[0]).each do |line|
|
||||
player,cards = line.chomp.split(/,/)
|
||||
score,hands = score(cards)
|
||||
total[player.downcase] += score
|
||||
evenorodd = even ? 'even' : 'odd'
|
||||
even = !even
|
||||
puts "<tr class=\"#{evenorodd}\">"
|
||||
puts " <td>#{PlayerNames[player]}<br/>[#{player}]</td>"
|
||||
colspan = 3 - hands.size
|
||||
hands.each do |h|
|
||||
puts " <td colspan=\"#{colspan}\">"
|
||||
h.to_s.split(/, ?/).each { |card| puts "<img src=\"img/#{card}.gif\">" }
|
||||
puts "<br/>#{h.score_name} (#{h.score})</td>"
|
||||
end
|
||||
puts " <td>#{score}</td>"
|
||||
puts " <td>#{total[player]}</td>"
|
||||
puts '</tr>'
|
||||
end
|
||||
puts '</table>'
|
||||
|
||||
puts '<br/><hr/><br/>'
|
||||
|
||||
puts '<h1>Total Scores</h1>'
|
||||
total.sort { |a,b| a[1] <=> b[1] }.reverse.each { |s| puts "#{s[1]} - #{PlayerNames[s[0]]} [#{s[0]}]<br/>" }
|
||||
|
||||
puts '</div>'
|
||||
puts '</body>'
|
||||
puts '</html>'
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
tj,tsjsqsksastcjcqckcac
|
||||
tj,tsjsqsksastcjcqckcac
|
||||
cathy,tsjsqsksastcjcqckcac
|
||||
cathy,3d8c6s7d8h9s9dkdqd5d
|
||||
cathy,2s3s4s5s6s7s8s9stsjs
|
||||
eileen,2c3s4c5d6h7s8d9sthjs
|
||||
randy,as3s4s5s6s7s8s9stsjs
|
||||
jen,asadacah6s7s8s9stsjs
|
||||
jen,asadackskd7s8s9stsjs
|
||||
jen,asadacksks2c8h5stdjs
|
||||
francois,2c3s4c5d6h7s8d9sthjs
|
||||
stephanie,as3s4s5s6s7s8s9stsjs
|
||||