Module:Ulam spiral
MyWikiBiz, Author Your Legacy — Sunday December 01, 2024
Jump to navigationJump to searchImplements {{Ulam spiral}}
-- Generate Ulam spiral based on primes, fibonacci, triangular numbers etc. -- Gts@el wiki, Sep. 2017 local p = {} -- determine whether number is prime -- params: n (number) -- return: boolean local function is_prime(n) for i = 2, n^(1/2) do if (n % i) == 0 then return false end end return true end -- determine whether number is triangular -- params: n (number) -- return: boolean local function is_triangular(n) x = (math.sqrt(8*n + 1) - 1) / 2 return (x % 1 == 0) end -- determine whether number is part of standard fibonacci sequence -- params: n (number) -- return: boolean local function is_fib(n) if n == 0 then return true end phi = 0.5 + (0.5 * math.sqrt(5.0)) a = phi * n return math.abs(math.floor(a+0.5) - a) < 1.0 / n end -- determine total divisors of a number -- params: n (number) -- return: int local function divisors(n) limit = n; total = 0; if n == 1 then return 1 end for i = 1, limit-1 do if n % i == 0 then limit = n / i if limit ~= i then total = total + 1 end total = total + 1 end end return total end -- CSS border for cells in order to recreate spiral -- params: row (number), column (number), size (number) -- return string function border(row, column, size) local on = 'solid ' local top, left, right, bottom = 'none ', 'none ', 'none ', 'none ' local last = size - 1 if column == math.floor(size/2) and row == column then bottom = on elseif row == math.floor(size/2) and column==row+1 then bottom=on right=on end if row < column and column < last - row then bottom = on elseif row > column and row < last - column then right = on elseif row >= column-1 and row < last and row > size/2 then bottom = on if column == row + 1 and column < last then right = on end elseif column>row and column < last then right = on end result = top .. right .. bottom .. left result = result:gsub("%s$", "") return result end -- convert values to wikitable. The wikitable string is preproccessed in frame. -- params: data (dictionary), size (int), fontSize (int) -- return: string object local function wikitable(data, size, fontSize) local fontSize = '1' --em if tonumber(size) > 15 and tonumber(size) <=30 then fontSize = '0.8' elseif tonumber(size) > 30 and tonumber(size) <= 45 then fontSize = '0.6' elseif tonumber(size) > 45 and tonumber(size) <= 60 then fontSize = '0.4' elseif tonumber(size) > 60 then fontSize = '0.2' end local result = '{| style="font-size:' .. fontSize .. 'em;text-align:center;border-spacing:0px"' -- background colour of a number corresponding to number of divisors divi = { [2] = '#8080ff', [3] = '#80ff80', [4] = '', [5] = '', [6] = '', [7] = '', [8] = '', [9] = '', } -- create wikitable for row=0, size-1 do result = result .. '\n|-\n|' for column=0, size-1 do if column > 0 then result = result .. '||' end number = data[row .. ':' .. column] bgcolor ='' divtotal = divisors(number) if divtotal >= 47 then bgcolor = '#ff8080' else bgcolor = tostring(divi[divtotal]) end result = result .. 'title="' .. math.floor(number) .. '" style="border-color:#9e9e9e;border-size:1px;border-style:' .. border(row, column, size) .. ';background-color:'.. bgcolor .. ';color:black"|' --result = result .. 'title="' .. math.floor(number) .. '" style="border-radius:50%;background-color:'.. bgcolor .. ';color:black !important"|' number = math.floor(data[row .. ':' .. column]) --if bgcolor ~= '' and bgcolor ~= 'nil' then result = result .. '[[' .. number .. ' (number)|' .. number .. ']]' --else -- result = result .. number --end end end result = result .. '\n|}' -- preprocess string in frame and render table local frame = mw.getCurrentFrame() result = frame:preprocess(result) return result end -- calculate ulam spiral value for each x,y tabular point. -- algorithm concept based on Python version at GPL 3 https://rosettacode.org/wiki/Ulam_spiral_(for_primes)#Python -- use of bitwise ops was attempted but Mediawiki Scribunto Lua doesn't seem to like them -- params: n (int), x (int), y (int), start (int) -- return: int local function cell(n, x, y, start) local d = 0 local x = x - math.floor((n - 1) /2) local y = y - math.floor(n / 2) l = 2 * math.max(math.abs(x), math.abs(y)) if y <= x then d = (l*3) + x + y else d = l - x - y end return math.pow(l - 1, 2) + d + start - 1 end -- prepare spiral display for output type (i.e. wikitable, coords only, etc) -- params: size (int), start (int) -- return: mixed local function show_spiral(size, start) local result = {} for i=0, size-1 do for x=0, i do for y=0, i do result[x .. ':' .. y] = cell(size, x, y, start) end end end return wikitable(result, size) end -- main -- params: frame -- return: mixed function p.ulam(frame) local size = tonumber(frame.args[1]) local start = tonumber(frame.args[2]) if size > 75 then return '<span style="font-family:Roboto;">The maximum allowed size is 75x75</span>' end return show_spiral(size, start) end return p