File Coverage

blib/lib/Games/Go/AGA/DataObjects/Player.pm
Criterion Covered Total %
statement 31 190 16.3
branch 0 96 0.0
condition 2 22 9.0
subroutine 11 30 36.6
pod 17 22 77.2
total 61 360 16.9


line stmt bran cond sub pod time code
1             #===============================================================================
2             #
3             # FILE: Games::Go::AGA::DataObjects::Player.pm
4             # PODNAME: Games::Go::AGA::DataObjects::Player
5             # ABSTRACT: model an AGA player
6             #
7             # AUTHOR: Reid Augustin (REID), full_name
8             # CREATED: 11/19/2010 03:13:05 PM PST
9             #===============================================================================
10              
11              
12 5     5   52953 use strict;
  5         9  
  5         187  
13 5     5   25 use warnings;
  5         8  
  5         270  
14              
15             package Games::Go::AGA::DataObjects::Player;
16 5     5   3669 use Moo;
  5         78057  
  5         41  
17 5     5   12184 use namespace::clean;
  5         58460  
  5         26  
18              
19 5     5   1089 use Carp qw{ cluck carp croak };
  5         9  
  5         382  
20 5     5   26 use Scalar::Util qw( refaddr looks_like_number );
  5         7  
  5         450  
21 5     5   3434 use Games::Go::AGA::Parse::Util qw( normalize_ID Rank_to_Rating );
  5         8450  
  5         407  
22 5     5   2546 use Games::Go::AGA::DataObjects::Types qw( is_ID is_Rating is_Rank_or_Rating isa_ArrayRef isa_Num isa_CodeRef);
  5         11  
  5         16314  
23              
24             our $VERSION = '0.152'; # VERSION
25              
26             our $deprecate = 0;
27             has id => (
28             is => 'rw',
29             isa => sub {
30             confess("$_[0] is not an ID\n") if (not is_ID($_[0]))
31             },
32             trigger => sub {
33             # TODO: make this a coercion?
34             my ($self, $new) = @_;
35             $self->{id} = normalize_ID($new);
36             $self->changed;
37             },
38             );
39             has last_name => (
40             is => 'rw',
41             trigger => sub { shift->changed; },
42             );
43             has first_name => (
44             is => 'rw',
45             trigger => sub { shift->changed; },
46             );
47             has rank => (
48             is => 'rw',
49             isa => sub {
50             confess("$_[0] is not a Rank or Rating\n") if (not is_Rank_or_Rating($_[0]))
51             },
52             trigger => sub {
53             my ($self, $new) = @_;
54             if (is_Rating($new)) {
55             $self->{rank} += 0; # force numification
56             }
57             shift->changed;
58             },
59             );
60             has date => (
61             is => 'rw',
62             lazy => 1,
63             default => '',
64             trigger => sub { shift->changed; },
65             );
66             has membership => (
67             is => 'rw',
68             lazy => 1,
69             default => '',
70             trigger => sub { shift->changed; },
71             );
72             has state => (
73             is => 'rw',
74             lazy => 1,
75             default => '',
76             trigger => sub { shift->changed; },
77             );
78             has club => (
79             is => 'rw',
80             lazy => 1,
81             default => '',
82             trigger => sub {
83             my $self = shift;
84             $self->{club} = uc $self->{club};
85             $self->changed;
86             },
87             );
88             has flags => (
89             is => 'rw',
90             isa => \&isa_ArrayRef,
91             );
92             has comment => (
93             is => 'rw',
94             lazy => 1,
95             default => '',
96             trigger => sub { shift->changed; },
97             );
98             has sigma => (
99             is => 'rw',
100             isa => \&isa_Num,
101             trigger => sub { shift->changed; },
102             );
103             has games => (
104             is => 'rw',
105             isa => \&isa_ArrayRef,
106             lazy => 1,
107             default => sub { [] },
108             # trigger => sub { shift->changed; },
109             );
110             has change_callback => (
111             is => 'rw',
112             isa => \&isa_CodeRef,
113             lazy => 1,
114             default => sub { sub { } }
115             );
116             has _adj_ratings => ( # array of adjusted ratings, one per round_num, but not 0
117             is => 'lazy',
118             isa => \&isa_ArrayRef,
119             default => sub { [] }
120             );
121              
122             sub BUILD {
123 29     29 0 220 my ($self) = @_;
124 29   100     570 $self->{flags} ||= []; # empty array
125             }
126              
127             sub changed {
128 161     161 0 171 my ($self) = @_;
129              
130 161         173 &{$self->change_callback}(@_);
  161         2905  
131             }
132              
133             sub full_name {
134 0     0 0 0 my ($self) = @_;
135              
136 0 0       0 if (my $name = $self->first_name) {
137 0         0 return join(', ', $self->last_name, $name),
138             }
139             # some players don't have first name
140 0         0 return $self->last_name;
141             }
142              
143              
144             # sub comment {
145             # my $self = shift;
146             # if (@_) {
147             # if (defined $_[0]) {
148             # $self->{comment} = join '', @_;
149             # }
150             # else {
151             # delete $self->{comment};
152             # }
153             # }
154             # return $self->{comment};
155             # }
156              
157             sub add_game {
158 0     0 1 0 my ($self, $game, $idx) = @_;
159              
160 0 0       0 croak("Player::add_game deprecated: Use tournament->round->games list instead\n") if ($deprecate > 0);
161 0         0 my $add_refaddr = refaddr $game; # ID of game to add
162 0 0       0 if(not grep { (refaddr $_) == $add_refaddr } @{$self->{games}}) {
  0         0  
  0         0  
163             #print STDERR "add_game $game to " . $self->full_name . "\n";
164 0 0       0 if (@_ < 3) {
165 0         0 push @{$self->{games}}, $game;
  0         0  
166             }
167             else {
168 0         0 splice @{$self->{games}}, $idx, 0, $game;
  0         0  
169             }
170             #$self->changed;
171             }
172             }
173              
174             sub delete_game {
175 0     0 1 0 my ($self, $idx, $id1) = @_;
176              
177 0 0       0 croak("Player::delete_game deprecated: Use tournament->round->games list instead\n") if ($deprecate > 0);
178 0         0 my $games = $self->{games};
179 0 0       0 if (not looks_like_number($idx)) {
180 0 0       0 if (ref $idx) {
    0          
181             # $idx is actually a Game object, find its idx in our games
182             # list
183 0         0 my $game = $idx;
184 0         0 my $refaddr = refaddr($game);
185 0         0 for my $ii (0 .. $#{$games}) {
  0         0  
186 0 0       0 if (refaddr($games->[$ii]) == $refaddr) {
187 0         0 $idx = $ii;
188 0         0 last;
189             }
190             }
191             }
192             elsif ($id1) {
193 0         0 my $id0 = $idx; # idx is actually ID_0
194 0         0 for my $ii (0 .. $#{$games}) {
  0         0  
195 0 0 0     0 if (($games->[$ii]->black->id eq $id0 and
      0        
      0        
196             $games->[$ii]->white->id eq $id1) or
197             ($games->[$ii]->black->id eq $id1 and
198             $games->[$ii]->white->id eq $id0)) {
199 0         0 $idx = $ii;
200 0         0 last;
201             }
202             }
203             }
204             }
205 0 0       0 if (not looks_like_number($idx)) {
206 0 0       0 if (ref $idx) {
207 0         0 croak(sprintf "Can't find game %s vs %s in games list for %s\n",
208             $idx->white->last_name,
209             $idx->black->last_name,
210             $self->id,
211             );
212             }
213             else {
214 0   0     0 $idx ||= '<>';
215 0   0     0 $id1 ||= '<>';
216 0         0 my $id = $self->id;
217 0         0 croak("Can't find game $idx vs $id1 in games list for $id\n");
218             }
219             }
220 0         0 splice(@{$games}, $idx, 1); # remove from list
  0         0  
221             #$self->changed; # not recorded in any file, so ignore
222 0         0 return $idx;
223             }
224              
225             sub adj_rating {
226 0     0 1 0 my ($self, $round_num, $new) = @_;
227              
228 0   0     0 $round_num ||= -1; # if no round number, use last round
229 0 0       0 croak('adj_rating: round_num not valid') if ($round_num < -1);
230             # there is no round_num 0, but -1 is allowed
231              
232 0 0       0 $self->{adj_rating} = [] if (not $self->{adj_rating});
233 0         0 my $adj_rating = $self->{adj_rating};
234 0 0       0 if (@_ > 2) {
235 0         0 $self->_adj_ratings->[$round_num] = $new;
236             }
237             # rating if no adjusted rating has been set
238 0 0       0 return $self->rating if (not $self->_adj_ratings->[$round_num]);
239 0         0 return $self->_adj_ratings->[$round_num];
240             }
241              
242             sub handicap_rating {
243 0     0 1 0 my ($self, $new) = @_;
244              
245 0 0       0 if (@_ > 1) {
246 0         0 $self->{handicap_rating} = $new;
247             }
248             return defined $self->{handicap_rating}
249             ? $self->{handicap_rating}
250 0 0       0 : $self->rating;
251             }
252              
253             sub opponents {
254 0     0 1 0 my ($self) = @_;
255              
256 0 0       0 croak("Player::opponents deprecated: Use tournament->round->games list instead\n") if ($deprecate > 0);
257 0         0 my @opps = map { $_->opponent($self) } @{$self->{games}};
  0         0  
  0         0  
258             return wantarray ? @opps
259 0 0       0 : scalar @opps;
260             }
261              
262             sub defeated {
263 0     0 1 0 my ($self) = @_;
264              
265 0 0       0 croak("Player::defeated deprecated: Use tournament->player_defeated instead\n") if ($deprecate > 0);
266 0         0 my $me = refaddr $self;
267 0         0 my @defeated = map { $_->loser }
268 0 0       0 grep { defined $_->winner and
269 0         0 (refaddr($_->winner) == $me) } @{$self->{games}};
  0         0  
270             return wantarray ? @defeated
271 0 0       0 : scalar @defeated;
272             }
273              
274             sub defeated_by {
275 0     0 1 0 my ($self) = @_;
276              
277 0 0       0 croak("Player::defeated_by deprecated: Use tournament->player_defeated_by instead\n") if ($deprecate > 0);
278 0         0 my $me = refaddr $self;
279 0         0 my @defeated_by = map { $_->winner }
280 0 0       0 grep { defined $_->loser and
281 0         0 (refaddr($_->loser) == $me) } @{$self->{games}};
  0         0  
282             return wantarray ? @defeated_by
283 0 0       0 : scalar @defeated_by;
284             }
285              
286             # games with no result (usually means still playing)
287             sub no_result {
288 0     0 0 0 my ($self) = @_;
289              
290 0 0       0 croak("Player::defeated_by deprecated: Use tournament->player_no_result instead\n") if ($deprecate > 0);
291 0         0 my $me = refaddr $self;
292 0 0       0 my @no_result = map { (refaddr($_->black) == $me) ? $_->white : $_->black }
293 0   0     0 grep { not defined $_->loser and
294 0         0 not defined $_->winner } @{$self->{games}};
  0         0  
295             return wantarray ? @no_result
296 0 0       0 : scalar @no_result;
297             }
298              
299             sub wins {
300 0     0 1 0 my ($self) = @_;
301              
302 0 0       0 croak("Player::wins deprecated: Use tournament->player_wins instead\n") if ($deprecate > 0);
303 0         0 my $me = refaddr $self;
304 0   0     0 my @wins = grep { (refaddr($_->winner) || -1) == $me} @{$self->{games}};
  0         0  
  0         0  
305             return wantarray ? @wins
306 0 0       0 : scalar @wins;
307             }
308              
309             sub losses {
310 0     0 1 0 my ($self) = @_;
311              
312 0 0       0 croak("Player::losses deprecated: Use tournament->player_losses instead\n") if ($deprecate > 0);
313 0         0 my $me = refaddr $self;
314 0 0       0 my @losses = grep {defined $_->winner and
315 0         0 refaddr $_->winner != $me} @{$self->{games}};
  0         0  
316             return wantarray ? @losses
317 0 0       0 : scalar @losses;
318             }
319              
320             sub completed_games {
321 0     0 0 0 my ($self) = @_;
322              
323 0 0       0 croak("Player::completed_games deprecated: Use tournament->round->games list instead\n") if ($deprecate > 0);
324 0         0 my @games = grep { $_->winner } @{$self->{games}};
  0         0  
  0         0  
325             return wantarray ? @games
326 0 0       0 : scalar @games;
327             }
328              
329             sub drop {
330 0     0 1 0 my ($self, $round_num) = @_;
331              
332 0 0       0 croak("Player::drop deprecated: Use tournament->get_directive('DROP') instead\n") if ($deprecate > 0);
333 0 0       0 return 1 if ($self->get_flag('drop'));
334 0 0       0 if (defined $round_num) {
335 0 0       0 return 1 if ($self->get_flag("drop$round_num"));
336             }
337 0         0 return 0;
338             }
339              
340             sub bye {
341 0     0 1 0 my ($self) = @_;
342              
343 0 0       0 croak("Player::bye deprecated: Use tournament->get_directive('BYE_CANDIDATE') instead\n") if ($deprecate > 0);
344 0         0 return $self->get_flag('bye');
345             }
346              
347             sub get_flag {
348 0     0 1 0 my ($self, $key) = @_;
349              
350 0         0 my $flags = $self->{flags};
351 0         0 my $ii = 0;
352 0         0 for (@{$flags}) {
  0         0  
353 0 0       0 last if (uc $key eq uc $flags->[$ii]);
354 0         0 $ii++;
355             }
356 0         0 return $flags->[$ii];
357             }
358              
359             sub set_flag {
360 0     0 1 0 my ($self, $key) = @_;
361              
362 0         0 my $flags = $self->{flags};
363 0         0 my $ii = 0;
364 0         0 for (@{$flags}) {
  0         0  
365 0 0       0 last if (uc $key eq uc $flags->[$ii]);
366 0         0 $ii++;
367             }
368 0         0 $flags->[$ii] = $key; # add if not there, overwrite if it is
369 0         0 $self->changed;
370 0         0 return $flags->[$ii];
371             }
372              
373             sub clear_flag {
374 0     0 1 0 my ($self, $key) = @_;
375              
376 0         0 my $flags = $self->{flags};
377 0         0 my $ii = 0;
378 0         0 for (@{$flags}) {
  0         0  
379 0 0       0 last if (uc $key eq uc $flags->[$ii]);
380 0         0 $ii++;
381             }
382 0 0       0 if ($ii < @{$flags}) { # if element was found
  0         0  
383 0         0 splice @{$flags}, $ii, 1; # remove it
  0         0  
384 0         0 $self->changed;
385             }
386             }
387              
388             sub rating {
389 36     36 1 6152 my ($self) = @_;
390              
391 36         803 return Rank_to_Rating($self->rank);
392             }
393              
394             # in register.tde format
395             sub fprint_register {
396 0     0 1   my ($self, $fh) = @_;
397              
398 0           my @flags = @{$self->{flags}};
  0            
399 0 0         push(@flags, "Club=" . $self->club) if ($self->club);
400              
401 0           $fh->printf("%s %s, %s %s",
402             $self->id,
403             $self->last_name,
404             $self->first_name,
405             $self->rank,
406             );
407 0 0         $fh->printf(" %s", join(' ', @flags)) if (@flags);
408 0           my $comment = $self->comment;
409 0 0         if ($comment) {
410 0           $comment =~ s/\n/\\n/g; # prevent newlines which would mess things up
411 0           $comment =~ s/^\s*(.*?)\s*$/$1/; # remove preceding and trailing whitespace
412 0           $fh->print(" # $comment");
413             }
414 0           $fh->print("\n");
415             }
416              
417             # in tdlist format
418             sub fprint_tdlist {
419 0     0 1   my ($self, $fh) = @_;
420              
421 0           $fh->printf("%s, %s %s %s %s %s %s %s\n",
422             $self->last_name,
423             $self->first_name,
424             $self->id,
425             $self->membership,
426             $self->rank,
427             $self->date,
428             $self->club,
429             $self->state,
430             );
431             }
432              
433             1;
434              
435             __END__