File Coverage

blib/lib/Game/TileMap.pm
Criterion Covered Total %
statement 91 91 100.0
branch 8 12 66.6
condition 3 6 50.0
subroutine 16 16 100.0
pod 5 6 83.3
total 123 131 93.8


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