#!/usr/bin/awk -f
#
# GLOBAL VARIABLES:
# grid - Game grid
# row - Horizontal slice through the grid
# col - Vertical slice through the grid
# sector - solved numbers per sector
# setorMap - map of sector for each cell
# solutions - grid of all possible solutions per unsolved cell
# solutionsCnt - count of possible solutions for each unsolved number per sector
#
BEGIN {
for (i=1; i <= 9; i++ ) {
for (j=1; j <= 9; j++ ) {
grid[i,j]=0
sectorMap[i,j]=toSector(i,j)
}
}
"tput smso" | getline SMSO
"tput bold" | getline BOLD
"tput rmso" | getline RMSO
"tput clear" | getline CLEAR
"tput cup 0 0" | getline HOME
"tput cup 20 0" | getline LINE20
PROMPT = ">>"
printf "%s ", PROMPT
}
$1 == "help" {
print "help, load, loadFile, step, dumpsolutions, dumpSector, dumpSectorMap, dump"
}
$1 == "list" {
LIST="ls puzzle.*"
while ( LIST | getline listing >0 ) {
print listing
}
close(LIST)
}
####################################################################
#
# load puzzle from a file
#
####################################################################
$1 == "loadFile" {
fileName = $2
print "loading " fileName
clearSector()
delete grid
delete row
delete col
r=0;
while ( (getline < fileName) > 0 ) {
r++
for (c=1; c<=NF; c++)
{
if ( $c != ".")
load(r, c, $c)
}
}
close(fileName)
}
####################################################################
#
# load puzzle from command line
#
####################################################################
$1 == "load" {
fileName=""
for (i=2; i<=NF; i++)
{
split($i,fields,",")
load(fields[1], fields[2], fields[3])
}
}
####################################################################
#
# step through automated solution of the puzzle
#
####################################################################
$1 == "step" {
if (solveStep()==0)
print "no solution"
}
####################################################################
#
# automatically solve the entire puzzle
#
####################################################################
$1 == "solve" {
printf "%s", CLEAR
do {
if ( $2 != "" ) {
system("sleep " $2)
}
printf "%s", HOME
} while (solveStep() != 0 )
dump()
print "Solution Stopped"
}
####################################################################
#
# validate the currently solved puzzle against a solution
# in a file
#
####################################################################
$1 == "check" {
fileName=$2
print "checking solution against " fileName
r=0
while ( (getline < fileName) > 0 ) {
r++
for (c=1; c<=NF; c++)
{
# print "grid["r","c"]("grid[r,c]")=" $c ## DEBUG
if (grid[r,c] != $c) {
dump(r,c)
print "Error @ cell " r","c
close(fileName)
next
}
}
}
print "Congradulations, your solution is correct!"
close(fileName)
}
####################################################################
#
# save the current puzzle in a file
#
####################################################################
$1 == "save" {
for (r=1; r<=9; r++) {
for (c=1; c<=9; c++) {
v = grid[r,c]
if ( v <=0 )
v="."
printf "%s ", v > $2
}
print "" > $2
}
close($2)
}
$1 == "dumpSolution" { dumpSolutions() } # dump the list of solutions to output
$1 == "dumpSectorMap" { dumpSectorMap() } # dump the sector map to output
$1 == "dumpSector" { dumpSectors() } # dump all solved numbers per sector to output
$1 == "dump" { C=$3; dump($2, $3) } # dump the puzzle grid to output
$1 == "quit" { exit 0 } # exit the game
{ printf "%s ", PROMPT }
####################################################################
#
# load a value into a (r)ow and (c)olumn of the puzzle grid
#
####################################################################
function load( r, c, value) {
grid[r,c]=value
solutions[r,c]="C"
row[r,value]=1
col[c,value]=1
addToSector(sectorMap[r, c],value)
}
####################################################################
#
# attempt to find the first solvable cell in the grid.
# print the grid with the solved cell highlighted.
#
####################################################################
function solveStep() {
plotSolutions()
for ( r=1; r<=9; r++ ) {
for ( c=1; c<=9; c++ ) {
for ( i=1; i <= 9; i++ ) {
if(solutions[r,c] != "C" && solutions[r,c] ~ i && solutions[r,c] !~ /,/) {
load(r,c,i)
dump(r,c)
print " "
return 1
}
if ( solutions[r,c]!="C" && solutions[r,c] ~ i && solutionsCnt[sectorMap[r,c],i]==1)
{
load(r,c,i)
dump(r,c)
print " "
return 1
}
}
}
}
if ( !gridSolved() ) {
plotSolutions()
plotTwins()
for ( r=1; r<=9; r++ ) {
for ( c=1; c<=9; c++ ) {
for ( i=1; i <= 9; i++ ) {
if(solutions[r,c] != "C" && solutions[r,c] ~ i && solutions[r,c] !~ /,/) {
load(r,c,i)
dump(r,c)
print "Solved using twins..."
return 1
}
if ( solutions[r,c]!="C" && solutions[r,c] ~ i && solutionsCnt[sectorMap[r,c],i]==1)
{
load(r,c,i)
dump(r,c)
print "Solved using twins..."
return 1
}
}
}
}
}
return 0
}
####################################################################
#
# plot all possible solutions for all unsolved cells
#
####################################################################
function plotSolutions() {
delete solutions
delete solutionsCnt
############################################################
#
# Mark solved cells in the solution space
#
############################################################
for ( r=1; r<=9; r++ ) {
for (c=1; c<=9; c++) {
if ( grid[r,c] != 0 ) {
solutions[r,c]="C"
}
}
}
############################################################
#
# plot all possible solutions for the current
# puzzle grid
#
############################################################
for (i=1; i<=9; i++ ) {
for ( r=1; r<=9; r++ ) {
for ( c=1; c<=9; c++ ) {
if ( solutions[r,c] != "C" ) {
if ( row[r,i] != 1 && col[c,i] != 1 && sector[sectorMap[r,c]] !~ i) {
if ( solutions[r,c] == 0 )
solutions[r,c]=i
else
solutions[r,c]=solutions[r,c]","i
solutionsCnt[sectorMap[r,c],i]= solutionsCnt[sectorMap[r,c],i]+1
}
}
}
}
}
}
function plotTwins() {
############################################################
#
# look for "twins" in the solutions space
#
############################################################
for ( r=1; r<=9; r++) {
for ( c=1; c<=9; c++ ) {
if (split(solutions[r,c],a,",") == 2 ) {
if (matchTwinCol(r,c,a)) {
extractTwinValuesFromCol(c,a)
}
if (matchTwinRow(r,c,a)) {
extractTwinValuesFromRow(r,a)
}
}
}
}
}
function matchTwinCol(R,C,A){
twinCount=0
############################################################
#
# look for "twins" across column in the solutions space
#
############################################################
for ( ; C<=9; C++ ) {
if (split(solutions[R,C],b,",") == 2 ) {
if( isTwin(A,b) ) {
twinCount++
}
}
}
if ( twinCount == 1 )
return 1
else
return 0 # false
}
function matchTwinRow(R,C,A){
twinCount=0
############################################################
#
# look for "twins" across Row in the solutions space
#
############################################################
for ( ; R<=9; R++ ) {
if (split(solutions[R,C],b,",") == 2 ) {
if( isTwin(A,b) ) {
twinCount++
}
}
}
if ( twinCount == 1 )
return 1
else
return 0 # false
}
function extractTwinValuesFromCol(C, A) {
for ( R=1; R<=9; R++ ) {
if ( solutions[R,C] != "C" ) {
split(solutions[R,C],B,",")
if ( length(B) > 1 && !isTwin(A,B)) {
solutions[R,C]=""
for ( i=1; i<= length(B); i++ ) {
if ( B[i] != A[1] && B[i] != A[2] ) {
if ( solutions[R,C]=="" ) {
solutions[R,C]=B[i]
}else{
solutions[R,C]=solutions[R,C]","B[i]
}
}
}
}
}
}
}
function extractTwinValuesFromRow(R, A) {
for ( C=1; C<=9; C++ ) {
if ( solutions[R,C] != "C" ) {
split(solutions[R,C],B,",")
if ( length(B) > 1 && !isTwin(A,B)) {
solutions[R,C]=""
for ( i=1; i<= length(B); i++ ) {
if ( B[i] != A[1] && B[i] != A[2] ) {
if ( solutions[R,C]=="" ) {
solutions[R,C]=B[i]
}else{
solutions[R,C]=solutions[R,C]","B[i]
}
}
}
}
}
}
}
function isTwin(A, B) {
if ( length(A) == 2 && length(B) == 2 && A[1] == B[1] && A[2] == B[2] ) {
return 1
}
return 0
}
function gridSolved() {
for ( r=1 ; r<=9; r++ ) {
for ( c=1; c<=9; c++ ) {
if ( solutions[r,c]!="C" )
return 0
}
}
return 1
}
####################################################################
#
# dump the list of all currently plotted solutions for
# unsolved cells
#
####################################################################
function dumpSolutions() {
for ( r=1; r<=9; r++ ) {
for ( c=1; c<=9; c++ ) {
printf "solutions[%d,%d]=%s\n", r, c, solutions[r,c]
}
}
}
####################################################################
#
# dump all solved numbers per sector
#
####################################################################
function dumpSectors() {
print "SECTORS {"
for ( i=1; i <=9; i++ ) {
printf " Sector[%d]: %s\n", i, sector[i]
}
print "}"
}
####################################################################
#
# map a cell to a sector
#
####################################################################
function toSector(r, c) {
if ( r <= 3 && c <=3 ) {
return 1
} else if ( r <= 3 && c <=6 ) {
return 2
} else if ( r <= 3 && c <=9 ) {
return 3
} else if ( r <= 6 && c <=3 ) {
return 4
} else if ( r <= 6 && c <=6 ) {
return 5
} else if ( r <= 6 && c <=9 ) {
return 6
} else if ( r <= 9 && c <=3 ) {
return 7
} else if ( r <= 9 && c <=6 ) {
return 8
} else if ( r <= 9 && c <=9 ) {
return 9
}
}
####################################################################
#
# dump the puzzle grid to output, highlight the cell
# designated by the (r)ow and (c)olumn arguments
#
####################################################################
function dump(r, c) {
print fileName
printf "===================\n"
for (i=1; i<=9; i++ ) {
printf "|"
for ( j=1; j<=9; j++) {
if( i==r && j==c) {
SM=SMSO
RM=RMSO
}else{
SM=""
RM=""
}
if (grid[i,j]!=0) {
printf "%s%d%s",SM,grid[i,j],RM
}else{
printf " "
}
if ( j%3 == 0 ) {
printf "|"
}else{
printf ":"
}
}
if ( i%3 == 0 ) {
printf "\n|=====|=====|=====|\n"
}else{
printf "\n|-----|-----|-----|\n"
}
}
}
####################################################################
#
# dump the pregenerated sector map to output
#
####################################################################
function dumpSectorMap() {
printf "SECTOR MAP {\n ===================\n "
for (i=1; i<=9; i++ ) {
printf "|"
for ( j=1; j<=9; j++) {
printf "%d", sectorMap[i,j]
if ( j%3 == 0 ) {
printf "|"
}else{
printf ":"
}
}
if ( i%3 == 0 ) {
printf "\n |=====|=====|=====|\n "
}else{
printf "\n |-----|-----|-----|\n "
}
}
printf "\n}\n"
}
####################################################################
#
# clear sector solutions
#
####################################################################
function clearSector() {
delete sector
delete sectorCnt
}
####################################################################
#
# add a solution (v)alue to a (s)ector
#
####################################################################
function addToSector(s,v) {
if ( sector[s]==0 ) {
sector[s]=v
} else{
sector[s]=sector[s]","v
}
sectorCnt[s,v]=sectorCnt[s,v]+1
}
####################################################################
#
# Program Exit
#
####################################################################
END { print ">> GOODBYE!" }
Comments
0 B
|👍
/👎
0 B
|👍
/👎