sanichi-chess_icu 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|