File Coverage

blib/lib/Chess/Opening/Book.pm
Criterion Covered Total %
statement 53 57 92.9
branch 22 36 61.1
condition 4 6 66.6
subroutine 6 7 85.7
pod 2 2 100.0
total 87 108 80.5


line stmt bran cond sub pod time code
1             #! /bin/false
2              
3             # Copyright (C) 2019 Guido Flohr ,
4             # all rights reserved.
5              
6             # This program is free software. It comes without any warranty, to
7             # the extent permitted by applicable law. You can redistribute it
8             # and/or modify it under the terms of the Do What the Fuck You Want
9             # to Public License, Version 2, as published by Sam Hocevar. See
10             # http://www.wtfpl.net/ for more details.
11              
12             # Make Dist::Zilla happy.
13             # ABSTRACT: Read chess opening books in polyglot format
14              
15             package Chess::Opening::Book;
16             $Chess::Opening::Book::VERSION = '0.6';
17 3     3   27 use common::sense;
  3         6  
  3         15  
18              
19 3     3   1308 use Locale::TextDomain 'com.cantanea.Chess-Opening';
  3         37958  
  3         20  
20              
21 3     3   57961 use Chess::Opening::Book::Entry;
  3         8  
  3         2643  
22              
23             sub new {
24 0     0 1 0 require Carp;
25              
26 0         0 Carp::croak(__"Chess::Opening::Book is an abstract base class");
27             }
28              
29             sub lookupFEN {
30 56     56 1 265 my ($self, $fen) = @_;
31              
32 56 50       163 my $key = $self->_getKey($fen) or return;
33 56 50       181 my ($first, $last) = $self->_findKey($key) or return;
34              
35 56         207 my $entry = Chess::Opening::Book::Entry->new($fen);
36 56         149 foreach my $i ($first .. $last) {
37 133         320 $entry->addMove($self->_getEntry($i));
38             }
39              
40 56         148 return $entry;
41             }
42              
43             sub _pieces {
44             # Polyglot style piece encodings.
45 130     130   896 p => 0,
46             P => 1,
47             n => 2,
48             N => 3,
49             b => 4,
50             B => 5,
51             r => 6,
52             R => 7,
53             q => 8,
54             Q => 9,
55             k => 10,
56             K => 11,
57             }
58              
59             sub _parseFEN {
60 65     65   109 my ($whatever, $fen) = @_;
61              
62 65         426 my @tokens = split /[ \t\r\n]+/, $fen;
63 65 50       193 return if 6 != @tokens;
64              
65 65         93 my %result;
66 65         293 @result{'ranks', 'on_move', 'castling', 'ep', 'hmc', 'next_move'} = @tokens;
67 65         150 $result{on_move} = lc $result{on_move};
68 65 50 66     231 return if $result{on_move} ne 'w' && $result{on_move} ne 'b';
69 65 50       177 return if $result{next_move} <= 0;
70              
71 65 100       349 if ('-' eq $result{castling}) {
    50          
72 1         3 $result{castling} = {};
73             } elsif ($result{castling} !~ /^[KQkq]+$/) {
74 0         0 return;
75             } else {
76 64         205 $result{castling} = {map { $_ => 1 } split //, $result{castling}};
  253         648  
77             }
78 65 100       206 if ($result{ep} ne '-') {
79 30 100       67 if ($result{on_move} eq 'b') {
80 21 50       84 return if $result{ep} !~ /^[a-h]3$/;
81             } else {
82 9 50       60 return if $result{ep} !~ /^[a-h]6$/;
83             }
84             }
85 65 50       217 return if $result{hmc} !~ /^(?:0|[1-9][0-9]*)$/;
86 65 50       186 return if $result{next_move} !~ /^[1-9][0-9]*$/;
87              
88 65         250 my @ranks = split /\//, delete $result{ranks};
89 65 50       151 return if 8 != @ranks;
90              
91 65         96 my $rank = 8;
92 65         83 my $file;
93 65         137 $result{pieces} = [];
94 65         156 my %pieces = $whatever->_pieces;
95 65         166 foreach my $token (@ranks) {
96 520         696 $file = ord 'a';
97 520         1207 foreach my $char (split //, $token) {
98 2623 100 66     7622 if ($char ge '1' && $char le '8') {
    50          
99 544         865 $file += $char;
100 544 50       1024 return if $file > ord 'i';
101             } elsif (exists $pieces{$char}) {
102 2079 50       3761 return if $file > ord 'h';
103 2079         2500 push @{$result{pieces}}, {
  2079         6808  
104             piece => $char,
105             field => (chr $file) . $rank,
106             };
107 2079         3494 ++$file;
108             } else {
109 0         0 return;
110             }
111             }
112 520         997 --$rank;
113             }
114              
115 65         723 return %result;
116             }
117              
118             1;