sanichi-chess_icu 0.3.3 → 0.3.4
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.
- data/VERSION.yml +1 -1
- data/lib/tournament.rb +96 -48
- data/lib/tournament_krause.rb +5 -19
- metadata +2 -2
data/VERSION.yml
CHANGED
data/lib/tournament.rb
CHANGED
@@ -33,6 +33,27 @@ Note that the players should be added first because the _add_result_ method will
|
|
33
33
|
raise an exception if the players it references through their tournament numbers
|
34
34
|
(10, 20 and 30 in this example) have not already been added to the tournament.
|
35
35
|
|
36
|
+
A tournament can be validated with either the _validate!_ or _invalid_ methods.
|
37
|
+
On success, the first returns true while the second returns false.
|
38
|
+
On error, the first throws an exception while the second returns a description of the message.
|
39
|
+
|
40
|
+
Validations checks that:
|
41
|
+
|
42
|
+
* there are at least two players
|
43
|
+
* every player has a least one result
|
44
|
+
* the round numbers are consistent
|
45
|
+
* the tournament dates are consistent
|
46
|
+
* the player ranks are consistent (only if the _rank_ or _rerank_ option is set)
|
47
|
+
|
48
|
+
Both messages are capable of taking the following boolean valued hash options:
|
49
|
+
|
50
|
+
* _rank_ - check the player ranks
|
51
|
+
* _rerank_ - check the player ranks and automatically repair if absent or not consistent
|
52
|
+
|
53
|
+
For example:
|
54
|
+
|
55
|
+
tournament.validate!(:rank => true)
|
56
|
+
|
36
57
|
=end
|
37
58
|
|
38
59
|
class Tournament
|
@@ -175,78 +196,105 @@ raise an exception if the players it references through their tournament numbers
|
|
175
196
|
@player[result.opponent].add_result(reverse)
|
176
197
|
end
|
177
198
|
end
|
199
|
+
|
200
|
+
# Rerank the tournament.
|
201
|
+
def rerank
|
202
|
+
@player.values.map{ |p| [p, p.points] }.sort do |a,b|
|
203
|
+
d = b[1] <=> a[1]
|
204
|
+
d = a[0].last_name <=> b[0].last_name if d == 0
|
205
|
+
d = a[0].first_name <=> b[0].first_name if d == 0
|
206
|
+
d
|
207
|
+
end.each_with_index do |v,i|
|
208
|
+
v[0].rank = i + 1
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Is a tournament invalid? Either returns false (if it's valid) or an error message.
|
213
|
+
def invalid(options={})
|
214
|
+
begin
|
215
|
+
validate!(options)
|
216
|
+
rescue => err
|
217
|
+
return err.message
|
218
|
+
end
|
219
|
+
false
|
220
|
+
end
|
221
|
+
|
222
|
+
# Raise an exception if a tournament is not valid.
|
223
|
+
# Covers all the ways a tournament can be invalid not already enforced by the setters.
|
224
|
+
def validate!(options={})
|
225
|
+
begin check_ranks rescue rerank end if options[:rerank]
|
226
|
+
check_players
|
227
|
+
check_dates
|
228
|
+
check_rounds
|
229
|
+
check_ranks if options[:rank]
|
230
|
+
true
|
231
|
+
end
|
232
|
+
|
233
|
+
private
|
234
|
+
|
235
|
+
# Check players.
|
236
|
+
def check_players
|
237
|
+
raise "the number of players (#{@player.size}) must be at least 2" if @player.size < 2
|
238
|
+
@player.each { |num, p| raise "player #{num} has no results" if p.results.size == 0 }
|
239
|
+
end
|
178
240
|
|
179
|
-
#
|
180
|
-
|
241
|
+
# Check dates are consistent.
|
242
|
+
def check_dates
|
243
|
+
# If there is a start date and an end date, the start should not come after the end.
|
244
|
+
raise "start date (#{start}) is after end date (#{finish})" if start && finish && start > finish
|
245
|
+
end
|
246
|
+
|
247
|
+
# Round should go from 1 to a maximum, there should be at least one result in every round and,
|
248
|
+
# if the number of rounds has been set, it should agree with the largest round from the results.
|
249
|
+
def check_rounds
|
250
|
+
round = Hash.new
|
251
|
+
round_last = 0
|
252
|
+
@player.values.each do |p|
|
253
|
+
p.results.each do |r|
|
254
|
+
round[r.round] = true
|
255
|
+
round_last = r.round if r.round > round_last
|
256
|
+
end
|
257
|
+
end
|
258
|
+
(1..round_last).each { |r| raise "there are no results for round #{r}" unless round[r] }
|
259
|
+
if rounds
|
260
|
+
raise "declared number of rounds is #{rounds} but there are results in later rounds, such as #{round_last}" if rounds < round_last
|
261
|
+
raise "declared number of rounds is #{rounds} but there are no results with rounds greater than #{round_last}" if rounds > round_last
|
262
|
+
else
|
263
|
+
self.rounds = round_last
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
# Check if the players ranking is consistent, which will be true if:
|
181
268
|
# * every player has a rank
|
182
269
|
# * no two players have the same rank
|
183
270
|
# * the highest rank is 1
|
184
271
|
# * the lowest rank is equal to the total of players
|
185
|
-
def
|
272
|
+
def check_ranks
|
186
273
|
# No two players can have the same rank.
|
187
274
|
ranks = Hash.new
|
188
275
|
@player.values.each do |p|
|
189
276
|
if p.rank
|
190
|
-
|
277
|
+
raise "two players have the same rank #{p.rank}" if ranks[p.rank]
|
191
278
|
ranks[p.rank] = p
|
192
279
|
end
|
193
280
|
end
|
194
|
-
|
195
|
-
# The special case of complete absence of ranking information is an option.
|
196
|
-
return true if ranks.size == 0 && option[:allow_none]
|
197
281
|
|
198
|
-
#
|
199
|
-
|
282
|
+
# Otherwise, every player has to have a rank.
|
283
|
+
raise "every player has to have a rank" unless ranks.size == @player.size
|
200
284
|
|
201
285
|
# The higest and lowest ranks respectively should be 1 and the number of players.
|
202
286
|
by_rank = @player.values.sort{ |a,b| a.rank <=> b.rank}
|
203
|
-
|
204
|
-
|
287
|
+
raise "the highest rank must be 1" unless by_rank[0].rank == 1
|
288
|
+
raise "the lowest rank must be #{ranks.size}" unless by_rank[-1].rank == ranks.size
|
205
289
|
|
206
290
|
# If scores are ordered by ranks, they should go from highest to lowest.
|
207
291
|
if by_rank.size > 1
|
208
292
|
(1..by_rank.size-1).each do |i|
|
209
293
|
p1 = by_rank[i-1]
|
210
294
|
p2 = by_rank[i]
|
211
|
-
|
295
|
+
raise "player #{p1.num} with #{p1.points} points is ranked above player #{p2.num} with #{p2.points} points" if p1.points < p2.points
|
212
296
|
end
|
213
297
|
end
|
214
|
-
|
215
|
-
true
|
216
|
-
end
|
217
|
-
|
218
|
-
# Rerank the tournament.
|
219
|
-
def rerank
|
220
|
-
@player.values.map{ |p| [p, p.points] }.sort do |a,b|
|
221
|
-
d = b[1] <=> a[1]
|
222
|
-
d = a[0].last_name <=> b[0].last_name if d == 0
|
223
|
-
d = a[0].first_name <=> b[0].first_name if d == 0
|
224
|
-
d
|
225
|
-
end.each_with_index do |v,i|
|
226
|
-
v[0].rank = i + 1
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
# Raise an exception if a tournament is not valid.
|
231
|
-
def validate!
|
232
|
-
error = invalid
|
233
|
-
raise error if error
|
234
|
-
end
|
235
|
-
|
236
|
-
# Is a tournament invalid? Either returns false (if it's valid) or an error message.
|
237
|
-
# Covers all the ways a tournament can be invalid not already enforced by the setters.
|
238
|
-
def invalid
|
239
|
-
# There must be at least two players.
|
240
|
-
return "number of players (#{@player.size}) must be at least 2" if @player.size < 2
|
241
|
-
|
242
|
-
# Every player must have at least one result.
|
243
|
-
@player.each { |num, p| return "player #{num} has no results" if p.results.size == 0 }
|
244
|
-
|
245
|
-
# The ranking should be consistent, with the proviso that no ranking at all is allowed.
|
246
|
-
return "ranking is not consistent" unless ranking_consistent?(:allow_none => true)
|
247
|
-
|
248
|
-
# If there is a start date and an end date, the start should not come after the end.
|
249
|
-
return "start date (#{start}) is after end date (#{finish})" if start && finish && start > finish
|
250
298
|
end
|
251
299
|
end
|
252
300
|
end
|
data/lib/tournament_krause.rb
CHANGED
@@ -149,11 +149,12 @@ The following lists Krause data identification numbers, their description and, w
|
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
152
|
-
#
|
153
|
-
|
152
|
+
# Certain attributes are mandatory and should have been specifically set.
|
153
|
+
raise "tournament name missing" unless @name_set
|
154
|
+
raise "tournament start date missing" unless @start_set
|
154
155
|
|
155
|
-
# Finally, exercise the tournament object's
|
156
|
-
@tournament.validate!
|
156
|
+
# Finally, exercise the tournament object's internal validation, reranking if neccessary.
|
157
|
+
@tournament.validate!(:rerank => true)
|
157
158
|
|
158
159
|
@tournament
|
159
160
|
end
|
@@ -239,21 +240,6 @@ The following lists Krause data identification numbers, their description and, w
|
|
239
240
|
@comments << @line
|
240
241
|
@comments << "\n"
|
241
242
|
end
|
242
|
-
|
243
|
-
def finish_up
|
244
|
-
# Certain attributes are mandatory and should have been specifically set.
|
245
|
-
raise "tournament name missing" unless @name_set
|
246
|
-
raise "tournament start date missing" unless @start_set
|
247
|
-
|
248
|
-
# Set the number of rounds.
|
249
|
-
@tournament.rounds = @tournament.players.inject(0) do |pa, p|
|
250
|
-
pm = p.results.inject(0){ |ra, r| ra < r.round ? r.round : ra }
|
251
|
-
pa < pm ? pm : pa
|
252
|
-
end
|
253
|
-
|
254
|
-
# Rerank the tournament if there are no ranking values or if there are, but they're not consistent.
|
255
|
-
@tournament.rerank unless @tournament.ranking_consistent?
|
256
|
-
end
|
257
243
|
end
|
258
244
|
end
|
259
245
|
|
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.3.
|
4
|
+
version: 0.3.4
|
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-
|
12
|
+
date: 2009-05-09 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|