Created
April 12, 2019 06:42
-
-
Save hhrhhr/350a00c275f49ed4bbb7f4acfaa4e7bb to your computer and use it in GitHub Desktop.
Omiga's cards generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ sym num bits | |
top: RB 2 1 | |
left: /\<> 4 2 | |
right: /\<> 4 2 | |
bottom: RB 2 1 | |
total: 64 6 | |
]] | |
local MULT = 1 | |
local CARD_NUM = 2^(1+2+2+1) -- =2*4*4*2 | |
local CARD_IN_ROW = 6 | |
--[[ SVG conf ]]--------------------------------------------------------------- | |
local CARD_SIZE = 100 -- do not change! | |
local CL = { | |
"ffffff", -- white | |
"000000", -- black | |
"C40233", -- red | |
"0087BD", -- blue | |
"7f7f7f" -- grey | |
} | |
local BG = { -- background | |
[1] = "M 0,0 H 100 V 100 H 0 Z" | |
} | |
local TB = { -- top/bottom half circle | |
[1] = "M 70,0 C 70,11 61,20 50,20 C 39,20 30,11 30,0 Z", | |
[2] = "M 30,100 C 30,89 39,80 50,80 C 61,80 70,89 70,100 Z" | |
} | |
local LR = { -- symbols | |
[1] = "M 50,70", | |
[2] = { -- left | |
[1] = "H 20 L 5,30 H 50", -- \ | |
[2] = "H 5 L 20,30 H 50", -- / | |
[3] = "H 5 L 20,50 L 5,30 H 50", -- > | |
[4] = "H 20 L 5,50 L 20,30 H 50", -- < | |
-- "H 20 L 5,60 L 20,50 L 5,40 L 20,30 H 50", -- { | |
-- "H 5 L 20,60 L 5,50 L 20,40 L 5,30 H 50", -- } | |
}, | |
[3] = { -- right | |
"H 80 L 95,70", -- \ | |
"H 95 L 80,70", -- / | |
"H 80 L 95,50 L 80,70", -- > | |
"H 95 L 80,50 L 95,70", -- < | |
-- "H 80 L 95,40 L 80,50 L 95,60 L 80,70 H 50", -- } | |
-- "H 95 L 80,40 L 95,50 L 80,60 L 95,70 H 50", -- { | |
}, | |
[4] = "Z" | |
} | |
local fmt_svg = "<svg version='1.1' viewBox='0 0 %d %d' xmlns='http://www.w3.org/2000/svg'>\n" | |
local fmt_card = "<g id='cards_%d' stroke='none' transform='translate(%d, %d)' >\n" | |
local fmt_g = "<g id='card_%s' transform='translate(%d, %d)'>\n" | |
local fmt_path = "<path fill='#%s' d='%s' />\n" | |
local fmt_back = "<path fill='#%s' stroke='#7f7f7f' stroke-width='.1' d='%s' />\n" | |
--[[ utils]] | |
local function dbg(fmt, ...) | |
io.stderr:write((fmt):format(...)) | |
end | |
local function rotate(t) | |
local i, j = 1, #t | |
while i < j do | |
t[i], t[j] = t[j], t[i] | |
i = i + 1 | |
j = j - 1 | |
end | |
end | |
local time_s = os.clock() | |
--[[ generator ]]-------------------------------------------------------------- | |
local card_all = {} | |
for i = 0, CARD_NUM-1 do | |
local t = {} | |
t[1] = (i >> 0) & 1 -- top | |
t[2] = (i >> 1) & 3 -- left | |
t[3] = 0 --(i >> 3) & 1 -- center | |
t[4] = (i >> 3) & 3 --(i >> 4) & 3 -- right | |
t[5] = (i >> 5) & 1 --(i >> 6) & 1 -- bottom | |
table.insert(card_all, t) | |
end | |
dbg("total : %d\n", #card_all) | |
-- check for rotated duplicates | |
local dup = {} | |
for i = 1, CARD_NUM-1 do | |
for j = i+1, CARD_NUM do | |
if not dup[j] then | |
local f = card_all[i] | |
local s = card_all[j] | |
if f[1] == s[5] | |
and f[2] == s[4] | |
-- and f[3] == s[3] | |
and f[4] == s[2] | |
and f[5] == s[1] then | |
dup[j] = true | |
end | |
end | |
end | |
end | |
-- clear duplicates | |
for i = #card_all, 1, -1 do | |
if dup[i] then | |
table.remove(card_all, i) | |
end | |
end | |
dup = nil | |
CARD_NUM = #card_all | |
dbg("unique: %d\n", CARD_NUM) | |
-- solve | |
local attempt = 1 | |
local last_line = 1 | |
local rnd = os.time() + tonumber("0x"..tostring({}):sub(8)) | |
--local rnd = 1545184959 -- 136285 tries | |
dbg("rnd: %d\n", rnd) | |
math.randomseed(rnd) | |
local card = {} | |
for _ = 1, MULT * CARD_NUM do | |
for j = 1, CARD_NUM do | |
local t = card_all[j] | |
table.insert(card, {t[1], t[2], t[3], t[4], t[5]}) | |
end | |
end | |
CARD_NUM = MULT * CARD_NUM | |
::again:: | |
local r = math.random(1, CARD_NUM) | |
card[1], card[r] = card[r], card[1] | |
--[[ 1st row ]]---------------------------------------------------------------- | |
local ready = 1 | |
for i = 2, CARD_IN_ROW do | |
local prev_r = card[i-1][4] | |
local found = 0 | |
-- for j = i, CARD_NUM do | |
for j = math.random(i, CARD_NUM-CARD_IN_ROW), CARD_NUM do | |
local c_next = card[j] | |
found = j | |
if i < CARD_IN_ROW then | |
if c_next[2] == prev_r then | |
goto founded | |
end | |
if c_next[4] == prev_r then | |
goto rotated | |
end | |
else -- last card | |
if c_next[2] == prev_r and c_next[4] == card[1][2] then | |
goto founded | |
end | |
if c_next[4] == prev_r and c_next[2] == card[1][2] then | |
goto rotated | |
end | |
end | |
end | |
attempt = attempt + 1 | |
goto again | |
::rotated:: | |
rotate(card[found]) | |
::founded:: | |
card[i], card[found] = card[found], card[i] | |
ready = ready + 1 | |
end | |
--[[ 2nd ... last-1 rows ]]---------------------------------------------------- | |
for i = CARD_IN_ROW + 1, CARD_NUM - CARD_IN_ROW do | |
local c_prev4 = card[i - 1][4] | |
local c_top5 = card[i - CARD_IN_ROW][5] | |
local found = 0 | |
for j = i, CARD_NUM do | |
local c_next = card[j] | |
found = j | |
if (i % CARD_IN_ROW == 0) then -- last card in row | |
local c_first2 = card[i - CARD_IN_ROW + 1][2] | |
if c_next[1] == c_top5 | |
and c_next[2] == c_prev4 | |
and c_next[4] == c_first2 | |
then | |
goto founded | |
end | |
if c_next[5] == c_top5 | |
and c_next[4] == c_prev4 | |
and c_next[2] == c_first2 | |
then | |
goto rotated | |
end | |
elseif ((i - 1) % CARD_IN_ROW == 0) then -- first card in row | |
if c_next[1] == c_top5 then | |
goto founded | |
end | |
if c_next[5] == c_top5 then | |
goto rotated | |
end | |
else -- check other cards | |
if c_next[2] == c_prev4 and c_next[1] == c_top5 then | |
goto founded | |
end | |
if c_next[4] == c_prev4 and c_next[5] == c_top5 then | |
goto rotated | |
end | |
end | |
end | |
attempt = attempt + 1 | |
goto again | |
::rotated:: | |
rotate(card[found]) | |
::founded:: | |
if found > i then | |
card[i], card[found] = card[found], card[i] | |
end | |
ready = ready + 1 | |
end | |
--[[ last row ]]--------------------------------------------------------------- | |
for i = CARD_NUM - CARD_IN_ROW + 1, CARD_NUM do | |
local c_prev4 = card[i - 1][4] | |
local c_top5 = card[i - CARD_IN_ROW][5] | |
local c_bot1 = card[i - (i - 1) // CARD_IN_ROW * CARD_IN_ROW][1] | |
local found = 0 | |
for j = i, CARD_NUM do | |
local c_next = card[j] | |
found = j | |
if (i % CARD_IN_ROW == 0) then -- last card in row | |
local c_first = card[i - CARD_IN_ROW + 1] | |
if c_next[1] == c_top5 | |
and c_next[5] == c_bot1 | |
and c_next[2] == c_prev4 | |
and c_next[4] == c_first[2] | |
then | |
goto founded | |
end | |
if c_next[5] == c_top5 | |
and c_next[1] == c_bot1 | |
and c_next[4] == c_prev4 | |
and c_next[2] == c_first[2] | |
then | |
goto rotated | |
end | |
elseif ((i - 1) % CARD_IN_ROW == 0) then -- first card in row | |
if c_next[1] == c_top5 | |
and c_next[5] == c_bot1 | |
then | |
goto founded | |
end | |
if c_next[5] == c_top5 | |
and c_next[1] == c_bot1 | |
then | |
goto rotated | |
end | |
else -- check other cards | |
if c_next[2] == c_prev4 | |
and c_next[1] == c_top5 | |
and c_next[5] == c_bot1 | |
then | |
goto founded | |
end | |
if c_next[4] == c_prev4 | |
and c_next[5] == c_top5 | |
and c_next[1] == c_bot1 | |
then | |
goto rotated | |
end | |
end | |
end | |
--dbg("last line: try %d, solved: %d/%d", attempt, ready, CARD_NUM) | |
if last_line % 100 == 0 then | |
dbg(".") | |
end | |
if attempt > 10000000 then | |
dbg("\n\n!!! breaked !!!\n\n") | |
break | |
end | |
last_line = last_line + 1 | |
attempt = attempt + 1 | |
goto again | |
::rotated:: | |
rotate(card[found]) | |
::founded:: | |
card[i], card[found] = card[found], card[i] | |
ready = ready + 1 | |
end | |
time_s = os.clock() - time_s | |
dbg("\ntries : %d\n", attempt) | |
dbg("time : %.3f\n", time_s) | |
for i = 1, CARD_NUM do | |
local c = card[i] | |
for j = 1, 5 do io.write(j ~= 3 and c[j] or "") end | |
io.write(i % CARD_IN_ROW == 0 and "\n" or " ") | |
end | |
--[[ SVG out ]]---------------------------------------------------------------- | |
local out = io.stdout | |
if arg[1] then | |
out = assert(io.open(arg[1], "w+")) | |
end | |
local o = CARD_SIZE // 20 -- offset | |
local w = (CARD_IN_ROW * CARD_SIZE * 2 + o * 2) | |
local h = (CARD_NUM // CARD_IN_ROW * CARD_SIZE + o * 2) | |
out:write(fmt_svg:format(w, h)) | |
local function print_svg(bg_color) | |
local sx = bg_color * CARD_SIZE * CARD_IN_ROW + o | |
local sy = o | |
out:write(fmt_card:format(bg_color, sx, sy)) | |
local X = 0 | |
local Y = 0 | |
for i = 1, CARD_NUM do | |
local c = card[i] | |
c[3] = bg_color | |
-- card begin | |
local card_id = table.concat(c) | |
out:write(fmt_g:format(card_id, X*CARD_SIZE, Y*CARD_SIZE)) | |
-- back | |
local bg = c[3] == 5 and CL[5] or (bg_color == 0 and CL[1] or CL[2]) | |
out:write(fmt_back:format(bg, BG[1])) | |
-- top, bottom | |
local v1 = c[1] | |
bg = v1 == 0 and CL[3] or CL[4] | |
out:write(fmt_path:format(bg, TB[1])) | |
v1 = c[5] | |
bg = v1 == 0 and CL[3] or CL[4] | |
out:write(fmt_path:format(bg, TB[2])) | |
-- left, right | |
v1 = c[2] | |
local v2 = c[4] | |
bg = bg_color == 0 and CL[2] or CL[1] | |
local t = {} | |
t[1] = LR[1] | |
t[2] = LR[2][v1+1] | |
t[3] = LR[3][v2+1] | |
t[4] = LR[4] | |
out:write(fmt_path:format(bg, table.concat(t, " "))) | |
-- card end | |
out:write("</g>\n") | |
X = X + 1 | |
if X == CARD_IN_ROW then | |
X = 0 | |
Y = Y + 1 | |
end | |
end | |
out:write("</g>\n") | |
end | |
print_svg(0) -- white back | |
print_svg(1) -- black back | |
out:write("</svg>\n") | |
if arg[1] then | |
out:close() | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment