File Coverage

blib/lib/Games/Tournament/Contestant/Swiss/Preference.pm
Criterion Covered Total %
statement 98 107 91.5
branch 41 48 85.4
condition 18 24 75.0
subroutine 19 21 90.4
pod 9 9 100.0
total 185 209 88.5


line stmt bran cond sub pod time code
1             package Games::Tournament::Contestant::Swiss::Preference;
2             $Games::Tournament::Contestant::Swiss::Preference::VERSION = '0.21';
3             # Last Edit: 2016 Jan 01, 13:45:02
4             # $Id: $
5              
6 30     30   128683 use warnings;
  30         50  
  30         1459  
7 30     30   149 use strict;
  30         47  
  30         596  
8 30     30   538 use Carp;
  30         61  
  30         2101  
9              
10 30     30   196 use List::Util qw/first/;
  30         50  
  30         1913  
11 30     30   910 use List::MoreUtils qw/any/;
  30         11651  
  30         183  
12              
13 30     30   13091 use Games::Tournament::Swiss::Config;
  30         52  
  30         1383  
14              
15 30 100       1533 use constant ROLES => @Games::Tournament::Swiss::Config::roles?
16             @Games::Tournament::Swiss::Config::roles:
17 30     30   144 Games::Tournament::Swiss::Config->roles;
  30         66  
18              
19 30     30   168 use base qw/Games::Tournament/;
  30         44  
  30         22657  
20              
21             # use overload qw/0+/ => 'next', qw/""/ => 'value', fallback => 1;
22              
23             =head1 NAME
24              
25             Games::Tournament::Contestant::Swiss::Preference A competitor's right to a role.
26              
27             =cut
28              
29             =head1 SYNOPSIS
30              
31             pray if $preference->role eq 'Black' and $preference->strength eq 'Strong';
32              
33             =head1 DESCRIPTION
34              
35             The preference, or expectation/right/duty one has with reference to a role, eg White, in the next round depends on the difference between the number of games previously played in it and in the alternative roles, and is either Mild, Strong, or Absolute. The more games played in other roles than in this role, the greater the right/duty to play the next game in this role. The FIDE Swiss Rules (C04.1) represent the difference as the number of Games as White minus the number as Black, so a greater number of games as Black is a negative number and of White a positive number. For equal number of games, +0 indicates the last game was as White, and -0 indicates the last game was as Black. So +0 represents a Mild preference for Black and -0 for White. This implementation uses a 'sign' field to perform the same function as the +/- sign.
36             As an API, the strength method returns 'Mild', 'Strong', or 'Absolute' and the role method returns 'Black', 'White', or whatever the preferred role is, respecting the 2 consecutive games in the same role rule. A7
37              
38             =head1 METHODS
39              
40             =head2 new
41              
42             $pref = Games::Tournament::Contestant::Swiss::Preference->new(
43             difference => 0, sign => 'Black', round => 0 );
44              
45             The default difference is 0. The default sign is ''.
46              
47             =cut
48              
49             sub new {
50 1931     1931 1 136202 my $self = shift;
51 1931         2957 my %args = @_;
52 1931 100       6005 $args{sign} = '' unless $args{sign};
53 1931 100       4827 $args{difference} = 0 unless $args{difference};
54 1931         3497 my $pref = bless \%args, $self;
55 1931         5904 return $pref;
56             }
57              
58              
59             =head2 update
60              
61             $pref->update( \@oldRoles )
62              
63             Updates the difference (ie, the internal representation of preference) on the basis of the last role (and second-last role) in \@oldRoles. A minimal sanity check is performed. \@oldRoles is a history of roles in previous rounds, and it is expected only the last role of this history has not yet been used to update the preference. That is, this method must be used round-by-round to keep a players preference up to date. However, the second-last role (in addition to the last role) is also needed to determine the preference in cases when the same role was taken in the last 2 games. So for updates after the second round, make sure the history is at least 2 elements long. Byes and unplayed games have no effect on the preference, so make sure that roles in unplayed games don't make it into oldRoles A5, F2 .
64              
65             =cut
66              
67             sub update {
68 749     749 1 1814 my $self = shift;
69 749         923 my $roles = shift;
70 749         981 my $message = "Preference update: ";
71 749 100 66 1142   4099 return unless $roles->[-1] and any { $roles->[-1] eq $_ } ROLES;
  1142         3736  
72 727         2570 my @reverseRoles = reverse @$roles;
73 727         1006 my $lastRole = $reverseRoles[0];
74 727         860 my $before = $reverseRoles[1];
75 727         871 my $oneBeforeThat = $reverseRoles[2];
76 727 100 100     3726 $message .= "3-game run as $lastRole\n" if $before and $oneBeforeThat and
      100        
      100        
77             $oneBeforeThat eq $before and $before eq $lastRole;
78 727         1526 my $difference = $self->difference;
79 727         1540 my $sign = $self->sign;
80 727     1004   3044 my $otherDirection = first { $_ ne $sign } ROLES;
  1004         1719  
81 727 100 66     4375 if ( not $sign or not defined $difference ) {
    100          
    50          
82 109         159 $sign = $lastRole;
83 109         154 $difference = 1;
84             }
85             elsif ( $lastRole eq $otherDirection ) {
86 486 100       1063 if ( $difference > 0 ) {
    50          
87 288         342 $difference--;
88 288 100       638 if ( $difference == 0 ) {
89 243         385 $sign = $otherDirection;
90             }
91             }
92             elsif ( $difference == 0 ) {
93 198         255 $sign = $lastRole;
94 198         298 $difference = 1;
95             }
96             else {
97 0         0 die "$difference games more as $sign after $lastRole role?";
98             }
99             }
100             elsif ( $lastRole eq $sign ) {
101 132         170 $difference++;
102 132 100       302 if ( $difference > 2 ) {
103 32         80 $message .= "$difference games more as $lastRole\n";
104             }
105             }
106             else {
107 0         0 die
108             "$lastRole role update on ${difference}-game difference in $sign role?";
109             }
110 727         1518 $self->sign($sign);
111 727         1441 $self->difference($difference);
112 727 100       1292 if ($before) { $self->lastTwo( [ $before, $lastRole ] ); }
  529         1521  
113 198         540 else { $self->lastTwo( [$lastRole] ); }
114             }
115              
116              
117             =head2 asString
118              
119             $pref->asString
120              
121             The difference as a string, ^[+-][012]$. '0' represents a mild preference, '1' a strong one and '2' an absolute one. '-' represents a preference for White, or the first element of @Games::Tournament::Swiss::Config::roles, and '+' represents a preference for Black or the second element. A player may have an absolute preference even if the difference is 0, because it played the previous 2 rounds in the other color.
122              
123             =cut
124              
125              
126             sub asString {
127 0     0 1 0 my $self = shift;
128 0 0       0 my $string = $self->sign eq (ROLES)[0] ? '+' :
    0          
129             $self->sign eq (ROLES)[1] ? '-' : '';
130 0         0 $string .= $self->difference;
131             }
132              
133              
134             =head2 difference
135              
136             $pref->difference(2)
137              
138             Sets/gets the value of the difference in games played in one role over those played in other alternative roles. Equals either 0,1,2.
139              
140             =cut
141              
142              
143             sub difference {
144 6843     6843 1 8404 my $self = shift;
145 6843         8036 my $difference = shift();
146 6843 100       14373 $self->{difference} = $difference if defined $difference;
147 6843         14261 return $self->{difference};
148             }
149              
150              
151             =head2 sign
152              
153             $pref->sign('Black')
154             $pref->sign('-')
155              
156             Sets/gets the role which the player has taken more often, or more recently, than other alternative roles. The preference is thus for the other role.
157              
158             =cut
159              
160             sub sign {
161 76723     76723 1 93458 my $self = shift;
162 76723   66     189313 my $sign = shift() || $self->{sign};
163 76723         166074 my %abbrev = ( White => '+', Black => '-' );
164 76723         169287 my %expando = reverse %abbrev;
165 76723 50       171612 $sign = $expando{$sign} if $expando{$sign};
166 76723         105236 $self->{sign} = $sign;
167 76723         294812 return $sign;
168             }
169              
170              
171             =head2 strength
172              
173             $pref->strength
174              
175             Gets the strength of the preference, 'Mild,' 'Strong,' or 'Absolute.'
176              
177             =cut
178              
179             sub strength {
180 3954     3954 1 5262 my $self = shift;
181 3954         7390 my @degree = qw/Mild Strong Absolute/;
182 3954         7125 my $diff = $self->difference;
183 3954         5591 my $strength = $degree[$diff];
184 3954 100       7678 $strength = 'Absolute' if $diff > 2 ;
185 3954         4346 my @lastRoles = @{ $self->lastTwo };
  3954         7182  
186 3954 100       8887 if ( @lastRoles == 2 ) {
187 3322 100       7653 $strength = 'Absolute' if $lastRoles[0] eq $lastRoles[1];
188             }
189 3954         21541 return $strength;
190             }
191              
192              
193             =head2 role
194              
195             $pref->role
196              
197             Gets the role which the preference entitles/requires the player to take in the next round. Not defined if sign is ''.
198              
199             =cut
200              
201             sub role {
202 30616     30616 1 39480 my $self = shift;
203 30616         32888 my $role;
204 30616 100   43138   55503 $role = first { $_ ne $self->sign } ROLES if $self->sign;
  43138         83091  
205 30616         72465 my @lastRoles = @{ $self->lastTwo };
  30616         57860  
206 30616 100 100     124466 if ( @lastRoles == 2 and $lastRoles[0] eq $lastRoles[1] )
207             {
208 3909     5903   14975 $role = first { $_ ne $lastRoles[0] } ROLES;
  5903         9343  
209             }
210 30616         153587 return $role;
211             }
212              
213              
214             =head2 round
215              
216             $pref->round
217              
218             Sets/gets the round in this game up to which play is used to calculate the preference . The default is 0.
219              
220             =cut
221              
222             sub round {
223 0     0 1 0 my $self = shift;
224 0   0     0 my $round = shift() || $self->{round};
225 0         0 $self->{round} = $round;
226 0         0 return $round;
227             }
228              
229              
230             =head2 lastTwo
231              
232             $pref->lastTwo
233              
234             Sets/gets a list of the roles in the last 2 games. If the 2 roles are the same, there is an absolute preference for the other role.
235              
236             =cut
237              
238             sub lastTwo {
239 35342     35342 1 42644 my $self = shift;
240 35342         39975 my $lastTwo = shift;
241 35342 100       88694 if ( defined $lastTwo ) { $self->{lastTwo} = $lastTwo; }
  727 100       4040  
242 31130         78532 elsif ( $self->{lastTwo} ) { return $self->{lastTwo}; }
243 3485         7492 else { return []; }
244             }
245              
246             =head1 AUTHOR
247              
248             Dr Bean, C<< >>
249              
250             =head1 BUGS
251              
252             Please report any bugs or feature requests to
253             C, or through the web interface at
254             L.
255             I will be notified, and then you'll automatically be notified of progress on
256             your bug as I make changes.
257              
258             =head1 SUPPORT
259              
260             You can find documentation for this module with the perldoc command.
261              
262             perldoc Games::Tournament::Contestant::Swiss::Preference
263              
264             You can also look for information at:
265              
266             =over 4
267              
268             =item * AnnoCPAN: Annotated CPAN documentation
269              
270             L
271              
272             =item * CPAN Ratings
273              
274             L
275              
276             =item * RT: CPAN's request tracker
277              
278             L
279              
280             =item * Search CPAN
281              
282             L
283              
284             =back
285              
286             =head1 ACKNOWLEDGEMENTS
287              
288             =head1 COPYRIGHT & LICENSE
289              
290             Copyright 2006 Dr Bean, all rights reserved.
291              
292             This program is free software; you can redistribute it and/or modify it
293             under the same terms as Perl itself.
294              
295             =cut
296              
297             1; # End of Games::Tournament::Contestant::Preference
298              
299             # vim: set ts=8 sts=4 sw=4 noet: