File Coverage

blib/lib/Games/Go/AGA/DataObjects/Player.pm
Criterion Covered Total %
statement 65 178 36.5
branch 11 76 14.4
condition 3 23 13.0
subroutine 15 30 50.0
pod 17 22 77.2
total 111 329 33.7


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