#!/usr/local/bin/perl -w

$file = $ARGV[0];
unless ($file){ $file="sudoku.in"; }

$c=0;
open IN, "< $file" or die "Cannot open $file: $!";
while (<IN>){
    chomp;
    @data = split "", $_;
    $j=0;
    for $i (@data){
	$d[$c][$j]=$i;
	print "$i";
	if ($i =~ /\d/) { 
	    $sol[$c][$j]=$i;
	}
	$j++;
	last if ($j==9);
    }
    print "\n";
    $c++;
    last if ($c==9);
}
close IN;
$c--;

top:
$countant=$count=9*9*9;
$iter=0;
$supo=0;
print "-"x20;
init();
while ($count!=81){
    $iter++;
    selec_xy();
    selec_box();
    $count=0;
    for $i (0..8){
	for $j (0..8){
	    $ok=0;
	    for $k (1..9){
		$ok+=$set[$i][$j][$k];
		if ($set[$i][$j][$k]==1){ $kk = $k; }
	    }
	    if ($ok==1){
		$sol[$i][$j]=$kk;
		tacha($i,$j,$kk);
	    }
	    $count+= $ok;
	}
    }
    print "$count posibilidades\n";
    report();
    if ($count<9*9){  goto top; }
    if ($count==$countant && $iter>2){
	$iter = 0;
	for $i (0..8){
	    for $j (0..8){
		$ok=0;
		for $k (1..9){
		    $ok += $set[$i][$j][$k];
		}
		if ($ok==2){
		    $random = rand();
		    for $k (1..9){                    # reverse?
			if ($random >.5) { $k = 9-$k+1; }
			if ($set[$i][$j][$k]==1){
			    if (!defined $guess[$i][$j]){
				$sol[$i][$j]=$k;
				tacha($i,$j,$k);
				$guess[$i][$j]++;
				$supo++;
				goto bottom;
			    }elsif ($guess[$i][$j]<2 && $supo%2==1) {
				$sol[$i][$j]=$k;
				tacha($i,$j,$k);
				$guess[$i][$j]++;
				goto bottom;
			    }
			}
		    }
		}
	    }
	}
    }
bottom:
    $countant=$count;
    print "$supo Suposiciones\n";
}


sub selec_xy{
    for $k (1..9){
	for $i (0..8){
	    $kount=0;
	    for $j (0..8){
		$kount += $set[$i][$j][$k];
		if ($set[$i][$j][$k]==1){ $jj = $j; }
	    }
	    if ($kount==1){
		$sol[$i][$jj]=$k;
		tacha($i,$jj,$k);
	    }
	}
	for $j (0..8){
	    $kount=0;
	    for $i (0..8){
		$kount += $set[$i][$j][$k];
		if ($set[$i][$j][$k]==1){ $ii = $i; }
	    }
	    if ($kount==1){
		$sol[$ii][$j]=$k;
		tacha($ii,$j,$k);
	    }
	}
    }
}


sub selec_box{
    for $k (1..9){
	$kount=0;
	for $l (0..2){
	    for $m (0..2){
		$kount += $set[$l][$m][$k];
		if ($set[$l][$m][$k]==1) { $ll=$l; $mm=$m; }
	    }
	}
	if ($kount==1){
	    $sol[$ll][$mm]=$k;
	    tacha($ll,$mm,$k);
	}
	$kount=0;
	for $l (0..2){
	    for $m (3..5){
		$kount += $set[$l][$m][$k];
		if ($set[$l][$m][$k]==1) { $ll=$l; $mm=$m; }
	    }
	}
	if ($kount==1){
	    $sol[$ll][$mm]=$k;
	    tacha($ll,$mm,$k);
	}
	$kount=0;
	for $l (0..2){
	    for $m (6..8){
		$kount += $set[$l][$m][$k];
		if ($set[$l][$m][$k]==1) { $ll=$l; $mm=$m; }
	    }
	}
	if ($kount==1){
	    $sol[$ll][$mm]=$k;
	    tacha($ll,$mm,$k);
	}
	$kount=0;
	for $l (3..5){
	    for $m (0..2){
		$kount += $set[$l][$m][$k];
		if ($set[$l][$m][$k]==1) { $ll=$l; $mm=$m; }
	    }
	}
	if ($kount==1){
	    $sol[$ll][$mm]=$k;
	    tacha($ll,$mm,$k);
	}
	$kount=0;
	for $l (3..5){
	    for $m (3..5){
		$kount += $set[$l][$m][$k];
		if ($set[$l][$m][$k]==1) { $ll=$l; $mm=$m; }
	    }
	}
	if ($kount==1){
	    $sol[$ll][$mm]=$k;
	    tacha($ll,$mm,$k);
	}
	$kount=0;
	for $l (3..5){
	    for $m (6..8){
		$kount += $set[$l][$m][$k];
		if ($set[$l][$m][$k]==1) { $ll=$l; $mm=$m; }
	    }
	}
	if ($kount==1){
	    $sol[$ll][$mm]=$k;
	    tacha($ll,$mm,$k);
	}
	$kount=0;
	for $l (6..8){
	    for $m (0..2){
		$kount += $set[$l][$m][$k];
		if ($set[$l][$m][$k]==1) { $ll=$l; $mm=$m; }
	    }
	}
	if ($kount==1){
	    $sol[$ll][$mm]=$k;
	    tacha($ll,$mm,$k);
	}
	$kount=0;
	for $l (6..8){
	    for $m (3..5){
		$kount += $set[$l][$m][$k];
		if ($set[$l][$m][$k]==1) { $ll=$l; $mm=$m; }
	    }
	}
	if ($kount==1){
	    $sol[$ll][$mm]=$k;
	    tacha($ll,$mm,$k);
	}
	$kount=0;
	for $l (6..8){
	    for $m (6..8){
		$kount += $set[$l][$m][$k];
		if ($set[$l][$m][$k]==1) { $ll=$l; $mm=$m; }
	    }
	}
	if ($kount==1){
	    $sol[$ll][$mm]=$k;
	    tacha($ll,$mm,$k);
	}
    }
}


sub init{
    for $i (0..8){
	for $j (0..8){
	    for $k (1..9){
		$set[$i][$j][$k]=1;
	    }
	}
    }
    for $i (0..8){
	for $j (0..8){
	    if ($d[$i][$j] !~ /\d/){ $sol[$i][$j]=undef; }
	    if (defined $sol[$i][$j]){
#		unless (defined $guess[$i][$j]){
		    tacha($i,$j,$sol[$i][$j]);
#		}
	    }
	}
    }
}

sub report {
    print "\n";
    for $i (0..8){
	for $j (0..8){
	    for $k (1..9){
		if ($set[$i][$j][$k]==1){
		    print $k;
		}
	    }
	    print " ";
	}
	print "\n";
    }
    print "\n";
}

sub tacha{
    my ($i,$j,$z) = @_;
    my ($k,$l);
    for $k (0..8){
	$set[$i][$k][$z]=0;
	$set[$k][$j][$z]=0;
    }
    for $k (1..9){
	$set[$i][$j][$k]=0;
    }
    if ($i<=2){
	if ($j<=2){
	    for $k (0..2){
		for $l (0..2){
		    $set[$k][$l][$z]=0;
		}
	    }
	}elsif ($j>2 && $j<=5){
	    for $k (0..2){
		for $l (3..5){
		    $set[$k][$l][$z]=0;
		}
	    }
	}elsif ($j>5 && $j<=8){
	    for $k (0..2){
		for $l (6..8){
		    $set[$k][$l][$z]=0;
		}
	    }
	}	
    }elsif ($i>2 && $i<=5){
	if ($j<=2){
	    for $k (3..5){
		for $l (0..2){
		    $set[$k][$l][$z]=0;
		}
	    }
	}elsif ($j>2 && $j<=5){
	    for $k (3..5){
		for $l (3..5){
		    $set[$k][$l][$z]=0;
		}
	    }
	}elsif ($j>5 && $j<=8){
	    for $k (3..5){
		for $l (6..8){
		    $set[$k][$l][$z]=0;
		}
	    }
	}	
    }elsif ($i>5 && $i<=8){
	if ($j<=2){
	    for $k (6..8){
		for $l (0..2){
		    $set[$k][$l][$z]=0;
		}
	    }
	}elsif ($j>2 && $j<=5){
	    for $k (6..8){
		for $l (3..5){
		    $set[$k][$l][$z]=0;
		}
	    }
	}elsif ($j>5 && $j<=8){
	    for $k (6..8){
		for $l (6..8){
		    $set[$k][$l][$z]=0;
		}
	    }		    
	}	
    }
    $set[$i][$j][$z]=1;
}		


__END__
Ejemplo de fichero sudoku.in
--25---4-
9----86--
-6--4----
-1-----98
3---8---4
48-----3-
----3--1-
--17----6
-2---97--
  
