Class: Bridge::Result

Inherits:
Object
  • Object
show all
Defined in:
lib/bridge/result.rb

Direct Known Subclasses

DuplicateResult, RubberResult

Constant Summary collapse

VULN_MAP =
{
  Vulnerability.none => [],
  Vulnerability.north_south => [Direction.north, Direction.south],
  Vulnerability.east_west => [Direction.east, Direction.west],
  Vulnerability.all => [
    Direction.north, Direction.east,
    Direction.west, Direction.south
  ]
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(board, contract, tricks_made = nil, opts = {}) ⇒ Result

Returns a new instance of Result.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/bridge/result.rb', line 25

def initialize(board, contract, tricks_made = nil, opts = {})
  self.board = board
  self.contract = contract
  self.tricks_made = tricks_made
  
  # a claim has been made. Let's modify the trick count accordingly
  if opts[:claim].is_a?(Array)
    self.claimed_by = opts[:claim][0]
    self.claimed = opts[:claim][1]
    defender_tricks = opts[:claim][2]
    if [self.contract[:declarer],(self.contract[:declarer] + 2) % 4].include?(claimed_by)
      self.tricks_made += claimed # if declarer claimed, add claim to tally
    else # if defender claimed, add what remains to tally
      self.tricks_made = 13 - (defender_tricks + claimed)
    end
    self.tricks_made
  end
  
  self.is_vulnerable = nil
  if self.contract
    vuln = self.board.vulnerability || Vulnerability.none
    self.is_vulnerable = VULN_MAP[vuln].include?(self.contract[:declarer])
  end
  
  self.score = self._get_score
end

Instance Attribute Details

#boardObject

Returns the value of attribute board.



21
22
23
# File 'lib/bridge/result.rb', line 21

def board
  @board
end

#claimedObject

Returns the value of attribute claimed.



22
23
24
# File 'lib/bridge/result.rb', line 22

def claimed
  @claimed
end

#claimed_byObject

Returns the value of attribute claimed_by.



22
23
24
# File 'lib/bridge/result.rb', line 22

def claimed_by
  @claimed_by
end

#contractObject

Returns the value of attribute contract.



21
22
23
# File 'lib/bridge/result.rb', line 21

def contract
  @contract
end

#contract_levelObject

Returns the value of attribute contract_level.



22
23
24
# File 'lib/bridge/result.rb', line 22

def contract_level
  @contract_level
end

#is_doubledObject

Returns the value of attribute is_doubled.



22
23
24
# File 'lib/bridge/result.rb', line 22

def is_doubled
  @is_doubled
end

#is_majorObject

Returns the value of attribute is_major.



22
23
24
# File 'lib/bridge/result.rb', line 22

def is_major
  @is_major
end

#is_redoubledObject

Returns the value of attribute is_redoubled.



22
23
24
# File 'lib/bridge/result.rb', line 22

def is_redoubled
  @is_redoubled
end

#is_vulnerableObject

Returns the value of attribute is_vulnerable.



21
22
23
# File 'lib/bridge/result.rb', line 21

def is_vulnerable
  @is_vulnerable
end

#scoreObject

Returns the value of attribute score.



21
22
23
# File 'lib/bridge/result.rb', line 21

def score
  @score
end

#tricks_madeObject

Returns the value of attribute tricks_made.



21
22
23
# File 'lib/bridge/result.rb', line 21

def tricks_made
  @tricks_made
end

#tricks_requiredObject

Returns the value of attribute tricks_required.



22
23
24
# File 'lib/bridge/result.rb', line 22

def tricks_required
  @tricks_required
end

#trump_suitObject

Returns the value of attribute trump_suit.



22
23
24
# File 'lib/bridge/result.rb', line 22

def trump_suit
  @trump_suit
end

Instance Method Details

#_get_scoreObject

Raises:

  • (NoMethodError)


14
15
16
# File 'lib/bridge/result.rb', line 14

def _get_score
  raise NoMethodError  # Expected to be implemented by subclasses.
end

#_get_score_componentsObject

Compute the component values which contribute to the score. Note that particular scoring schemes may ignore some of the components. Scoring values: en.wikipedia.org/wiki/Bridge_scoring @return: a dict of component values. @rtype: dict



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/bridge/result.rb', line 57

def _get_score_components
  components = {}

  self.is_doubled      = self.contract[:double_by] ? true : false
  self.is_redoubled    = self.contract[:redouble_by] ? true : false
  self.contract_level  = self.contract[:bid].level + 1
  self.tricks_required = contract_level + 6
  self.trump_suit      = self.contract[:bid].strain
  self.is_major        = [Strain.spade, Strain.heart].include?(self.contract[:bid].strain)
  
  if tricks_made >= tricks_required  # Contract successful.
    #### Contract tricks (bid and made) ####
    if is_major || self.contract[:bid].strain == Strain.no_trump # Hearts, Spades and NT score 30 for each odd trick.
      components['odd'] = contract_level * 30
      if trump_suit == Strain.no_trump
        components['odd'] += 10  # For NT, add a 10 point bonus.
      end
    else
      components['odd'] = contract_level * 20
    end
    
    if is_redoubled
      components['odd'] *= 4  # Double the doubled score.
    elsif is_doubled
      components['odd'] *= 2  # Double score.
    end


    #### over_tricks ####
    over_tricks = tricks_made - tricks_required
    
    if is_redoubled
      # 400 for each overtrick if vulnerable, 200 if not.
      if is_vulnerable
        components['over'] = over_tricks * 400
      else
        components['over'] = over_tricks * 200
      end
    elsif is_doubled
      # 200 for each overtrick if vulnerable, 100 if not.
      if is_vulnerable
        components['over'] = over_tricks * 200
      else
        components['over'] = over_tricks * 100
      end
    else  # Undoubled contract.
      if is_major || self.contract[:bid].strain == Strain.no_trump
        # Hearts, Spades and NT score 30 for each overtrick.
        components['over'] = over_tricks * 30
      else
        # Clubs and Diamonds score 20 for each overtrick.
        components['over'] = over_tricks * 20
      end
    end

    #### Premium bonuses ####

    if tricks_required == 13
      # 1500 for grand slam if vulnerable, 1000 if not.
      if is_vulnerable
        components['slambonus'] = 1500
      else
        components['slambonus'] = 1000
      end
    elsif tricks_required == 12
      # 750 for small slam if vulnerable, 500 if not.
      if is_vulnerable
        components['slambonus'] = 750
      else
        components['slambonus'] = 500
      end
    end
    
    if components['odd'] >= 100 # Game contract (non-slam).
      # 500 for game if vulnerable, 300 if not.
      if is_vulnerable
        components['gamebonus'] = 500
      else
        components['gamebonus'] = 300
      end
    else # Non-game contract.
      components['partscore'] = 50
    end
    
    #### Insult bonus ####
    if is_redoubled
      components['insultbonus'] = 100
    elsif is_doubled
      components['insultbonus'] = 50
    end
  else  # Contract not successful.
    under_tricks = tricks_required - tricks_made
    if is_redoubled
      if is_vulnerable
        # -400 for first, then -600 each.
        components['under'] = -400 + (under_tricks - 1) * -600
      else
        # -200 for first, -400 for second and third, then -600 each.
        components['under'] = -200 + (under_tricks - 1) * -400
        if under_tricks > 3
          components['under'] += (under_tricks - 3) * -200
        end
      end
    elsif is_doubled
      if is_vulnerable
        # -200 for first, then -300 each.
        components['under'] = -200 + (under_tricks - 1) * -300
      else
        # -100 for first, -200 for second and third, then -300 each.
        components['under'] = -100 + (under_tricks - 1) * -200
        if under_tricks > 3
          components['under'] += (under_tricks - 3) * -100
        end
      end
    else
      if is_vulnerable
        # -100 each.
        components['under'] = under_tricks * -100
      else
        # -50 each.
        components['under'] = under_tricks * -50
      end
    end
  end
  components
end

#to_aObject



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/bridge/result.rb', line 184

def to_a
  { 
    score: _get_score,
    tricks_made: tricks_made,
    tricks_required: tricks_required,
    contract_level: contract_level,
    trump_suit: trump_suit,
    vulnerable: is_vulnerable,
    major: is_major,
    doubled: is_doubled,
    redoubled: is_redoubled,
    claimed: claimed,
    claimed_by: claimed_by
  }
end