texlive[67175] Master: context-sudoku (20may23)

commits+karl at tug.org commits+karl at tug.org
Sat May 20 22:23:06 CEST 2023


Revision: 67175
          http://tug.org/svn/texlive?view=revision&revision=67175
Author:   karl
Date:     2023-05-20 22:23:06 +0200 (Sat, 20 May 2023)
Log Message:
-----------
context-sudoku (20may23)

Modified Paths:
--------------
    trunk/Master/tlpkg/tlpsrc/collection-context.tlpsrc

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/context/third/sudoku/
    trunk/Master/texmf-dist/doc/context/third/sudoku/LICENSE
    trunk/Master/texmf-dist/doc/context/third/sudoku/README.md
    trunk/Master/texmf-dist/doc/context/third/sudoku/VERSION
    trunk/Master/texmf-dist/tex/context/third/sudoku/
    trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-01.txt
    trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-02.txt
    trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-03.txt
    trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku.lua
    trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku.mkvi
    trunk/Master/tlpkg/tlpsrc/context-sudoku.tlpsrc

Added: trunk/Master/texmf-dist/doc/context/third/sudoku/LICENSE
===================================================================
--- trunk/Master/texmf-dist/doc/context/third/sudoku/LICENSE	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/context/third/sudoku/LICENSE	2023-05-20 20:23:06 UTC (rev 67175)
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021-2023 Jairo A. del Rio
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

Added: trunk/Master/texmf-dist/doc/context/third/sudoku/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/context/third/sudoku/README.md	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/context/third/sudoku/README.md	2023-05-20 20:23:06 UTC (rev 67175)
@@ -0,0 +1,40 @@
+# sudoku
+
+This is a ConTeXt port of a famous sudoku solver by Peter Norvig. It
+provides four commands, as well as a command handler:
+
+1. `\sudoku` typesets a sudoku if valid.
+2. `\sudokufile` typesets a sudoku from a file if valid.
+3. `\solvesudoku` solves a sudoku if valid.
+3. `\solvesudokufile` solves a sudoku from a file if valid.
+5. `\setupsudoku` is the command handler for commands above.
+
+`\setupsudoku` understands the following parameters:
+
+```tex
+\setupsudoku
+    [size=2em,
+     align={middle,lohi},
+     evenbackground=color,
+     oddbackground=color,
+     evenbackgroundcolor=darkred,
+     oddbackgroundcolor=darkblue]
+```
+
+As you might notice, sudokus are just `TABLE`'s in disguise, but only
+certain parameters are passed in order to enforce constraints and keep
+a sudoku in square shape.
+
+If an invalid sudoku or sudoku file is provided, a placeholder with an
+error message is printed instead. To change message errors, set
+something like this:
+
+```tex
+\setupsudoku
+    [placeholdercommand=\inframed,
+     placeholderlabela=First error,
+     placeholderlabelb=Second error,
+     placeholderlabelc=Third error]
+```
+
+For actual examples, check `t-sudoku.mkvi`.


Property changes on: trunk/Master/texmf-dist/doc/context/third/sudoku/README.md
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/context/third/sudoku/VERSION
===================================================================
--- trunk/Master/texmf-dist/doc/context/third/sudoku/VERSION	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/context/third/sudoku/VERSION	2023-05-20 20:23:06 UTC (rev 67175)
@@ -0,0 +1 @@
+2023-05-15

Added: trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-01.txt
===================================================================
--- trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-01.txt	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-01.txt	2023-05-20 20:23:06 UTC (rev 67175)
@@ -0,0 +1,9 @@
+003  010  008
+000  400  030 
+870  003  020 
+010  009  605 
+300  867  002
+906  500  040 
+020  900  074 
+090  006  000 
+500  070  100 
\ No newline at end of file


Property changes on: trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-01.txt
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-02.txt
===================================================================
--- trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-02.txt	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-02.txt	2023-05-20 20:23:06 UTC (rev 67175)
@@ -0,0 +1,9 @@
+000 000 620
+106 230 040
+900 600 001
+200 400 803
+090 000 010
+708 009 004
+600 005 008
+020 048 905
+045 000 000


Property changes on: trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-02.txt
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-03.txt
===================================================================
--- trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-03.txt	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-03.txt	2023-05-20 20:23:06 UTC (rev 67175)
@@ -0,0 +1,9 @@
+043080250
+600000000
+000001094
+900004070
+000608000
+010200003
+820500000
+000000005
+034090710


Property changes on: trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku-test-03.txt
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku.lua
===================================================================
--- trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku.lua	2023-05-20 20:23:06 UTC (rev 67175)
@@ -0,0 +1,1237 @@
+if not modules then modules = { } end modules ['t-sudoku'] = 
+{
+  version   = "2023-05-15",
+  comment   = "Sudokus for ConTeXt",
+  author    = "Jairo A. del Rio",
+  copyright = "Jairo A. del Rio",
+  license   = "MIT License"
+}
+
+-- Sources:
+
+-- https://norvig.com/sudoku.html
+-- https://naokishibuya.medium.com/peter-norvigs-sudoku-solver-25779bb349ce
+-- https://gist.github.com/neilalbrock/894520
+
+local table, math, io = table, math, io
+local ipairs, pairs, tostring = ipairs, pairs, tostring
+
+local floor, ceil = math.floor, math.ceil
+local insert, concat, sort = table.insert, table.concat, table.sort
+
+-- ConTeXt goodies
+
+local context    = context       
+local interfaces = interfaces
+local implement  = interfaces.implement
+
+-- Take a look for definitions
+-- https://source.contextgarden.net/tex/context/base/mkiv/l-table.lua
+-- https://source.contextgarden.net/tex/context/base/mkiv/l-io.lua
+
+local contains, copy, unique = table.contains, table.copy, table.unique
+
+local loaddata   = io.loaddata
+
+local rows     = {"A", "B", "C", "D", "E", "F", "G", "H", "I"}
+local columns  = {"1", "2", "3", "4", "5", "6", "7", "8", "9"}
+
+local rowsquare =
+{
+  {"A", "B", "C"}, {"D", "E", "F"}, {"G", "H", "I"}
+}
+
+local columnsquare = 
+{
+  {"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}
+}
+
+local digits   = '123456789'
+
+-- Helper functions 
+-- F#ck Python
+
+local shuffle, string_to_table
+
+shuffle = function(t)
+  for i = #t, 2, -1 do
+    local j = random(i)
+    t[i], t[j] = t[j], t[i]
+  end
+  return t
+end
+
+string_to_table = function(s)
+  local result = {}
+  s = s:gsub("[.%d]", function(x)
+    insert(result, x == "." and x or tostring(floor(x)))
+  end)
+  return result 
+end
+
+-- Data
+
+local squares, units 
+
+squares = 
+{
+  "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9",
+  "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9",
+  "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9",
+  "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9",
+  "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9",
+  "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9",
+  "G1", "G2", "G3", "G4", "G5", "G6", "G7", "G8", "G9",
+  "H1", "H2", "H3", "H4", "H5", "H6", "H7", "H8", "H9",
+  "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9"
+}
+
+units =
+{
+  ['A1'] = 
+  {
+    {'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1'},
+    {'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'},
+    {'A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3'}
+  },
+  ['A2'] = 
+  {
+    {'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'},
+    {'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'},
+    {'A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3'}
+  },
+  ['A3'] = 
+  {
+    {'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3'},
+    {'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'},
+    {'A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3'}
+  },
+  ['A4'] = 
+  {
+    {'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4'},
+    {'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'},
+    {'A4', 'A5', 'A6', 'B4', 'B5', 'B6', 'C4', 'C5', 'C6'}
+  },
+  ['A5'] = {
+    {'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5'},
+    {'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'},
+    {'A4', 'A5', 'A6', 'B4', 'B5', 'B6', 'C4', 'C5', 'C6'}
+  }, 
+  ['A6'] = 
+  {
+    {'A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', 'I6'},
+    {'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'},
+    {'A4', 'A5', 'A6', 'B4', 'B5', 'B6', 'C4', 'C5', 'C6'}
+  },
+  ['A7'] = {
+    {'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', 'I7'},
+    {'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'},
+    {'A7', 'A8', 'A9', 'B7', 'B8', 'B9', 'C7', 'C8', 'C9'}
+  },
+  ['A8'] = 
+  {
+    {'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', 'I8'},
+    {'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'},
+    {'A7', 'A8', 'A9', 'B7', 'B8', 'B9', 'C7', 'C8', 'C9'}
+  },
+  ['A9'] = 
+  {
+    {'A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', 'I9'},
+    {'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'},
+    {'A7', 'A8', 'A9', 'B7', 'B8', 'B9', 'C7', 'C8', 'C9'}
+  }, 
+  ['B1'] = 
+  {
+    {'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1'},
+    {'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9'},
+    {'A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3'}
+  },
+  ['B2'] = 
+  {
+    {'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'},
+    {'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9'},
+    {'A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3'}
+  },
+  ['B3'] = 
+  {
+    {'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3'},
+    {'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9'},
+    {'A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3'}
+  },
+  ['B4'] =
+  {
+    {'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4'},
+    {'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9'},
+    {'A4', 'A5', 'A6', 'B4', 'B5', 'B6', 'C4', 'C5', 'C6'}
+  },
+  ['B5'] = 
+  {
+    {'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5'},
+    {'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9'},
+    {'A4', 'A5', 'A6', 'B4', 'B5', 'B6', 'C4', 'C5', 'C6'}
+  },
+  ['B6'] = 
+  {
+    {'A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', 'I6'},
+    {'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9'},
+    {'A4', 'A5', 'A6', 'B4', 'B5', 'B6', 'C4', 'C5', 'C6'}
+  },
+  ['B7'] =
+  {
+    {'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', 'I7'},
+    {'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9'},
+    {'A7', 'A8', 'A9', 'B7', 'B8', 'B9', 'C7', 'C8', 'C9'}
+  },
+  ['B8'] =
+  {
+    {'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', 'I8'},
+    {'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9'},
+    {'A7', 'A8', 'A9', 'B7', 'B8', 'B9', 'C7', 'C8', 'C9'}
+  },
+  ['B9'] =
+  {
+    {'A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', 'I9'},
+    {'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9'},
+    {'A7', 'A8', 'A9', 'B7', 'B8', 'B9', 'C7', 'C8', 'C9'}
+  },
+  ['C1'] =
+  {
+    {'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1'},
+    {'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'},
+    {'A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3'}
+  },
+  ['C2'] =
+  {
+    {'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'},
+    {'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'},
+    {'A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3'}
+  },
+  ['C3'] =
+  {
+    {'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3'},
+    {'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'},
+    {'A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3'}
+  },
+  ['C4'] =
+  {
+    {'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4'},
+    {'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'},
+    {'A4', 'A5', 'A6', 'B4', 'B5', 'B6', 'C4', 'C5', 'C6'}
+  },
+  ['C5'] =
+  {
+    {'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5'},
+    {'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'},
+    {'A4', 'A5', 'A6', 'B4', 'B5', 'B6', 'C4', 'C5', 'C6'}
+  },
+  ['C6'] =
+  {
+    {'A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', 'I6'},
+    {'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'},
+    {'A4', 'A5', 'A6', 'B4', 'B5', 'B6', 'C4', 'C5', 'C6'}
+  },
+  ['C7'] =
+  {
+    {'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', 'I7'},
+    {'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'},
+    {'A7', 'A8', 'A9', 'B7', 'B8', 'B9', 'C7', 'C8', 'C9'}
+  },
+  ['C8'] =
+  {
+    {'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', 'I8'},
+    {'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'},
+    {'A7', 'A8', 'A9', 'B7', 'B8', 'B9', 'C7', 'C8', 'C9'}
+  },
+  ['C9'] =
+  {
+    {'A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', 'I9'},
+    {'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'},
+    {'A7', 'A8', 'A9', 'B7', 'B8', 'B9', 'C7', 'C8', 'C9'}
+  },
+  ['D1'] =
+  {
+    {'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1'},
+    {'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9'},
+    {'D1', 'D2', 'D3', 'E1', 'E2', 'E3', 'F1', 'F2', 'F3'}
+  },
+  ['D2'] =
+  {
+    {'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'},
+    {'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9'},
+    {'D1', 'D2', 'D3', 'E1', 'E2', 'E3', 'F1', 'F2', 'F3'}
+  },
+  ['D3'] =
+  {
+    {'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3'},
+    {'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9'},
+    {'D1', 'D2', 'D3', 'E1', 'E2', 'E3', 'F1', 'F2', 'F3'}
+  },
+  ['D4'] =
+  {
+    {'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4'},
+    {'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9'},
+    {'D4', 'D5', 'D6', 'E4', 'E5', 'E6', 'F4', 'F5', 'F6'}
+  },
+  ['D5'] =
+  {
+    {'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5'},
+    {'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9'},
+    {'D4', 'D5', 'D6', 'E4', 'E5', 'E6', 'F4', 'F5', 'F6'}
+  },
+  ['D6'] =
+  {
+    {'A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', 'I6'},
+    {'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9'},
+    {'D4', 'D5', 'D6', 'E4', 'E5', 'E6', 'F4', 'F5', 'F6'}
+  },
+  ['D7'] =
+  {
+    {'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', 'I7'},
+    {'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9'},
+    {'D7', 'D8', 'D9', 'E7', 'E8', 'E9', 'F7', 'F8', 'F9'}
+  },
+  ['D8'] =
+  {
+    {'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', 'I8'},
+    {'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9'},
+    {'D7', 'D8', 'D9', 'E7', 'E8', 'E9', 'F7', 'F8', 'F9'}
+  },
+  ['D9'] =
+  {
+    {'A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', 'I9'},
+    {'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9'},
+    {'D7', 'D8', 'D9', 'E7', 'E8', 'E9', 'F7', 'F8', 'F9'}
+  },
+  ['E1'] =
+  {
+    {'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1'},
+    {'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9'},
+    {'D1', 'D2', 'D3', 'E1', 'E2', 'E3', 'F1', 'F2', 'F3'}
+  },
+  ['E2'] =
+  {
+    {'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'},
+    {'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9'},
+    {'D1', 'D2', 'D3', 'E1', 'E2', 'E3', 'F1', 'F2', 'F3'}
+  },
+  ['E3'] =
+  {
+    {'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3'},
+    {'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9'},
+    {'D1', 'D2', 'D3', 'E1', 'E2', 'E3', 'F1', 'F2', 'F3'}
+  },
+  ['E4'] =
+  {
+    {'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4'},
+    {'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9'},
+    {'D4', 'D5', 'D6', 'E4', 'E5', 'E6', 'F4', 'F5', 'F6'}
+  },
+  ['E5'] =
+  {
+    {'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5'},
+    {'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9'},
+    {'D4', 'D5', 'D6', 'E4', 'E5', 'E6', 'F4', 'F5', 'F6'}
+  },
+  ['E6'] =
+  {
+    {'A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', 'I6'},
+    {'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9'},
+    {'D4', 'D5', 'D6', 'E4', 'E5', 'E6', 'F4', 'F5', 'F6'}
+  },
+  ['E7'] =
+  {
+    {'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', 'I7'},
+    {'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9'},
+    {'D7', 'D8', 'D9', 'E7', 'E8', 'E9', 'F7', 'F8', 'F9'}
+  },
+  ['E8'] =
+  {
+    {'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', 'I8'},
+    {'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9'},
+    {'D7', 'D8', 'D9', 'E7', 'E8', 'E9', 'F7', 'F8', 'F9'}
+  },
+  ['E9'] =
+  {
+    {'A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', 'I9'},
+    {'E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9'},
+    {'D7', 'D8', 'D9', 'E7', 'E8', 'E9', 'F7', 'F8', 'F9'}
+  },
+  ['F1'] =
+  {
+    {'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1'},
+    {'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9'},
+    {'D1', 'D2', 'D3', 'E1', 'E2', 'E3', 'F1', 'F2', 'F3'}
+  },
+  ['F2'] =
+  {
+    {'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'},
+    {'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9'},
+    {'D1', 'D2', 'D3', 'E1', 'E2', 'E3', 'F1', 'F2', 'F3'}
+  },
+  ['F3'] =
+  {
+    {'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3'},
+    {'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9'},
+    {'D1', 'D2', 'D3', 'E1', 'E2', 'E3', 'F1', 'F2', 'F3'}
+  },
+  ['F4'] =
+  {
+    {'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4'},
+    {'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9'},
+    {'D4', 'D5', 'D6', 'E4', 'E5', 'E6', 'F4', 'F5', 'F6'}
+  },
+  ['F5'] =
+  {
+    {'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5'},
+    {'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9'},
+    {'D4', 'D5', 'D6', 'E4', 'E5', 'E6', 'F4', 'F5', 'F6'}
+  },
+  ['F6'] =
+  {
+    {'A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', 'I6'},
+    {'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9'},
+    {'D4', 'D5', 'D6', 'E4', 'E5', 'E6', 'F4', 'F5', 'F6'}
+  },
+  ['F7'] =
+  {
+    {'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', 'I7'},
+    {'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9'},
+    {'D7', 'D8', 'D9', 'E7', 'E8', 'E9', 'F7', 'F8', 'F9'}
+  },
+  ['F8'] =
+  {
+    {'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', 'I8'},
+    {'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9'},
+    {'D7', 'D8', 'D9', 'E7', 'E8', 'E9', 'F7', 'F8', 'F9'}
+  },
+  ['F9'] =
+  {
+    {'A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', 'I9'},
+    {'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9'},
+    {'D7', 'D8', 'D9', 'E7', 'E8', 'E9', 'F7', 'F8', 'F9'}
+  },
+  ['G1'] =
+  {
+    {'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1'},
+    {'G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7', 'G8', 'G9'},
+    {'G1', 'G2', 'G3', 'H1', 'H2', 'H3', 'I1', 'I2', 'I3'}
+  },
+  ['G2'] =
+  {
+    {'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'},
+    {'G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7', 'G8', 'G9'},
+    {'G1', 'G2', 'G3', 'H1', 'H2', 'H3', 'I1', 'I2', 'I3'}
+  },
+  ['G3'] =
+  {
+    {'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3'},
+    {'G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7', 'G8', 'G9'},
+    {'G1', 'G2', 'G3', 'H1', 'H2', 'H3', 'I1', 'I2', 'I3'}
+  },
+  ['G4'] =
+  {
+    {'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4'},
+    {'G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7', 'G8', 'G9'},
+    {'G4', 'G5', 'G6', 'H4', 'H5', 'H6', 'I4', 'I5', 'I6'}
+  },
+  ['G5'] =
+  {
+    {'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5'},
+    {'G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7', 'G8', 'G9'},
+    {'G4', 'G5', 'G6', 'H4', 'H5', 'H6', 'I4', 'I5', 'I6'}
+  },
+  ['G6'] =
+  {
+    {'A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', 'I6'},
+    {'G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7', 'G8', 'G9'},
+    {'G4', 'G5', 'G6', 'H4', 'H5', 'H6', 'I4', 'I5', 'I6'}
+  },
+  ['G7'] =
+  {
+    {'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', 'I7'},
+    {'G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7', 'G8', 'G9'},
+    {'G7', 'G8', 'G9', 'H7', 'H8', 'H9', 'I7', 'I8', 'I9'}
+  },
+  ['G8'] =
+  {
+    {'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', 'I8'},
+    {'G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7', 'G8', 'G9'},
+    {'G7', 'G8', 'G9', 'H7', 'H8', 'H9', 'I7', 'I8', 'I9'}
+  },
+  ['G9'] =
+  {
+    {'A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', 'I9'},
+    {'G1', 'G2', 'G3', 'G4', 'G5', 'G6', 'G7', 'G8', 'G9'},
+    {'G7', 'G8', 'G9', 'H7', 'H8', 'H9', 'I7', 'I8', 'I9'}
+  },
+  ['H1'] =
+  {
+    {'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1'},
+    {'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7', 'H8', 'H9'},
+    {'G1', 'G2', 'G3', 'H1', 'H2', 'H3', 'I1', 'I2', 'I3'}
+  },
+  ['H2'] =
+  {
+    {'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'},
+    {'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7', 'H8', 'H9'},
+    {'G1', 'G2', 'G3', 'H1', 'H2', 'H3', 'I1', 'I2', 'I3'}
+  },
+  ['H3'] =
+  {
+    {'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3'},
+    {'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7', 'H8', 'H9'},
+    {'G1', 'G2', 'G3', 'H1', 'H2', 'H3', 'I1', 'I2', 'I3'}
+  },
+  ['H4'] =
+  {
+    {'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4'},
+    {'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7', 'H8', 'H9'},
+    {'G4', 'G5', 'G6', 'H4', 'H5', 'H6', 'I4', 'I5', 'I6'}
+  },
+  ['H5'] =
+  {
+    {'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5'},
+    {'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7', 'H8', 'H9'},
+    {'G4', 'G5', 'G6', 'H4', 'H5', 'H6', 'I4', 'I5', 'I6'}
+  },
+  ['H6'] =
+  {
+    {'A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', 'I6'},
+    {'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7', 'H8', 'H9'},
+    {'G4', 'G5', 'G6', 'H4', 'H5', 'H6', 'I4', 'I5', 'I6'}
+  },
+  ['H7'] =
+  {
+    {'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', 'I7'},
+    {'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7', 'H8', 'H9'},
+    {'G7', 'G8', 'G9', 'H7', 'H8', 'H9', 'I7', 'I8', 'I9'}
+  },
+  ['H8'] =
+  {
+    {'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', 'I8'},
+    {'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7', 'H8', 'H9'},
+    {'G7', 'G8', 'G9', 'H7', 'H8', 'H9', 'I7', 'I8', 'I9'}
+  },
+  ['H9'] =
+  {
+    {'A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', 'I9'},
+    {'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7', 'H8', 'H9'},
+    {'G7', 'G8', 'G9', 'H7', 'H8', 'H9', 'I7', 'I8', 'I9'}
+  },
+  ['I1'] =
+  {
+    {'A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1'},
+    {'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9'},
+    {'G1', 'G2', 'G3', 'H1', 'H2', 'H3', 'I1', 'I2', 'I3'}
+  },
+  ['I2'] =
+  {
+    {'A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'},
+    {'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9'},
+    {'G1', 'G2', 'G3', 'H1', 'H2', 'H3', 'I1', 'I2', 'I3'}
+  },
+  ['I3'] =
+  {
+    {'A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3'},
+    {'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9'},
+    {'G1', 'G2', 'G3', 'H1', 'H2', 'H3', 'I1', 'I2', 'I3'}
+  },
+  ['I4'] =
+  {
+    {'A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4'},
+    {'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9'},
+    {'G4', 'G5', 'G6', 'H4', 'H5', 'H6', 'I4', 'I5', 'I6'}
+  },
+  ['I5'] =
+  {
+    {'A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5'},
+    {'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9'},
+    {'G4', 'G5', 'G6', 'H4', 'H5', 'H6', 'I4', 'I5', 'I6'}
+  },
+  ['I6'] =
+  {
+    {'A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6', 'H6', 'I6'},
+    {'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9'},
+    {'G4', 'G5', 'G6', 'H4', 'H5', 'H6', 'I4', 'I5', 'I6'}
+  },
+  ['I7'] =
+  {
+    {'A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7', 'H7', 'I7'},
+    {'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9'},
+    {'G7', 'G8', 'G9', 'H7', 'H8', 'H9', 'I7', 'I8', 'I9'}
+  },
+  ['I8'] =
+  {
+    {'A8', 'B8', 'C8', 'D8', 'E8', 'F8', 'G8', 'H8', 'I8'},
+    {'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9'},
+    {'G7', 'G8', 'G9', 'H7', 'H8', 'H9', 'I7', 'I8', 'I9'}
+  },
+  ['I9'] =
+  {
+    {'A9', 'B9', 'C9', 'D9', 'E9', 'F9', 'G9', 'H9', 'I9'},
+    {'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9'},
+    {'G7', 'G8', 'G9', 'H7', 'H8', 'H9', 'I7', 'I8', 'I9'}
+  }
+}
+
+local peers =
+{
+  ['A1'] =
+  {
+    'C1', 'A5', 'A4', 'H1', 'A9', 'D1', 'E1', 'A7', 'A2', 'F1',
+    'B3', 'B1', 'G1', 'I1', 'C3', 'B2', 'A6', 'A3', 'A8', 'C2'
+  },
+  ['A2'] =
+  {
+    'C1', 'A5', 'A4', 'A9', 'I2', 'A7', 'F2', 'B3', 'H2', 'D2',
+    'B1', 'E2', 'C3', 'B2', 'A6', 'A1', 'A3', 'A8', 'C2', 'G2'
+  },
+  ['A3'] =
+  {
+    'C1', 'A5', 'A4', 'A9', 'I3', 'F3', 'D3', 'A7', 'A2', 'B3',
+    'B1', 'E3', 'C3', 'H3', 'B2', 'G3', 'A6', 'A1', 'A8', 'C2'
+  },
+  ['A4'] =
+  {
+    'A5', 'A9', 'H4', 'I4', 'A7', 'A2', 'A8', 'C4', 'B6', 'C5',
+    'C6', 'B5', 'A6', 'D4', 'G4', 'A1', 'E4', 'A3', 'F4', 'B4'
+  },
+  ['A5'] =
+  {
+    'A4', 'A9', 'H5', 'A7', 'A2', 'D5', 'C4', 'E5', 'F5', 'B6',
+    'C5', 'C6', 'B5', 'I5', 'A6', 'A1', 'A3', 'A8', 'G5', 'B4'
+  },
+  ['A6'] =
+  {
+    'A5', 'A4', 'A9', 'F6', 'G6', 'D6', 'I6', 'A2', 'A7', 'E6',
+    'H6', 'C4', 'B6', 'C6', 'C5', 'B5', 'A1', 'A3', 'A8', 'B4'
+  },
+  ['A7'] =
+  {
+    'B7', 'A4', 'A9', 'A5', 'C9', 'C7', 'E7', 'A2', 'F7', 'B9',
+    'D7', 'G7', 'I7', 'A6', 'C8', 'A1', 'A3', 'A8', 'B8', 'H7'
+  },
+  ['A8'] =
+  {
+    'A5', 'A4', 'A9', 'E8', 'F8', 'B7', 'C9', 'C7', 'A7', 'A2',
+    'B9', 'I8', 'H8', 'A6', 'C8', 'A1', 'A3', 'B8', 'G8', 'D8'
+  },
+  ['A9'] =
+  {
+    'A5', 'A4', 'B7', 'E9', 'C9', 'I9', 'C7', 'H9', 'A7', 'A2',
+    'F9', 'B9', 'G9', 'D9', 'A6', 'C8', 'A1', 'A3', 'A8', 'B8'
+  },
+  ['B1'] =
+  {
+    'C1', 'B7', 'H1', 'D1', 'E1', 'A2', 'F1', 'B3', 'B9', 'G1',
+    'B6', 'I1', 'C3', 'B2', 'B5', 'A1', 'A3', 'B8', 'C2', 'B4'
+  },
+  ['B2'] =
+  {
+    'C1', 'B7', 'I2', 'F2', 'A2', 'B3', 'H2', 'D2', 'B1', 'B9',
+    'B6', 'E2', 'C3', 'B5', 'A1', 'A3', 'B8', 'C2', 'G2', 'B4'
+  },
+  ['B3'] =
+  {
+    'C1', 'B7', 'I3', 'F3', 'D3', 'A2', 'B1', 'B9', 'B6', 'E3',
+    'C3', 'H3', 'B2', 'B5', 'G3', 'A1', 'A3', 'B8', 'C2', 'B4'
+  },
+  ['B4'] =
+  {
+    'B7', 'A4', 'A5', 'H4', 'I4', 'B3', 'C4', 'B1', 'B9', 'B6',
+    'C5', 'C6', 'B2', 'B5', 'A6', 'D4', 'G4', 'E4', 'B8', 'F4'
+  },
+  ['B5'] =
+  {
+    'A5', 'B7', 'A4', 'H5', 'B3', 'D5', 'C4', 'B1', 'B9', 'F5',
+    'E5', 'B6', 'C5', 'C6', 'B2', 'I5', 'A6', 'B8', 'G5', 'B4'
+  },
+  ['B6'] =
+  {
+    'B7', 'A4', 'A5', 'F6', 'G6', 'D6', 'I6', 'B3', 'E6', 'H6',
+    'C4', 'B1', 'B9', 'C6', 'C5', 'B2', 'B5', 'A6', 'B8', 'B4'
+  },
+  ['B7'] =
+  {
+    'A9', 'C9', 'C7', 'E7', 'A7', 'A8', 'B3', 'B1', 'B9', 'D7',
+    'G7', 'B6', 'I7', 'B2', 'B5', 'C8', 'F7', 'B8', 'H7', 'B4'
+  },
+  ['B8'] =
+  {
+    'B7', 'A9', 'E8', 'F8', 'C9', 'C7', 'A7', 'B3', 'B1', 'B9',
+    'B6', 'I8', 'B2', 'H8', 'B5', 'C8', 'A8', 'G8', 'D8', 'B4'
+  },
+  ['B9'] =
+  {
+    'B7', 'A9', 'E9', 'C9', 'I9', 'C7', 'H9', 'A7', 'B3', 'F9',
+    'B1', 'B6', 'G9', 'D9', 'B2', 'B5', 'C8', 'A8', 'B8', 'B4'
+  },
+  ['C1'] =
+  {
+    'H1', 'D1', 'E1', 'C9', 'C7', 'A2', 'F1', 'B3', 'B1', 'G1',
+    'C5', 'I1', 'C3', 'C6', 'B2', 'C8', 'A1', 'A3', 'C2', 'C4'
+  },
+  ['C2'] =
+  {
+    'C1', 'C9', 'C7', 'I2', 'F2', 'A2', 'B3', 'H2', 'D2', 'B1',
+    'E2', 'C5', 'C6', 'C3', 'B2', 'C8', 'A1', 'A3', 'G2', 'C4'
+  },
+  ['C3'] =
+  {
+    'C1', 'C9', 'I3', 'C7', 'F3', 'D3', 'A2', 'B3', 'B1', 'E3',
+    'C5', 'C6', 'H3', 'B2', 'G3', 'C8', 'A1', 'A3', 'C2', 'C4'
+  },
+  ['C4'] =
+  {
+    'C1', 'A5', 'A4', 'H4', 'C9', 'I4', 'C7', 'B6', 'C5', 'C6',
+    'C3', 'B5', 'A6', 'C8', 'D4', 'G4', 'E4', 'C2', 'F4', 'B4'
+  },
+  ['C5'] =
+  {
+    'C1', 'A5', 'A4', 'C9', 'H5', 'C7', 'D5', 'E5', 'F5', 'B4',
+    'B6', 'C6', 'C3', 'B5', 'I5', 'A6', 'C8', 'C2', 'G5', 'C4'
+  },
+  ['C6'] =
+  {
+    'C1', 'A5', 'A4', 'C9', 'C7', 'F6', 'G6', 'D6', 'I6', 'E6',
+    'H6', 'B4', 'B6', 'C5', 'C3', 'B5', 'A6', 'C8', 'C2', 'C4'
+  },
+  ['C7'] =
+  {
+    'C1', 'B7', 'A9', 'C9', 'E7', 'A7', 'A8', 'B9', 'D7', 'G7',
+    'C5', 'C6', 'C3', 'I7', 'C8', 'F7', 'B8', 'H7', 'C2', 'C4'
+  },
+  ['C8'] =
+  {
+    'C1', 'B7', 'A9', 'E8', 'F8', 'C9', 'C7', 'A7', 'B9', 'I8',
+    'C5', 'C3', 'C6', 'H8', 'A8', 'B8', 'G8', 'C2', 'D8', 'C4'
+  },
+  ['C9'] =
+  {
+    'C1', 'B7', 'A9', 'E9', 'I9', 'C7', 'H9', 'A7', 'F9', 'B9',
+    'G9', 'C5', 'C6', 'D9', 'C3', 'C8', 'A8', 'B8', 'C2', 'C4'
+  },
+  ['D1'] =
+  {
+    'C1', 'H1', 'E1', 'F3', 'D3', 'D6', 'F2', 'F1', 'D5', 'D2',
+    'B1', 'D7', 'G1', 'E2', 'E3', 'I1', 'D9', 'A1', 'D4', 'D8'
+  },
+  ['D2'] =
+  {
+    'D1', 'E1', 'F3', 'D3', 'I2', 'D6', 'F2', 'A2', 'F1', 'D5',
+    'H2', 'D7', 'E2', 'E3', 'D9', 'B2', 'D4', 'C2', 'G2', 'D8'
+  },
+  ['D3'] =
+  {
+    'D1', 'E1', 'I3', 'F3', 'D6', 'F2', 'F1', 'B3', 'D5', 'D2',
+    'D7', 'E2', 'E3', 'C3', 'H3', 'D9', 'G3', 'D4', 'A3', 'D8'
+  },
+  ['D4'] =
+  {
+    'A4', 'H4', 'D1', 'F4', 'I4', 'D3', 'F6', 'D6', 'D5', 'D2',
+    'E6', 'C4', 'D7', 'F5', 'E5', 'D9', 'G4', 'E4', 'D8', 'B4'
+  },
+  ['D5'] =
+  {
+    'A5', 'D1', 'F4', 'H5', 'D3', 'F6', 'D6', 'D2', 'E6', 'E5',
+    'F5', 'D7', 'C5', 'D9', 'B5', 'I5', 'D4', 'E4', 'G5', 'D8'
+  },
+  ['D6'] =
+  {
+    'D1', 'F4', 'D3', 'F6', 'G6', 'I6', 'D5', 'D2', 'E6', 'H6',
+    'D7', 'F5', 'E5', 'B6', 'C6', 'D9', 'A6', 'D4', 'E4', 'D8'
+  },
+  ['D7'] =
+  {
+    'B7', 'E8', 'F8', 'D1', 'E9', 'C7', 'D3', 'E7', 'A7', 'D6',
+    'D5', 'D2', 'F9', 'G7', 'D9', 'I7', 'D4', 'F7', 'H7', 'D8'
+  },
+  ['D8'] =
+  {
+    'E8', 'F8', 'D1', 'E9', 'D3', 'E7', 'D6', 'A8', 'D5', 'D2',
+    'F9', 'D7', 'I8', 'D9', 'H8', 'C8', 'D4', 'F7', 'B8', 'G8'
+  },
+  ['D9'] =
+  {
+    'A9', 'E8', 'F8', 'D1', 'E9', 'C9', 'I9', 'D3', 'E7', 'H9',
+    'D6', 'D5', 'D2', 'F9', 'B9', 'D7', 'G9', 'D4', 'F7', 'D8'
+  },
+  ['E1'] =
+  {
+    'C1', 'H1', 'E8', 'D1', 'E9', 'F3', 'D3', 'E7', 'F2', 'F1',
+    'D2', 'E6', 'B1', 'E5', 'G1', 'E2', 'E3', 'I1', 'A1', 'E4'
+  },
+  ['E2'] =
+  {
+    'E8', 'D1', 'E1', 'E9', 'F3', 'D3', 'E7', 'I2', 'F2', 'A2',
+    'F1', 'H2', 'D2', 'E6', 'E5', 'E3', 'B2', 'E4', 'C2', 'G2'
+  },
+  ['E3'] =
+  {
+    'E8', 'D1', 'E1', 'I3', 'E9', 'F3', 'D3', 'E7', 'F2', 'F1',
+    'B3', 'D2', 'E6', 'E5', 'E2', 'C3', 'H3', 'G3', 'A3', 'E4'
+  },
+  ['E4'] =
+  {
+    'A4', 'E8', 'H4', 'E1', 'E9', 'I4', 'E7', 'F6', 'D6', 'D5',
+    'E6', 'C4', 'E5', 'F5', 'E2', 'E3', 'D4', 'G4', 'F4', 'B4'
+  },
+  ['E5'] =
+  {
+    'A5', 'E8', 'E1', 'E9', 'H5', 'E7', 'F6', 'D6', 'D5', 'E6',
+    'F5', 'E2', 'E3', 'C5', 'B5', 'I5', 'D4', 'E4', 'G5', 'F4'
+  },
+  ['E6'] =
+  {
+    'E8', 'E1', 'E9', 'E7', 'F6', 'G6', 'D6', 'I6', 'D5', 'H6',
+    'E5', 'F5', 'B6', 'E2', 'E3', 'C6', 'A6', 'D4', 'E4', 'F4'
+  },
+  ['E7'] =
+  {
+    'B7', 'E8', 'F8', 'E1', 'E9', 'C7', 'A7', 'F9', 'E6', 'D7',
+    'E5', 'G7', 'E2', 'E3', 'D9', 'I7', 'E4', 'F7', 'H7', 'D8'
+  },
+  ['E8']  =
+  {
+    'F8', 'E1', 'E9', 'E7', 'A8', 'F9', 'E6', 'E5', 'D7', 'E2',
+    'E3', 'I8', 'D9', 'H8', 'C8', 'E4', 'F7', 'B8', 'G8', 'D8'
+  },
+  ['E9'] =
+  {
+    'A9', 'E8', 'F8', 'C9', 'E1', 'I9', 'E7', 'H9', 'F9', 'E6',
+    'B9', 'E5', 'D7', 'E2', 'G9', 'E3', 'D9', 'E4', 'F7', 'D8'
+  },
+  ['F1'] =
+  {
+    'C1', 'H1', 'F8', 'D1', 'E1', 'F3', 'D3', 'F6', 'F2', 'D2',
+    'F9', 'B1', 'G1', 'F5', 'E2', 'E3', 'I1', 'A1', 'F7', 'F4'
+  },
+  ['F2'] =
+  {
+    'F8', 'D1', 'E1', 'F3', 'D3', 'I2', 'F6', 'A2', 'F1', 'H2',
+    'F9', 'D2', 'F5', 'E2', 'E3', 'B2', 'F7', 'C2', 'G2', 'F4'
+  },
+  ['F3'] =
+  {
+    'F8', 'D1', 'E1', 'I3', 'D3', 'F6', 'F2', 'F1', 'B3', 'D2',
+    'F9', 'F5', 'E2', 'E3', 'C3', 'H3', 'G3', 'A3', 'F7', 'F4'
+  },
+  ['F4'] =
+  {
+    'A4', 'F8', 'H4', 'I4', 'F3', 'F6', 'D6', 'F2', 'F7', 'F1',
+    'D5', 'F9', 'E6', 'C4', 'E5', 'F5', 'D4', 'G4', 'E4', 'B4'
+  },
+  ['F5'] =
+  {
+    'A5', 'F8', 'H5', 'F3', 'F6', 'D6', 'F2', 'F1', 'D5', 'F9',
+    'E6', 'E5', 'C5', 'B5', 'I5', 'D4', 'E4', 'F7', 'G5', 'F4'
+  },
+  ['F6'] =
+  {
+    'F8', 'F3', 'G6', 'D6', 'F2', 'I6', 'F1', 'D5', 'F9', 'E6',
+    'H6', 'E5', 'F5', 'B6', 'C6', 'A6', 'D4', 'E4', 'F7', 'F4'
+  },
+  ['F7'] =
+  {
+    'B7', 'E8', 'F8', 'E9', 'F4', 'C7', 'F3', 'E7', 'F6', 'A7',
+    'F2', 'F1', 'F9', 'D7', 'F5', 'G7', 'D9', 'I7', 'H7', 'D8'
+  },
+  ['F8'] =
+  {
+    'E8', 'E9', 'F3', 'E7', 'F6', 'F2', 'F7', 'F1', 'F9', 'D7',
+    'F5', 'D8', 'I8', 'D9', 'H8', 'C8', 'A8', 'B8', 'G8', 'F4'
+  },
+  ['F9'] =
+  {
+    'A9', 'E8', 'F8', 'E9', 'C9', 'F4', 'I9', 'F3', 'E7', 'F6',
+    'H9', 'F2', 'F1', 'B9', 'D7', 'F5', 'G9', 'D9', 'F7', 'D8'
+  },
+  ['G1'] =
+  {
+    'C1', 'H1', 'D1', 'E1', 'I3', 'I2', 'G5', 'G6', 'F1', 'H2',
+    'B1', 'G7', 'G9', 'I1', 'H3', 'G3', 'A1', 'G4', 'G8', 'G2'
+  },
+  ['G2'] =
+  {
+    'H1', 'I3', 'I2', 'G5', 'G6', 'F2', 'A2', 'H2', 'D2', 'G1',
+    'G7', 'E2', 'G9', 'I1', 'H3', 'B2', 'G3', 'G4', 'G8', 'C2'
+  },
+  ['G3'] =
+  {
+    'H1', 'I3', 'F3', 'D3', 'I2', 'G5', 'G6', 'B3', 'H2', 'G1',
+    'G7', 'G9', 'E3', 'I1', 'C3', 'H3', 'G4', 'A3', 'G8', 'G2'
+  },
+  ['G4'] =
+  {
+    'A4', 'H4', 'I4', 'H5', 'G5', 'G6', 'I6', 'H6', 'C4', 'G1',
+    'G7', 'G9', 'G3', 'I5', 'D4', 'E4', 'G8', 'G2', 'F4', 'B4'
+  },
+  ['G5'] =
+  {
+    'A5', 'H4', 'I4', 'H5', 'G6', 'I6', 'D5', 'H6', 'G2', 'E5',
+    'F5', 'G1', 'G7', 'G9', 'C5', 'B5', 'G3', 'I5', 'G4', 'G8'
+  },
+  ['G6'] =
+  {
+    'H4', 'I4', 'H5', 'G5', 'F6', 'D6', 'I6', 'E6', 'H6', 'G1',
+    'G7', 'B6', 'G9', 'C6', 'G3', 'I5', 'A6', 'G4', 'G8', 'G2'
+  },
+  ['G7'] =
+  {
+    'B7', 'C7', 'I9', 'E7', 'G5', 'G6', 'H9', 'A7', 'G8', 'D7',
+    'G1', 'G9', 'I8', 'I7', 'H8', 'G3', 'G4', 'F7', 'H7', 'G2'
+  },
+  ['G8'] =
+  {
+    'E8', 'F8', 'I9', 'G5', 'H7', 'G6', 'H9', 'G1', 'G7', 'G9',
+    'I8', 'I7', 'H8', 'G3', 'C8', 'G4', 'A8', 'B8', 'G2', 'D8'
+  },
+  ['G9'] =
+  {
+    'A9', 'E9', 'C9', 'I9', 'H7', 'G6', 'H9', 'F9', 'B9', 'G2',
+    'G1', 'G7', 'I8', 'D9', 'I7', 'H8', 'G3', 'G4', 'G8', 'G5'
+  },
+  ['H1'] =
+  {
+    'C1', 'H4', 'D1', 'E1', 'I3', 'H5', 'I2', 'H9', 'F1', 'H2',
+    'H6', 'B1', 'G1', 'I1', 'H3', 'H8', 'G3', 'A1', 'H7', 'G2'
+  },
+  ['H2'] =
+  {
+    'H1', 'H4', 'I3', 'H5', 'I2', 'H9', 'F2', 'A2', 'D2', 'H6',
+    'G1', 'E2', 'I1', 'H3', 'H8', 'B2', 'G3', 'H7', 'C2', 'G2'
+  },
+  ['H3'] =
+  {
+    'H1', 'H4', 'I3', 'H5', 'F3', 'D3', 'I2', 'H9', 'B3', 'H2',
+    'H6', 'G1', 'E3', 'I1', 'C3', 'H8', 'G3', 'A3', 'H7', 'G2'
+  },
+  ['H4'] =
+  {
+    'A4', 'H1', 'I4', 'H5', 'G6', 'H9', 'I6', 'H2', 'H6', 'C4',
+    'H3', 'H8', 'I5', 'D4', 'G4', 'E4', 'H7', 'G5', 'F4', 'B4'
+  },
+  ['H5'] =
+  {
+    'A5', 'H1', 'H4', 'I4', 'G6', 'H9', 'I6', 'D5', 'H2', 'H6',
+    'E5', 'F5', 'C5', 'H3', 'H8', 'B5', 'I5', 'G4', 'H7', 'G5'
+  },
+  ['H6'] =
+  {
+    'H1', 'H4', 'I4', 'H5', 'F6', 'H9', 'D6', 'G6', 'I6', 'H2',
+    'E6', 'B6', 'C6', 'H3', 'H8', 'I5', 'A6', 'G4', 'H7', 'G5'
+  },
+  ['H7'] =
+  {
+    'B7', 'H1', 'H4', 'H5', 'C7', 'I9', 'E7', 'H9', 'A7', 'H2',
+    'H6', 'G8', 'D7', 'G7', 'G9', 'I8', 'I7', 'H3', 'H8', 'F7'
+  },
+  ['H8'] =
+  {
+    'H1', 'E8', 'F8', 'H4', 'H5', 'I9', 'H7', 'H9', 'H2', 'H6',
+    'G7', 'G9', 'I8', 'H3', 'I7', 'C8', 'A8', 'B8', 'G8', 'D8'
+  },
+  ['H9'] =
+  {
+    'A9', 'H1', 'H4', 'E9', 'C9', 'H5', 'I9', 'H2', 'F9', 'H6',
+    'B9', 'G8', 'G7', 'G9', 'I8', 'D9', 'H3', 'H8', 'I7', 'H7'
+  },
+  ['I1'] =
+  {
+    'C1', 'H1', 'D1', 'E1', 'I3', 'I4', 'I9', 'I2', 'I6', 'F1',
+    'H2', 'B1', 'G1', 'I8', 'I7', 'H3', 'G3', 'I5', 'A1', 'G2'
+  },
+  ['I2'] =
+  {
+    'H1', 'I3', 'I4', 'I9', 'I6', 'F2', 'A2', 'H2', 'D2', 'G1',
+    'E2', 'I8', 'I1', 'I7', 'H3', 'B2', 'G3', 'I5', 'C2', 'G2'
+  },
+  ['I3'] =
+  {
+    'H1', 'I4', 'I9', 'F3', 'D3', 'I2', 'I6', 'B3', 'H2', 'G1',
+    'E3', 'I8', 'I1', 'H3', 'I7', 'C3', 'G3', 'I5', 'A3', 'G2'
+  },
+  ['I4'] =
+  {
+    'A4', 'H4', 'I3', 'H5', 'I9', 'I2', 'G6', 'I6', 'H6', 'C4',
+    'I8', 'I1', 'I7', 'I5', 'D4', 'G4', 'E4', 'G5', 'F4', 'B4'
+  },
+  ['I5'] =
+  {
+    'A5', 'H4', 'I3', 'I4', 'H5', 'I9', 'I2', 'G6', 'I6', 'D5',
+    'H6', 'E5', 'F5', 'C5', 'I1', 'I8', 'I7', 'B5', 'G4', 'G5'
+  },
+  ['I6'] =
+  {
+    'H4', 'I3', 'I4', 'H5', 'I9', 'I2', 'F6', 'G6', 'D6', 'E6',
+    'H6', 'B6', 'C6', 'I1', 'I8', 'I7', 'I5', 'A6', 'G4', 'G5'
+  },
+  ['I7'] =
+  {
+    'B7', 'I3', 'I4', 'C7', 'I9', 'E7', 'I2', 'H9', 'A7', 'I6',
+    'G8', 'D7', 'G7', 'G9', 'I8', 'I1', 'H8', 'I5', 'F7', 'H7'
+  },
+  ['I8'] =
+  {
+    'E8', 'F8', 'I3', 'I4', 'I9', 'I2', 'H9', 'I6', 'G8', 'G7',
+    'G9', 'I1', 'I7', 'H8', 'I5', 'C8', 'A8', 'B8', 'H7', 'D8'
+  },
+  ['I9'] =
+  {
+    'A9', 'E9', 'C9', 'I4', 'I3', 'I2', 'H9', 'I6', 'F9', 'B9',
+    'G8', 'G7', 'G9', 'I8', 'I1', 'D9', 'I7', 'H8', 'I5', 'H7'
+  }
+}
+
+local grid_chars, grid_values, parse_grid, assign, 
+      eliminate, solve, search, random_sudoku
+
+-- Input: a string representation 
+-- Output: an association between squares and characters
+
+grid_values = function(grid)
+  local result = {}
+  local chars  = string_to_table(grid)
+  assert(#chars == 81, "Invalid grid")
+  
+  -- ipairs is necessary here 
+    
+  for k, v in ipairs(squares) do
+    result[v] = chars[k]
+  end
+  return result
+end
+
+-- Input: a table grid 
+-- Output: return false if contradiction
+
+parse_grid = function(grid)
+  local values = {}
+  local gridvalues = grid_values(grid)
+    
+  -- Every square can be any digit 
+  
+  for _, s in ipairs(squares) do
+    values[s] = digits
+  end
+  
+  for s, d in pairs(gridvalues) do
+    if digits:find(d) and not assign(values, s, d) then
+      return false
+    end
+  end
+  return values
+end
+
+assign = function(values, s, d)
+  -- Eliminate all the other values and propagate
+  local result = true
+  local other_values = string_to_table(values[s]:gsub(d,''))
+  for _, d2 in ipairs(other_values) do
+    if not eliminate(values, s, d2) then
+      result = false
+    end
+  end
+  return result and values or false
+end
+
+eliminate = function(values, s, d)
+  -- Eliminate d from values[s]
+  if not values[s]:find(d) then
+    return values --Already eliminated
+  end
+  values[s] = values[s]:gsub(d,'')
+    -- 1. If a square s is reduced to one value d2, then eliminate d2 from the peers
+  if #values[s] == 0 then
+    return false 
+  elseif #values[s] == 1 then
+    local check = true
+    local d2 = values[s]
+    for _, s2 in pairs(peers[s]) do
+      if not eliminate(values, s2, values[s]) then
+        check = false
+      end 
+    end
+    if not check then return false end
+  end
+  -- 2. If a unit u is reduced to only one place for a value d, then put it there
+  for _, u in ipairs(units[s]) do
+    local dplaces = {}
+    for _, w in ipairs(u) do
+      if values[w]:find(d) then
+        insert(dplaces, w)
+      end
+    end
+    if #dplaces == 0 then
+      return false --contradiction
+    elseif #dplaces == 1 then
+      if not assign(values, dplaces[1], d) then
+        return false
+      end
+    end
+  end
+  return values 
+end
+
+solve = function(grid)
+  return search(parse_grid(grid))
+end
+
+search = function(values)
+  local check = true
+  local n = {}
+  local s 
+  if not values then
+    return false --Fail
+  end
+  for _, s in ipairs(squares) do
+    if #values[s] ~= 1 then
+      check = false
+    end
+  end
+  if check then return values end --Solved!
+  for _, x in ipairs(squares) do
+    if #values[x] > 1 then
+      insert(n, {#values[x], x})
+    end
+  end
+  sort(n, function(t1,t2) return t1[1] < t2[1] end)
+  s = n[1][2]
+  for _, d in ipairs(string_to_table(values[s])) do
+    local result = search(assign(copy(values), s, d))
+    if result then return result end
+  end
+  return false
+end 
+
+-- Unused until I find a handy way to interface with ConTeXt
+
+random_sudoku = function(N)
+  local N = N or 17
+  local result = {}
+  local values = {}
+  for _, v in ipairs(squares) do
+    values[s] = digits
+  end
+  for _, v in ipairs(shuffle(squares)) do
+    if not assign(values, s, values[rows[random(9)]..columns[random(9)]]) then
+      break
+    end
+    local ds = {}
+    for _, s in ipairs(squares) do
+      if #values[s] == 1 then
+        insert(ds, values[s])
+      end
+    end
+    if #ds >= N and #unique(ds) >= 8 then
+      for _, i in ipairs(rows) do
+        for _, j in ipairs(columns) do
+          insert(result, #values[i..j]>0 and values[i..j] or "0")
+        end
+      end
+      return concat(result)
+    end
+  end
+  return random_sudoku(N)
+end
+
+-- ConTeXt functions
+
+local ctx_sudoku, ctx_solvesudoku, 
+      ctx_sudokufile, ctx_solvesudokufile, 
+      ctx_randomsudoku, ctx_sudokufunction, 
+      ctx_typeset, ctx_error
+
+ctx_sudoku = function(grid, data)
+  local ok, result = pcall(grid_values, grid)
+  if ok then
+    ctx_typeset(result, data)
+  else
+    ctx_error("a") -- Invalid sudoku
+  end
+end
+
+ctx_sudokufile = function(file, data)
+  local ok, result = pcall(grid_values, loaddata(file))
+  if ok then
+    ctx_typeset(result, data)
+  else
+    ctx_error("b") -- "Invalid sudoku file"
+  end
+end
+
+ctx_solvesudoku = function(grid, data)
+  local ok, result = pcall(solve, grid)
+  if ok then
+    if result then
+      ctx_typeset(result, data)
+    else
+      ctx_error("c") -- "Impossible to find a solution"
+    end
+  else
+    ctx_error("a") -- "Invalid sudoku"
+  end
+end
+
+ctx_solvesudokufile = function(file, data)
+  local ok, result = pcall(solve, loaddata(file))
+  if ok then
+    if result then
+      ctx_typeset(result, data)
+    else
+      ctx_error("c") -- "Impossible to find a solution"
+    end
+  else
+    ctx_error("b") -- "Invalid sudoku file"
+  end
+end
+
+ctx_error = function(nerror)
+  local c = interfaces.constants
+  local placeholder, label, command = c.placeholder, c.label, c.command
+  c = context
+  c.sudokuparameter(placeholder .. command,
+    c.nested.sudokuparameter(placeholder .. label .. nerror)
+  )
+end
+
+local ctx_sudokufunctions = 
+{
+  sudoku          = ctx_sudoku,
+  sudokufile      = ctx_sudokufile,
+  solvesudoku     = ctx_solvesudoku,
+  solvesudokufile = ctx_solvesudokufile
+}
+
+ctx_sudokufunction = function(t)
+  ctx_sudokufunctions[t.name](t.content, t)
+end
+
+ctx_typeset = function(grid, data)
+  local alternatives = 
+    {
+      {background = data.oddbackground,  backgroundcolor = data.oddbackgroundcolor }, 
+      {background = data.evenbackground, backgroundcolor = data.evenbackgroundcolor}
+    }
+  for i, a in ipairs(rows) do
+    context.bTR()
+    for j, b in ipairs(columns) do
+      local r = grid[a..b]
+      context.bTD(alternatives[(ceil(i/3)+ceil(j/3))%2+1])
+      context(r == '0' and "" or r == '.' and "" or r)
+      context.eTD()
+    end
+    context.eTR()
+  end
+end
+
+--context.sudokuplaceholder = function(text)
+--  context.quitvmode()
+--  context.framed(context.nested.type(text))
+--end
+
+implement{
+  name      = "sudokufunction",
+  arguments = {"hash"},
+  actions   = ctx_sudokufunction
+}


Property changes on: trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku.mkvi
===================================================================
--- trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku.mkvi	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/context/third/sudoku/t-sudoku.mkvi	2023-05-20 20:23:06 UTC (rev 67175)
@@ -0,0 +1,217 @@
+%D \module
+%D   [     file=t-sudoku,
+%D      version=2023-05-15,
+%D        title=\CONTEXT\ User Module,
+%D     subtitle=Sudokus for ConTeXt,
+%D       author=Jairo A. del Rio,
+%D         date=\currentdate,
+%D    copyright=Jairo A. del Rio,
+%D        email=jairoadelrio6 at gmail.com,
+%D      license=MIT License]
+
+%C Copyright (c) 2021-2023 Jairo A. del Rio
+%C
+%C Permission is hereby granted, free of charge, to any person obtaining
+%C a copy of this software and associated documentation files (the
+%C "Software"), to deal in the Software without restriction, including
+%C without limitation the rights to use, copy, modify, merge, publish,
+%C distribute, sublicense, and/or sell copies of the Software, and to
+%C permit persons to whom the Software is furnished to do so, subject to
+%C the following conditions:
+%C
+%C The above copyright notice and this permission notice shall be
+%C included in all copies or substantial portions of the Software.
+%C
+%C THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+%C EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+%C MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+%C IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+%C CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+%C TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+%C SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+%D I'm not fond of sudokus. In fact, I seldom solve one or two in a row.
+%D However, they come in handy in puzzle books and existing packages are 
+%D LaTeX or Python specific. Being so, a ConTeXt dedicated module is 
+%D more comfortable and customizable. After all, ConTeXt is about control
+%D as Hans often says.
+
+\writestatus{loading}{Sudokus for ConTeXt}
+\writestatus{loading}{A Lua port of Peter Norvig's sudoku solver}
+
+\startmodule[sudoku]
+
+%D As always, Lua does the hard job
+
+\ctxloadluafile{t-sudoku}
+
+\unprotect
+
+%D \type{\definesudoku} is not really required
+
+\installnamespace                      {sudoku}
+\installsimplecommandhandler\????sudoku{sudoku}\????sudoku
+
+%D Some aliases
+
+\let\setupsudokus\setupsudoku
+
+%D Basic setups
+%D
+%D In order not to define new constants/variables, recycling existing 
+%D ones looks better (trick learnt from Aditya Mahajan's modules).
+
+\setupsudokus
+  [\c!size=1.5em,
+   \c!align={\v!middle,\v!lohi},
+   \v!even\c!background=\v!color,
+   \v!odd\c!background=\v!color,
+   \v!even\c!backgroundcolor=white,     
+   \v!odd\c!backgroundcolor=gray,
+   \c!placeholder\c!label a=Invalid sudoku,
+   \c!placeholder\c!label b=Invalid sudoku file,
+   \c!placeholder\c!label c=Impossible to find a solution,
+   \c!placeholder\c!command=\framed]
+
+%D A generic sudoku generator macro
+%D Yeah, I'm that lazy
+
+\unexpanded\def\sudokufunction_name{\dodoubleempty\sudokufunction_direct}
+
+%D Passing values to TABLE's is easier and unknown keys will be ignored. 
+%D However, we need to enforce a square shape.Hence the need to passing 
+%D values twice.
+
+\def\sudokufunction_direct[#name][#parameters]#content%
+  {\begingroup%
+   \ifsecondargument
+     \setupTABLE[#parameters]%
+     \setupsudokus[#parameters]%
+   \fi
+   \bTABLE
+    [\c!align=\sudokuparameter\c!align,
+     \c!width=\sudokuparameter\c!size,
+     \c!height=\sudokuparameter\c!size]
+     \clf_sudokufunction
+      [name                =#name,
+       content             ={#content},
+       evenbackground      =\sudokuparameter{\v!even\c!background},
+       oddbackground       =\sudokuparameter{\v!odd\c!background},
+       evenbackgroundcolor =\sudokuparameter{\v!even\c!backgroundcolor},
+       oddbackgroundcolor  =\sudokuparameter{\v!odd\c!backgroundcolor}]
+   \eTABLE%
+   \endgroup}
+
+%D Sudoku macros
+
+\def\sudoku{\sudokufunction_name[sudoku]}
+\def\sudokufile{\sudokufunction_name[sudokufile]}
+\def\solvesudoku{\sudokufunction_name[solvesudoku]}
+\def\solvesudokufile{\sudokufunction_name[solvesudokufile]}
+
+%D More aliases
+
+\let\solvedsudoku\solvesudoku
+\let\solvedsudokufile\solvesudokufile
+
+\protect
+
+\stopmodule
+
+\continueifinputfile{t-sudoku.mkvi}
+
+%D Some examples
+
+\usecolors[svg]
+\setupsudokus[oddbackgroundcolor=paleturquoise,evenbackgroundcolor=aliceblue]
+
+\starttext
+
+\startsection[title={\type{\sudoku}}]
+
+\sudoku{
+......... ........1 .....2.3.
+....1...4 ..3.5.... .26....7.
+14...8... 5........ 7....6.2.
+}
+
+\blank[line]
+
+\sudoku{
+000000001 000002030 004056000
+000004500 010700000 080000400
+000030000 000100008 205000000
+}
+
+\blank[line]
+
+\sudoku
+{
+000000000 111111111 222222222
+333333333 444444444 555555555
+666666666 777777777 888888888
+}
+
+\blank[line]
+
+\sudoku{666}
+
+\stopsection
+
+\startsection[title={\type{\solvesudoku}}]
+
+\solvesudoku[size=9mm,evenbackgroundcolor=gray,oddbackgroundcolor=white]{
+.......... .......1 .....2.3.
+....1...4. .3.5.... .26....7.
+14...8...5 ........ 7....6.2.
+}
+
+\blank[line]
+
+\solvedsudoku{
+000000001 000002030 004056000
+000004500 010700000 080000400
+000030000 000100008 205000000
+}
+
+\blank[line]
+
+\solvesudoku
+{
+000000000 111111111 222222222
+333333333 444444444 555555555
+666666666 777777777 888888888
+}
+
+\stopsection
+
+\startsection[title={\type{\sudokufile}}]
+
+\sudokufile[evenbackgroundcolor=cornsilk,oddbackgroundcolor=pink]{t-sudoku-test-01.txt}
+
+\blank[line]
+
+\sudokufile{t-sudoku-test-03.txt}
+
+\blank[line]
+
+\sudokufile[rulethickness=2pt,evenbackgroundcolor=cornsilk]{t-sudoku-test-02.txt}
+
+\stopsection
+
+\startsection[title={\type{\solvesudokufile}}]
+
+\setupsudokus[oddbackgroundcolor=plum,evenbackgroundcolor=pink]%
+\solvesudokufile[oddbackgroundcolor=thistle]{t-sudoku-test-01.txt}
+
+\blank[line]
+
+\solvesudokufile{t-sudoku-test-02.txt}
+
+\blank[line]
+
+\solvesudokufile{t-sudoku-test-03.txt}
+
+\stopsection
+
+\stoptext

Modified: trunk/Master/tlpkg/tlpsrc/collection-context.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/collection-context.tlpsrc	2023-05-20 20:19:20 UTC (rev 67174)
+++ trunk/Master/tlpkg/tlpsrc/collection-context.tlpsrc	2023-05-20 20:23:06 UTC (rev 67175)
@@ -39,6 +39,7 @@
 depend context-ruby
 depend context-simplefonts
 depend context-simpleslides
+depend context-sudoku
 depend context-title
 depend context-transliterator
 depend context-typearea

Added: trunk/Master/tlpkg/tlpsrc/context-sudoku.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/context-sudoku.tlpsrc	                        (rev 0)
+++ trunk/Master/tlpkg/tlpsrc/context-sudoku.tlpsrc	2023-05-20 20:23:06 UTC (rev 67175)
@@ -0,0 +1,2 @@
+category ConTeXt
+depend context



More information about the tex-live-commits mailing list.