sanichi-chess_icu 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 4
4
- :patch: 2
4
+ :patch: 3
data/lib/player.rb CHANGED
@@ -205,6 +205,14 @@ All other attributes are unaffected.
205
205
  @results.inject(0.0) { |t, r| t += r.points }
206
206
  end
207
207
 
208
+ # Renumber the player according to the supplied hash. Return self.
209
+ def renumber!(map)
210
+ raise "player number #{@num} not found in renumbering hash" unless map[@num]
211
+ self.num = map[@num]
212
+ @results.each{ |r| r.renumber!(map) }
213
+ self
214
+ end
215
+
208
216
  # Loose equality test. Passes if the names match and the federations are not different.
209
217
  def ==(other)
210
218
  return true if equal?(other)
data/lib/result.rb CHANGED
@@ -159,7 +159,7 @@ The _points_ read-only accessor always returns a floating point number: either 0
159
159
  end
160
160
  end
161
161
 
162
- # Reverse a result so it is seen from the opponent's perspective.
162
+ # Return a reversed version (from the opponent's perspective) of a result.
163
163
  def reverse(rateable=nil)
164
164
  return unless @opponent
165
165
  r = Result.new(@round, @opponent, @score == 'W' ? 'L' : (@score == 'L' ? 'W' : 'D'))
@@ -170,6 +170,17 @@ The _points_ read-only accessor always returns a floating point number: either 0
170
170
  r
171
171
  end
172
172
 
173
+ # Renumber the player and opponent (if there is one) according to the supplied hash. Return self.
174
+ def renumber!(map)
175
+ raise "result player number #{@player} not found in renumbering hash" unless map[@player]
176
+ self.player = map[@player]
177
+ if @opponent
178
+ raise "result opponent number #{@opponent} not found in renumbering hash" unless map[@opponent]
179
+ self.opponent = map[@opponent]
180
+ end
181
+ self
182
+ end
183
+
173
184
  # Loose equality. True if the round, player and opponent numbers, colour and score all match.
174
185
  def ==(other)
175
186
  return unless other.is_a? Result
data/lib/team.rb CHANGED
@@ -68,6 +68,15 @@ Attempting to add non-numbers or duplicate numbers as new team members results i
68
68
  @members.push(pnum)
69
69
  end
70
70
 
71
+ # Renumber the players according to the supplied hash. Return self.
72
+ def renumber!(map)
73
+ @members.each_with_index do |pnum, index|
74
+ raise "player number #{pnum} not found in renumbering hash" unless map[pnum]
75
+ @members[index] = map[pnum]
76
+ end
77
+ self
78
+ end
79
+
71
80
  # Detect if a member exists in a team.
72
81
  def include?(number)
73
82
  @members.include?(number)
data/lib/tournament.rb CHANGED
@@ -52,7 +52,7 @@ Side effects of calling _validate!_ or _invalid_ include:
52
52
 
53
53
  If the _rerank_ option is set, as in this example:
54
54
 
55
- tournament.validate!(:rerank => true)
55
+ t.validate!(:rerank => true)
56
56
 
57
57
  then there are additional side effects of validating a tournament:
58
58
 
@@ -61,6 +61,16 @@ then there are additional side effects of validating a tournament:
61
61
 
62
62
  Ranking is consistent if either no players have any rank or if all players have a rank and no player is ranked higher than another player with more points.
63
63
 
64
+ The players in a tournament can be renumbered by rank or name. After any renumbering the player numbers,
65
+ which initially can be any collection of unique integers, will start at 1 and go up to the number of players.
66
+
67
+ t.renumber!(:name) # renumber by name
68
+ t.renumber!(:rank) # renumber by rank
69
+ t.renumber! # same - rank is the default
70
+
71
+ A side effect of renumbering by rank is that if the tournament started without any player ranking or
72
+ with inconsitent ranking, it will be reranked (i.e. the method _rerank_ will be called on it).
73
+
64
74
  =end
65
75
 
66
76
  class Tournament
@@ -234,7 +244,7 @@ Ranking is consistent if either no players have any rank or if all players have
234
244
  end
235
245
  end
236
246
 
237
- # Rerank the tournament.
247
+ # Rerank the tournament by score, resolving ties using name.
238
248
  def rerank
239
249
  @player.values.map{ |p| [p, p.points] }.sort do |a,b|
240
250
  d = b[1] <=> a[1]
@@ -245,6 +255,29 @@ Ranking is consistent if either no players have any rank or if all players have
245
255
  v[0].rank = i + 1
246
256
  end
247
257
  end
258
+
259
+ # Renumber the players according to a given criterion. Return self.
260
+ def renumber!(criterion = :rank)
261
+ map = Hash.new
262
+
263
+ # Decide how to rank.
264
+ if criterion == :name
265
+ @player.values.sort_by{ |p| p.name }.each_with_index{ |p, i| map[p.num] = i + 1 }
266
+ else
267
+ begin check_ranks rescue rerank end
268
+ @player.values.each{ |p| map[p.num] = p.rank}
269
+ end
270
+
271
+ # Apply ranking.
272
+ @teams.each{ |t| t.renumber!(map) }
273
+ @player = @player.values.inject({}) do |hash, player|
274
+ player.renumber!(map)
275
+ hash[player.num] = player
276
+ hash
277
+ end
278
+
279
+ self
280
+ end
248
281
 
249
282
  # Is a tournament invalid? Either returns false (if it's valid) or an error message.
250
283
  def invalid(options={})
@@ -273,7 +306,13 @@ Ranking is consistent if either no players have any rank or if all players have
273
306
  # Check players.
274
307
  def check_players
275
308
  raise "the number of players (#{@player.size}) must be at least 2" if @player.size < 2
276
- @player.each { |num, p| raise "player #{num} has no results" if p.results.size == 0 }
309
+ @player.each do |num, p|
310
+ raise "player #{num} has no results" if p.results.size == 0
311
+ p.results.each do |r|
312
+ next unless r.opponent
313
+ raise "opponent #{r.opponent} of player #{num} is not in the tournament" unless @player[r.opponent]
314
+ end
315
+ end
277
316
  end
278
317
 
279
318
  # Round should go from 1 to a maximum, there should be at least one result in every round and,
@@ -330,7 +369,7 @@ Ranking is consistent if either no players have any rank or if all players have
330
369
  # * no two players have the same rank
331
370
  # * the highest rank is 1
332
371
  # * the lowest rank is equal to the total of players
333
- def check_ranks(options)
372
+ def check_ranks(options={})
334
373
  ranks = Hash.new
335
374
  @player.values.each do |p|
336
375
  if p.rank
data/spec/player_spec.rb CHANGED
@@ -236,6 +236,25 @@ module ICU
236
236
  end
237
237
  end
238
238
 
239
+ context "renumber the player numbers" do
240
+ before(:each) do
241
+ @p = Player.new('Mark', 'Orr', 10)
242
+ @p.add_result(Result.new(1, 10, 'W', :opponent => 20))
243
+ @p.add_result(Result.new(2, 10, 'W', :opponent => 30))
244
+ end
245
+
246
+ it "should renumber successfully if the map has the relevant player numbers" do
247
+ map = { 10 => 1, 20 => 2, 30 => 3 }
248
+ @p.renumber!(map).num.should == 1
249
+ @p.results.map{ |r| r.opponent }.sort.join('').should == '23'
250
+ end
251
+
252
+ it "should raise exception if a player number is not in the map" do
253
+ lambda { @p.renumber!({ 100 => 1, 20 => 2, 30 => 3 }) }.should raise_error(/player.*10.*not found/)
254
+ lambda { @p.renumber!({ 10 => 1, 200 => 2, 30 => 3 }) }.should raise_error(/opponent.*20.*not found/)
255
+ end
256
+ end
257
+
239
258
  context "loose equality" do
240
259
  before(:all) do
241
260
  @mark1 = Player.new('Mark', 'Orr', 1)
data/spec/result_spec.rb CHANGED
@@ -138,6 +138,25 @@ module ICU
138
138
  end
139
139
  end
140
140
 
141
+ context "renumber the player numbers in a result" do
142
+ before(:each) do
143
+ @r1 = Result.new(1, 4, 0)
144
+ @r2 = Result.new(2, 3, 1, :opponent => 4, :color => 'B')
145
+ end
146
+
147
+ it "should renumber successfully if the map has the relevant player numbers" do
148
+ map = { 4 => 1, 3 => 2 }
149
+ @r1.renumber!(map).player.should == 1
150
+ @r2.renumber!(map).player.should == 2
151
+ @r1.opponent.should be_nil
152
+ @r2.opponent.should == 1
153
+ end
154
+
155
+ it "should raise exception if a player number is not in the map" do
156
+ lambda { @r1.renumber!({ 5 => 1, 3 => 2 }) }.should raise_error(/player.*4.*not found/)
157
+ end
158
+ end
159
+
141
160
  context "loose equality" do
142
161
  before(:each) do
143
162
  @r1 = Result.new(1, 1, 0, :opponent => 2, :colour => 'W')
data/spec/team_spec.rb CHANGED
@@ -45,6 +45,15 @@ module ICU
45
45
  it "should blow up if an attempt is made to add a duplicate number" do
46
46
  lambda { @t.add_member(3) }.should raise_error(/duplicate/)
47
47
  end
48
+
49
+ it "should renumber successfully if the map has the relevant player numbers" do
50
+ map = { 0 => 1, 3 => 2, -7 => 3 }
51
+ @t.renumber!(map).members.sort.join('').should == '123'
52
+ end
53
+
54
+ it "should raise exception if a player is missing from the renumber map" do
55
+ lambda { @t.renumber!({ 5 => 1, 3 => 2 }) }.should raise_error(/player.*not found/)
56
+ end
48
57
  end
49
58
  end
50
59
  end
@@ -171,15 +171,15 @@ KRAUSE
171
171
  KRAUSE
172
172
  @p = Krause.new
173
173
  @t = @p.parse!(@krause)
174
- @s = Krause.new
174
+ @q = Krause.new
175
175
  end
176
176
 
177
177
  it "should serialize back to the original if the input is fully canonicalised" do
178
- @s.serialize(@t).should == @krause
178
+ @q.serialize(@t).should == @krause
179
179
  end
180
180
 
181
181
  it "should return nil on invalid input" do
182
- @s.serialize('Rubbish').should be_nil
182
+ @q.serialize('Rubbish').should be_nil
183
183
  end
184
184
  end
185
185
 
@@ -202,6 +202,32 @@ KRAUSE
202
202
  @t.player(3).rank.should == 3
203
203
  end
204
204
  end
205
+
206
+ context "renumbering" do
207
+ before(:all) do
208
+ @krause = <<KRAUSE
209
+ 012 Las Vegas National Open
210
+ 042 2008-06-07
211
+ 001 10 w Ui Laighleis,Gearoidin 1985 IRL 1.0 20 b 0 30 w 1
212
+ 001 20 m m Orr,Mark 2258 IRL 2.0 10 w 1 30 b 1
213
+ 001 30 m g Bologan,Viktor 2663 MDA 0.0 10 b 0 20 w 0
214
+ KRAUSE
215
+ @p = Krause.new
216
+ @t = @p.parse!(@krause)
217
+ @reordered = <<REORDERED
218
+ 012 Las Vegas National Open
219
+ 042 2008-06-07
220
+ 001 1 m m Orr,Mark 2258 IRL 2.0 1 2 w 1 3 b 1
221
+ 001 2 w Ui Laighleis,Gearoidin 1985 IRL 1.0 2 1 b 0 3 w 1
222
+ 001 3 m g Bologan,Viktor 2663 MDA 0.0 3 2 b 0 1 w 0
223
+ REORDERED
224
+ end
225
+
226
+ it "should serialise correctly after renumbering by rank" do
227
+ @t.renumber!
228
+ @p.serialize(@t).should == @reordered
229
+ end
230
+ end
205
231
 
206
232
  context "errors" do
207
233
  before(:each) do
@@ -417,5 +417,39 @@ module ICU
417
417
  @t.invalid.should match(/already.*member/)
418
418
  end
419
419
  end
420
+
421
+ context "renumbering" do
422
+ before(:each) do
423
+ @t = Tournament.new('Edinburgh Masters', '2009-11-09')
424
+ @t.add_player(@mark = Player.new('Mark', 'Orr', 10))
425
+ @t.add_player(@gary = Player.new('Gary', 'Kasparov', 20))
426
+ @t.add_player(@boby = Player.new('Bobby', 'Fischer', 30))
427
+ @t.add_result(Result.new(1, 10, 'W', :opponent => 20))
428
+ @t.add_result(Result.new(2, 20, 'W', :opponent => 30))
429
+ @t.add_result(Result.new(3, 30, 'L', :opponent => 10))
430
+ end
431
+
432
+ it "sample tournament is valid but unranked" do
433
+ @t.invalid.should be_false
434
+ @t.player(10).rank.should be_nil
435
+ end
436
+
437
+ it "should be renumberable by rank" do
438
+ @t.renumber!.invalid.should be_false
439
+ @t.players.map{ |p| p.num }.join('|').should == '1|2|3'
440
+ @t.players.map{ |p| p.first_name }.join('|').should == 'Mark|Gary|Bobby'
441
+ end
442
+
443
+ it "should be ranked after renumbering by rank" do
444
+ @t.renumber!.invalid.should be_false
445
+ @t.players.map{ |p| p.rank }.join('|').should == '1|2|3'
446
+ end
447
+
448
+ it "should be renumberable by name" do
449
+ @t.renumber!(:name).invalid.should be_false
450
+ @t.players.map{ |p| p.num }.join('|').should == '1|2|3'
451
+ @t.players.map{ |p| p.last_name }.join('|').should == 'Fischer|Kasparov|Orr'
452
+ end
453
+ end
420
454
  end
421
455
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sanichi-chess_icu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Orr
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-13 00:00:00 -07:00
12
+ date: 2009-05-17 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency