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              
3             # Last Edit: 2010 1月 01, 18時07分25秒
4             # $Id: $
5              
6 30     30   129507 use warnings;
  30         56  
  30         1485  
7 30     30   150 use strict;
  30         46  
  30         601  
8 30     30   455 use Carp;
  30         66  
  30         1943  
9              
10 30     30   165 use List::Util qw/first/;
  30         51  
  30         1885  
11 30     30   977 use List::MoreUtils qw/any/;
  30         11691  
  30         178  
12              
13 30     30   13047 use Games::Tournament::Swiss::Config;
  30         53  
  30         1345  
14              
15 30 100       1599 use constant ROLES => @Games::Tournament::Swiss::Config::roles?
16             @Games::Tournament::Swiss::Config::roles:
17 30     30   147 Games::Tournament::Swiss::Config->roles;
  30         61  
18              
19 30     30   148 use base qw/Games::Tournament/;
  30         44  
  30         22608  
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             =head1 VERSION
28              
29             Version 0.04
30              
31             =cut
32              
33             our $VERSION = '0.05';
34              
35             =head1 SYNOPSIS
36              
37             pray if $preference->role eq 'Black' and $preference->strength eq 'Strong';
38              
39             =head1 DESCRIPTION
40              
41             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.
42             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
43              
44             =head1 METHODS
45              
46             =head2 new
47              
48             $pref = Games::Tournament::Contestant::Swiss::Preference->new(
49             difference => 0, sign => 'Black', round => 0 );
50              
51             The default difference is 0. The default sign is ''.
52              
53             =cut
54              
55             sub new {
56 1931     1931 1 133712 my $self = shift;
57 1931         2805 my %args = @_;
58 1931 100       5349 $args{sign} = '' unless $args{sign};
59 1931 100       4346 $args{difference} = 0 unless $args{difference};
60 1931         3318 my $pref = bless \%args, $self;
61 1931         5825 return $pref;
62             }
63              
64              
65             =head2 update
66              
67             $pref->update( \@oldRoles )
68              
69             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 .
70              
71             =cut
72              
73             sub update {
74 749     749 1 1877 my $self = shift;
75 749         970 my $roles = shift;
76 749         976 my $message = "Preference update: ";
77 749 100 66 1142   4139 return unless $roles->[-1] and any { $roles->[-1] eq $_ } ROLES;
  1142         3544  
78 727         2575 my @reverseRoles = reverse @$roles;
79 727         945 my $lastRole = $reverseRoles[0];
80 727         962 my $before = $reverseRoles[1];
81 727         877 my $oneBeforeThat = $reverseRoles[2];
82 727 100 100     3873 $message .= "3-game run as $lastRole\n" if $before and $oneBeforeThat and
      100        
      100        
83             $oneBeforeThat eq $before and $before eq $lastRole;
84 727         1509 my $difference = $self->difference;
85 727         1497 my $sign = $self->sign;
86 727     1004   3120 my $otherDirection = first { $_ ne $sign } ROLES;
  1004         1781  
87 727 100 66     4307 if ( not $sign or not defined $difference ) {
    100          
    50          
88 109         153 $sign = $lastRole;
89 109         189 $difference = 1;
90             }
91             elsif ( $lastRole eq $otherDirection ) {
92 490 100       1060 if ( $difference > 0 ) {
    50          
93 288         347 $difference--;
94 288 100       677 if ( $difference == 0 ) {
95 243         637 $sign = $otherDirection;
96             }
97             }
98             elsif ( $difference == 0 ) {
99 202         256 $sign = $lastRole;
100 202         321 $difference = 1;
101             }
102             else {
103 0         0 die "$difference games more as $sign after $lastRole role?";
104             }
105             }
106             elsif ( $lastRole eq $sign ) {
107 128         174 $difference++;
108 128 100       316 if ( $difference > 2 ) {
109 32         77 $message .= "$difference games more as $lastRole\n";
110             }
111             }
112             else {
113 0         0 die
114             "$lastRole role update on ${difference}-game difference in $sign role?";
115             }
116 727         1544 $self->sign($sign);
117 727         1464 $self->difference($difference);
118 727 100       1317 if ($before) { $self->lastTwo( [ $before, $lastRole ] ); }
  529         1542  
119 198         583 else { $self->lastTwo( [$lastRole] ); }
120             }
121              
122              
123             =head2 asString
124              
125             $pref->asString
126              
127             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.
128              
129             =cut
130              
131              
132             sub asString {
133 0     0 1 0 my $self = shift;
134 0 0       0 my $string = $self->sign eq (ROLES)[0] ? '+' :
    0          
135             $self->sign eq (ROLES)[1] ? '-' : '';
136 0         0 $string .= $self->difference;
137             }
138              
139              
140             =head2 difference
141              
142             $pref->difference(2)
143              
144             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.
145              
146             =cut
147              
148              
149             sub difference {
150 6729     6729 1 8302 my $self = shift;
151 6729         8046 my $difference = shift();
152 6729 100       14231 $self->{difference} = $difference if defined $difference;
153 6729         13853 return $self->{difference};
154             }
155              
156              
157             =head2 sign
158              
159             $pref->sign('Black')
160             $pref->sign('-')
161              
162             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.
163              
164             =cut
165              
166             sub sign {
167 76486     76486 1 95405 my $self = shift;
168 76486   66     191464 my $sign = shift() || $self->{sign};
169 76486         168400 my %abbrev = ( White => '+', Black => '-' );
170 76486         177649 my %expando = reverse %abbrev;
171 76486 50       172063 $sign = $expando{$sign} if $expando{$sign};
172 76486         108401 $self->{sign} = $sign;
173 76486         303510 return $sign;
174             }
175              
176              
177             =head2 strength
178              
179             $pref->strength
180              
181             Gets the strength of the preference, 'Mild,' 'Strong,' or 'Absolute.'
182              
183             =cut
184              
185             sub strength {
186 3954     3954 1 5440 my $self = shift;
187 3954         7626 my @degree = qw/Mild Strong Absolute/;
188 3954         7451 my $diff = $self->difference;
189 3954         5807 my $strength = $degree[$diff];
190 3954 100       7698 $strength = 'Absolute' if $diff > 2 ;
191 3954         4392 my @lastRoles = @{ $self->lastTwo };
  3954         7072  
192 3954 100       9025 if ( @lastRoles == 2 ) {
193 3322 100       7581 $strength = 'Absolute' if $lastRoles[0] eq $lastRoles[1];
194             }
195 3954         21782 return $strength;
196             }
197              
198              
199             =head2 role
200              
201             $pref->role
202              
203             Gets the role which the preference entitles/requires the player to take in the next round. Not defined if sign is ''.
204              
205             =cut
206              
207             sub role {
208 30575     30575 1 39354 my $self = shift;
209 30575         33733 my $role;
210 30575 100   43056   56636 $role = first { $_ ne $self->sign } ROLES if $self->sign;
  43056         84968  
211 30575         74515 my @lastRoles = @{ $self->lastTwo };
  30575         58371  
212 30575 100 100     129365 if ( @lastRoles == 2 and $lastRoles[0] eq $lastRoles[1] )
213             {
214 3909     5903   15254 $role = first { $_ ne $lastRoles[0] } ROLES;
  5903         9894  
215             }
216 30575         159517 return $role;
217             }
218              
219              
220             =head2 round
221              
222             $pref->round
223              
224             Sets/gets the round in this game up to which play is used to calculate the preference . The default is 0.
225              
226             =cut
227              
228             sub round {
229 0     0 1 0 my $self = shift;
230 0   0     0 my $round = shift() || $self->{round};
231 0         0 $self->{round} = $round;
232 0         0 return $round;
233             }
234              
235              
236             =head2 lastTwo
237              
238             $pref->lastTwo
239              
240             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.
241              
242             =cut
243              
244             sub lastTwo {
245 35301     35301 1 44131 my $self = shift;
246 35301         43376 my $lastTwo = shift;
247 35301 100       89223 if ( defined $lastTwo ) { $self->{lastTwo} = $lastTwo; }
  727 100       4097  
248 31130         80981 elsif ( $self->{lastTwo} ) { return $self->{lastTwo}; }
249 3444         7269 else { return []; }
250             }
251              
252             =head1 AUTHOR
253              
254             Dr Bean, C<< >>
255              
256             =head1 BUGS
257              
258             Please report any bugs or feature requests to
259             C, or through the web interface at
260             L.
261             I will be notified, and then you'll automatically be notified of progress on
262             your bug as I make changes.
263              
264             =head1 SUPPORT
265              
266             You can find documentation for this module with the perldoc command.
267              
268             perldoc Games::Tournament::Contestant::Swiss::Preference
269              
270             You can also look for information at:
271              
272             =over 4
273              
274             =item * AnnoCPAN: Annotated CPAN documentation
275              
276             L
277              
278             =item * CPAN Ratings
279              
280             L
281              
282             =item * RT: CPAN's request tracker
283              
284             L
285              
286             =item * Search CPAN
287              
288             L
289              
290             =back
291              
292             =head1 ACKNOWLEDGEMENTS
293              
294             =head1 COPYRIGHT & LICENSE
295              
296             Copyright 2006 Dr Bean, all rights reserved.
297              
298             This program is free software; you can redistribute it and/or modify it
299             under the same terms as Perl itself.
300              
301             =cut
302              
303             1; # End of Games::Tournament::Contestant::Preference
304              
305             # vim: set ts=8 sts=4 sw=4 noet: