Games-Crossword-Puzzle

 view release on metacpan or  search on metacpan

lib/Games/Crossword/Puzzle.pm  view on Meta::CPAN

use strict;
use warnings;
package Games::Crossword::Puzzle 0.004;
# ABSTRACT: six letters for "reusable unit of code"

#pod =head1 SYNOPSIS
#pod
#pod   my $puzzle = Games::Crossword::Puzzle->from_file('nyt-sunday.puz');
#pod
#pod   for my $row ($puzzle->rows) {
#pod     for my $cell (@$row) {
#pod       die "Nope, not completed properly"
#pod         if $cell->value and (not $cell->guess) || $cell->guess ne $cell->value;
#pod     }
#pod   }
#pod
#pod =head1 DESCRIPTION
#pod
#pod The F<.PUZ> file format is used by many crossword programs and, more
#pod importantly, is offered by many newspapers.  It servers as both a puzzle and a
#pod "saved game," storing the grid, the answers, the clues, and guesses.
#pod
#pod Games::Crossword::Puzzle reads F<.PUZ> files and produces
#pod Games::Crossword::Puzzle objects.
#pod
#pod A puzzle is a rectangular grid of L<Games::Crossword::Puzzle::Cell> objects.
#pod
#pod =cut

use Carp ();
use Games::Crossword::Puzzle::Cell;

#pod =method from_file
#pod
#pod   my $puzzle = Games::Crossword::Puzzle->from_file($filename);
#pod
#pod This method reads in a puzzle file and returns a puzzle object.  It will raise
#pod an exception if the file does not appear to be a valid puzzle file.
#pod
#pod =cut

sub from_file {
  my ($class, $filename) = @_;

  my $self = bless {} => $class;

  open my $fh, $filename or die "couldn't open file: $!";

  seek $fh, 2, 0;
  read $fh, (my $magic), 12;
  die "file is not a valid puzzle" unless $magic eq "ACROSS&DOWN\0";

  {
    seek $fh, 0x2C, 0;
    read $fh, (my $size), 2;
    $self->{width}  = ord substr $size, 0, 1;
    $self->{height} = ord substr $size, 1, 1;
  }

  seek $fh, 0x34, 0;
  read $fh, (my $solution), $self->height * $self->width;
  read $fh, (my $guess), $self->height * $self->width;

  seek $fh, 0x2E, 0;
  read $fh, (my $clues), 2;
  $clues = unpack 'v2', $clues;

  seek $fh, 0x34  +  2 * $self->height * $self->width, 0;
  $self->{title}     = $self->_read_nul_string($fh);
  $self->{author}    = $self->_read_nul_string($fh);
  $self->{copyright} = $self->_read_nul_string($fh);

  my @clues;
  for (1 .. $clues) {
    my $clue = $self->_read_nul_string($fh);
    push @clues, $clue;
  }

  $self->{notes} = $self->_read_nul_string($fh);

  my $tables = $self->_read_tables($fh);

  $self->__build_grid(\$solution, \$guess, \@clues, $tables);

  return $self;
}

sub _read_tables {
  my ($self, $fh) = @_;

  my %return;

  while (! eof $fh) {
    read($fh, my $front, 8) or die "error reading table: $!";

    my ($title, $len, $ck) = unpack "A4SS", $front;
    read($fh, my $data, $len) or die "error reading table $title: $!";

    read($fh, my $nul, 1) or die "error reading table $title: $!";
    die "data for $title table not nul-terminated" unless $nul eq "\0";

    $return{ $title } = $data;
  }

  return \%return;

 view all matches for this distribution
 view release on metacpan -  search on metacpan

( run in 1.000 second using v1.00-cache-2.02-grep-82fe00e-cpan-1925d2aa809 )