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