Algorithm-X-DLX

 view release on metacpan or  search on metacpan

examples/sudoku/Sudoku.pm  view on Meta::CPAN

      $self->{values_} = [@$arg];
    } elsif (defined $arg && !ref($arg)) {
      croak "Got empty string" unless length $arg;
      $string = $arg;
    } else {
      die "Unknown blessed parameter.\n";
    }
  }

  if (! $self->{type_} && $string ) {
   $self->{type_} = SudokuType::guess($string);
  }

  if (! $self->{values_} && $string ) {
   $self->{values_} = SudokuFormat::get_values($string);
  }
  
  $self->{type_}   ||= SudokuType->new();
  $self->{values_} ||= [(0) x $self->{type_}->size()];

  return bless $self, $class;

examples/sudoku/SudokuFormat.pm  view on Meta::CPAN

       $self->{template} = $input;
    }

    if (ref($type_or_format) eq 'SudokuType') {
        my $type = $type_or_format;
        $self->{type} = $type;
        $self->{template} ||= default_template($type);

    } else {
        my $format = $type_or_format;
        my $type = SudokuType::guess($format);
        $self->{type} = $type;
        $self->{template} ||= $format;
    }

    $self->{labels} = choose_labels($self->{template});
    
    # Validate cells
    my $cells = 0;
    foreach my $c (split //, $self->{template}) {
        if (is_cell($c, $self)) {

examples/sudoku/SudokuType.pm  view on Meta::CPAN

    croak "Sudoku must have non-zero size";
  }
  return $type;
}

sub from_size {
    my ($size) = @_;
    return new(__PACKAGE__, isqrt($size));
}

sub guess {
  my ($str) = @_;

  my @lines;
  my $line = '';
  my $cells = 0;
  my $size = SudokuFormat::count_cells($str);
  my $n = isqrt($size);
  
  foreach my $c (split //, $str) {
    if ($c eq "\n") {

examples/sudoku/SudokuType.pm  view on Meta::CPAN

  for my $y (0 .. $#lines) {
    for my $x (0 .. length($lines[$y]) - 1) {
      if (SudokuFormat::is_valid_cell(substr($lines[$y], $x, 1))) {
        $total_size++;
        $region_size{$region[$y][$x]}++;
        push @final_regions, $region[$y][$x];
      }
    }
  }
#print "\%region_size = ", Dumper(\%region_size);
#print "guess(): \$total_size = $total_size, \$size = $size\n";
  croak "Total size mismatch" if $total_size != $size;
#print "guess(): \$n = $n, \@final_regions = (@final_regions)\n";
#print Dumper(\%region_size);
  for my $p (values %region_size) {
    return from_size($size) if $p != $n;
#      croak "Region has wrong size" if $p != $n;
  }

  return new(__PACKAGE__, \@final_regions);
}

sub n {

examples/sudoku/sudoku.pl  view on Meta::CPAN

    $input .= $line;
    if (!$opt_one_sudoku_per_line) {
      $input .= "\n";
      next unless eof(STDIN);
    }
  }

  $input or next;

  eval {
    my $type = SudokuType::guess($input);

    my $format;
    if ($opt_format eq 'PRESERVE') {
      $format = SudokuFormat->new($type, $input);
    } elsif ($opt_format eq 'COMPACT') {
      $format = SudokuFormat->compact($type);
    } elsif ($opt_format eq 'ONELINE') {
      $format = SudokuFormat->oneline($type);
    } else {
      $format = SudokuFormat->new($type);

examples/t/sudoku/02-sudokutype.t  view on Meta::CPAN


	lives_ok { SudokuType->new([0]) } 'valid type';
	lives_ok { SudokuType->new([1]) } 'valid type';
	lives_ok { SudokuType->new([999]) } 'valid type';
	lives_ok { SudokuType->new([0, 0, 1, 1]) } 'valid type';
	lives_ok { SudokuType->new([0, 1, 1, 0]) } 'valid type';

	is_deeply(SudokuType->new([0, 0, 1, 1]),  SudokuType->new([6, 6, 2, 2]), 'same custom type');
};

subtest 'guess type nxn regions' => sub {
  plan tests => 7;
	throws_ok { SudokuType::guess(join '',
    "....",
    "....",
    "....",
    "..."
  ) } qr/Not a square/i, 'corrupt lines';
	throws_ok { SudokuType::guess(join '',
    "....",
    "....",
    "....",
    "....."
  ) } qr/Not a square/i, 'corrupt lines';
	is_deeply(SudokuType->new(1),  SudokuType::guess(join '',
    "+-+\n",
    "|.|\n",
    "+-+\n"
  ), 'same custom type');
	is_deeply(SudokuType->new(4),  SudokuType::guess(join '',
    "....",
    "....",
    "....",
    "....",
  ), 'same custom type');
	is_deeply(SudokuType->new(4),  SudokuType::guess(join '',
    ". .|..\n",
    ". .|..\n",
    " +-+--\n",
    ".|.|..\n",
    "-+ |  \n",
    ". .|..\n"
  ), 'same custom type');
	is_deeply(SudokuType->new(4),  SudokuType::guess(join '',
    "..|..\n",
    "..|..\n",
    "..|..\n",
    "--+--\n",
    "..|..\n"
  ), 'same custom type');
	is_deeply(SudokuType->new(4),  SudokuType::guess(join '',
    ".1|..\n",
    "..|2.\n",
    "-----\n",
    "z.|..\n",
    ".a|..\n"
  ), 'same custom type');
};

subtest 'guess type nxm regions' => sub {
  plan tests => 6;
	is_deeply(SudokuType->new(4, 1),  SudokuType::guess(join '',
    "....\n",
    "----\n",
    "....\n",
    "----\n",
    "....\n",
    "----\n",
    "....\n"
  ), 'same custom type');
	is_deeply(SudokuType->new(1, 4),  SudokuType::guess(join '',
    ".|.|.|.\n",
    ".|.|.|.\n",
    ".|.|.|.\n",
    ".|.|.|.\n"
  ), 'same custom type');
	is_deeply(SudokuType->new(3, 2),  SudokuType::guess(join '',
    "|...|...|\n",
    "|...|...|\n",
    "|-------|\n",
    "|...|...|\n",
    "|...|...|\n",
    "|-------|\n",
    "|...|...|\n",
    "|...|...|\n"
  ), 'same custom type');
	is_deeply(SudokuType->new(3, 2),  SudokuType::guess(join '',
    "|...|...|\n",
    "|...|...|\n",
    "\n",
    "|...|...|\n",
    "|...|...|\n",
    "\n",
    "|...|...|\n",
    "|...|...|\n"
  ), 'same custom type');
	is_deeply(SudokuType->new(3, 2),  SudokuType::guess(join '',
    "...|......|...\n\n",
    "...|......|...\n\n",
    "...|......|..."
  ), 'same custom type');
	is_deeply(SudokuType->new(3, 2),  SudokuType::guess(join '',
    "|. ..|...|\n",
    "|. ..|...|\n",
    "----------\n",
    "|. ..|...|\n",
    "|. ..|...|\n",
    "----------\n",
    "|. ..|...|\n",
    "|    |   |\n",
    "|. ..|...|\n"
  ), 'same custom type');
};

subtest 'guess arbitrary regions' => sub {
  plan tests => 5;
	is_deeply(SudokuType->new([
    0, 0, 1, 1, 1, 1, 2,
    0, 0, 0, 1, 1, 1, 2,
    3, 0, 0, 4, 4, 2, 2,
    3, 3, 4, 4, 4, 2, 2,
    3, 3, 4, 4, 5, 5, 2,
    3, 6, 6, 6, 5, 5, 5,
    3, 6, 6, 6, 6, 5, 5,
  ]), SudokuType::guess(join '',
    "+---+-------+-+\n",
    "|. .|. . . .|.|\n",
    "|   +-+     | |\n",
    "|. . .|. . .|.|\n",
    "+-+   +---+-+ |\n",
    "|.|. .|. .|. .|\n",
    "| +-+-+   |   |\n",
    "|. .|. . .|. .|\n",
    "|   |   +-+-+ |\n",
    "|. .|. .|. .|.|\n",

examples/t/sudoku/02-sudokutype.t  view on Meta::CPAN

    "|.|. . .|. . .|\n",
    "| |     +-+   |\n",
    "|.|. . . .|. .|\n",
    "+-+-------+---+\n"
  ), 'same arbitrary type');
	is_deeply(SudokuType->new([
    0, 0, 0, 1,
    0, 1, 1, 1,
    2, 3, 3, 3,
    2, 2, 2, 3,
  ]), SudokuType::guess(join '',
    ". ..|.\n",
    "  --  \n",
    ".|.. .\n",
    "------\n",
    ".|.. .\n",
    "  --  \n",
    ". ..|.\n"
  ), 'same arbitrary type');
	is_deeply(SudokuType->new([
    0, 0, 0, 1,
    0, 1, 1, 1,
    2, 3, 3, 3,
    2, 2, 2, 3,
  ]), SudokuType::guess(join '',
    "...|.\n",
    "  /  \n",
    ".|...\n",
    "-----\n",
    ".|...\n",
    " --- \n",
    "...|.\n"
  ), 'same arbitrary type');
	is_deeply(SudokuType->new([
    0, 0, 0, 1,
    0, 1, 1, 1,
    2, 3, 3, 3,
    2, 2, 2, 3,
  ]), SudokuType::guess(join '',
    "...,.",
    ".!!...\n",
    "\n",
    ".@#...",
    "..._."
  ), 'same arbitrary type');
	is_deeply(SudokuType->new([
    0, 0, 0, 1,
    0, 1, 1, 1,
    2, 3, 3, 3,
    2, 2, 2, 3,
  ]), SudokuType::guess(
    "...,..=]...\n\n.:)......_."
  ), 'same arbitrary type');

};

done_testing();



( run in 0.261 second using v1.01-cache-2.11-cpan-702932259ff )