sanichi-chess_icu 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +2 -2
- data/lib/chess_icu.rb +1 -1
- data/lib/team.rb +81 -0
- data/lib/tournament.rb +35 -1
- data/lib/tournament_krause.rb +18 -2
- data/spec/team_spec.rb +50 -0
- data/spec/tournament_krause_spec.rb +3 -2
- data/spec/tournament_spec.rb +52 -0
- metadata +5 -2
data/VERSION.yml
CHANGED
data/lib/chess_icu.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
chess_icu_files = Array.new
|
4
4
|
chess_icu_files.concat %w{util name federation}
|
5
|
-
chess_icu_files.concat %w{player result tournament}
|
5
|
+
chess_icu_files.concat %w{player result team tournament}
|
6
6
|
chess_icu_files.concat %w{fcsv krause}.map{ |f| "tournament_#{f}"}
|
7
7
|
|
8
8
|
dir = File.dirname(__FILE__)
|
data/lib/team.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
module ICU
|
2
|
+
|
3
|
+
=begin rdoc
|
4
|
+
|
5
|
+
== Team
|
6
|
+
|
7
|
+
A team consists of a name and one or more players referenced by numbers.
|
8
|
+
Typically the team will be attached to a tournament (ICU::Tournament)
|
9
|
+
and the numbers will the unique numbers by which the players in that
|
10
|
+
tournament are referenced. To instantiate a team, you must supply a
|
11
|
+
name.
|
12
|
+
|
13
|
+
team = ICU::Team.new('Wandering Dragons')
|
14
|
+
|
15
|
+
Then you simply add player's (numbers) to it.
|
16
|
+
|
17
|
+
team.add_player(1)
|
18
|
+
team.add_payeer(3)
|
19
|
+
team.add_player(7)
|
20
|
+
|
21
|
+
To get the current members of a team
|
22
|
+
|
23
|
+
team.members # => [1, 3, 7]
|
24
|
+
|
25
|
+
You can enquire whether a team contains a given player number.
|
26
|
+
|
27
|
+
team.contains?(3) # => true
|
28
|
+
team.contains?(4) # => false
|
29
|
+
|
30
|
+
Or whether it matches a given name (which ignoring case and removing spurious whitespace)
|
31
|
+
|
32
|
+
team.matches(' wandering dragons ') # => true
|
33
|
+
team.matches('Blundering Bishops') # => false
|
34
|
+
|
35
|
+
Whenever you reset the name of a tournament spurious whitespace is removed but case is not altered.
|
36
|
+
|
37
|
+
team.name = ' blundering bishops '
|
38
|
+
team.name # => "blundering bishops"
|
39
|
+
|
40
|
+
Attempting to add non-numbers or duplicate numbers as new team members results in an exception.
|
41
|
+
|
42
|
+
team.add(nil) # exception - not a number
|
43
|
+
team.add(3) # exception - already a member
|
44
|
+
|
45
|
+
=end
|
46
|
+
|
47
|
+
class Team
|
48
|
+
|
49
|
+
attr_reader :name, :members
|
50
|
+
|
51
|
+
# Constructor. Name must be supplied.
|
52
|
+
def initialize(name)
|
53
|
+
self.name = name
|
54
|
+
@members = Array.new
|
55
|
+
end
|
56
|
+
|
57
|
+
# Set name. Must not be blank.
|
58
|
+
def name=(name)
|
59
|
+
@name = name.strip.squeeze(' ')
|
60
|
+
raise "team can't be blank" if @name.length == 0
|
61
|
+
end
|
62
|
+
|
63
|
+
# Add a team member referenced by any integer.
|
64
|
+
def add_member(number)
|
65
|
+
pnum = number.to_i
|
66
|
+
raise "'#{number}' is not a valid as a team member player number" if pnum == 0 && !number.to_s.match(/^[^\d]*0/)
|
67
|
+
raise "can't add duplicate player number #{pnum} to team '#{@name}'" if @members.include?(pnum)
|
68
|
+
@members.push(pnum)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Detect if a member exists in a team.
|
72
|
+
def include?(number)
|
73
|
+
@members.include?(number)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Does the team name match the given string (ignoring case and spurious whitespace).
|
77
|
+
def matches(name)
|
78
|
+
self.name.downcase == name.strip.squeeze(' ').downcase
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/tournament.rb
CHANGED
@@ -64,7 +64,7 @@ Ranking is consistent if either no players have any rank or if all players have
|
|
64
64
|
=end
|
65
65
|
|
66
66
|
class Tournament
|
67
|
-
attr_reader :name, :rounds, :start, :finish, :round_dates, :site, :city, :fed, :type, :arbiter, :deputy, :time_control
|
67
|
+
attr_reader :name, :rounds, :start, :finish, :round_dates, :site, :city, :fed, :type, :arbiter, :deputy, :time_control, :teams
|
68
68
|
|
69
69
|
# Constructor. Name and start date must be supplied. Other attributes are optional.
|
70
70
|
def initialize(name, start, opt={})
|
@@ -72,6 +72,7 @@ Ranking is consistent if either no players have any rank or if all players have
|
|
72
72
|
self.start = start
|
73
73
|
[:finish, :rounds, :site, :city, :fed, :type, :arbiter, :deputy, :time_control].each { |a| self.send("#{a}=", opt[a]) unless opt[a].nil? }
|
74
74
|
@player = {}
|
75
|
+
@teams = []
|
75
76
|
@round_dates = []
|
76
77
|
end
|
77
78
|
|
@@ -178,6 +179,20 @@ Ranking is consistent if either no players have any rank or if all players have
|
|
178
179
|
raise "invalid tournament time control (#{time_control})" unless @time_control.nil? || @time_control.match(/[1-9]\d/)
|
179
180
|
end
|
180
181
|
|
182
|
+
# Add a new team. The argument is either a team (possibly already with members) or the name of a new team.
|
183
|
+
# The team's name must be unique in the tournament. Returns the the team instance.
|
184
|
+
def add_team(team)
|
185
|
+
team = Team.new(team.to_s) unless team.is_a? Team
|
186
|
+
raise "a team with a name similar to '#{team.name}' already exists" if self.get_team(team.name)
|
187
|
+
@teams << team
|
188
|
+
team
|
189
|
+
end
|
190
|
+
|
191
|
+
# Return the team object that matches a given name, or nil if not found.
|
192
|
+
def get_team(name)
|
193
|
+
@teams.find{ |t| t.matches(name) }
|
194
|
+
end
|
195
|
+
|
181
196
|
# Add a new player to the tournament. Must have a unique player number.
|
182
197
|
def add_player(player)
|
183
198
|
raise "invalid player" unless player.class == ICU::Player
|
@@ -248,6 +263,7 @@ Ranking is consistent if either no players have any rank or if all players have
|
|
248
263
|
check_players
|
249
264
|
check_rounds
|
250
265
|
check_dates
|
266
|
+
check_teams
|
251
267
|
check_ranks(:allow_none => true)
|
252
268
|
true
|
253
269
|
end
|
@@ -290,6 +306,24 @@ Ranking is consistent if either no players have any rank or if all players have
|
|
290
306
|
@finish = @round_dates[-1] unless @finish
|
291
307
|
end
|
292
308
|
end
|
309
|
+
|
310
|
+
# Check teams. Either there are none or:
|
311
|
+
# * every team member is a valid player, and
|
312
|
+
# * every player is a member of exactly one team.
|
313
|
+
def check_teams
|
314
|
+
return if @teams.size == 0
|
315
|
+
member = Hash.new
|
316
|
+
@teams.each do |t|
|
317
|
+
t.members.each do |m|
|
318
|
+
raise "member #{m} of team '#{t.name}' is not a valid player number for this tournament" unless @player[m]
|
319
|
+
raise "member #{m} of team '#{t.name}' is already a member of team #{member[m]}" if member[m]
|
320
|
+
member[m] = t.name
|
321
|
+
end
|
322
|
+
end
|
323
|
+
@player.keys.each do |p|
|
324
|
+
raise "player #{p} is not a member of any team" unless member[p]
|
325
|
+
end
|
326
|
+
end
|
293
327
|
|
294
328
|
# Check if the players ranking is consistent, which will be true if:
|
295
329
|
# * every player has a rank
|
data/lib/tournament_krause.rb
CHANGED
@@ -65,7 +65,7 @@ The following lists Krause data identification numbers, their description and, w
|
|
65
65
|
|
66
66
|
[001 Player record] Use _players_ to get all players or _player_ with a player number to get a single instance.
|
67
67
|
[012 Name] Get or set with _name_. Free text. A tounament name is mandatory.
|
68
|
-
[013 Teams]
|
68
|
+
[013 Teams] Create an ICU::Team, add player numbers to it, use _add_team_ to add to tournament, _get_team_/_teams_ to retrive it/them.
|
69
69
|
[022 City] Get or set with _city_. Free text.
|
70
70
|
[032 Federation] Get or set with _fed_. Getter returns either _nil_ or a three letter code. Setter can take various formats (see ICU::Federation).
|
71
71
|
[042 Start date] Get or set with _start_. Getter returns <em>yyyy-mm-dd</em> format, but setter can use any reasonable date format. Start date is mandadory.
|
@@ -124,7 +124,7 @@ The following lists Krause data identification numbers, their description and, w
|
|
124
124
|
case din
|
125
125
|
when '001' then add_player # player and results record
|
126
126
|
when '012' then set_name # name (mandatory)
|
127
|
-
when '013' then
|
127
|
+
when '013' then add_team # team name and members
|
128
128
|
when '022' then @tournament.city = @data # city
|
129
129
|
when '032' then @tournament.fed = @data # federation
|
130
130
|
when '042' then set_start # start date (mandatory)
|
@@ -177,6 +177,11 @@ The following lists Krause data identification numbers, their description and, w
|
|
177
177
|
krause << "102 #{t.arbiter}\n" if t.arbiter
|
178
178
|
krause << "112 #{t.deputy}\n" if t.deputy
|
179
179
|
krause << "122 #{t.time_control}\n" if t.time_control
|
180
|
+
t.teams.each do |team|
|
181
|
+
krause << sprintf('013 %-31s', team.name)
|
182
|
+
team.members.each{ |m| krause << sprintf(' %4d', m) }
|
183
|
+
krause << "\n"
|
184
|
+
end
|
180
185
|
if t.round_dates.size > 0
|
181
186
|
krause << "132 #{' ' * 85}"
|
182
187
|
t.round_dates.each{ |d| krause << d.sub(/^../, ' ') }
|
@@ -246,6 +251,17 @@ The following lists Krause data identification numbers, their description and, w
|
|
246
251
|
result.points
|
247
252
|
end
|
248
253
|
|
254
|
+
def add_team
|
255
|
+
raise error "team record less than minimum length" if @line.length < 40
|
256
|
+
team = Team.new(@data[0, 31])
|
257
|
+
index = 32
|
258
|
+
while @data.length >= index + 4
|
259
|
+
team.add_member(@data[index, 4])
|
260
|
+
index+= 5
|
261
|
+
end
|
262
|
+
@tournament.add_team(team)
|
263
|
+
end
|
264
|
+
|
249
265
|
def add_round_dates
|
250
266
|
raise "round dates record less than minimum length" if @line.length < 99
|
251
267
|
index = 87
|
data/spec/team_spec.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module ICU
|
4
|
+
describe Team do
|
5
|
+
context "a typical team" do
|
6
|
+
before(:each) do
|
7
|
+
@t = Team.new('Wandering Dragons')
|
8
|
+
@t.add_member(0)
|
9
|
+
@t.add_member('3')
|
10
|
+
@t.add_member(' -7 ')
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have a name" do
|
14
|
+
@t.name.should == 'Wandering Dragons'
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have some members" do
|
18
|
+
@t.should have(3).members
|
19
|
+
@t.include?(0).should be_true
|
20
|
+
@t.include?(3).should be_true
|
21
|
+
@t.include?(-7).should be_true
|
22
|
+
@t.include?(7).should be_false
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should match names ignoring case and irrelevant whitespace" do
|
26
|
+
@t.matches('Wandering Dragons').should be_true
|
27
|
+
@t.matches(' wandering dragons ').should be_true
|
28
|
+
@t.matches(' wanderingdragons ').should be_false
|
29
|
+
@t.matches('Blundering Bishops').should be_false
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have a changeable name with irrelevant whitespace being trimmed" do
|
33
|
+
@t.name = ' blue dragons '
|
34
|
+
@t.name.should == 'blue dragons'
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should blowup if an attempt is made to blank the name" do
|
38
|
+
lambda { @t.name = ' ' }.should raise_error(/blank/)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should blowup if an attempt is made to add a non-number" do
|
42
|
+
lambda { @t.add_member(' ') }.should raise_error(/number/)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should blow up if an attempt is made to add a duplicate number" do
|
46
|
+
lambda { @t.add_member(3) }.should raise_error(/duplicate/)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -37,7 +37,7 @@ module ICU
|
|
37
37
|
102 Hans Scmidt
|
38
38
|
112 Gerry Graham, Herbert Scarry
|
39
39
|
122 60 in 2hr, 30 in 1hr, rest in 1hr
|
40
|
-
013 Coaching Team 1 2
|
40
|
+
013 Coaching Team 1 2 3
|
41
41
|
0 1 2 3 4 5 6 7 8 9 0 1 2
|
42
42
|
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
43
43
|
132 08.06.07 08.06.08 08.06.09
|
@@ -93,7 +93,6 @@ KRAUSE
|
|
93
93
|
062 3
|
94
94
|
072 3
|
95
95
|
082 1
|
96
|
-
013 Coaching Team 1 2
|
97
96
|
0 1 2 3 4 5 6 7 8 9 0 1 2
|
98
97
|
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
99
98
|
COMMENTS
|
@@ -162,6 +161,8 @@ KRAUSE
|
|
162
161
|
102 Hans Scmidt
|
163
162
|
112 Gerry Graham, Herbert Scarry
|
164
163
|
122 60 in 2hr, 30 in 1hr, rest in 1hr
|
164
|
+
013 Boys 2 3
|
165
|
+
013 Girls 1 4
|
165
166
|
132 08-06-07 08-06-08 08-06-09
|
166
167
|
001 1 w Ui Laighleis,Gearoidin 1985 IRL 2501171 1964-06-10 2.0 2 2 b 0 3 w + 4 b 1
|
167
168
|
001 2 m m Orr,Mark 2258 IRL 2500035 1955-11-09 2.5 1 1 w 1 0000 - = 3 b 1
|
data/spec/tournament_spec.rb
CHANGED
@@ -294,7 +294,32 @@ module ICU
|
|
294
294
|
@t.find_player(Player.new('John', 'Orr', 4, :fed => 'IRL')).should be_nil
|
295
295
|
end
|
296
296
|
end
|
297
|
+
|
298
|
+
context "teams" do
|
299
|
+
before(:each) do
|
300
|
+
@t = Tournament.new('Bangor Bash', '2009-11-09')
|
301
|
+
end
|
297
302
|
|
303
|
+
it "should be able to create a new team, add it and retrieve it" do
|
304
|
+
team = Team.new('Wandering Dragons')
|
305
|
+
@t.add_team(team).should be_an_instance_of Team
|
306
|
+
@t.get_team(' wandering dragons ').should be_an_instance_of Team
|
307
|
+
@t.get_team('Blundering Bishops').should be_nil
|
308
|
+
end
|
309
|
+
|
310
|
+
it "should be able to create and add a new team and retrieve it" do
|
311
|
+
@t.add_team('Blundering Bishops').should be_an_instance_of Team
|
312
|
+
@t.get_team(' blundering bishops ').should be_an_instance_of Team
|
313
|
+
@t.get_team('Wandering Dragons').should be_nil
|
314
|
+
end
|
315
|
+
|
316
|
+
it "should throw and exception if there is an attempt to add a team with a name that matches an existing team" do
|
317
|
+
lambda { @t.add_team('Blundering Bishops') }.should_not raise_error
|
318
|
+
lambda { @t.add_team('Wandering Dragons') }.should_not raise_error
|
319
|
+
lambda { @t.add_team(' wandering dragons ') }.should raise_error(/similar.*exists/)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
298
323
|
context "validation" do
|
299
324
|
before(:each) do
|
300
325
|
@t = Tournament.new('Edinburgh Masters', '2009-11-09')
|
@@ -364,6 +389,33 @@ module ICU
|
|
364
389
|
@t.player(3).rank = 3
|
365
390
|
lambda { @t.validate! }.should raise_error(/player 2.*above.*player 1/)
|
366
391
|
end
|
392
|
+
|
393
|
+
it "should be valid if there are teams, every player is in one of them, and no team has an invalid member" do
|
394
|
+
team1 = Team.new('International Masters')
|
395
|
+
team2 = Team.new('World Champions')
|
396
|
+
@t.add_team(team1)
|
397
|
+
@t.add_team(team2)
|
398
|
+
@t.invalid.should match(/not.*member/)
|
399
|
+
team1.add_member(1)
|
400
|
+
team2.add_member(2)
|
401
|
+
team2.add_member(3)
|
402
|
+
@t.invalid.should be_false
|
403
|
+
team1.add_member(4)
|
404
|
+
@t.invalid.should match(/not.*valid/)
|
405
|
+
end
|
406
|
+
|
407
|
+
it "should not be valid if one player is in more than one team" do
|
408
|
+
team1 = Team.new('XInternational Masters')
|
409
|
+
team1.add_member(1)
|
410
|
+
team2 = Team.new('XWorld Champions')
|
411
|
+
team2.add_member(2)
|
412
|
+
team2.add_member(3)
|
413
|
+
@t.add_team(team1)
|
414
|
+
@t.add_team(team2)
|
415
|
+
@t.invalid.should be_false
|
416
|
+
team1.add_member(2)
|
417
|
+
@t.invalid.should match(/already.*member/)
|
418
|
+
end
|
367
419
|
end
|
368
420
|
end
|
369
421
|
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
|
+
version: 0.4.0
|
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-10 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -42,6 +42,7 @@ files:
|
|
42
42
|
- lib/name.rb
|
43
43
|
- lib/player.rb
|
44
44
|
- lib/result.rb
|
45
|
+
- lib/team.rb
|
45
46
|
- lib/tournament.rb
|
46
47
|
- lib/tournament_fcsv.rb
|
47
48
|
- lib/tournament_krause.rb
|
@@ -51,6 +52,7 @@ files:
|
|
51
52
|
- spec/player_spec.rb
|
52
53
|
- spec/result_spec.rb
|
53
54
|
- spec/spec_helper.rb
|
55
|
+
- spec/team_spec.rb
|
54
56
|
- spec/tournament_fcsv_spec.rb
|
55
57
|
- spec/tournament_krause_spec.rb
|
56
58
|
- spec/tournament_spec.rb
|
@@ -87,6 +89,7 @@ test_files:
|
|
87
89
|
- spec/player_spec.rb
|
88
90
|
- spec/result_spec.rb
|
89
91
|
- spec/spec_helper.rb
|
92
|
+
- spec/team_spec.rb
|
90
93
|
- spec/tournament_fcsv_spec.rb
|
91
94
|
- spec/tournament_krause_spec.rb
|
92
95
|
- spec/tournament_spec.rb
|