File Coverage

blib/lib/Games/Sudoku/CLI.pm
Criterion Covered Total %
statement 63 79 79.7
branch 20 26 76.9
condition 2 6 33.3
subroutine 8 8 100.0
pod 0 4 0.0
total 93 123 75.6


line stmt bran cond sub pod time code
1             package Games::Sudoku::CLI;
2 1     1   48220 use strict;
  1         2  
  1         27  
3 1     1   4 use warnings;
  1         1  
  1         23  
4 1     1   24 use 5.010;
  1         3  
5              
6 1     1   281 use Games::Sudoku::Component::Controller;
  1         7196  
  1         820  
7              
8             our $VERSION = '0.02';
9              
10             sub new {
11 2     2 0 3915 my ($class) = @_;
12              
13 2         9 return bless {}, $class;
14             }
15              
16             sub play {
17 2     2 0 4 my ($self) = @_;
18              
19 2         8 $self->msg("Welcome to CLI Sudoku version $VERSION");
20              
21 2         8 while (1) {
22 2 100       6 $self->start_game or return;
23              
24 1         3 while (1) {
25 2         79 $self->print_as_grid;
26 2         7257 while (1) {
27 5         28 $self->prompt('Enter your choice (row, col, value) or [q-quit game, x-exit app, h-hint]: ');
28 5         46 $self->get_input();
29 5         40 $self->{input} = lc $self->{input};
30 5 100       18 last if $self->verify_input();
31             }
32              
33 2 50       10 if ($self->{input} eq 'h') {
34 0         0 for my $item ($self->{ctrl}->find_hints) {
35 0         0 $self->msg(sprintf "%s, %s, %s", $item->row, $item->col, $item->allowed);
36             }
37 0         0 next;
38             }
39 2 100       10 if ($self->{input} eq 'x') {
40 1         7 $self->msg('BYE');
41 1         9 return;
42             }
43 1 50       5 if ($self->{input} eq 'q') {
44 0         0 $self->msg('quit game');
45 0         0 last;
46             }
47 1         3 $self->{ctrl}->set(@{ $self->{step} });
  1         7  
48              
49 1 50       1691 if ($self->{ctrl}->table->is_finished) {
50 0         0 $self->print_as_grid;
51 0         0 $self->msg('DONE');
52 0         0 last;
53             }
54             }
55             }
56 0         0 return;
57             }
58              
59             sub start_game {
60 2     2 0 3 my ($self) = @_;
61              
62 2         3 while (1) {
63 2         5 $self->msg('Would you like to start a new game, load saved game, or exit?');
64 2         8 $self->msg('Type in "n NUMBER" to start a new game with NUMBER empty slots');
65 2         8 $self->msg('Type in "l FILENAME" to load the file called FILENAME');
66 2         7 $self->msg('Type x to exit');
67 2         18 $self->get_input();
68 2 100       16 if ($self->{input} eq 'x') {
69 1         4 $self->msg('BYE BYE');
70 1         5 return;
71             }
72 1 50       6 if ($self->{input} =~ /^n\s+(\d+)$/) {
73 0         0 my $blank = $1;
74 0         0 $self->{ctrl} = Games::Sudoku::Component::Controller->new(size => 9);
75 0         0 $self->{ctrl}->solve;
76 0         0 $self->{ctrl}->make_blank($blank);
77 0         0 last;
78             }
79 1 50       6 if ($self->{input} =~ /^l\s+(\S+)$/) {
80 1         4 my $filename = $1;
81 1         9 $self->{ctrl} = Games::Sudoku::Component::Controller->new(size => 9);
82 1         4551 $self->{ctrl}->load(filename => $filename);
83             }
84 1         12207 last;
85             }
86              
87 1         9 return 1;
88             }
89              
90             sub get_input {
91             my ($self) = @_;
92             $self->{input} = ;
93             chomp $self->{input};
94              
95             return;
96             }
97              
98             sub verify_input {
99 5     5 0 12 my ($self) = @_;
100              
101 5 100       58 if ($self->{input} =~ /^[xqh]$/) {
102 1         7 return 1;
103             }
104              
105 4         18 (my $spaceless_input = $self->{input}) =~ s/\s+//g;
106 4         27 my ($row, $col, $value) = $spaceless_input =~ /^(\d+),(\d+),(\d+)$/;
107 4 100       18 if (not defined $value) {
108 1         10 $self->msg("Invalid format: '$self->{input}'");
109 1         10 return;
110             }
111 3 50 33     30 if ($row > 9 or $col > 9 or $value > 9) {
      33        
112 0         0 $self->msg("Invalid values in: '$self->{input}'");
113 0         0 return;
114             }
115 3 100       13 if (not $self->{ctrl}->table->cell($row,$col)->is_allowed($value)) {
116 2         210 $self->msg("Value $value is not allowed in ($row, $col)");
117 2         15 return;
118             }
119              
120 1         156 $self->{step} = [$row, $col, $value];
121              
122 1         6 return 1;
123             }
124              
125             sub print_as_grid {
126             my ($self) = @_;
127              
128             my $table = $self->{ctrl}->table;
129              
130             my $size = $table->{size};
131             my $digit = int(log($size) / log(10)) + 1;
132              
133             print " ";
134             for my $c (1 .. $size) {
135             print " $c ";
136             if ($c % 3 == 0 and $c < 9) {
137             print ' | ';
138             }
139             }
140             print "\n";
141             say ' |' . '-' x 33;
142              
143             foreach my $row (1..$size) {
144             print " $row |";
145             foreach my $col (1..$size) {
146             my $value = $table->cell($row, $col)->value;
147             print $value ? " $value " : ' ';
148             if ($col % 3 == 0 and $col < 9) {
149             print ' | ';
150             }
151             }
152             print "\n";
153             if ($row % 3 == 0 and $row < 9) {
154             say ' |' . '-' x 33;
155             }
156             }
157             return;
158             }
159              
160             sub msg {
161             my ($self, $msg) = @_;
162             say $msg;
163             return;
164             }
165              
166             sub prompt {
167             my ($self, $msg) = @_;
168             print $msg;
169             return;
170             }
171              
172              
173             1;
174              
175             =pod
176              
177             =head1 NAME
178              
179             Games::Sudoku::CLI - play Sudoku on the command line
180              
181             =cut
182              
183