diff options
Diffstat (limited to 'macros/context/contrib/context-squares/tex/context/third/squares/t-squares.lua')
-rw-r--r-- | macros/context/contrib/context-squares/tex/context/third/squares/t-squares.lua | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/macros/context/contrib/context-squares/tex/context/third/squares/t-squares.lua b/macros/context/contrib/context-squares/tex/context/third/squares/t-squares.lua new file mode 100644 index 0000000000..c0e613a3e0 --- /dev/null +++ b/macros/context/contrib/context-squares/tex/context/third/squares/t-squares.lua @@ -0,0 +1,306 @@ +if not modules then modules = {} end modules["t-squares"] = { + version = "2023-08-01", + comment = "Magic and Latin squares", + author = "Jairo A. del Rio", + copyright = "Jairo A. del Rio", + license = "MIT License", +} + +local interfaces = interfaces +local implement = interfaces.implement +local magic_reporter = logs.reporter("squares", "magic") +local latin_reporter = logs.reporter("squares", "latin") +local random = math.random + +-- https://www.iupindia.in/910/IJCM_Magic_Square_Construction_Algorithms34.pdf +-- https://arxiv.org/pdf/1402.3273.pdf +-- https://en.wikipedia.org/wiki/Conway%27s_LUX_method_for_magic_squares + +-- Helpers +local function init(s) + local q = {} + for j = 1, s do + q[j] = {} + local c = q[j] + for i = 1, s do + c[i] = 0 + end + end + return q +end + +-- Odd numbers + +local function magic_01(n) + local res = init(n) + local i, j = 1 + (n >> 1), 1 + local k, l + res[i][j] = 1 + for key = 2, n * n do + k = 2 <= i and i - 1 or n + l = 2 <= j and j - 1 or n + if res[k][l] > 0 then + i = i % n + 1 + else + i, j = k, l + end + res[i][j] = key + end + return res +end + +local function magic_02(N) + local res = init(N) + local n = N // 2 + local lux = init(n) + local L, U, X = 1, 2, 4 + local x1, x2, x3, x4 = -1, 0, -1, 0 + for i = 1, n do + for j = 1, n // 2 + 1 do + lux[i][j] = L + end + end + for i = 1, n do + lux[i][n // 2 + 2] = U + end + for j = n // 2 + 3, n do + for i = 1, n do + lux[i][j] = X + end + end + lux[n // 2 + 1][n // 2 + 1] = U + lux[n // 2 + 1][n // 2 + 2] = L + local i, j = 1, 1 + (n >> 1) + local k, l + res[2 * i + x1][2 * j - 1] = 1 + res[2 * i + x2][2 * j] = 2 + res[2 * i + x3][2 * j] = 3 + res[2 * i + x4][2 * j - 1] = 4 + for key = 2, n * n do + k = 2 <= i and i - 1 or n + l = 2 <= j and j - 1 or n + if res[2 * k][2 * l] > 0 then + i = i % n + 1 + else + i, j = k, l + end + if lux[i][j] == L then + x1, x2, x3, x4 = -1, 0, -1, 0 + elseif lux[i][j] == U then + x1, x2, x3, x4 = 0, 0, -1, -1 + else + x1, x2, x3, x4 = 0, -1, 0, -1 + end + res[2 * i + x1][2 * j] = 4 * (key - 1) + 1 + res[2 * i + x2][2 * j - 1] = 4 * (key - 1) + 2 + res[2 * i + x3][2 * j - 1] = 4 * (key - 1) + 3 + res[2 * i + x4][2 * j] = 4 * key + end + return res +end + +local function magic_03(n) + local res = init(n) + for x = 1, n, 4 do + for y = 1, n, 4 do + local q = 0 + for i = x, x + 3 do + q = q + 1 + local q1 = 0 + for j = y, y + 3 do + q1 = q1 + 1 + if i == j or i + j == 5 or q + q1 == 5 or q == q1 then + res[i][j] = n * (i - 1) + j + else + res[i][j] = n * n - ((i - 1) * n + j) + 1 + end + end + end + end + end + return res +end + +local currentsquare = nil + +local function magicsquare(n) + local r = n & 3 + if r == 0 then + return magic_03(n) + elseif r == 2 then + return magic_02(n) + end + return magic_01(n) +end + +local bTR, eTR = context.bTR, context.eTR +local bTD, eTD = context.bTD, context.eTD + +implement({ + name = "magicsquarecell", + arguments = { "integer", "integer" }, + actions = function(x, y) + context(currentsquare and currentsquare[x][y] or "") + end, +}) + +implement({ + name = "magicsquareinit", + arguments = { "integer" }, + actions = function(n) + if n > 0 and n ~= 2 then + currentsquare = magicsquare(n) + else + magic_reporter(("Invalid number %d: nothing will be provided"):format(n)) + end + end, +}) + +implement({ + name = "magicsquarereset", + actions = function() + currentsquare = nil + end, +}) + +implement({ + name = "magicsquare", + actions = function() + local r = currentsquare + if r then + local n = #r + for i = 1, n do + bTR() + for j = 1, n do + bTD() + context(r[i][j]) + eTD() + end + eTR() + end + else + magic_reporter("Magic square not initialized...") + return + end + end, +}) + +local function rand2(a, b) + if random(2) == 1 then + return a, b + else + return b, a + end +end + +local function latinsquare(n) + local xy, xz, yz = {}, {}, {} + local mxy, mxz, myz + local m + local proper = true + local min = n * n * n + for i = 1, n do + xy[i] = {} + yz[i] = {} + xz[i] = {} + end + for i = 1, n do + for j = 1, n do + local k = (i + j - 2) % n + 1 + xy[i][j] = k + xz[i][k] = j + yz[j][k] = i + end + end + for _ = 1, min do + local i, j, k, i2, j2, k2, i2_, j2_, k2_ + if proper then + i, j, k = random(n), random(n), random(n) + while xy[i][j] == k do + i, j, k = random(n), random(n), random(n) + end + i2 = yz[j][k] + j2 = xz[i][k] + k2 = xy[i][j] + i2_, j2_, k2_ = i, j, k + else + i, j, k = m[1], m[2], m[3] + i2, i2_ = rand2(yz[j][k], myz) + j2, j2_ = rand2(xz[i][k], mxz) + k2, k2_ = rand2(xy[i][j], mxy) + end + proper = xy[i2][j2] == k2 + if not proper then + m = { i2, j2, k2 } + mxy = xy[i2][j2] + myz = yz[j2][k2] + mxz = xz[i2][k2] + end + xy[i][j] = k2_ + xy[i][j2] = k2 + xy[i2][j] = k2 + xy[i2][j2] = k + + yz[j][k] = i2_ + yz[j][k2] = i2 + yz[j2][k] = i2 + yz[j2][k2] = i + + xz[i][k] = j2_ + xz[i][k2] = j2 + xz[i2][k] = j2 + xz[i2][k2] = j + end + return xy +end + +local currentlatin = nil + +implement({ + name = "latinsquarecell", + arguments = { "integer", "integer" }, + actions = function(x, y) + context(currentlatin and currentlatin[x][y] or "") + end, +}) + +implement({ + name = "latinsquareinit", + arguments = { "integer" }, + actions = function(n) + if n > 0 then + currentlatin = latinsquare(n) + else + latin_reporter(("Invalid number %d: nothing will be provided"):format(n)) + end + end, +}) + +implement({ + name = "latinsquarereset", + actions = function() + currentlatin = nil + end, +}) + +implement({ + name = "latinsquare", + actions = function() + local r = currentlatin + if r then + local n = #r + for i = 1, n do + bTR() + for j = 1, n do + bTD() + context(r[i][j]) + eTD() + end + eTR() + end + else + latin_reporter("Latin square not initialized...") + return + end + end, +}) |