Skip to content

Instantly share code, notes, and snippets.

@hhrhhr
Created April 12, 2019 06:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hhrhhr/350a00c275f49ed4bbb7f4acfaa4e7bb to your computer and use it in GitHub Desktop.
Save hhrhhr/350a00c275f49ed4bbb7f4acfaa4e7bb to your computer and use it in GitHub Desktop.
Omiga's cards generator
--[[ 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