Last active
August 10, 2023 23:57
-
-
Save PM2Ring/d2793fc9402a6f27d0b3cdb71d8eea59 to your computer and use it in GitHub Desktop.
Domino tiling
This file contains hidden or 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
(0, 1) : 50 | |
(1, 0) : 50 | |
(0, 2) : 258 | |
(1, 1) : 600 | |
(2, 0) : 258 | |
(0, 3) : 186 | |
(1, 2) : 1086 | |
(2, 1) : 1086 | |
(3, 0) : 186 | |
(0, 4) : 5 | |
(1, 3) : 400 | |
(2, 2) : 1362 | |
(3, 1) : 400 | |
(4, 0) : 5 | |
(1, 4) : 20 | |
(2, 3) : 342 | |
(3, 2) : 342 | |
(4, 1) : 20 | |
(2, 4) : 35 | |
(4, 2) : 35 | |
(2, 5) : 1 | |
(5, 2) : 1 |
This file contains hidden or 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
() (0,) : 6 | |
() (1,) : 15 | |
() (2,) : 8 | |
() (3,) : 15 | |
() (4,) : 6 | |
(0,) () : 6 | |
(1,) () : 15 | |
(2,) () : 8 | |
(3,) () : 15 | |
(4,) () : 6 | |
() (0, 1) : 12 | |
() (0, 2) : 24 | |
() (0, 3) : 24 | |
() (0, 4) : 12 | |
() (1, 2) : 24 | |
() (1, 3) : 78 | |
() (1, 4) : 24 | |
() (2, 3) : 24 | |
() (2, 4) : 24 | |
() (3, 4) : 12 | |
(0,) (1,) : 28 | |
(0,) (3,) : 28 | |
(1,) (0,) : 28 | |
(1,) (1,) : 42 | |
(1,) (2,) : 52 | |
(1,) (3,) : 42 | |
(1,) (4,) : 28 | |
(2,) (1,) : 52 | |
(2,) (3,) : 52 | |
(3,) (0,) : 28 | |
(3,) (1,) : 42 | |
(3,) (2,) : 52 | |
(3,) (3,) : 42 | |
(3,) (4,) : 28 | |
(4,) (1,) : 28 | |
(4,) (3,) : 28 | |
(0, 1) () : 12 | |
(0, 2) () : 24 | |
(0, 3) () : 24 | |
(0, 4) () : 12 | |
(1, 2) () : 24 | |
(1, 3) () : 78 | |
(1, 4) () : 24 | |
(2, 3) () : 24 | |
(2, 4) () : 24 | |
(3, 4) () : 12 | |
() (0, 1, 3) : 31 | |
() (0, 2, 3) : 31 | |
() (0, 2, 4) : 31 | |
() (1, 2, 3) : 31 | |
() (1, 2, 4) : 31 | |
() (1, 3, 4) : 31 | |
(0,) (1, 3) : 72 | |
(1,) (0, 1) : 13 | |
(1,) (0, 2) : 42 | |
(1,) (0, 3) : 42 | |
(1,) (0, 4) : 13 | |
(1,) (1, 2) : 42 | |
(1,) (1, 3) : 108 | |
(1,) (1, 4) : 42 | |
(1,) (2, 3) : 42 | |
(1,) (2, 4) : 42 | |
(1,) (3, 4) : 13 | |
(2,) (1, 3) : 144 | |
(3,) (0, 1) : 13 | |
(3,) (0, 2) : 42 | |
(3,) (0, 3) : 42 | |
(3,) (0, 4) : 13 | |
(3,) (1, 2) : 42 | |
(3,) (1, 3) : 108 | |
(3,) (1, 4) : 42 | |
(3,) (2, 3) : 42 | |
(3,) (2, 4) : 42 | |
(3,) (3, 4) : 13 | |
(4,) (1, 3) : 72 | |
(0, 1) (1,) : 13 | |
(0, 1) (3,) : 13 | |
(0, 2) (1,) : 42 | |
(0, 2) (3,) : 42 | |
(0, 3) (1,) : 42 | |
(0, 3) (3,) : 42 | |
(0, 4) (1,) : 13 | |
(0, 4) (3,) : 13 | |
(1, 2) (1,) : 42 | |
(1, 2) (3,) : 42 | |
(1, 3) (0,) : 72 | |
(1, 3) (1,) : 108 | |
(1, 3) (2,) : 144 | |
(1, 3) (3,) : 108 | |
(1, 3) (4,) : 72 | |
(1, 4) (1,) : 42 | |
(1, 4) (3,) : 42 | |
(2, 3) (1,) : 42 | |
(2, 3) (3,) : 42 | |
(2, 4) (1,) : 42 | |
(2, 4) (3,) : 42 | |
(3, 4) (1,) : 13 | |
(3, 4) (3,) : 13 | |
(0, 1, 3) () : 31 | |
(0, 2, 3) () : 31 | |
(0, 2, 4) () : 31 | |
(1, 2, 3) () : 31 | |
(1, 2, 4) () : 31 | |
(1, 3, 4) () : 31 | |
() (0, 1, 2, 3) : 1 | |
() (0, 1, 2, 4) : 1 | |
() (0, 1, 3, 4) : 1 | |
() (0, 2, 3, 4) : 1 | |
() (1, 2, 3, 4) : 1 | |
(1,) (0, 1, 2) : 2 | |
(1,) (0, 1, 3) : 32 | |
(1,) (0, 1, 4) : 2 | |
(1,) (0, 2, 3) : 32 | |
(1,) (0, 2, 4) : 32 | |
(1,) (0, 3, 4) : 2 | |
(1,) (1, 2, 3) : 32 | |
(1,) (1, 2, 4) : 32 | |
(1,) (1, 3, 4) : 32 | |
(1,) (2, 3, 4) : 2 | |
(3,) (0, 1, 2) : 2 | |
(3,) (0, 1, 3) : 32 | |
(3,) (0, 1, 4) : 2 | |
(3,) (0, 2, 3) : 32 | |
(3,) (0, 2, 4) : 32 | |
(3,) (0, 3, 4) : 2 | |
(3,) (1, 2, 3) : 32 | |
(3,) (1, 2, 4) : 32 | |
(3,) (1, 3, 4) : 32 | |
(3,) (2, 3, 4) : 2 | |
(0, 1) (1, 3) : 30 | |
(0, 2) (1, 3) : 84 | |
(0, 3) (1, 3) : 84 | |
(0, 4) (1, 3) : 30 | |
(1, 2) (1, 3) : 84 | |
(1, 3) (0, 1) : 30 | |
(1, 3) (0, 2) : 84 | |
(1, 3) (0, 3) : 84 | |
(1, 3) (0, 4) : 30 | |
(1, 3) (1, 2) : 84 | |
(1, 3) (1, 3) : 174 | |
(1, 3) (1, 4) : 84 | |
(1, 3) (2, 3) : 84 | |
(1, 3) (2, 4) : 84 | |
(1, 3) (3, 4) : 30 | |
(1, 4) (1, 3) : 84 | |
(2, 3) (1, 3) : 84 | |
(2, 4) (1, 3) : 84 | |
(3, 4) (1, 3) : 30 | |
(0, 1, 2) (1,) : 2 | |
(0, 1, 2) (3,) : 2 | |
(0, 1, 3) (1,) : 32 | |
(0, 1, 3) (3,) : 32 | |
(0, 1, 4) (1,) : 2 | |
(0, 1, 4) (3,) : 2 | |
(0, 2, 3) (1,) : 32 | |
(0, 2, 3) (3,) : 32 | |
(0, 2, 4) (1,) : 32 | |
(0, 2, 4) (3,) : 32 | |
(0, 3, 4) (1,) : 2 | |
(0, 3, 4) (3,) : 2 | |
(1, 2, 3) (1,) : 32 | |
(1, 2, 3) (3,) : 32 | |
(1, 2, 4) (1,) : 32 | |
(1, 2, 4) (3,) : 32 | |
(1, 3, 4) (1,) : 32 | |
(1, 3, 4) (3,) : 32 | |
(2, 3, 4) (1,) : 2 | |
(2, 3, 4) (3,) : 2 | |
(0, 1, 2, 3) () : 1 | |
(0, 1, 2, 4) () : 1 | |
(0, 1, 3, 4) () : 1 | |
(0, 2, 3, 4) () : 1 | |
(1, 2, 3, 4) () : 1 | |
(1,) (0, 1, 2, 3) : 2 | |
(1,) (0, 1, 2, 4) : 2 | |
(1,) (0, 1, 3, 4) : 2 | |
(1,) (0, 2, 3, 4) : 2 | |
(1,) (1, 2, 3, 4) : 2 | |
(3,) (0, 1, 2, 3) : 2 | |
(3,) (0, 1, 2, 4) : 2 | |
(3,) (0, 1, 3, 4) : 2 | |
(3,) (0, 2, 3, 4) : 2 | |
(3,) (1, 2, 3, 4) : 2 | |
(1, 3) (0, 1, 2) : 12 | |
(1, 3) (0, 1, 3) : 49 | |
(1, 3) (0, 1, 4) : 12 | |
(1, 3) (0, 2, 3) : 49 | |
(1, 3) (0, 2, 4) : 49 | |
(1, 3) (0, 3, 4) : 12 | |
(1, 3) (1, 2, 3) : 49 | |
(1, 3) (1, 2, 4) : 49 | |
(1, 3) (1, 3, 4) : 49 | |
(1, 3) (2, 3, 4) : 12 | |
(0, 1, 2) (1, 3) : 12 | |
(0, 1, 3) (1, 3) : 49 | |
(0, 1, 4) (1, 3) : 12 | |
(0, 2, 3) (1, 3) : 49 | |
(0, 2, 4) (1, 3) : 49 | |
(0, 3, 4) (1, 3) : 12 | |
(1, 2, 3) (1, 3) : 49 | |
(1, 2, 4) (1, 3) : 49 | |
(1, 3, 4) (1, 3) : 49 | |
(2, 3, 4) (1, 3) : 12 | |
(0, 1, 2, 3) (1,) : 2 | |
(0, 1, 2, 3) (3,) : 2 | |
(0, 1, 2, 4) (1,) : 2 | |
(0, 1, 2, 4) (3,) : 2 | |
(0, 1, 3, 4) (1,) : 2 | |
(0, 1, 3, 4) (3,) : 2 | |
(0, 2, 3, 4) (1,) : 2 | |
(0, 2, 3, 4) (3,) : 2 | |
(1, 2, 3, 4) (1,) : 2 | |
(1, 2, 3, 4) (3,) : 2 | |
(1, 3) (0, 1, 2, 3) : 7 | |
(1, 3) (0, 1, 2, 4) : 7 | |
(1, 3) (0, 1, 3, 4) : 7 | |
(1, 3) (0, 2, 3, 4) : 7 | |
(1, 3) (1, 2, 3, 4) : 7 | |
(0, 1, 2, 3) (1, 3) : 7 | |
(0, 1, 2, 4) (1, 3) : 7 | |
(0, 1, 3, 4) (1, 3) : 7 | |
(0, 2, 3, 4) (1, 3) : 7 | |
(1, 2, 3, 4) (1, 3) : 7 | |
(1, 3) (0, 1, 2, 3, 4) : 1 | |
(0, 1, 2, 3, 4) (1, 3) : 1 |
This file contains hidden or 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
<!DOCTYPE HTML> | |
<html> | |
<head> | |
<title>Domino grid</title> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width"> | |
<style> | |
.zrb {height: 2em;} | |
.c0 {background: #d81b60;} | |
.c1 {background: #ffc107;} | |
.c2 {background: #004d40;} | |
.c3 {background: #1e88e5;} | |
</style> | |
</head> | |
<body> | |
<input id="iWidth" size="2" value="6"><label for="iWidth">Width</label> | |
<input id="iHeight" size="2" value="6"><label for="iHeight">Height</label> | |
<input id="iScale" size="2" value="6"><label for="iScale">Scale</label> | |
<br><br> | |
<svg xmlns="http://www.w3.org/2000/svg" id="svg"> | |
<style> | |
.c0 {fill: #d81b60;} | |
.c1 {fill: #ffc107;} | |
.c2 {fill: #004d40;} | |
.c3 {fill: #1e88e5;} | |
</style> | |
<defs> | |
<pattern id="checks" patternUnits="userSpaceOnUse" | |
width="20" height="20"> | |
<rect width="10" height="10" fill="#bbb"/> | |
<rect width="10" height="10" x="10" y="10" fill="#bbb"/> | |
</pattern> | |
<rect id="dh" width="20" height="10"/> | |
<rect id="dv" width="10" height="20"/> | |
</defs> | |
<g transform="translate(0.5, 0.5)"> | |
<g style="stroke:#444; stroke-width:1"> | |
<rect x="-0.5" y="-0.5" width="100%" height="100%" fill="#eee"/> | |
<rect x="-0.5" y="-0.5" width="100%" height="100%" fill="url(#checks)" id="zzz"/> | |
</g> | |
<g style="stroke:#333; stroke-linejoin:round; | |
stroke-width:0.5; stroke-opacity:0.7; fill-opacity:0.8" id="cvs"/> | |
</g></svg> | |
<br> | |
<button id="bclear">Clear</button> | |
<button id="bdump">Export</button> | |
<button id="bfetch">Import</button> | |
<div> | |
<span id="zcblock" class="c0">Color</span> | |
<input type="radio" id="zbcr0" class="zrb" | |
checked | |
name="zbcolor" value="c0"> | |
<label for="zbcr0" class="c0">Red</label> | |
<input type="radio" id="zbcr1" class="zrb" | |
name="zbcolor" value="c1"> | |
<label for="zbcr1" class="c1">Gold</label> | |
<input type="radio" id="zbcr2" class="zrb" | |
name="zbcolor" value="c2"> | |
<label for="zbcr2" class="c2">Green</label> | |
<input type="radio" id="zbcr3" class="zrb" | |
name="zbcolor" value="c3"> | |
<label for="zbcr3" class="c3">Blue</label> | |
</div> | |
<br> | |
<textarea id="ta" cols=40 rows=10 wrap="off"></textarea> | |
<br> | |
<button id="btaclear">Clear</button> | |
</body> | |
<script> | |
(function(){ | |
// const put = (s) => ta.value += s + "\n"; | |
const dqs = (s) => document.querySelector(s); | |
const svg = dqs("#svg"), cvs = dqs("#cvs"), ta = dqs('#ta'); | |
let width, height, cclass = "c0"; | |
function setSize() { | |
width = dqs("#iWidth").value * 10 + 1; | |
height = dqs("#iHeight").value * 10 + 1; | |
let sc = dqs("#iScale").value; | |
svg.setAttribute("width", width * sc); | |
svg.setAttribute("height", height * sc); | |
svg.setAttribute("viewBox", '0 0 ' + width + ' ' + height); | |
} | |
setSize(); | |
dqs("#iWidth").onchange = setSize; | |
dqs("#iHeight").onchange = setSize; | |
dqs("#iScale").onchange = setSize; | |
function newcolor() { | |
cclass = dqs("#zcblock").className = this.value; | |
} | |
for (let i=0; i<4; i++) | |
dqs("#zbcr" + i).onclick = newcolor; | |
function svgPointer(evt) { | |
const coords = evt.touches ? evt.touches[0] : evt; | |
const pt = new DOMPoint(coords.clientX, coords.clientY); | |
return pt.matrixTransform(evt.target.getScreenCTM().inverse()); | |
} | |
function makeBlock(x, y, id, cc) { | |
const a = document.createElementNS(svg.namespaceURI, 'use'); | |
a.setAttribute("x", x); | |
a.setAttribute("y", y); | |
a.setAttribute("href", id); | |
a.setAttribute("class", cc); | |
cvs.appendChild(a); | |
} | |
function onClick(evt) { | |
const pt = svgPointer(evt), tgt = evt.target; | |
if (tgt.id !== "zzz") { | |
tgt.remove(); | |
return; | |
} | |
let x = pt.x, y = pt.y; | |
x = Math.floor(x/5 - 0.75) * 5; | |
y = Math.floor(y/5 - 0.75) * 5; | |
if (x < 0 || x > width - 10 | |
|| y < 0 || y > height - 10) | |
return; | |
const xx = x % 10, yy = y % 10; | |
if (xx === yy) | |
return; | |
makeBlock(x - xx, y - yy, xx ? "#dh" : "#dv", cclass); | |
} | |
svg.addEventListener("mousedown", onClick, false); | |
function clear() { | |
while (cvs.firstChild !== null) | |
cvs.removeChild(cvs.firstChild); | |
} | |
dqs("#bclear").onclick = clear; | |
dqs("#btaclear").onclick = () => ta.value = ''; | |
function dump() { | |
const XMLS = new XMLSerializer(); | |
ta.value = XMLS.serializeToString(svg).replaceAll('><', '>\n<'); | |
ta.select(); | |
document.execCommand('copy'); | |
ta.selectionStart = ta.selectionEnd; | |
} | |
dqs("#bdump").onclick = dump; | |
function parseSVG(svgstr){ | |
const parser = new DOMParser(); | |
const doc2 = parser.parseFromString(svgstr, 'image/svg+xml'); | |
const errorNode = doc2.querySelector('parsererror'); | |
if (errorNode) { | |
alert('Input is not SVG!'); | |
return null; | |
} | |
else { | |
return doc2.documentElement; | |
} | |
} | |
function fetch() { | |
const s = ta.value; | |
const el = parseSVG(s); | |
if (el === null) return; | |
const src = el.querySelector("#cvs"); | |
if (src === null) | |
alert('Invalid SVG input'); | |
else | |
cvs.append(...src.children); | |
} | |
dqs("#bfetch").onclick = fetch; | |
})(); | |
</script> | |
</html> |
This file contains hidden or 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
''' Domino tiling | |
Fill a rectangular grid with dominoes | |
Use Knuth's Algorithm X for the exact cover problem, | |
using dicts instead of doubly linked circular lists. | |
Algorithm X code written by Ali Assaf | |
From http://www.cs.mcgill.ca/~aassaf9/python/algorithm_x.html | |
and http://www.cs.mcgill.ca/~aassaf9/python/sudoku.txt | |
See http://math.stackexchange.com/q/1580934/207316 | |
Written by PM 2Ring 2016.01.20 | |
Added SVG output 2023.08.05 | |
''' | |
from itertools import product | |
from collections import Counter | |
from time import sleep | |
# Algorithm X functions | |
def solve(X, Y, solution): | |
if not X: | |
yield list(solution) | |
else: | |
c = min(X, key=lambda c: len(X[c])) | |
for r in list(X[c]): | |
solution.append(r) | |
cols = select(X, Y, r) | |
yield from solve(X, Y, solution) | |
deselect(X, Y, r, cols) | |
solution.pop() | |
def select(X, Y, r): | |
cols = [] | |
for j in Y[r]: | |
for i in X[j]: | |
for k in Y[i]: | |
if k != j: | |
X[k].remove(i) | |
cols.append(X.pop(j)) | |
return cols | |
def deselect(X, Y, r, cols): | |
for j in reversed(Y[r]): | |
X[j] = cols.pop() | |
for i in X[j]: | |
for k in Y[i]: | |
if k != j: | |
X[k].add(i) | |
# Invert subset collection | |
def exact_cover(X, Y): | |
newX = {j: set() for j in X} | |
for i, row in Y.items(): | |
for j in row: | |
newX[j].add(i) | |
return newX | |
#---------------------------------------------------------------------- | |
# Solve domino puzzle | |
def fill_grid(width, height, init=[]): | |
# Set to cover | |
X = product(range(width), range(height)) | |
# Subsets to cover X with. Dominoes in both orientations at each grid location | |
Y = {} | |
# Horizontal | |
for x, y in product(range(width - 1), range(height)): | |
Y[(x, y, 'h')] = [(x, y), (x + 1, y)] | |
# Vertical | |
for x, y in product(range(width), range(height - 1)): | |
Y[(x, y, 'v')] = [(x, y), (x, y + 1)] | |
# Invert subset collection | |
X = exact_cover(X, Y) | |
for s in init: | |
select(X, Y, s) | |
for s in solve(X, Y, []): | |
yield s + init | |
# Convert domino tuple list into grid form | |
def doms_to_grid(doms, width, height): | |
grid = [[0] * width for _ in range(height)] | |
for k, (x, y, d) in enumerate(doms): | |
grid[y][x] = k | |
grid[y + (d == 'v')][x + (d == 'h')] = k | |
return grid | |
#---------------------------------------------------------------------- | |
# Color a graph given its nodes and edges | |
def color_map(nodes, edges, ncolors=4): | |
colors = range(ncolors) | |
# The edges that meet each node | |
node_edges = {n: set() for n in nodes} | |
for e in edges: | |
n0, n1 = e | |
node_edges[n0].add(e) | |
node_edges[n1].add(e) | |
for n in nodes: | |
node_edges[n] = list(node_edges[n]) | |
# Set to cover | |
colored_edges = list(product(colors, edges)) | |
X = nodes + colored_edges | |
# Subsets to cover X with | |
Y = {} | |
# Primary rows | |
for n in nodes: | |
ne = node_edges[n] | |
for c in colors: | |
Y[(n, c)] = [n] + [(c, e) for e in ne] | |
# Dummy rows | |
for i, ce in enumerate(colored_edges): | |
Y[i] = [ce] | |
X = exact_cover(X, Y) | |
# Set first two nodes | |
soln = {nodes[0]: 0, nodes[1]: 1} | |
for s in soln.items(): | |
select(X, Y, s) | |
for s in solve(X, Y, []): | |
soln.update(u for u in s if not isinstance(u, int)) | |
yield soln | |
# Extract the nodes and edges from a grid | |
def gridtograph(grid): | |
gridheight = len(grid) | |
gridwidth = len(grid[0]) | |
# Find regions. | |
nodes = sorted({c for row in grid for c in row}) | |
#print('nodes =', nodes) | |
# Find neighbours | |
# Verticals | |
edges = set() | |
for y in range(gridheight): | |
for x in range(gridwidth - 1): | |
c0, c1 = grid[y][x], grid[y][x+1] | |
if c0 != c1 and (c1, c0) not in edges: | |
edges.add((c0, c1)) | |
# Horizontals | |
for y in range(gridheight - 1): | |
for x in range(gridwidth): | |
c0, c1 = grid[y][x], grid[y+1][x] | |
if c0 != c1 and (c1, c0) not in edges: | |
edges.add((c0, c1)) | |
edges = sorted(edges) | |
#print('edges =', edges) | |
return nodes, edges | |
def show_grid(grid, strwidth): | |
for row in grid: | |
print(' '.join([f'{k:0{strwidth}}' for k in row])) | |
print() | |
def faultlines(grid): | |
gridheight = len(grid) | |
gridwidth = len(grid[0]) | |
hlines = [y for y in range(gridheight - 1) | |
if all(grid[y][x] != grid[y+1][x] | |
for x in range(gridwidth))] | |
vlines = [x for x in range(gridwidth - 1) | |
if all(grid[y][x] != grid[y][x+1] | |
for y in range(gridheight))] | |
return tuple(hlines), tuple(vlines) | |
#---------------------------------------------------------------------- | |
# Domino grid in SVG | |
def domino(x, y, d, c): | |
return f'<use x="{x*10}" y="{y*10}" href="#d{d}" class="c{c}"/>' | |
def make_svg(blocks, width, height, scale=5): | |
palette = """<style> | |
.c0 {fill:#d81b60;} | |
.c1 {fill:#ffc107;} | |
.c2 {fill:#004d40;} | |
.c3 {fill:#1e88e5;} | |
</style>""" | |
w, h = 10 * width + 1, 10 * height + 1 | |
head = f"""\ | |
<svg xmlns="http://www.w3.org/2000/svg" | |
width="{scale*w}" height="{scale*h}" viewBox="0 0 {w} {h}"> | |
{palette} | |
<defs> | |
<pattern id="checks" patternUnits="userSpaceOnUse" width="20" height="20"> | |
<rect width="10" height="10" fill="#bbb"/> | |
<rect width="10" height="10" x="10" y="10" fill="#bbb"/> | |
</pattern> | |
<rect id="dh" width="20" height="10"/> | |
<rect id="dv" width="10" height="20"/> | |
</defs> | |
<g transform="translate(0.5, 0.5)"> | |
<g style="stroke:#444; stroke-width:1"> | |
<rect x="-0.5" y="-0.5" width="100%" height="100%" fill="#eee"/> | |
<rect x="-0.5" y="-0.5" width="100%" height="100%" fill="url(#checks)"/> | |
</g> | |
<g style="stroke:#333; stroke-linejoin:round; | |
stroke-width:0.5; stroke-opacity:0.7; fill-opacity:0.8" id="cvs"> | |
""" | |
blocks = "\n".join([domino(*args) for args in blocks]) | |
tail = "\n</g></g></svg>" | |
return f'{head}{blocks}{tail}' | |
def save_area(s): | |
return ( | |
f'<div><textarea cols=40 rows=20 wrap="off">{s}</textarea><br>' | |
'''<button onclick="(()=>{const ta=this.parentNode.firstElementChild; | |
ta.select();document.execCommand('copy'); | |
ta.selectionStart=ta.selectionEnd;})();"> | |
Copy</button></div>''') | |
#---------------------------------------------------------------------- | |
# Faultline counters | |
def keyfunc(t): | |
h, v = t | |
return (len(h) + len(v), len(h), len(v), h, v) | |
def count_lines(gen, width, height): | |
counter = Counter(faultlines(doms_to_grid(soln, width, height)) | |
for soln in gen) | |
keys = sorted(counter.keys(), key=keyfunc) | |
for k in keys: | |
print(*k, ':', counter[k]) | |
def numlines(t): | |
h, v = t | |
return len(h), len(v) | |
def keyfunc_cl(t): | |
h, v = t | |
return (h + v, h, v) | |
def count_numlines(gen, width, height): | |
counter = Counter(numlines(faultlines(doms_to_grid(soln, width, height))) | |
for soln in gen) | |
keys = sorted(counter.keys(), key=keyfunc_cl) | |
for k in keys: | |
print(k, ':', counter[k]) | |
def wins(t): | |
h, v = t | |
h, v = len(h), len(v) | |
return (h > v) - (h < v) | |
def count_wins(gen, width, height): | |
counter = Counter(wins(faultlines(doms_to_grid(soln, width, height))) | |
for soln in gen) | |
for k in (1, 0, -1): | |
print(f'{k:2}: {counter[k]}') | |
#%time k = sum(1 for _ in fill_grid(6, 6)) | |
#print(k) | |
# 6728, 248 ms | |
@interact | |
def _(txt=HtmlBox('Domino Tiling'), | |
width=6, height=6, scale=5, | |
colors=ExpressionBox('3, 0'), | |
counts=Selector([(None, None), | |
(count_lines, "lines"), | |
(count_numlines, "num_lines"), | |
(count_wins, "wins")], selector_type='radio'), | |
init=ExpressionBox(default='', width=32, height=3), | |
auto_update=False): | |
# Do simple color mapping if colors is a tuple, | |
# otherwise do | |
if isinstance(colors, tuple): | |
cmap = dict(zip('hv', colors)) | |
buttons = ['Next', 'Save'] | |
else: | |
cmap = None | |
buttons = ['Next', 'Recolor', 'Save'] | |
try: | |
init = list(init) | |
except TypeError: | |
init = [] | |
if counts: | |
gen = fill_grid(width, height, init) | |
counts(gen, width, height) | |
sleep(float(0.01)) | |
tiling_gen = enumerate(fill_grid(width, height, init), 1) | |
@interact | |
def main(cmd=ButtonBar(buttons, default='Next', label='')): | |
global cnt, soln, color_gen, svg, hlines, vlines | |
if cmd == 'Next': | |
try: | |
cnt, soln = next(tiling_gen) | |
except StopIteration: | |
print("No more tilings") | |
return | |
grid = doms_to_grid(soln, width, height) | |
hlines, vlines = faultlines(grid) | |
if not cmap: | |
#Find a coloring for this grid | |
nodes, edges = gridtograph(grid) | |
color_gen = color_map(nodes, edges, ncolors=colors) | |
elif cmd == 'Save': | |
show(html(f"<h3>{cnt}</h3><pre>{hlines}, {vlines}</pre>")) | |
show(html(svg)) | |
with open("domino.svg", "w") as f: | |
f.write(svg) | |
show(html(save_area(svg))) | |
return | |
if cmap: | |
blocks = [(x, y, d, cmap[d]) for x, y, d in soln] | |
else: | |
try: | |
colormap = next(color_gen) | |
except StopIteration: | |
print("No more colorings") | |
return | |
color_list = [colormap[i] for i in range(len(soln))] | |
blocks = [(*t, c) for t, c in zip(soln, color_list)] | |
svg = make_svg(blocks, width, height, scale) | |
#print(svg) | |
show(html(f"<h3>{cnt}</h3><pre>{hlines}, {vlines}</pre>")) | |
show(html(svg)) | |
## (0, 5, 'h'), (1, 4, 'h'), (2, 3, 'h') |
domino__1234.svg is the tiling corresponding to () (1, 2, 3, 4) : 1 in 6x6_faultlines.txt which is one of the combos contained in (0, 4): 5 in 6x6_faultline_counts.txt.
DominoGridMaker on SageMathCell.
DominoTiling on SageMathCell.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
6x6_faultlines.txt lists the faultline position stats for the 6×6 domino tilings.
(horizontal) (vertical) : number.
6x6_faultline_counts.txt summarises 6x6_faultlines.txt. It lists the number of tilings for each (horizontal line count, vertical line count) combination.