File Coverage

blib/lib/Game/TileMap.pm
Criterion Covered Total %
statement 89 89 100.0
branch 8 12 66.6
condition 3 6 50.0
subroutine 15 15 100.0
pod 5 6 83.3
total 120 128 93.7


line stmt bran cond sub pod time code
1             package Game::TileMap;
2             $Game::TileMap::VERSION = '1.000';
3 3     3   205362 use v5.10;
  3         34  
4 3     3   17 use strict;
  3         8  
  3         95  
5 3     3   18 use warnings;
  3         6  
  3         100  
6              
7 3     3   1636 use Moo;
  3         34474  
  3         15  
8 3     3   5758 use Mooish::AttributeBuilder -standard;
  3         5415  
  3         20  
9 3     3   2341 use Storable qw(dclone);
  3         10232  
  3         237  
10 3     3   22 use Carp qw(croak);
  3         7  
  3         135  
11              
12 3     3   1496 use Game::TileMap::Legend;
  3         9  
  3         112  
13 3     3   1444 use Game::TileMap::Tile;
  3         9  
  3         2950  
14              
15             has param 'legend' => (
16              
17             # isa => InstanceOf ['Game::TileMap::Legend'],
18             );
19              
20             has field 'coordinates' => (
21             writer => -hidden,
22              
23             # isa => ArrayRef [ArrayRef [Any]],
24             );
25              
26             has field 'size_x' => (
27             writer => -hidden,
28              
29             # isa => PositiveInt,
30             );
31              
32             has field 'size_y' => (
33             writer => -hidden,
34              
35             # isa => PositiveInt,
36             );
37              
38             has field '_guide' => (
39             writer => 1,
40              
41             # isa => HashRef [ArrayRef [Tuple [Any, PositiveInt, PositiveInt]]],
42             );
43              
44             with qw(
45             Game::TileMap::Role::Checks
46             Game::TileMap::Role::Helpers
47             );
48              
49             sub new_legend
50             {
51 3     3 1 259 my $self = shift;
52              
53 3         30 return Game::TileMap::Legend->new(@_);
54             }
55              
56             sub BUILD
57             {
58 3     3 0 6737 my ($self, $args) = @_;
59              
60 3 50       17 if ($args->{map}) {
61             $self->from_string($args->{map})
62 3 50       22 if !ref $args->{map};
63              
64             $self->from_array($args->{map})
65 3 50       35 if ref $args->{map} eq 'ARRAY';
66             }
67             }
68              
69             sub from_string
70             {
71 3     3 1 11 my ($self, $map_str) = @_;
72 3         16 my $per_tile = $self->legend->characters_per_tile;
73              
74             my @map_lines =
75             reverse
76 22         36 grep { length }
77 3         16 map { s/\s//g; $_ }
  22         60  
  22         40  
78             split "\n", $map_str
79             ;
80              
81 3         8 my @map;
82 3         8 foreach my $line (@map_lines) {
83 22         48 my @objects;
84 22         81 while (length $line) {
85 186         328 my $marker = substr $line, 0, $per_tile, '';
86 186   33     507 push @objects, ($self->legend->objects->{$marker} // croak "Invalid map marker '$marker'");
87             }
88              
89 22         46 push @map, \@objects;
90             }
91              
92 3         13 return $self->from_array(\@map);
93             }
94              
95             sub from_array
96             {
97 3     3 1 10 my ($self, $map_aref) = @_;
98 3         7 my @map = @{$map_aref};
  3         8  
99              
100 3         52 my @map_size = (scalar @{$map[0]}, scalar @map);
  3         28  
101 3         10 my %guide;
102              
103             my @new_map;
104 3         19 foreach my $line (0 .. $#map) {
105             croak "invalid map size on line $line"
106 22 50       183 if @{$map[$line]} != $map_size[0];
  22         67  
107              
108 22         32 for my $col (0 .. $#{$map[$line]}) {
  22         59  
109 186         1555 my $prev_obj = $map[$line][$col];
110 186         2990 my $obj = Game::TileMap::Tile->new(
111             legend => $self->legend,
112             contents => $prev_obj,
113             x => $col,
114             y => $line,
115             );
116              
117 186         373 $new_map[$col][$line] = $obj;
118 186         234 push @{$guide{$self->legend->get_class_of_object($prev_obj)}}, $obj;
  186         444  
119             }
120             }
121              
122 3         39 $self->_set_coordinates(\@new_map);
123 3         11 $self->_set_size_x($map_size[0]);
124 3         11 $self->_set_size_y($map_size[1]);
125 3         22 $self->_set_guide(\%guide);
126              
127 3         16 return $self;
128             }
129              
130             sub to_string
131             {
132 2     2 1 11058 return shift->to_string_and_mark;
133             }
134              
135             sub to_string_and_mark
136             {
137 5     5 1 16 my ($self, $mark_positions, $with) = @_;
138 5   66     41 $with //= '!' x $self->legend->characters_per_tile;
139              
140 5         9 my @lines;
141             my %markers_rev = map {
142 45         116 $self->legend->objects->{$_} => $_
143 5         8 } keys %{$self->legend->objects};
  5         29  
144              
145 5         17 my $mark = \undef;
146 5         12 my $coordinates = $self->coordinates;
147 5 100       16 if ($mark_positions) {
148 3         1529 $coordinates = dclone $coordinates;
149              
150 3         14 foreach my $pos (@{$mark_positions}) {
  3         10  
151 5         29 $coordinates->[$pos->[0]][$pos->[1]] = $mark;
152             }
153             }
154              
155 5         17 foreach my $pos_x (0 .. $#$coordinates) {
156 49         65 foreach my $pos_y (0 .. $#{$coordinates->[$pos_x]}) {
  49         94  
157 474         628 my $obj = $coordinates->[$pos_x][$pos_y];
158 474 100       1211 $lines[$pos_y][$pos_x] = $obj eq $mark ? $with : $markers_rev{$obj->type};
159             }
160             }
161              
162             return join "\n",
163             reverse
164 5         13 map { join '', @{$_} } @lines;
  51         67  
  51         261  
165             }
166              
167             1;
168              
169             __END__