ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Games-Sokoban/Sokoban.pm
(Generate patch)

Comparing Games-Sokoban/Sokoban.pm (file contents):
Revision 1.6 by root, Tue May 11 23:49:40 2010 UTC vs.
Revision 1.12 by root, Wed May 12 20:55:30 2010 UTC

22use common::sense; 22use common::sense;
23 23
24use Carp (); 24use Carp ();
25use List::Util (); 25use List::Util ();
26 26
27our $VERSION = '0.02'; 27our $VERSION = '1.01';
28 28
29=item $level = new Games::Sokoban [format => "text|rle|binpack"], [data => "###..."] 29=item $level = new Games::Sokoban [format => "text|rle|binpack"], [data => "###..."]
30 30
31=cut 31=cut
32 32
58sub detect_format($) { 58sub detect_format($) {
59 my ($data) = @_; 59 my ($data) = @_;
60 60
61 return "text" if $data =~ /^[ #\@\*\$\.\+\015\012\-_]+$/; 61 return "text" if $data =~ /^[ #\@\*\$\.\+\015\012\-_]+$/;
62 62
63 warn $data;#d#
64 return "rle" if $data =~ /^[ #\@\*\$\.\+\015\012\-_|1-9]+$/; 63 return "rle" if $data =~ /^[ #\@\*\$\.\+\015\012\-_|1-9]+$/;
65 exit 5;#d#
66 64
67 my ($a, $b) = unpack "ww", $data; 65 my ($a, $b) = unpack "ww", $data;
68 return "binpack" if defined $a && defined $b; 66 return "binpack" if defined $a && defined $b;
69 67
70 Carp::croak "unable to autodetect sokoban level format"; 68 Carp::croak "unable to autodetect sokoban level format";
71} 69}
72 70
73=item $level->data ([$new_data, [$new_data_format]]]) 71=item $level->data ([$new_data, [$new_data_format]])
74 72
75Sets the level from the given data. 73Sets the level from the given data.
76 74
77=cut 75=cut
78 76
119 117
120 } else { 118 } else {
121 Carp::croak "$format: unsupported sokoban level format requested"; 119 Carp::croak "$format: unsupported sokoban level format requested";
122 } 120 }
123 121
122 $self->{format} = $format;
124 $self->update; 123 $self->update;
125 } 124 }
126 125
127 $_[0]{data} 126 $_[0]{data}
128} 127}
153 } 152 }
154} 153}
155 154
156=item $text = $level->as_text 155=item $text = $level->as_text
157 156
157Returns the level in xsb/text format - every row of the level is one line
158ended by a newline, e.g.:
159
160 "###\n# #\n###\n"
161
158=cut 162=cut
159 163
160sub as_text { 164sub as_text {
161 my ($self) = @_; 165 my ($self) = @_;
162 166
163 "$self->{data}\n" 167 "$self->{data}\n"
164} 168}
165 169
166=item $binary = $level->as_binpack 170=item $binary = $level->as_binpack
171
172Binpack is a very compact binary format (usually 17% of the size of an xsb
173file), that is still reasonably easy to encode/decode.
174
175It only tries to store simplified levels with full fidelity - other levels
176can be slightly changed outside the playable area.
167 177
168=cut 178=cut
169 179
170sub as_binpack { 180sub as_binpack {
171 my ($self) = @_; 181 my ($self) = @_;
203 pack "wwB*", $w - 2, $s, $data 213 pack "wwB*", $w - 2, $s, $data
204} 214}
205 215
206=item @lines = $level->as_lines 216=item @lines = $level->as_lines
207 217
218Returns the level as a list of rows, each row is a text representation of
219the respective level row, e.g.:
220
221 ("###", "# #", "###")
222
208=cut 223=cut
209 224
210sub as_lines { 225sub as_lines {
211 split /\n/, $_[0]{data} 226 split /\n/, $_[0]{data}
212} 227}
213 228
214=item $line = $level->as_rle 229=item $line = $level->as_rle
215 230
216http://www.sokobano.de/wiki/index.php?title=Level_format 231http://www.sokobano.de/wiki/index.php?title=Level_format
232
233Example:
234
235 "3#|# #|3#"
217 236
218=cut 237=cut
219 238
220sub as_rle { 239sub as_rle {
221 my $data = $_[0]{data}; 240 my $data = $_[0]{data};
240 $self->pos2xy ($-[0]); 259 $self->pos2xy ($-[0]);
241} 260}
242 261
243=item $level->hflip 262=item $level->hflip
244 263
264Mirror horizontally.
265
245=item $level->vflip 266=item $level->vflip
246 267
247=item $level->transpose # topleft to bottomright 268Mirror vertically.
269
270=item $level->transpose
271
272Transpose level (mirror at top-left/bottom-right diagonal).
248 273
249=item $level->rotate_90 274=item $level->rotate_90
250 275
276Rotate by 90 degrees clockwise.
277
251=item $level->rotate_180 278=item $level->rotate_180
279
280Rotate by 180 degrees clockwise.
252 281
253=cut 282=cut
254 283
255sub hflip { 284sub hflip {
256 $_[0]{data} = join "\n", map { scalar reverse $_ } split /\n/, $_[0]{data}; 285 $_[0]{data} = join "\n", map { scalar reverse $_ } split /\n/, $_[0]{data};
344 # phew, done 373 # phew, done
345} 374}
346 375
347=item $id = $level->normalise 376=item $id = $level->normalise
348 377
349normalises the level map and calculates/returns it's identity code 378Simplifies the level map and calculates/returns its identity code.
350 379.
351http://www.sourcecode.se/sokoban/level_id.php, assume uppercase and hex. 380http://www.sourcecode.se/sokoban/level_id.php, assume uppercase and hex.
352 381
353=cut 382=cut
354 383
355sub normalise { 384sub normalise {
389Games::Sokoban objects in an arrayref. 418Games::Sokoban objects in an arrayref.
390 419
391=cut 420=cut
392 421
393sub load_sokevo($) { 422sub load_sokevo($) {
394 open my $fh, "<", $_[0] 423 open my $fh, "<:crlf", $_[0]
395 or Carp::croak "$_[0]: $!"; 424 or Carp::croak "$_[0]: $!";
396 425
397 my @levels; 426 my @levels;
398 427
428 # skip file header
429 local $/ = "\n\n";
430 scalar <$fh>;
431
399 while (<$fh>) { 432 while (<$fh>) {
400 if (/^##+$/) { 433 chomp;
401 my $data = $_; 434 my %meta = split /(?:: |\n)/;
402 while (<$fh>) {
403 $data .= $_;
404 last if /^$/;
405 }
406 435
436 $_ = <$fh>;
437
438 /^##+\n/ or last;
439
440 # sokevo internally locks some cells
441 y/^%:,;-=?/ #.$* +#/;
442
443 # skip levels without pusher
444 y/@+// or next;
445
407 push @levels, new Games::Sokoban data => $data; 446 push @levels, new Games::Sokoban data => $_, meta => \%meta;
408 }
409 } 447 }
410 448
411 \@levels 449 \@levels
412} 450}
413 451

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines