bridge 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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