File Coverage

blib/lib/Games/Tournament/Contestant/Swiss.pm
Criterion Covered Total %
statement 70 105 66.6
branch 22 38 57.8
condition 15 21 71.4
subroutine 15 19 78.9
pod 11 11 100.0
total 133 194 68.5


line stmt bran cond sub pod time code
1             package Games::Tournament::Contestant::Swiss;
2             $Games::Tournament::Contestant::Swiss::VERSION = '0.21';
3             # Last Edit: 2011 2月 27, 21時32分54秒
4             # $Id: $
5              
6 28     28   973412 use warnings;
  28         62  
  28         838  
7 28     28   133 use strict;
  28         45  
  28         662  
8              
9 28     28   19577 use List::MoreUtils qw/any/;
  28         295965  
  28         192  
10              
11 28     28   29700 use Games::Tournament::Swiss::Config;
  28         1100  
  28         1395  
12 28 100       3057 use constant ROLES => @Games::Tournament::Swiss::Config::roles?
13             @Games::Tournament::Swiss::Config::roles:
14 28     28   154 Games::Tournament::Swiss::Config->roles;
  28         46  
15              
16 28     28   139 use base qw/Games::Tournament::Contestant/;
  28         48  
  28         11119  
17              
18             # use overload qw/0+/ => 'pairingNumber', qw/""/ => 'name', fallback => 1;
19              
20             =head1 NAME
21              
22             Games::Tournament::Contestant::Swiss A competitor in a FIDE-Swiss-Rules event
23              
24             =cut
25              
26             =head1 SYNOPSIS
27              
28             my $foo = Games::Tournament::Contestant::Swiss->new( rating => '15', name => 'Deep Blue', pairingNumber => 2 );
29             ...
30              
31             =head1 DESCRIPTION
32              
33             Subclasses Games::Tournament::Contestant with Games::Tournament::Swiss-specific data and methods, like pairingNumber, floats.
34              
35             Games::Tournament::Swiss will use this class when constructing a 'Bye' contestant.
36              
37             =head1 METHODS
38              
39             =head2 new
40              
41             Games::Tournament::Contestant::Swiss->new( rating => '15',
42             name => 'Red Chessman', pairingNumber => 2,
43             floats => [qw/Not Down Not Not],
44             roles => [qw/Black White Black White/] );
45              
46             Actually, you don't want to assign pairing numbers this way. Let the assignPairingNumbers method in Games::Tournament::Swiss do it. The player gets a default mild preference for neither role.
47              
48             =cut
49              
50             sub new() {
51 1853     1853 1 407114 my $self = shift;
52 1853         5980 my %args = @_;
53             # $args{roles} = [] unless $args{roles};
54 1853         3291 my $object = bless \%args, $self;
55 1853         5264 $object->preference(
56             Games::Tournament::Contestant::Swiss::Preference->new );
57 1853         5360 return $object;
58             }
59              
60              
61             =head2 preference
62              
63             $member->preference
64              
65             Gets (sets) $member's preference, or right (duty) to take a role, eg White or Black, in the next round, calculated as a function of the difference between the number of games previously played in the different roles, and accommodated according to its value, Mild, Strong, or Absolute. An Absolute preference of +2 for White is given when the contestant has played 2 (or a larger number) more of the previous rounds as Black than as White, or when the last 2 rounds were played as Black. A Strong preference of +1 for White represents having played one more round as Black than as White. A Mild preference of +0 occurs when the number of games played with both colors is the same, but the last game was played as Black. A Mild preference of -0 is the same, but with the last game being as White, the preference is for Black. Preferences of -1 and -2 represent the same situations as for +1 and +2, but with the roles reversed. Before the first round, the preference of the highest ranked player (+-0) is determined by lot. A7
66              
67             =cut
68              
69             sub preference {
70 45642     45642 1 63426 my $self = shift;
71 45642   66     114228 my $preference = shift() || $self->{preference};
72 45642         62075 $self->{preference} = $preference;
73 45642         120675 return $preference;
74             }
75              
76              
77             =head2 pairingNumber
78              
79             $member->pairingNumber(1)
80              
81             Sets/gets the pairing number of the contestant, used to identify participants when pairing them with others. This index is assigned in order of a sorting of the participants by ranking, title and name. You know what you're doing with this number, don't you?
82              
83             =cut
84              
85             sub pairingNumber {
86 39863     39863 1 47791 my $self = shift;
87 39863 100       77182 $self->{pairingNumber} = shift if @_;
88 39863         116070 $self->{pairingNumber};
89             }
90              
91              
92             =head2 oldId
93              
94             $member->oldId
95              
96             Sets/gets an original, possibly unreliable id of the contestant, supplied by the user.
97              
98             =cut
99              
100             sub oldId {
101 0     0 1 0 my $self = shift;
102 0         0 my $oldId = shift;
103 0 0       0 if ( defined $oldId ) { $self->{oldId} = $oldId; }
  0 0       0  
104 0         0 elsif ( $self->{oldId} ) { return $self->{oldId}; }
105             }
106              
107             =head2 opponents
108              
109             $member->opponents( 0, 5, 11 )
110             $rolehistory = $member->opponents
111              
112             If ids are passed, adds them to the end of the list representing the latest opponents that $member has had in this tournament. (Normally one and only one parameter, the id of the opponent in the latest round, will be passed.) If no parameter is passed, returns a reference to the list. If the member had no game or played no game, because of a bye, or no result, or was unpaired, pass 'Bye' or 'Forfeit' or 'Unpaired'.
113              
114             =cut
115              
116             sub opponents {
117 0     0 1 0 my $self = shift;
118 0         0 my @opponents = @_;
119 0 0       0 if ( @opponents ) { push @{ $self->{opponents} }, @opponents; return }
  0 0       0  
  0         0  
  0         0  
120 0         0 elsif ( $self->{opponents} ) { return $self->{opponents}; }
121 0         0 else { return []; }
122             }
123              
124              
125             =head2 roles
126              
127             $member->roles( 1, 'Black' )
128             $member->roles( 1 ) # 'Black'
129             $rolehistory = $member->roles # { 1 => 'Black' }
130              
131             If a round and role are passed, adds them to the roles that $member has had in this tournament. If the member had no game (or had a game but didn't play it), that is, if they had a bye, or no result, or were unpaired, pass 'Bye', or 'Forfeit', or 'Unpaired.' F2,3
132              
133             =cut
134              
135             sub roles {
136 2412     2412 1 3008 my $self = shift;
137 2412         3026 my $round = shift;
138 2412         2750 my $role = shift;
139 2412 100 66     13793 if ( defined $role and defined $round ) {
    50 66        
    100          
140 648         1142 my $oldrole = $self->{roles}->{$round};
141 648 50 33     1551 warn "$oldrole role replaced by $role" if defined $oldrole and
142             $oldrole ne $role;
143 648         1871 $self->{roles}->{$round} = $role;
144             }
145 0         0 elsif ( $self->{roles} and $round ) { return $self->{roles}->{$round}; }
146 1536         3142 elsif ( $self->{roles} ) { return $self->{roles}; }
147 228         530 else { return {}; }
148             }
149              
150              
151             =head2 rolesPlayedList
152              
153             A list, in round order, of the roles played against other players. Byes and other non-partnership roles are not included.
154              
155             =cut
156              
157             sub rolesPlayedList {
158 1116     1116 1 1443 my $self = shift;
159 1116         2253 my $roles = $self->roles;
160 1116         3522 my @rounds = sort { $a <=> $b } keys %$roles;
  3003         5400  
161 1116         1925 my $last = $rounds[-1];
162 1116         1681 my @playrounds = grep { my $role = $roles->{$_};
  3034         4608  
163 3034     4589   11495 any { $role eq $_ } ROLES } @rounds;
  4589         13307  
164 1116         1715 my @playroles = map { $roles->{$_} } @playrounds;
  2938         5728  
165 1116         4628 return \@playroles;
166             }
167              
168              
169             =head2 floating
170              
171             $member->floating
172             $member->floating( 'Up'|'Down'|'' )
173              
174             Sets/gets the direction in which the contestant is floating in the next round, "Up", "Down". If nothing is returned, the contestant is not floating. A4
175              
176             =cut
177              
178             sub floating {
179 2295     2295 1 3046 my $self = shift;
180 2295         2849 my $direction = shift;
181 2295 100 100     14075 if ( defined $direction and $direction =~ m/^(?:Up|Down|)$/ ) {
    100          
182 1223         3862 $self->{floater} = $direction;
183             }
184 362         1923 elsif ( $self->{floater} ) { return $self->{floater}; }
185             }
186              
187             =head2 floats
188              
189             $member->floats( $round, 'Down' )
190             $rolehistory = $member->floats
191              
192             If a round number and float is passed, inserts this in an anonymous array representing the old floats that $member has had in this tournament. If only a round is passed, returns the float for that round. If no parameter is passed, returns a anonymous array of all the floats ordered by the round. If the player was not floated, pass 'Not'. For convenience, if -1 or -2 are passed for the last round before, or the round 2 rounds ago, and those rounds do not exist (perhaps the tournament only started one round before), 'Not' is returned.
193              
194             =cut
195              
196              
197             sub floats {
198 2669     2669 1 3441 my $self = shift;
199 2669         3155 my $round = shift;
200 2669         3240 my $float = shift;
201 2669 100 100     11575 if ( defined $round and defined $float ) {
    100          
    50          
202 648         1609 $self->{floats}->[$round-1] = $float;
203 648         1292 return;
204             }
205             elsif ( defined $round ) {
206 2003 50 66     6387 if ($round == -1 or $round == -2) {
207 2003 100       4683 if (not exists $self->{floats}->[$round-1] ) {return 'Not'}
  634         1983  
208 1369         5163 else { return $self->{floats}->[$round]; }
209             }
210 0         0 else { return $self->{floats}->[$round-1]; }
211             }
212 18         59 elsif ( $self->{floats} ) { return $self->{floats}; }
213 0           else { return; }
214             }
215              
216             =head2 importPairtableRecord
217              
218             $member->importPairtableRecord(
219             { opponents => [ 6,4 ]
220             roles => [ 'Win', 'Loss' ],
221             floats => [ undef, 'Not', 'Down' ],
222             score => 1.5 } )
223              
224             Populate $member with data about opponents met, roles played, and floats received in previous rounds, which together with the total score will allow it to be paired with an appropriate opponent in the next round. Set $member's preference. Delete any pre-existing opponents, roles, floats, scores, score, or preference data.
225              
226             =cut
227              
228              
229             sub importPairtableRecord {
230 0     0 1   my $self = shift;
231 0           my $record = shift;
232             #die $self->name . ", " . $self->id . " pairtable record field lengths"
233             # unless @{$record->{opponents}} == @{$record->{roles}} and
234             # @{$record->{roles}} == @{$record->{floats}} - 1;
235 0           my ($opponents, $roles, $floats) = @$record{qw/opponents roles floats/};
236 0           delete @$self{qw/opponents roles floats scores score preference/};
237 0           $self->opponents(@$opponents);
238 0           $self->roles(@$roles);
239 0           for my $i ( 0 .. $#$floats ) { $self->floats( $i, $floats->[$i] ); }
  0            
240 28     28   15255 use Games::Tournament::Contestant::Swiss::Preference;
  28         67  
  28         4783  
241 0           $self->preference(Games::Tournament::Contestant::Swiss::Preference->new);
242 0           $self->preference->update( [ @$roles[0..$_] ] ) for 0.. $#$roles;
243 0           $self->{score} = $record->{score};
244 0           return;
245             }
246              
247             =head2 unbyable
248              
249             $member->unbyable(1)
250             return BYE unless $member->unbyable
251              
252             A flag of convenience telling you whether to let this player have the bye. Am I doing the right thing here? This will be gettable and settable, but will it be reliable?
253              
254             =cut
255              
256             sub unbyable {
257 0     0 1   my $self = shift;
258 0           my $unbyable = shift;
259 0 0         if ( $unbyable ) { $self->{unbyable} = 1; return }
  0 0          
  0            
260 0           elsif ( defined $self->{unbyable} ) { return $self->{unbyable}; }
261 0           else { return; }
262             }
263              
264              
265             =head1 AUTHOR
266              
267             Dr Bean, C<< >>
268              
269             =head1 BUGS
270              
271             Please report any bugs or feature requests to
272             C, or through the web interface at
273             L.
274             I will be notified, and then you'll automatically be notified of progress on
275             your bug as I make changes.
276              
277             =head1 SUPPORT
278              
279             You can find documentation for this module with the perldoc command.
280              
281             perldoc Games::Tournament::Contestant::Swiss
282              
283             You can also look for information at:
284              
285             =over 4
286              
287             =item * AnnoCPAN: Annotated CPAN documentation
288              
289             L
290              
291             =item * CPAN Ratings
292              
293             L
294              
295             =item * RT: CPAN's request tracker
296              
297             L
298              
299             =item * Search CPAN
300              
301             L
302              
303             =back
304              
305             =head1 ACKNOWLEDGEMENTS
306              
307             =head1 COPYRIGHT & LICENSE
308              
309             Copyright 2006 Dr Bean, all rights reserved.
310              
311             This program is free software; you can redistribute it and/or modify it
312             under the same terms as Perl itself.
313              
314             =cut
315              
316             1; # End of Games::Tournament::Contestant::Swiss
317              
318             # vim: set ts=8 sts=4 sw=4 noet: