bridge 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,41 +1,33 @@
1
1
  module Bridge
2
2
  class Score
3
- attr_reader :tricks, :contract, :vulnerable
4
- alias :vulnerable? :vulnerable
5
-
6
- # Checks contract with result, i.e. "1NTX-1", "2S=", "6SXX+1"
7
- # on Ruby >= 1.9 there are named groups :contract and :result
8
- # on Ruby < 1.9 there are: contract on $1 and result on $5
9
- if RUBY_VERSION >= "1.9"
10
- REGEXP = Regexp.new %q{\A(?<contract>([1-7])([CDHS]|NT)(X{1,2})?)(?<result>=|\+[1-6]|-([1-9]|1[0-3]))\Z}
11
- else
12
- REGEXP = Regexp.new %q{\A(([1-7])([CDHS]|NT)(X{1,2})?)(=|\+[1-6]|-([1-9]|1[0-3]))\Z}
13
- end
3
+ attr_reader :contract, :vulnerable, :tricks_number
14
4
 
15
5
  # Creates new score object
16
6
  #
17
7
  # ==== Example
18
- # Bridge::Score.new(:contract => "7SXX", :vulnerable => true, :tricks => "=")
19
- def initialize(options = {})
20
- @contract, @modifier = split_contract(options[:contract])
21
- @tricks = calculate_tricks(options[:tricks])
22
- raise ArgumentError, "invalid tricks: #{@tricks}" unless (0..13).include?(@tricks)
23
- @vulnerable = options[:vulnerable] || false
8
+ # Bridge::Score.new("7SXXN", "NS", 0)
9
+ def initialize(contract, vulnerable, tricks)
10
+ @contract = contract
11
+ @vulnerable = vulnerable
12
+ @tricks_number = calculate_tricks(tricks)
13
+ end
14
+
15
+ # Returns all possible contracts with given points
16
+ def self.with_points(points)
17
+ all_contracts.select { |contract, result| result == points }.keys.sort
24
18
  end
25
19
 
26
20
  # Returns nr of overtricks or undertricks. 0 if contract was made without them
27
21
  def result
28
- tricks - tricks_to_make_contract
22
+ tricks_number - tricks_to_make_contract
29
23
  end
30
24
 
31
25
  # Returns string with nr of tricks relative to contract level
32
26
  def result_string
33
- if result > 0
34
- "+" << result.to_s
35
- elsif result == 0
36
- "="
37
- else
38
- result.to_s
27
+ case
28
+ when result > 0 then "+#{result}"
29
+ when result == 0 then "="
30
+ when result < 0 then result.to_s
39
31
  end
40
32
  end
41
33
 
@@ -49,24 +41,44 @@ module Bridge
49
41
  made? ? (made_contract_points + overtrick_points + bonus) : undertrick_points
50
42
  end
51
43
 
52
- # Returns all possible contracts with given points
53
- def self.with_points(points)
54
- contracts = all_contracts.select { |contract, result| result == points }
55
- contracts.respond_to?(:keys) ? contracts.keys.sort : contracts.map { |c| c.first }.sort # Ruby 1.8.* compatibility
44
+ # Returns if declarer side is vulnerable
45
+ def vulnerable?
46
+ case vulnerable
47
+ when "BOTH" then true
48
+ when "NONE" then false
49
+ else
50
+ vulnerable.split("").include?(declarer)
51
+ end
56
52
  end
57
53
 
58
- # private
54
+ private
55
+
56
+ def contract_bid
57
+ @contract_bid ||= Bid.new(contract.match(Bridge::CONTRACT_REGEXP)[:bid])
58
+ end
59
+
60
+ def declarer
61
+ @declarer ||= contract.match(Bridge::CONTRACT_REGEXP)[:direction]
62
+ end
59
63
 
60
64
  def tricks_to_make_contract
61
- contract.level.to_i + 6
65
+ @tricks_to_make_contract ||= contract_bid.level.to_i + 6
62
66
  end
63
67
 
64
68
  def doubled?
65
- @modifier == 2
69
+ modifier == 2
66
70
  end
67
71
 
68
72
  def redoubled?
69
- @modifier == 4
73
+ modifier == 4
74
+ end
75
+
76
+ def modifier
77
+ case contract.match(Bridge::CONTRACT_REGEXP)[:modifier]
78
+ when nil then 1
79
+ when "X" then 2
80
+ when "XX" then 4
81
+ end
70
82
  end
71
83
 
72
84
  def bonus
@@ -84,7 +96,7 @@ module Bridge
84
96
  end
85
97
 
86
98
  def grand_slam_bonus
87
- if made? and contract.grand_slam?
99
+ if made? and contract_bid.grand_slam?
88
100
  vulnerable? ? 1500 : 1000
89
101
  else
90
102
  0
@@ -92,7 +104,7 @@ module Bridge
92
104
  end
93
105
 
94
106
  def small_slam_bonus
95
- if made? and contract.small_slam?
107
+ if made? and contract_bid.small_slam?
96
108
  vulnerable? ? 750 : 500
97
109
  else
98
110
  0
@@ -108,11 +120,11 @@ module Bridge
108
120
  end
109
121
 
110
122
  def first_trick_points
111
- contract.no_trump? ? 40 : single_trick_points
123
+ contract_bid.no_trump? ? 40 : single_trick_points
112
124
  end
113
125
 
114
126
  def single_trick_points
115
- contract.minor? ? 20 : 30
127
+ contract_bid.minor? ? 20 : 30
116
128
  end
117
129
 
118
130
  def undertrick_points
@@ -120,7 +132,7 @@ module Bridge
120
132
  end
121
133
 
122
134
  def made_contract_points
123
- first_trick_points * @modifier + (contract.level.to_i - 1) * single_trick_points * @modifier
135
+ first_trick_points * modifier + (contract_bid.level.to_i - 1) * single_trick_points * modifier
124
136
  end
125
137
 
126
138
  def overtrick_points
@@ -136,7 +148,7 @@ module Bridge
136
148
  # TODO: do some refactoring
137
149
  def vulnerable_undertrick_points
138
150
  if !made?
139
- p = -100 * @modifier
151
+ p = -100 * modifier
140
152
  if result < -1
141
153
  return p += (result + 1) * 300 if doubled?
142
154
  return p += (result + 1) * 600 if redoubled?
@@ -150,7 +162,7 @@ module Bridge
150
162
 
151
163
  def not_vulnerable_undertrick_points
152
164
  if !made?
153
- p = -50 * @modifier
165
+ p = -50 * modifier
154
166
  if [-3, -2].include?(result)
155
167
  return p += (result + 1) * 200 if doubled?
156
168
  return p += (result + 1) * 400 if redoubled?
@@ -180,21 +192,15 @@ module Bridge
180
192
  end
181
193
  end
182
194
 
183
- def split_contract(contract)
184
- contract = contract.gsub(/(X+)/, "")
185
- modifier = $1.nil? ? 1 : $1.to_s.size * 2
186
- [Bridge::Bid.new(contract), modifier]
187
- end
188
-
189
195
  def self.all_contracts
190
196
  result = {}
191
197
  contracts = %w(1 2 3 4 5 6 7).inject([]) do |bids, level|
192
198
  bids += ["H/S", "C/D", "NT"].map { |suit| level + suit }
193
199
  end
194
200
  (contracts + contracts.map { |c| c + "X" } + contracts.map { |c| c + "XX" } ).each do |contract|
195
- [true, false].each do |vulnerable|
201
+ ["BOTH", "NONE"].each do |vulnerable|
196
202
  (0..13).each do |tricks|
197
- score = new(:contract => contract.sub("H/S", "S").sub("C/D", "C"), :tricks => tricks, :vulnerable => vulnerable)
203
+ score = new(contract.sub("H/S", "S").sub("C/D", "C").sub("NT", "NT") + "N", vulnerable, tricks)
198
204
  result[contract + score.result_string + (score.vulnerable? ? "v" : "")] = score.points
199
205
  end
200
206
  end
@@ -8,11 +8,11 @@ module Bridge
8
8
  end
9
9
 
10
10
  def winner(trump = nil)
11
- winner_in_suit(trump) || winner_in_suit(@suit)
11
+ winner_in_suit(trump) || winner_in_suit(suit)
12
12
  end
13
13
 
14
14
  def complete?
15
- @cards.size == 4
15
+ cards.size == 4
16
16
  end
17
17
 
18
18
  def incomplete?
@@ -22,7 +22,7 @@ module Bridge
22
22
  private
23
23
 
24
24
  def winner_in_suit(suit)
25
- @cards.select { |c| c.suit == suit }.max
25
+ cards.select { |c| c.suit == suit }.max
26
26
  end
27
27
  end
28
28
  end
@@ -1,3 +1,3 @@
1
1
  module Bridge
2
- VERSION = "0.1.4"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,133 @@
1
+ require "helper"
2
+
3
+ describe Bridge::Auction do
4
+ it "raises on invalid bids" do
5
+ assert_raises ArgumentError do
6
+ Bridge::Auction.new("N", ["8NT"])
7
+ end
8
+ end
9
+
10
+ describe "directions" do
11
+ it "returns empty array when no bids" do
12
+ auction = Bridge::Auction.new("N", [])
13
+ assert_equal [], auction.directions
14
+ end
15
+
16
+ it "returns directions" do
17
+ auction = Bridge::Auction.new("N", ["1NT", "PASS", "PASS", "X", "PASS"])
18
+ assert_equal ["N", "E", "S", "W", "N"], auction.directions
19
+ end
20
+ end
21
+
22
+ describe "#next_direction" do
23
+ it "returns next direction" do
24
+ auction = Bridge::Auction.new("N", ["1NT", "PASS", "PASS", "X", "PASS"])
25
+ assert_equal "E", auction.next_direction
26
+ end
27
+
28
+ it "returns dealer direction when no bids" do
29
+ auction = Bridge::Auction.new("S", [])
30
+ assert_equal "S", auction.next_direction
31
+ end
32
+ end
33
+
34
+ describe "#finished?" do
35
+ it "returns false when not finished" do
36
+ refute Bridge::Auction.new("N", ["2NT"]).finished?
37
+ end
38
+
39
+ it "returns true when finished" do
40
+ assert Bridge::Auction.new("N", ["2NT", "PASS", "PASS", "PASS"]).finished?
41
+ end
42
+ end
43
+
44
+ describe "#contract" do
45
+ it "returns nil when no contract" do
46
+ assert_nil Bridge::Auction.new("N", ["PASS"]).contract
47
+ end
48
+
49
+ it "returns current contract" do
50
+ assert_equal "2SN", Bridge::Auction.new("N", ["2S", "PASS"]).contract
51
+ end
52
+
53
+ it "returns current contract with modifier" do
54
+ assert_equal "2SXN", Bridge::Auction.new("N", ["2S", "X", "PASS"]).contract
55
+ end
56
+
57
+ it "returns current contract without modifier" do
58
+ assert_equal "2NTS", Bridge::Auction.new("N", ["2S", "X", "2NT", "PASS"]).contract
59
+ end
60
+ end
61
+
62
+ describe "#declarer" do
63
+ it "returns declarer direction" do
64
+ assert_equal "W", Bridge::Auction.new("E", ["2S", "X", "2NT", "PASS", "PASS", "PASS"]).declarer
65
+ end
66
+ end
67
+
68
+ describe "#bid_allowed?" do
69
+ it "returns false if finished" do
70
+ refute Bridge::Auction.new("N", ["1NT", "PASS", "PASS", "PASS"]).bid_allowed?("PASS")
71
+ end
72
+
73
+ it "returns true if PASS" do
74
+ assert Bridge::Auction.new("N", ["1NT", "PASS", "PASS"]).bid_allowed?("PASS")
75
+ end
76
+
77
+ it "returns false if bid is lower than previous" do
78
+ refute Bridge::Auction.new("N", ["1NT", "PASS"]).bid_allowed?("1S")
79
+ end
80
+
81
+ it "returns true if bid is higher than previous" do
82
+ assert Bridge::Auction.new("N", ["1NT", "PASS", "X"]).bid_allowed?("2C")
83
+ end
84
+
85
+ it "returns true if bid is first contract" do
86
+ assert Bridge::Auction.new("N", ["PASS"]).bid_allowed?("2C")
87
+ end
88
+
89
+ it "returns true if bid is double on previous contract" do
90
+ assert Bridge::Auction.new("N", ["1C"]).bid_allowed?("X")
91
+ end
92
+
93
+ it "returns true if bid is double on previous 2 bids contract" do
94
+ assert Bridge::Auction.new("N", ["1C", "PASS", "PASS"]).bid_allowed?("X")
95
+ end
96
+
97
+ it "returns false if bid is double on partner contract" do
98
+ refute Bridge::Auction.new("N", ["1C", "PASS"]).bid_allowed?("X")
99
+ end
100
+
101
+ it "returns false if bid is double on PASS" do
102
+ refute Bridge::Auction.new("N", ["PASS"]).bid_allowed?("X")
103
+ end
104
+
105
+ it "returns false if bid is double on doubled contract" do
106
+ refute Bridge::Auction.new("N", ["1C", "X", "PASS"]).bid_allowed?("X")
107
+ end
108
+
109
+ it "returns true if bid is redouble on doubled previous contract" do
110
+ assert Bridge::Auction.new("N", ["1C", "X"]).bid_allowed?("XX")
111
+ end
112
+
113
+ it "returns true if bid is redouble on 2 bids previous dobuled contract" do
114
+ assert Bridge::Auction.new("N", ["1C", "X", "PASS", "PASS"]).bid_allowed?("XX")
115
+ end
116
+
117
+ it "returns false if bid is redouble on partners double" do
118
+ refute Bridge::Auction.new("N", ["1C", "X", "PASS"]).bid_allowed?("XX")
119
+ end
120
+
121
+ it "returns false if bid is redouble on not doubled contract" do
122
+ refute Bridge::Auction.new("N", ["1C", "PASS", "PASS"]).bid_allowed?("XX")
123
+ end
124
+
125
+ it "returns false if bid is redouble on redoubled contract" do
126
+ refute Bridge::Auction.new("N", ["1C", "X", "XX", "PASS"]).bid_allowed?("XX")
127
+ end
128
+
129
+ it "returns true if 2 PASS in the auction" do
130
+ assert Bridge::Auction.new("N", ["PASS", "1D", "PASS", "PASS", "1H"]).bid_allowed?("PASS")
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,135 @@
1
+ require "helper"
2
+
3
+ describe Bridge::Bid do
4
+ it "pas is not a valid bid" do
5
+ assert_raises(ArgumentError) do
6
+ Bridge::Bid.new("pas")
7
+ end
8
+ end
9
+
10
+ it "case doesn't matter in bid" do
11
+ assert_equal "PASS", Bridge::Bid.new("pass").to_s
12
+ assert_equal "X", Bridge::Bid.new("x").to_s
13
+ assert_equal "XX", Bridge::Bid.new("xx").to_s
14
+ assert_equal "1NT", Bridge::Bid.new("1nt").to_s
15
+ end
16
+
17
+ it "pass is a valid bid" do
18
+ bid = Bridge::Bid.new("PASS")
19
+ assert bid.pass?
20
+ refute bid.double?
21
+ refute bid.redouble?
22
+ refute bid.modifier?
23
+ refute bid.contract?
24
+ assert_nil bid.level
25
+ assert_nil bid.suit
26
+ end
27
+
28
+ it "double is a valid bid" do
29
+ bid = Bridge::Bid.new("X")
30
+ refute bid.pass?
31
+ assert bid.double?
32
+ refute bid.redouble?
33
+ assert bid.modifier?
34
+ refute bid.contract?
35
+ assert_nil bid.level
36
+ assert_nil bid.suit
37
+ end
38
+
39
+ it "redouble is a valid bid" do
40
+ bid = Bridge::Bid.new("XX")
41
+ refute bid.pass?
42
+ refute bid.double?
43
+ assert bid.redouble?
44
+ assert bid.modifier?
45
+ refute bid.contract?
46
+ assert_nil bid.level
47
+ assert_nil bid.suit
48
+ end
49
+
50
+ it "1H is a valid bid" do
51
+ bid = Bridge::Bid.new("1H")
52
+ refute bid.pass?
53
+ refute bid.double?
54
+ refute bid.redouble?
55
+ refute bid.modifier?
56
+ assert bid.contract?
57
+ assert_equal "1", bid.level
58
+ assert_equal "H", bid.suit
59
+ end
60
+
61
+ it "7NT is a valid bid" do
62
+ bid = Bridge::Bid.new("7NT")
63
+ refute bid.pass?
64
+ refute bid.double?
65
+ refute bid.redouble?
66
+ refute bid.modifier?
67
+ assert bid.contract?
68
+ assert_equal "7", bid.level
69
+ assert_equal "NT", bid.suit
70
+ end
71
+
72
+ it "7NT is greater than 1C" do
73
+ assert Bridge::Bid.new("7NT") > Bridge::Bid.new("1C")
74
+ refute Bridge::Bid.new("7NT") < Bridge::Bid.new("1C")
75
+ refute Bridge::Bid.new("7NT") == Bridge::Bid.new("1C")
76
+ end
77
+
78
+ it "1S is greater than 1H" do
79
+ assert Bridge::Bid.new("1S") > Bridge::Bid.new("1H")
80
+ refute Bridge::Bid.new("1S") < Bridge::Bid.new("1H")
81
+ refute Bridge::Bid.new("1S") == Bridge::Bid.new("1H")
82
+ end
83
+
84
+ it "comparison of PASS and 1S raises an error" do
85
+ assert_raises(ArgumentError) do
86
+ Bridge::Bid.new("PASS") > Bridge::Bid.new("1S")
87
+ end
88
+ end
89
+
90
+ it "comparison of X and PASS raises an error" do
91
+ assert_raises(ArgumentError) do
92
+ Bridge::Bid.new("X") > Bridge::Bid.new("PASS")
93
+ end
94
+ end
95
+
96
+ it "PASS and XX are not equal" do
97
+ refute_equal Bridge::Bid.new("PASS"), Bridge::Bid.new("XX")
98
+ end
99
+
100
+ it "1S returns S trump" do
101
+ assert_equal "S", Bridge::Bid.new("1S").trump
102
+ end
103
+
104
+ it "5NT returns nil trump" do
105
+ assert_nil Bridge::Bid.new("5NT").trump
106
+ end
107
+
108
+ it "1H is a major bid" do
109
+ assert Bridge::Bid.new("1H").major?
110
+ end
111
+
112
+ it "5S is a major bid" do
113
+ assert Bridge::Bid.new("5S").major?
114
+ end
115
+
116
+ it "2C is a minor bid" do
117
+ assert Bridge::Bid.new("2C").minor?
118
+ end
119
+
120
+ it "6D is a minor bid" do
121
+ assert Bridge::Bid.new("6D").minor?
122
+ end
123
+
124
+ it "1NT is a nt bid" do
125
+ assert Bridge::Bid.new("1NT").nt?
126
+ end
127
+
128
+ it "6NT is a small slam" do
129
+ assert Bridge::Bid.new("6NT").small_slam?
130
+ end
131
+
132
+ it "7NT is a grand slam" do
133
+ assert Bridge::Bid.new("7NT").grand_slam?
134
+ end
135
+ end