File Coverage

blib/lib/Chess/ChessKit/Trad.pm
Criterion Covered Total %
statement 18 198 9.0
branch 0 100 0.0
condition 0 21 0.0
subroutine 6 12 50.0
pod n/a
total 24 331 7.2


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             ####-----------------------------------
3             ### File : Trad.pm
4             ### Author : C.Minc
5             ### Purpose : chess translator
6             ### Version : 1.1 2007/12/22
7             ### copyright GNU license
8             ####-----------------------------------
9              
10              
11             package Trad ;
12              
13             #package Chess::ChessKit::Trad ;
14              
15 1     1   1686 use warnings;
  1         3  
  1         40  
16 1     1   7 use strict;
  1         2  
  1         68  
17              
18             =head1 NAME
19              
20             ChessKit::Trad
21              
22             =head1 VERSION
23              
24             Version 1.1
25              
26             =cut
27              
28             =head1 SYNOPSIS
29              
30             see ChessKit
31              
32             =head1 FUNCTIONS
33              
34             =head2 sub dscrip
35              
36             see ChessKit
37              
38             =head2 sub mauv
39              
40             retrieve the move from notation
41             see ChessKit
42              
43             =head2 sub promote
44              
45             retrieve the element of pawn promotion
46             see ChessKit
47              
48             =head2 sub resolve
49              
50             resolve move ambiguity of the destination square
51             see ChessKit
52              
53             =head2 sub resolve_deb
54              
55             resolve move ambiguity of the starting square
56             see ChessKit
57              
58             =head2 sub trad
59              
60             High level interface for translating notation
61             from languages
62             see ChessKit
63              
64             =cut
65              
66              
67            
68             =head1 AUTHOR
69              
70             Charles Minc, C<< >>
71              
72             =head1 BUGS
73              
74             Please report any bugs or feature requests to
75             C, or through the web interface at
76             L.
77             I will be notified, and then you'll automatically be notified of progress on
78             your bug as I make changes.
79              
80             =head1 ACKNOWLEDGEMENTS
81              
82             =head1 COPYRIGHT & LICENSE
83              
84             Copyright 2005 Charles Minc, all rights reserved.
85              
86             This program is free software; you can redistribute it and/or modify it
87             under the same terms as Perl itself.
88              
89             =cut
90              
91             our $VERSION = '1.0' ;
92              
93 1     1   5 use strict ;
  1         2  
  1         25  
94 1     1   1205 use Symbol ;
  1         1085  
  1         107  
95 1     1   8 use Chess::ChessKit::Board ;
  1         2  
  1         34  
96              
97              
98             require Exporter ;
99              
100 1         3687 use vars qw(
101             @ISA
102             @EXPORT
103 1     1   7 );
  1         1  
104             our @ISA =qw(Exporter) ;
105              
106             our @EXPORT = qw( %country $bd );
107              
108             # this part concerns only algrbraic notation
109              
110             our %country=(
111             Czech =>'Czech ',
112             Danish =>'Danish ',
113             Dutch =>'Dutch ',
114             English =>'English ',
115             Estonian =>'Estonian ',
116             Finnish =>'Finnish ',
117             French =>'French ',
118             German =>'German ',
119             Hungarian =>'Hungarian ',
120             Icelandic =>'Icelandic ',
121             Italian =>'Italian ',
122             Norwegian =>'Norwegian ',
123             Polish =>'Polish ',
124             Portuguese =>'Portuguese',
125             Romanian =>'Romanian ',
126             Spanish =>'Spanish ',
127             Swedish =>'Swedish ') ;
128              
129              
130             sub trad {
131 0     0     (my $fileresult, my $file, my $lang ,my $lang2)=@_ ;
132              
133 0           my %trad2eng=(
134             Czech =>'JSVDK',
135             Danish =>'SLTDK',
136             Dutch =>'PLTDK',
137             English =>'NBRQK',
138             Estonian =>'ROVLK',
139             Finnish =>'RLTDK',
140             French =>'CFTDR',
141             German =>'SLTDK',
142             Hungarian =>'HFBVK',
143             Icelandic =>'RBHDK',
144             Italian =>'CATDR',
145             Norwegian =>'SLTDK',
146             Polish =>'SGWHK',
147             Portuguese =>'CBTDR',
148             Romanian =>'CNTDR',
149             Spanish =>'CATDR',
150             Swedish =>'SLTDK') ;
151              
152 0           print "from $lang to $lang2\n " ;
153 0           my $piece=$trad2eng{$lang} ;
154 0           my $prom=substr($piece,0,4) ;
155 0           my @ltr=split( // ,$piece );
156 0           my @ltr2=split( // ,$trad2eng{$lang2} );
157              
158 0           my %trad2en=("" => "", $ltr[0] => $ltr2[0], $ltr[1] => $ltr2[1], $ltr[2] => $ltr2[2], $ltr[3] => $ltr2[3], $ltr[4] => $ltr2[4]) ;
159              
160 0           open(OFILE,">",$fileresult) ;
161              
162 0 0         open(HFILE,$file) or die "cannot open file $file ";
163 0           my @line= ;
164              
165 0           foreach (@line) {
166              
167             # because we can find also something like that :3. d4, cxd4 ; 4. Cxd4, e5; 5. Cdb5, Cf6 ;
168 0           s/([$piece]?)([a-h]?[1-8]?\s*x?\s*[a-h][1-8][\+#]?\s*)(?:[,;]*)(\s*\=?\s*)([$prom]?)/$trad2en{$1}$2$3$trad2en{$4}/g ;
169              
170             # piece ^^
171             # column or line ^^^ ^^^
172             # capture ^
173             # destination square ^^^ ^^^
174             # promotion ^^^
175             #
176              
177             # just as above to delete semi-colons and commas
178 0           s/([O-]?O-O\s*)(?:[,;]*)/$1/g ;
179              
180 0           print OFILE $_ ;
181             }
182              
183 0           close(HFILE) ;
184 0           close(OFILE) ;
185 0           return ;
186             }
187              
188              
189             # the following part concerns only english descriptive notation
190              
191             my @from ,
192             my @to ;
193             my $status={} ; # used to valid castling
194             my @moves ;
195             our $bd ;
196              
197              
198             # this array below is used to reverse the column numbering of the Black moves
199             my @black=(0,8,7,6,5,4,3,2,1) ;
200              
201             # the following make the correspondance of the row naming between
202             # descriptive and algebraic notation
203              
204             my %algebra=(QR=>'a',
205             QN=>'b',
206             QB=>'c',
207             Q=> 'd',
208             K=> 'e',
209             KB=>'f',
210             KN=>'g',
211             KR=>'h') ;
212              
213             sub dscrip {
214              
215 0     0     my (%arg)=@_ ;
216 0           my @sauces=@{$arg{mov}} ;
  0            
217 0 0         my %study=%{$arg{ini}}if ( defined($arg{ini})) ;
  0            
218 0           @moves=() ;
219              
220             # read a game @sauces in descriptive notation return a game in
221             # long algebraic notation @moves
222             # chess is initialized with %study if nothing usual initial chess game position
223             # usage:
224             #@array_of_moves=&Trad::dscrip(ini=>ref_someposition or not,
225             # mov=>ref_set_of_moves)
226              
227              
228 0           $bd=Board->new() ;
229 0           $bd->startgame(%study) ;
230 0           $bd->has_moved(status=>$status,ini=>'y') ;
231              
232             # for debug
233             #$bd->chessview ;
234              
235             # main loop to translate notation
236              
237 0           for (my $i=0; $i<=$#sauces ; $i++) {
238              
239             # parse the white & black moves
240              
241              
242              
243             # $sauces[$i]=~ /(\d*\.)\s*(O|\w*\/?\d?)(-|x)([PQKNBR|O-O|O]*)(\d)?\s*(ch|e\.p\.|\([QNBR]\)|=\s*[QNBR])?\s*(O|\w*\/?\d?)(-|x)([PQKNBR|O-O|O]*)(\d)?\s*(ch|e\.p\.|\([QNBR]\)|=[QNBR])?\s*/ ;
244             # # 1 2 3 4 5 6 7 8 9 10 11
245              
246              
247              
248 0           my $cnt=$sauces[$i]=~ tr/-x/-x/ ;
249 0           my $pattern=qr/\s*(O|\w*\/?\d?)(-|x)([PQKNBR|O-O|O]*)(\d)?\s*(ch|e\.p\.|\([QNBR]\)|=\s*[QNBR])?/ x $cnt ;
250 0           $sauces[$i]=~ /(\d*\.)$pattern\s*/ ;
251              
252 0           my $n=$1 ;
253 0           my $wpiece=$2 ;
254 0           my $waction=$3 ;
255 0           my $wdestalpha=$4 ;
256 0 0         my $wdestnum=$5 ? $5 : "";
257 0 0         my $wechec=$6 ? $6 : "" ;
258             # for debug
259             # print "splitting results: $n $wpiece $waction $wdestalpha $wdestnum $wechec " ;
260 0           mauv($bd,'White',$wpiece ,$waction ,$wdestalpha, $wdestnum ,$wechec) ;
261              
262             # my $bpiece=$7 ;
263             # my $baction=$8 ;
264             # my $bdestalpha=$9 ;
265 0 0         my $bpiece= $cnt==2 ? $7 : "";
266 0 0         my $baction= $cnt==2 ? $8 : "";
267 0 0         my $bdestalpha= $cnt==2 ? $9 : "";
268 0 0         my $bdestnum=$10 ? $10 : "";
269 0 0         my $bechec=$11 ? $11 : "" ;
270              
271             # for debug
272 0 0         if($cnt == 2){
273             # print "$bpiece $baction $bdestalpha $bdestnum $bechec \n" ;
274 0           mauv($bd,'Black',$bpiece ,$baction ,$bdestalpha ,$bdestnum ,$bechec) ;}
275              
276             #print $n ;
277             }
278            
279             # for debug
280             #$bd->chessview ;
281              
282 0           return @moves ;
283              
284              
285             sub mauv{
286 0     0     my $bd=shift ;
287 0           my ($color,$wpiece, $waction, $wdestalpha, $wdestnum ,$wechec)=@_ ;
288              
289 0           @from=() ;
290 0           @to=() ;
291              
292             # find the set of pieces for the start of the moves
293              
294              
295 0           my $fpiece= $wpiece ;
296 0           my $roq=$wpiece . $waction . $wdestalpha ;
297              
298 0 0         if ( $roq =~ /O-O-O/ ) {
    0          
    0          
299              
300 0           $bd->castling(side=>'Q',status=>$status,couleur=>$color );
301 0           push(@moves,$roq) ;
302 0           return ;
303             } elsif ( $roq =~/O-O/ ) {
304              
305 0           $bd->castling(side=>'K',status=>$status,couleur=>$color );
306 0           push(@moves,$roq) ;
307 0           return ;
308              
309             } elsif ($fpiece =~ /^[PKQRBN]$/ ) {
310 0 0         @from=grep { $color eq 'White'? $fpiece eq $bd->{$_} : lc $fpiece eq $bd->{$_} } (keys %{$bd}) ;
  0            
  0            
311             } else {
312 0           $fpiece=&resolve_deb($color,$wpiece,$waction, $wdestalpha, $wdestnum ,$wechec) ;
313             }
314             # find the set of possible arrival cases
315              
316 0 0         if (!defined ($algebra{$wdestalpha} )) {
317 0           &resolve($bd,$color,$wpiece,$waction, $wdestalpha, $wdestnum ,$wechec) ;
318             } else {
319 0           my $exp= $algebra{$wdestalpha} ;
320 0 0         my $num=$color eq 'White' ? $wdestnum : $black[$wdestnum] ;
321 0           push @to,$exp . $num ;
322              
323 0 0         my $exp2=( ($wpiece eq 'P') ? "" : ( (length($wpiece) == 2) ? substr( $wpiece,1,1) : $wpiece )) . $exp . $num ;
    0          
324              
325             }
326             # for debug
327             # print "**from ", @from , "## to ", @to ,"\n";
328              
329             # select the right move(s)
330              
331              
332 0           foreach my $f (0..$#from) {
333 0           foreach my $t (0..$#to) {
334 0           my $set=[] ;
335             ## $set contient tous les coups valides (sans echec donc)
336 0 0         my $tpiece=$color eq 'White' ? $fpiece : lc($fpiece) ;
337 0           $bd->vldmov(row=>chr(vec($from[$f],1,8)),
338             col=>chr( vec($from[$f],0,8)),
339             piece=>$tpiece,
340             valid=>$set) ;
341              
342 0           foreach (0..$#{$set}) {
  0            
343 0 0         if ($set->[$_] eq $to[$t]) {
344             # asap la case de destination est trouvée le coup est joué
345 0           my $hadak= uc($tpiece) . $from[$f] ;
346 0 0         $hadak .= (defined($bd->getpiece($to[$t])) ? 'x' :'-' ) . $to[$t];
347 0           $hadak=~ s/P//g ;
348 0           ($tpiece,my $promo)=&promote($tpiece,chr(vec($to[$t],1,8)),$wechec) ;
349 0           push(@moves,$hadak . $promo) ;
350 0           $bd->deletepiece($from[$f]) ;
351 0           $bd->put($tpiece, $to[$t]) ;
352             # for debug
353             # $bd->chessview ;
354 0           last ;
355             }
356             }
357             }
358             }
359              
360 0           return ;
361             }
362              
363             sub resolve{
364 0     0     my $bd=shift ;
365 0           my ($color,$wpiece,$waction, $wdestalpha, $wdestnum ,$wechec)=@_ ;
366              
367             # resout les ambiguités
368              
369             # prise en passant
370 0 0         if ($wechec eq 'e.p.') {
371 0           my %pred=(a=>'',b=>'a',c=>'b',d=>'c',e=>'d',f=>'e',g=>'f',h=>'g') ;
372 0           my %suiv=(a=>'b',b=>'c',c=>'d',d=>'e',e=>'f',f=>'g',g=>'h',h=>'') ;
373 0           my @ep ;
374              
375 0 0         my ( $c,$pion)= $color eq 'White'? ('Black','p'): ('White','P') ;
376 0 0         my $cto=$color eq 'White' ? '5' : '4' ;
377 0           my $n=$moves[$#moves] ;
378 0           my ($col,$row)=split('',substr( $n,-2) ) ;
379 0 0         push @to, $c eq 'White' ? $col . '3' : $col . '6' ;
380              
381 0           foreach (@from) {
382 0 0 0       if ( ($_ eq $pred{$col}.$cto ) || ($_ eq $suiv{$col}.$cto )) {
383 0           push @ep , $_ ;
384             }
385             }
386             # ep entre 1 et 2 mais $#to=0 max
387 0 0         if (@ep >= 1) {
388 0           @from=@ep ;
389             # pas propre à ce niveau mais efficace
390              
391 0           $bd->deletepiece($col.$row) ;
392 0           $bd->put($pion, $to[0]) ;
393              
394 0           return ;
395             } else {
396 0           print "erreur sur ep", @ep, "\n" ;
397 0           return ;
398             }
399             }
400              
401             # ambiguité de cote K or Q
402 0 0 0       if ($wdestalpha=~ /^[BRN]$/ && $wdestnum ne '') {
403 0 0         my $num=($color eq 'White' ? $wdestnum : $black[$wdestnum]) ;
404 0           push @to ,$algebra{'K' . $wdestalpha} . $num ;
405 0           push @to ,$algebra{'Q' . $wdestalpha} . $num ;
406 0           return ;
407             }
408              
409             # ambiguité prise de piece
410 0 0 0       if ($wdestalpha=~ /^[BRNP]$/ && $waction eq 'x') {
411 0 0         my $tpiece=$color eq 'White' ? lc($wdestalpha) :uc($wdestalpha) ;
412 0           foreach my $loc (keys %{$bd}) {
  0            
413 0 0         if ($bd->{$loc} eq $tpiece ) {
414 0           push @to,$loc;
415             }
416             ;
417             }
418              
419 0           return ;
420             }
421              
422             # ambiguité prise de pion
423             # /[QK|][BRN]P/
424 0 0 0       if ($wdestalpha=~ /^[BRN]P$/ && $waction eq 'x') {
425 0 0         my $opp=$color eq 'White' ? 'p' :'P' ;
426 0           foreach my $sq (keys %{$bd}) {
  0            
427 0           my $piece= $bd->{$sq} ;
428 0           my $rk=substr($sq,0,1) ;
429 0 0         if ($piece eq $opp ) {
430 0           my $wx ;
431 0 0         if ($wdestalpha=~ /^([BRN])P$/ ) {
432 0           my $wx=$1 ;
433 0           foreach ('Q','K') {
434 0 0         if ($algebra{$_ . $wx} eq $rk) {
435 0           push @to,$sq ;
436             }
437             }
438             } else {
439 0           foreach ('Q','K') {
440 0 0         if ($algebra{$_ } eq $rk) {
441 0           push @to,$sq ;
442             }
443             }
444             }
445             }
446             }
447 0           return ;
448             }
449              
450             # ambiguités persistantes
451 0           print "**** ambiguity *** \n" ;
452 0           return ;
453             }
454              
455             sub resolve_deb {
456              
457 0     0     my ($color,$wpiece,$waction, $wdestalpha, $wdestnum ,$wechec)=@_ ;
458 0           my $truepiece ;
459             my $side ;
460 0           my $piece ;
461 0           my $col ;
462 0           my $rank ;
463 0           my $wcol ;
464 0           my $loc ;
465 0           my $case ;
466             #ambiguité sur colonne
467              
468 0 0         if ($wpiece =~ /^([QRBKN])\/([1-8])$/) {
469             # $truepiece=$1 ;
470 0 0         ($wcol,$truepiece)=$color eq 'White' ? ($2,$1): ($black[$2],lc($1)) ;
471 0           foreach $case (keys %{$bd}) {
  0            
472 0           ($rank, $col)=split(//,$case) ;
473 0 0 0       if ( ($bd->{$case} eq $truepiece) && ($col == $wcol) ) {
474 0           push @from,$case ;
475             }
476             }
477 0           return ($truepiece) ;
478             }
479              
480             #ambiguité sur queen side & king side
481             # ex N=e4 et N =g8 => QN=e4 et KN=g8 e
482             # pb avec 3 pieces ??
483              
484 0 0         if ($wpiece =~ /(^[QK])([QRBN]$)/ ) {
485 0 0         $truepiece=$color eq 'White' ? $2:lc($2) ;
486 0           $side=$1 ;
487 0           my $i=0 ;
488 0           my @loc ;
489              
490 0           foreach $case (keys %{$bd} ) {
  0            
491 0 0         if ($bd->{$case} eq $truepiece ) {
492 0           $loc[$i]= $case ;$i++ ;
  0            
493             }
494             }
495              
496 0 0         if ($#loc < 2) {
497 0 0         push @from,( $side eq 'Q' ? ( ( substr($loc[0],0,1) lt substr($loc[1],0,1)) ? $loc[0]: $loc[1] )
    0          
    0          
498             : ( ( substr($loc[0],0,1) gt substr($loc[1],0,1)) ? $loc[0]: $loc[1] )) ;}
499             else {
500 0           print " ambiguity : piece number gt à 2 : $#loc \n " ;
501             }
502             }
503              
504 0           return ($truepiece) ;
505              
506             # ambiguités peristantes = not solved
507              
508 0           print "ambiguity at start of the mpve \n" ;
509              
510 0           return ;
511             }
512              
513              
514              
515             sub promote{
516             #check if the pawn get the last rank
517             # usage (piece chosen , = piece chosen)=promote(pawn,row location,piece chosen)
518             # dual syntax for the chosen piece X: =X or (X)
519 0     0     my $tpiece=shift ;
520 0           my $row=shift ;
521 0           my $wechec=shift ;
522              
523 0 0 0       if( $tpiece eq 'P' && $row==8){
524             # retrieve the piece to promote
525 0           $wechec=~ s/[\(|=]\s*([QNBR])\s*\)?/$1/ ;
526 0           return ($wechec,'='. uc($wechec) ) ;}
527              
528 0 0 0       if( $tpiece eq 'p' && $row==1){
529             # retrieve the piece to promote
530 0           $wechec=~ s/[\(|=]\s*([QNBR])\s*\)?/$1/ ;
531 0           return (lc $wechec,'='. uc($wechec) ) ;}
532             # not a pawn to promote , nothing to do
533 0           return ($tpiece,"") ;
534             }
535             }
536             1 ;