lib/bridge/score.rb in bridge-0.1.4 vs lib/bridge/score.rb in bridge-0.2.0
- old
+ new
@@ -1,43 +1,35 @@
module Bridge
class Score
- attr_reader :tricks, :contract, :vulnerable
- alias :vulnerable? :vulnerable
+ attr_reader :contract, :vulnerable, :tricks_number
- # Checks contract with result, i.e. "1NTX-1", "2S=", "6SXX+1"
- # on Ruby >= 1.9 there are named groups :contract and :result
- # on Ruby < 1.9 there are: contract on $1 and result on $5
- if RUBY_VERSION >= "1.9"
- REGEXP = Regexp.new %q{\A(?<contract>([1-7])([CDHS]|NT)(X{1,2})?)(?<result>=|\+[1-6]|-([1-9]|1[0-3]))\Z}
- else
- REGEXP = Regexp.new %q{\A(([1-7])([CDHS]|NT)(X{1,2})?)(=|\+[1-6]|-([1-9]|1[0-3]))\Z}
- end
-
# Creates new score object
#
# ==== Example
- # Bridge::Score.new(:contract => "7SXX", :vulnerable => true, :tricks => "=")
- def initialize(options = {})
- @contract, @modifier = split_contract(options[:contract])
- @tricks = calculate_tricks(options[:tricks])
- raise ArgumentError, "invalid tricks: #{@tricks}" unless (0..13).include?(@tricks)
- @vulnerable = options[:vulnerable] || false
+ # Bridge::Score.new("7SXXN", "NS", 0)
+ def initialize(contract, vulnerable, tricks)
+ @contract = contract
+ @vulnerable = vulnerable
+ @tricks_number = calculate_tricks(tricks)
end
+ # Returns all possible contracts with given points
+ def self.with_points(points)
+ all_contracts.select { |contract, result| result == points }.keys.sort
+ end
+
# Returns nr of overtricks or undertricks. 0 if contract was made without them
def result
- tricks - tricks_to_make_contract
+ tricks_number - tricks_to_make_contract
end
# Returns string with nr of tricks relative to contract level
def result_string
- if result > 0
- "+" << result.to_s
- elsif result == 0
- "="
- else
- result.to_s
+ case
+ when result > 0 then "+#{result}"
+ when result == 0 then "="
+ when result < 0 then result.to_s
end
end
# Returns true if contract was made, false otherwise
def made?
@@ -47,30 +39,50 @@
# Returns points achieved by declarer: + for made contract - if conctract wasn't made
def points
made? ? (made_contract_points + overtrick_points + bonus) : undertrick_points
end
- # Returns all possible contracts with given points
- def self.with_points(points)
- contracts = all_contracts.select { |contract, result| result == points }
- contracts.respond_to?(:keys) ? contracts.keys.sort : contracts.map { |c| c.first }.sort # Ruby 1.8.* compatibility
+ # Returns if declarer side is vulnerable
+ def vulnerable?
+ case vulnerable
+ when "BOTH" then true
+ when "NONE" then false
+ else
+ vulnerable.split("").include?(declarer)
+ end
end
- # private
+ private
+ def contract_bid
+ @contract_bid ||= Bid.new(contract.match(Bridge::CONTRACT_REGEXP)[:bid])
+ end
+
+ def declarer
+ @declarer ||= contract.match(Bridge::CONTRACT_REGEXP)[:direction]
+ end
+
def tricks_to_make_contract
- contract.level.to_i + 6
+ @tricks_to_make_contract ||= contract_bid.level.to_i + 6
end
def doubled?
- @modifier == 2
+ modifier == 2
end
def redoubled?
- @modifier == 4
+ modifier == 4
end
+ def modifier
+ case contract.match(Bridge::CONTRACT_REGEXP)[:modifier]
+ when nil then 1
+ when "X" then 2
+ when "XX" then 4
+ end
+ end
+
def bonus
game_bonus + grand_slam_bonus + small_slam_bonus + doubled_bonus + redoubled_bonus
end
def game_bonus
@@ -82,19 +94,19 @@
0
end
end
def grand_slam_bonus
- if made? and contract.grand_slam?
+ if made? and contract_bid.grand_slam?
vulnerable? ? 1500 : 1000
else
0
end
end
def small_slam_bonus
- if made? and contract.small_slam?
+ if made? and contract_bid.small_slam?
vulnerable? ? 750 : 500
else
0
end
end
@@ -106,23 +118,23 @@
def redoubled_bonus
(made? and redoubled?) ? 100 : 0
end
def first_trick_points
- contract.no_trump? ? 40 : single_trick_points
+ contract_bid.no_trump? ? 40 : single_trick_points
end
def single_trick_points
- contract.minor? ? 20 : 30
+ contract_bid.minor? ? 20 : 30
end
def undertrick_points
vulnerable? ? vulnerable_undertrick_points : not_vulnerable_undertrick_points
end
def made_contract_points
- first_trick_points * @modifier + (contract.level.to_i - 1) * single_trick_points * @modifier
+ first_trick_points * modifier + (contract_bid.level.to_i - 1) * single_trick_points * modifier
end
def overtrick_points
if doubled?
vulnerable? ? result * 200 : result * 100
@@ -134,11 +146,11 @@
end
# TODO: do some refactoring
def vulnerable_undertrick_points
if !made?
- p = -100 * @modifier
+ p = -100 * modifier
if result < -1
return p += (result + 1) * 300 if doubled?
return p += (result + 1) * 600 if redoubled?
return p += (result + 1) * 100
end
@@ -148,11 +160,11 @@
end
end
def not_vulnerable_undertrick_points
if !made?
- p = -50 * @modifier
+ p = -50 * modifier
if [-3, -2].include?(result)
return p += (result + 1) * 200 if doubled?
return p += (result + 1) * 400 if redoubled?
return p += (result + 1) * 50 if (!doubled? and !redoubled?)
elsif result < -3
@@ -178,24 +190,18 @@
elsif tricks =~ /\A\d[0-3]?\Z/
tricks.to_i
end
end
- def split_contract(contract)
- contract = contract.gsub(/(X+)/, "")
- modifier = $1.nil? ? 1 : $1.to_s.size * 2
- [Bridge::Bid.new(contract), modifier]
- end
-
def self.all_contracts
result = {}
contracts = %w(1 2 3 4 5 6 7).inject([]) do |bids, level|
bids += ["H/S", "C/D", "NT"].map { |suit| level + suit }
end
(contracts + contracts.map { |c| c + "X" } + contracts.map { |c| c + "XX" } ).each do |contract|
- [true, false].each do |vulnerable|
+ ["BOTH", "NONE"].each do |vulnerable|
(0..13).each do |tricks|
- score = new(:contract => contract.sub("H/S", "S").sub("C/D", "C"), :tricks => tricks, :vulnerable => vulnerable)
+ score = new(contract.sub("H/S", "S").sub("C/D", "C").sub("NT", "NT") + "N", vulnerable, tricks)
result[contract + score.result_string + (score.vulnerable? ? "v" : "")] = score.points
end
end
end
result