HomeHome More SamplesMore Samples
///////////////////////////////////////////////////////////////////////////////
//
// SudokuGUI.f1
//
// SUDOKU puzzle solver with a Graphical User Interface.
//
// The puzzle was invented in Basel, Switzerland, by 18th century matematician
// Leonhard Euler. Euler called his puzzle "Magic Squares", it became 
// "Sudoku" ("single number" in Japanese) in the 1980s. The puzzle comes in 
// several variants, the most common being a square grid nine by nine, consisting
// of nine sub-grids 3x3. This variant is often referred to as Sudoku 3x3. 
// There are numerous Sudoku web sites dealing with history, solving strategies
// and posting new puzzles. Puzzles are often rated by their difficulty.
//
// The rules: Fill the grid with numbers so that each column, each row 
// and each each tree by three grid of nine squares contains the numbers 
// one to nine. No column, row or grid can have two of the same numbers.
//
// Solving:
// The code in the predicate SudokuSolve3x3 will solve any Sudoku problem. It is 
// an ideal problem for declarative programming: all the code does is transcribe 
// the rules above in the syntax of the F1 language. 
// Though the actual solving is done by the predicate SudokuSolve3x3, all input/output
// routines are handled by an external module SudokuExt.dll. All in all we need
// five external routines to handle this programs' needs from inputing of 
// the user values to displaying the found solutions. 
//
// Note the usage of the routines RtlGetCutPoint / RtlSetCutPoint. These routines
// are needed in case the user does not want all solutions. By using these routines
// we are able to prematurely terminate the predicate SudokuSolve3x3, explicitly
// cutting off the predicate backtracking branches.
//
// To execute the program, issue the query 
//
//      SudokuGUI
//
// Final note: The code will find all solutions, therefore can be easily used 
// to generate new Sudoku puzzles: simply start with any partially filled grid,
// generate all solution, and keep filling the grid with more numbers until
// the puzzle has a single solution.
//
///////////////////////////////////////////////////////////////////////////////

local SUDOKUTYPE = [0..80]->I[1..9]
local ATYPE = [0..8]->>I[1..9]

subr SudokuGUI() iff
    SudokuCreateWindow('F1 3x3 Sudoku Solver',h) & SudokuGUISolve(h)

local subr SudokuGUISolve(h:<I) iff
    SudokuGetUserValues(h,arr) & 
    all x in l 
        RtlGetCutPoint(cp) &
        SudokuSolve3x3(x,arr) & ShowResult(x,h) &
        if ~SudokuQueryNext() then
            RtlSetCutPoint(cp)
        end
    end & SudokuDone() & 
    SudokuGUISolve(h)

local pred SudokuSolve3x3(s::SUDOKUTYPE , a:<[0..80]->[0..9]) iff
    Assign(s,a,0) & 

    DiffCols(s,0) & DiffCols(s,1) & DiffCols(s,2) & 
    DiffCols(s,3) & DiffCols(s,4) & DiffCols(s,5) &
    DiffCols(s,6) & DiffCols(s,7) & DiffCols(s,8) &

    DiffRows(s,0) & DiffRows(s,1) & DiffRows(s,2) &
    DiffRows(s,3) & DiffRows(s,4) & DiffRows(s,5) &
    DiffRows(s,6) & DiffRows(s,7) & DiffRows(s,8) & 

    DiffSubGrid(s,0,0) & DiffSubGrid(s,0,3)  & DiffSubGrid(s,0,6) & 
    DiffSubGrid(s,3,0) & DiffSubGrid(s,3,3)  & DiffSubGrid(s,3,6) & 
    DiffSubGrid(s,6,0) & DiffSubGrid(s,6,3)  & DiffSubGrid(s,6,6)  

local pred DiffSubGrid(s::SUDOKUTYPE, row:<I, col:<I) iff
    sg::ATYPE & sg = [
        s(row*9+col),s(row*9+col+1),s(row*9+col+2),
        s((row+1)*9+col),s((row+1)*9+col+1),s((row+1)*9+col+2),
        s((row+2)*9+col),s((row+2)*9+col+1),s((row+2)*9+col+2)]

local pred DiffCols(s::SUDOKUTYPE, col:<I) iff
    sg::ATYPE & sg = [
        s(col), s(col+9), s(col+2*9), s(col+3*9),
        s(col+4*9),s(col+5*9),s(col+6*9), s(col+7*9),
        s(col+8*9)]

local pred DiffRows(s::SUDOKUTYPE, row:<I) iff
    sg::ATYPE & sg = [
        s(row*9), s(row*9+1),s(row*9+2), s(row*9+3),
        s(row*9+4),s(row*9+5),s(row*9+6), s(row*9+7),
        s(row*9+8)]

local proc ShowResult(s:<SUDOKUTYPE, h:<I) iff
      SudokuShowValues(h,s:([0..80]->I)) 

local pred Assign(s::SUDOKUTYPE, a:<[0..80]->[0..9],col:<I) iff
    if col < Len(s) then
        if a(col) <> 0 then 
            s(col) = a(col) 
        end & Assign(s,a,col+1)
    end

///////////////////////////////////////////////////////////////////////////////
//
// External routines used by this program.
//
///////////////////////////////////////////////////////////////////////////////

// Initialize the external code
local subr SudokuCreateWindow(title :<S,w:>I) iff 
    external 'SudokuExt':'SudokuCreateWindow'

// Query the external code for some initial Sudoku values
local subr SudokuGetUserValues(w:<I,a:>[0..80]->I[0..9]) iff 
    external 'SudokuExt':'SudokuGetUserValues'

// Present the external code with one Sudoku solution
local proc SudokuShowValues(w:<I,a:<[0..80]->I) iff 
    external 'SudokuExt':'SudokuShowValues'

// Notify the external code we are finished (there will be no more solutions)
local proc SudokuDone() iff 
    external 'SudokuExt':'SudokuDone'

// Query the external code if another solution desired
local proc SudokuQueryNext() iff 
    external 'SudokuExt':'SudokuQueryNext'








This page was created by F1toHTML