with javascript_semantics
sequence board = split("""
.......39
.....1..5
..3.5.8..
..8.9...6
.7...2...
1..4.....
..9.8..5.
.2....6..
4..7.....""",'\n')

function valid_move(integer y, x, ch)
    for i=1 to 9 do
        if ch=board[i][x] then return false end if
        if ch=board[y][i] then return false end if
    end for
    y -= mod(y-1,3)
    x -= mod(x-1,3)
    for ys=y to y+2 do
        for xs=x to x+2  do
            if ch=board[ys][xs] then return false end if
        end for
    end for
    return true
end function

sequence solution = {}

procedure brute_solve()
    for y=1 to 9 do
        for x=1 to 9 do
            if board[y][x]<='0' then
                for ch='1' to '9' do
                    if valid_move(y,x,ch) then
                        board[y][x] = ch
                        brute_solve()
                        board[y][x] = ' '
                        if length(solution) then return end if
                    end if
                end for
                return
            end if
        end for
    end for
    solution = deep_copy(board) -- (already solved case)
end procedure

atom t0 = time()
brute_solve()
printf(1,"%s\n(solved in %3.2fs)\n",{join(solution,"\n"),time()-t0})


/*REXX program to compute and display  (unsigned)  Stirling numbers   of the first kind.*/
parse arg lim .                                  /*obtain optional argument from the CL.*/
if lim=='' | lim==","  then lim= 12              /*Not specified?  Then use the default.*/
olim= lim                                        /*save     the original value of  LIM. */
lim= abs(lim)                                    /*only use the absolute value of  LIM. */
numeric digits max(9, 2*lim)                     /*(over) specify maximum number in grid*/
@.=;                                 @.0.0= 1    /*define the   (0, 0)th  value  in grid*/
        do n=0  for lim+1                        /* [↓]  initialize some  values  "   " */
        if n>0  then @.n.0 = 0                   /*assign value if  N > zero.           */
          do k=n+1  to lim
          @.n.k = 0                              /*zero some values in grid  if  K > N. */
          end   /*k*/
        end     /*n*/
max#.= 0                                         /* [↓]  calculate values for the grid. */
        do   n=1  for lim;           nm= n - 1
          do k=1  for lim;           km= k - 1
          @.n.k = @.nm.km  +  nm * @.nm.k        /*calculate an unsigned number in grid.*/
          max#.k= max(max#.k, @.n.k)             /*find the      maximum value   "   "  */
          max#.b= max(max#.b, @.n.k)             /*find the maximum value for all rows. */
          end   /*k*/
        end     /*n*/

        do k=1  for lim                          /*find max column width for each column*/
        max#.a= max#.a + length(max#.k)
        end   /*k*/
                                                 /* [↓]  only show the maximum value ?  */
w= length(max#.b)                                /*calculate max width of all numbers.  */
if olim<0  then do;  say 'The maximum value  (which has '      w      " decimal digits):"
                     say max#.b                  /*display maximum number in the grid.  */
                     exit                        /*stick a fork in it,  we're all done. */
                end
wi= max(3, length(lim+1) )                       /*the maximum width of the grid's index*/
say 'row'  center('columns', max(9, max#.a + lim), '═')    /*display header of the grid.*/

        do r=0  for lim+1;   $=                  /* [↓]  display the grid to the term.  */
          do c=0  for lim+1  until c>=r          /*build a row of grid, 1 col at a time.*/
          $= $  right(@.r.c, length(max#.c) )    /*append a column to a row of the grid.*/
          end   /*c*/
        say right(r,wi)  strip(substr($,2), 'T') /*display a single row of the grid.    */
        end     /*r*/                            /*stick a fork in it,  we're all done. */


$cache = {}
def sterling1(n, k)
    if n == 0 and k == 0 then
        return 1
    end
    if n > 0 and k == 0 then
        return 0
    end
    if k > n then
        return 0
    end
    key = [n, k]
    if $cache[key] then
        return $cache[key]
    end
    value = sterling1(n - 1, k - 1) + (n - 1) * sterling1(n - 1, k)
    $cache[key] = value
    return value
end

MAX = 12
def main
    print "Unsigned Stirling numbers of the first kind:\n"
    print "n/k"
    for n in 0 .. MAX
        print "%10d" % [n]
    end
    print "\n"

    for n in 0 .. MAX
        print "%-3d" % [n]
        for k in 0 .. n
            print "%10d" % [sterling1(n, k)]
        end
        print "\n"
    end

    print "The maximum value of S1(100, k) =\n"
    previous = 0
    for k in 1 .. 100
        current = sterling1(100, k)
        if previous < current then
            previous = current
        else
            print previous, "\n"
            print "(%d digits, k = %d)\n" % [previous.to_s.length, k - 1]
            break
        end
    end
end

main()


	class SudokuSolver {
		protected $grid = [];
		protected $emptySymbol;
		public static function parseString($str, $emptySymbol = '0')
		{
			$grid = str_split($str);
			foreach($grid as &$v)
			{
				if($v == $emptySymbol)
				{
					$v = 0;
				}
				else
				{
					$v = (int)$v;
				}
			}
			return $grid;
		}

		public function __construct($str, $emptySymbol = '0') {
			if(strlen($str) !== 81)
			{
				throw new \Exception('Error sudoku');
			}
			$this->grid = static::parseString($str, $emptySymbol);
			$this->emptySymbol = $emptySymbol;
		}

		public function solve()
		{
			try
			{
				$this->placeNumber(0);
				return false;
			}
			catch(\Exception $e)
			{
				return true;
			}
		}

		protected function placeNumber($pos)
		{
			if($pos == 81)
			{
				throw new \Exception('Finish');
			}
			if($this->grid[$pos] > 0)
			{
				$this->placeNumber($pos+1);
				return;
			}
			for($n = 1; $n <= 9; $n++)
			{
				if($this->checkValidity($n, $pos%9, floor($pos/9)))
				{
					$this->grid[$pos] = $n;
					$this->placeNumber($pos+1);
					$this->grid[$pos] = 0;
				}
			}
		}

		protected function checkValidity($val, $x, $y)
		{
			for($i = 0; $i < 9; $i++)
			{
				if(($this->grid[$y*9+$i] == $val) || ($this->grid[$i*9+$x] == $val))
				{
					return false;
				}
			}
			$startX = (int) ((int)($x/3)*3);
			$startY = (int) ((int)($y/3)*3);

			for($i = $startY; $i<$startY+3;$i++)
			{
				for($j = $startX; $j<$startX+3;$j++)
				{
					if($this->grid[$i*9+$j] == $val)
					{
						return false;
					}
				}
			}
			return true;
		}

		public function display() {
			$str = '';
			for($i = 0; $i<9; $i++)
			{
				for($j = 0; $j<9;$j++)
				{
					$str .= $this->grid[$i*9+$j];
					$str .= " ";
					if($j == 2 || $j == 5)
					{
						$str .= "| ";
					}
				}
				$str .= PHP_EOL;
				if($i == 2 || $i == 5)
				{
					$str .=  "------+-------+------".PHP_EOL;
				}
			}
			echo $str;
		}

		public function __toString() {
			foreach ($this->grid as &$item)
			{
				if($item == 0)
				{
					$item = $this->emptySymbol;
				}
			}
			return implode('', $this->grid);
		}
	}
	$solver = new SudokuSolver('009170000020600001800200000200006053000051009005040080040000700006000320700003900');
	$solver->solve();
	$solver->display();


func S1(n, k) {     # unsigned Stirling numbers of the first kind
    stirling(n, k).abs
}

const r = (0..12)

var triangle = r.map {|n| 0..n -> map {|k| S1(n, k) } }
var widths   = r.map {|n| r.map {|k| (triangle[k][n] \\ 0).len }.max }

say ('n\k ', r.map {|n| "%*s" % (widths[n], n) }.join(' '))

r.each {|n|
    var str = ('%-3s ' % n)
    str += triangle[n].map_kv {|k,v| "%*s" % (widths[k], v) }.join(' ')
    say str
}

with (100) {|n|
    say "\nMaximum value from the S1(#{n}, *) row:"
    say { S1(n, _) }.map(^n).max
}


proc US1 {n k} {
    if {$k == 0} {
        return [expr {$n == 0}]
    }
    if {$n < $k} {
        return 0
    }
    if {$n == $k} {
        return 1
    }

    set nk [list $n $k]
    if {[info exists ::US1cache($nk)]} {
        return      $::US1cache($nk)
    }
    set n1 [expr {$n - 1}]
    set k1 [expr {$k - 1}]
    set r  [expr {($n1 * [US1 $n1 $k]) + [US1 $n1 $k1]}]

    set ::US1cache($nk) $r
}

proc main {} {
    puts "Unsigned Stirling numbers of the first kind:"
    set max 12                  ;# last table line to print
    set L   9                   ;# space to use for 1 number
    puts -nonewline "n\\k"
    for {set n 0} {$n <= $max} {incr n} {
        puts -nonewline " [format %${L}d $n]"
    }
    puts ""
    for {set n 0} {$n <= $max} {incr n} {
        puts -nonewline [format %-3d $n]
        for {set k 0} {$k <= $n} {incr k} {
            puts -nonewline " [format %${L}s [US1 $n $k]]"
        }
        puts ""
    }
    puts "The maximum value of US1(100, k) = "
    set previous 0
    for {set k 1} {$k <= 100} {incr k} {
        set current [US1 100 $k]
        if {$current > $previous} {
            set previous $current
        } else {
            puts $previous
            puts "([string length $previous] digits, k = [expr {$k-1}])"
            break
        }
    }
}
main


import "/big" for BigInt
import "/fmt" for Fmt

var computed = {}

var stirling1 // recursive
stirling1 = Fn.new { |n, k|
    var key = "%(n),%(k)"
    if (computed.containsKey(key)) return computed[key]
    if (n == 0 && k == 0) return BigInt.one
    if (n > 0 && k == 0) return BigInt.zero
    if (k > n) return BigInt.zero
    var result = stirling1.call(n-1, k-1) + stirling1.call(n-1, k)*(n-1)
    computed[key] = result
    return result
}

System.print("Unsigned Stirling numbers of the first kind:")
var max = 12
System.write("n/k")
for (n in 0..max) Fmt.write("$10d", n)
System.print()
for (n in 0..max) {
    Fmt.write("$-3d", n)
    for (k in 0..n) Fmt.write("$10i", stirling1.call(n, k))
    System.print()
}
System.print("The maximum value of S1(100, k) =")
var previous = BigInt.zero
for (k in 1..100) {
    var current = stirling1.call(100, k)
    if (current > previous) {
        previous = current
    } else {
        Fmt.print("$i\n($d digits, k = $d)", previous, previous.toString.count, k - 1)
        break
    }
}


fcn stirling1(n,k){
   var seen=Dictionary();	// cache for recursion
   if(n==k==0)      return(1);
   if(n==0 or k==0) return(0);

   z1,z2 := "%d,%d".fmt(n-1,k-1), "%d,%d".fmt(n-1,k);
   if(Void==(s1 := seen.find(z1))){ s1 = seen[z1] = stirling1(n - 1, k - 1) }
   if(Void==(s2 := seen.find(z2))){ s2 = seen[z2] = stirling1(n - 1, k)     }
   (n - 1)*s2 + s1;   // n is first to cast to BigInt (if using BigInts)
}


(load "lib/simul.l")

### Fields/Board ###
# val lst

(setq
   *Board (grid 9 9)
   *Fields (apply append *Board) )

# Init values to zero (empty)
(for L *Board
   (for This L
      (=: val 0) ) )

# Build lookup lists
(for (X . L) *Board
   (for (Y . This) L
      (=: lst
         (make
            (let A (* 3 (/ (dec X) 3))
               (do 3
                  (inc 'A)
                  (let B (* 3 (/ (dec Y) 3))
                     (do 3
                        (inc 'B)
                        (unless (and (= A X) (= B Y))
                           (link
                              (prop (get *Board A B) 'val) ) ) ) ) ) )
            (for Dir '(`west `east `south `north)
               (for (This (Dir This)  This  (Dir This))
                  (unless (memq (:: val) (made))
                     (link (:: val)) ) ) ) ) ) ) )

# Cut connections (for display only)
(for (X . L) *Board
   (for (Y . This) L
      (when (member X (3 6))
         (con (car (val This))) )
      (when (member Y (4 7))
         (set (cdr (val This))) ) ) )

# Display board
(de display ()
   (disp *Board 0
      '((This)
         (if (=0 (: val))
            "   "
            (pack " " (: val) " ") ) ) ) )

# Initialize board
(de main (Lst)
   (for (Y . L) Lst
      (for (X . N) L
         (put *Board X (- 10 Y) 'val N) ) )
   (display) )

# Find solution
(de go ()
   (unless
      (recur (*Fields)
         (with (car *Fields)
            (if (=0 (: val))
               (loop
                  (NIL
                     (or
                        (assoc (inc (:: val)) (: lst))
                        (recurse (cdr *Fields)) ) )
                  (T (= 9 (: val)) (=: val 0)) )
               (recurse (cdr *Fields)) ) ) )
      (display) ) )

(main
   (quote
      (5 3 0 0 7 0 0 0 0)
      (6 0 0 1 9 5 0 0 0)
      (0 9 8 0 0 0 0 6 0)
      (8 0 0 0 6 0 0 0 3)
      (4 0 0 8 0 3 0 0 1)
      (7 0 0 0 2 0 0 0 6)
      (0 6 0 0 0 0 2 8 0)
      (0 0 0 4 1 9 0 0 5)
      (0 0 0 0 8 0 0 7 9) ) )


V t = [[String(‘79’), ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’],
       [String(‘’),   ‘H’, ‘O’, ‘L’, ‘’,  ‘M’, ‘E’, ‘S’, ‘’,  ‘R’, ‘T’],
       [String(‘3’),  ‘A’, ‘B’, ‘C’, ‘D’, ‘F’, ‘G’, ‘I’, ‘J’, ‘K’, ‘N’],
       [String(‘7’),  ‘P’, ‘Q’, ‘U’, ‘V’, ‘W’, ‘X’, ‘Y’, ‘Z’, ‘.’, ‘/’]]

F straddle(s)
   R multiloop_filtered(Array(s.uppercase()), :t, (c, l) -> c C l, (c, l) -> l[0]‘’:t[0][l.index(c)]).join(‘’)

F unstraddle(s)
   [String] r
   V si = 0
   F next()
      R @s[@si++]
   L
      I si == s.len
         L.break
      V c = s[si++]
      I c C (:t[2][0], :t[3][0])
         V i = [:t[2][0], :t[3][0]].index(c)
         V n = :t[2 + i][:t[0].index(next())]
         r [+]= I n == ‘/’ {next()} E n
      E
         r [+]= :t[1][:t[0].index(c)]
   R r

V O = ‘One night-it was on the twentieth of March, 1888-I was returning’
print(‘Encoded: ’straddle(O))
print(‘Decoded: ’unstraddle(straddle(O)).join(‘’))


sudoku: procedure options (main); /* 27 July 2014 */

  declare grid (9,9) fixed (1) static initial (
      0, 0, 3, 0, 2, 0, 6, 0, 0,
      9, 0, 0, 3, 0, 5, 0, 0, 1,
      0, 0, 1, 8, 0, 6, 4, 0, 0,
      0, 0, 8, 1, 0, 2, 9, 0, 0,
      7, 0, 0, 0, 0, 0, 0, 0, 8,
      0, 0, 6, 7, 0, 8, 2, 0, 0,
      0, 0, 2, 6, 0, 9, 5, 0, 0,
      8, 0, 0, 2, 0, 3, 0, 0, 9,
      0, 0, 5, 0, 1, 0, 3, 0, 0 );

  declare grid_solved (9,9) fixed (1);

  call print_sudoku (grid);
  call solve (1, 1);
  put skip (2);
  call print_sudoku (grid_solved);

solve: procedure (i, j) recursive options (reorder);
    declare (i, j) fixed binary;
    declare (n, n_tmp) fixed binary;

    if i > 9 then
      grid_solved = grid;
    else
      do n = 1 to 9;
        if is_safe (i, j, n) then
          do;
             n_tmp = grid (i, j);
             grid (i, j) = n;
             if j = 9 then
               call solve (i + 1, 1);
             else
               call solve (i, j + 1);
             grid (i, j) = n_tmp;
          end;
      end;

  end solve;

is_safe: procedure (i, j, n) returns (bit(1) aligned) options (reorder);
    declare (i, j, n) fixed binary;
    declare (true value ('1'b), false value ('0'b) ) bit (1);
    declare (i_min, j_min, ii, jj) fixed binary;
    declare kk bit(1) aligned;

    if grid (i, j)  = n      then return (true);
    if grid (i, j) ^= 0      then return (false);
    if any (grid (i, *) = n) then return (false);
    if any (grid (*, j) = n) then return (false);

    /* i_min and j_min are the co-ordinates of the top left-hand corner */
    /* of 3 x 3 grid in which element (i,j) exists.                     */
    i_min = 1 + 3 * trunc((i - 1) / 3);
    j_min = 1 + 3 * trunc((j - 1) / 3);

    begin;
       declare sub_grid(3,3) fixed (1) defined grid(1sub+i_min-1,2sub+j_min-1);

       kk = true;
       if any(sub_grid = n) then kk = false;
    end;
    return (kk);
  end is_safe;

print_sudoku: procedure (grid);
    declare grid (*,*) fixed (1);
    declare ( i, j, ii) fixed binary;
    declare bar character (19) initial ( '+-----+-----+-----+' );
    declare frame (9) character (1) initial (' ', ' ', '|', ' ', ' ', '|', ' ', ' ', '|' );

    put skip list (bar);
    do i = 1 to 7 by 3;
       do ii = i to i + 2;
          put skip edit ( '|', (grid (ii, j), frame(j) do j = 1 to 9) ) (a, f(1));
       end;
       put skip list (bar);
    end;
  end print_sudoku;

end sudoku;


#!/usr/local/bin/a68g --script #

PRIO MIN=5, MAX=5;
OP MIN = (INT a, b)INT: (a<b|a|b),
   MAX = (INT a, b)INT: (a>b|a|b);

MODE STRADDLINGCHECKERBOARD=STRUCT(
  [0:9]CHAR first, second, third,
  [ABS ".": ABS "Z"]STRING table,
  INT row u, row v,
  CHAR esc, skip
);

STRUCT(
  PROC (REF STRADDLINGCHECKERBOARD #self#, STRING #alphabet#, INT #u#, INT #v#)VOID init,
  PROC (REF STRADDLINGCHECKERBOARD #self#, STRING #plain#)STRING encode,
  PROC (REF STRADDLINGCHECKERBOARD #self#, STRING #plain#)STRING decode
) sc class = (
# PROC init = # (REF STRADDLINGCHECKERBOARD self, STRING in alphabet, INT u, v)VOID:
  (
    STRING alphabet = in alphabet[@0];

    esc OF self := alphabet[UPB alphabet]; # use the last CHAR as the escape #
    skip OF self := alphabet[UPB alphabet-1];

    row u OF self := u MIN v;
    row v OF self := u MAX v;

    OP DIGIT = (INT i)CHAR: REPR(ABS "0" + i );

    INT j := LWB alphabet;

  # (first OF self)[u] := (first OF self)[v] := skip; #

    FOR i FROM LWB first OF self TO UPB first OF self  DO
      IF i NE u AND i NE v THEN
        (first OF self)[i] := alphabet[j];
        (table OF self)[ABS alphabet[j]] := DIGIT i;
        j+:=1
      FI;

      (second OF self)[i] := alphabet[i+8];
      (table OF self)[ABS alphabet[i+8]] := DIGIT (row u OF self) + DIGIT i;

      (third OF self)[i] := alphabet[i+18];
      (table OF self)[ABS alphabet[i+18]] := DIGIT (row v OF self) + DIGIT i
    OD
  ),

# PROC encode = # (REF STRADDLINGCHECKERBOARD self, STRING plain)STRING:
  (
    STRING esc = (table OF self)[ABS (esc OF self)];
    INT l2u = ABS "A" - ABS "a";

    STRING out := "";
    FOR i FROM LWB plain TO UPB plain DO
      CHAR c := plain[i];
      IF "a" <= c AND c <= "z" THEN
        c := REPR ( ABS c + l2u) FI;

      IF "A" <= c AND c <= "Z" THEN
        out +:= (table OF self)[ABS c]
      ELIF "0" <= c AND c <= "9" THEN
        out +:= esc + c
      FI
    OD;
    out # EXIT #
  ),

# PROC decode = # (REF STRADDLINGCHECKERBOARD self, STRING cipher)STRING:
  (
    CHAR null = REPR 0;
    STRING out;
    INT state := 0;
    FOR i FROM LWB cipher TO UPB cipher DO
      INT n := ABS cipher[i] - ABS "0";

      CHAR next :=
        CASE state IN
          #1:# (second OF self)[n],
          #2:# (third OF self)[n],
          #3:# cipher[i]
        OUT
          IF n = row u OF self THEN
            state := 1; null
          ELIF n = row v OF self THEN
            state := 2; null
          ELSE
            (first OF self)[n]
          FI
        ESAC;

      IF next = "/" THEN
        state := 3
      ELIF next NE null THEN
        state := 0;
        out +:= next
      FI
    OD;
    out # EXIT #
  )
);

main:
(
  STRADDLINGCHECKERBOARD sc; (init OF sc class)(sc, "HOLMESRTABCDFGIJKNPQUVWXYZ./", 3, 7);

  STRING original := "One night-it was on the twentieth of March, 1888-I was returning"[@0];
  STRING en := (encode OF sc class)(sc, original);
  STRING de := (decode OF sc class)(sc, en);

  printf(($ggl$,
          "Original: ", original,
          "Encoded:  ", en,
          "Decoded:  ", de
  ))

)


board := "
(
ET AON RIS
BCDFGHJKLM
PQ/UVWXYZ.
)"
Text = One night-it was on the twentieth of March, 1888-I was returning
StringUpper, Text, Text
Text := RegExReplace(text, "[^A-Z0-9]")
Num2 := InStr(board, A_Space)               -1
Num3 := InStr(board, A_Space, true, Num1+1) -1
Loop Parse, Text
{
	char := A_LoopField
	Loop Parse, board, `n
	{
		If (Pos := InStr(A_LoopField, char))
			out .= Num%A_Index% . Pos-1
		else if (Pos := InStr(A_LoopField, "/")) && InStr("0123456789", char)
			out .= Num%A_Index% . Pos-1 . char
	}
}
MsgBox % out

i := 0
While (LoopField := SubStr(out, ++i, 1)) <> ""
{
	If (LoopField = num2) or (LoopField = num3)
		col := SubStr(out, ++i, 1)
	else	col := 0
	Loop Parse, board, `n
	{
		If !col && A_Index = 1
			dec .= SubStr(A_LoopField, LoopField+1, 1)
		Else If (Num%A_Index% = LoopField) && col
			dec .= SubStr(A_LoopField, col+1, 1)
		If SubStr(dec, 0) = "/"
			dec := SubStr(dec, 1, StrLen(dec)-1) . SubStr(out, ++i, 1)
	}
}
MsgBox % dec


DataSection
  puzzle:
  Data.s "394002670"
  Data.s "000300400"
  Data.s "500690020"
  Data.s "045000900"
  Data.s "600000007"
  Data.s "007000580"
  Data.s "010067008"
  Data.s "009008000"
  Data.s "026400735"
EndDataSection

#IsPossible = 0
#IsNotPossible = 1
#Unknown = 0
Global Dim sudoku(8, 8)
;-declarations
Declare readSudoku()
Declare displaySudoku()
Declare.s buildpossible(x, y, Array possible.b(1))
Declare solvePuzzle(x = 0, y = 0)

;-procedures
Procedure readSudoku()
  Protected a$, row, column

  Restore puzzle
  For row = 0 To 8
    Read.s a$
    For column = 0 To 8
      sudoku(column, row) = Val(Mid(a$, column + 1, 1))
    Next
  Next
EndProcedure

Procedure displaySudoku()
  Protected row, column
  Static border.s = "+-----+-----+-----+"
  For row = 0 To 8
    If row % 3 = 0: PrintN(border): EndIf
    For column = 0 To 8
      If column % 3 = 0: Print("|"): Else: Print(" "): EndIf
      If sudoku(column, row): Print(Str(sudoku(column, row))): Else: Print("."): EndIf
    Next
    PrintN("|")
  Next
  PrintN(border)
EndProcedure

Procedure.s buildpossible(x, y, Array possible.b(1))
  Protected index, column, row, boxColumn = (x / 3) * 3, boxRow = (y / 3) * 3
  Dim possible.b(9)

  For index = 0 To 8
    possible(sudoku(index, y)) = #IsNotPossible ;record possibles in column
    possible(sudoku(x, index)) = #IsNotPossible ;record possibles in row
  Next

  ;record possibles in box
  For row = boxRow To boxRow + 2
    For column = boxColumn To boxColumn + 2
      possible(sudoku(column, row)) = #IsNotPossible
    Next
  Next
EndProcedure

Procedure solvePuzzle(x = 0, y = 0)
  Protected row, column, spot, digit
  Dim possible.b(9)

  For row = y To 8
    For column = x To 8
      If sudoku(column, row) = #Unknown
        buildpossible(column, row, possible())

        For digit =  1 To 9
          If possible(digit) = #IsPossible
            sudoku(column, row) = digit
            spot = row * 9 + column + 1
            If solvePuzzle(spot % 9, spot / 9)
              Break 3
            EndIf
          EndIf
        Next

        If digit = 10
          sudoku(column, row) = #Unknown
          ProcedureReturn #False
        EndIf
      EndIf
    Next
    x = 0 ;reset column start point
  Next
  ProcedureReturn #True
EndProcedure

If OpenConsole()
  readSudoku()
  displaySudoku()
  If solvePuzzle()
    PrintN("Solved.")
    displaySudoku()
  Else
    PrintN("Unable to solve puzzle") ;due to bad starting data
  EndIf

  Print(#CRLF$ + #CRLF$ + "Press ENTER to exit")
  Input()
  CloseConsole()
EndIf


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <glib.h>

#define ROWS   4
#define COLS  10
#define NPRX  "/"

/* wikipedia table
const char *table[ROWS][COLS] =
{
  { "0", "1", "2",  "3", "4", "5", "6",  "7", "8", "9" },
  { "E", "T", NULL, "A", "O", "N", NULL, "R", "I", "S  },
  { "B", "C", "D",  "F", "G", "H", "J",  "K", "L", "M" },
  { "P", "Q", NPRX, "U", "V", "W", "X",  "Y", "Z", "." }
};
*/

/* example of extending the table, COLS must be 11
const char *table[ROWS][COLS] =
{
  { "0", "1", "2", "3",  "4", "5", "6", "7",  "8", "9",  ":"  },
  { "H", "O", "L", NULL, "M", "E", "S", NULL, "R", "T",  ","  },
  { "A", "B", "C", "D",  "F", "G", "I", "J",  "K", "N",  "-"  },
  { "P", "Q", "U", "V",  "W", "X", "Y", "Z",  ".", NPRX, "?"  }
};
*/

// task table
const char *table[ROWS][COLS] =
{
  { "0", "1", "2", "3",  "4", "5", "6", "7",  "8", "9"  },
  { "H", "O", "L", NULL, "M", "E", "S", NULL, "R", "T"  },
  { "A", "B", "C", "D",  "F", "G", "I", "J",  "K", "N"  },
  { "P", "Q", "U", "V",  "W", "X", "Y", "Z",  ".", NPRX }
};

GHashTable *create_table_from_array(const char *table[ROWS][COLS], bool is_encoding)
{
  char buf[16];

  GHashTable *r = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
  size_t i, j, k, m;

  for(i = 0, m = 0; i < COLS; i++)
  {
    if (table[1][i] == NULL) m++;
  }

  const size_t SELNUM = m;

  size_t selectors[SELNUM];
  size_t numprefix_row, numprefix_col;
  bool has_numprefix = false;

  // selectors keep the indexes of the symbols to select 2nd and 3rd real row;
  // nulls must be placed into the 2nd row of the table
  for(i = 0, k = 0; i < COLS && k < SELNUM; i++)
  {
    if ( table[1][i] == NULL )
    {
      selectors[k] = i;
      k++;
    }
  }

  // numprefix is the prefix to insert symbols from the 1st row of table (numbers)
  for(j = 1; j < ROWS; j++)
  {
    for(i = 0; i < COLS; i++)
    {
      if (table[j][i] == NULL) continue;
      if ( strcmp(table[j][i], NPRX) == 0 )
      {
        numprefix_col = i;
        numprefix_row = j;
        has_numprefix = true;
	break;
      }
    }
  }

  // create the map for each symbol
  for(i = has_numprefix ? 0 : 1; i < ROWS; i++)
  {
    for(j = 0; j < COLS; j++)
    {
      if (table[i][j] == NULL) continue;
      if (strlen(table[i][j]) > 1)
      {
	fprintf(stderr, "symbols must be 1 byte long\n");
	continue; // we continue just ignoring the issue
      }
      if (has_numprefix && i == (ROWS-1) && j == numprefix_col && i == numprefix_row) continue;
      if (has_numprefix && i == 0)
      {
	snprintf(buf, sizeof(buf), "%s%s%s", table[0][selectors[SELNUM-1]], table[0][numprefix_col], table[0][j]);
      }
      else if (i == 1)
      {
	snprintf(buf, sizeof(buf), "%s", table[0][j]);
      }
      else
      {
	snprintf(buf, sizeof(buf), "%s%s", table[0][selectors[i-2]], table[0][j]);
      }
      if (is_encoding) g_hash_table_insert(r, strdup(table[i][j]), strdup(buf));
      else g_hash_table_insert(r, strdup(buf), strdup(table[i][j]));
    }
  }
  if (is_encoding) g_hash_table_insert(r, strdup("mode"), strdup("encode"));
  else g_hash_table_insert(r, strdup("mode"), strdup("decode"));

  return r;
}

char *decode(GHashTable *et, const char *enctext)
{
  char *r = NULL;

  if (et == NULL || enctext == NULL || strlen(enctext) == 0 ||
      g_hash_table_lookup(et, "mode") == NULL ||
      strcmp(g_hash_table_lookup(et, "mode"), "decode") != 0) return NULL;

  GString *res = g_string_new(NULL);
  GString *en = g_string_new(NULL);

  for( ; *enctext != '\0'; enctext++ )
  {
    if (en->len < 3)
    {
      g_string_append_c(en, *enctext);
      r = g_hash_table_lookup(et, en->str);
      if (r == NULL) continue;
      g_string_append(res, r);
      g_string_truncate(en, 0);
    }
    else
    {
      fprintf(stderr, "decoding error\n");
      break;
    }
  }

  r = res->str;
  g_string_free(res, FALSE);
  g_string_free(en, TRUE);
  return r;
}

char *encode(GHashTable *et, const char *plaintext, int (*trasf)(int), bool compress_spaces)
{
  GString *s;
  char *r = NULL;
  char buf[2] = { 0 };

  if (plaintext == NULL ||
      et == NULL || g_hash_table_lookup(et, "mode") == NULL ||
      strcmp(g_hash_table_lookup(et, "mode"), "encode") != 0) return NULL;

  s = g_string_new(NULL);

  for(buf[0] = trasf ? trasf(*plaintext) : *plaintext;
      buf[0] != '\0';
      buf[0] = trasf ? trasf(*++plaintext) : *++plaintext)
  {
    if ( (r = g_hash_table_lookup(et, buf)) != NULL )
    {
      g_string_append(s, r);
    }
    else if (isspace(buf[0]))
    {
      if (!compress_spaces) g_string_append(s, buf);
    }
    else
    {
      fprintf(stderr, "char '%s' is not encodable%s\n",
	      isprint(buf[0]) ? buf : "?",
	      !compress_spaces ? ", replacing with a space" : "");
      if (!compress_spaces) g_string_append_c(s, ' ');
    }
  }

  r = s->str;
  g_string_free(s, FALSE);
  return r;
}

int main()
{
  GHashTable *enctab = create_table_from_array(table, true);  // is encoding? true
  GHashTable *dectab = create_table_from_array(table, false); // is encoding? false (decoding)

  const char *text = "One night-it was on the twentieth of March, 1888-I was returning";

  char *encoded = encode(enctab, text, toupper, true);
  printf("%s\n", encoded);

  char *decoded = decode(dectab, encoded);
  printf("%s\n", decoded);

  free(decoded);
  free(encoded);
  g_hash_table_destroy(enctab);
  g_hash_table_destroy(dectab);

  return 0;
}


def initiate():
    box.append([0, 1, 2, 9, 10, 11, 18, 19, 20])
    box.append([3, 4, 5, 12, 13, 14, 21, 22, 23])
    box.append([6, 7, 8, 15, 16, 17, 24, 25, 26])
    box.append([27, 28, 29, 36, 37, 38, 45, 46, 47])
    box.append([30, 31, 32, 39, 40, 41, 48, 49, 50])
    box.append([33, 34, 35, 42, 43, 44, 51, 52, 53])
    box.append([54, 55, 56, 63, 64, 65, 72, 73, 74])
    box.append([57, 58, 59, 66, 67, 68, 75, 76, 77])
    box.append([60, 61, 62, 69, 70, 71, 78, 79, 80])
    for i in range(0, 81, 9):
        row.append(range(i, i+9))
    for i in range(9):
        column.append(range(i, 80+i, 9))

def valid(n, pos):
    current_row = pos/9
    current_col = pos%9
    current_box = (current_row/3)*3 + (current_col/3)
    for i in row[current_row]:
        if (grid[i] == n):
            return False
    for i in column[current_col]:
        if (grid[i] == n):
            return False
    for i in box[current_box]:
        if (grid[i] == n):
            return False
    return True

def solve():
    i = 0
    proceed = 1
    while(i < 81):
        if given[i]:
            if proceed:
                    i += 1
            else:
                i -= 1
        else:
            n = grid[i]
            prev = grid[i]
            while(n < 9):
              if (n < 9):
                  n += 1
              if valid(n, i):
                  grid[i] = n
                  proceed = 1
                  break
            if (grid[i] == prev):
               grid[i] = 0
               proceed = 0
            if proceed:
               i += 1
            else:
               i -=1

def inputs():
    nextt = 'T'
    number = 0
    pos = 0
    while(not(nextt == 'N' or nextt == 'n')):
        print "Enter the position:",
        pos = int(raw_input())
        given[pos - 1] = True
        print "Enter the numerical:",
        number = int(raw_input())
        grid[pos - 1] = number
        print "Do you want to enter another given?(Y, for yes: N, for no)"
        nextt = raw_input()

grid = [0]*81
given = [False]*81
box = []
row = []
column = []
initiate()
inputs()
solve()
for i in range(9):
    print grid[i*9:i*9+9]
raw_input()


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace StraddlingCheckerboard
{
    class Program
    {
        public readonly static IReadOnlyDictionary<char, string> val2Key;
        public readonly static IReadOnlyDictionary<string, char> key2Val;

        static Program()
        {
            val2Key = new Dictionary<char, string> {
                {'A',"30"},  {'B',"31"}, {'C',"32"},  {'D',"33"},  {'E',"5"},   {'F',"34"},  {'G',"35"},
                {'H',"0"},   {'I',"36"}, {'J',"37"},  {'K',"38"},  {'L',"2"},   {'M',"4"},   {'.',"78"},
                {'N',"39"},  {'/',"79"}, {'O',"1"},   {'0',"790"}, {'P',"70"},  {'1',"791"}, {'Q',"71"},
                {'2',"792"}, {'R',"8"},  {'3',"793"}, {'S',"6"},   {'4',"794"}, {'T',"9"},   {'5',"795"},
                {'U',"72"},  {'6',"796"},{'V',"73"},  {'7',"797"}, {'W',"74"},  {'8',"798"}, {'X',"75"},
                {'9',"799"}, {'Y',"76"}, {'Z',"77"}};

            key2Val = val2Key.ToDictionary(kv => kv.Value, kv => kv.Key);
        }

        public static string Encode(string s)
        {
            return string.Concat(s.ToUpper().ToCharArray()
                .Where(c => val2Key.ContainsKey(c)).Select(c => val2Key[c]));
        }

        public static string Decode(string s)
        {
            return string.Concat(Regex.Matches(s, "79.|7.|3.|.").Cast<Match>()
                .Where(m => key2Val.ContainsKey(m.Value)).Select(m => key2Val[m.Value]));
        }

        static void Main(string[] args)
        {
            var enc = Encode("One night-it was on the twentieth of March, 1888-I was returning");
            Console.WriteLine(enc);
            Console.WriteLine(Decode(enc));

            Console.ReadLine();
        }
    }
}


#include <iostream>
#include <string>
#include <map>
#include <algorithm> // for min, max
using namespace std;

class StraddlingCheckerboard
{
  map<char, string> table;
  char first[10], second[10], third[10];
  int rowU, rowV;

public:
  StraddlingCheckerboard(const string &alphabet, int u, int v)
  {
    rowU = min(u, v);
    rowV = max(u, v);

    for(int i = 0, j = 0; i < 10; ++i)
    {
      if(i != u && i != v)
      {
        first[i] = alphabet[j];
        table[alphabet[j]] = '0' + i;
        ++j;
      }

      second[i] = alphabet[i+8];
      table[alphabet[i+8]] = '0' + rowU;
      table[alphabet[i+8]] += '0' + i;

      third[i] = alphabet[i+18];
      table[alphabet[i+18]] = '0' + rowV;
      table[alphabet[i+18]] += '0' + i;
    }
  }

  string encode(const string &plain)
  {
    string out;
    for(int i = 0; i < plain.size(); ++i)
    {
      char c = plain[i];
      if(c >= 'a' && c <= 'z')
        c += 'A' - 'a';

      if(c >= 'A' && c <= 'Z')
        out += table[c];
      else if(c >= '0' && c <= '9')
      {
        out += table['/'];
        out += c;
      }
    }
    return out;
  }

  string decode(const string &cipher)
  {
    string out;
    int state = 0;
    for(int i = 0; i < cipher.size(); ++i)
    {
      int n = cipher[i] - '0';
      char next = 0;

      if(state == 1)
        next = second[n];
      else if(state == 2)
        next = third[n];
      else if(state == 3)
        next = cipher[i];
      else if(n == rowU)
        state = 1;
      else if(n == rowV)
        state = 2;
      else
        next = first[n];

      if(next == '/')
        state = 3;
      else if(next != 0)
      {
        state = 0;
        out += next;
      }
    }
    return out;
  }
};


import std.stdio, std.algorithm, std.string, std.array;

immutable T = ["79|0|1|2|3|4|5|6|7|8|9", "|H|O|L||M|E|S||R|T",
               "3|A|B|C|D|F|G|I|J|K|N", "7|P|Q|U|V|W|X|Y|Z|.|/"]
              .map!(r => r.split("|")).array;

enum straddle = (in string s) pure /*nothrow @safe*/ =>
    toUpper(s)
    .split("")
    .cartesianProduct(T)
    .filter!(cL => cL[1].canFind(cL[0]))
    .map!(cL => cL[1][0] ~ T[0][cL[1].countUntil(cL[0])])
    .join;

string unStraddle(string s) pure nothrow @safe {
    string result;
    for (; !s.empty; s.popFront) {
        immutable i = [T[2][0], T[3][0]].countUntil([s[0]]);
        if (i >= 0) {
            s.popFront;
            immutable n = T[2 + i][T[0].countUntil([s[0]])];
            if (n == "/") {
                s.popFront;
                result ~= s[0];
            } else result ~= n;
        } else
            result ~= T[1][T[0].countUntil([s[0]])];
    }
    return result;
}

void main() {
    immutable O = "One night-it was on the twentieth of March, 1888-I was returning";
    writeln("Encoded: ", O.straddle);
    writeln("Decoded: ", O.straddle.unStraddle);
}


import Prelude;
import vis::Figure;
import vis::Render;

public rel[int,int,int] sudoku(rel[int x, int y, int v] sudoku){
	annotated= annotateGrid(sudoku);
	solved = {<0,0,0,0,{0}>};

	while(!isEmpty(solved)){
		for (n <- [0 ..8]){
			column = domainR(annotated, {n});
			annotated -= column;
			annotated += reduceOptions(column);

			row = {<x,y,v,g,p> | <x,y,v,g,p> <- annotated, y==n};
			annotated -= row;
			annotated += reduceOptions(row);

			grid1 = {<x,y,v,g,p> | <x,y,v,g,p> <- annotated, g==n};
			annotated -= grid1;
			annotated += reduceOptions(grid1);
		}

		solved = {<x,y,v,g,p> | <x,y,v,g,p> <- annotated, size(p)==1};
		annotated -= solved;
		annotated += {<x,y,getOneFrom(p),g,{*[1 .. 9]}> | <x,y,v,g,p> <- solved};
	}

	result = {<x,y,v> | <x,y,v,g,p> <- annotated};
	return result;
}

//adds gridnumber and default set of options
public rel[int,int,int,int,set[int]] annotateGrid(rel[int x, int y, int v] sudoku){
	result = {};
		for (<x, y, v> <- sudoku){
			g = 0;
			if (x<3 && y<3) g = 0;
			if (2<x && x<6 && y<3) g = 1;
			if (x>5 && y<3) g = 2;

			if (x<3 && 2<y && y<6) g = 3;
			if (2<x && x<6 && 2<y && y<6) g = 4;
			if (x>5 && 2<y && y<6) g = 5;

			if (x<3 && y>5) g=6;
			if (2<x && x<6 && y>5) g=7;
			if (x>5 && y>5) g=8;

			result += <x,y,v,g,{*[1 .. 9]}>;
			}
	return result;
}

//reduces set of options
public rel[int,int,int,int,set[int]] reduceOptions(rel[int x, int y, int v, int g, set[int] p] subSudoku){
	solved = {<x,y,v,g,p> | <x,y,v,g,p> <- subSudoku, v!=0};
	numbers = {*[1 .. 9]} - {v | <x,y,v,g,p> <- solved};
	remaining = {<x,y,v,g,numbers&p> | <x,y,v,g,p> <- subSudoku-solved};
	result = remaining + solved;
	return result;
}

//a function to visualize the result
public void displaySudoku(rel[int x, int y, int v] sudoku){
	points = [box(text("<v>"), align(0.111111*(x+1),0.111111*(y+1)),shrink(0.1)) | <x,y,v> <- sudoku];
	print(points);
	render(overlay([*points], aspectRatio(1.0)));
}

//a sudoku
public rel[int, int, int] sudokuA =
{
<0,0,3>, <1,0,9>, <2,0,4>, <3,0,0>, <4,0,0>, <5,0,2>, <6,0,6>, <7,0,7>, <8,0,0>,
<0,1,0>, <1,1,0>, <2,1,0>, <3,1,3>, <4,1,0>, <5,1,0>, <6,1,4>, <7,1,0>, <8,1,0>,
<0,2,5>, <1,2,0>, <2,2,0>, <3,2,6>, <4,2,9>, <5,2,0>, <6,2,0>, <7,2,2>, <8,2,0>,
<0,3,0>, <1,3,4>, <2,3,5>, <3,3,0>, <4,3,0>, <5,3,0>, <6,3,9>, <7,3,0>, <8,3,0>,
<0,4,6>, <1,4,0>, <2,4,0>, <3,4,0>, <4,4,0>, <5,4,0>, <6,4,0>, <7,4,0>, <8,4,7>,
<0,5,0>, <1,5,0>, <2,5,7>, <3,5,0>, <4,5,0>, <5,5,0>, <6,5,5>, <7,5,8>, <8,5,0>,
<0,6,0>, <1,6,1>, <2,6,0>, <3,6,0>, <4,6,6>, <5,6,7>, <6,6,0>, <7,6,0>, <8,6,8>,
<0,7,0>, <1,7,0>, <2,7,9>, <3,7,0>, <4,7,0>, <5,7,8>, <6,7,0>, <7,7,0>, <8,7,0>,
<0,8,0>, <1,8,2>, <2,8,6>, <3,8,4>, <4,8,0>, <5,8,0>, <6,8,7>, <7,8,3>, <8,8,5>
};


(*
Encode and Decode using StraddlingCheckerboard
Nigel Galloway May 15th., 2017
*)
type G={n:char;i:char;g:System.Collections.Generic.Dictionary<(char*char),string>;e:System.Collections.Generic.Dictionary<char,string>}
       member G.encode n=n|>Seq.map(fun n->if (n='/') then G.e.['/']+string n else match (G.e.TryGetValue(n)) with |(true,n)->n|(false,_)->G.e.['/']+string n)
       member G.decode n =
         let rec fn n = seq{ if not (Seq.isEmpty n)
           then match (match Seq.head n with |g when g=G.n||g=G.i->(G.g.[(g,(Seq.item 1 n))],(Seq.skip 2 n))|g->(G.g.[('/',g)],(Seq.tail n))) with
                |(a,b) when a="/"->yield string (Seq.head b); yield! fn (Seq.tail b)
                |(a,b)           ->yield a;                   yield! fn b
         }
         fn n
let G n i g e l z=
  let a = new System.Collections.Generic.Dictionary<(char*char),string>()
  let b = new System.Collections.Generic.Dictionary<char,string>()
  Seq.iter2 (fun ng gn->a.[('/'   ,char ng)]<-string gn;b.[gn]<-ng) (List.except [n;i] z) g
  Seq.iter2 (fun ng gn->a.[(char n,char ng)]<-string gn;b.[gn]<-n+ng)                  z  e
  Seq.iter2 (fun ng gn->a.[(char i,char ng)]<-string gn;b.[gn]<-i+ng)                  z  l
  {n=char n;i=char i;g=a;e=b}


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Register And Flag Usage
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;        0        General purpose variable used for miscelaneous purposes
;        1        Current index (0-80) in the pseudo-recursion
;        2        Row (0-8) of current index
;        3        Column (0-8) of current index
;        4        Block # (0-8) of current index
;        5        Power of 10 of current column index
;        6        Value in the test solution at current index
;        7        Value of start clue at current index (0 if not set)
;        8 – 16   Starting row data
;        17 – 25  Current test solution
;        26 – 34  Flag matrix (bit set if digit used in a row/column/block)
;
;        Flag 2   Indicates that a digit has been used in cur row/column/block
;        Flag 3   Input to Subroutine B (whether to set or clear flags)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; setU(x)
; Set/clear flag matrix values (show that x is used in a row/column/block)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LBL D
        GSB 5       ; calc bit value we need to set/clear in existing row
        RCL 2       ; Get the current row index into x
        GSB B       ; set flag matrix value and calc new bit value for the column
        RCL 3       ; Get the current column index into x
        GSB B       ; set flag matrix values and calc new bit value for the block
        RCL 4       ; Get the current block index into x

; MUST IMMEDIATELY FOLLOW PRECEEDING SUBROUTINE
; utility subroutine for setting flag matrix values

LBL B
        GSB 1       ; get the current flag matrix row at index x

        RCL 0       ; get temp register (holds the bit value we will be setting)
        F? 3        ; flag 3 indicates if we are setting or clearing the flag
        CHS         ; if we are clearing, we will do a subtraction instead
        +           ; set/clear the flag

        X<>Y        ; bring the row index back into x
        2           ; 26 is the starting register for the flag matrix
        6
        GSB 3       ; set I so that we are ready to store the new value
        STO (i)     ; store the new value into the flag matrix
        RDN         ; get rid of the new value to restore the stack
        9           ; the next bit value will be 9 bits to the left
        +           ; set the next bit index
        GTO 5       ; calculate the value with that bit set
                    ; we GTO instead of GSB and it will do the RTN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; putA(x)
; Set the value x into the current row/column in the trial solution.
; Does it by subtracting the previous value and adding the new one.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LBL 7
        X<>6        ; swap new value with register that holds current value
        STO 0       ; store the old value in the temp register
        RCL 2       ; Get the current row index into x
        1           ; 17 is the starting register for the current trial solution
        7
        GSB 3       ; Set the indirect register
        RCL (i)     ; Get the current value for the entire row
        RCL 6       ; Get the new value
        RCL- 0      ; subtract the old value from the new value
        RCL* 5      ; shift the power of 10 to the appropriate column
        +           ; add to the old value
        STO (i)     ; store the new row value from where we got it
        RTN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; change(x)
; Increments or decrements the current position in the trial solution.
; Updates the registers containing the current row, column and block index,
; and the one with the power of 10 factor for the current column and others
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LBL 6
        STO+ 1      ; x holds +1 or -1; Register 1 is the current index

        RCL 1       ; get the current index (0 to 80)
        RCL 1       ; get the current index (0 to 80)
        9           ; integer divide by 9 to get the row index (0 to 8)
        /           ; no integer divide on 15c so do a floating point divide
        INT         ; use the INT operator to finish of the integer divide
        STO 2       ; register 2 contains the current row index

        9
        *
        -           ; col = index - 9 * row
        STO 3       ; register 3 contains the current column index

        3           ; calculate the block index from the row & column indexes
        /           ; TODO: save a couple of bytes in this section of code
        RCL 2
        3
        /
        INT
        3
        *
        +
        STO 4       ; register 4 holds the block index

        8           ; now calculate the power of 10 of the current column
        RCL- 3      ; Get the digit (from right) based on the column
        10^X        ; calculate the exponent
        STO 5       ; save in register 5 which is used throughout the code

        RCL 2       ; get the current row
        1           ; 17 is the start register of the current trial solution
        7
        GSB 4       ; extract the value at the current column
        STO 6       ; reg 6: the current trial value at the current row/column

        RCL 2       ; get the current row
        8           ; 8 is the start register of the input data from the user
        GSB 4       ; extract the value at the current column
        STO 7       ; reg 7: starting value at the current row/column (0 if none)
        RTN

; Extract value at the current column from the matrix indirectly specified by x&y
LBL 4
        GSB 3       ; set the indirect register based on x & y
        RCL (i)     ; get the row from the matrix passed in
        RCL / 5     ; shift the row to the right
        INT         ; trim off the digits shifted to the right of the decimal
        1           ; we will do a modulus 10 to extract the last digit
        0
        /           ; do the equivalent of a mod 10
        FRAC
        1
        0
        *
        RTN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  main()
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LBL A
        CF 2        ; make sure flag 2 is unset - CLR REG does not do this
        CF 3        ; make sure flag 3 is unset - CLR REG does not do this
        1           ; start with a index in register 1 of -1 (0 to 80)
        CHS         ; that way we can start with an increment operation
        STO 1       ; and actually start at 0 where we want.

LBL 2               ; set the flags to show the input values are set
        1           ; go forward one position at a time
        GSB 6       ; go to the next position in the trial solution

        RCL 7       ; get the starting input value at this row/col
        GSB 7       ; set the value in the trial solution
        RCL 7       ; get starting input value because the last call destroyed it
        TEST 1      ; if > 0 then the user input a value for this row/col
        GSB D       ; set the flags to indicate this value is set

        8           ; 80 is the upper bound of the indexes (9x9 = 80 = 0:80)
        0
        RCL 1       ; get the current index
        TEST 6      ; if the current index hasn't reached 80
        GTO 2       ; do the next value
        1           ; reset the starting value
        CHS         ; to -1 as we did at the beginning of the program
        STO 1       ; register 1 holds the current index

LBL E               ; main solution loop
        8           ; when we reach the last index (80) we are done
        0
        RCL 1       ; register 1 holds the current index
        TEST 5      ; see if we are at the end
        RTN         ;  finished        ; woohoo - we are done!
        1           ; Go forward one spot
        GSB 6       ; Do the position increment
        RCL 7       ; get the starting input value at this row/col
        TEST 1      ; if it's > 0, the user specified a value here
        GTO E       ; go forward, since this value was specified by the user
        GSB 7       ; Set the value in the trial solution

LBL 8
        9           ; check the possible digits in order 1-9.
        RCL 6       ; Get the current trial solution value
        TEST 5      ; Check to see if it is 9
        GTO C       ; If it is, backup one step
        1           ; We weren't at 9 yet, so increment the value by 1
        +
        GSB 7       ; Set the value in the trial solution

        RCL 6       ; Get the current trial solution value
        GSB 5       ; Calc 2^x-1 to get the bit mask
        CF 2        ; Clear the flag thats used as a return value
        RCL 2       ; Get the current row index into x
        GSB 9       ; see if the current value has already been used in the row
        F? 2        ; If number has been used in the block, try the next value
        GTO 8
        RCL 3       ; Get the current column index into x
        GSB 9       ; see if current value has already been used in the column
        F? 2        ; If number has been used in the block, try the next value
        GTO 8
        RCL 4       ; Get the current block index into x
        GSB 9       ; see if the current value has already been used in the block
        F? 2        ; If number has been used in the block, try the next value
        GTO 8
        RCL 6       ; Get the current trial solution value
        GSB D       ; set the flags to indicate this value is set
        GTO E       ; move on to the next position in the puzzle

LBL C               ; Come here to back up to the previous position
        1           ; We will go one spot backwards
        CHS
        GSB 6       ; Set the new current position and all temp values
        TEST 1      ; previous call leaves the starting value in X
        GTO C       ; if value is > 0, it was set, backup one more spot
        RCL 6       ; Get the current trial solution value

        SF 3        ; flag 3: clear the flag matrix bits, instead of setting them
        GSB D       ; Set/Clear the flag matrix bits
        CF 3        ; unset the 3 flag
        GTO 8       ; check the next digit

LBL 9
        GSB 1       ; get the appropriate row (x) from the flag matrix
        RCL /  0    ; divide by the temp register - right shifts value
        INT
        2           ; if bit is set, fractional part will be non 0 when / 2
        /
        FRAC
        TEST 1      ; if bit is set, set flag 2 which is used as a return value
        SF 2
        RDN         ; move the stack down to prepare the caller for the next call
        RDN         ; move the stack down to prepare the caller for the next call
        9           ; bit flags for row/col/block are << by 9 from each other
        +           ; calculates the appropriate bit offset for the next call
        GTO 5       ; calc 2^x-1 to get the bit mask
                    ; do a GTO instead of GSB and it will return for us

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; setPow2(x)
; Sets the utility temp register to 2^(x-1). Leaves x in place.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LBL 5
        STO 0       ; store the input X in the temp register
        1           ; we want to subtract 1 from the exponent
        -           ; calculate x-1
        2           ; set the base as 2
        X<>Y        ; the y^x function wants x and y reversed
        y^x         ; calculate the value
        X<>0        ; stuff result in temp register and restore the input x
        RTN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; getPart(x)
; Returns the integer representing the entire Xth row of the flag matrix
; Row numbers start at 0.
; returns value in x - input parameter x ends up in y
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LBL 1
        ENTER
        ENTER       ; duplicate the parameter so we can leave it for the caller
        2           ; 26 is the starting register for the flag matrix
        6
        GSB 3       ; set the indirect register to the row specified by x
        RCL (i)     ; retrieve the entire row from the flag matrix
        RTN

; Set the indirect register and remove the parameters from the stack
LBL 3
        +           ; x+y is the memory offset we want
        STO I       ; put it in the indirect register
        RDN         ; get rid of the sum from the stack
        RTN


package main

import (
    "fmt"
    "strings"
)

func main() {
    key := `
 8752390146
 ET AON RIS
5BC/FGHJKLM
0PQD.VWXYZU`
    p := "you have put on 7.5 pounds since I saw you."
    fmt.Println(p)
    c := enc(key, p)
    fmt.Println(c)
    fmt.Println(dec(key, c))
}

func enc(bd, pt string) (ct string) {
    enc := make(map[byte]string)
    row := strings.Split(bd, "\n")[1:]
    r2d := row[2][:1]
    r3d := row[3][:1]
    for col := 1; col <= 10; col++ {
        d := string(row[0][col])
        enc[row[1][col]] = d
        enc[row[2][col]] = r2d+d
        enc[row[3][col]] = r3d+d
    }
    num := enc['/']
    delete(enc, '/')
    delete(enc, ' ')
    for i := 0; i < len(pt); i++ {
        if c := pt[i]; c <= '9' && c >= '0' {
            ct += num + string(c)
        } else {
            if c <= 'z' && c >= 'a' {
                c -= 'a'-'A'
            }
            ct += enc[c]
        }
    }
    return
}

func dec(bd, ct string) (pt string) {
    row := strings.Split(bd, "\n")[1:]
    var cx [10]int
    for i := 1; i <= 10; i++ {
        cx[row[0][i]-'0'] = i
    }
    r2d := row[2][0]-'0'
    r3d := row[3][0]-'0'
    for i := 0; i < len(ct); i++ {
        var r int
        switch d := ct[i]-'0'; d {
        case r2d:
            r = 2
        case r3d:
            r = 3
        default:
            pt += string(row[1][cx[d]])
            continue
        }
        i++
        if b := row[r][cx[ct[i]-'0']]; b == '/' {
            i++
            pt += string(ct[i])
        } else {
            pt += string(b)
        }
    }
    return
}


import Data.Char
import Data.Map

charToInt :: Char -> Int
charToInt c = ord c - ord '0'

-- Given a string, decode a single character from the string.
-- Return the decoded char and the remaining undecoded string.
decodeChar :: String -> (Char,String)
decodeChar ('7':'9':r:rs) = (r,rs)
decodeChar ('7':r:rs)     = ("PQUVWXYZ. " !! charToInt r, rs)
decodeChar ('3':r:rs)     = ("ABCDFGIJKN" !! charToInt r, rs)
decodeChar (r:rs)         = ("HOL MES RT" !! charToInt r, rs)

-- Decode an entire string.
decode :: String -> String
decode [] = []
decode st = let (c, s) = decodeChar st in c:decode s

-- Given a string, decode a single character from the string.
-- Return the decoded char and the part of the encoded string
-- used to encode that character.
revEnc :: String -> (Char, String)
revEnc enc = let (dec, rm) = decodeChar enc in (dec, take (length enc - length rm) enc)

ds :: String
ds = ['0'..'9']

-- Decode all 1000 possible encodings of three digits and
-- use results to construct map used to encode.
encodeMap :: Map Char String
encodeMap = fromList [ revEnc [d2,d1,d0] | d2 <- ds, d1 <- ds, d0 <- ds ]

-- Encode a single char using encoding map.
encodeChar :: Char -> String
encodeChar c = findWithDefault "" c encodeMap

-- Encode an entire string.
encode :: String -> String
encode st = concatMap encodeChar $ fmap toUpper st

-- Test by encoding, decoding, printing results.
main = let orig = "One night-it was on the twentieth of March, 1888-I was returning"
           enc = encode orig
           dec = decode enc
       in mapM_ putStrLn [ "Original: " ++ orig
                         , "Encoded: " ++ enc
                         , "Decoded: " ++ dec ]


def read_matrix(data)
  lines = data.lines
  9.times.collect { |i| 9.times.collect { |j| lines[i][j].to_i } }
end

def permissible(matrix, i, j)
  ok = [nil, *1..9]
  check = ->(x,y) { ok[matrix[x][y]] = nil  if matrix[x][y].nonzero? }
  # Same as another in the column isn't permissible...
  9.times { |x| check[x, j] }
  # Same as another in the row isn't permissible...
  9.times { |y| check[i, y] }
  # Same as another in the 3x3 block isn't permissible...
  xary = [ *(x = (i / 3) * 3) .. x + 2 ]        #=> [0,1,2], [3,4,5] or [6,7,8]
  yary = [ *(y = (j / 3) * 3) .. y + 2 ]
  xary.product(yary).each { |x, y| check[x, y] }
  # Gathering only permitted one
  ok.compact
end

def deep_copy_sudoku(matrix)
  matrix.collect { |row| row.dup }
end

def solve_sudoku(matrix)
  loop do
    options = []
    9.times do |i|
      9.times do |j|
        next if matrix[i][j].nonzero?
        p = permissible(matrix, i, j)
        # If nothing is permissible, there is no solution at this level.
        return if p.empty?              # return nil
        options << [i, j, p]
      end
    end
    # If the matrix is complete, we have a solution...
    return matrix if options.empty?

    i, j, permissible = options.min_by { |x| x.last.length }

    # If there is an option with only one solution, set it and re-check permissibility
    if permissible.length == 1
      matrix[i][j] = permissible[0]
      next
    end

    # We have two or more choices. We need to search both...
    permissible.each do |v|
      mtmp = deep_copy_sudoku(matrix)
      mtmp[i][j] = v
      ret = solve_sudoku(mtmp)
      return ret if ret
    end

    # We did an exhaustive search on this branch and nothing worked out.
    return
  end
end

def print_matrix(matrix)
  puts "Impossible" or return  unless matrix

  border = "+-----+-----+-----+"
  9.times do |i|
    puts border if i%3 == 0
    9.times do |j|
      print j%3 == 0 ? "|" : " "
      print matrix[i][j] == 0 ? "." : matrix[i][j]
    end
    puts "|"
  end
  puts border
end

data = <<EOS
394__267_
___3__4__
5__69__2_
_45___9__
6_______7
__7___58_
_1__67__8
__9__8___
_264__735
EOS

matrix = read_matrix(data)
print_matrix(matrix)
puts
print_matrix(solve_sudoku(matrix))


procedure main()
StraddlingCheckerBoard("setup","HOLMESRTABCDFGIJKNPQUVWXYZ./", 3,7)

text := "One night. it was on the twentieth of March, 1888. I was returning"
write("text   = ",image(text))
write("encode = ",image(en := StraddlingCheckerBoard("encode",text)))
write("decode = ",image(StraddlingCheckerBoard("decode",en)))
end

procedure StraddlingCheckerBoard(act,text,b1,b2)
static SCE,SCD
case act of {
   "setup" : {
      if (b1 < b2 < 10) & (*text = *cset(text) = 28) then {
         SCE := table("")
         SCD := table()
         esc := text[-1]                               # escape
         every text[(b1|b2)+1+:0] := " "               # blanks
         uix := ["",b1,b2]                             # 1st position
         every c := text[1 + (i := 0 to *text-1)] do   # build translation
            if c ~== " " then                          # skip blanks
               SCD[SCE[c] := SCE[map(c)] := uix[i/10+1]||(i%10) ] := c
         every c := !&digits do
            SCD[SCE[c] := SCE[esc] || c] := c
         delete(SCD,SCE[esc])
         delete(SCE,esc)
         }
         else stop("Improper setup: ",image(text),", ",b1,", ",b2)
      }
   "encode" : {
      every (s := "") ||:= x := SCE[c := !text]
      return s
      }
   "decode" : {
      s := ""
      text ? until pos(0) do
         s ||:= \SCD[k := move(1 to 3)]
      return s
      }
   }
end


type Sudoku = [u8; 81];

fn is_valid(val: u8, x: usize, y: usize, sudoku_ar: &mut Sudoku) -> bool {
    (0..9).all(|i| sudoku_ar[y * 9 + i] != val && sudoku_ar[i * 9 + x] != val) && {
        let (start_x, start_y) = ((x / 3) * 3, (y / 3) * 3);
        (start_y..start_y + 3).all(|i| (start_x..start_x + 3).all(|j| sudoku_ar[i * 9 + j] != val))
    }
}

fn place_number(pos: usize, sudoku_ar: &mut Sudoku) -> bool {
    (pos..81).find(|&p| sudoku_ar[p] == 0).map_or(true, |pos| {
        let (x, y) = (pos % 9, pos / 9);
        for n in 1..10 {
            if is_valid(n, x, y, sudoku_ar) {
                sudoku_ar[pos] = n;
                if place_number(pos + 1, sudoku_ar) {
                    return true;
                }
                sudoku_ar[pos] = 0;
            }
        }
        false
    })
}

fn pretty_print(sudoku_ar: Sudoku) {
    let line_sep = "------+-------+------";
    println!("{}", line_sep);
    for (i, e) in sudoku_ar.iter().enumerate() {
        print!("{} ", e);
        if (i + 1) % 3 == 0 && (i + 1) % 9 != 0 {
            print!("| ");
        }
        if (i + 1) % 9 == 0 {
            println!(" ");
        }
        if (i + 1) % 27 == 0 {
            println!("{}", line_sep);
        }
    }
}

fn solve(sudoku_ar: &mut Sudoku) -> bool {
    place_number(0, sudoku_ar)
}

fn main() {
    let mut sudoku_ar: Sudoku = [
        8, 5, 0, 0, 0, 2, 4, 0, 0,
        7, 2, 0, 0, 0, 0, 0, 0, 9,
        0, 0, 4, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 1, 0, 7, 0, 0, 2,
        3, 0, 5, 0, 0, 0, 9, 0, 0,
        0, 4, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 8, 0, 0, 7, 0,
        0, 1, 7, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 3, 6, 0, 4, 0
    ];
    if solve(&mut sudoku_ar) {
        pretty_print(sudoku_ar);
    } else {
        println!("Unsolvable");
    }
}


'Esc Stop'=: '/.'
'Nums Alpha'=: '0123456789';'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
Charset=: Nums,Alpha,Stop

escapenum=: (,@:((; Esc&,)&>) Nums) rplc~ ]               NB. escape numbers
unescapenum=: ((, ; ' '&,@])"1 0  Nums"_) rplc~ ]         NB. unescape coded numbers (x is escape code, y is cipher)
expandKeyatUV=: 0:`[`(1 #~ 2 + #@])} #inv ]
makeChkBrd=: Nums , expandKeyatUV

chkbrd=: conjunction define
  'uv key'=. n
  board=. uv makeChkBrd key
  select. m
  case. 0 do.                                                      NB. encode
    digits=. board 10&#[email protected] escapenum y
    ' ' -.~ ,(":@{:"1 digits) ,.~ (1 1 0 2{":uv) {~ {."1 digits
  case. 1 do.                                                      NB. decode
    esc=. 0 chkbrd (uv;key) Esc                                    NB. find code for Esc char
    tmp=. esc unescapenum esc,'0',y
    tmp=. ((":uv) (([email protected]~ _1&|.) *. e.~) tmp) <;.1 tmp            NB. box on chars from rows 0 2 3
    idx=. (}. ,~ (1 1 0 2{":uv) ":@i. {.) each tmp                 NB. recreate indices for rows 0 2 3
    idx=. ;(2&{. , [: ((0 1 $~ +:@#) #inv!.'1' ]) 2&}.) each idx   NB. recreate indices for row 1
    }.board {~ _2 (_&".)\ idx
  end.
)


import java.util.HashMap;
import java.util.Map;
import java.util.regex.*;

public class StraddlingCheckerboard {

    final static String[] keyvals = {"H:0", "O:1", "L:2", "M:4", "E:5", "S:6",
        "R:8", "T:9", "A:30", "B:31", "C:32", "D:33", "F:34", "G:35", "I:36",
        "J:37", "K:38", "N:39", "P:70", "Q:71", "U:72", "V:73", "W:74", "X:75",
        "Y:76", "Z:77", ".:78", "/:79", "0:790", "1:791", "2:792", "3:793",
        "4:794", "5:795", "6:796", "7:797", "8:798", "9:799"};

    final static Map<String, String> val2key = new HashMap<>();
    final static Map<String, String> key2val = new HashMap<>();

    public static void main(String[] args) {
        for (String keyval : keyvals) {
            String[] kv = keyval.split(":");
            val2key.put(kv[0], kv[1]);
            key2val.put(kv[1], kv[0]);
        }
        String enc = encode("One night-it was on the twentieth of March, "
                + "1888-I was returning");
        System.out.println(enc);
        System.out.println(decode(enc));
    }

    static String encode(String s) {
        StringBuilder sb = new StringBuilder();
        for (String c : s.toUpperCase().split("")) {
            c = val2key.get(c);
            if (c != null)
                sb.append(c);
        }
        return sb.toString();
    }

    static String decode(String s) {
        Matcher m = Pattern.compile("(79.|3.|7.|.)").matcher(s);
        StringBuilder sb = new StringBuilder();
        while (m.find()) {
            String v = key2val.get(m.group(1));
            if (v != null)
                sb.append(v);
        }
        return sb.toString();
    }
}


/* define SAS data set */
data Indata;
   input C1-C9;
   datalines;
. . 5 . . 7 . . 1
. 7 . . 9 . . 3 .
. . . 6 . . . . .
. . 3 . . 1 . . 5
. 9 . . 8 . . 2 .
1 . . 2 . . 4 . .
. . 2 . . 6 . . 9
. . . . 4 . . 8 .
8 . . 1 . . 5 . .
;

/* call OPTMODEL procedure in SAS/OR */
proc optmodel;
   /* declare variables */
   set ROWS = 1..9;
   set COLS = ROWS;
   var X {ROWS, COLS} >= 1 <= 9 integer;

   /* declare nine row constraints */
   con RowCon {i in ROWS}:
      alldiff({j in COLS} X[i,j]);

   /* declare nine column constraints */
   con ColCon {j in COLS}:
      alldiff({i in ROWS} X[i,j]);

   /* declare nine 3x3 block constraints */
   con BlockCon {s in 0..2, t in 0..2}:
      alldiff({i in 3*s+1..3*s+3, j in 3*t+1..3*t+3} X[i,j]);

   /* fix variables to cell values */
   /* X[i,j] = c[i,j] if c[i,j] is not missing */
   num c {ROWS, COLS};
   read data indata into [_N_] {j in COLS} <c[_N_,j]=col('C'||j)>;
   for {i in ROWS, j in COLS: c[i,j] ne .}
      fix X[i,j] = c[i,j];

   /* call CLP solver */
   solve;

   /* print solution */
   print X;
quit;


<script>
var alphabet=new Array("ESTONIA  R","BCDFGHJKLM","PQUVWXYZ./") // scramble alphabet as you wish
var prefixes=new Array("",alphabet[0].indexOf(" "),alphabet[0].lastIndexOf(" "))

function straddle(message){
  var out=""
  message=message.toUpperCase()
  message=message.replace(/([0-9])/g,"/$1") // dumb way to escape numbers
  for(var i=0;i<message.length;i++){
    var chr=message[i]
	if(chr==" ")continue
	for(var j=0;j<3;j++){
	  var k=alphabet[j].indexOf(chr)
	  if(k<0)continue
	  out+=prefixes[j].toString()+k
	}
	if(chr=="/")out+=message[++i]
  }
  return out
}

function unstraddle(message){
  var out=""
  var n,o
  for(var i=0;i<message.length;i++){
	n=message[i]*1
    switch(n){
	  case prefixes[1]: o=alphabet[1][message[++i]];break
	  case prefixes[2]: o=alphabet[2][message[++i]];break
	  default: o=alphabet[0][n]
	}
	o=="/"?out+=message[++i]:out+=o
  }
  return out
}

str="One night-it was on the twentieth of March, 1888-I was returning."
document.writeln(str)
document.writeln(straddle(str))
document.writeln(unstraddle(straddle(str)))
</script>


function straddlingcheckerboard(board, msg, doencode)
    lookup = Dict()
    reverselookup = Dict()
    row2 = row3 = slash = -1
    function encode(x)
        s = ""
        for ch in replace(replace(uppercase(x), r"([01-9])", s";=;\1"), r";=;", slash)
            c = string(ch)
            if haskey(lookup, c)
                s *= lookup[c]
            elseif contains("0123456789", c)
                s *= c
            end
        end
        s
    end
    function decode(x)
        s = ""
        i = 1
        while i <= length(x)
            c = string(x[i])
            if haskey(reverselookup, c)
                s *= reverselookup[c]
                i += 1
            else
                if "$c$(x[i+1])" == slash
                    s *= string(x[i+2])
                    i += 3
                else
                    s *= reverselookup["$c$(x[i+1])"]
                    i += 2
                end
            end
        end
        s
    end
    for (i,c) in enumerate(board)
        c = string(c)
        if c == " "
            if row2 == -1
                row2 = i-1
            else
                row3 = i-1
            end
        else
            if i < 11
                lookup[c] = "$(i-1)"; reverselookup["$(i-1)"] =  c
            elseif i < 21
                lookup[c] = "$row2$(i-11)"; reverselookup["$row2$(i-11)"] = c
            else
                lookup[c] = "$row3$(i-21)"; reverselookup["$row3$(i-21)"] = c
            end
            if c == "/"
                slash = lookup[c]
            end
        end
    end
    doencode ? encode(msg) : decode(msg)
end

btable = "ET AON RISBCDFGHJKLMPQ/UVWXYZ."
message = "Thecheckerboardcakerecipespecifies3largeeggsand2.25cupsofflour."
encoded = straddlingcheckerboard(btable, message, true)
decoded = straddlingcheckerboard(btable, encoded, false)
println("Original: $message\nEncoded:  $encoded\nDecoded:  $decoded")


object SudokuSolver extends App {

  class Solver {

    var solution = new Array[Int](81)   //listOfFields toArray

    val fp2m: Int => Tuple2[Int,Int] = pos => Pair(pos/9+1,pos%9+1) //get row, col from array position
    val setAll = (1 to 9) toSet //all possibilities

    val arrayGroups = new Array[List[List[Int]]](81)
    val sv: Int => Int = (row: Int) => (row-1)*9 //start value group row
    val ev: Int => Int = (row: Int) => sv(row)+8 //end value group row
    val fgc: (Int,Int) => Int = (i,col) => i*9+col-1 //get group col
    val fgs: Int => (Int,Int) = p => Pair(p, p/(27)*3+p%9/3) //get group square box
    for (pos <- 0 to 80) {
      val (row,col) = fp2m(pos)
      val gRow = (sv(row) to ev(row)).toList
      val gCol = ((0 to 8) toList) map (fgc(_,col))
      val gSquare = (0 to 80 toList) map fgs filter (_._2==(fgs(pos))._2) map (_._1)
      arrayGroups(pos) = List(gRow,gCol,gSquare)
    }
    val listGroups = arrayGroups toList

    val fpv4s: (Int) => List[Int] = pos => {   //get possible values for solving
      val setRow = (listGroups(pos)(0) map (solution(_))).toSet
      val setCol = listGroups(pos)(1).map(solution(_)).toSet
      val setSquare = listGroups(pos)(2).map(solution(_)).toSet
      val setG = setRow++setCol++setSquare--Set(0)
      val setPossible = setAll--setG
      setPossible.toList.sortWith(_<_)
    }

    //solve the riddle: Nil ==> solution does not exist
    def solve(listOfFields: List[Int]): List[Int] = {
      solution = listOfFields toArray

      def checkSol(uncheckedSol: List[Int]): List[Int] = {
        if (uncheckedSol == Nil) return Nil
        solution = uncheckedSol toArray
        val check = (0 to 80).map(fpv4s(_)).filter(_.size>0)
        if (check == Nil) return uncheckedSol
        return Nil
      }

      val f1: Int => Pair[Int,Int] = p => Pair(p,listOfFields(p))
      val numFields = (0 to 80 toList) map f1 filter (_._2==0)
      val iter = numFields map ((_: (Int,Int))._1)
      var p_iter = 0

      val first: () => Int = () => {
        val ret = numFields match {
          case Nil => -1
          case _   => numFields(0)._1
        }
        ret
      }

      val last: () => Int = () => {
        val ret = numFields match {
          case Nil => -1
          case _   => numFields(numFields.size-1)._1
        }
        ret
      }

      val hasPrev: () => Boolean = () => p_iter > 0
      val prev: () => Int = () => {p_iter -= 1; iter(p_iter)}
      val hasNext: () => Boolean = () => p_iter < iter.size-1
      val next: () => Int = () => {p_iter += 1; iter(p_iter)}
      val fixed: Int => Boolean = pos => listOfFields(pos) != 0
      val possiArray = new Array[List[Int]](numFields.size)
      val firstUF = first() //first unfixed
      if (firstUF < 0) return checkSol(solution.toList) //that is it!
      var pif = iter(p_iter) //pos in fields
      val lastUF = last() //last unfixed
      val (row,col) = fp2m(pif)
      possiArray(p_iter) = fpv4s(pif).toList.sortWith(_<_)

      while(pif <= lastUF) {
        val (row,col) = fp2m(pif)
        if (possiArray(p_iter) == null) possiArray(p_iter) = fpv4s(pif).toList.sortWith(_<_)
        val possis = possiArray(p_iter)
        if (possis.isEmpty) {
          if (hasPrev()) {
            possiArray(p_iter) = null
            solution(pif) = 0
            pif = prev()
          } else {
            return Nil
          }
        } else {
          solution(pif) = possis(0)
          possiArray(p_iter) = (possis.toSet - possis(0)).toList.sortWith(_<_)
          if (hasNext()) {
            pif = next()
          } else {
            return checkSol(solution.toList)
          }
        }
      }
      checkSol(solution.toList)
    }
  }

  val f2Str: List[Int] => String = fields => {
    val sepLine = "+---+---+---+"
    val sepPoints = Set(2,5,8)
    val fs: (Int, Int) => String = (i, v) => v.toString.replace("0"," ")+(if (sepPoints.contains(i%9)) "|" else "")
    sepLine+"\n"+(0 to fields.size-1).map(i => (if (i%9==0) "|" else "")+fs(i,fields(i))+(if (i%9==8) if (sepPoints.contains(i/9)) "\n"+sepLine+"\n" else "\n" else "")).foldRight("")(_+_)
  }

  val solver = new Solver()

  val riddle = List(3,9,4,0,0,2,6,7,0,
                    0,0,0,3,0,0,4,0,0,
                    5,0,0,6,9,0,0,2,0,
                    0,4,5,0,0,0,9,0,0,
                    6,0,0,0,0,0,0,0,7,
                    0,0,7,0,0,0,5,8,0,
                    0,1,0,0,6,7,0,0,8,
                    0,0,9,0,0,8,0,0,0,
                    0,2,6,4,0,0,7,3,5)

  println("riddle:")
  println(f2Str(riddle))
  var solution = solver.solve(riddle)

  println("solution:")
  println(solution match {case Nil => "no solution!!!" case _ => f2Str(solution)})

}


// version 1.2.0

val board = "ET AON RISBCDFGHJKLMPQ/UVWXYZ."
val digits = "0123456789"
val rows = " 26"
val escape = "62"
val key = "0452"

fun encrypt(message: String): String {
    val msg = message.toUpperCase()
                     .filter { (it in board || it in digits) && it !in " /" }
    val sb = StringBuilder()
    for (c in msg) {
        val idx = board.indexOf(c)
        if (idx > -1) {
            val row = idx / 10
            val col = idx % 10
            sb.append(if (row == 0) "$col" else "${rows[row]}$col")
        }
        else {
            sb.append("$escape$c")
        }
    }
    val enc = sb.toString().toCharArray()
    for ((i, c) in enc.withIndex()) {
        val k = key[i % 4] - '0'
        if (k == 0) continue
        val j = c - '0'
        enc[i] = '0' + ((j + k) % 10)
    }
    return String(enc)
}

fun decrypt(encoded: String): String {
    val enc = encoded.toCharArray()
    for ((i, c) in enc.withIndex()) {
        val k = key[i % 4] - '0'
        if (k == 0) continue
        val j = c - '0'
        enc[i] = '0' + if (j >= k) (j - k) % 10 else (10 + j - k) % 10
    }
    val len = enc.size
    val sb = StringBuilder()
    var i = 0
    while (i < len) {
        val c = enc[i]
        val idx = rows.indexOf(c)
        if (idx == -1) {
            val idx2 = c - '0'
            sb.append(board[idx2])
            i++
        }
        else if ("$c${enc[i + 1]}" == escape) {
            sb.append(enc[i + 2])
            i += 3
        }
        else {
            val idx2 = idx * 10 + (enc[i + 1] - '0')
            sb.append(board[idx2])
            i += 2
        }
    }
    return sb.toString()
}

fun main(args: Array<String>) {
    val messages = listOf(
        "Attack at dawn",
        "One night-it was on the twentieth of March, 1888-I was returning",
        "In the winter 1965/we were hungry/just barely alive",
        "you have put on 7.5 pounds since I saw you.",
        "The checkerboard cake recipe specifies 3 large eggs and 2.25 cups of flour."
    )
    for (message in messages) {
        val encrypted = encrypt(message)
        val decrypted = decrypt(encrypted)
        println("\nMessage   : $message")
        println("Encrypted : $encrypted")
        println("Decrypted : $decrypted")
    }
}


Init_board=[...
5 3 0 0 7 0 0 0 0;...
6 0 0 1 9 5 0 0 0;...
0 9 8 0 0 0 0 6 0;...
8 0 0 0 6 0 0 0 3;...
4 0 0 8 0 3 0 0 1;...
7 0 0 0 2 0 0 0 6;...
0 6 0 0 0 0 2 8 0;...
0 0 0 4 1 9 0 0 5;...
0 0 0 0 8 0 0 7 9];

break_point=1.0d5; //if 0 there will be no break

function []=disp_board(board)
    StringBoard=string(board);
    for i=1:9
        for j=1:9
            if board(i,j)==0 then
                StringBoard(i,j)='×';
            end
        end
    end

    StringBoard=[StringBoard, string(zeros(9,2))];
    StringBoard=[StringBoard; string(zeros(2,11))];

    for i=1:9
        StringBoard(i,:)=[StringBoard(i,1:3), '|', StringBoard(i,4:6), '|', StringBoard(i,7:9)]
    end
    StringBoard(9:11,:)=StringBoard(7:9,:);
    StringBoard(8,:)=strsplit('-----------');
    StringBoard(5:7,:)=StringBoard(4:6,:);
    StringBoard(4,:)=strsplit('-----------');

    disp(StringBoard)
endfunction

function varargout=validate_input(input,position,board)
    row=board(position(1),:);
    column=board(:,position(2));
    block=zeros(3,3);
    if position(1)>=1 & position(1)<=3 then
        i=0;
    elseif position(1)>=4 & position(1)<=6 then
        i=3;
    else
        i=6;
    end
    if position(2)>=1 & position(2)<=3 then
        j=0;
    elseif position(2)>=4 & position(2)<=6 then
        j=3;
    else
        j=6;
    end
    block=board(i+1:i+3,j+1:j+3)

    valid_input=%F;
    valid_row=%F;
    valid_col=%F;
    valid_block=%F;

    if find(input==row)==[] then
        valid_row=%T;
    end
    if find(input==column)==[] then
        valid_col=%T;
    end
    if find(input==block)==[] then
        valid_block=%T;
    end
    if valid_row & valid_col & valid_block then
        valid_input=%T;
    end

    varargout=list(valid_input,valid_row,valid_col,valid_block)
endfunction

function varargout=validate_board(board)
    valid_flag1=%T;
    for i=1:9
        for j=1:9
            if board(i,j)~= 0 then
                check_board=Init_board;
                check_board(i,j)=0;
                valid_flag1=validate_input(board(i,j),[i j],check_board);
                if ~valid_flag1 then
                    break
                end
            end
        end
        if ~valid_flag1 then
            break
        end
    end

    valid_flag2 = (length( find(board) ) >= 17); //enforces rule of minimum of 17 givens
                                                 //set it to always %T to ignore this rule
    valid_board = (valid_flag1 & valid_flag2);

    varargout=list(valid_board)
endfunction

disp('Initial board:');
disp_board(Init_board);

valid_init_board=validate_board(Init_board);

if ~valid_init_board then
    error('Invalid initial board. Should follow sudoku rules and have at least 17 clues.');
end

blank=[];
for i=1:9
    for j=1:9
        if Init_board(i,j)== 0 then
            blank=[blank; i j];
        end
    end
end

Solved_board=Init_board;

tic();
i=0; counter=0; breaked=%F;
while i<size(blank,'r')
    i=i+1;
    counter=counter+1;
    pos=blank(i,:);

    value=Solved_board(pos(1),pos(2));

    valid_value=%F;

    while valid_value==%F
        value=value+1;
        if value>=10
            break
        else
            valid_value=validate_input(value,pos,Solved_board);
        end
    end

    if valid_value & value<10 then
        Solved_board(pos(1),pos(2))=value
    else
        Solved_board(pos(1),pos(2))=0;
        i=i-2;
    end

    if counter==break_point
        breaked=%T;
        break
    end
end

valid_solved_board=validate_board(Solved_board);
t2=toc();

if valid_solved_board & ~breaked then
    disp('Solved!');
    disp('Solution:');
    disp_board(Solved_board);
    disp('Time: '+string(t2)+'s.');
    disp('Steps: '+string(counter)+'.');
elseif breaked
    disp('Break point reached.');
    disp('Time: '+string(t2)+'s.');
    disp_board(Solved_board);
elseif ~valid_solved_board & ~breaked
    disp('Invalid solution found.');
    disp_board(Solved_board);
end


local brd = { "HOL MES RT", "ABCDFGIJKN", "PQUVWXYZ./" }
local dicE, dicD, s1, s2 = {}, {}, 0, 0

function dec( txt )
    local i, numb, s, t, c = 1, false
    while( i < #txt ) do
        c = txt:sub( i, i )
        if not numb then
            if tonumber( c ) == s1 then
                i = i + 1; s = string.format( "%d%s", s1, txt:sub( i, i ) )
                t = dicD[s]
            elseif tonumber( c ) == s2 then
                i = i + 1; s = string.format( "%d%s", s2, txt:sub( i, i ) )
                t = dicD[s]
            else
                t = dicD[c]
            end
            if t == "/" then
                numb = true
            else
                io.write( t )
            end
        else
            io.write( c )
            numb = false
        end
        i = i + 1
    end
    print()
end
function enc( txt )
    local c
    for i = 1, #txt do
        c = txt:sub( i, i )
        if c >= "A" and c <= "Z" then
            io.write( dicE[c] )
        elseif c >= "0" and c <= "9" then
            io.write( string.format( "%s%s", dicE["/"], c ) )
        end
    end
    print()
end
function createDictionaries()
    for i = 1, 10 do
        c = brd[1]:sub( i, i )
        if c == " " then
            if s1 == 0 then s1 = i - 1
            elseif s2 == 0 then s2 = i - 1 end
        else
            dicE[c] = string.format( "%d", i - 1 )
            dicD[string.format( "%d", i - 1 )] = c
        end
    end
    for i = 1, 10 do
        dicE[brd[2]:sub( i, i )] = string.format( "%d%d", s1, i - 1 )
        dicE[brd[3]:sub( i, i )] = string.format( "%d%d", s2, i - 1 )
        dicD[string.format( "%d%d", s1, i - 1 )] = brd[2]:sub( i, i )
        dicD[string.format( "%d%d", s2, i - 1 )] = brd[3]:sub( i, i )
    end
end
function enterText()
    createDictionaries()
    io.write( "\nEncrypt or Decrypt (E/D)? " )
    d = io.read()
    io.write( "\nEnter the text:\n" )
    txt = io.read():upper()
    if d == "E" or d == "e" then enc( txt )
    elseif d == "D" or d == "d" then dec( txt )
    end
end
-- entry point
enterText()


func check(i, j) is cached {
    var (id, im) = i.divmod(9)
    var (jd, jm) = j.divmod(9)

    jd == id && return true
    jm == im && return true

    (id//3 == jd//3) &&
    (jm//3 == im//3)
}

func solve(grid) {
    for i in ^grid {
        grid[i] && next
        var t = [grid[{|j| check(i, j) }.grep(^grid)]].freq

        { |k|
            t.has_key(k) && next
            grid[i] = k
            solve(grid)
        } << 1..9

        grid[i] = 0
        return nil
    }

    for i in ^grid {
        print "#{grid[i]} "
        print " "  if (3  -> divides(i+1))
        print "\n" if (9  -> divides(i+1))
        print "\n" if (27 -> divides(i+1))
    }
}

var grid = %i(
    5 3 0  0 2 4  7 0 0
    0 0 2  0 0 0  8 0 0
    1 0 0  7 0 3  9 0 2

    0 0 8  0 7 2  0 4 9
    0 2 0  9 8 0  0 7 0
    7 9 0  0 0 0  0 8 0

    0 0 0  0 3 0  5 0 6
    9 6 0  0 1 0  3 0 0
    0 5 0  6 9 0  0 1 0
)

solve(grid)


module Straddling_checkerboard {
	function encrypt$(message$, alphabet) {
		message$=filter$(ucase$(message$),"-/,. ")
		def num1, num2
		num1=instr(alphabet#val$(0)," ")
		num2=instr(alphabet#val$(0)," ", num1+1)-1
		num1--
		escapenum=instr(alphabet#val$(2),"/")-1
		escapenum1=instr(alphabet#val$(2),".")-1
		num0=-10
		num10=num1*10-20
		num20=num2*10-30
		numbers=(escapenum+num2*10)*10
		numbers1=(escapenum1+num2*10)*10
		boardrow=each(alphabet)
		cipherkey$="0123456789" :	while boardrow :cipherkey$+=array$(boardrow) :end while
		encoded$=""
		for i=1 to len(message$)
			n=instr(cipherkey$, mid$(message$,i,1))-1
			if n<10 then
				n+=if(random(10)<5->numbers, numbers1)
			else.if n<20 then
				n+=num0
			else.if n<30 then
				n+=num10
			else
				n+=num20
			end if
			encoded$+=str$(n,"")
		next
		=encoded$
	}
	function decrypt$(encoded$, alphabet) {
		def num1, num2
		num1=instr(alphabet#val$(0)," ")
		num2=instr(alphabet#val$(0)," ", num1+1)-1
		num1--
		escapenum=instr(alphabet#val$(2),"/")-1
		escapenum1=instr(alphabet#val$(2),".")-1
		def i=1, decoded$
		j=len(encoded$)+1
		while i<j
		m=val(mid$(encoded$,i,1))
		if m=num1 then
			decoded$+=mid$(alphabet#val$(1), val(mid$(encoded$,i+1,1))+1,1)
			i++
		else.if m=num2 then
			if i+1<j then
				mm=val(mid$(encoded$,i+1,1))
				if mm=escapenum or mm=escapenum1 then
					decoded$+=mid$(encoded$,i+2,1)
					i+=2
				else
					decoded$+=mid$(alphabet#val$(2), val(mid$(encoded$,i+1,1))+1,1)
					i++
				end if
			else
				decoded$+=mid$(alphabet#val$(2), val(mid$(encoded$,i+1,1))+1,1)
				i++
			end if
		else
			decoded$+=mid$(alphabet#val$(0), m+1,1)
		end if
		i++
		end while
		=decoded$
	}
	Module DisplayBoard (alphabet, &Doc$){
		num1=instr(alphabet#val$(0)," ")
		num2=instr(alphabet#val$(0)," ", num1+1)-1
		num1--
		escapenum=instr(alphabet#val$(2),"/")-1
		escapenum1=instr(alphabet#val$(2),".")-1
		\\ display straddling checkerboard
		checkerboard =cons(("0123456789",),alphabet)
		labels=(" "," ",str$(num1,""), str$(num2,""))
		disp=each(checkerboard)
		while disp
			Doc$=labels#val$(disp^)+" "+array$(disp)+{
			}
		end while
	}
	Document Doc$
	Const nl$={
	}
	Function OnePad$(Message$, PadSerial, n=1) {
		x=random(!PadSerial)  ' push old seed, set the new one
		encoded$=""
		for i=1 to len(Message$)
		encoded$+=str$((val(mid$(Message$,i,1))+10+n*random(1, 10))mod 10,"")
		next i
		x=random(!) ' restore old seed
		=encoded$
	}
	\\ select a random alphabet
	select case random(1,3)
	case 1
	alphabet=("ESTONIAR  ","BCDFGHJKLM","/PQUVWXYZ.") : Doc$="First "+nl$
	case 2
	alphabet=("ET AON RIS","BCDFGHJKLM","PQ/UVWXYZ.") : Doc$="Second"+nl$
	case 3
	alphabet=("ESTONIAR  ","BCDFGHJKLM","PQU.VWXYZ/") : Doc$="Third"+nl$
	end select
	DisplayBoard alphabet, &Doc$
	msg$="One night-it was on the twentieth of March, 1888-I was returning"
	Doc$= "original message:"+nl$
	Doc$= msg$+nl$
	Doc$= "encrypted message:"+nl$
	crypt$=encrypt$(msg$, alphabet)
	Doc$=crypt$+nl$
	serial=random(1234567,9345678)
	Doc$= "encrypted message using one pad using serial:"+str$(serial)+nl$
	crypt$=OnePad$(crypt$, serial)
	Doc$=crypt$+nl$
	Doc$= "decrypted message using one pad:"+nl$
	crypt$=OnePad$(crypt$, serial,-1)
	Doc$=crypt$+nl$
	Doc$= "decrypted message:"+nl$
	Doc$=decrypt$(crypt$, alphabet)
	Print #-2, Doc$  ' render to console using new lines codes from Doc$
	Clipboard Doc$
}
Straddling_checkerboard


import strutils, tables

const
  FullStop = '.'
  Escape = '/'

type Checkerboard = object
  encryptTable: Table[char, string]
  decryptTable: Table[string, char]

proc initCheckerboard(digits: string; row1, row2, row3: string): Checkerboard =
  ## Initialize a checkerboard with given digits in row 0 and the following given rows.
  ## No sanity check is performed.

  var rowChars: seq[char]   # The two characters to use to identify rows 2 and 3.

  # Process row 1.
  for col, ch in row1:
    if ch == ' ':
      rowChars.add digits[col]
    else:
      result.encryptTable[ch] = $digits[col]
  if rowChars.len != 2:
    raise newException(ValueError, "expected two blank spots in first letter row.")

  # Add rows 2 and 3.
  for col, ch in row2:
    result.encryptTable[ch] = rowChars[0] & digits[col]
  for col, ch in row3:
    result.encryptTable[ch] = rowChars[1] & digits[col]
  if Escape notin result.encryptTable:
    raise newException(ValueError, "missing Escape character.")

  # Build decrypt table from encrypt table.
  for c, s in result.encryptTable.pairs:
    result.decryptTable[s] = c

proc encrypt(board: Checkerboard; message: string): string =
  ## Encrypt a string.

  let message = message.toUpperAscii
  for ch in message:
    case ch
    of 'A'..'Z', FullStop, Escape:
      result.add board.encryptTable[ch]
    of '0'..'9':
      result.add board.encryptTable[Escape]
      result.add ch
    else:
      discard   # Ignore other characters.

proc raiseError() =
  ## Raise a ValueError to signal a corrupt message.
  raise newException(ValueError, "corrupt message")

proc decrypt(board: Checkerboard; message: string): string =
  ## Decrypt a message.

  var escaped = false   # Escape char previously encountered.
  var str = ""          # Current sequence of characters (contains 0, 1 or 2 chars).

  for ch in message:
    if ch notin '0'..'9': raiseError()

    if escaped:
      # Digit is kept as is.
      result.add ch
      escaped = false
    else:
      # Try to decrypt this new digit.
      str.add ch
      if str in board.decryptTable:
        let c = board.decryptTable[str]
        if c == Escape: escaped = true
        else: result.add c
        str.setLen(0)
      elif str.len == 2:
        # Illegal combination of two digits.
        raiseError()

when isMainModule:
  let board = initCheckerboard("8752390146", "ET AON RIS", "BC/FGHJKLM", "PQD.VWXYZU")
  let message = "you have put on 7.5 pounds since I saw you."
  echo "Message: ", message
  let crypted = board.encrypt(message)
  echo "Crypted: ", crypted
  echo "Decrypted: ", board.decrypt(crypted)


use strict;
use warnings;
use feature 'say';
use List::Util <min max>;

my(%encode,%decode,@table);

sub build {
    my($u,$v,$alphabet) = @_;
    my(@flat_board,%p2c,%c2p);
    my $numeric_escape = '/';

    @flat_board = split '', uc $alphabet;
    splice @flat_board, min($u,$v), 0, undef;
    splice @flat_board, max($u,$v), 0, undef;

    push @table, [' ', 0..9];
    push @table, [' ', map { defined $_ ? $_ : ' '} @flat_board[ 0 ..  9] ];
    push @table, [$u,  @flat_board[10 .. 19]];
    push @table, [$v,  @flat_board[20 .. 29]];

    my @nums = my @order = 0..9;
    push @nums, (map { +"$u$_" } @order), map { +"$v$_" } @order;

    @c2p{@nums} = @flat_board;
    for (keys %c2p) { delete $c2p{$_} unless defined $c2p{$_} }
    @p2c{values %c2p} = keys %c2p;
    $p2c{$_} = $p2c{$numeric_escape} . $_ for 0..9;
    while (my ($k, $v) = each %p2c) {
        $encode{$k} = $v;
        $decode{$v} = $k unless $k eq $numeric_escape;
    }
}

sub decode {
    my($string) = @_;
    my $keys = join '|', keys %decode;
    $string =~ s/($keys)/$decode{$1}/gr;
}

sub encode {
    my($string) = uc shift;
    $string =~ s#(.)#$encode{$1} // $encode{'.'}#ger;
}

my $sc = build(3, 7, 'HOLMESRTABCDFGIJKNPQUVWXYZ./');
say join  ' ', @$_ for @table;
say '';
say 'Original: ', my $original = 'One night-it was on the twentieth of March, 1888-I was returning';
say 'Encoded:  ', my $en = encode($original);
say 'Decoded:  ', decode($en);