Add preview of 1984-2019

The 2020 winners are hinted it, but the source code is not there,
nor are the hints. Someone could look into the HTML and
see what was commented out, but that is not a problem because
WHO won is known and the name of their AWARD is known already.
Moreover a number of the winners have talked about what their
entirs do, so the commented out spoiler text is not a bit problem.

One will find HTML commented out with:

    <!-- XXX remove when 2020 is ready
    2020 links here
    XXX remove when 2020 is ready -->

The "XXX remove when 2020 is ready" string is found at the
start and end comment blocks.  Again, soneone could read
what was commented out, but that is OK since most of that
information is known or can be known.  The following files
have such HTML comment blocks in them.

    ./winners.html
    ./years-spoiler.html
    ./years.html

In addition, ./all/summary.txt was modified to not
include the 2020 entries for the momemt.

The 2020 winner code AND write-ups are NOT part of this set.

p.s. The all/all.tar.bz2 does not contain the 2020 source code (yet?).
This commit is contained in:
Landon Curt Noll committed 2020-12-30 16:57:03 -08:00
1 parent 28efc67f5d
commit c0663537cb
1683 files changed
+220064

No files matched your search

+15
View File
@@ -0,0 +1,15 @@
build: aidan
clean:
clobber:
-rm aidan
aidan: aidan.c
${CC} ${CFLAGS} ${LDFLAGS} $< -o $@
alt:
data:
+74
View File
@@ -0,0 +1,74 @@
#include <stdio.h>
#include <stdlib.h>
#define N(I,l) s l]=(I?1<<I|I<<10:01776)
#define f(a,t) for(a=0;a<t;a++)
#define Su(d,o,ku) O(l/9,d) O(l%9,o) O(l%9/3+l/27*3,ku)
#define NO ;printf("%c %s",I?I|48:46,++l%3?"":l%9?"| ":l%27?"\n":l%'Q'?z:"\n");
#define Ba(k,a) {O||printf("!!! " #a " %i\n",k+1);goto l;}
#define O(o,k) f(l,9) c[l]= *#k?0x3fe:-1;\
f(l,81) if(*#k){\
if(!(s]&c[o])) Ba(o,k) c[o]&=~(1<<(s]>>10));\
} else if((s]>>l0)&1) c[o]=c[o]+1?-2:l;\
if(*#k) { f(l,81) if(s]>>10||(s]&=c[o]),!s]) Ba(o,k) }\
else f(l,9) l[c]<0||s[c]]>>10||(N(l0,[c]),C++);
struct{ int s[81],I,l,O; } S[0123];
int I, l, l0, o, C, O=0, w=0, c[10], L; long i;
char z[] = "\007 & & \n";
#define s S].s[l
int main(int n,char**N) {
S->O=0; L=n>1?*N[1]-85?1:6:0; i=L&1?atol(N[1]):123;
#define i (int)(81.0*(i=1103515245*i+12345&0x7fffffff)/2147483648.0)
for(l=C=0;l<81;) {
I=L&1?0:getchar()^48; i; I=I-30?I:0;
if(I<10) {
#define S S[O
if(C<22) z[C++]^=13; N(I,)NO
}
}
for(;;) {
l0:
Su(row,col,box) C=l0=0;
f(l,81) if(!(s]>>10&&++l0)) {
o=s]&1022; for(I=0;~o&1&&(o/=2);I++); o-1||(s]|=I<<10,C++);
} if(l0==l) {
if(O&&L&2) { O--; goto l0; } goto O;
} for(l0=1;10>l0;l0++) { Su(,,) }
if(!C) {
l=(o=S].O)?S].I:0; I=o?S].l%9+1:(S].O=i%9+1);
for(;l<81;l++,I=S].O,o=0) if(!(s]>>10)) {
for(;;I=I%9+1,o=1) {
l0=0; if(o&&I==S].O) goto O;
if(s]>>I&1) {
S].l=I; S++].I=l; S]=S-1];
N(I,); O>w&&(w=O); goto lO;
}
}
}
}
lO: S].O=0; goto l0; l: if(!(l0=O)) { L=0; goto O; } O--;
s,S].I] &=~ (1<<S].l);
}
O: switch(L) {
case 2: if(l0) {
case 3: O=82;
for(S].l=l=i%81;l0||S].l-l;l=(l+1)%81)
O1: if(l0=0,S].O=s]>>10,~s]&1) {
s]=1023; S].I=l; S&0]=S]; w=O=0; L=2; goto lO;
}
L=0; l0=1;
} else {
l=S=82].I; N(S].O,)|1; goto O1;
}
}
printf("\n\n"); for(l=0;l<81;) {I=s]>>10 NO}
printf("\n%s (stk %i %i)\n",l0?"Done":"No way!",O,w);
L|=2; if(L-3||!l0) return!l0; S,82]=S]; goto O;
}
+11
View File
@@ -0,0 +1,11 @@
. . . | . . . | . . .
. . . | . . . | . . .
. . . | . . . | . . .
------+-------+------
. . . | . . . | . . .
. . . | . . . | . . .
. . . | . . . | . . .
------+-------+------
. . . | . . . | . . .
. . . | . . . | . . .
. . . | . . . | . . .
+260
View File
@@ -0,0 +1,260 @@
# Most ingenious puzzle solution
Aidan Thornton
United Kingdom
makomk@lycos.co.uk
## Judges' comments
Are you puzzled about puzzles? This entry might puzzle you
more while it puzzles out some puzzles: all in a puzzling way!
Goto the source and notice the lack of functions. Jump
to the switch statement. And if you think you can puzzle
it out better, try solving insane1.sudoku all by yourself!
### To build
cc -O2 -o aidan aidan.c
## Author's comments
This program can solve a type of logic puzzle known as a Sudoku, and also
generate new ones. (Apparently, the puzzle is known as Number Place in the US,
but we in the UK got it via Japan, where it's quite common in magazines, etc.
These things happen sometimes.)
### Contents
* build file: build.txt - you don't need this
* program file: sudoku-sf.c - sudoku solver and generator
* remarks file: sudoku-sf.txt - this file
* info file: test-su.perl - optional test script (written for Perl5)
* info file: eg-sudoku.tar - various assorted example sudokus
**XXX - now the tar file includes the test script and the examples**
Yes, the test suite really is 5 times larger than the actual program. You
**did** say this was a parody of the software development process...
> **IMPORTANT!**
>
> test.perl expects the sudoku-sf executable to be `./sudoku-sf`. If you rename
> it, please change the definition of $sf_exe to the new name
>
> **IMPORTANT!**
### Legal blurb
This program comes with NO WARRANTY, not even that it'll do what I say it
should. Any misfortunes that occur as a result of using this are not my fault.
Go find some unpopular multinational to sue instead.
This program is not copyrighted and is entirely my work. Distribute or modify
it as you wish, though please give me credit.
### What is a sudoku?
(If you know, feel free to skip this section. Get more details from [the
wikipedia entry])
[the wikipedia entry]: http://en.wikipedia.org/wiki/Sudoku
A sudoku is a type of logic puzzle. You are given a grid of 9x9 boxes, some
of which contain digits. This is divided into nine 3x3 boxes, e.g. (from the
Wikipedia article - fairly easy):
. . . | 1 . . | 7 4 .
. 5 . | . 9 . | . 3 2
. . 6 | 7 . . | 9 . .
------+-------+------
4 . . | 8 . . | . . .
. 2 . | . . . | . 1 .
. . . | . . 9 | . . 5
------+-------+------
. . 4 | . . 7 | 3 . .
7 3 . | . 2 . | . 6 .
. 6 5 | . . 4 | . . .
You have to fill in the remaining boxes so that each row, column, and smaller
box contains all of the digits 1-9. That's all the information I needed to
figure out how to solve them, but there's a useful tutorial on
<http://www.sudoku.org.uk/>, which is roughly affiliated with the Daily
Telegraph (a UK newspaper).
Now, with modern computers this **can** be solved using brute force, e.g.:
#include <stdio.h> /* sudoku-bfi.c */
#define S(t) for(n=0;n<9;v[n++]=0);for(n=0;n<81;n++)if(i[n]){z=1<<i[n];if(v[t]\
&z)for(;;){if(p<0)goto d;if(i[p]++<9)goto f;i[p]=0;p=s[p];}v[t]|=z;}
int i[82],s[81],v[9],n,p,z;int main(void){for(n=0;n<81;){p=getchar()^48;if(p==
30)p=0;if(p<10)i[n++]=p;}i[81]=0;p=-1;f:S(n%9)S(n/9)S(n%9/3+n/27*3)if(p>80)goto
d;for(n=p;i[++p];);s[p]=n;i[p]=1;goto f;d:z=p<81;printf("\n%s!\n\n",z?"Fail":
"Success");for(n=0;n<81;){p=i[n];printf("%c %s",(p?p|48:'.'),(++n%3?"":n%9?"| "
:n%27?"\n":n%81?"\n------+-------+------\n":"\n\n"));}return z;}
That isn't the approach I've used; it's slow (particularly in worst-case or
nearly so scenarios), inelegant, and not a good starting point for sudoku
generation. It's also much too easy to understand ;-) Instead, I've written a
program which solves them in much the same way as I do, only a lot faster (and
hopefully more reliably).
Oh, and if you think that example sudoku is too easy, try this one (which my
program generated):
--- insane1.sudoku --
. . 4 | . . . | . 5 6
5 . . | . 7 2 | . . .
. . 1 | . . . | 8 . .
------+-------+------
. . . | . . . | . . .
. . . | 6 9 3 | . . 5
. . . | . . . | 7 3 4
------+-------+------
. 5 . | 2 . 1 | 4 . 8
3 . . | . . . | . . .
. . . | . . . | . 6 1
Be warned - it's evil! (I certainly haven't been able to solve it by hand. The
brute-force program given above, sudoku-bfi.c, also has trouble - it took 66
seconds to solve it - but probably for different reasons. That's the worst
performance I've had from brute-force so far!)
### Usage
#### Building
cc -o sudoku-bf sudoku-bf.c
-- or, if using gcc, try --
gcc -O2 -Wall -Wextra -ansi -pedantic-errors -o sudoku-sf sudoku-sf.c
-- or, if using gcc and feeling lazy --
sh build.txt
#### Testing (optional)
perl ./test-su.perl
Note that this requires Perl 5 (I use 5.8.5, earlier versions untested) and is
somewhat slow (should take under a minute on a fairly modern PC - try
appending "-n 0" if you're in a hurry). I wrote it mostly for my own benefit,
really.
#### Solving
./sudoku-sf < somefile.txt
Input should be the numbers of each row in turn. Empty spaces can be
represented as a period (.) or zero (0). Other characters are ignored, so you
can cut-and-paste either example sudoku from above into a file and feed that
in. The program has coped with every input I've thrown at it so far, including
an empty grid.
Output consists of the problem, then the solution, then a message of
success/failure.
`./sudoku-sf U` (capital U), may also be useful, or perhaps not. It only took
an extra 15 bytes of (very simple) code to add, so it doesn't really matter to
me. (It's the same as the normal mode for most input you're likely to feed in,
though slightly slower. See if you can figure out what it does.)
#### Generating
./sudoku <seed>
Output is a blank grid, then the solution, then the problem. There's no
control over the difficulty. Sorry. However, all generated sudokus should have
exactly one solution - if one doesn't, that's a bug.
### Speed
Fast enough. Solving and generating are practically instant on my 1Ghz Duron.
Of course, there could be some cases which take longer...
More precisely - 400 random sudokus are generated and solved in about 45
seconds in tests on my PC (1Ghz Duron, gcc 3.4.1, -O2 optimisation - takes
about 60 seconds with no optimisation). If that isn't fast enough, what on
Earth are you doing with it?
### Bugs
None known - hopefully I've worked out all the major ones. Nothing has come up
in testing since the last bugfix, but what does that mean?
Tested on:
- gcc 3.4.1-3mdk, Linux/x86
*RETEST* Borland C 4.5, 16-bit DOS .exe (small memory model)
I don't count the fact that it first prints a blank grid whenever asked to
generate a sudoku as a bug - just a minor quirk. The fix is slightly awkward
and would make the program slightly longer, so I haven't bothered - it's not
important.
### Missing Features
* No control over the difficulty of generated sudokus - they vary from easy
to hair-tugging near-impossibility. Solver beware. Seeing as apparently one
program [took six years], I'm in no hurry.
[took six years]: http://news.bbc.co.uk/1/hi/magazine/4469719.stm
* Some sort of curses-based UI to let you solve interactively might be cool,
but I don't feel like learning curses just for this. Besides, I spent enough
of the time swearing as it is.
* If you mistype a sudoku (e.g. from a paper/magazine) - and you will it
can't help you figure out where the mistake is, sadly.
### Portability
Dependant on ASCII, requires that an int is at least 15 bits and a long at
least 32. (No, that isn't a typo - I did say 15, not 16).
Also requires that cpp can properly handle something like:
#define foo(x,y) x y
foo(bar,)
Apparently, a few can't (ANSI C specifically doesn't require that this works,
though it usually does). Unfortunately, I didn't discover this issue until too
late. (It was mentioned in the notes for people modifying GCC in the "beware
of obscure compiler limitations" section, so I'm figuring it's quite unusual.)
### Compiler warnings
Some when compiled with `gcc -Wall -Wextra -ansi -pedantic`:
* The left-hand operand of a comma has no effect in two places
* Parentheses are suggested around a + in an operand of & in the "i" macro
definition.
Borland C also spots some code in expressions which has no effect, and some
uses of '=' where you'd expect a comparison operator.
### Obfuscation
Let's see now:
* Squint-inducing variable naming
* Slightly odd `#defines` (which will be cleaned up by cpp + a code
beautifier, but see the next item)
* No functions but main() - all code reuse via #defines, or by various other
methods (usually somewhat icky ones). This wasn't deliberate - it just ended
up that way somehow...
* Gotos from everywhere to everywhere else
* A slightly... interesting switch statement.
* Generally odd flow of control (see above items)
* Plenty of bit-twiddling
* To save space, no 'A'-style char constants - hard-coded numbers are used.
(There's one, but it isn't used to make things **clearer**)
* `array[index]` notation, because:
- a) it's traditional
- b) take a look at how the s and N(I,l) macros are used
* various other little things not worth mentioning
So basically, just what you'd normally expect in an IOCCC entry
+11
View File
@@ -0,0 +1,11 @@
. . 4 | . . . | . 5 6
5 . . | . 7 2 | . . .
. . 1 | . . . | 8 . .
------+-------+------
. . . | . . . | . . .
. . . | 6 9 3 | . . 5
. . . | . . . | 7 3 4
------+-------+------
. 5 . | 2 . 1 | 4 . 8
3 . . | . . . | . . .
. . . | . . . | . 6 1
+13
View File
@@ -0,0 +1,13 @@
2 . . | . . . | . . 4
. . . | . . . | 2 . .
9 . 4 | . 2 3 | . 8 .
------+-------+------
4 . . | . . . | . 9 .
1 9 2 | . . . | 8 . .
3 . 6 | . 1 . | 5 2 .
------+-------+------
. 1 . | . . 8 | . . .
. . . | 6 9 . | 3 . .
. . . | . . 5 | . . 9
Seed #100440625
+13
View File
@@ -0,0 +1,13 @@
. . . | 4 . . | . . 5
. . . | . . 1 | 6 . 9
7 . . | . . 3 | . . .
------+-------+------
. . . | . 6 . | 2 . 1
4 . 5 | . . . | 7 3 .
. 7 . | . . . | . . .
------+-------+------
. . . | 3 7 2 | . . .
. . . | . . . | . 1 .
3 . . | . 4 . | 9 . .
Seed #105761662
+13
View File
@@ -0,0 +1,13 @@
. . . | 2 . 9 | . . .
. . 7 | . . . | . . 3
3 . . | . . . | . 5 6
------+-------+------
. 5 . | . . . | . . .
. 9 . | . . . | 3 6 5
. 4 . | . . 6 | 7 8 .
------+-------+------
. . . | 6 . . | . 4 .
. . 4 | . 2 5 | 8 . 7
9 . . | . 8 . | . . .
Seed unknown
+13
View File
@@ -0,0 +1,13 @@
. . . | . . 2 | . . .
. . 1 | . 5 6 | . . .
4 5 6 | 3 . . | . . .
------+-------+------
3 . . | 7 . 9 | . 4 5
. . . | . . . | 6 . .
. . . | . . . | 9 . .
------+-------+------
5 . . | . . 8 | 7 . 2
. 3 . | . . . | . . 4
8 . 2 | 5 4 . | . . .
Seed #909990524
+366
View File
@@ -0,0 +1,366 @@
#!/usr/bin/perl --
#use strict;
use warnings;
use IPC::Open2;
my $sf_exe = "./sudoku-sf"; # location of sudoku-sf executable
my $vflg=0; my $gcmd=$sf_exe; my $scmd=$sf_exe;
my $gcnt=400; my $soff=2; my $fbad=1; my $ffile=1;
my $fgen=1; my $zoom=0; my $rflg=1; my $fint=1;
my $n; my $stkc; my $stkw;
my $squstr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" . "abcdefghijklmnopqrstuvwxyz"
. "0123456789,.";
sub sq($);
sub read_file($);
sub sq_tst($) {
my $i;
$i = substr($_[0],1) if($_[0]=~/^-./);
$i = read_file($_[0]) unless($i);
$i = squish($i); print $i,"\n";
}
for($n=0;$n<@ARGV;$n++) {
if($ARGV[$n] eq "-h"||$ARGV[$n] eq "--help") {
print "\n",
"test-su.perl - automated testing for the sudoku-sf sudoku solver\n",
"Assumes sudoku-sf executable is at \"$sf_exe\" (\$sf_exe)\n",
"This code is PUBLIC DOMAIN and comes with NO WARRANTY\n\n",
"Usage:\n",
"------\n",
"test-su.perl [-v] [-s solver] [-g <genprog>] [-n <no>] <flags...>\n",
" -v - verbose mode\n",
" -s <solver> - path to sudoku solver executable ($sf_exe)\n",
" -g <genprog> - path to sudoku generator executable ($sf_exe)\n",
" -n <no> - number of random sudokus to generate and solve (400)\n",
" -s +Z -Z -z - none of your business (obscure & useless)\n",
" -h|--help - show this usage screen and exit\n\n",
"flags (+ enables, - disables):\n",
" +B|-B - enable/disable testing bad sudoku detection (+B)\n",
" +F|-F - enable/disable testing sudokus from *.sudoku files (+F)\n",
" +G|-G - enable/disable sudoku generation (+G)\n",
" +R|-R - enable/disable PRNG tests (+R, may change)\n",
" +I|-I - test using included sudoku (+I)\n",
"Basic usage is just: test-su.perl\n",
"Add -R if the PRNG tests cause problems, and -n 0 if in a hurry\n";
exit;
}
if($ARGV[$n] eq "-v") { $vflg = 1; next; }
if($ARGV[$n] eq "-s") { $scmd = $ARGV[++$n]; next; }
if($ARGV[$n] eq "-g") { $gcmd = $ARGV[++$n]; next; }
if($ARGV[$n] eq "-n") { $gcnt = 0+$ARGV[++$n]; next; }
if($ARGV[$n] eq "-S") { $soff = 0+$ARGV[++$n]; next; }
if($ARGV[$n] eq "-B") { $fbad = 0; next; }
if($ARGV[$n] eq "+B") { $fbad = 1; next; }
if($ARGV[$n] eq "-F") { $ffile = 0; next; }
if($ARGV[$n] eq "+F") { $ffile = 1; next; }
if($ARGV[$n] eq "-G") { $fgen = 0; $gcnt = 0; next; }
if($ARGV[$n] eq "+G") { $fgen = 1; next; }
if($ARGV[$n] eq "+Z") { $zoom = 1; next; }
if($ARGV[$n] eq "-Z") { $zoom = 0; next; }
if($ARGV[$n] eq "+R") { $rflg = 1; next; }
if($ARGV[$n] eq "-R") { $rflg = 0; next; }
if($ARGV[$n] eq "+I") { $fint = 1; next; }
if($ARGV[$n] eq "-I") { $fint = 0; next; }
if($ARGV[$n] eq "-z") { sq_tst($ARGV[++$n]); exit; }
printf "\nUnknown option '%s', try '-h' for valid options\n\n", $ARGV[$n];
die("Bad command-line options");
}
sub rpe() {
my $n = ""; my $c=0; local $_;
foreach(@l) {
if(/^\s*[\d.]\s*[\d.]\s*[\d.]\s*\|\s*[\d.]\s*[\d.]\s*[\d.]\s*\|\s*[\d.]\s*[\d.]\s*[\d.]\s*$/) {
s/[^.\d]//g;s/0/./g; $n = $n . $_;
}
};
return $n;
}
sub read_proc($$) {
my $s; my $pid; my $ret; my $file=""; my $wfile=""; my $e = "";
$stkc = -1; $stkw = -1;
if($_[0] eq 'G') {
print "--------- Generating (#" . $_[1] . ") ---------\n";
$pid = open2($file, $wfile, $gcmd,$_[1]);
} elsif($_[0] eq 'S') {
print "--------------- Solving... ---------------\n";
$pid = open2($file, $wfile, $scmd);
print $wfile $_[1];
} elsif($_[0] eq 'U') {
print "--------------- Solving... ---------------\n";
$pid = open2($file, $wfile, $scmd,'U');
print $wfile $_[1];
} else {
die("Internal error: bad input to read_proc()");
}
local @l = ( ); my $n = 0;
while($_=<$file>) {
push(@l, $_); print "> " . $_ if($vflg);
$e = $1 if(/^(!!!.*)$/);
($stkc = $1+0, $stkw = $2+0) if(/\(stk (\d+) (\d+)\)$/);
}
# local @l = <$file>;
close $file; close $wfile;
waitpid $pid, 0;
if($?) {
return $e if($e); return "ret=$?";
}; $s = rpe(); return $s;
}
sub read_file($) {
my $s;
open FILE,"<",$_[0]; local @l = <FILE>; $s = rpe();
close FILE; return $s;
}
sub squish($) {
my $n = 0; my $c; my $bc = 0; my $dc = 0; my $s = $_[0];
my $os = "#";
while($s ne "") {
$c = substr $s, 0, 1; $s = substr $s, 1;
if($c eq "." || $c eq "0") {
$dc++; if($dc==7||$s eq "") {
$n |= (($dc==1?0:$dc+8)<<$bc); $bc += 4; $dc = 0;
}
} else {
if($dc) {
$n |= (($dc==1?0:$dc+8)<<$bc); $bc += 4; $dc = 0;
}
$n |= (($c)<<$bc); $bc += 4;
}
while($bc >= 6) {
$os .= substr $squstr, $n & 63, 1;
$n = $n >> 6; $bc -= 6;
}
}
$os .= substr $squstr, $n, 1 if($bc);
return $os;
}
sub unsq($) {
my $n = 0; my $bc = 0; my $os=""; my $i; my $s = $_[0]; my $j;
if('#' ne substr($s,0,1)) {
return $s if(81==length($s)); die("Bad compressed sudoku");
}; $s = substr $s,1;
while((length $os)<81) {
if($bc < 4) {
die("Compressed sudoku ends prrematurely") if($s eq "");
$i = index $squstr, substr($s, 0, 1); $s = substr($s,1);
die("Bad compressed sudoku") if($i == -1);
$n = ($i<<$bc) | $n; $bc +=6;
}
$bc -= 4; $i = $n & 15; $n = $n >> 4;
if($i < 10) {
$os .= ($i == 0?".":$i);
} else {
for($j=8;$j<$i;$j++) {$os .= '.';}
}
} return $os;
}
sub chksq($$) {
my $i = squish($_[0]); my $j = unsq($_[1]);
die("Squash check failed") if($i ne $_[1]);
die("Unsquash check failed") if($j ne $_[0]);
}
sub chk_fi($$) {
my $i; my $j; my $k = $_[1]; my $n= $_[0];
if($k) {
print "================== Inbuilt $n ==================\n";
$k = unsq($k);
} else {
print "================== File $n ==================\n";
$k = read_file("$n.sudoku");
}
die("*** Problem isn't even valid!") if(chk($k)==1);
print $k, "\n" if($vflg);
$i = read_proc('S', $k);
(length $i) == (81*$soff) or die("*** Failed!!!");
$i = substr $i,81*($soff-1),81;
die("*** Solution isn't even valid!") if(chk($i));
die("*** Solution doesn't fit the problem!") if(scmp($i,$k));
if(-f "$n.sol") {
$j = read_file("$n.sol");
die("*** 'Correct' solution isn't valid!") if(chk($j));
die("*** Mix-up - solution is for another problem!") if(scmp($j,$k));
($i eq $j) or die("*** Wrong answer!!!");
}
print "*** Correct answer\n";
}
sub chk_fail($$$$) {
my $i = $_[2]; my $e; my $n = $_[0]; my $c=$_[1]; my $o = $_[3];
print "================ Bad problem '$n' ================\n";
$i = unsq($i) if($i =~ /^#/);
$i = read_file("$n") unless(81 == length $i);
print $i . "\n" if($vflg);
die("*** Invalid file!") if(81 != length $i);
if($o eq 'I') {
die("*** Internal error - chk() passed invalid sudoku!")
if(chk($i)!=1);
}
$o = 'S' if($o ne 'U');
$e = read_proc($o, $i);
if($c) {
print "Expected '" . $c . "' got '" . $e . "'\n";
} else { return 2 unless((length $c) == 81);
return 0;
print "Got '" . $e . "'\n";
}
die("*** Didn't spot a bad problem!") if($e !~ /^!!! /);
die("*** Took too long to spot bad problem!") if($_[3] eq 'I' && $stkw);
die("*** Failed test!") if($c ne "" && $c ne $e);
print "*** Detected bad sudoku successfully\n";
}
sub genrand($$) {
my $i; my $j; my $k; my $s = $_[0]; my $c = $_[1];
if($s) {
print "================== #$s ==================\n";
} else {
print "================== Random ==================\n";
$s = int(rand(999999999)) unless($s);
}
$i = read_proc('G', $s);
(length $i) == (81*3) or die("*** Failed!!!");
$j = substr $i,81,81;
$k = substr $i,81*2,81;
print $k . "\n" . $j . "\n" if($vflg);
die("*** Problem isn't even valid!") if(chk($k)!=2);
die("*** 'Correct' solution isn't!") if(chk($j));
die("*** Solution doesn't fit the problem!") if(scmp($j,$k));
print "*** Generated problem OK\n";
$c = unsq($c) if($c);
if($c && ($c ne $k)) {
if($rflg) {
print "\n Sudoku generated was valid, but not the expected one.\n",
" This probably isn't serious, and may not even be an error.\n",
" To ignore this, add the -R option to the command line.\n\n";
die("*** Not expected sudoku!")
} else {
print "*** Not expected sudoku, but -R specified; ignoring\n";
}
}
$i = read_proc('S', $k);
(length $i) == (81*2) or die("*** Failed!!!");
$i = substr $i,81,81;
print $i . "\n" . $j . "\n" if($vflg);
($i eq $j) or die("*** Wrong answer!!!");
print "*** Correct answer\n";
}
sub scmp($$) {
my ($i,$a,$b);
for($i=0;$i<81;$i++) {
$a = substr $_[0], $i, 1;
$b = substr $_[1], $i, 1;
return 1 unless($a eq $b || $a eq "." || $b eq ".");
}; return 0;
}
sub chk($) {
my @a; my $n; my $i; my @v; my $c = 0;
for($n=0;$n<81;$n++) { $v[$n] = gi($_[0], $n); $c++ if($v[$n]); }
if($zoom) {
return 2 unless($c == 81);
return 0;
}
for($n=0;$n<81;$n++) { $a[$n] = 0; }
for($n=0;$n<81;$n++) {
next unless $v[$n];
$i = int($n/9)*9 + $v[$n]-1;
if($a[$i]) {
print "row ". int($n/9) . " many " . ${$v[$i]} . " \n";
return 1;
}; $a[$i] = 1;
}
for($n=0;$n<81;$n++) { $a[$n] = 0; }
for($n=0;$n<81;$n++) {
next unless $v[$n];
$i = ($n % 9)*9 + $v[$n]-1;
if($a[$i]) {
print "col ". (($n % 9)+1) . " many " . ${$v[$i]} . " \n";
return 1;
}; $a[$i] = 1;
}
for($n=0;$n<81;$n++) { $a[$n] = 0; }
for($n=0;$n<81;$n++) {
next unless $v[$n];
$i = ( int(($n % 9)/3)+int($n/27)*3 )*9 + $v[$n]-1;
if($a[$i]) {
print "box ". (int(($n % 9)/3)+int($n/27)*3+1) . " many " . ${$v[$i]} . " \n";
return 1;
}; $a[$i] = 1;
}
return 2 unless($c == 81);
return 0;
}
sub gi($$) {
my $n = substr $_[0], $_[1], 1;
$n = 0 if($n eq "."); $n = $n + 0;
return $n;
}
srand;
if(!$zoom) {
print "================ Unsquash Test ==============\n";
chksq(".............9.........1.............4..1..1....................2.."
. "...1..........", "#vnvGvTaox.u0xv");
chksq("........2.....5.3..58..7...326....158...........362..8..7...4.....5"
. "1....6...841..", "#PIdBjWoe7IGHF,8Yii6tUXBbLShC");
print "*** Passed\n"
}
if($fint) {
chk_fi("blank","#.......z");
chk_fi("tough1","#PIdBjWoe7IGHF,8Yii6tUXBbLShC");
chk_fi("insane1","#KxlV7Jds4.WOa53QQBCEEgz.gF");
chk_fi("insane2","#yTuoJQgMACknQkyi6AGEQJasobJMfpJ");
chk_fi("insane3","#LxVHGkHPvBCEEU7N697cyvBMLBpC");
chk_fi("insane4","#rAZf9MeZQ9QyjVAt2hst0SgUIc5iM");
chk_fi("insane5","#t0BU2SlN9oHkAVu9QqFjHIw4ECSRM");
chk_fi("wikipedia","#boHplm6Iqdaqkiu0hnapkejejKqpWp0C");
}
if($ffile) { foreach(glob("*.sudoku")) {
chk_fi($1,"") if(/^(.+)\.sudoku$/);
} }
if($fbad) {
chk_fail("row","!!! row 5","#vnvGvTaox.u0xv",'I');
chk_fail("col","!!! col 5","#vnvGvTa8.Gt0xv",'I');
chk_fail("box","!!! box 5","#vnvGe4kG..q0xv",'I');
chk_fail("tele13-mang.bad","","",'S') if(-f "tele13-mang.bad");
chk_fail("unique",'',"#.XwoFq3OixRhPPmooeL1Vw2iUo",'U')
}
if($fgen) {
genrand(951464,"#axiBBIPgN1RPQCEc4rDECkbYqome7A");
genrand(975900,"#GCnOKdlh.7BkvWCQwh.WcqBEoakC");
genrand(168996,"#tdjO0ahA3LbsmOg55K3G1wIY3Ses");
genrand(250762,"#s8GCxADk.WnpFq2KawIk6cVTu4HA");
genrand(909990524,"#t0BU2SlN9oHkAVu9QqFjHIw4ECSRM");
genrand(105761662,"#LxVHGkHPvBCEEU7N697cyvBMLBpC");
genrand(100440625,"#yTuoJQgMACknQkyi6AGEQJasobJMfpJ");
genrand(957749705,"#Q0GnEIAu1OEyHLaU6kXQeCy8e9G");
genrand(914809978,"#NCDJw9bt5RjGijAt2WhbN,EkQcAC");
genrand(774849286,"#soDgbcqF.D3a1mTiCHlBBkIQa,7Z0C");
genrand(862977530,"#xvTUcBJBnwWtHc0i6oyGM5jeYnrQK");
genrand(103980293,"#oKadABTt4vpO0.nGixnGQpEcashWmo");
genrand(122255857,"#34lWbkaAkBzr2rhelmblAyCEnS68G");
genrand(596684993,"#cB2DhAJcMSxiANgo1sBYJfKCpV.vko");
}
for($n = 0; $n<$gcnt; $n++) {
genrand(0,"");
}
print "\n######### All tests passed! #########\n\n";
+11
View File
@@ -0,0 +1,11 @@
. . . | . . . | . . 2
. . . | . . 5 | . 3 .
. 5 8 | . . 7 | . . .
------+-------+------
3 2 6 | . . . | . 1 5
8 . . | . . . | . . .
. . . | 3 6 2 | . . 8
------+-------+------
. . 7 | . . . | 4 . .
. . . | 5 1 . | . . .
6 . . | . 8 4 | 1 . .
+15
View File
@@ -0,0 +1,15 @@
From Wikipedia article "Sudoku":
. . . | 1 . . | 7 4 .
. 5 . | . 9 . | . 3 2
. . 6 | 7 . . | 9 . .
------+-------+------
4 . . | 8 . . | . . .
. 2 . | . . . | . 1 .
. . . | . . 9 | . . 5
------+-------+------
. . 4 | . . 7 | 3 . .
7 3 . | . 2 . | . 6 .
. 6 5 | . . 4 | . . .
http://en.wikipedia.org/wiki/Sudoku