class ICU::Tournament::SPExport
The SWissPerfect export format used to be important in Irish chess as it was used to submit results to the ICU’s first computerised ratings system, a MicroSoft Access database. As a text based format, it was easier to manipulate than the full binary formats of SwissPerfect
. Here is an illustrative example of this format:
No Name Feder Intl Id Loc Id Rtg Loc Title Total 1 2 3 1 Duck, Daffy IRL 12345 2200 im 2 0:= 3:W 2:D 2 Mouse, Minerva 1234568 1900 1.5 3:D 0:= 1:D 3 Mouse, Mickey USA 1234567 gm 1 2:D 1:L 0:=
The format does not record either the name nor the start date of the tournament. Player
colours are also missing. When parsing data in this format it is necessary to specify name and start date explicitly:
parser = ICU::Tournament::SPExport.new tournament = parser.parse_file('sample.txt', :name => 'Mickey Mouse Masters', :start => '2011-02-06') tournament.name # => "Mickey Mouse Masters" tournament.start # => "2011-02-06" tournament.rounds # => 3 tournament.player(1).name # => "Duck, Daffy" tournament.player(2).points # => 1.5 tournament.player(3).fed # => "USA"
See ICU::Tournament
for further details about the object returned.
The SwissPerfect
application offers a number of choices when exporting a tournament cross table, one of which is the column separator. The ICU::Tournament::SPExport
parser can only handle data with tab separators but is able to cope with any other configuration choices. For example, if some of the optional columns are missing or if the data is not formatted with space padding.
To serialize an ICU::Tournament
instance to the format, use the serialize method of the appropriate parser:
parser = ICU::Tournament::Krause.new spexport = parser.serialize(tournament)
or use the serialize method of the instance with the appropraie format name:
spexport = tournament.serialize('SPExport')
In either case the method returns a string representation of the tourament in SwissPerfect
export format with tab separators, space padding and (by default) all the available information about the players. To customize what is displayed, use the only option and supply an array of symbols or strings to specify which columns to include. For example:
spexport = tournament.serialize('SPExport', :only => [:id, :points]) No Name Loc Id Total 1 2 3 1 Griffiths, Ryan-Rhys 6897 3 4:W 2:W 3:W 2 Flynn, Jamie 5226 2 3:W 1:L 4:W 3 Hulleman, Leon 6409 1 2:L 4:W 1:L 4 Dunne, Thomas 10914 0 1:L 3:L 2:L
The optional attribute names, together with their column header names in SwissPerfect
, are as follows: fed (Feder), fide_id (Intl Id), id (Loc Id), fide_rating (Rtg), rating (Loc), title (Title), points: (Total). To omitt the optional columns completely, supply an empty array of column names:
tournament.serialize('SPExport', :only => []) No Name 1 2 3 1 Griffiths, Ryan-Rhys 4:W 2:W 3:W 2 Flynn, Jamie 3:W 1:L 4:W 3 Hulleman, Leon 2:L 4:W 1:L 4 Dunne, Thomas 1:L 3:L 2:L
Or supply whatever columns you want, for example:
tournament.serialize('SPExport', :only => %w{fide_id fide_rating})
Or to omitt rather than include, use the logically opposite except option:
tournament.serialize('SPExport', :except => [:fide_id, :fide_rating])
Note that the column order in the serialised string is the same as it is in the SwissPerfect
application. The order of column names in the only option has no effect.
The default, when you leave out the only or except options, is equivalent to both of the following:
tournament.serialize('SPExport', :only => %w{fed fide_id id fide_rating rating title points}) tournament.serialize('SPExport', :except => [])
The order of players in the serialized output is always by player number and as a side effect of serialization, the player numbers will be adjusted to ensure they range from 1 to the total number of players, maintaining the original order. If you would prefer rank-order instead, then you must first renumber the players by rank before serializing. For example:
spexport = tournament.renumber(:rank).serialize('SPExport')
Or equivalently, since renumbering by rank is the default, just:
spexport = tournament.renumber.serialize('SPExport')
You may wish to set the tie-break rules before ranking:
tournament.tie_breaks = [:buchholz, :neustadtl] spexport = tournament.rerank.renumber.serialize('SwissPerfect')
See ICU::Tournament
for more about tie-breaks.
Constants
- COLUMNS
- KEY2NAM
- NAM2KEY
Attributes
Public Instance Methods
Parse SwissPerfect
export text returning a Tournament
on success or a nil on failure. In the case of failure, an error message can be retrived via the error method.
# File lib/icu_tournament/tournament_spx.rb, line 164 def parse(spx, arg={}) begin parse!(spx, arg) rescue => ex @error = ex.message nil end end
Parse SwissPerfect
export data returning a Tournament
on success or raising an exception on error.
# File lib/icu_tournament/tournament_spx.rb, line 126 def parse!(spx, arg={}) @tournament = init_tournament(arg) @lineno = 0 @header = nil @results = Array.new spx = ICU::Util::String.to_utf8(spx) unless arg[:is_utf8] # Process each line. spx.each_line do |line| @lineno += 1 line.strip! # remove leading and trailing white space next if line == '' # skip blank lines if @header process_player(line) else process_header(line) end end # Now that all players are present, add the results to the tournament. @results.each do |r| lineno, player, data, result = r begin @tournament.add_result(result) rescue => err raise "line #{lineno}, player #{player}, result '#{data}': #{err.message}" end end # Finally, exercise the tournament object's internal validation, reranking if neccessary. @tournament.validate!(:rerank => true) @tournament end
Same as parse except the input is a file name rather than file contents.
# File lib/icu_tournament/tournament_spx.rb, line 181 def parse_file(file, arg={}) begin parse_file!(file, arg) rescue => ex @error = ex.message nil end end
Same as parse! except the input is a file name rather than file contents.
# File lib/icu_tournament/tournament_spx.rb, line 174 def parse_file!(file, arg={}) spx = ICU::Util::File.read_utf8(file) arg[:is_utf8] = true parse!(spx, arg) end
Serialise a tournament to SwissPerfect
text export format.
# File lib/icu_tournament/tournament_spx.rb, line 191 def serialize(t, arg={}) t.validate!(:type => self) # Ensure a nice set of player numbers and get the number of rounds. t.renumber(:order) rounds = t.last_round # Optional columns. defaults = COLUMNS.map(&:first) case when arg[:except].instance_of?(Array) optional = (Set.new(defaults) - arg[:except].map!(&:to_s).map!(&:to_sym)).to_a when arg[:only].instance_of?(Array) optional = arg[:only].map!(&:to_s).map!(&:to_sym) else optional = defaults end optional = optional.inject({}) { |m, a| m[a] = true; m } # Columns identifiers in SwissPerfect order. columns = Array.new columns.push(:num) columns.push(:name) defaults.each { |x| columns.push(x) if optional[x] && x != :num && x != :name } # Widths and formats for each column. width = Hash.new format = Hash.new columns.each do |col| width[col] = t.players.inject(KEY2NAM[col].length) { |l, p| p.send(col).to_s.length > l ? p.send(col).to_s.length : l } format[col] = "%-#{width[col]}s" end # The header, followed by a blank line. formats = columns.map{ |col| format[col] } (1..rounds).each { |r| formats << "%#{width[:num]}d " % r } sp = formats.join("\t") % columns.map{ |col| KEY2NAM[col] } sp << "\r\n\r\n" # The round formats for players are slightly different to those for the header. formats.pop(rounds) (1..rounds).each{ |r| formats << "%#{2+width[:num]}s" } # Serialize the formats already. formats = formats.join("\t") + "\r\n" # Now add a line for each player. t.players.each { |p| sp << p.to_sp_text(rounds, columns, formats) } # And return the whole lot. sp end
Additional tournament validation rules for this specific type.
# File lib/icu_tournament/tournament_spx.rb, line 245 def validate!(t) # None. end