1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 | -- https://play.luau.org/
-- I am absolutely losing it over this polyomino nonsense.
-- I swear these rotations are conspiring behind my back.
-- I may evaporate.
-- This code will either enumerate every polyomino or take me down with it.
-- I've decided to neglect reflections and rotations because I value survival.
type Polyomino = { { number } }
local known = {} :: { [number]: { Polyomino } }
local function doPolyominoesMatch(polyomino1: Polyomino, polyomino2: Polyomino): boolean
if #polyomino1 ~= #polyomino2 then return false end
if #polyomino1[1] ~= #polyomino2[1] then return false end
for y = 1, #polyomino1 do
for x = 1, #polyomino1[y] do
if polyomino1[y][x] ~= polyomino2[y][x] then
return false
end
end
end
return true
end
local function isUnique(polyominoToCheck: Polyomino, n: number): boolean
for _, polyomino in known[n] do
if doPolyominoesMatch(polyomino, polyominoToCheck) then
return false
end
end
return true
end
local function addToPolyomino(polyomino: Polyomino, posx: number, posy: number): Polyomino
local height = #polyomino
local width = #polyomino[1]
local offsetX = if posx < 1 then 1 else 0
local offsetY = if posy < 1 then 1 else 0
local newWidth = math.max(width + offsetX, posx)
local newHeight = math.max(height + offsetY, posy)
local newPolyomino = table.create(newHeight)
for y = 1, newHeight do
newPolyomino[y] = table.create(newWidth, 0)
end
for y = 1, height do
for x = 1, width do
newPolyomino[y + offsetY][x + offsetX] = polyomino[y][x]
end
end
newPolyomino[posy + offsetY][posx + offsetX] = 1
return newPolyomino
end
local function polyominoes(n: number): number
known[n] = {}
if n == 0 then
table.insert(known[n], { { 0 } })
elseif n == 1 then
table.insert(known[n], { { 1 } })
else
for _, polyomino in known[n - 1] do
local height = #polyomino
local width = #polyomino[1]
for y = 1, height do
for x = 1, width do
if polyomino[y][x] == 0 then continue end
local neighbors = {
{x + 1, y},
{x - 1, y},
{x, y + 1},
{x, y - 1}
}
for _, neighbor in neighbors do
local neighborx, neighbory = neighbor[1], neighbor[2]
local isEmpty = neighborx < 1 or neighbory < 1 or neighborx > width or neighbory > height or polyomino[neighbory][neighborx] == 0
if isEmpty then
local newPolyomino = addToPolyomino(polyomino, neighborx, neighbory)
if isUnique(newPolyomino, n) then
table.insert(known[n], newPolyomino)
end
end
end
end
end
end
end
return known[n] and #known[n] or 0
end
local function printPolyomino(polyomino: Polyomino)
for y = 1, #polyomino do
local row = ''
for x = 1, #polyomino[y] do
row ..= if polyomino[y][x] == 1 then '██' else ' '
end
print(` {row}`)
end
end
for i = 0, 4 do
local count = polyominoes(i)
print(('='):rep(40))
print(`n = {i} ({count} polyominoes)`)
print(('='):rep(40))
for j, polyomino in known[i] do
print(` #{j}`)
printPolyomino(polyomino)
if j < #known[i] then
print(('-'):rep(20))
end
end
print()
end
|
post a comment