File Coverage

blib/lib/App/Greple/wordle/game.pm
Criterion Covered Total %
statement 23 90 25.5
branch 0 16 0.0
condition 0 5 0.0
subroutine 8 23 34.7
pod 0 9 0.0
total 31 143 21.6


line stmt bran cond sub pod time code
1             package App::Greple::wordle::game;
2 1     1   15 use v5.14;
  1         3  
3 1     1   6 use warnings;
  1         2  
  1         58  
4              
5 1     1   6 use Data::Dumper;
  1         2  
  1         65  
6 1     1   6 use List::Util qw(any uniq);
  1         2  
  1         120  
7 1     1   846 use List::MoreUtils qw(pairwise);
  1         22744  
  1         9  
8 1     1   1603 use Getopt::EX::Colormap qw(colorize);
  1         2  
  1         93  
9              
10 1     1   905 use Mo qw(is required default); {
  1         765  
  1         6  
11             has answer => is => 'ro', required => 1 ;
12             has attempts => [], lazy => 0 ;
13             has map => {} ;
14             }
15 1     1   3668 no Mo;
  1         3  
  1         1885  
16              
17             sub try {
18 0     0 0   my $obj = shift;
19 0           push @{$obj->attempts}, @_;
  0            
20 0           $obj->update(@_);
21 0           $obj->solved;
22             }
23              
24             sub attempt {
25 0     0 0   my $obj = shift;
26 0           int @{$obj->attempts};
  0            
27             }
28              
29             sub solved {
30 0     0 0   my $obj = shift;
31 0     0     any { lc eq lc $obj->answer } @{$obj->attempts};
  0            
  0            
32             }
33              
34             sub update {
35 0     0 0   my $obj = shift;
36 0           my $answer = $obj->answer;
37 0           my %a = map { $_ => 1 } my @a = $answer =~ /./g;
  0            
38 0           my $keys = $obj->map;
39 0           for my $try (@_) {
40 0           my @b = $try =~ /./g;
41 0 0   0     pairwise { $keys->{$a} = 'G' if $a eq $b } @a, @b;
  0            
42 0 0 0       $keys->{$_} ||= $a{$_} ? 'Y' : 'K' for @b;
43             }
44 0           $obj;
45             }
46              
47             ######################################################################
48             # keymap
49             ######################################################################
50              
51             my %map_color = (
52             G => '555/#6aaa64',
53             Y => '555/#c9b458',
54             K => '#787c7e/#787c7e',
55             K => 'L17/#787c7e',
56             _ => '555/#787c7e',
57             );
58              
59             sub keycolor {
60 0     0 0   my($kmap, $cmap, $s) = @_;
61 0   0       join '', map colorize($cmap->{$kmap->{$_}//'_'}, $_), $s =~ /./g;
62             }
63              
64             sub keymap {
65 0     0 0   my $obj = shift;
66 0           my $keys = keycolor $obj->map, \%map_color, join('', 'a'..'z');
67 0           $keys;
68             }
69              
70             ######################################################################
71             # result
72             ######################################################################
73              
74             my %square = (
75             G => "\N{U+1F7E9}", # LARGE GREEN SQUARE
76             Y => "\N{U+1F7E8}", # LARGE YELLOW SQUARE
77             K => "\N{U+2B1C}", # WHITE LARGE SQUARE
78             );
79              
80             sub result {
81 0     0 0   my $obj = shift;
82 0           my @result = _result(map lc, $obj->answer, @{$obj->attempts});
  0            
83 0           my $result = join "\n", map s/([GYK])/$square{$1}/ger, @result;
  0            
84 0           $result;
85             }
86              
87             sub _result {
88 0     0     my $answer = shift;
89 0           my %a = map { $_ => 1 } my @a = $answer =~ /./g;
  0            
90             map {
91 0           my @b = /./g;
  0            
92             join '', pairwise {
93 0 0   0     $a eq $b ? 'G' : $a{$b} ? 'Y' : 'K'
    0          
94 0           } @a, @b;
95             } @_;
96             }
97              
98             ######################################################################
99             # hint
100             ######################################################################
101              
102             my %hint_color = (
103             G => 'G',
104             Y => 'Y',
105             K => 'KU',
106             _ => 'K',
107             );
108              
109             sub hint_color {
110 0     0 0   my $obj = shift;
111 0           map keycolor($obj->map, \%hint_color, $_), @_;
112             }
113              
114             sub hint {
115 0     0 0   my $obj = shift;
116 0           my $pattern = _hint(map lc, $obj->answer, @{$obj->attempts});
  0            
117             }
118              
119             sub _hint {
120 0     0     my $answer = shift;
121 0           my %a = map { $_ => 1 } my @a = $answer =~ /./g;
  0            
122 0           my(@yes, @no);
123 0           my $seen = '';
124             map {
125 0           my @b = /./g;
  0            
126 0           for my $i (0 .. $#b) {
127 0 0         if ($a{$b[$i]}) {
128 0           $seen .= $b[$i];
129             } else {
130 0           $seen .= "-$b[$i]";
131             }
132 0 0         if ($a[$i] eq $b[$i]) {
133 0           $yes[$i] = $a[$i];
134             } else {
135 0           $no[$i] .= $b[$i];
136             }
137             }
138             } @_;
139             my $match = join '', pairwise {
140 0 0   0     $b = join '', uniq $b =~ /./g if $b;
141 0 0         $a ? $a : "[^$b]";
142 0           } @yes, @no;
143 0           my $in = join '', map { "(?=.*$_)" } uniq $seen =~ /(?<!-)\w/g;
  0            
144 0           my $ex = sprintf '(?!.*[%s])', join('', uniq $seen =~ /(?<=-)\w/g);
145 0           $in . $ex . $match;
146             }
147              
148             1;