File Coverage

blib/lib/Karel/Grid.pm
Criterion Covered Total %
statement 59 59 100.0
branch 10 10 100.0
condition 2 2 100.0
subroutine 18 18 100.0
pod 6 7 85.7
total 95 96 98.9


line stmt bran cond sub pod time code
1             package Karel::Grid;
2              
3             =head1 NAME
4              
5             Karel::Grid
6              
7             =head1 DESCRIPTION
8              
9             Represents the map in which the robot moves.
10              
11             =head1 METHODS
12              
13             =over 4
14              
15             =item 'Karel::Grid'->new
16              
17             my $grid = 'Karel::Grid'->new( x => 10, y => 12 );
18              
19             The constructor creates an empty grid of the given size.
20              
21             =cut
22              
23 9     9   129522 use warnings;
  9         16  
  9         280  
24 9     9   36 use strict;
  9         14  
  9         182  
25              
26 9     9   43 use Carp;
  9         13  
  9         676  
27 9     9   3419 use Karel::Util qw{ positive_int m_to_n };
  9         16  
  9         646  
28 9     9   49 use List::Util qw{ any none };
  9         26  
  9         753  
29 9     9   4248 use Moo;
  9         94256  
  9         48  
30 9     9   14326 use namespace::clean;
  9         79931  
  9         41  
31              
32             =item $grid->x, $grid->y
33              
34             my ($x, $y) = map $grid->$_, qw( x y );
35              
36             Returns the size of the grid.
37              
38             =cut
39              
40             has [qw[ x y ]] => (is => 'ro',
41             isa => \&positive_int,
42             required => 1,
43             );
44              
45              
46             has _grid => ( is => 'rw',
47             isa => sub {
48             croak "Grid should be an AoA!"
49             if 'ARRAY' ne ref $_[0]
50             || any { 'ARRAY' ne ref } @{ $_[0] };
51             },
52             );
53              
54             # Create an empty grid
55             sub BUILD {
56 62     62 0 820 my ($self) = @_;
57 62         420 my ($x, $y) = map $self->$_, qw( x y );
58 62         1712 $self->_grid([ map [ (' ') x ($y + 2) ], 0 .. $x + 1 ]);
59 62         1069 $self->_set($_, 0, 'W'), $self->_set($_, $y + 1, 'W') for 0 .. $x + 1;
60 62         582 $self->_set(0, $_, 'W'), $self->_set($x + 1, $_, 'W') for 0 .. $y + 1;
61 62         1387 return $self
62             }
63              
64             =item $grid->at($x, $y)
65              
66             Returns a space if there's nothing at the given position. For marks,
67             it returns 1 - 9. For walls, it returns "W" (outer walls) or "w"
68             (inner walls).
69              
70             =cut
71              
72             sub at {
73 253     253 1 5250 my ($self, $x, $y) = @_;
74 253         794 m_to_n($x, 0, $self->x + 1);
75 252         697 m_to_n($y, 0, $self->y + 1);
76 252         5451 return $self->_grid->[$x][$y]
77             }
78              
79              
80             sub _set {
81 1443     1443   6882 my ($self, $x, $y, $what) = @_;
82 1443         3519 m_to_n($x, 0, $self->x + 1);
83 1443         3425 m_to_n($y, 0, $self->y + 1);
84             croak "Unknown object '$what'."
85 1443 100   16351   7436 if none { $_ eq $what } ' ', '0' .. '9', 'w', 'W';
  16351         13199  
86 1442         29795 $self->_grid->[$x][$y] = $what;
87             }
88              
89             =item $grid->build_wall($x, $y)
90              
91             Builds a wall ("w") at the given coordinates.
92              
93             =cut
94              
95             sub build_wall {
96 10     10 1 276 my ($self, $x, $y) = @_;
97 10         43 m_to_n($x, 1, $self->x);
98 10         39 m_to_n($y, 1, $self->y);
99 10         25 $self->_set($x, $y, 'w');
100             }
101              
102             =item $gird->remove_wall($x, $y)
103              
104             Removes a wall ("w") from the given coordinates. Dies if there's no
105             wall.
106              
107             =cut
108              
109             sub remove_wall {
110 2     2 1 454 my ($self, $x, $y) = @_;
111 2 100       7 croak "Not a removable wall at $x, $y." unless 'w' eq $self->at($x, $y);
112 1         15 $self->_set($x, $y, ' ');
113             }
114              
115             =item $grid->drop_mark($x, $y)
116              
117             Drop a mark at the given position. There must be an empty place or
118             less than 9 marks, otherwise the method dies.
119              
120             =cut
121              
122             sub drop_mark {
123 138     138 1 2277 my ($self, $x, $y) = @_;
124 138         213 my $previous = $self->at($x, $y);
125             croak "Can't drop mark to '$previous'."
126 138 100   598   1172 if none { $_ eq $previous } ' ', '1' .. '8';
  598         755  
127 137 100       396 $previous = 0 if ' ' eq $previous;
128 137         268 $self->_set($x, $y, $previous + 1);
129             }
130              
131             =item $grid->pick_mark($x, $y)
132              
133             Pick up a mark from the given position. Dies if there's no mark.
134              
135             =cut
136              
137             sub pick_mark {
138 30     30 1 1183 my ($self, $x, $y) = @_;
139 30         61 my $previous = $self->at($x, $y);
140             croak "Can't pick mark from '$previous'."
141 30 100   153   328 if none { $_ eq $previous } '1' .. '9';
  153         234  
142 29   100     174 $self->_set($x, $y, ($previous - 1) || ' ');
143             }
144              
145             =item $grid->clear($x, $y)
146              
147             Set the given position to empty (" ").
148              
149             =cut
150              
151             sub clear {
152 106     106 1 319 my ($self, $x, $y) = @_;
153 106         272 m_to_n($x, 1, $self->x);
154 105         264 m_to_n($y, 1, $self->y);
155 105         164 $self->_set($x, $y, ' ');
156             }
157              
158             =back
159              
160             =cut
161              
162             __PACKAGE__