File Coverage

blib/lib/Chess/GameClock/GclkCounter.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             ####-----------------------------------
3             ### File : GclkCounter.pm
4             ### Author : Ch.Minc
5             ### Purpose : Package for Counter
6             ### Version : 1.0 2006/1/26
7             ### copyright GNU license
8             ####-----------------------------------
9              
10             package GclkCounter ;
11              
12             our $VERSION = '1.0' ;
13              
14             require Exporter ;
15 1     1   5259 use warnings;
  1         2  
  1         34  
16 1     1   5 use strict;
  1         2  
  1         40  
17              
18              
19 1     1   464987 use Time::HiRes qw(gettimeofday tv_interval);
  1         2036  
  1         7  
20 1     1   695 use Tk ;
  0            
  0            
21             use Tk::Dialog ;
22              
23             use Chess::GameClock::GclkData qw(:tout) ;
24              
25             my %cad=%GclkData::cad ;
26              
27             our @ISA=qw(Exporter) ;
28              
29             our @EXPORT_OK=qw (&capture &stop $start) ;
30              
31             sub new {
32             my ($class,@args)=@_ ;
33             my $self=[{}] ;
34             return bless ($self,$class) ;
35             }
36              
37              
38             sub init {
39             #build the counter data array
40             #usage $self->init(@values) i.e cadence color
41             my ($self,$arg,$col)=@_ ;
42              
43             #my @default= ( {ct=>'0', #cadence 1
44             # mv=>'0', # if 0 means KO else number of moves
45             # b=>'0', # fisher ou bronstein
46             # f=>'0',
47             # byo=>'0' # byo mode no time glue
48             # }
49             # ) ;
50              
51             my $rec;
52             my @default ;
53             my ($t,$c,$i)=split(' ',$arg) ;
54             # concaténation des cadences si Cadence
55             if ($c =~ /Cadence(\d)/) {
56             for (1..$1) {
57             @default=(@default,$cad{$t}{"Cadence" . $_}[$i]) ;
58             }
59             } else {
60             for my $j (0..$#{$cad{$t}{$c}[$i]} ) {
61             @default=(@default,$cad{$t}{$c}[$i][$j]);
62             }
63             ;
64             }
65              
66             for (0..$#default) {
67             my $st=$default[$_]{ct} ;
68             $default[$_]{'ct'}=eval($st) ;warn $@ if $@;
69             }
70              
71             @{$self}=( {state=>'Off',
72             newstate=>'Off',
73             color=>$col ,
74             mouse=>'',
75             cmpt=>'0', # compteur temps joué
76             ct=>'0' , # temps disponible
77             mvt=>'0', # number of moves
78             mv=>'0', # number of moves inside a cadence
79             ts=>'0', # timestamp
80             indc=>'1'}) ;
81              
82             for my $k (0..$#default) {
83             map {$self->[$k+1]{$_}=$default[$k]{$_} } (qw/ct mv b f byo/) ;
84             }
85              
86             # use Dumpvalue;
87             # my $dumper = new Dumpvalue;
88             # $dumper->dumpValues(@{$self});
89             }
90              
91             sub cntupdate {
92             # active increment of counter
93             my $self=shift ;
94             my $tod=shift ;
95             my $icad=$self->[0]{indc} ; # indc pointe sur la cadence en cours
96              
97             if ( $self->[0]{state} eq "Off" && $self->[0]{newstate} eq "On") {
98             # $self->[0]{b}= $self->[$icad]{b} ; ### f ???
99             $self->[0]{state}= $self->[0]{newstate} ;
100             $self->[0]{ts}=$tod ;
101             }
102              
103             # add on time when fisher is on and elapsed time or substracted
104             # bronstein time
105             if ( $self->[0]{state} eq "On" && $self->[0]{newstate} eq "Off") {
106             my $delta=tv_interval($self->[0]{ts});
107             $self->[0]{cmpt}+=$delta ;
108              
109             if ($self->[$icad]{byo}==1) {
110             $self->[0]{ct}-=$delta ;
111             $self->[0]{ct}+=$self->[$icad]{f}+ ($delta <= $self->[$icad]{b} ?$delta: $self->[$icad]{b}) ;
112             }
113             $self->[0]{state}= $self->[0]{newstate} ;
114              
115             # update move
116             ($self->[0]{mv})++ ;
117             ($self->[0]{mvt})++ ;
118              
119             # check limits
120             #if mv = 0 means KO unless byo==0
121             #if mv !=0 && last cadence loop on that cadence
122              
123             if (( $self->[0]{mv} == $self->[$icad]{mv}) && $self->[$icad]{mv} !=0 ) {
124              
125             # update time limit & next cadence ,time checked in on-on
126            
127             $self->[0]{mv}=0 ;
128             $self->[0]{indc}=$icad<$#{$self}? ++$icad : $#{$self} ;
129             if ( $self->[$icad]{byo} ==0 && $self->[$icad]{b} !=0 ) { # japonais
130             $self->[0]{ct}=
131             $self->[$icad]{b}*(int($self->[0]{ct}/$self->[$icad]{b})-int($delta/$self->[$icad]{b}));
132             } else {
133             $self->[0]{ct}=$self->[$icad]{ct}+ $self->[0]{ct}*$self->[$icad]{byo} ; # si b=0 canadien
134              
135             }
136             }
137            
138              
139             # byo-yomi japonais
140             # deux cadences main time
141             if ($self->[$icad]{mv} ==0 && $self->[$icad]{byo} ==0 ) {
142             $self->[0]{ct} -=$delta ;
143             # main time épuisé passage au byo-yomi (dans $self->[icad]{b} !=0 )
144             if ($self->[0]{ct} <= 0 ) {
145             $self->[0]{mv}=0 ;
146             $self->[0]{indc}=$icad<$#{$self}? ++$icad : $#{$self} ;
147             $self->[0]{ct} +=$self->[$icad]{ct} ;
148             # normalisation byo-yomi
149             # my $d1=int($self->[0]{ct}/$self->[$icad]{b}) ;
150             # my $d2=int($delta/$self->[$icad]{b}) ;
151             # $self->[0]{ct}=$self->[$icad]{b}*($d1-$d2) ;
152             }
153              
154             }
155              
156             }
157              
158              
159             # if( $self->[0]{state} eq "Off" && $self->[0]{newstate} eq "Off"){
160             # # nothing to do
161             #$self->print ;
162             # }
163              
164              
165             if ( $self->[0]{state} eq "On" && $self->[0]{newstate} eq "On") {
166            
167             my $tchk ;
168             # time limit
169             if ($self->[$icad]{byo} ) {
170             $tchk=$self->[$icad]{b} + $self->[0]{ct}-tv_interval($self->[0]{ts}) ;
171              
172             } else {
173             # valable avant le byo-yomi -----$icad=2
174             $tchk=$self->[0]{ct}-tv_interval($self->[0]{ts}) ;
175            
176             }
177             unless (0<=$tchk ) {
178             print "lost \n" ;
179             my $lmw=MainWindow->new ;
180             $lmw->withdraw ;
181             $lmw->messageBox(-icon =>'info',
182             -message =>"GameOver for (Dépassement de temps pour les) $self->[0]{color}",
183             -title => 'GameClock Warning',
184             -type => 'Ok',
185             -default => 'Ok' ) ;
186             $lmw->destroy ;
187             return ;
188             }
189             }
190              
191             }
192             sub start{
193              
194             #$cnt->start($cnt,$cnt_black,Mouse)
195             #bouton start (re)initialise
196             #mais ce sont les Noirs mettent en marche
197             my ($self,$wself,$bself,$mw,$white_mv,$black_mv)=@_ ;
198              
199             undef($wself->[0]{mouse}) ;
200             undef($bself->[0]{mouse}) ;
201             $wself->[0]{indc}=1 ;
202             $bself->[0]{indc}=1 ;
203             # time limits
204             $wself->[0]{ct}=$wself->[1]{ct} ;
205             $bself->[0]{ct}=$bself->[1]{ct} ;
206             $wself->[0]{cmpt}=0 ;
207             $bself->[0]{cmpt}=0 ;
208             # reset move counters
209             $wself->[0]{mv}=0 ;
210             $bself->[0]{mv}=0 ;
211             $wself->[0]{mvt}=0 ;
212             $bself->[0]{mvt}=0 ;
213             # state
214             $wself->[0]{newstate}='Off';
215             $bself->[0]{newstate}='Off' ;
216             $wself->[0]{state}='Off';
217             $bself->[0]{state}='Off' ;
218             # Fix a bug :move counter don't show the value
219             # after a setting with ®lage ?
220             $white_mv->configure(-textvariable=>\$wself->[0]{mvt}) ;
221             $black_mv->configure(-textvariable=>\$bself->[0]{mvt}) ;
222              
223             $mw->bind('',[\&capture, Ev('s'),$wself,$bself]) ;
224             ##
225             print "Counters ready to start\n" ;
226              
227             }
228              
229             sub stop{
230             our @pile ;
231             my ($mw,$but,$wself,$bself,@arg)=@_ ;
232              
233             # etat du bouton
234             my $col=$but->cget(-background) ;
235             if ($col eq 'red') {
236             # etat rouge -arret
237             $but->configure(-background=>pop @pile) ;
238             $but->configure(-activebackground=>pop @pile) ;
239             $bself->[0]{state}=pop @pile ;
240             $wself->[0]{state}=pop @pile ;
241              
242             # actualise le timestamp
243             my $self=$wself->[0]{state} eq 'On'?$wself:$bself ;
244             $self->[0]{ts}=[gettimeofday];
245             $mw->bind('',[\&capture, Ev('s'),$wself,$bself]) ;
246             } else {
247             # etat non rouge - marche
248             # actualise les compteurs- passe à l'arret
249             my $self=$wself->[0]{state} eq 'On'?$wself:$bself ;
250             my $delta=tv_interval($self->[0]{ts});
251             $self->[0]{cmpt}+=$delta ;
252             $self->[0]{ct}-=$delta ;
253             $mw->bind('',"") ;
254              
255             # sauve l'etat du bouton et des compteurs
256             push(@pile,$wself->[0]{state} ) ;
257             push(@pile,$bself->[0]{state} ) ;
258             push(@pile,$but->cget(-activebackground)) ;
259             push(@pile,$col) ;
260              
261             # bloque les compteurs
262             $wself->[0]{state}='Off' ;
263             $bself->[0]{state}='Off' ;
264             $but->configure(-activebackground=>'red') ;
265             $but->configure(-background=>'red') ;
266             }
267             ;
268             ## a faire reactiver start en arret
269             #print "pile:@pile \n" ;
270             }
271              
272             sub capture{
273             my ($hashref,$mouse,$whites,$blacks )=@_ ;
274             my $tod=[gettimeofday];
275             my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(time);
276             # appel à l'init sans click
277             $mouse=~ s/-// ; # Ev('s') return Bn-
278             if (!defined($whites->[0]{mouse})) {
279             my $cb=$mouse eq 'B1' ;
280             ($mouse eq 'B1') ? $blacks->[0]{mouse}='B1': $whites->[0]{mouse}='B1' ;
281             ($mouse eq 'B3') ? $blacks->[0]{mouse}='B3': $whites->[0]{mouse}='B3' ;
282             }
283             # set the new counters state
284             if ( $mouse eq $whites->[0]{mouse}) {
285             $whites->[0]{newstate} ="Off" ;
286             $blacks->[0]{newstate} ="On" ;
287             } else {
288             $whites->[0]{newstate} ="On" ;
289             $blacks->[0]{newstate} ="Off" ;
290             }
291             $whites->cntupdate($tod) ;
292             $blacks->cntupdate($tod) ;
293              
294             # print into the log
295              
296             my $str=sprintf("%02d:%02d:%02d",$hour,$min,$sec) ;
297             print
298             "Time: $str \n
299             Whites move: $whites->[0]{mvt} whites time Av.:$whites->[0]{ct} #$whites->[0]{mv}\n
300             Blacks move: $blacks->[0]{mvt} Blacks time Av.:$blacks->[0]{ct} #$blacks->[0]{mv}\n" ;
301              
302             }
303              
304             sub print{
305             my $self=shift ;
306             #print " Counter elem: $$self[0]{state} \n" ;
307             #print " Counter elem: $self->[0]->{state} \n" ;
308             #print " Counter elem: $self->[0]{state} \n" ;
309             # print the whole thing with refs
310             for my $href ( @{$self} ) {
311             print "{ ";
312             for my $t ( keys %$href ) {
313             print "$t=$href->{$t} ";
314             }
315             print "}\n";
316             }
317             }
318              
319              
320             =head1 NAME
321              
322             GclkCounter - The Heart of GameClock
323              
324             =head1 VERSION
325              
326             Version 1.0
327              
328             =cut
329              
330             =head1 SYNOPSIS
331              
332             This module does everythings at counter level.
333             It makes counters,inits them, update them, captures events,
334             start , halt , eventually print the internal datas
335              
336             use GclkCounter;
337              
338             $whites=GclkCounter->new ;
339             $whites->init($arg,$color) ;
340             $whites-> cntupdate{$timestamp);
341             $whites->print ;
342             # the functions hereafter are only used inside callbacks
343             &start($whites,$blacks,$mainwindow,$white_move_button,$black_move_button)= ;
344             &stop($halt_button,$whites,$blacks) ;
345             &capture($mouse_event,$whites,$blacks ) ;
346              
347             =head1 EXPORT
348              
349             &capture
350             &stop
351             $start
352              
353             =head1 FUNCTIONS
354              
355             =head2 new ;
356              
357             Create object GclkCounter
358              
359             =cut
360            
361             =head2 init
362              
363             Get the parameters from GameClock directly or via Gamesettings
364             and adapts the datas for the counters
365              
366             =head2 cntupdate
367              
368             When an event more precisely a mouse button is
369             released the state of the counter changes.
370             This determines the following actions:
371              
372             =over 4
373              
374             =item * Change the counter states.
375              
376             =item * Check times
377              
378             =item * Update the time counters
379              
380             =item * Update the move counters
381              
382             =item * Update the sequence pointers
383              
384             =back
385              
386             =head2 capture
387              
388             When a mouse event occurs the first time
389             after enabling the start mode, it determines
390             the mouse button for each player, knowing that
391             the Blacks must push the button at first.
392             It set the newsate of each counter accorging
393             to the mouse button pressed, and after that,
394             it gets a timestamp for calling the methode cntupdate.
395              
396             =cut
397              
398             =head2 start
399              
400             Initialization of the program to begin
401             the counting mode.
402              
403             =cut
404              
405             =head2 stop
406              
407             This routines halt counters , necessary if
408             one player receive a phone call in a friendly
409             situation ;=) or in some case, when people need
410             that an arbiter comes.
411              
412             =cut
413              
414             =head2 print
415              
416             Could help for people that wants add new cadences.
417              
418             =cut
419              
420              
421             =head1 AUTHOR
422              
423             Charles Minc, C<< >>
424              
425             =head1 BUGS
426              
427             Please report any bugs or feature requests to
428             C, or through the web interface at
429             L.
430             I will be notified, and then you'll automatically be notified of progress on
431             your bug as I make changes.
432              
433             =head1 SUPPORT
434              
435             You can find documentation for this module with the perldoc command.
436              
437             perldoc GameClock
438              
439             You can also look for information at:
440              
441             =over 4
442              
443             =item * AnnoCPAN: Annotated CPAN documentation
444              
445             L
446              
447             =item * CPAN Ratings
448              
449             L
450              
451             =item * RT: CPAN's request tracker
452              
453             L
454              
455             =item * Search CPAN
456              
457             L
458              
459             =back
460              
461             =head1 ACKNOWLEDGEMENTS
462              
463             =head1 COPYRIGHT & LICENSE
464              
465             Copyright 2006 Charles Minc, all rights reserved.
466              
467             This program is free software; you can redistribute it and/or modify it
468             under the same terms as Perl itself.
469              
470             =cut
471              
472             1; # End of GclkCounter