add other game scoring scripts
This commit is contained in:
1 parent
9a87aca70c
commit
c864cf5cdb
73 files changed
+2311
No files matched your search
Executable
+375
@@ -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
|
||||||
|
|
||||||
|
|
||||||
+1101
File diff suppressed because it is too large.
Load diff
Executable
+501
@@ -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
|
||||||
|
|
||||||
|
|
||||||
Vendored
BIN
Binary file not shown.
@@ -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
|
||||||
|
======================================================
|
||||||
|
|
||||||
Vendored
BIN
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 275 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 226 B |
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
Executable
+161
@@ -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
|
||||||
|
|
||||||
Executable
+124
@@ -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
|
||||||
|
|
||||||
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Reference in new issue
Block a user