File Coverage

lib/Games/Sokoban/Controller.pm
Criterion Covered Total %
statement 9 99 9.0
branch 0 32 0.0
condition 0 13 0.0
subroutine 3 23 13.0
pod 14 14 100.0
total 26 181 14.3


line stmt bran cond sub pod time code
1             package Games::Sokoban::Controller;
2            
3 1     1   72724 use strict;
  1         2  
  1         42  
4 1     1   7 use warnings;
  1         3  
  1         31  
5 1     1   1133 use Games::Sokoban;
  1         6867  
  1         1614  
6            
7             our $VERSION = '0.01';
8            
9             sub new {
10 0     0 1   my $class = shift;
11 0           bless { model => Games::Sokoban->new, @_ }, $class;
12             }
13            
14             sub set_data {
15 0     0 1   my ($self, $data, $format) = @_;
16 0           $self->{model}->data($data, $format);
17 0           $self->{level_id} = $self->{model}->normalise;
18 0           $self->{model}->data($data, $format);
19 0           $self->reset;
20             }
21            
22 0     0 1   sub level_id { shift->{level_id} }
23            
24             sub reset {
25 0     0 1   my $self = shift;
26 0           my $model = $self->{model};
27 0           $self->{data} = $model->data;
28 0           $self->{size} = [$model->{w}, $model->{h}];
29 0           $self->{pos} = [$model->start];
30 0           $self->{replaced} = [];
31 0           $self->{step} = 0;
32             }
33            
34 0     0 1   sub size { @{shift->{size}} }
  0            
35 0     0 1   sub width { shift->{size}[0] }
36 0     0 1   sub height { shift->{size}[1] }
37            
38             sub get {
39 0     0 1   my ($self, $pos) = @_;
40 0           substr($self->{data}, $self->_pos($pos), 1);
41             }
42            
43             sub _rel {
44 0     0     my ($self, $rel_pos) = @_;
45 0           $rel_pos->[0] += $self->{pos}[0];
46 0           $rel_pos->[1] += $self->{pos}[1];
47 0           $self->get($rel_pos);
48             }
49            
50             sub _replace {
51 0     0     my ($self, $pos, $char) = @_;
52 0           $pos->[0] += $self->{pos}[0];
53 0           $pos->[1] += $self->{pos}[1];
54 0           substr($self->{data}, $self->_pos($pos), 1, $char);
55 0           push @{$self->{replaced}}, $pos;
  0            
56             }
57            
58             sub _pos {
59 0     0     my ($self, $pos) = @_;
60 0           my ($x, $y) = @$pos;
61 0           my ($w, $h) = @{$self->{size}};
  0            
62 0 0         if ($x < 0) { $x = 0; }
  0            
63 0 0         if ($y < 0) { $y = 0; }
  0            
64 0 0         if ($x >= $w) { $x = $w - 1; }
  0            
65 0 0         if ($y >= $h) { $y = $h - 1; }
  0            
66 0           $x + $y * ($w + 1); # +1 for "\n"
67             }
68            
69             sub _dump {
70 0     0     my $self = shift;
71 0           my $data = $self->{data};
72 0           my $left = $data =~ /([\.\+])/;
73 0           my $done = $data =~ /(\*)/;
74 0   0       my $dump = join "",
      0        
75             $data, "\n",
76             "pos: (", $self->{pos}[0], ", ", $self->{pos}[1], ")\n",
77             "step: ", $self->{step}, "\n",
78             "left: ", ($left || 0), "\n",
79             "done: ", ($done || 0), "\n";
80            
81 0 0         if (defined wantarray) {
82 0           return $dump;
83             }
84             else {
85 0           print STDERR "\n", $dump;
86             }
87             }
88            
89             sub _move {
90 0     0     my ($self, $delta, $direction) = @_;
91            
92 0           my ($x, $y) = @{$self->{pos}};
  0            
93 0           my ($dx, $dy) = @$delta;
94 0           my $me = $self->_rel([0, 0]);
95 0           my $dest = $self->_rel([$dx, $dy]);
96            
97 0           $self->{direction} = $direction;
98 0           @{$self->{replaced}} = ();
  0            
99            
100 0           my $moved;
101 0 0 0       if ($dest eq ' ' or $dest eq '.') {
    0 0        
102 0 0         $self->_replace([0, 0] => ($me eq '@' ? ' ' : '.'));
103 0 0         $self->_replace([$dx, $dy] => ($dest eq ' ' ? '@' : '+'));
104 0           $moved = 1;
105             }
106             elsif ($dest eq '$' or $dest eq '*') {
107 0           my $next = $self->_rel([$dx * 2, $dy * 2]);
108 0 0 0       if ($next eq ' ' or $next eq '.') {
109 0 0         $self->_replace([0, 0] => ($me eq '@' ? ' ' : '.'));
110 0 0         $self->_replace([$dx, $dy] => ($dest eq '$' ? '@' : '+'));
111 0 0         $self->_replace([$dx * 2, $dy * 2] => ($next eq ' ' ? '$' : '*'));
112 0           $moved = 1;
113             }
114             else {
115 0           $self->_debug("blocked");
116             }
117             }
118             else {
119 0           $self->_debug("wall");
120             }
121 0 0         if ($moved) {
122 0           $self->{step}++;
123 0           $self->{pos} = [$x + $dx, $y + $dy];
124 0           return @{$self->{replaced}};
  0            
125             }
126 0           return;
127             }
128            
129 0     0 1   sub go_right { shift->_move([1, 0], 'right') }
130 0     0 1   sub go_left { shift->_move([-1, 0], 'left') }
131 0     0 1   sub go_up { shift->_move([0, -1], 'up') }
132 0     0 1   sub go_down { shift->_move([0, 1], 'down') }
133            
134 0 0   0 1   sub direction { shift->{direction} || 'left' }
135            
136             sub solved {
137 0     0 1   my $self = shift;
138 0           my $left = $self->{data} =~ /([\.\+\$])/;
139 0           !$left;
140             }
141            
142             sub _debug {
143 0     0     my $self = shift;
144 0 0         print STDERR @_, "\n" if $self->{debug};
145             }
146            
147             1;
148            
149             __END__