| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# $Id: AGATourn.pm,v 1.35 2005/01/24 04:32:17 reid Exp $ |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# AGATourn |
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
# Copyright (C) 1999, 2004, 2005 Reid Augustin reid@netchip.com |
|
6
|
|
|
|
|
|
|
# 1000 San Mateo Dr. |
|
7
|
|
|
|
|
|
|
# Menlo Park, CA 94025 USA |
|
8
|
|
|
|
|
|
|
# |
|
9
|
|
|
|
|
|
|
# This library is free software; you can redistribute it and/or modify it |
|
10
|
|
|
|
|
|
|
# under the same terms as Perl itself, either Perl version 5.8.5 or, at your |
|
11
|
|
|
|
|
|
|
# option, any later version of Perl 5 you may have available. |
|
12
|
|
|
|
|
|
|
# |
|
13
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, but |
|
14
|
|
|
|
|
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
|
15
|
|
|
|
|
|
|
# or FITNESS FOR A PARTICULAR PURPOSE. |
|
16
|
|
|
|
|
|
|
# |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 NAME |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
AGATourn - Perl extensions to ease the pain of using AGA tournament data files. |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
use Games::Go::AGATourn; |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
my $agaTourn = Bnew> (options); |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
An AGATourn object represents a round or several rounds of an American Go |
|
31
|
|
|
|
|
|
|
Association tournament. There are methods for parsing several type of AGA |
|
32
|
|
|
|
|
|
|
file format: |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=over 4 |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=item tdlist |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
The entire list of AGA members including playing strength, club affiliation, |
|
39
|
|
|
|
|
|
|
and some other stuff. |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=item register.tde |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
The starting point for a tournament. All players in a tournament must be |
|
44
|
|
|
|
|
|
|
entered in the register.tde file. |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=item round results: 1.tde, 2.tde, etc. |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
Game results for each round of the tournament. |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=back |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
A note on IDs: in general, hashes in an AGATourn object are keyed by the AGA |
|
53
|
|
|
|
|
|
|
ID. An AGA ID consists of a three letter country specifier (like USA or TMP |
|
54
|
|
|
|
|
|
|
for temporary IDs) concatenated to an integer. Here we specify the three |
|
55
|
|
|
|
|
|
|
letter country specifier as the 'country' and the integer part as the |
|
56
|
|
|
|
|
|
|
'agaNum'. The country concatenated with the agaNum is the ID. My ID for |
|
57
|
|
|
|
|
|
|
example is USA2122. IDs should be normalized (capitalize the country part and |
|
58
|
|
|
|
|
|
|
remove preceding 0s from the agaNum part) with the B method |
|
59
|
|
|
|
|
|
|
(below). |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
Note also that some programs may accept limited integers in the agaNum part of |
|
62
|
|
|
|
|
|
|
the ID. Accelerat, for example, seems to accept only up to 32K (someone used |
|
63
|
|
|
|
|
|
|
a signed short somewhere?) |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=cut |
|
66
|
|
|
|
|
|
|
|
|
67
|
1
|
|
|
1
|
|
56906
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
63
|
|
|
68
|
|
|
|
|
|
|
require 5.001; |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
package Games::Go::AGATourn; |
|
71
|
1
|
|
|
1
|
|
7
|
use Carp; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
76
|
|
|
72
|
1
|
|
|
1
|
|
6
|
use IO::File; |
|
|
1
|
|
|
|
|
7
|
|
|
|
1
|
|
|
|
|
292
|
|
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# Items to export into callers namespace by default. Note: do not export |
|
77
|
|
|
|
|
|
|
# names by default without a very good reason. Use EXPORT_OK instead. |
|
78
|
|
|
|
|
|
|
# Do not simply export all your public functions/methods/constants. |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# This allows declaration use PackageName ':all'; |
|
81
|
|
|
|
|
|
|
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK |
|
82
|
|
|
|
|
|
|
# will save memory. |
|
83
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( 'all' => [ qw( |
|
84
|
|
|
|
|
|
|
) ] ); |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
our @EXPORT = qw( |
|
89
|
|
|
|
|
|
|
); |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
BEGIN { |
|
92
|
1
|
|
|
1
|
|
43
|
our $VERSION = sprintf "%d.%03d", '$Revision: 1.35 $' =~ /(\d+)/g; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
###################################################### |
|
96
|
|
|
|
|
|
|
# |
|
97
|
|
|
|
|
|
|
# Class Variables |
|
98
|
|
|
|
|
|
|
# |
|
99
|
|
|
|
|
|
|
##################################################### |
|
100
|
|
|
|
|
|
|
|
|
101
|
1
|
|
|
1
|
|
6
|
use constant NOTARANK => -99.9; # illegal rank or rating |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
13688
|
|
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
###################################################### |
|
104
|
|
|
|
|
|
|
# |
|
105
|
|
|
|
|
|
|
# Public methods |
|
106
|
|
|
|
|
|
|
# |
|
107
|
|
|
|
|
|
|
##################################################### |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=head1 METHODS |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=over 4 |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=item my $agaTourn = Bnew> (options) |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
A B AGATourn by default reads the B file to get the name, |
|
116
|
|
|
|
|
|
|
rank, and AGA numbers for all the players in the tournament. It then reads |
|
117
|
|
|
|
|
|
|
all available game results (B files: 1.tde, 2.tde, etc.) and the game |
|
118
|
|
|
|
|
|
|
data is incorporated into the AGATourn object. |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head2 Options: |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=over 4 |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=item B |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
Round file number to read. If B is 0, no round files are read. If |
|
127
|
|
|
|
|
|
|
B is 1 or greater, only the one round file will be read. If B |
|
128
|
|
|
|
|
|
|
is undef (or not specified), all existing round files are read. Round files |
|
129
|
|
|
|
|
|
|
should be named I<1.tde>, I<2.tde>, etc. |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
Default: undef |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=item B |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
Name of register.tde file. Use undef to prevent reading the register.tde |
|
136
|
|
|
|
|
|
|
file. Changing the name of this file is probably a bad idea. |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
Default 'register.tde' (in the current directory) |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=item B |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
Starting length of name field. While reading the register file (see |
|
143
|
|
|
|
|
|
|
B below), B grows to reflect the longest name |
|
144
|
|
|
|
|
|
|
seen so far (see B method below). |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
Default: 0 |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=item B |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
Default three-letter country name. |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
The tdlist file does not include country information in the ID, so the |
|
153
|
|
|
|
|
|
|
B method returns country => B. |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
Default: 'USA' |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=back |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=cut |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub new { |
|
162
|
2
|
|
|
2
|
1
|
29
|
my ($proto, %args) = @_; |
|
163
|
|
|
|
|
|
|
|
|
164
|
2
|
|
|
|
|
5
|
my $self = {}; |
|
165
|
2
|
|
33
|
|
|
18
|
bless($self, ref($proto) || $proto); |
|
166
|
2
|
|
|
|
|
13
|
$self->{defaultCountry} = 'USA'; |
|
167
|
2
|
|
|
|
|
10
|
$self->Clear; |
|
168
|
|
|
|
|
|
|
# transfer user args |
|
169
|
2
|
|
|
|
|
9
|
foreach (keys(%args)) { |
|
170
|
4
|
|
|
|
|
10
|
$self->{$_} = $args{$_}; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
2
|
100
|
|
|
|
9
|
if (defined($self->{register_tde})) { |
|
173
|
1
|
50
|
|
|
|
6
|
return(undef) unless($self->ReadRegisterFile($self->{register_tde})); |
|
174
|
|
|
|
|
|
|
} |
|
175
|
2
|
100
|
|
|
|
7
|
if (defined($self->{register_tde})) { |
|
176
|
1
|
50
|
|
|
|
4
|
if (defined($self->{Round})) { |
|
177
|
1
|
50
|
|
|
|
3
|
if ($self->{Round} > 0) { |
|
178
|
0
|
|
|
|
|
0
|
$self->ReadRoundFile("$self->{Round}.tde"); |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
} else { |
|
181
|
0
|
|
|
|
|
0
|
my $round = 1; |
|
182
|
0
|
|
|
|
|
0
|
while (-f "$round.tde") { |
|
183
|
0
|
|
|
|
|
0
|
$self->{Round} = $round; |
|
184
|
0
|
|
|
|
|
0
|
$self->ReadRoundFile("$self->{Round}.tde"); |
|
185
|
0
|
|
|
|
|
0
|
$round++; |
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
} |
|
189
|
2
|
|
|
|
|
11
|
return($self); |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=item $agaTourn-EB |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
Clears AGATourn database. |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=cut |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub Clear { |
|
199
|
2
|
|
|
2
|
1
|
4
|
my ($self) = @_; |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
# set defaults |
|
202
|
2
|
|
|
|
|
6
|
$self->{Round} = undef; |
|
203
|
2
|
|
|
|
|
3
|
$self->{register_tde} = "register.tde"; # default |
|
204
|
2
|
|
|
|
|
9
|
$self->{Directive}{ROUNDS}[0] = 1; # I hope there's at least one! |
|
205
|
2
|
|
|
|
|
6
|
$self->{Directive}{TOURNEY}[0] = "Unknown tournament"; |
|
206
|
2
|
|
|
|
|
7
|
$self->{nameLength} = 0; |
|
207
|
2
|
|
|
|
|
4
|
$self->{Name} = {}; # empty hash |
|
208
|
2
|
|
|
|
|
4
|
$self->{Rating} = {}; |
|
209
|
2
|
|
|
|
|
5
|
$self->{Rank} = {}; |
|
210
|
2
|
|
|
|
|
5
|
$self->{Comment} = {}; |
|
211
|
2
|
|
|
|
|
6
|
$self->{Wins} = {}; |
|
212
|
2
|
|
|
|
|
4
|
$self->{Losses} = {}; |
|
213
|
2
|
|
|
|
|
4
|
$self->{NoResults} = {}; |
|
214
|
2
|
|
|
|
|
4
|
$self->{Played} = {}; |
|
215
|
2
|
|
|
|
|
3
|
$self->{gameAllList} = []; # empty array |
|
216
|
2
|
|
|
|
|
5
|
$self->{error} = 0; |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=item my $hash = $agaTourn-EB ($line) |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Parses a single line from the TDLIST file (the latest TDLIST file |
|
222
|
|
|
|
|
|
|
should be downloaded from the AGA at http://usgo.org shortly before |
|
223
|
|
|
|
|
|
|
the tournament, and either the tab-delimited tdlista or the |
|
224
|
|
|
|
|
|
|
space-delimited versions are accepted). The return value is a |
|
225
|
|
|
|
|
|
|
reference to a hash of the following values: |
|
226
|
|
|
|
|
|
|
agaNum => the number part if the ID |
|
227
|
|
|
|
|
|
|
country => the country part of the ID (always the default |
|
228
|
|
|
|
|
|
|
country) |
|
229
|
|
|
|
|
|
|
name => complains if there is no a comma |
|
230
|
|
|
|
|
|
|
memType => membership type or '' if none |
|
231
|
|
|
|
|
|
|
agaRating => rating in decimal form, or '' if none |
|
232
|
|
|
|
|
|
|
agaRank => undef unless rating is a D/K style rank |
|
233
|
|
|
|
|
|
|
expire => date membership expires or '' if none |
|
234
|
|
|
|
|
|
|
club => club affiliation or '' if none |
|
235
|
|
|
|
|
|
|
state => state or '' if none |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
If the line is not parsable, prints a warning and returns undef. |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=cut |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# sadly, we need to deal with two formats |
|
242
|
|
|
|
|
|
|
# old tdlist input looks like this: |
|
243
|
|
|
|
|
|
|
# name AGA# MmbrTyp Rank expires Club State |
|
244
|
|
|
|
|
|
|
#Abe, Shozo 2443 L 8603 NJ |
|
245
|
|
|
|
|
|
|
#Abe, Y. 2043 8312 GA |
|
246
|
|
|
|
|
|
|
#Abell, John 3605 -1.4 9105 MHGA CO |
|
247
|
|
|
|
|
|
|
#Abrahms, Judy 1253 L 8012 MGA MA |
|
248
|
|
|
|
|
|
|
#Abrams, Michael 6779 L -27.4 9411 MIAM FL |
|
249
|
|
|
|
|
|
|
#Abramson, Allan 101 3.5 9504 NOVA VA |
|
250
|
|
|
|
|
|
|
# the new format is like this: |
|
251
|
|
|
|
|
|
|
#Abe, Shozo 2443 Limit 03/28/1986 NJ |
|
252
|
|
|
|
|
|
|
#Abe, Y. 2043 Full 12/28/1983 GA |
|
253
|
|
|
|
|
|
|
#Abell, John 3605 Full -1.4 05/28/1991 MHGA CO |
|
254
|
|
|
|
|
|
|
#Abrahms, Judy 1253 Limit 12/28/1980 MGA MA |
|
255
|
|
|
|
|
|
|
# |
|
256
|
|
|
|
|
|
|
# There's also a tab-delimited version |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub ParseTdListLine { |
|
259
|
1
|
|
|
1
|
1
|
3
|
my ($self, $string) = @_; |
|
260
|
|
|
|
|
|
|
|
|
261
|
1
|
|
|
|
|
18
|
$string =~ s/[\n\r]*$/\t/s; # remove crlf, and tack on an extra tab |
|
262
|
1
|
|
|
|
|
6
|
my @fields = $string =~ m/(.*?)\t/g; # is it the tab-delimited version? |
|
263
|
1
|
50
|
|
|
|
5
|
if (@fields == 9) { |
|
264
|
|
|
|
|
|
|
return { |
|
265
|
0
|
|
|
|
|
0
|
name => $fields[0], # return ref to hash |
|
266
|
|
|
|
|
|
|
agaNum => $fields[1], |
|
267
|
|
|
|
|
|
|
memType => $fields[2], |
|
268
|
|
|
|
|
|
|
agaRating => $fields[3], |
|
269
|
|
|
|
|
|
|
expire => $fields[4], |
|
270
|
|
|
|
|
|
|
club => $fields[5], |
|
271
|
|
|
|
|
|
|
state => $fields[6], |
|
272
|
|
|
|
|
|
|
sigma => $fields[7], |
|
273
|
|
|
|
|
|
|
ratingDate => $fields[8], |
|
274
|
|
|
|
|
|
|
country => $self->{defaultCountry}, |
|
275
|
|
|
|
|
|
|
}; |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
# else parse a space-delimited version: |
|
278
|
1
|
|
|
|
|
2
|
my ($name, $agaNum, $agaRank, $misc); |
|
279
|
1
|
|
|
|
|
4
|
my ($agaRating, $memType, $club, $state, $expire) = (-99, '', '', '', ''); |
|
280
|
|
|
|
|
|
|
|
|
281
|
1
|
50
|
|
|
|
11
|
unless($string =~ m/^\s*(.*?)\s*(\d+) (.*)/) { # break into manageble groups |
|
282
|
0
|
|
|
|
|
0
|
carp("Error: can't extract AGA number from \"$string\"\n"); |
|
283
|
0
|
|
|
|
|
0
|
return(undef); |
|
284
|
|
|
|
|
|
|
} |
|
285
|
1
|
|
|
|
|
3
|
$name = $1; # part before is name |
|
286
|
1
|
|
|
|
|
3
|
$agaNum = $2; # middle part is the AGA number |
|
287
|
1
|
|
|
|
|
3
|
$misc = $3; # part after match |
|
288
|
1
|
50
|
|
|
|
11
|
if ($misc =~ m/([\w ]{6}?) ([-\d\. ]{5}) ([\d\/ ]{10}) ([\w ]{4}) (.*?)\s*$/) { |
|
289
|
|
|
|
|
|
|
# parse by character positions (blanks lined up in the right places) |
|
290
|
0
|
|
|
|
|
0
|
$memType = _ws_clean($1); |
|
291
|
0
|
|
|
|
|
0
|
$agaRating = _ws_clean($2); |
|
292
|
0
|
|
|
|
|
0
|
$expire = _ws_clean($3); |
|
293
|
0
|
|
|
|
|
0
|
$club = _ws_clean($4); |
|
294
|
0
|
|
|
|
|
0
|
$state = _ws_clean($5); |
|
295
|
0
|
0
|
|
|
|
0
|
if ($agaRating =~ m/(\d+)([dk])/i) { |
|
296
|
0
|
|
|
|
|
0
|
$agaRank = uc($agaRating); |
|
297
|
0
|
|
|
|
|
0
|
$agaRating = $1 + 0.5; |
|
298
|
0
|
0
|
|
|
|
0
|
$agaRating = -$agaRating if (uc($2) eq 'K'); |
|
299
|
|
|
|
|
|
|
} |
|
300
|
|
|
|
|
|
|
} else { # try to parse free-form style |
|
301
|
1
|
50
|
|
|
|
9
|
if ($misc =~ s/^\s*([^\s\d-]+) //) { # membership type, if any |
|
|
|
0
|
|
|
|
|
|
|
302
|
1
|
|
|
|
|
3
|
$memType = $1; |
|
303
|
|
|
|
|
|
|
} elsif (not $misc =~ s/^ //) { |
|
304
|
0
|
|
|
|
|
0
|
carp("Uh oh, no membership type space in: '$misc'"); |
|
305
|
|
|
|
|
|
|
} |
|
306
|
1
|
50
|
|
|
|
8
|
if ($misc =~ s/^\s*(-?\d+\.\d) //) { # find rank, if any |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
307
|
1
|
|
|
|
|
3
|
$agaRating = $1; |
|
308
|
|
|
|
|
|
|
} elsif ($misc =~ s/^\s*(\d+)([dkDK]) //) { # 4D or 15k type rank |
|
309
|
0
|
|
|
|
|
0
|
$agaRank = uc("$1$2"); |
|
310
|
0
|
|
|
|
|
0
|
$agaRating = $1 + 0.5; |
|
311
|
0
|
0
|
|
|
|
0
|
$agaRating = -$agaRating if (uc($2) eq 'K'); |
|
312
|
|
|
|
|
|
|
} elsif ($misc =~ s/^\s*(-?\d\d?) //) { # one or two digit number, no decimal point? |
|
313
|
0
|
|
|
|
|
0
|
$agaRating = $1; # it's another way of indicating rank |
|
314
|
|
|
|
|
|
|
} elsif (not $misc =~ s/^ //) { |
|
315
|
0
|
|
|
|
|
0
|
carp("Uh oh, no rating space in: '$misc'"); |
|
316
|
|
|
|
|
|
|
} |
|
317
|
1
|
50
|
|
|
|
6
|
if ($misc =~ s/^\s*([\d\/]+) //) { # expiration date, if any |
|
|
|
0
|
|
|
|
|
|
|
318
|
1
|
|
|
|
|
3
|
$expire = $1; |
|
319
|
|
|
|
|
|
|
} elsif (not $misc =~ s/ //) { |
|
320
|
0
|
|
|
|
|
0
|
carp("Uh oh, no expire space in: '$misc'"); |
|
321
|
|
|
|
|
|
|
} |
|
322
|
1
|
50
|
33
|
|
|
5
|
unless(defined($expire) or defined($memType)) { |
|
323
|
0
|
|
|
|
|
0
|
carp "Uh oh"; |
|
324
|
|
|
|
|
|
|
} |
|
325
|
1
|
50
|
|
|
|
6
|
if ($misc =~ s/^(\w+)\s*//) { # club |
|
|
|
0
|
|
|
|
|
|
|
326
|
1
|
|
|
|
|
2
|
$club = $1; |
|
327
|
1
|
|
|
|
|
4
|
$club =~ s/\W//g; # remove all non-word chars |
|
328
|
|
|
|
|
|
|
} elsif (not $misc =~ s/ //) { |
|
329
|
0
|
|
|
|
|
0
|
carp("Uh oh, no expire space in: '$misc'"); |
|
330
|
|
|
|
|
|
|
} |
|
331
|
1
|
50
|
|
|
|
8
|
if ($misc =~ s/^\s*(.*?)\s*$//) { # state |
|
332
|
1
|
|
|
|
|
4
|
$state = $1; |
|
333
|
|
|
|
|
|
|
} |
|
334
|
1
|
50
|
|
|
|
4
|
if ($misc ne '') { |
|
335
|
0
|
|
|
|
|
0
|
carp("Error: \"$misc\" was left over after parsing \"$string\"\n", |
|
336
|
|
|
|
|
|
|
"name=$name, id=$agaNum, mem=$memType, rating=$agaRating, ", |
|
337
|
|
|
|
|
|
|
"expire=$expire, club=$club, state=$state\n"); |
|
338
|
|
|
|
|
|
|
} |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
return { |
|
341
|
1
|
|
|
|
|
22
|
agaNum => $agaNum, # return ref to hash |
|
342
|
|
|
|
|
|
|
country => $self->{defaultCountry}, |
|
343
|
|
|
|
|
|
|
name => $name, |
|
344
|
|
|
|
|
|
|
memType => $memType, |
|
345
|
|
|
|
|
|
|
agaRating => $agaRating, |
|
346
|
|
|
|
|
|
|
agaRank => $agaRank, |
|
347
|
|
|
|
|
|
|
expire => $expire, |
|
348
|
|
|
|
|
|
|
club => $club, |
|
349
|
|
|
|
|
|
|
state => $state, |
|
350
|
|
|
|
|
|
|
}; |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
sub _ws_clean { |
|
354
|
0
|
|
|
0
|
|
0
|
my $str = shift @_; |
|
355
|
0
|
|
|
|
|
0
|
$str =~ m/^\s*(.*?)\s*$/; |
|
356
|
0
|
|
|
|
|
0
|
return $1; |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=item my $result = $agaTourn-EB ($fileName) |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
Reads a register.tde file and calls B on each line of the file. |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
Returns 0 if $fileName couldn't be opened for reading, 1 otherwise. |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=cut |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
sub ReadRegisterFile { |
|
368
|
1
|
|
|
1
|
1
|
3
|
my ($self, $fName) = @_; |
|
369
|
|
|
|
|
|
|
|
|
370
|
1
|
|
|
|
|
5
|
$self->{fileName} = $fName; # set global name |
|
371
|
1
|
|
|
|
|
12
|
my $inFP = new IO::File("<$fName"); |
|
372
|
1
|
50
|
|
|
|
151
|
unless ($inFP) { |
|
373
|
0
|
|
|
|
|
0
|
carp("Error: can't open $fName for reading\n"), |
|
374
|
|
|
|
|
|
|
$self->{error} = 1, |
|
375
|
|
|
|
|
|
|
return(0); |
|
376
|
|
|
|
|
|
|
} |
|
377
|
1
|
|
|
|
|
132
|
while(my $line = <$inFP>) { |
|
378
|
17
|
|
|
|
|
36
|
$self->AddRegisterLine($line); |
|
379
|
|
|
|
|
|
|
} |
|
380
|
1
|
|
|
|
|
13
|
$inFP->close(); |
|
381
|
1
|
|
|
|
|
30
|
return(1); |
|
382
|
|
|
|
|
|
|
} |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=item $agaTourn-EB ($line) |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
Calls B on $line. Information extracted about players and |
|
387
|
|
|
|
|
|
|
directives is added to the $agaTourn object. Comments and blank lines are |
|
388
|
|
|
|
|
|
|
ignored. |
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
=cut |
|
391
|
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub AddRegisterLine { |
|
393
|
17
|
|
|
17
|
1
|
27
|
my ($self, $line) = @_; |
|
394
|
|
|
|
|
|
|
|
|
395
|
17
|
50
|
33
|
|
|
104
|
my $fileMsg = (ref ($self) and exists ($self->{fileName})) ? |
|
396
|
|
|
|
|
|
|
" at line $. in $self->{fileName} " : |
|
397
|
|
|
|
|
|
|
''; |
|
398
|
17
|
|
|
|
|
35
|
my $h = $self->ParseRegisterLine($line); |
|
399
|
17
|
100
|
|
|
|
46
|
return unless(defined($h)); |
|
400
|
16
|
100
|
|
|
|
36
|
if (exists($h->{directive})) { |
|
401
|
9
|
|
|
|
|
16
|
foreach (qw(HANDICAPS ROUNDS RULES TOURNEY)) { # non-array directives |
|
402
|
30
|
100
|
|
|
|
78
|
if ($h->{directive} eq $_) { |
|
403
|
4
|
|
|
|
|
14
|
$self->{Directive}{$h->{directive}} = [$h->{value}]; # single value |
|
404
|
4
|
|
|
|
|
29
|
return; |
|
405
|
|
|
|
|
|
|
} |
|
406
|
|
|
|
|
|
|
} |
|
407
|
5
|
|
|
|
|
7
|
push(@{$self->{Directive}{$h->{directive}}}, $h->{value}); |
|
|
5
|
|
|
|
|
15
|
|
|
408
|
5
|
|
|
|
|
22
|
return; |
|
409
|
|
|
|
|
|
|
} |
|
410
|
7
|
100
|
|
|
|
25
|
return unless(exists($h->{agaNum})); # probably a comment |
|
411
|
4
|
|
|
|
|
9
|
my $id = "$h->{country}$h->{agaNum}"; |
|
412
|
4
|
50
|
|
|
|
11
|
if (defined($self->{Name}{$id})) { |
|
413
|
0
|
|
|
|
|
0
|
carp("Error: Player ID $id is duplicated$fileMsg\n"); |
|
414
|
0
|
|
|
|
|
0
|
$self->{error} = 1; |
|
415
|
|
|
|
|
|
|
} |
|
416
|
4
|
|
|
|
|
16
|
$self->{Name}{$id} = $h->{name}; |
|
417
|
4
|
|
|
|
|
8
|
$self->{Rating}{$id} = $h->{agaRating}; |
|
418
|
4
|
|
|
|
|
8
|
$self->{Rank}{$id} = $h->{agaRank}; |
|
419
|
4
|
|
|
|
|
138
|
$self->{Comment}{$id} = $h->{comment}; |
|
420
|
4
|
|
|
|
|
10
|
$self->{Club}{$id} = $h->{club}; |
|
421
|
4
|
|
|
|
|
10
|
$self->{Flags}{$id} = $h->{flags}; |
|
422
|
4
|
50
|
|
|
|
16
|
$self->{Played}{$id} = [] unless exists($self->{Played}{$id}); |
|
423
|
4
|
|
|
|
|
10
|
foreach (qw(Wins Losses NoResults)) { |
|
424
|
12
|
50
|
|
|
|
41
|
$self->{$_}{$id} = 0 unless exists($self->{$_}{$id}); |
|
425
|
|
|
|
|
|
|
} |
|
426
|
4
|
|
|
|
|
9
|
my $len = length($h->{name}); |
|
427
|
4
|
100
|
|
|
|
31
|
$self->{nameLength} = $len if ($len > $self->{nameLength}); |
|
428
|
|
|
|
|
|
|
} |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=item my $hash = $agaTourn-EB ($line) |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
Parses a single line from the register.tde file (name lines). Here are some |
|
433
|
|
|
|
|
|
|
examples lines from register.tde file: |
|
434
|
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
# this line is a comment. the following line is a directive: |
|
436
|
|
|
|
|
|
|
## HANDICAPS MAX |
|
437
|
|
|
|
|
|
|
# the following line is a name line: |
|
438
|
|
|
|
|
|
|
USA02122 Augustin, Reid 5.0 CLUB=PALO # 12/31/2004 CA |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
The return value is a reference to a hash of the following values: |
|
441
|
|
|
|
|
|
|
agaNum => just the number part of the ID |
|
442
|
|
|
|
|
|
|
country => just the country part of the ID (default ='USA') |
|
443
|
|
|
|
|
|
|
name => complains if name doesn't contain a comma |
|
444
|
|
|
|
|
|
|
agaRating => rating for the player |
|
445
|
|
|
|
|
|
|
agaRank => undef if line contains a rating and not a rank |
|
446
|
|
|
|
|
|
|
club => if there is a club association, '' if not |
|
447
|
|
|
|
|
|
|
flags => anything left over (excluding comment) |
|
448
|
|
|
|
|
|
|
comment => everything after the #, '' if none |
|
449
|
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
If the line is a directive, the return hash reference contains only: |
|
451
|
|
|
|
|
|
|
directive => the directive name |
|
452
|
|
|
|
|
|
|
value => the directive value ('' if none) |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
If the line is a comment, leading and trailing whitespace is removed and the |
|
455
|
|
|
|
|
|
|
hash contains only: |
|
456
|
|
|
|
|
|
|
comment => comment contents (may be '') |
|
457
|
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
If the line is empty, returns undef. |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
If the line is not parsable, prints a warning and returns undef. |
|
461
|
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
=cut |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
sub ParseRegisterLine { |
|
465
|
18
|
|
|
18
|
1
|
30
|
my ($self, $line) = @_; |
|
466
|
|
|
|
|
|
|
|
|
467
|
18
|
|
|
|
|
134
|
$line =~ s/\s*$//s; # delete trailing spaces |
|
468
|
18
|
100
|
|
|
|
45
|
return undef if ($line eq ''); # nothing left? return undef |
|
469
|
|
|
|
|
|
|
|
|
470
|
17
|
100
|
|
|
|
57
|
if ($line =~ s/^\s*##\s*//) { |
|
471
|
9
|
|
|
|
|
40
|
$line =~ m/(\S+)\s*(.*?)\s*$/; |
|
472
|
|
|
|
|
|
|
return { |
|
473
|
9
|
|
|
|
|
39
|
directive => $1, |
|
474
|
|
|
|
|
|
|
value => $2 |
|
475
|
|
|
|
|
|
|
}; |
|
476
|
|
|
|
|
|
|
} |
|
477
|
8
|
|
|
|
|
11
|
my $comment = ''; |
|
478
|
8
|
50
|
|
|
|
73
|
if ($line =~ s/\s*#\s*(.*?)\s*$//) { |
|
479
|
8
|
|
|
|
|
18
|
$comment = $1; |
|
480
|
|
|
|
|
|
|
} |
|
481
|
8
|
100
|
|
|
|
19
|
if ($line eq '') { |
|
482
|
|
|
|
|
|
|
return { |
|
483
|
3
|
|
|
|
|
8
|
comment => $comment, |
|
484
|
|
|
|
|
|
|
}; |
|
485
|
|
|
|
|
|
|
} |
|
486
|
|
|
|
|
|
|
|
|
487
|
5
|
50
|
33
|
|
|
39
|
my $fileMsg = (ref ($self) and exists ($self->{fileName})) ? |
|
488
|
|
|
|
|
|
|
" at line $. in $self->{fileName} " : |
|
489
|
|
|
|
|
|
|
''; |
|
490
|
5
|
|
|
|
|
7
|
my $club = ''; |
|
491
|
5
|
50
|
|
|
|
53
|
if ($line =~ s/\s*CLUB=(\S*)\s*//) { |
|
492
|
5
|
|
|
|
|
8
|
$club = $1; |
|
493
|
5
|
|
|
|
|
10
|
$club =~ s/\W//g; # remove all non-word chars |
|
494
|
|
|
|
|
|
|
} |
|
495
|
5
|
|
|
|
|
18
|
my ($agaRating, $agaRank); |
|
496
|
5
|
100
|
|
|
|
89
|
if($line =~ s/^\s*(\S*)\s+(.*?)\s+(\d+[dDkK])\s*//) { # look for dan or kyu rank |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
497
|
2
|
|
|
|
|
4
|
$agaRank = $3; |
|
498
|
2
|
|
|
|
|
7
|
$agaRating = $self->RankToRating($3); |
|
499
|
|
|
|
|
|
|
} elsif($line =~ s/^\s*(\S*)\s+(.*?)\s+(-*\d+\.\d+)\s*//) { # look for 5.4 or -13.6 type of rank |
|
500
|
3
|
|
|
|
|
9
|
$agaRating = $3; # ok as is |
|
501
|
|
|
|
|
|
|
} elsif($line =~ s/^\s*(\S*)\s+(.*?)\s+(-*\d+)\s*//) { # look for 5 or -13 type of rank |
|
502
|
0
|
|
|
|
|
0
|
carp("Warning: rank is non-decimalized:\n$line\n"); |
|
503
|
0
|
|
|
|
|
0
|
$agaRating = "$3.0"; |
|
504
|
|
|
|
|
|
|
} else { |
|
505
|
0
|
|
|
|
|
0
|
carp("Error: Can't parse name$fileMsg:\n$line\n"); |
|
506
|
0
|
|
|
|
|
0
|
$self->{error} = 1; |
|
507
|
0
|
|
|
|
|
0
|
return; |
|
508
|
|
|
|
|
|
|
} |
|
509
|
|
|
|
|
|
|
|
|
510
|
5
|
|
|
|
|
11
|
my $name = $2; |
|
511
|
5
|
|
|
|
|
23
|
my $agaNum = $self->NormalizeID($1); |
|
512
|
5
|
|
|
|
|
11
|
my $country = $self->{defaultCountry}; |
|
513
|
5
|
50
|
|
|
|
25
|
if ($agaNum =~ s/^(\D+)//) { |
|
514
|
5
|
|
|
|
|
10
|
$country = uc($1); |
|
515
|
|
|
|
|
|
|
} |
|
516
|
5
|
50
|
|
|
|
18
|
unless ($name =~ m/,/) { |
|
517
|
0
|
|
|
|
|
0
|
carp("Warning: no comma in name \"$name\"$fileMsg\n"); |
|
518
|
|
|
|
|
|
|
} |
|
519
|
|
|
|
|
|
|
return { # return ref to hash of: |
|
520
|
5
|
|
|
|
|
51
|
agaNum => $agaNum, |
|
521
|
|
|
|
|
|
|
name => $name, |
|
522
|
|
|
|
|
|
|
agaRating => $agaRating, |
|
523
|
|
|
|
|
|
|
agaRank => $agaRank, |
|
524
|
|
|
|
|
|
|
club => $club, |
|
525
|
|
|
|
|
|
|
country => $country, |
|
526
|
|
|
|
|
|
|
flags => $line, # whatever's left over |
|
527
|
|
|
|
|
|
|
comment => $comment, |
|
528
|
|
|
|
|
|
|
}; |
|
529
|
|
|
|
|
|
|
} |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=item my $result = $agaTourn-EB ($fileName) |
|
532
|
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
Reads a round file and calls B on each line of the file. |
|
534
|
|
|
|
|
|
|
Complains if filename is not in the form I<1.tde>, I<2.tde>, etc. |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
Sets the current B number to the digit part of fileName. |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
Returns 0 if fileName couldn't be opened for reading, 1 otherwise. |
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
=cut |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
sub ReadRoundFile { |
|
543
|
1
|
|
|
1
|
1
|
3
|
my ($self, $fName) = @_; |
|
544
|
|
|
|
|
|
|
|
|
545
|
1
|
50
|
|
|
|
9
|
if ($fName =~ m/^\d+$/) { # no TDE extension? |
|
546
|
0
|
|
|
|
|
0
|
$fName .= '.tde'; |
|
547
|
|
|
|
|
|
|
} |
|
548
|
1
|
|
|
|
|
4
|
$self->{fileName} = $fName; # set global name |
|
549
|
1
|
50
|
|
|
|
8
|
if ($fName =~ m/(\d+).tde/) { |
|
550
|
1
|
|
|
|
|
5
|
$self->{Round} = $1; |
|
551
|
|
|
|
|
|
|
} else { |
|
552
|
0
|
|
|
|
|
0
|
carp "Round filename not in normal ('1.tde', '2.tde', etc) format\n"; |
|
553
|
|
|
|
|
|
|
} |
|
554
|
1
|
|
|
|
|
11
|
my $inFP = new IO::File("<$fName"); |
|
555
|
1
|
50
|
|
|
|
144
|
unless ($inFP) { |
|
556
|
0
|
|
|
|
|
0
|
carp("Error: can't open $fName for reading\n"); |
|
557
|
0
|
|
|
|
|
0
|
$self->{error} = 1; |
|
558
|
0
|
|
|
|
|
0
|
return(0); |
|
559
|
|
|
|
|
|
|
} |
|
560
|
1
|
|
|
|
|
31
|
while (my $line = <$inFP>) { |
|
561
|
4
|
|
|
|
|
12
|
$self->AddRoundLine($line); |
|
562
|
|
|
|
|
|
|
} |
|
563
|
1
|
|
|
|
|
8
|
$inFP->close(); |
|
564
|
1
|
|
|
|
|
28
|
return(1); |
|
565
|
|
|
|
|
|
|
} |
|
566
|
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
=item $agaTourn-EB ($line) |
|
568
|
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
Parses $line (by calling B) and adds the information to the |
|
570
|
|
|
|
|
|
|
B. Games without a result ('?') increment both players' NoResults |
|
571
|
|
|
|
|
|
|
list scores, and games with a result ('b' or 'w') increment the two players' |
|
572
|
|
|
|
|
|
|
Wins and Losses scores. If the game result is 'b' or 'w', the black player is |
|
573
|
|
|
|
|
|
|
added to the white player's B list and vica-versa. Note that |
|
574
|
|
|
|
|
|
|
B is not affected by games that are not complete. |
|
575
|
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
Complains if either player, or both, are not registered via |
|
577
|
|
|
|
|
|
|
B. |
|
578
|
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
=cut |
|
580
|
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
sub AddRoundLine { |
|
582
|
4
|
|
|
4
|
1
|
9
|
my ($self, $line) = @_; |
|
583
|
|
|
|
|
|
|
|
|
584
|
4
|
|
|
|
|
10
|
my $g = $self->ParseRoundLine($line); # get game result |
|
585
|
4
|
100
|
66
|
|
|
29
|
return unless(defined($g) and exists($g->{result})); |
|
586
|
2
|
|
|
|
|
11
|
my $wId = $self->NormalizeID("$g->{wcountry}$g->{wagaNum}"); |
|
587
|
2
|
|
|
|
|
8
|
my $bId = $self->NormalizeID("$g->{bcountry}$g->{bagaNum}"); |
|
588
|
2
|
50
|
|
|
|
8
|
carp("Game $wId.vs.$bId, $wId is not registered\n") unless (exists($self->{Rating}{$wId})); |
|
589
|
2
|
50
|
|
|
|
8
|
carp("Game $wId.vs.$bId, $bId is not registered\n") unless (exists($self->{Rating}{$bId})); |
|
590
|
2
|
|
|
|
|
5
|
foreach (qw(Wins Losses NoResults)) { |
|
591
|
6
|
50
|
|
|
|
14
|
$self->{$_}{$wId} = 0 unless exists($self->{$_}{$wId}); |
|
592
|
6
|
50
|
|
|
|
26
|
$self->{$_}{$bId} = 0 unless exists($self->{$_}{$bId}); |
|
593
|
|
|
|
|
|
|
} |
|
594
|
2
|
50
|
|
|
|
24
|
if ($g->{result} eq 'w') { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
595
|
0
|
|
|
|
|
0
|
$self->{Wins}{$wId}++; |
|
596
|
0
|
|
|
|
|
0
|
$self->{Losses}{$bId}++; |
|
597
|
0
|
|
|
|
|
0
|
push(@{$self->{Played}{$bId}}, $wId); |
|
|
0
|
|
|
|
|
0
|
|
|
598
|
0
|
|
|
|
|
0
|
push(@{$self->{Played}{$wId}}, $bId); |
|
|
0
|
|
|
|
|
0
|
|
|
599
|
|
|
|
|
|
|
} elsif ($g->{result} eq 'b') { |
|
600
|
1
|
|
|
|
|
3
|
$self->{Wins}{$bId}++; |
|
601
|
1
|
|
|
|
|
3
|
$self->{Losses}{$wId}++; |
|
602
|
1
|
|
|
|
|
3
|
push(@{$self->{Played}{$bId}}, $wId); |
|
|
1
|
|
|
|
|
4
|
|
|
603
|
1
|
|
|
|
|
2
|
push(@{$self->{Played}{$wId}}, $bId); |
|
|
1
|
|
|
|
|
3
|
|
|
604
|
|
|
|
|
|
|
} elsif ($g->{result} eq '?') { |
|
605
|
1
|
|
|
|
|
2
|
$self->{NoResults}{$bId}++; |
|
606
|
1
|
|
|
|
|
2
|
$self->{NoResults}{$wId}++; |
|
607
|
|
|
|
|
|
|
} else { |
|
608
|
0
|
|
|
|
|
0
|
carp("Unknown game result:$g->{result}"); # probably can't happen |
|
609
|
|
|
|
|
|
|
} |
|
610
|
2
|
|
|
|
|
10
|
my $game = "$wId,$bId,$g->{result},$g->{handi},$g->{komi},$self->{Round}"; |
|
611
|
2
|
|
|
|
|
3
|
push(@{$self->{gameAllList}}, $game); |
|
|
2
|
|
|
|
|
6
|
|
|
612
|
2
|
|
|
|
|
2
|
push(@{$self->{gameIDList}{$wId}}, $game); |
|
|
2
|
|
|
|
|
8
|
|
|
613
|
2
|
|
|
|
|
3
|
push(@{$self->{gameIDList}{$bId}}, $game); |
|
|
2
|
|
|
|
|
24
|
|
|
614
|
|
|
|
|
|
|
} |
|
615
|
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
=item my $hash = $agaTourn-EB ($line) |
|
617
|
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
Parses a single line from a results file (I<1.tde>, I<2.tde>, etc). Here's an |
|
619
|
|
|
|
|
|
|
example line from a results file: |
|
620
|
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
TMP18 TMP10 b 0 7 # Lee, Ken -28.5 : Yang, John -28.5 |
|
622
|
|
|
|
|
|
|
# wID bID result handi komi comment |
|
623
|
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
The return value is a reference to a hash of the following values: |
|
625
|
|
|
|
|
|
|
wcountry => combine with wagaNum to get complete ID |
|
626
|
|
|
|
|
|
|
wagaNum => the number part of white's AGA number |
|
627
|
|
|
|
|
|
|
bcountry => combine with bagaNum to get complete ID |
|
628
|
|
|
|
|
|
|
bagaNum => the number part of black's AGA number |
|
629
|
|
|
|
|
|
|
result => winner: 'b', 'w' or '?' |
|
630
|
|
|
|
|
|
|
handi => handicap game was played with |
|
631
|
|
|
|
|
|
|
komi => komi game was played with |
|
632
|
|
|
|
|
|
|
comment => everything after the # |
|
633
|
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
If $line is empty, returns undef. |
|
635
|
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
If $line is a comment, returns only: |
|
637
|
|
|
|
|
|
|
comment => everything after the # |
|
638
|
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
If the line is not parsable, prints a warning and returns undef. |
|
640
|
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
=cut |
|
642
|
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
sub ParseRoundLine { |
|
644
|
4
|
|
|
4
|
1
|
7
|
my ($self, $line) = @_; |
|
645
|
|
|
|
|
|
|
|
|
646
|
4
|
|
|
|
|
39
|
$line =~ s/\s*$//s; # delete trailing spaces |
|
647
|
4
|
50
|
|
|
|
15
|
return undef if ($line eq ''); # nothing left? return undef |
|
648
|
|
|
|
|
|
|
|
|
649
|
4
|
100
|
|
|
|
19
|
if ($line =~ s/^\s*##\s*//) { |
|
650
|
2
|
|
|
|
|
6
|
$line =~ m/(\S+)\s*(.*?)\s*/; |
|
651
|
|
|
|
|
|
|
return { |
|
652
|
2
|
|
|
|
|
11
|
directive => $1, |
|
653
|
|
|
|
|
|
|
value => $2 |
|
654
|
|
|
|
|
|
|
}; |
|
655
|
|
|
|
|
|
|
} |
|
656
|
2
|
|
|
|
|
4
|
my $comment = ''; |
|
657
|
2
|
50
|
|
|
|
24
|
if ($line =~ s/\s*#\s*(.*?)\s*$//) { |
|
658
|
2
|
|
|
|
|
7
|
$comment = $1; |
|
659
|
|
|
|
|
|
|
} |
|
660
|
2
|
50
|
|
|
|
5
|
if ($line eq '') { |
|
661
|
|
|
|
|
|
|
return { |
|
662
|
0
|
|
|
|
|
0
|
comment => $comment, |
|
663
|
|
|
|
|
|
|
}; |
|
664
|
|
|
|
|
|
|
} |
|
665
|
|
|
|
|
|
|
|
|
666
|
2
|
50
|
|
|
|
15
|
if ($line =~ m/^\s*(\w+)(\d+)\s+(\w+)(\d+)\s+([bwBW\?])\s+(\d+)\s+(-?\d+)$/) { |
|
667
|
|
|
|
|
|
|
return { |
|
668
|
2
|
|
|
|
|
47
|
wcountry => uc($1), |
|
669
|
|
|
|
|
|
|
wagaNum => $2, |
|
670
|
|
|
|
|
|
|
bcountry => uc($3), |
|
671
|
|
|
|
|
|
|
bagaNum => $4, |
|
672
|
|
|
|
|
|
|
result => lc($5), |
|
673
|
|
|
|
|
|
|
handi => $6, |
|
674
|
|
|
|
|
|
|
komi => $7, |
|
675
|
|
|
|
|
|
|
comment => $comment, |
|
676
|
|
|
|
|
|
|
}; |
|
677
|
|
|
|
|
|
|
} |
|
678
|
0
|
0
|
0
|
|
|
0
|
my $fileMsg = (ref ($self) and exists ($self->{fileName})) ? |
|
679
|
|
|
|
|
|
|
" at line $. in $self->{fileName} " : |
|
680
|
|
|
|
|
|
|
''; |
|
681
|
0
|
|
|
|
|
0
|
carp("Can't parse round line $.$fileMsg:\n$line\n"); |
|
682
|
0
|
|
|
|
|
0
|
$self->{error} = 1; |
|
683
|
0
|
|
|
|
|
0
|
return undef; |
|
684
|
|
|
|
|
|
|
} |
|
685
|
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
=item my $tourney = $agaTourn-EB |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
Returns the name of the tournament from a ##TOURNEY directive added via |
|
689
|
|
|
|
|
|
|
B, or 'Unknown Tournament' if no TOURNEY directive has been |
|
690
|
|
|
|
|
|
|
added. |
|
691
|
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
=cut |
|
693
|
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
sub Tourney { |
|
695
|
2
|
|
|
2
|
1
|
4103
|
my ($self) = @_; |
|
696
|
2
|
|
|
|
|
17
|
return ($self->{Directive}{TOURNEY}[0]); # last TOURNEY directive |
|
697
|
|
|
|
|
|
|
} |
|
698
|
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
=item my $directive = $agaTourn-EB ($directive) |
|
700
|
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
Returns a list (or a reference to the list in scalar context) of directives |
|
702
|
|
|
|
|
|
|
added via calls to B. Directive names are always turned into |
|
703
|
|
|
|
|
|
|
upper case (but the case of the directive value, if any, is preserved). |
|
704
|
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
Since some directives (like BAND) may occur several times, all directives are |
|
706
|
|
|
|
|
|
|
stored as a list in the order added (either from B or |
|
707
|
|
|
|
|
|
|
B). Certain directives (HANDICAPS ROUNDS RULES TOURNEY) keep |
|
708
|
|
|
|
|
|
|
only the last directive added. |
|
709
|
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
Some directives have no associated value. |
|
711
|
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
B returns undef if $directive has not been added, or a list |
|
713
|
|
|
|
|
|
|
(possibly empty) if $directive has been added. |
|
714
|
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
If called with no arguments (or $directive is undef), returns a reference to a |
|
716
|
|
|
|
|
|
|
hash of all the current directives. |
|
717
|
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=cut |
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
sub Directive { |
|
721
|
2
|
|
|
2
|
1
|
7
|
my ($self, $directive) = @_; |
|
722
|
|
|
|
|
|
|
|
|
723
|
2
|
50
|
|
|
|
10
|
if (defined($directive)) { |
|
724
|
0
|
|
|
|
|
0
|
$directive = uc($directive); # force to upper case |
|
725
|
0
|
0
|
|
|
|
0
|
if (exists($self->{Directive}{$directive})) { |
|
726
|
0
|
0
|
|
|
|
0
|
return wantarray ? @{$self->{Directive}{$directive}} : $self->{Directive}{$directive}; |
|
|
0
|
|
|
|
|
0
|
|
|
727
|
|
|
|
|
|
|
} |
|
728
|
0
|
|
|
|
|
0
|
return(undef); |
|
729
|
|
|
|
|
|
|
} |
|
730
|
2
|
|
|
|
|
33
|
return($self->{Directive}); # the whole shebang... |
|
731
|
|
|
|
|
|
|
} |
|
732
|
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
=item my $rounds = $agaTourn-EB |
|
734
|
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
Returns the total number of rounds the $agaTourn object knows about. If there |
|
736
|
|
|
|
|
|
|
has been a ##ROUNDS directive in a call to B file, this will |
|
737
|
|
|
|
|
|
|
return that number. If not, it will return the number part of the last |
|
738
|
|
|
|
|
|
|
I.tde file read or undef. |
|
739
|
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
=cut |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
sub Rounds { |
|
743
|
2
|
|
|
2
|
1
|
6
|
my ($self) = @_; |
|
744
|
|
|
|
|
|
|
|
|
745
|
2
|
50
|
|
|
|
18
|
return $self->{Directive}{ROUNDS}[0] # fetch ROUNDS directive |
|
746
|
|
|
|
|
|
|
if(defined($self->{Directive}{ROUNDS}[0])); |
|
747
|
0
|
|
|
|
|
0
|
return($self->{Round}); |
|
748
|
|
|
|
|
|
|
} |
|
749
|
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
=item my $round = $agaTourn-EB |
|
751
|
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
Returns the number of the current round (based on the last I.tde |
|
753
|
|
|
|
|
|
|
file read). |
|
754
|
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
=cut |
|
756
|
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
sub Round { |
|
758
|
2
|
|
|
2
|
1
|
5
|
my ($self) = @_; |
|
759
|
2
|
|
|
|
|
10
|
return($self->{Round}); |
|
760
|
|
|
|
|
|
|
} |
|
761
|
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
=item my $name = $agaTourn-EB ($id) |
|
763
|
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
Returns the the name for $id. |
|
765
|
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
If $id is undef, returns a reference to the entire B hash (keyed by ID). |
|
767
|
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
=cut |
|
769
|
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
sub Name { |
|
771
|
2
|
|
|
2
|
1
|
5
|
my ($self, $id) = @_; |
|
772
|
|
|
|
|
|
|
|
|
773
|
2
|
50
|
|
|
|
9
|
return ($self->{Name}{$id}) if (defined($id)); |
|
774
|
2
|
|
|
|
|
24
|
return ($self->{Name}); |
|
775
|
|
|
|
|
|
|
} |
|
776
|
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
=item my $name_length = $agaTourn-EB |
|
778
|
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
Returns the length of the longest name. |
|
780
|
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=cut |
|
782
|
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
sub NameLength { |
|
784
|
2
|
|
|
2
|
1
|
6
|
my ($self) = @_; |
|
785
|
2
|
|
|
|
|
13
|
return ($self->{nameLength}); |
|
786
|
|
|
|
|
|
|
} |
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
=item my $rating = $agaTourn-EB ($id, $newRating) |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
Sets (if $newRating is defined) or returns the rating for $id. If $id is not |
|
791
|
|
|
|
|
|
|
defined, returns a reference to the entire B hash (keyed by IDs). |
|
792
|
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
$id can also be a rank ('4d', or '5k'), or a rating (4.2 or -5.3, but not |
|
794
|
|
|
|
|
|
|
between 1.0 and -1.0). This form is simply a converter - $newRating is not |
|
795
|
|
|
|
|
|
|
accepted. |
|
796
|
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
If $id is defined but not registered (via B), complains and |
|
798
|
|
|
|
|
|
|
returns undef. |
|
799
|
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
=cut |
|
801
|
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
sub Rating { |
|
803
|
2
|
|
|
2
|
1
|
6
|
my ($self, $id, $newRating) = @_; |
|
804
|
|
|
|
|
|
|
|
|
805
|
2
|
50
|
|
|
|
10
|
$self->{Rating}{$id} = $newRating if (defined($newRating)); |
|
806
|
2
|
50
|
|
|
|
43
|
if (defined($id)) { |
|
807
|
0
|
0
|
|
|
|
0
|
return ($self->{Rating}{$id}) if (exists($self->{Rating}{$id})); |
|
808
|
0
|
0
|
|
|
|
0
|
if ($id =~ m/^(-?\d+\.\d)\s*/) { # find rank |
|
809
|
0
|
|
|
|
|
0
|
return $1; # rating format |
|
810
|
|
|
|
|
|
|
} |
|
811
|
0
|
0
|
|
|
|
0
|
if ($id =~ m/^\s*(\d+)([dkDK])\b/) { # 4D or 15k type rank |
|
812
|
0
|
|
|
|
|
0
|
my $rating = $1; |
|
813
|
0
|
0
|
|
|
|
0
|
$rating = -$rating if (lc($2) eq 'k'); |
|
814
|
0
|
|
|
|
|
0
|
return $rating; |
|
815
|
|
|
|
|
|
|
} |
|
816
|
0
|
0
|
|
|
|
0
|
if ($id =~ m/^\s*(-?\d\d?)\b/) { # one or two digit number, no decimal point? |
|
817
|
0
|
|
|
|
|
0
|
return $1; # it's another way of indicating rank |
|
818
|
|
|
|
|
|
|
} |
|
819
|
0
|
|
|
|
|
0
|
carp ("Invalid Rating argument:$id\n"); |
|
820
|
0
|
|
|
|
|
0
|
return undef; # eh? |
|
821
|
|
|
|
|
|
|
} |
|
822
|
2
|
|
|
|
|
18
|
return ($self->{Rating}); |
|
823
|
|
|
|
|
|
|
} |
|
824
|
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
=item my $rank = $agaTourn-EB ($id) |
|
826
|
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
Returns the rank for $id. This field is undef unless the B |
|
828
|
|
|
|
|
|
|
contained a rank field of the form '4k' or '3d' as opposed to a rating of the |
|
829
|
|
|
|
|
|
|
form '-4.5' or '3.4'. |
|
830
|
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
If $id is not defined, returns a reference to the entire B hash (keyed |
|
832
|
|
|
|
|
|
|
by IDs). |
|
833
|
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
=cut |
|
835
|
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
sub Rank { |
|
837
|
0
|
|
|
0
|
1
|
0
|
my ($self, $id) = @_; |
|
838
|
|
|
|
|
|
|
|
|
839
|
0
|
0
|
|
|
|
0
|
return ($self->{Rank}{$id}) if(defined($id)); |
|
840
|
0
|
|
|
|
|
0
|
return ($self->{Rank}); |
|
841
|
|
|
|
|
|
|
} |
|
842
|
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
=item my $sigma = $agaTourn-EB ($id) |
|
844
|
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
Returns the sigma for $id. Sigma is determined by the rating/rank in the |
|
846
|
|
|
|
|
|
|
B. If the line contains a rank field of the form '4k' or '3d', |
|
847
|
|
|
|
|
|
|
sigma is 1.2 for 7k and stronger, and |
|
848
|
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
(k - 0.3) / 6 |
|
850
|
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
for 8k and weaker. If the line contains a rating of the form '-4.5' or '3.4', |
|
852
|
|
|
|
|
|
|
sigma is 0.6 for -8.0 and stronger, and |
|
853
|
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
(-rating - 4.4) / 6 |
|
855
|
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
for weaker than -8.0. |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
Complains and returns undef if $id is undefined or unregistered. |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
=cut |
|
861
|
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
sub Sigma { |
|
863
|
0
|
|
|
0
|
1
|
0
|
my ($self, $id) = @_; |
|
864
|
|
|
|
|
|
|
|
|
865
|
0
|
0
|
|
|
|
0
|
if (defined($id)) { |
|
866
|
0
|
0
|
|
|
|
0
|
if (defined($self->{Rank}{$id})) { |
|
|
|
0
|
|
|
|
|
|
|
867
|
0
|
|
|
|
|
0
|
$self->{Rank}{$id} =~ m/^([\d]+)([kdKD])$/; |
|
868
|
0
|
|
|
|
|
0
|
my $r = $1; |
|
869
|
0
|
0
|
|
|
|
0
|
$r = -$r if (lc($2) eq 'k'); |
|
870
|
0
|
|
|
|
|
0
|
my $sigma = (-$r - 0.3) / 6; |
|
871
|
0
|
0
|
|
|
|
0
|
return ($sigma > 1.2) ? $sigma : 1.2; |
|
872
|
|
|
|
|
|
|
} elsif (defined($self->{Rating}{$id})) { |
|
873
|
0
|
|
|
|
|
0
|
my $sigma = (-$self->{Rating}{$id} - 4.4) / 6; |
|
874
|
0
|
0
|
|
|
|
0
|
return ($sigma > 0.6) ? $sigma : 0.6; |
|
875
|
|
|
|
|
|
|
} else { |
|
876
|
0
|
|
|
|
|
0
|
carp("$id is not registered\n"); |
|
877
|
|
|
|
|
|
|
} |
|
878
|
|
|
|
|
|
|
} else { |
|
879
|
0
|
|
|
|
|
0
|
carp("called Sigma(\$id) without a valid ID\n"); |
|
880
|
|
|
|
|
|
|
} |
|
881
|
0
|
|
|
|
|
0
|
return(undef); |
|
882
|
|
|
|
|
|
|
} |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
=item my $club = $agaTourn-EB ($id) |
|
885
|
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
Returns the club for $id or '' if no club is known. Returns undef if $id is |
|
887
|
|
|
|
|
|
|
not registered (via B). |
|
888
|
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
If no $id parameter is passed, returns a reference to the entire B hash |
|
890
|
|
|
|
|
|
|
(keyed by IDs). |
|
891
|
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
=cut |
|
893
|
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
sub Club { |
|
895
|
0
|
|
|
0
|
1
|
0
|
my ($self, $id) = @_; |
|
896
|
|
|
|
|
|
|
|
|
897
|
0
|
0
|
|
|
|
0
|
return ($self->{Club}{$id}) if (defined($id)); |
|
898
|
0
|
|
|
|
|
0
|
return($self->{Club}); |
|
899
|
|
|
|
|
|
|
} |
|
900
|
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
=item my $flags = $agaTourn-EB ($id) |
|
902
|
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
Returns the flags for $id or '' if no flags are known. Flags are anything |
|
904
|
|
|
|
|
|
|
left over (excluding the comment) after the ID, name, rating, and club have |
|
905
|
|
|
|
|
|
|
been parsed by B. It might include (for example) BYE or |
|
906
|
|
|
|
|
|
|
Drop. The case is preserved from the original line parsed. |
|
907
|
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
Returns undef if $id is not registered (via B). If no $id |
|
909
|
|
|
|
|
|
|
parameter is passed, returns a reference to the entire B hash (keyed by |
|
910
|
|
|
|
|
|
|
IDs). |
|
911
|
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
=cut |
|
913
|
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
sub Flags { |
|
915
|
0
|
|
|
0
|
1
|
0
|
my ($self, $id) = @_; |
|
916
|
|
|
|
|
|
|
|
|
917
|
0
|
0
|
|
|
|
0
|
if (defined($id)) { |
|
918
|
0
|
0
|
|
|
|
0
|
return ($self->{Flags}{$id}) if (exists($self->{Flags}{$id})); |
|
919
|
0
|
0
|
|
|
|
0
|
return ('') if exists($self->{Rating}{$id}); |
|
920
|
|
|
|
|
|
|
return (undef) |
|
921
|
0
|
|
|
|
|
0
|
} |
|
922
|
0
|
|
|
|
|
0
|
return($self->{Flags}); |
|
923
|
|
|
|
|
|
|
} |
|
924
|
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
=item $comment = $agaTourn-EB ($id) |
|
926
|
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
Returns the comment associated with $id line as added via B. |
|
928
|
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
If no $id argument is passed, returns a reference to the entire B |
|
930
|
|
|
|
|
|
|
hash (keyed by IDs). |
|
931
|
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
=cut |
|
933
|
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
sub Comment { |
|
935
|
2
|
|
|
2
|
1
|
8
|
my ($self, $id) = @_; |
|
936
|
|
|
|
|
|
|
|
|
937
|
2
|
50
|
|
|
|
12
|
if (defined($id)) { |
|
938
|
0
|
0
|
|
|
|
0
|
return ($self->{Comment}{$id}) if (exists($self->{Comment}{$id})); |
|
939
|
0
|
0
|
|
|
|
0
|
return ('') if exists($self->{Rating}{$id}); |
|
940
|
|
|
|
|
|
|
return (undef) |
|
941
|
0
|
|
|
|
|
0
|
} |
|
942
|
2
|
|
|
|
|
18
|
return ($self->{Comment}); |
|
943
|
|
|
|
|
|
|
} |
|
944
|
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
=item my $error = $agaTourn-EB |
|
946
|
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
If called with an argument, sets the error flag to the new value. |
|
948
|
|
|
|
|
|
|
Returns the current (or new) value of the error flag. |
|
949
|
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
=cut |
|
951
|
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
sub Error { |
|
953
|
2
|
|
|
2
|
1
|
7
|
my ($self, $error) = @_; |
|
954
|
|
|
|
|
|
|
|
|
955
|
2
|
50
|
|
|
|
13
|
$self->{error} = $error if (defined($error)); |
|
956
|
2
|
|
|
|
|
12
|
return ($self->{error}); |
|
957
|
|
|
|
|
|
|
} |
|
958
|
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
=item my $gamesList = $agaTourn-EB ($id, ...) |
|
960
|
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
Returns a list (or a reference to the list in scalar context) of games played |
|
962
|
|
|
|
|
|
|
by B(s). If no B argument is passed, returns the list of all |
|
963
|
|
|
|
|
|
|
games. |
|
964
|
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
Games are added via the B or the B methods. |
|
966
|
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
Entries in the returned list are comma separated strings. They can be parsed |
|
968
|
|
|
|
|
|
|
with: |
|
969
|
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
my ($whiteID, $blackID, $result, |
|
971
|
|
|
|
|
|
|
$handicap, $komi, $round) = split(',', $agaTourn->GamesList[$index]); |
|
972
|
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
=cut |
|
974
|
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
sub GamesList { |
|
976
|
3
|
|
|
3
|
1
|
10
|
my ($self, @arg) = @_; |
|
977
|
|
|
|
|
|
|
|
|
978
|
3
|
50
|
|
|
|
31
|
return($self->{gameAllList}) unless (@arg); |
|
979
|
0
|
|
|
|
|
0
|
my @games; |
|
980
|
0
|
|
|
|
|
0
|
foreach (@arg) { |
|
981
|
0
|
|
|
|
|
0
|
push(@games, @{$self->{gameIDList}{$_}}); |
|
|
0
|
|
|
|
|
0
|
|
|
982
|
|
|
|
|
|
|
} |
|
983
|
0
|
0
|
|
|
|
0
|
return(wantarray ? @games : \@games); |
|
984
|
|
|
|
|
|
|
} |
|
985
|
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
=item my $wins = $agaTourn-EB ($id) |
|
987
|
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
Returns the number of winning games recorded for $id. Wins are recorded |
|
989
|
|
|
|
|
|
|
via the B method. |
|
990
|
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
If no $id argument is passed, returns a reference to the entire B hash |
|
992
|
|
|
|
|
|
|
(keyed by IDs). |
|
993
|
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
=cut |
|
995
|
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
sub Wins { |
|
997
|
0
|
|
|
0
|
1
|
0
|
my ($self, $id) = @_; |
|
998
|
|
|
|
|
|
|
|
|
999
|
0
|
0
|
|
|
|
0
|
return($self->{Wins}{$id}) if (defined($id)); |
|
1000
|
0
|
|
|
|
|
0
|
return($self->{Wins}); |
|
1001
|
|
|
|
|
|
|
} |
|
1002
|
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
=item my $losses = $agaTourn-EB ($id) |
|
1004
|
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
Returns the number of losing games recorded for $id. Losses are |
|
1006
|
|
|
|
|
|
|
recorded via the B method. |
|
1007
|
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
If no $id argument is passed, returns a reference to the entire B hash |
|
1009
|
|
|
|
|
|
|
(keyed by IDs). |
|
1010
|
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
=cut |
|
1012
|
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
sub Losses { |
|
1014
|
0
|
|
|
0
|
1
|
0
|
my ($self, $id) = @_; |
|
1015
|
|
|
|
|
|
|
|
|
1016
|
0
|
0
|
|
|
|
0
|
return($self->{Losses}{$id}) if (defined($id)); |
|
1017
|
0
|
|
|
|
|
0
|
return($self->{Losses}); |
|
1018
|
|
|
|
|
|
|
} |
|
1019
|
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
=item my $no_results = $agaTourn-EB ($id) |
|
1021
|
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
Returns the number of no-result games recorded for $id. No-results are |
|
1023
|
|
|
|
|
|
|
recorded via the B method. |
|
1024
|
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
If no $id argument is passed, returns a reference to the entire B |
|
1026
|
|
|
|
|
|
|
hash (keyed by IDs). |
|
1027
|
|
|
|
|
|
|
|
|
1028
|
|
|
|
|
|
|
=cut |
|
1029
|
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
sub NoResults { |
|
1031
|
0
|
|
|
0
|
1
|
0
|
my ($self, $id) = @_; |
|
1032
|
|
|
|
|
|
|
|
|
1033
|
0
|
0
|
|
|
|
0
|
return($self->{NoResults}{$id}) if (defined($id)); |
|
1034
|
0
|
|
|
|
|
0
|
return($self->{NoResults}); |
|
1035
|
|
|
|
|
|
|
} |
|
1036
|
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
=item my @played = $agaTourn-EB ($id) |
|
1038
|
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
Returns a list (or a reference to the list in scalar context) of $id's |
|
1040
|
|
|
|
|
|
|
opponents. The list is ordered as they were added by B method. |
|
1041
|
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
If no $id argument is passed, returns a reference to the entire B hash |
|
1043
|
|
|
|
|
|
|
(keyed by IDs). |
|
1044
|
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
=cut |
|
1046
|
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
sub Played { |
|
1048
|
0
|
|
|
0
|
1
|
0
|
my ($self, $id) = @_; |
|
1049
|
|
|
|
|
|
|
|
|
1050
|
0
|
0
|
|
|
|
0
|
if (defined($id)) { |
|
1051
|
0
|
0
|
|
|
|
0
|
return wantarray ? @{$self->{Played}{$id}} : $self->{Played}{$id}; |
|
|
0
|
|
|
|
|
0
|
|
|
1052
|
|
|
|
|
|
|
} |
|
1053
|
0
|
|
|
|
|
0
|
return $self->{Played}; |
|
1054
|
|
|
|
|
|
|
} |
|
1055
|
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
=item my $rating = $agaTourn-EB ($rank | $rating) |
|
1057
|
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
Returns a value guaranteed to be in a correct AGA Rating format. The format |
|
1059
|
|
|
|
|
|
|
is a number with a tenths decimal, where the number represents the dan rank |
|
1060
|
|
|
|
|
|
|
(if positive) or the kyu rank (if negative). A rating of 3.5 represents |
|
1061
|
|
|
|
|
|
|
squarely in the middle of the 3 dan rank, and -1.9 represents a weak 1 kyu |
|
1062
|
|
|
|
|
|
|
rank. The range from 1.0 to -1.0 is not used (see |
|
1063
|
|
|
|
|
|
|
B/B below). |
|
1064
|
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
=cut |
|
1066
|
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
sub RankToRating { |
|
1068
|
32
|
|
|
32
|
1
|
53
|
my ($self, $rating) = @_; |
|
1069
|
|
|
|
|
|
|
|
|
1070
|
32
|
50
|
33
|
|
|
187
|
return (NOTARANK) if (not defined($rating) or ($rating eq '')); |
|
1071
|
32
|
100
|
|
|
|
132
|
return "$rating.0" if ($rating =~ m/^-?\d+$/); # not in decimalized format? |
|
1072
|
29
|
100
|
|
|
|
79
|
unless ($rating =~ m/^-?\d+\.\d+$/) { # not in rating format? |
|
1073
|
24
|
50
|
|
|
|
91
|
return(NOTARANK) unless($rating =~ m/^(\d+)([dDkK])$/); # not in rank format either? |
|
1074
|
24
|
|
|
|
|
52
|
$rating = "$1.5"; # it's in rank format (like 5D or 2k), convert to rating |
|
1075
|
24
|
100
|
|
|
|
85
|
$rating = -$rating if (uc($2) eq "K"); # kyus are negative |
|
1076
|
|
|
|
|
|
|
} |
|
1077
|
29
|
|
|
|
|
87
|
return($rating); |
|
1078
|
|
|
|
|
|
|
} |
|
1079
|
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
=item my $band_idx = $agaTourn-EB ($rank | $rating) |
|
1081
|
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
Returns the band index for a B or B. Returns NOTARANK if |
|
1083
|
|
|
|
|
|
|
rank/rating is not in any bands. |
|
1084
|
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
See also B below. |
|
1086
|
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
=cut |
|
1088
|
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
sub WhichBandIs { |
|
1090
|
8
|
|
|
8
|
1
|
15
|
my ($self, $r) = @_; |
|
1091
|
|
|
|
|
|
|
|
|
1092
|
8
|
100
|
|
|
|
24
|
unless (exists($self->{bandTop})) { |
|
1093
|
2
|
|
|
|
|
10
|
$self->_setBands(); |
|
1094
|
|
|
|
|
|
|
} |
|
1095
|
8
|
|
|
|
|
22
|
$r = $self->RankToRating($r); |
|
1096
|
8
|
|
|
|
|
14
|
my $ii; |
|
1097
|
8
|
|
|
|
|
11
|
for ($ii = 0; $ii < @{$self->{bandTop}}; $ii++) { |
|
|
21
|
|
|
|
|
52
|
|
|
1098
|
15
|
50
|
|
|
|
44
|
next if ($r > $self->{bandTop}[$ii]); |
|
1099
|
15
|
100
|
|
|
|
39
|
if ($r >= $self->{bandBot}[$ii]) { |
|
1100
|
2
|
|
|
|
|
14
|
return($ii); # this is it |
|
1101
|
|
|
|
|
|
|
} |
|
1102
|
|
|
|
|
|
|
} |
|
1103
|
6
|
|
|
|
|
12
|
return(NOTARANK); |
|
1104
|
|
|
|
|
|
|
} |
|
1105
|
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
=item my $band_name = $agaTourn-EB ($bandIndex) |
|
1107
|
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
Returns the name of a band specified by the B or undef of not known. |
|
1109
|
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
Scoring bands are specified via B with ##BAND directives. |
|
1111
|
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
AGATourn complains if bands are specified with holes between them. |
|
1113
|
|
|
|
|
|
|
|
|
1114
|
|
|
|
|
|
|
The bands are sorted (by strength) and indexed. B returns the |
|
1115
|
|
|
|
|
|
|
original name (as specified in the ##BAND directive) from a band index. |
|
1116
|
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
=cut |
|
1118
|
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
sub BandName { |
|
1120
|
4
|
|
|
4
|
1
|
10
|
my ($self, $idx) = @_; |
|
1121
|
|
|
|
|
|
|
|
|
1122
|
4
|
|
|
|
|
7
|
my ($band, $top, $bot); |
|
1123
|
4
|
|
|
|
|
7
|
foreach $band (@{$self->{Directive}{'BAND'}}) { |
|
|
4
|
|
|
|
|
12
|
|
|
1124
|
6
|
|
|
|
|
16
|
($top, $bot) = split(/\s+/, $band); |
|
1125
|
6
|
|
|
|
|
17
|
$top = int($self->RankToRating($top)); |
|
1126
|
6
|
100
|
|
|
|
24
|
return undef unless defined($self->{bandTop}[$idx]); |
|
1127
|
5
|
100
|
|
|
|
17
|
if ($top == int($self->{bandTop}[$idx])) { |
|
1128
|
3
|
|
|
|
|
16
|
return($band); |
|
1129
|
|
|
|
|
|
|
} |
|
1130
|
|
|
|
|
|
|
} |
|
1131
|
0
|
|
|
|
|
0
|
return(undef); |
|
1132
|
|
|
|
|
|
|
} |
|
1133
|
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
=item my ($handicap, $komi) = $agaTourn-EB ($player1, $player2) |
|
1135
|
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
Returns the appropriate handicap and komi for two players. Players can be in |
|
1137
|
|
|
|
|
|
|
any form acceptable to B. |
|
1138
|
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
If player1 is stronger than player two, the handicap is a |
|
1140
|
|
|
|
|
|
|
positive number. If player1 is weaker than player2, (players need to be |
|
1141
|
|
|
|
|
|
|
swapped), the returned handicap is a negative number. If the handicap would |
|
1142
|
|
|
|
|
|
|
normally be 0 and the players need to be swapped, the returned handicap is -1. |
|
1143
|
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
A handicap of 1 is never returned. The returned handicap and komi are always |
|
1145
|
|
|
|
|
|
|
integers (you may assume that komi needs a additional half-point if you like). |
|
1146
|
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
If either player1 or player2 is invalid, B complains (during the |
|
1148
|
|
|
|
|
|
|
call to B for the player) and returns (-1, -1). |
|
1149
|
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
B uses the following table (same as the AGA handicap practice): |
|
1151
|
|
|
|
|
|
|
|
|
1152
|
|
|
|
|
|
|
rating handi Ing AGA |
|
1153
|
|
|
|
|
|
|
diff Komi Komi |
|
1154
|
|
|
|
|
|
|
0.000-0.650 0 7 6 even, normal komi |
|
1155
|
|
|
|
|
|
|
0.651-1.250 0 -1* 0 no komi (* black wins ties under Ing) |
|
1156
|
|
|
|
|
|
|
1.251-2.200 0 -7 -6 reverse komi |
|
1157
|
|
|
|
|
|
|
2.201-3.300 2 -2 0 two stones |
|
1158
|
|
|
|
|
|
|
3.301-4.400 3 -3 0 three stones ... |
|
1159
|
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
=cut |
|
1161
|
|
|
|
|
|
|
|
|
1162
|
|
|
|
|
|
|
sub Handicap { |
|
1163
|
0
|
|
|
0
|
1
|
0
|
my ($self, $p1, $p2) = @_; |
|
1164
|
|
|
|
|
|
|
|
|
1165
|
0
|
|
|
|
|
0
|
$p1 = $self->CollapseRating($self->Rating($p1)); |
|
1166
|
0
|
|
|
|
|
0
|
$p2 = $self->CollapseRating($self->Rating($p2)); |
|
1167
|
0
|
0
|
0
|
|
|
0
|
return (-1, -1) unless(defined($p1) and defined($p2)); |
|
1168
|
0
|
|
|
|
|
0
|
my $diff = $p1 - $p2; |
|
1169
|
0
|
|
|
|
|
0
|
my $ing = $self->{Directive}{RULES}[0] eq 'ING'; |
|
1170
|
0
|
|
|
|
|
0
|
my $swap = 1; |
|
1171
|
0
|
|
|
|
|
0
|
my ($handi, $komi) = (0, 0); |
|
1172
|
0
|
0
|
|
|
|
0
|
if ($diff < 0) { |
|
1173
|
0
|
|
|
|
|
0
|
$swap = $handi = -1; |
|
1174
|
0
|
|
|
|
|
0
|
$diff = -$diff; |
|
1175
|
|
|
|
|
|
|
} |
|
1176
|
0
|
0
|
|
|
|
0
|
if ($diff <= .650) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1177
|
0
|
0
|
|
|
|
0
|
$komi = $ing ? 7 : 6; # normal komi game |
|
1178
|
|
|
|
|
|
|
} elsif ($diff <= 1.25) { |
|
1179
|
0
|
0
|
|
|
|
0
|
$komi = $ing ? -1 : 0; # no komi game |
|
1180
|
|
|
|
|
|
|
} elsif ($diff <= 2.2) { |
|
1181
|
0
|
0
|
|
|
|
0
|
$komi = $ing ? -7 : -6; # reverse komi game |
|
1182
|
|
|
|
|
|
|
} else { |
|
1183
|
0
|
|
|
|
|
0
|
$handi = $swap * int($diff / 1.1); |
|
1184
|
0
|
|
|
|
|
0
|
$komi = 0; |
|
1185
|
|
|
|
|
|
|
} |
|
1186
|
0
|
|
|
|
|
0
|
return (int($handi), int($komi)); |
|
1187
|
|
|
|
|
|
|
} |
|
1188
|
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
=item my $collapsed_rating = $agaTourn-EB ($aga_rating) |
|
1190
|
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
AGA ratings have a hole between 1.0 and -1.0. This method fills the hole by |
|
1192
|
|
|
|
|
|
|
adding 1 to kyu ratings and subtracting 1 from dan ratings. If $aga_rating is |
|
1193
|
|
|
|
|
|
|
between 1.0 and -1.0, complains and returns the original $rating. |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
=cut |
|
1196
|
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
sub CollapseRating { |
|
1198
|
0
|
|
|
0
|
1
|
0
|
my ($self, $rating) = @_; |
|
1199
|
|
|
|
|
|
|
|
|
1200
|
0
|
0
|
|
|
|
0
|
if ($rating >= 1) { |
|
|
|
0
|
|
|
|
|
|
|
1201
|
0
|
|
|
|
|
0
|
$rating -= 1; # pull dan ratings down to 0 |
|
1202
|
|
|
|
|
|
|
} elsif ($rating <= -1) { |
|
1203
|
0
|
|
|
|
|
0
|
$rating += 1; # pull kyu ratings up to 0 |
|
1204
|
|
|
|
|
|
|
} else { |
|
1205
|
0
|
|
|
|
|
0
|
carp "CollapseRating called on a rating between -1 and +1: $rating\n"; |
|
1206
|
|
|
|
|
|
|
} |
|
1207
|
0
|
|
|
|
|
0
|
return $rating; |
|
1208
|
|
|
|
|
|
|
} |
|
1209
|
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
=item my $AGA_rating = $agaTourn-EB ($collapsed_rating) |
|
1211
|
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
AGA ratings have a hole between 1.0 and -1.0. This method converts a |
|
1213
|
|
|
|
|
|
|
continuous rating with no hole into a valid AGA rating by adding 1 to ratings |
|
1214
|
|
|
|
|
|
|
greater than 0 and subtracting 1 from ratings less than 0. |
|
1215
|
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
=cut |
|
1217
|
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
sub ExpandRating { |
|
1219
|
0
|
|
|
0
|
1
|
0
|
my ($self, $rating) = @_; |
|
1220
|
|
|
|
|
|
|
|
|
1221
|
0
|
0
|
|
|
|
0
|
if ($rating >= 0) { |
|
1222
|
0
|
|
|
|
|
0
|
$rating += 1; # dan ratings are upwards from 1 |
|
1223
|
|
|
|
|
|
|
} else { |
|
1224
|
0
|
|
|
|
|
0
|
$rating -= 1; # kyu ratings are downwards from -1 |
|
1225
|
|
|
|
|
|
|
} |
|
1226
|
0
|
|
|
|
|
0
|
return $rating; |
|
1227
|
|
|
|
|
|
|
} |
|
1228
|
|
|
|
|
|
|
|
|
1229
|
|
|
|
|
|
|
=item my $normalized_id = $agaTourn-EB ($id) |
|
1230
|
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
Performs normalization of $id so the we can compare variations of $id without |
|
1232
|
|
|
|
|
|
|
considering them as different. Normalization consists of turning the country |
|
1233
|
|
|
|
|
|
|
part of $id to all upper-case and removing leading zeros from the number part. |
|
1234
|
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
All $ids used as hash keys should be normalized. |
|
1236
|
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
=cut |
|
1238
|
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
sub NormalizeID { |
|
1240
|
9
|
|
|
9
|
1
|
23
|
my ($self, $id) = @_; |
|
1241
|
|
|
|
|
|
|
|
|
1242
|
9
|
|
|
|
|
14
|
$id = uc ($id); # make all letters upper case |
|
1243
|
9
|
|
|
|
|
56
|
$id =~ s/^([A-Z]*)0*([1-9].*)/$1$2/; # remove leading zeros from number part |
|
1244
|
9
|
|
|
|
|
25
|
return($id); |
|
1245
|
|
|
|
|
|
|
} |
|
1246
|
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
###################################################### |
|
1248
|
|
|
|
|
|
|
# |
|
1249
|
|
|
|
|
|
|
# Private methods |
|
1250
|
|
|
|
|
|
|
# |
|
1251
|
|
|
|
|
|
|
##################################################### |
|
1252
|
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
sub _setBands { |
|
1254
|
2
|
|
|
2
|
|
4
|
my ($self) = @_; |
|
1255
|
|
|
|
|
|
|
|
|
1256
|
2
|
100
|
|
|
|
12
|
unless(exists($self->{Directive}{'BAND'})) { |
|
1257
|
|
|
|
|
|
|
# carp("Note: no bands selected, assuming one band.\n"); |
|
1258
|
1
|
|
|
|
|
2
|
unshift(@{$self->{Directive}{'BAND'}}, '99D 99K'); |
|
|
1
|
|
|
|
|
7
|
|
|
1259
|
|
|
|
|
|
|
} |
|
1260
|
2
|
|
|
|
|
9
|
$self->{bandTop} = []; # ref to empty array (to prevent infinite recursion) |
|
1261
|
2
|
|
|
|
|
4
|
my ($band, $ovBand, $top, $bot); |
|
1262
|
2
|
|
|
|
|
6
|
foreach $band (@{$self->{Directive}{'BAND'}}) { |
|
|
2
|
|
|
|
|
7
|
|
|
1263
|
6
|
|
|
|
|
20
|
($top, $bot) = split(/\s+/, $band); |
|
1264
|
6
|
|
|
|
|
18
|
$top = int($self->RankToRating($top)); |
|
1265
|
6
|
100
|
|
|
|
20
|
$top += 0.99999 if ($top > 0); |
|
1266
|
6
|
|
|
|
|
17
|
$bot = int($self->RankToRating($bot)); |
|
1267
|
6
|
100
|
|
|
|
31
|
$bot -= 0.99999 if ($bot < 0); |
|
1268
|
6
|
50
|
33
|
|
|
51
|
if (($top > 9999) || ($bot < -9999) || ($bot >= $top)) { |
|
|
|
|
33
|
|
|
|
|
|
1269
|
0
|
|
|
|
|
0
|
carp("Error: can't parse BAND directive at line $. in $self->{fileName}: $band\n"); |
|
1270
|
0
|
|
|
|
|
0
|
$self->{error} = 1; |
|
1271
|
|
|
|
|
|
|
return |
|
1272
|
0
|
|
|
|
|
0
|
} |
|
1273
|
6
|
|
|
|
|
20
|
$ovBand = $self->WhichBandIs($top); # check for overlapped bands |
|
1274
|
6
|
50
|
|
|
|
83
|
$ovBand = $self->WhichBandIs($bot) unless ($ovBand eq NOTARANK); |
|
1275
|
6
|
50
|
|
|
|
32
|
unless ($ovBand eq NOTARANK) { |
|
1276
|
0
|
|
|
|
|
0
|
carp("Warning: band conflict: $band\n (overlaps $self->{Directive}{'BAND'}[$ovBand])\n"); |
|
1277
|
|
|
|
|
|
|
} |
|
1278
|
6
|
|
|
|
|
6
|
push(@{$self->{bandTop}}, $top); |
|
|
6
|
|
|
|
|
16
|
|
|
1279
|
6
|
|
|
|
|
7
|
push(@{$self->{bandBot}}, $bot); |
|
|
6
|
|
|
|
|
18
|
|
|
1280
|
|
|
|
|
|
|
} |
|
1281
|
2
|
|
|
|
|
5
|
my (@tops) = sort({ $b <=> $a; } @{$self->{bandTop}}); # now check for holes |
|
|
8
|
|
|
|
|
15
|
|
|
|
2
|
|
|
|
|
12
|
|
|
1282
|
2
|
|
|
|
|
4
|
my (@bots) = sort({ $b <=> $a; } @{$self->{bandBot}}); |
|
|
8
|
|
|
|
|
12
|
|
|
|
2
|
|
|
|
|
5
|
|
|
1283
|
2
|
|
|
|
|
4
|
my $ii; |
|
1284
|
2
|
|
|
|
|
16
|
for ($ii = 0; $ii < @tops - 1; $ii++) { |
|
1285
|
4
|
100
|
66
|
|
|
21
|
next if (($bots[$ii] == 1) && ($tops[$ii + 1] == -1)); # 1d to 1k is a legitimate hole |
|
1286
|
3
|
50
|
|
|
|
22
|
if ($bots[$ii] - $tops[$ii + 1] > 0.001) { |
|
1287
|
0
|
|
|
|
|
0
|
carp( "Warning: hole between bands\n"); |
|
1288
|
|
|
|
|
|
|
} |
|
1289
|
|
|
|
|
|
|
} |
|
1290
|
2
|
|
|
|
|
7
|
$self->{bandTop} = \@tops; # use sorted bands |
|
1291
|
2
|
|
|
|
|
7
|
$self->{bandBot} = \@bots; |
|
1292
|
|
|
|
|
|
|
} |
|
1293
|
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
1; |
|
1295
|
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
__END__ |