icu_tournament 1.1.2 → 1.2.0
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/README.rdoc +3 -8
- data/lib/icu_tournament.rb +4 -1
- data/lib/icu_tournament/federation.rb +66 -72
- data/lib/icu_tournament/player.rb +97 -103
- data/lib/icu_tournament/result.rb +82 -89
- data/lib/icu_tournament/team.rb +45 -52
- data/lib/icu_tournament/tournament.rb +153 -163
- data/lib/icu_tournament/tournament_fcsv.rb +123 -129
- data/lib/icu_tournament/tournament_krause.rb +107 -113
- data/lib/icu_tournament/tournament_sp.rb +93 -99
- data/lib/icu_tournament/util.rb +22 -41
- data/lib/icu_tournament/version.rb +3 -1
- metadata +23 -26
- data/lib/icu_tournament/name.rb +0 -274
- data/spec/name_spec.rb +0 -208
data/README.rdoc
CHANGED
|
@@ -5,15 +5,12 @@ For reading or writing files of chess tournament data. Original project name on
|
|
|
5
5
|
|
|
6
6
|
== Install
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
For ruby 1.9.2 (version 1.1.2 was the last compatible with ruby 1.8.7).
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
gem install icu_tournament
|
|
11
11
|
|
|
12
|
+
For name canonicalisation, _icu_name_ is required.
|
|
12
13
|
For handling SwissPerfect files the _dbf_, _inifile_ and _rubyzip_ gems are required.
|
|
13
|
-
For Ruby prior to version 1.9 the _fastercsv_ gem is needed to handle CSV files.
|
|
14
|
-
|
|
15
|
-
Tested with ruby 1.8.7, 1.9.2.
|
|
16
|
-
|
|
17
14
|
|
|
18
15
|
== Usage
|
|
19
16
|
|
|
@@ -31,7 +28,6 @@ The currently supported formats are:
|
|
|
31
28
|
* ICU::Tournament::ForeignCSV - used by Irish players to report their individual results in foreign tournaments.
|
|
32
29
|
* ICU::Tournament::SwissPerfect - often used by Irish tournament controllers to report results.
|
|
33
30
|
|
|
34
|
-
|
|
35
31
|
== Writing Files
|
|
36
32
|
|
|
37
33
|
Here's how the 1972 Fischer-Spassky match could be formatted to Krause. First a tournament object is created
|
|
@@ -60,7 +56,6 @@ Then finally, to create the file:
|
|
|
60
56
|
|
|
61
57
|
open('match.txt', 'w') { |f| f.puts @t.serialize('Krause') }
|
|
62
58
|
|
|
63
|
-
|
|
64
59
|
== Reading Files
|
|
65
60
|
|
|
66
61
|
Suppose you have a tournament file in Krause format. Parse it into a tournament object like this:
|
data/lib/icu_tournament.rb
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# :enddoc:
|
|
2
2
|
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'icu_name'
|
|
5
|
+
|
|
3
6
|
icu_tournament_files = Array.new
|
|
4
|
-
icu_tournament_files.concat %w{util
|
|
7
|
+
icu_tournament_files.concat %w{util federation}
|
|
5
8
|
icu_tournament_files.concat %w{player result team tournament}
|
|
6
9
|
icu_tournament_files.concat %w{fcsv krause sp}.map{ |f| "tournament_#{f}"}
|
|
7
10
|
|
|
@@ -1,73 +1,67 @@
|
|
|
1
1
|
module ICU
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
fed.
|
|
21
|
-
|
|
22
|
-
If the string is
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
ICU::Federation.find('
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
ICU::Federation.find('
|
|
39
|
-
|
|
40
|
-
The method
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
ICU::Federation.menu(:
|
|
54
|
-
|
|
55
|
-
To
|
|
56
|
-
|
|
57
|
-
ICU::Federation.menu(:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
ICU::Federation.menu(:none => 'None') # => [['None', ''], ['Afghanistan', 'AFG], ...]
|
|
62
|
-
|
|
63
|
-
The "None" option's code is the empty string and it come above the "top" option if both are specified.
|
|
64
|
-
|
|
65
|
-
=end
|
|
66
|
-
|
|
2
|
+
#
|
|
3
|
+
# This class can be used to map a string into an object representing a chess federation.
|
|
4
|
+
# In FIDE, chess federations are generally either referred to by their full names such as
|
|
5
|
+
# _Ireland_ or _Russia_ or by three letter codes such as _IRL_ or _RUS_. The three letter
|
|
6
|
+
# codes are mostly the same as those found in the international standard known as
|
|
7
|
+
# {ISO 3166-1 alpha-3}[http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3], but with
|
|
8
|
+
# some differences (e.g. for England, Scotland and Wales).
|
|
9
|
+
#
|
|
10
|
+
# You cannot directly create instances of this class using _new_. Instead, you supply
|
|
11
|
+
# a string to the class method _find_ and, if the string supplied uniguely identifies a
|
|
12
|
+
# federation, an instance is returned which responds to _name_ and _code_.
|
|
13
|
+
#
|
|
14
|
+
# fed = ICU::Federation.find('IRL')
|
|
15
|
+
# fed.name # => "Ireland"
|
|
16
|
+
# fed.code # => "IRL"
|
|
17
|
+
#
|
|
18
|
+
# If the string is not sufficient to identify a federation, the _find_ method returns _nil_.
|
|
19
|
+
#
|
|
20
|
+
# fed = ICU::Federation.find('ZYX') # => nil
|
|
21
|
+
#
|
|
22
|
+
# If the string is three letters long and matches (case insenstively) one of the unique
|
|
23
|
+
# federation codes, then the instance corresponding to that federation is returned.
|
|
24
|
+
#
|
|
25
|
+
# ICU::Federation.find('rUs').code # => "RUS"
|
|
26
|
+
#
|
|
27
|
+
# If the string is more than three letters long and if it is a substring (case insensitive)
|
|
28
|
+
# of exactly one federation name, then that federation is returned.
|
|
29
|
+
#
|
|
30
|
+
# ICU::Federation.find('ongoli').name # => "Mongolia"
|
|
31
|
+
#
|
|
32
|
+
# In all other cases, nil is returned. In the following example, the string matches more than one federation.
|
|
33
|
+
#
|
|
34
|
+
# ICU::Federation.find('land') # => nil
|
|
35
|
+
#
|
|
36
|
+
# The method is not fooled by irrelevant white space.
|
|
37
|
+
#
|
|
38
|
+
# ICU::Federation.find(' united states ').code # => 'USA'
|
|
39
|
+
#
|
|
40
|
+
# The class method _menu_ will return an array of two-element arrays each of which contain a name
|
|
41
|
+
# and a code.
|
|
42
|
+
#
|
|
43
|
+
# ICU::Federation.menu # => [['Afghanistan', 'AFG'], ['Albania', 'ALB], ...]
|
|
44
|
+
#
|
|
45
|
+
# Such an array could be used, for example, as the basis of a selection menu in a web application.
|
|
46
|
+
# Various options are available to alter the array returned. Use the _:order_ option to order by code
|
|
47
|
+
# instead of the default (by country name).
|
|
48
|
+
#
|
|
49
|
+
# ICU::Federation.menu(:order => 'code') # => [..., ['Ireland', 'IRL'], ['Iraq', 'IRQ], ...]
|
|
50
|
+
#
|
|
51
|
+
# To put one country at the top (followed by the rest, in order) supply the country's code with the _:top_ option:
|
|
52
|
+
#
|
|
53
|
+
# ICU::Federation.menu(:top => 'IRL') # => [['Ireland', 'IRL'], ['Afghanistan', 'AFG], ...]
|
|
54
|
+
#
|
|
55
|
+
# To supply an extra "None" item at the top, specify its label with the _:none_ option:
|
|
56
|
+
#
|
|
57
|
+
# ICU::Federation.menu(:none => 'None') # => [['None', ''], ['Afghanistan', 'AFG], ...]
|
|
58
|
+
#
|
|
59
|
+
# The "None" option's code is the empty string and it come above the "top" option if both are specified.
|
|
60
|
+
#
|
|
67
61
|
class Federation
|
|
68
62
|
attr_reader :code, :name
|
|
69
63
|
private_class_method :new
|
|
70
|
-
|
|
64
|
+
|
|
71
65
|
# Given a code, name or part of a name, return the corresponding federation instance.
|
|
72
66
|
# If there is no match or more than one match, _nil_ is returned.
|
|
73
67
|
def self.find(str=nil)
|
|
@@ -86,7 +80,7 @@ The "None" option's code is the empty string and it come above the "top" option
|
|
|
86
80
|
return nil unless matches.length == 1
|
|
87
81
|
matches[0]
|
|
88
82
|
end
|
|
89
|
-
|
|
83
|
+
|
|
90
84
|
def self.menu(opts = {})
|
|
91
85
|
compile unless @@objects;
|
|
92
86
|
top, menu = nil, []
|
|
@@ -96,14 +90,14 @@ The "None" option's code is the empty string and it come above the "top" option
|
|
|
96
90
|
menu.unshift([opts[:none], '']) if opts[:none]
|
|
97
91
|
menu
|
|
98
92
|
end
|
|
99
|
-
|
|
93
|
+
|
|
100
94
|
def initialize(code, name) # :nodoc: because new is private
|
|
101
95
|
@code = code
|
|
102
96
|
@name = name
|
|
103
97
|
end
|
|
104
|
-
|
|
98
|
+
|
|
105
99
|
private
|
|
106
|
-
|
|
100
|
+
|
|
107
101
|
def self.compile
|
|
108
102
|
return if @@objects
|
|
109
103
|
@@names = Hash.new
|
|
@@ -118,10 +112,10 @@ The "None" option's code is the empty string and it come above the "top" option
|
|
|
118
112
|
end
|
|
119
113
|
end
|
|
120
114
|
end
|
|
121
|
-
|
|
115
|
+
|
|
122
116
|
# The data structures compiled.
|
|
123
117
|
@@objects, @@codes, @@names = nil, nil, nil
|
|
124
|
-
|
|
118
|
+
|
|
125
119
|
# An array of data that gets compiled into other data structures.
|
|
126
120
|
@@data =
|
|
127
121
|
[
|
|
@@ -1,100 +1,94 @@
|
|
|
1
1
|
module ICU
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
bobby
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
john1
|
|
54
|
-
john2
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
mark1
|
|
64
|
-
mark2
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
fox1.fed # => 'IRL'
|
|
85
|
-
fox1.gender # => 'M'
|
|
86
|
-
|
|
87
|
-
=end
|
|
88
|
-
|
|
2
|
+
#
|
|
3
|
+
# A player in a tournament must have a first name, a last name and a number
|
|
4
|
+
# which is unique in the tournament but otherwise arbitary.
|
|
5
|
+
#
|
|
6
|
+
# bobby = ICU::Player.new('robert j', 'fischer', 17)
|
|
7
|
+
#
|
|
8
|
+
# Names are automatically cannonicalised (tidied up).
|
|
9
|
+
#
|
|
10
|
+
# bobby.first_name # => 'Robert J.'
|
|
11
|
+
# bobby.last_name # => 'Fischer'
|
|
12
|
+
#
|
|
13
|
+
# In addition, players have a number of optional attributes which can be specified
|
|
14
|
+
# via setters or in constructor hash options: _id_ (local or national ID), _fide_
|
|
15
|
+
# (FIDE ID), _fed_ (federation), _title_, _rating_, _rank_ and _dob_ (date of birth).
|
|
16
|
+
#
|
|
17
|
+
# peter = ICU::Player.new('Peter', 'Svidler', 21, :fed => 'rus', :title => 'g', :rating = 2700)
|
|
18
|
+
# peter.dob = '17th June, 1976'
|
|
19
|
+
# peter.rank = 1
|
|
20
|
+
#
|
|
21
|
+
# Some of these values will also be canonicalised to some extent. For example,
|
|
22
|
+
# date of birth will be turned into _yyyy-mm-dd_ format, the chess title will be two
|
|
23
|
+
# to three capital letters always ending in _M_ and the federation, if it's three
|
|
24
|
+
# letters long, will be upcased.
|
|
25
|
+
#
|
|
26
|
+
# peter.dob # => 1976-07-17
|
|
27
|
+
# peter.title # => 'GM'
|
|
28
|
+
# peter.fed # => 'RUS'
|
|
29
|
+
#
|
|
30
|
+
# It is preferable to add results (ICU::Result) to a player via the tournament (ICU::Tournament) object's
|
|
31
|
+
# _add_result_ method rather than the method of the same name belonging to player instances. Doing so
|
|
32
|
+
# allows mirrored results to be added to both players with one call (e.g. one player won, so the
|
|
33
|
+
# other lost). A player's results can later be retieved via the _results_ accessor.
|
|
34
|
+
#
|
|
35
|
+
# Total scores is available via the _points_ method.
|
|
36
|
+
#
|
|
37
|
+
# peter.points # => 5.5
|
|
38
|
+
#
|
|
39
|
+
# A player can have up to two ID numbers (both positive integers or nil): _id_ (local or national ID,
|
|
40
|
+
# such as ICU number) and _fide_ (FIDE ID).
|
|
41
|
+
#
|
|
42
|
+
# peter.id = 16790 # ICU
|
|
43
|
+
# peter.fide = 4102142 # FIDE
|
|
44
|
+
#
|
|
45
|
+
# Players can be compared to see if they're roughly or exactly the same, which may be useful in detecting duplicates.
|
|
46
|
+
# If the names match and the federations don't disagree then two players are equal according to the _==_ operator.
|
|
47
|
+
# The player number is irrelevant.
|
|
48
|
+
#
|
|
49
|
+
# john1 = ICU::Player.new('John', 'Smith', 12)
|
|
50
|
+
# john2 = ICU::Player.new('John', 'Smith', 22, :fed = 'IRL')
|
|
51
|
+
# john2 = ICU::Player.new('John', 'Smith', 32, :fed = 'ENG')
|
|
52
|
+
#
|
|
53
|
+
# john1 == john2 # => true (federations don't disagree because one is unset)
|
|
54
|
+
# john2 == john3 # => false (federations disagree)
|
|
55
|
+
#
|
|
56
|
+
# If, in addition, _rating_, _dob_, _gender_, _id_ and _fide_ do not disagree then two players are equal
|
|
57
|
+
# according to the stricter criteria of _eql?_.
|
|
58
|
+
#
|
|
59
|
+
# mark1 = ICU::Player.new('Mark', 'Orr', 31, :fed = 'IRL', :rating => 2100)
|
|
60
|
+
# mark2 = ICU::Player.new('Mark', 'Orr', 33, :fed = 'IRL', :rating => 2100, :title => 'IM')
|
|
61
|
+
# mark3 = ICU::Player.new('Mark', 'Orr', 37, :fed = 'IRL', :rating => 2200, :title => 'IM')
|
|
62
|
+
#
|
|
63
|
+
# mark1.eql?(mark2) # => true (ratings agree and titles don't disagree)
|
|
64
|
+
# mark2.eql?(mark3) # => false (the ratings are not the same)
|
|
65
|
+
#
|
|
66
|
+
# The presence of two players in the same tournament that are equal according to _==_ but unequal
|
|
67
|
+
# according to _eql?__ is likely to indicate a data entry error.
|
|
68
|
+
#
|
|
69
|
+
# If two instances represent the same player and are equal according to _==_ then the _id_, _fide_, _rating_,
|
|
70
|
+
# _title_ and _fed_ attributes of the two can be merged. For example:
|
|
71
|
+
#
|
|
72
|
+
# fox1 = ICU::Player.new('Tony', 'Fox', 12, :id => 456)
|
|
73
|
+
# fox2 = ICU::Player.new('Tony', 'Fox', 21, :rating => 2100, :fed => 'IRL', :gender => 'M')
|
|
74
|
+
# fox1.merge(fox2)
|
|
75
|
+
#
|
|
76
|
+
# Any attributes present in the second player but not in the first are copied to the first.
|
|
77
|
+
# All other attributes are unaffected.
|
|
78
|
+
#
|
|
79
|
+
# fox1.rating # => 2100
|
|
80
|
+
# fox1.fed # => 'IRL'
|
|
81
|
+
# fox1.gender # => 'M'
|
|
82
|
+
#
|
|
83
|
+
#
|
|
89
84
|
class Player
|
|
90
|
-
|
|
91
85
|
extend ICU::Accessor
|
|
92
86
|
attr_integer :num
|
|
93
87
|
attr_positive_or_nil :id, :fide, :rating, :rank
|
|
94
88
|
attr_date_or_nil :dob
|
|
95
|
-
|
|
89
|
+
|
|
96
90
|
attr_reader :results, :first_name, :last_name, :fed, :title, :gender
|
|
97
|
-
|
|
91
|
+
|
|
98
92
|
# Constructor. Must supply both names and a unique number for the tournament.
|
|
99
93
|
def initialize(first_name, last_name, num, opt={})
|
|
100
94
|
self.first_name = first_name
|
|
@@ -105,33 +99,33 @@ All other attributes are unaffected.
|
|
|
105
99
|
end
|
|
106
100
|
@results = []
|
|
107
101
|
end
|
|
108
|
-
|
|
102
|
+
|
|
109
103
|
# Canonicalise and set the first name(s).
|
|
110
104
|
def first_name=(first_name)
|
|
111
105
|
name = Name.new(first_name, 'Last')
|
|
112
106
|
raise "invalid first name" unless name.first.length > 0
|
|
113
107
|
@first_name = name.first
|
|
114
108
|
end
|
|
115
|
-
|
|
109
|
+
|
|
116
110
|
# Canonicalise and set the last name(s).
|
|
117
111
|
def last_name=(last_name)
|
|
118
112
|
name = Name.new('First', last_name)
|
|
119
113
|
raise "invalid last name" unless name.last.length > 0 && name.first.length > 0
|
|
120
114
|
@last_name = name.last
|
|
121
115
|
end
|
|
122
|
-
|
|
116
|
+
|
|
123
117
|
# Return the full name, last name first.
|
|
124
118
|
def name
|
|
125
119
|
"#{last_name}, #{first_name}"
|
|
126
120
|
end
|
|
127
|
-
|
|
121
|
+
|
|
128
122
|
# Federation. Is either unknown (nil) or a string containing at least three letters.
|
|
129
123
|
def fed=(fed)
|
|
130
124
|
obj = Federation.find(fed)
|
|
131
125
|
@fed = obj ? obj.code : nil
|
|
132
126
|
raise "invalid federation (#{fed})" if @fed.nil? && fed.to_s.strip.length > 0
|
|
133
127
|
end
|
|
134
|
-
|
|
128
|
+
|
|
135
129
|
# Chess title. Is either unknown (nil) or one of: _GM_, _IM_, _FM_, _CM_, _NM_,
|
|
136
130
|
# or any of these preceeded by the letter _W_.
|
|
137
131
|
def title=(title)
|
|
@@ -142,7 +136,7 @@ All other attributes are unaffected.
|
|
|
142
136
|
@title = nil if @title == ''
|
|
143
137
|
raise "invalid chess title (#{title})" unless @title.nil? || @title.match(/^W?[GIFCN]M$/)
|
|
144
138
|
end
|
|
145
|
-
|
|
139
|
+
|
|
146
140
|
# Gender. Is either unknown (nil) or one of _M_ or _F_.
|
|
147
141
|
def gender=(gender)
|
|
148
142
|
@gender = gender.to_s.strip[0,1].upcase
|
|
@@ -150,7 +144,7 @@ All other attributes are unaffected.
|
|
|
150
144
|
@gender = 'F' if @gender == 'W'
|
|
151
145
|
raise "invalid gender (#{gender})" unless @gender.nil? || @gender.match(/^[MF]$/)
|
|
152
146
|
end
|
|
153
|
-
|
|
147
|
+
|
|
154
148
|
# Add a result. Don't use this method directly - use ICU::Tournament#add_result instead.
|
|
155
149
|
def add_result(result)
|
|
156
150
|
raise "invalid result" unless result.class == ICU::Result
|
|
@@ -165,17 +159,17 @@ All other attributes are unaffected.
|
|
|
165
159
|
@results.insert(i, result)
|
|
166
160
|
end
|
|
167
161
|
end
|
|
168
|
-
|
|
162
|
+
|
|
169
163
|
# Lookup a result by round number.
|
|
170
164
|
def find_result(round)
|
|
171
165
|
@results.find { |r| r.round == round }
|
|
172
166
|
end
|
|
173
|
-
|
|
167
|
+
|
|
174
168
|
# Return the player's total points.
|
|
175
169
|
def points
|
|
176
170
|
@results.inject(0.0) { |t, r| t += r.points }
|
|
177
171
|
end
|
|
178
|
-
|
|
172
|
+
|
|
179
173
|
# Renumber the player according to the supplied hash. Return self.
|
|
180
174
|
def renumber(map)
|
|
181
175
|
raise "player number #{@num} not found in renumbering hash" unless map[@num]
|
|
@@ -183,7 +177,7 @@ All other attributes are unaffected.
|
|
|
183
177
|
@results.each{ |r| r.renumber(map) }
|
|
184
178
|
self
|
|
185
179
|
end
|
|
186
|
-
|
|
180
|
+
|
|
187
181
|
# Loose equality test. Passes if the names match and the federations are not different.
|
|
188
182
|
def ==(other)
|
|
189
183
|
return true if equal?(other)
|
|
@@ -193,7 +187,7 @@ All other attributes are unaffected.
|
|
|
193
187
|
return false if @fed && other.fed && @fed != other.fed
|
|
194
188
|
true
|
|
195
189
|
end
|
|
196
|
-
|
|
190
|
+
|
|
197
191
|
# Strict equality test. Passes if the playes are loosly equal and also if their IDs, rating, gender and title are not different.
|
|
198
192
|
def eql?(other)
|
|
199
193
|
return true if equal?(other)
|
|
@@ -203,7 +197,7 @@ All other attributes are unaffected.
|
|
|
203
197
|
end
|
|
204
198
|
true
|
|
205
199
|
end
|
|
206
|
-
|
|
200
|
+
|
|
207
201
|
# Merge in some of the details of another player.
|
|
208
202
|
def merge(other)
|
|
209
203
|
raise "cannot merge two players that are not equal" unless self == other
|