… | |
… | |
22 | use common::sense; |
22 | use common::sense; |
23 | |
23 | |
24 | use Carp (); |
24 | use Carp (); |
25 | use List::Util (); |
25 | use List::Util (); |
26 | |
26 | |
27 | our $VERSION = '0.02'; |
27 | our $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 | |
… | |
… | |
152 | } |
152 | } |
153 | } |
153 | } |
154 | |
154 | |
155 | =item $text = $level->as_text |
155 | =item $text = $level->as_text |
156 | |
156 | |
|
|
157 | Returns the level in xsb/text format - every row of the level is one line |
|
|
158 | ended by a newline, e.g.: |
|
|
159 | |
|
|
160 | "###\n# #\n###\n" |
|
|
161 | |
157 | =cut |
162 | =cut |
158 | |
163 | |
159 | sub as_text { |
164 | sub as_text { |
160 | my ($self) = @_; |
165 | my ($self) = @_; |
161 | |
166 | |
… | |
… | |
208 | pack "wwB*", $w - 2, $s, $data |
213 | pack "wwB*", $w - 2, $s, $data |
209 | } |
214 | } |
210 | |
215 | |
211 | =item @lines = $level->as_lines |
216 | =item @lines = $level->as_lines |
212 | |
217 | |
|
|
218 | Returns the level as a list of rows, each row is a text representation of |
|
|
219 | the respective level row, e.g.: |
|
|
220 | |
|
|
221 | ("###", "# #", "###") |
|
|
222 | |
213 | =cut |
223 | =cut |
214 | |
224 | |
215 | sub as_lines { |
225 | sub as_lines { |
216 | split /\n/, $_[0]{data} |
226 | split /\n/, $_[0]{data} |
217 | } |
227 | } |
218 | |
228 | |
219 | =item $line = $level->as_rle |
229 | =item $line = $level->as_rle |
220 | |
230 | |
221 | http://www.sokobano.de/wiki/index.php?title=Level_format |
231 | http://www.sokobano.de/wiki/index.php?title=Level_format |
|
|
232 | |
|
|
233 | Example: |
|
|
234 | |
|
|
235 | "3#|# #|3#" |
222 | |
236 | |
223 | =cut |
237 | =cut |
224 | |
238 | |
225 | sub as_rle { |
239 | sub as_rle { |
226 | my $data = $_[0]{data}; |
240 | my $data = $_[0]{data}; |
… | |
… | |
245 | $self->pos2xy ($-[0]); |
259 | $self->pos2xy ($-[0]); |
246 | } |
260 | } |
247 | |
261 | |
248 | =item $level->hflip |
262 | =item $level->hflip |
249 | |
263 | |
|
|
264 | Mirror horizontally. |
|
|
265 | |
250 | =item $level->vflip |
266 | =item $level->vflip |
251 | |
267 | |
252 | =item $level->transpose # topleft to bottomright |
268 | Mirror vertically. |
|
|
269 | |
|
|
270 | =item $level->transpose |
|
|
271 | |
|
|
272 | Transpose level (mirror at top-left/bottom-right diagonal). |
253 | |
273 | |
254 | =item $level->rotate_90 |
274 | =item $level->rotate_90 |
255 | |
275 | |
|
|
276 | Rotate by 90 degrees clockwise. |
|
|
277 | |
256 | =item $level->rotate_180 |
278 | =item $level->rotate_180 |
|
|
279 | |
|
|
280 | Rotate by 180 degrees clockwise. |
257 | |
281 | |
258 | =cut |
282 | =cut |
259 | |
283 | |
260 | sub hflip { |
284 | sub hflip { |
261 | $_[0]{data} = join "\n", map { scalar reverse $_ } split /\n/, $_[0]{data}; |
285 | $_[0]{data} = join "\n", map { scalar reverse $_ } split /\n/, $_[0]{data}; |
… | |
… | |
349 | # phew, done |
373 | # phew, done |
350 | } |
374 | } |
351 | |
375 | |
352 | =item $id = $level->normalise |
376 | =item $id = $level->normalise |
353 | |
377 | |
354 | normalises the level map and calculates/returns it's identity code |
378 | Simplifies the level map and calculates/returns its identity code. |
355 | |
379 | . |
356 | http://www.sourcecode.se/sokoban/level_id.php, assume uppercase and hex. |
380 | http://www.sourcecode.se/sokoban/level_id.php, assume uppercase and hex. |
357 | |
381 | |
358 | =cut |
382 | =cut |
359 | |
383 | |
360 | sub normalise { |
384 | sub normalise { |
… | |
… | |
405 | local $/ = "\n\n"; |
429 | local $/ = "\n\n"; |
406 | scalar <$fh>; |
430 | scalar <$fh>; |
407 | |
431 | |
408 | while (<$fh>) { |
432 | while (<$fh>) { |
409 | chomp; |
433 | chomp; |
410 | my %meta = split /[:\n]/; |
434 | my %meta = split /(?:: |\n)/; |
411 | |
435 | |
412 | $_ = <$fh>; |
436 | $_ = <$fh>; |
413 | |
437 | |
414 | /^##+\n/ or last; |
438 | /^##+\n/ or last; |
415 | |
439 | |
416 | # sokevo internally locks some cells |
440 | # sokevo internally locks some cells |
417 | y/^%:,;-=?/ #.$* +#/; |
441 | y/^%:,;-=?/ #.$* +#/; |
418 | |
442 | |
|
|
443 | # skip levels without pusher |
|
|
444 | y/@+// or next; |
|
|
445 | |
419 | push @levels, new Games::Sokoban data => $_, meta => \%meta; |
446 | push @levels, new Games::Sokoban data => $_, meta => \%meta; |
420 | } |
447 | } |
421 | |
448 | |
422 | \@levels |
449 | \@levels |
423 | } |
450 | } |