Pentomino tiling

You are encouraged to solve this task according to the task description, using any language you may know.
A pentomino is a polyomino that consists of 5 squares. There are 12 pentomino shapes, if you don't count rotations and reflections. Most pentominoes can form their own mirror image through rotation, but some of them have to be flipped over.
I I L N Y FF I L NN PP TTT V W X YY ZZ FF I L N PP T U U V WW XXX Y Z F I LL N P T UUU VVV WW X Y ZZ
A Pentomino tiling is an example of an exact cover problem and can take on many forms.
A traditional tiling presents an 8 by 8 grid, where 4 cells are left uncovered. The other cells are covered
by the 12 pentomino shapes, without overlaps, with every shape only used once.
The 4 uncovered cells should be chosen at random. Note that not all configurations are solvable.
- Task
Create an 8 by 8 tiling and print the result.
- Example
F I I I I I L N F F F L L L L N W F - X Z Z N N W W X X X Z N V T W W X - Z Z V T T T P P V V V T Y - P P U U U Y Y Y Y P U - U
- Related tasks
11l
F nonrandom(n)
UInt32 :seed = 0
:seed = 1664525 * :seed + 1013904223
R (:seed >> 16) % n
-V
SF = [[1, -1, 1, 0, 1, 1, 2, 1], [0, 1, 1, -1, 1, 0, 2, 0],
[1, 0, 1, 1, 1, 2, 2, 1], [1, 0, 1, 1, 2, -1, 2, 0],
[1, -2, 1, -1, 1, 0, 2, -1], [0, 1, 1, 1, 1, 2, 2, 1],
[1, -1, 1, 0, 1, 1, 2, -1], [1, -1, 1, 0, 2, 0, 2, 1]]
SI = [[0, 1, 0, 2, 0, 3, 0, 4], [1, 0, 2, 0, 3, 0, 4, 0]]
SL = [[1, 0, 1, 1, 1, 2, 1, 3], [1, 0, 2, 0, 3, -1, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 3], [0, 1, 1, 0, 2, 0, 3, 0],
[0, 1, 1, 1, 2, 1, 3, 1], [0, 1, 0, 2, 0, 3, 1, 0],
[1, 0, 2, 0, 3, 0, 3, 1], [1, -3, 1, -2, 1, -1, 1, 0]]
SN = [[0, 1, 1, -2, 1, -1, 1, 0], [1, 0, 1, 1, 2, 1, 3, 1],
[0, 1, 0, 2, 1, -1, 1, 0], [1, 0, 2, 0, 2, 1, 3, 1],
[0, 1, 1, 1, 1, 2, 1, 3], [1, 0, 2, -1, 2, 0, 3, -1],
[0, 1, 0, 2, 1, 2, 1, 3], [1, -1, 1, 0, 2, -1, 3, -1]]
SP = [[0, 1, 1, 0, 1, 1, 2, 1], [0, 1, 0, 2, 1, 0, 1, 1],
[1, 0, 1, 1, 2, 0, 2, 1], [0, 1, 1, -1, 1, 0, 1, 1],
[0, 1, 1, 0, 1, 1, 1, 2], [1, -1, 1, 0, 2, -1, 2, 0],
[0, 1, 0, 2, 1, 1, 1, 2], [0, 1, 1, 0, 1, 1, 2, 0]]
ST = [[0, 1, 0, 2, 1, 1, 2, 1], [1, -2, 1, -1, 1, 0, 2, 0],
[1, 0, 2, -1, 2, 0, 2, 1], [1, 0, 1, 1, 1, 2, 2, 0]]
SU = [[0, 1, 0, 2, 1, 0, 1, 2], [0, 1, 1, 1, 2, 0, 2, 1],
[0, 2, 1, 0, 1, 1, 1, 2], [0, 1, 1, 0, 2, 0, 2, 1]]
SV = [[1, 0, 2, 0, 2, 1, 2, 2], [0, 1, 0, 2, 1, 0, 2, 0],
[1, 0, 2, -2, 2, -1, 2, 0], [0, 1, 0, 2, 1, 2, 2, 2]]
SW = [[1, 0, 1, 1, 2, 1, 2, 2], [1, -1, 1, 0, 2, -2, 2, -1],
[0, 1, 1, 1, 1, 2, 2, 2], [0, 1, 1, -1, 1, 0, 2, -1]]
SX = [[1, -1, 1, 0, 1, 1, 2, 0]]
SY = [[1, -2, 1, -1, 1, 0, 1, 1], [1, -1, 1, 0, 2, 0, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 1], [1, 0, 2, 0, 2, 1, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 2], [1, 0, 1, 1, 2, 0, 3, 0],
[1, -1, 1, 0, 1, 1, 1, 2], [1, 0, 2, -1, 2, 0, 3, 0]]
SZ = [[0, 1, 1, 0, 2, -1, 2, 0], [1, 0, 1, 1, 1, 2, 2, 2],
[0, 1, 1, 1, 2, 1, 2, 2], [1, -2, 1, -1, 1, 0, 2, -2]]
Shapes = [SF, SI, SL, SN, SP, ST, SU, SV, SW, SX, SY, SZ]
Symbols = Array(‘FILNPTUVWXYZ-’)
NRows = 8
NCols = 8
Blank = Shapes.len
T Tiling
[[[Int]]] shapes
[Char] symbols
[[Int]] grid
[Bool] placed
F ()
V indexes = [4, 6, 11, 7, 10, 3, 9, 5, 1, 8, 0, 2]
L(index) indexes
.shapes.append(Shapes[index])
.symbols.append(Symbols[index])
.symbols.append(Symbols.last)
.grid = [[-1] * NCols] * NRows
L 4
L
V randRow = nonrandom(NRows)
V randCol = nonrandom(NCols)
I .grid[randRow][randCol] != Blank
.grid[randRow][randCol] = Blank
L.break
.placed = [0B] * Shapes.len
F tryPlaceOrientation(o, r, c, shapeIndex)
L(i) (0 .< o.len).step(2)
V x = c + o[i + 1]
V y = r + o[i]
I x !C 0 .< NCols | y !C 0 .< NRows | .grid[y][x] != -1
R 0B
.grid[r][c] = shapeIndex
L(i) (0 .< o.len).step(2)
.grid[r + o[i]][c + o[i + 1]] = shapeIndex
R 1B
F removeOrientation(o, r, c)
.grid[r][c] = -1
L(i) (0 .< o.len).step(2)
.grid[r + o[i]][c + o[i + 1]] = -1
F solve(pos, numPlaced)
I numPlaced == .shapes.len
R 1B
V row = pos I/ NCols
V col = pos % NCols
I .grid[row][col] != -1
R .solve(pos + 1, numPlaced)
L(i) 0 .< .shapes.len
I !.placed[i]
L(orientation) .shapes[i]
I !.tryPlaceOrientation(orientation, row, col, i)
L.continue
.placed[i] = 1B
I .solve(pos + 1, numPlaced + 1)
R 1B
.removeOrientation(orientation, row, col)
.placed[i] = 0B
R 0B
F printResult()
L(r) .grid
print(r.map(i -> @.symbols[i]).join(‘ ’))
V tiling = Tiling()
I tiling.solve(0, 0)
tiling.printResult()
E
print(‘No solution’)
- Output:
P P U U U V V V P P U X U L L V T P X X X L - V T T T X F L Z Z T - F F F L Z Y N N N F W Z Z Y - - N N W W Y Y I I I I I W W Y
BASIC
FreeBASIC
With corner characters.
Const nRows As Integer = 8
Const nCols As Integer = 8
Const target As Integer = 12
Const blank As Integer = 12
Dim Shared symbols As String
symbols = "XYPFTVNLUZWI-"
Dim Shared grid(nRows - 1, nCols - 1) As Integer
Dim Shared As Integer pens(63, 7)
Dim seeds(11) As Integer = {291, 292, 293, 295, 297, 329, 330, 332, 333, 335, 378, 586}
Function Puzzle(a As String, b As String) As String
Dim res As String = ""
If Len(a) > Len(b) Then b &= Space(Len(a) - Len(b))
If Len(a) < Len(b) Then a &= Space(Len(b) - Len(a))
For i As Integer = 0 To Len(a) - 2
Dim As String cad = " 12"&chr(192)&"4"&chr(217)&chr(196)&chr(193)&"8"&chr(179)&chr(218)&chr(195)&chr(191)&chr(180)&chr(194)&chr(197)
res &= Mid(cad, (Iif(Mid(a, i + 1, 1) = Mid(a, i + 2, 1), 0, 1) + _
Iif(Mid(b, i + 2, 1) = Mid(a, i + 2, 1), 0, 2) + _
Iif(Mid(a, i + 1, 1) = Mid(b, i + 1, 1), 0, 4) + _
Iif(Mid(b, i + 1, 1) = Mid(b, i + 2, 1), 0, 8)) + 1, 1)
Next
Return res
End Function
Function Cornered(s As String) As String
Dim As String lines(100), res, linea, last
Dim As Integer lineCount, start, posic, i
lineCount = 0
start = 1
posic = Instr(start, s, Chr(10))
While posic > 0
lines(lineCount) = Mid(s, start, posic - start)
lineCount += 1
start = posic + 1
posic = Instr(start, s, Chr(10))
Wend
lines(lineCount) = Mid(s, start)
lineCount += 1
res = ""
linea = Space(Len(lines(0)) + 1)
For i = 0 To lineCount - 1
last = linea
linea = " " & lines(i)
res &= Puzzle(last, linea) & Chr(10)
Next
Return res & Puzzle(linea, Space(Len(lines(lineCount - 1)) + 1))
End Function
Function TPO(ori() As Integer, Byval row As Integer, Byval col As Integer, Byval sIdx As Integer) As Boolean
Dim As Integer i, x, y
For i = 0 To Ubound(ori) Step 2
x = col + ori(i + 1)
y = row + ori(i)
If x < 0 Or x >= nCols Or y < 0 Or y >= nRows Or grid(y, x) <> -1 Then Return False
Next
grid(row, col) = sIdx
For i = 0 To Ubound(ori) Step 2
grid(row + ori(i), col + ori(i + 1)) = sIdx
Next
Return True
End Function
Sub ShuffleShapes(count As Integer)
Dim As Integer i, j, r, k
For i = 0 To count
For j = 0 To Ubound(pens, 1)
Do
r = Int(Rnd * (Ubound(pens, 1) + 1))
Loop Until r <> j
For k = 0 To Ubound(pens, 2)
'Dim tmp As Integer = pens(r, k)
Swap pens(r, k), pens(j, k)
'pens(j, k) = tmp
Next
Dim ch As String = Mid(symbols, r + 1, 1)
Mid(symbols, r + 1, 1) = Mid(symbols, j + 1, 1)
Mid(symbols, j + 1, 1) = ch
Next
Next
End Sub
Function DW(s As String) As String
Dim result As String = ""
For i As Integer = 1 To Len(s)
Dim ch As String = Mid(s, i, 1)
result &= ch & Iif(ch = Chr(10), "", ch)
Next
Return result
End Function
Sub PrintResult()
Dim res As String = ""
For r As Integer = 0 To nRows - 1
For c As Integer = 0 To nCols - 1
res &= Iif(grid(r, c) < 0, ".", Mid(symbols, grid(r, c) + 1, 1))
Next
res &= " " & Chr(10)
Next
Print Cornered(DW(res))
End Sub
Sub RmvO(ori() As Integer, Byval row As Integer, Byval col As Integer)
grid(row, col) = -1
For i As Integer = 0 To Ubound(ori) Step 2
grid(row + ori(i), col + ori(i + 1)) = -1
Next
End Sub
Sub Expand(i As Integer, result() As Integer)
result(0) = 0
For j As Integer = 0 To 3
result(4 - j) = i And 15
i Shr= 4
Next
End Sub
Sub Sort(arr() As Integer)
Dim As Integer n, i, j
n = Ubound(arr)
For i = 0 To n - 1
For j = 0 To n - i - 1
If arr(j) > arr(j + 1) Then Swap arr(j), arr(j + 1)
Next
Next
End Sub
Sub ToP(p() As Integer, res() As Integer)
Dim As Integer tmp(4), i, item, adj
tmp(0) = 0
For i = 1 To 4
item = p(i)
Select Case (item And 3)
Case 0
tmp(i) = tmp(item \ 4) + 1
Case 1
tmp(i) = tmp(item \ 4) + 8
Case 2
tmp(i) = tmp(item \ 4) - 1
Case 3
tmp(i) = tmp(item \ 4) - 8
End Select
Next
Sort(tmp())
For i = 4 To 1 Step -1
tmp(i) -= tmp(0)
Next
For i = 1 To 4
item = tmp(i)
adj = Iif((item And 7) > 4, 8, 0)
res(2 * (i - 1)) = (adj + item) \ 8
res(2 * (i - 1) + 1) = (item And 7) - adj
Next
End Sub
Sub Rot(p() As Integer)
For i As Integer = 0 To Ubound(p)
p(i) = (p(i) And -4) Or ((p(i) + 1) And 3)
Next
End Sub
Sub Mir(p() As Integer)
For i As Integer = 0 To Ubound(p)
p(i) = (p(i) And -4) Or (((p(i) Xor 1) + 1) And 3)
Next
End Sub
Sub Unpack(sv() As Integer)
Dim As Integer idx, item, i, j, k, l
Dim As Boolean exists, same
idx = 0
For i = 0 To Ubound(sv)
item = sv(i)
Dim exi(3) As Integer
Expand(item, exi())
Dim fx(7) As Integer
ToP(exi(), fx())
For j = 0 To 7
pens(idx, j) = fx(j)
Next
idx += 1
For j = 1 To 7
If j = 4 Then
Mir(exi())
Else
Rot(exi())
End If
ToP(exi(), fx())
exists = False
For k = 0 To idx - 1
same = True
For l = 0 To 7
If pens(k, l) <> fx(l) Then
same = False
Exit For
End If
Next
If same Then
exists = True
Exit For
End If
Next
If Not exists Then
For l = 0 To 7
pens(idx, l) = fx(l)
Next
idx += 1
End If
Next
Next
End Sub
Function TheSame(a() As Integer, b() As Integer) As Boolean
For i As Integer = 0 To Ubound(a)
If a(i) <> b(i) Then Return False
Next
Return True
End Function
Function Solve(Byval posic As Integer, Byval numPlaced As Integer) As Boolean
Dim placed(target - 1) As Boolean
If numPlaced = target Then Return True
Dim As Integer row, col, i, j, k, orientation(7)
row = posic \ nCols
col = posic Mod nCols
If grid(row, col) <> -1 Then Return Solve(posic + 1, numPlaced)
For i = 0 To Ubound(pens, 1)
If Not placed(i) Then
For j = 0 To Ubound(pens, 2)
For k = 0 To 7
orientation(k) = pens(i, k)
Next
If Not TPO(orientation(), row, col, i) Then Continue For
placed(i) = True
If Solve(posic + 1, numPlaced + 1) Then Return True
RmvO(orientation(), row, col)
placed(i) = False
Next
End If
Next
Return False
End Function
'--- Main program ---
Unpack(seeds())
Randomize Timer
ShuffleShapes(2)
Dim As Integer r, c
For r = 0 To nRows - 1
For c = 0 To nCols - 1
grid(r, c) = -1
Next
Next
Dim As Integer rRow, rCol
For r = 0 To 3
Do
rRow = Int(Rnd * nRows)
rCol = Int(Rnd * nCols)
Loop While grid(rRow, rCol) = blank
grid(rRow, rCol) = blank
Next
If Solve(0, 0) Then
PrintResult()
Else
Print "no solution for this configuration:"
PrintResult()
End If
Sleep
Visual Basic .NET
via
Instead of having a large declaration for each rotation of each pentomino, a small array of encoded positions is supplied (seeds), and it is expanded into the set of 63 possible orientations. However, the additional expansion routines code does take up about 2/3 of the space that would have been taken by the elaborate Integer array definitions.
Module Module1
Dim symbols As Char() = "XYPFTVNLUZWI█".ToCharArray(),
nRows As Integer = 8, nCols As Integer = 8,
target As Integer = 12, blank As Integer = 12,
grid As Integer()() = New Integer(nRows - 1)() {},
placed As Boolean() = New Boolean(target - 1) {},
pens As List(Of List(Of Integer())), rand As Random,
seeds As Integer() = {291, 292, 293, 295, 297, 329, 330, 332, 333, 335, 378, 586}
Sub Main()
Unpack(seeds) : rand = New Random() : ShuffleShapes(2)
For r As Integer = 0 To nRows - 1
grid(r) = Enumerable.Repeat(-1, nCols).ToArray() : Next
For i As Integer = 0 To 3
Dim rRow, rCol As Integer : Do : rRow = rand.Next(nRows) : rCol = rand.Next(nCols)
Loop While grid(rRow)(rCol) = blank : grid(rRow)(rCol) = blank
Next
If Solve(0, 0) Then
PrintResult()
Else
Console.WriteLine("no solution for this configuration:") : PrintResult()
End If
If System.Diagnostics.Debugger.IsAttached Then Console.ReadKey()
End Sub
Sub ShuffleShapes(count As Integer) ' changes order of the pieces for a more random solution
For i As Integer = 0 To count : For j = 0 To pens.Count - 1
Dim r As Integer : Do : r = rand.Next(pens.Count) : Loop Until r <> j
Dim tmp As List(Of Integer()) = pens(r) : pens(r) = pens(j) : pens(j) = tmp
Dim ch As Char = symbols(r) : symbols(r) = symbols(j) : symbols(j) = ch
Next : Next
End Sub
Sub PrintResult() ' display results
For Each r As Integer() In grid : For Each i As Integer In r
Console.Write("{0} ", If(i < 0, ".", symbols(i)))
Next : Console.WriteLine() : Next
End Sub
' returns first found solution only
Function Solve(ByVal pos As Integer, ByVal numPlaced As Integer) As Boolean
If numPlaced = target Then Return True
Dim row As Integer = pos \ nCols, col As Integer = pos Mod nCols
If grid(row)(col) <> -1 Then Return Solve(pos + 1, numPlaced)
For i As Integer = 0 To pens.Count - 1 : If Not placed(i) Then
For Each orientation As Integer() In pens(i)
If Not TPO(orientation, row, col, i) Then Continue For
placed(i) = True : If Solve(pos + 1, numPlaced + 1) Then Return True
RmvO(orientation, row, col) : placed(i) = False
Next : End If : Next : Return False
End Function
' removes a placed orientation
Sub RmvO(ByVal ori As Integer(), ByVal row As Integer, ByVal col As Integer)
grid(row)(col) = -1 : For i As Integer = 0 To ori.Length - 1 Step 2
grid(row + ori(i))(col + ori(i + 1)) = -1 : Next
End Sub
' checks an orientation, if possible it is placed, else returns false
Function TPO(ByVal ori As Integer(), ByVal row As Integer, ByVal col As Integer,
ByVal sIdx As Integer) As Boolean
For i As Integer = 0 To ori.Length - 1 Step 2
Dim x As Integer = col + ori(i + 1), y As Integer = row + ori(i)
If x < 0 OrElse x >= nCols OrElse y < 0 OrElse y >= nRows OrElse
grid(y)(x) <> -1 Then Return False
Next : grid(row)(col) = sIdx
For i As Integer = 0 To ori.Length - 1 Step 2
grid(row + ori(i))(col + ori(i + 1)) = sIdx
Next : Return True
End Function
'!' the following routines expand the seed values into the 63 orientation arrays.
' source code space savings comparison:
' around 2000 chars for the expansion code, verses about 3000 chars for the integer array defs.
' perhaps not worth the savings?
Sub Unpack(sv As Integer()) ' unpacks a list of seed values into a set of 63 rotated pentominoes
pens = New List(Of List(Of Integer())) : For Each item In sv
Dim Gen As New List(Of Integer()), exi As List(Of Integer) = Expand(item),
fx As Integer() = ToP(exi) : Gen.Add(fx) : For i As Integer = 1 To 7
If i = 4 Then Mir(exi) Else Rot(exi)
fx = ToP(exi) : If Not Gen.Exists(Function(Red) TheSame(Red, fx)) Then Gen.Add(ToP(exi))
Next : pens.Add(Gen) : Next
End Sub
' expands an integer into a set of directions
Function Expand(i As Integer) As List(Of Integer)
Expand = {0}.ToList() : For j As Integer = 0 To 3 : Expand.Insert(1, i And 15) : i >>= 4 : Next
End Function
' converts a set of directions to an array of y, x pairs
Function ToP(p As List(Of Integer)) As Integer()
Dim tmp As List(Of Integer) = {0}.ToList() : For Each item As Integer In p.Skip(1)
tmp.Add(tmp.Item(item >> 2) + {1, 8, -1, -8}(item And 3)) : Next
tmp.Sort() : For i As Integer = tmp.Count - 1 To 0 Step -1 : tmp.Item(i) -= tmp.Item(0) : Next
Dim res As New List(Of Integer) : For Each item In tmp.Skip(1)
Dim adj = If((item And 7) > 4, 8, 0)
res.Add((adj + item) \ 8) : res.Add((item And 7) - adj)
Next : Return res.ToArray()
End Function
' compares integer arrays for equivalency
Function TheSame(a As Integer(), b As Integer()) As Boolean
For i As Integer = 0 To a.Count - 1 : If a(i) <> b(i) Then Return False
Next : Return True
End Function
Sub Rot(ByRef p As List(Of Integer)) ' rotates a set of directions by 90 degrees
For i As Integer = 0 To p.Count - 1 : p(i) = (p(i) And -4) Or ((p(i) + 1) And 3) : Next
End Sub
Sub Mir(ByRef p As List(Of Integer)) ' mirrors a set of directions
For i As Integer = 0 To p.Count - 1 : p(i) = (p(i) And -4) Or (((p(i) Xor 1) + 1) And 3) : Next
End Sub
End Module
- Output:
Solution found result (typical output):
Y F F █ L L L L Y Y F F L P P P Y T F N N N P P Y T N N █ V V V T T T W W Z Z V U U X █ W W Z V U X X X █ W Z Z U U X I I I I I
Impossible to solve result (a somewhat rare occurrence):
no solution for this configuration: . █ . . . . . . █ . . █ . . . . . . . . . . . . . . . . █ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
VB .NET alternative output (corner characters)
This output may appear better in a command window Try it online!
- Output:
Solution found result (typical output):
┌─────┬─────┬─┬─┐ │ ┌─┐ ├─┐ │ │ │ ├─┼─┴─┴─┴─┬─┘ │ │ │ └───┬─┐ │ ┌─┤ │ │ ┌───┼─┼─┴─┘ │ │ ├─┘ ┌─┘ └─┐ ┌─┼─┤ │ ┌─┼─┐ ┌─┴─┘ │ │ ├─┴─┘ └─┤ ┌───┘ │ └───────┴─┴─────┘
Impossible to solve result (a somewhat rare occurrence):
no solution for this configuration: ┌─┬─┬─┬─┬───────┐ │ └─┘ └─┘ │ │ ┌─┐ │ ├─┼─┘ │ ├─┘ │ │ │ │ │ │ │ └───────────────┘
C#
using System;
using System.Linq;
namespace PentominoTiling
{
class Program
{
static readonly char[] symbols = "FILNPTUVWXYZ-".ToCharArray();
static readonly int nRows = 8;
static readonly int nCols = 8;
static readonly int target = 12;
static readonly int blank = 12;
static int[][] grid = new int[nRows][];
static bool[] placed = new bool[target];
static void Main(string[] args)
{
var rand = new Random();
for (int r = 0; r < nRows; r++)
grid[r] = Enumerable.Repeat(-1, nCols).ToArray();
for (int i = 0; i < 4; i++)
{
int randRow, randCol;
do
{
randRow = rand.Next(nRows);
randCol = rand.Next(nCols);
}
while (grid[randRow][randCol] == blank);
grid[randRow][randCol] = blank;
}
if (Solve(0, 0))
{
PrintResult();
}
else
{
Console.WriteLine("no solution");
}
Console.ReadKey();
}
private static void PrintResult()
{
foreach (int[] r in grid)
{
foreach (int i in r)
Console.Write("{0} ", symbols[i]);
Console.WriteLine();
}
}
private static bool Solve(int pos, int numPlaced)
{
if (numPlaced == target)
return true;
int row = pos / nCols;
int col = pos % nCols;
if (grid[row][col] != -1)
return Solve(pos + 1, numPlaced);
for (int i = 0; i < shapes.Length; i++)
{
if (!placed[i])
{
foreach (int[] orientation in shapes[i])
{
if (!TryPlaceOrientation(orientation, row, col, i))
continue;
placed[i] = true;
if (Solve(pos + 1, numPlaced + 1))
return true;
RemoveOrientation(orientation, row, col);
placed[i] = false;
}
}
}
return false;
}
private static void RemoveOrientation(int[] orientation, int row, int col)
{
grid[row][col] = -1;
for (int i = 0; i < orientation.Length; i += 2)
grid[row + orientation[i]][col + orientation[i + 1]] = -1;
}
private static bool TryPlaceOrientation(int[] orientation, int row, int col, int shapeIndex)
{
for (int i = 0; i < orientation.Length; i += 2)
{
int x = col + orientation[i + 1];
int y = row + orientation[i];
if (x < 0 || x >= nCols || y < 0 || y >= nRows || grid[y][x] != -1)
return false;
}
grid[row][col] = shapeIndex;
for (int i = 0; i < orientation.Length; i += 2)
grid[row + orientation[i]][col + orientation[i + 1]] = shapeIndex;
return true;
}
// four (x, y) pairs are listed, (0,0) not included
static readonly int[][] F = {
new int[] {1, -1, 1, 0, 1, 1, 2, 1}, new int[] {0, 1, 1, -1, 1, 0, 2, 0},
new int[] {1, 0, 1, 1, 1, 2, 2, 1}, new int[] {1, 0, 1, 1, 2, -1, 2, 0},
new int[] {1, -2, 1, -1, 1, 0, 2, -1}, new int[] {0, 1, 1, 1, 1, 2, 2, 1},
new int[] {1, -1, 1, 0, 1, 1, 2, -1}, new int[] {1, -1, 1, 0, 2, 0, 2, 1}};
static readonly int[][] I = {
new int[] { 0, 1, 0, 2, 0, 3, 0, 4 }, new int[] { 1, 0, 2, 0, 3, 0, 4, 0 } };
static readonly int[][] L = {
new int[] {1, 0, 1, 1, 1, 2, 1, 3}, new int[] {1, 0, 2, 0, 3, -1, 3, 0},
new int[] {0, 1, 0, 2, 0, 3, 1, 3}, new int[] {0, 1, 1, 0, 2, 0, 3, 0},
new int[] {0, 1, 1, 1, 2, 1, 3, 1}, new int[] {0, 1, 0, 2, 0, 3, 1, 0},
new int[] {1, 0, 2, 0, 3, 0, 3, 1}, new int[] {1, -3, 1, -2, 1, -1, 1, 0}};
static readonly int[][] N = {
new int[] {0, 1, 1, -2, 1, -1, 1, 0}, new int[] {1, 0, 1, 1, 2, 1, 3, 1},
new int[] {0, 1, 0, 2, 1, -1, 1, 0}, new int[] {1, 0, 2, 0, 2, 1, 3, 1},
new int[] {0, 1, 1, 1, 1, 2, 1, 3}, new int[] {1, 0, 2, -1, 2, 0, 3, -1},
new int[] {0, 1, 0, 2, 1, 2, 1, 3}, new int[] {1, -1, 1, 0, 2, -1, 3, -1}};
static readonly int[][] P = {
new int[] {0, 1, 1, 0, 1, 1, 2, 1}, new int[] {0, 1, 0, 2, 1, 0, 1, 1},
new int[] {1, 0, 1, 1, 2, 0, 2, 1}, new int[] {0, 1, 1, -1, 1, 0, 1, 1},
new int[] {0, 1, 1, 0, 1, 1, 1, 2}, new int[] {1, -1, 1, 0, 2, -1, 2, 0},
new int[] {0, 1, 0, 2, 1, 1, 1, 2}, new int[] {0, 1, 1, 0, 1, 1, 2, 0}};
static readonly int[][] T = {
new int[] {0, 1, 0, 2, 1, 1, 2, 1}, new int[] {1, -2, 1, -1, 1, 0, 2, 0},
new int[] {1, 0, 2, -1, 2, 0, 2, 1}, new int[] {1, 0, 1, 1, 1, 2, 2, 0}};
static readonly int[][] U = {
new int[] {0, 1, 0, 2, 1, 0, 1, 2}, new int[] {0, 1, 1, 1, 2, 0, 2, 1},
new int[] {0, 2, 1, 0, 1, 1, 1, 2}, new int[] {0, 1, 1, 0, 2, 0, 2, 1}};
static readonly int[][] V = {
new int[] {1, 0, 2, 0, 2, 1, 2, 2}, new int[] {0, 1, 0, 2, 1, 0, 2, 0},
new int[] {1, 0, 2, -2, 2, -1, 2, 0}, new int[] {0, 1, 0, 2, 1, 2, 2, 2}};
static readonly int[][] W = {
new int[] {1, 0, 1, 1, 2, 1, 2, 2}, new int[] {1, -1, 1, 0, 2, -2, 2, -1},
new int[] {0, 1, 1, 1, 1, 2, 2, 2}, new int[] {0, 1, 1, -1, 1, 0, 2, -1}};
static readonly int[][] X = { new int[] { 1, -1, 1, 0, 1, 1, 2, 0 } };
static readonly int[][] Y = {
new int[] {1, -2, 1, -1, 1, 0, 1, 1}, new int[] {1, -1, 1, 0, 2, 0, 3, 0},
new int[] {0, 1, 0, 2, 0, 3, 1, 1}, new int[] {1, 0, 2, 0, 2, 1, 3, 0},
new int[] {0, 1, 0, 2, 0, 3, 1, 2}, new int[] {1, 0, 1, 1, 2, 0, 3, 0},
new int[] {1, -1, 1, 0, 1, 1, 1, 2}, new int[] {1, 0, 2, -1, 2, 0, 3, 0}};
static readonly int[][] Z = {
new int[] {0, 1, 1, 0, 2, -1, 2, 0}, new int[] {1, 0, 1, 1, 1, 2, 2, 2},
new int[] {0, 1, 1, 1, 2, 1, 2, 2}, new int[] {1, -2, 1, -1, 1, 0, 2, -2}};
static readonly int[][][] shapes = { F, I, L, N, P, T, U, V, W, X, Y, Z };
}
}
I N F F - - L L I N N F F P P L I - N F W P P L I Y N W W X P L I Y W W X X X - Y Y T T T X Z V U Y U T Z Z Z V U U U T Z V V V
C++
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <random>
#include <vector>
const std::vector<std::vector<int32_t>> F = { { 1, -1, 1, 0, 1, 1, 2, 1 }, { 0, 1, 1, -1, 1, 0, 2, 0 },
{ 1, 0, 1, 1, 1, 2, 2, 1 }, { 1, 0, 1, 1, 2, -1, 2, 0 }, { 1, -2, 1, -1, 1, 0, 2, -1 },
{ 0, 1, 1, 1, 1, 2, 2, 1 }, { 1, -1, 1, 0, 1, 1, 2, -1 }, { 1, -1, 1, 0, 2, 0, 2, 1 } };
const std::vector<std::vector<int32_t>> I = { { 0, 1, 0, 2, 0, 3, 0, 4 }, { 1, 0, 2, 0, 3, 0, 4, 0 } };
const std::vector<std::vector<int32_t>> L = { { 1, 0, 1, 1, 1, 2, 1, 3 }, { 1, 0, 2, 0, 3, -1, 3, 0 },
{ 0, 1, 0, 2, 0, 3, 1, 3 }, { 0, 1, 1, 0, 2, 0, 3, 0 }, { 0, 1, 1, 1, 2, 1, 3, 1 },
{ 0, 1, 0, 2, 0, 3, 1, 0 }, { 1, 0, 2, 0, 3, 0, 3, 1 }, { 1, -3, 1, -2, 1, -1, 1, 0 } };
const std::vector<std::vector<int32_t>> N = { { 0, 1, 1, -2, 1, -1, 1, 0 }, { 1, 0, 1, 1, 2, 1, 3, 1 },
{ 0, 1, 0, 2, 1, -1, 1, 0 }, { 1, 0, 2, 0, 2, 1, 3, 1 }, { 0, 1, 1, 1, 1, 2, 1, 3 },
{ 1, 0, 2, -1, 2, 0, 3, -1 }, { 0, 1, 0, 2, 1, 2, 1, 3 }, { 1, -1, 1, 0, 2, -1, 3, -1 } };
const std::vector<std::vector<int32_t>> P = { { 0, 1, 1, 0, 1, 1, 2, 1 }, { 0, 1, 0, 2, 1, 0, 1, 1 },
{ 1, 0, 1, 1, 2, 0, 2, 1 }, { 0, 1, 1, -1, 1, 0, 1, 1 }, { 0, 1, 1, 0, 1, 1, 1, 2 },
{ 1, -1, 1, 0, 2, -1, 2, 0 }, { 0, 1, 0, 2, 1, 1, 1, 2 }, { 0, 1, 1, 0, 1, 1, 2, 0 } };
const std::vector<std::vector<int32_t>> T = { { 0, 1, 0, 2, 1, 1, 2, 1 }, { 1, -2, 1, -1, 1, 0, 2, 0 },
{ 1, 0, 2, -1, 2, 0, 2, 1 }, { 1, 0, 1, 1, 1, 2, 2, 0 } };
const std::vector<std::vector<int32_t>> U = { { 0, 1, 0, 2, 1, 0, 1, 2 }, { 0, 1, 1, 1, 2, 0, 2, 1 },
{ 0, 2, 1, 0, 1, 1, 1, 2 }, { 0, 1, 1, 0, 2, 0, 2, 1 } };
const std::vector<std::vector<int32_t>> V = { { 1, 0, 2, 0, 2, 1, 2, 2 }, { 0, 1, 0, 2, 1, 0, 2, 0 },
{ 1, 0, 2, -2, 2, -1, 2, 0 }, { 0, 1, 0, 2, 1, 2, 2, 2 } };
const std::vector<std::vector<int32_t>> W = { { 1, 0, 1, 1, 2, 1, 2, 2 }, { 1, -1, 1, 0, 2, -2, 2, -1 },
{ 0, 1, 1, 1, 1, 2, 2, 2 }, { 0, 1, 1, -1, 1, 0, 2, -1 } };
const std::vector<std::vector<int32_t>> X = { { 1, -1, 1, 0, 1, 1, 2, 0 } };
const std::vector<std::vector<int32_t>> Y = { { 1, -2, 1, -1, 1, 0, 1, 1 }, { 1, -1, 1, 0, 2, 0, 3, 0 },
{ 0, 1, 0, 2, 0, 3, 1, 1 }, { 1, 0, 2, 0, 2, 1, 3, 0 }, { 0, 1, 0, 2, 0, 3, 1, 2 },
{ 1, 0, 1, 1, 2, 0, 3, 0 }, { 1, -1, 1, 0, 1, 1, 1, 2 }, { 1, 0, 2, -1, 2, 0, 3, 0 } };
const std::vector<std::vector<int32_t>> Z = { { 0, 1, 1, 0, 2, -1, 2, 0 }, { 1, 0, 1, 1, 1, 2, 2, 2 },
{ 0, 1, 1, 1, 2, 1, 2, 2 }, { 1, -2, 1, -1, 1, 0, 2, -2 } };
const int32_t blank_index = 12;
const int32_t nRows = 8;
const int32_t nCols = 8;
std::vector<std::vector<std::vector<int32_t>>> shapes = { F, I, L, N, P, T, U, V, W, X, Y, Z };
std::vector<char> symbols = { 'F', 'I', 'L', 'N', 'P', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '-' };
std::vector<std::vector<int32_t>> grid{nRows, std::vector<int32_t>(nCols, -1)};
std::vector<bool> placed(symbols.size() - 1, false);
std::random_device random;
std::mt19937 generator(random());
std::uniform_real_distribution<double> distribution(0.0F, 1.0F);
void display() {
for ( const std::vector<int32_t>& row : grid ) {
for ( const int32_t& index : row ) {
std::cout << symbols[index] << " ";
}
std::cout << std::endl;
}
}
void shuffle_shapes() {
uint64_t size = shapes.size();
while ( size > 1 ) {
int32_t random = static_cast<int32_t>( distribution(generator) * ( size-- ) );
const std::vector<std::vector<int32_t>> temp = shapes[random];
shapes[random] = shapes[size];
shapes[size] = temp;
const char temp_symbol = symbols[random];
symbols[random] = symbols[size];
symbols[size] = temp_symbol;
}
}
bool place_orientation(const std::vector<int32_t>& orientation,
const int32_t& row, const int32_t& col, const int32_t& shape_index) {
for ( uint64_t i = 0; i < orientation.size(); i += 2 ) {
int32_t x = col + orientation[i + 1];
int32_t y = row + orientation[i];
if ( x < 0 || x >= nCols || y < 0 || y >= nRows || grid[y][x] != -1 ) {
return false;
}
}
grid[row][col] = shape_index;
for ( uint64_t i = 0; i < orientation.size(); i += 2 ) {
grid[row + orientation[i]][col + orientation[i + 1]] = shape_index;
}
return true;
}
void remove_orientation(const std::vector<int32_t>& oorientation, const int32_t& row, const int32_t& col) {
grid[row][col] = -1;
for ( uint64_t i = 0; i < oorientation.size(); i += 2 ) {
grid[row + oorientation[i]][col + oorientation[i + 1]] = -1;
}
}
bool solve(const int32_t& position, const uint64_t& number_placed) {
if ( number_placed == shapes.size() ) {
return true;
}
int32_t row = position / nCols;
int32_t col = position % nCols;
if ( grid[row][col] != -1 ) {
return solve(position + 1, number_placed);
}
for ( uint64_t i = 0; i < shapes.size(); ++i ) {
if ( ! placed[i] ) {
for ( const std::vector<int32_t>& orientation : shapes[i] ) {
if ( ! place_orientation(orientation, row, col, i) ) {
continue;
}
placed[i] = true;
if ( solve(position + 1, number_placed + 1) ) {
return true;
}
remove_orientation(orientation, row, col);
placed[i] = false;
}
}
}
return false;
}
int main() {
shuffle_shapes();
for ( int32_t i = 0; i < 4; ++i ) {
int32_t random_row, random_col;
do {
random_row = static_cast<int32_t>(distribution(generator) * nRows);
random_col = static_cast<int32_t>(distribution(generator) * nCols);
} while ( grid[random_row][random_col] == blank_index );
grid[random_row][random_col] = blank_index;
}
if ( solve(0, 0) ) {
display();
} else {
std::cout << "No solution found" << std::endl;
}
}
- Output:
Y Y Y Y X V V V U Y U X X X - V U U U T X W W V I T T T W W F - I L Z T W F F F I L Z Z Z F P P I L N N Z - P P I L L N N N - P
Go
package main
import (
"fmt"
"math/rand"
"time"
)
var F = [][]int{
{1, -1, 1, 0, 1, 1, 2, 1}, {0, 1, 1, -1, 1, 0, 2, 0},
{1, 0, 1, 1, 1, 2, 2, 1}, {1, 0, 1, 1, 2, -1, 2, 0},
{1, -2, 1, -1, 1, 0, 2, -1}, {0, 1, 1, 1, 1, 2, 2, 1},
{1, -1, 1, 0, 1, 1, 2, -1}, {1, -1, 1, 0, 2, 0, 2, 1},
}
var I = [][]int{{0, 1, 0, 2, 0, 3, 0, 4}, {1, 0, 2, 0, 3, 0, 4, 0}}
var L = [][]int{
{1, 0, 1, 1, 1, 2, 1, 3}, {1, 0, 2, 0, 3, -1, 3, 0},
{0, 1, 0, 2, 0, 3, 1, 3}, {0, 1, 1, 0, 2, 0, 3, 0}, {0, 1, 1, 1, 2, 1, 3, 1},
{0, 1, 0, 2, 0, 3, 1, 0}, {1, 0, 2, 0, 3, 0, 3, 1}, {1, -3, 1, -2, 1, -1, 1, 0},
}
var N = [][]int{
{0, 1, 1, -2, 1, -1, 1, 0}, {1, 0, 1, 1, 2, 1, 3, 1},
{0, 1, 0, 2, 1, -1, 1, 0}, {1, 0, 2, 0, 2, 1, 3, 1}, {0, 1, 1, 1, 1, 2, 1, 3},
{1, 0, 2, -1, 2, 0, 3, -1}, {0, 1, 0, 2, 1, 2, 1, 3}, {1, -1, 1, 0, 2, -1, 3, -1},
}
var P = [][]int{
{0, 1, 1, 0, 1, 1, 2, 1}, {0, 1, 0, 2, 1, 0, 1, 1},
{1, 0, 1, 1, 2, 0, 2, 1}, {0, 1, 1, -1, 1, 0, 1, 1}, {0, 1, 1, 0, 1, 1, 1, 2},
{1, -1, 1, 0, 2, -1, 2, 0}, {0, 1, 0, 2, 1, 1, 1, 2}, {0, 1, 1, 0, 1, 1, 2, 0},
}
var T = [][]int{
{0, 1, 0, 2, 1, 1, 2, 1}, {1, -2, 1, -1, 1, 0, 2, 0},
{1, 0, 2, -1, 2, 0, 2, 1}, {1, 0, 1, 1, 1, 2, 2, 0},
}
var U = [][]int{
{0, 1, 0, 2, 1, 0, 1, 2}, {0, 1, 1, 1, 2, 0, 2, 1},
{0, 2, 1, 0, 1, 1, 1, 2}, {0, 1, 1, 0, 2, 0, 2, 1},
}
var V = [][]int{
{1, 0, 2, 0, 2, 1, 2, 2}, {0, 1, 0, 2, 1, 0, 2, 0},
{1, 0, 2, -2, 2, -1, 2, 0}, {0, 1, 0, 2, 1, 2, 2, 2},
}
var W = [][]int{
{1, 0, 1, 1, 2, 1, 2, 2}, {1, -1, 1, 0, 2, -2, 2, -1},
{0, 1, 1, 1, 1, 2, 2, 2}, {0, 1, 1, -1, 1, 0, 2, -1},
}
var X = [][]int{{1, -1, 1, 0, 1, 1, 2, 0}}
var Y = [][]int{
{1, -2, 1, -1, 1, 0, 1, 1}, {1, -1, 1, 0, 2, 0, 3, 0},
{0, 1, 0, 2, 0, 3, 1, 1}, {1, 0, 2, 0, 2, 1, 3, 0}, {0, 1, 0, 2, 0, 3, 1, 2},
{1, 0, 1, 1, 2, 0, 3, 0}, {1, -1, 1, 0, 1, 1, 1, 2}, {1, 0, 2, -1, 2, 0, 3, 0},
}
var Z = [][]int{
{0, 1, 1, 0, 2, -1, 2, 0}, {1, 0, 1, 1, 1, 2, 2, 2},
{0, 1, 1, 1, 2, 1, 2, 2}, {1, -2, 1, -1, 1, 0, 2, -2},
}
var shapes = [][][]int{F, I, L, N, P, T, U, V, W, X, Y, Z}
var symbols = []byte("FILNPTUVWXYZ-")
const (
nRows = 8
nCols = 8
blank = 12
)
var grid [nRows][nCols]int
var placed [12]bool
func tryPlaceOrientation(o []int, r, c, shapeIndex int) bool {
for i := 0; i < len(o); i += 2 {
x := c + o[i+1]
y := r + o[i]
if x < 0 || x >= nCols || y < 0 || y >= nRows || grid[y][x] != -1 {
return false
}
}
grid[r][c] = shapeIndex
for i := 0; i < len(o); i += 2 {
grid[r+o[i]][c+o[i+1]] = shapeIndex
}
return true
}
func removeOrientation(o []int, r, c int) {
grid[r][c] = -1
for i := 0; i < len(o); i += 2 {
grid[r+o[i]][c+o[i+1]] = -1
}
}
func solve(pos, numPlaced int) bool {
if numPlaced == len(shapes) {
return true
}
row := pos / nCols
col := pos % nCols
if grid[row][col] != -1 {
return solve(pos+1, numPlaced)
}
for i := range shapes {
if !placed[i] {
for _, orientation := range shapes[i] {
if !tryPlaceOrientation(orientation, row, col, i) {
continue
}
placed[i] = true
if solve(pos+1, numPlaced+1) {
return true
}
removeOrientation(orientation, row, col)
placed[i] = false
}
}
}
return false
}
func shuffleShapes() {
rand.Shuffle(len(shapes), func(i, j int) {
shapes[i], shapes[j] = shapes[j], shapes[i]
symbols[i], symbols[j] = symbols[j], symbols[i]
})
}
func printResult() {
for _, r := range grid {
for _, i := range r {
fmt.Printf("%c ", symbols[i])
}
fmt.Println()
}
}
func main() {
rand.Seed(time.Now().UnixNano())
shuffleShapes()
for r := 0; r < nRows; r++ {
for i := range grid[r] {
grid[r][i] = -1
}
}
for i := 0; i < 4; i++ {
var randRow, randCol int
for {
randRow = rand.Intn(nRows)
randCol = rand.Intn(nCols)
if grid[randRow][randCol] != blank {
break
}
}
grid[randRow][randCol] = blank
}
if solve(0, 0) {
printResult()
} else {
fmt.Println("No solution")
}
}
- Output:
Sample output:
Z I I I I I - Y Z Z Z V - F Y Y U U Z V - F F Y U V V V F F X Y U U P P W X X X T P P P W W X - T T T N N W W L T N N N L L L L
Java
package pentominotiling;
import java.util.*;
public class PentominoTiling {
static final char[] symbols = "FILNPTUVWXYZ-".toCharArray();
static final Random rand = new Random();
static final int nRows = 8;
static final int nCols = 8;
static final int blank = 12;
static int[][] grid = new int[nRows][nCols];
static boolean[] placed = new boolean[symbols.length - 1];
public static void main(String[] args) {
shuffleShapes();
for (int r = 0; r < nRows; r++)
Arrays.fill(grid[r], -1);
for (int i = 0; i < 4; i++) {
int randRow, randCol;
do {
randRow = rand.nextInt(nRows);
randCol = rand.nextInt(nCols);
} while (grid[randRow][randCol] == blank);
grid[randRow][randCol] = blank;
}
if (solve(0, 0)) {
printResult();
} else {
System.out.println("no solution");
}
}
static void shuffleShapes() {
int n = shapes.length;
while (n > 1) {
int r = rand.nextInt(n--);
int[][] tmp = shapes[r];
shapes[r] = shapes[n];
shapes[n] = tmp;
char tmpSymbol = symbols[r];
symbols[r] = symbols[n];
symbols[n] = tmpSymbol;
}
}
static void printResult() {
for (int[] r : grid) {
for (int i : r)
System.out.printf("%c ", symbols[i]);
System.out.println();
}
}
static boolean tryPlaceOrientation(int[] o, int r, int c, int shapeIndex) {
for (int i = 0; i < o.length; i += 2) {
int x = c + o[i + 1];
int y = r + o[i];
if (x < 0 || x >= nCols || y < 0 || y >= nRows || grid[y][x] != -1)
return false;
}
grid[r][c] = shapeIndex;
for (int i = 0; i < o.length; i += 2)
grid[r + o[i]][c + o[i + 1]] = shapeIndex;
return true;
}
static void removeOrientation(int[] o, int r, int c) {
grid[r][c] = -1;
for (int i = 0; i < o.length; i += 2)
grid[r + o[i]][c + o[i + 1]] = -1;
}
static boolean solve(int pos, int numPlaced) {
if (numPlaced == shapes.length)
return true;
int row = pos / nCols;
int col = pos % nCols;
if (grid[row][col] != -1)
return solve(pos + 1, numPlaced);
for (int i = 0; i < shapes.length; i++) {
if (!placed[i]) {
for (int[] orientation : shapes[i]) {
if (!tryPlaceOrientation(orientation, row, col, i))
continue;
placed[i] = true;
if (solve(pos + 1, numPlaced + 1))
return true;
removeOrientation(orientation, row, col);
placed[i] = false;
}
}
}
return false;
}
static final int[][] F = {{1, -1, 1, 0, 1, 1, 2, 1}, {0, 1, 1, -1, 1, 0, 2, 0},
{1, 0, 1, 1, 1, 2, 2, 1}, {1, 0, 1, 1, 2, -1, 2, 0}, {1, -2, 1, -1, 1, 0, 2, -1},
{0, 1, 1, 1, 1, 2, 2, 1}, {1, -1, 1, 0, 1, 1, 2, -1}, {1, -1, 1, 0, 2, 0, 2, 1}};
static final int[][] I = {{0, 1, 0, 2, 0, 3, 0, 4}, {1, 0, 2, 0, 3, 0, 4, 0}};
static final int[][] L = {{1, 0, 1, 1, 1, 2, 1, 3}, {1, 0, 2, 0, 3, -1, 3, 0},
{0, 1, 0, 2, 0, 3, 1, 3}, {0, 1, 1, 0, 2, 0, 3, 0}, {0, 1, 1, 1, 2, 1, 3, 1},
{0, 1, 0, 2, 0, 3, 1, 0}, {1, 0, 2, 0, 3, 0, 3, 1}, {1, -3, 1, -2, 1, -1, 1, 0}};
static final int[][] N = {{0, 1, 1, -2, 1, -1, 1, 0}, {1, 0, 1, 1, 2, 1, 3, 1},
{0, 1, 0, 2, 1, -1, 1, 0}, {1, 0, 2, 0, 2, 1, 3, 1}, {0, 1, 1, 1, 1, 2, 1, 3},
{1, 0, 2, -1, 2, 0, 3, -1}, {0, 1, 0, 2, 1, 2, 1, 3}, {1, -1, 1, 0, 2, -1, 3, -1}};
static final int[][] P = {{0, 1, 1, 0, 1, 1, 2, 1}, {0, 1, 0, 2, 1, 0, 1, 1},
{1, 0, 1, 1, 2, 0, 2, 1}, {0, 1, 1, -1, 1, 0, 1, 1}, {0, 1, 1, 0, 1, 1, 1, 2},
{1, -1, 1, 0, 2, -1, 2, 0}, {0, 1, 0, 2, 1, 1, 1, 2}, {0, 1, 1, 0, 1, 1, 2, 0}};
static final int[][] T = {{0, 1, 0, 2, 1, 1, 2, 1}, {1, -2, 1, -1, 1, 0, 2, 0},
{1, 0, 2, -1, 2, 0, 2, 1}, {1, 0, 1, 1, 1, 2, 2, 0}};
static final int[][] U = {{0, 1, 0, 2, 1, 0, 1, 2}, {0, 1, 1, 1, 2, 0, 2, 1},
{0, 2, 1, 0, 1, 1, 1, 2}, {0, 1, 1, 0, 2, 0, 2, 1}};
static final int[][] V = {{1, 0, 2, 0, 2, 1, 2, 2}, {0, 1, 0, 2, 1, 0, 2, 0},
{1, 0, 2, -2, 2, -1, 2, 0}, {0, 1, 0, 2, 1, 2, 2, 2}};
static final int[][] W = {{1, 0, 1, 1, 2, 1, 2, 2}, {1, -1, 1, 0, 2, -2, 2, -1},
{0, 1, 1, 1, 1, 2, 2, 2}, {0, 1, 1, -1, 1, 0, 2, -1}};
static final int[][] X = {{1, -1, 1, 0, 1, 1, 2, 0}};
static final int[][] Y = {{1, -2, 1, -1, 1, 0, 1, 1}, {1, -1, 1, 0, 2, 0, 3, 0},
{0, 1, 0, 2, 0, 3, 1, 1}, {1, 0, 2, 0, 2, 1, 3, 0}, {0, 1, 0, 2, 0, 3, 1, 2},
{1, 0, 1, 1, 2, 0, 3, 0}, {1, -1, 1, 0, 1, 1, 1, 2}, {1, 0, 2, -1, 2, 0, 3, 0}};
static final int[][] Z = {{0, 1, 1, 0, 2, -1, 2, 0}, {1, 0, 1, 1, 1, 2, 2, 2},
{0, 1, 1, 1, 2, 1, 2, 2}, {1, -2, 1, -1, 1, 0, 2, -2}};
static final int[][][] shapes = {F, I, L, N, P, T, U, V, W, X, Y, Z};
}
F I I I I I L L F F F P P V L - Z F P P P V L N Z Z Z V V V L N - X Z - W W N N X X X W W - N T U X U W Y T T T U U U Y Y Y Y T
jq
Adapted from Wren
Works with jq, the C implementation of jq
Works with gojq, the Go implementation of jq
The following solution takes advantage of jq's support for backtracking. This means, for example, that there is no need for `removeOrientation`.
Since jq does not currently have a built-in PRNG, /dev/random is used as a source of entropy. An invocation of jq along the lines of the following would therefore be appropriate in a typical command-line environment:
< /dev/random tr -cd '0-9' | fold -w 1 | jq -cnr -f pentomino.jq
where "pentomino.jq" is the name of a file containing the following jq program.
# Output: a PRN in range(0; .)
def prn:
if . == 1 then 0
else . as $n
| (($n-1)|tostring|length) as $w
| [limit($w; inputs)] | join("") | tonumber
| if . < $n then . else ($n | prn) end
end;
### Generic functions
def array($n): . as $in | [range(0;$n)|$in];
def array_swap($i; $j):
if $j < $i then array_swap($j;$i)
elif $i == $j then .
else .[:$i] + [.[$j]] + .[$i+1:$j] + [.[$i]] + .[$j+1:]
end ;
### Pentominos
def F: [
[1, -1, 1, 0, 1, 1, 2, 1], [0, 1, 1, -1, 1, 0, 2, 0],
[1, 0, 1, 1, 1, 2, 2, 1], [1, 0, 1, 1, 2, -1, 2, 0],
[1, -2, 1, -1, 1, 0, 2, -1], [0, 1, 1, 1, 1, 2, 2, 1],
[1, -1, 1, 0, 1, 1, 2, -1], [1, -1, 1, 0, 2, 0, 2, 1]
];
def I: [
[0, 1, 0, 2, 0, 3, 0, 4], [1, 0, 2, 0, 3, 0, 4, 0]
];
def L: [
[1, 0, 1, 1, 1, 2, 1, 3], [1, 0, 2, 0, 3, -1, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 3], [0, 1, 1, 0, 2, 0, 3, 0],
[0, 1, 1, 1, 2, 1, 3, 1], [0, 1, 0, 2, 0, 3, 1, 0],
[1, 0, 2, 0, 3, 0, 3, 1], [1, -3, 1, -2, 1, -1, 1, 0]
];
def N: [
[0, 1, 1, -2, 1, -1, 1, 0], [1, 0, 1, 1, 2, 1, 3, 1],
[0, 1, 0, 2, 1, -1, 1, 0], [1, 0, 2, 0, 2, 1, 3, 1],
[0, 1, 1, 1, 1, 2, 1, 3], [1, 0, 2, -1, 2, 0, 3, -1],
[0, 1, 0, 2, 1, 2, 1, 3], [1, -1, 1, 0, 2, -1, 3, -1]
];
def P: [
[0, 1, 1, 0, 1, 1, 2, 1], [0, 1, 0, 2, 1, 0, 1, 1],
[1, 0, 1, 1, 2, 0, 2, 1], [0, 1, 1, -1, 1, 0, 1, 1],
[0, 1, 1, 0, 1, 1, 1, 2], [1, -1, 1, 0, 2, -1, 2, 0],
[0, 1, 0, 2, 1, 1, 1, 2], [0, 1, 1, 0, 1, 1, 2, 0]
];
def T: [
[0, 1, 0, 2, 1, 1, 2, 1], [1, -2, 1, -1, 1, 0, 2, 0],
[1, 0, 2, -1, 2, 0, 2, 1], [1, 0, 1, 1, 1, 2, 2, 0]
];
def U: [
[0, 1, 0, 2, 1, 0, 1, 2], [0, 1, 1, 1, 2, 0, 2, 1],
[0, 2, 1, 0, 1, 1, 1, 2], [0, 1, 1, 0, 2, 0, 2, 1]
];
def V: [
[1, 0, 2, 0, 2, 1, 2, 2], [0, 1, 0, 2, 1, 0, 2, 0],
[1, 0, 2, -2, 2, -1, 2, 0], [0, 1, 0, 2, 1, 2, 2, 2]
];
def W: [
[1, 0, 1, 1, 2, 1, 2, 2], [1, -1, 1, 0, 2, -2, 2, -1],
[0, 1, 1, 1, 1, 2, 2, 2], [0, 1, 1, -1, 1, 0, 2, -1]
];
def X: [[1, -1, 1, 0, 1, 1, 2, 0]];
def Y: [
[1, -2, 1, -1, 1, 0, 1, 1], [1, -1, 1, 0, 2, 0, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 1], [1, 0, 2, 0, 2, 1, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 2], [1, 0, 1, 1, 2, 0, 3, 0],
[1, -1, 1, 0, 1, 1, 1, 2], [1, 0, 2, -1, 2, 0, 3, 0]
];
def Z: [
[0, 1, 1, 0, 2, -1, 2, 0], [1, 0, 1, 1, 1, 2, 2, 2],
[0, 1, 1, 1, 2, 1, 2, 2], [1, -2, 1, -1, 1, 0, 2, -2]
];
def shapes: [F, I, L, N, P, T, U, V, W, X, Y, Z];
def symbols: "FILNPTUVWXYZ-" | split("");
def nRows: 8;
def nCols: 8;
def blank: 12;
def printResult:
.symbols as $symbols
| .grid[] as $row
| reduce $row[] as $i (""; . + $symbols[$i]);
# Input: {grid}
def placeOrientation($o; $r; $c; $shapeIndex):
.grid[$r][$c] = $shapeIndex
| reduce range(0; $o|length; 2) as $io (.;
.grid[$r + $o[$io]][$c + $o[$io + 1]] = $shapeIndex);
# Input and output: {grid}
# If the placement is feasible, call placeOrientation/3
def tryPlaceOrientation($o; $r; $c; $shapeIndex):
.grid as $grid
| if any( range(0; $o|length; 2);
. as $io
| ($c + $o[$io + 1]) as $x
| ($r + $o[$io] ) as $y
| $x < 0 or $x >= nCols or $y < 0 or $y >= nRows or $grid[$y][$x] != -1 )
then empty
else placeOrientation($o; $r; $c; $shapeIndex)
end
;
# Input: {grid, placed, shapes}
def solve($pos; $numPlaced):
if $numPlaced == (.shapes|length)
then .
else (($pos / nCols)|floor) as $row
| ($pos % nCols ) as $col
| if .grid[$row][$col] != -1
then solve($pos + 1; $numPlaced)
else .emit = false
| foreach range(0; .shapes|length) as $i (.;
if .placed[$i] then .
else foreach .shapes[$i][] as $orientation (.;
(tryPlaceOrientation($orientation; $row; $col; $i)
| .placed[$i] = true
| solve($pos + 1; $numPlaced + 1)
| .emit = true)
// .)
end )
| select(.emit)
end
end;
# input: {shapes, symbols}
def shuffleShapes:
(.shapes|length) as $n
| reduce range(0; $n) as $i (.;
($n | prn) as $r
| .shapes |= array_swap($r; $i)
| .symbols |= array_swap($r; $i) )
;
def task:
def grid:
0 | array(nCols) | array(nRows);
def placed:
false | array(symbols|length - 1);
{ shapes: shapes,
symbols: symbols,
grid: grid,
placed: placed}
| shuffleShapes
| reduce range(0; nRows) as $r (.;
reduce range(0; .grid[$r]|length) as $c (.;
.grid[$r][$c] = -1))
| reduce range(0; 4) as $i (.;
.done = false
| until(.done;
.randRow = (nRows | prn)
| .randCol = (nCols | prn)
| .done = (.grid[.randRow][.randCol] != blank) )
| .grid[.randRow][.randCol] = blank
)
| first(solve(0; 0))
| printResult
// "No solution"
;
task
- Output:
TTTPPUUU VTPPPUXU VTZZWXXX VVVZWWXL YF-ZZWWL YFFF-NNL YYFNNNLL YIIIII--
Julia
using Random
struct GridPoint x::Int; y::Int end
const nrows, ncols, target = 8, 8, 12
const grid = fill('*', nrows, ncols)
const shapeletters = ['F', 'I', 'L', 'N', 'P', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
const shapevec = [
[(1,-1, 1,0, 1,1, 2,1), (0,1, 1,-1, 1,0, 2,0),
(1,0 , 1,1, 1,2, 2,1), (1,0, 1,1, 2,-1, 2,0), (1,-2, 1,-1, 1,0, 2,-1),
(0,1, 1,1, 1,2, 2,1), (1,-1, 1,0, 1,1, 2,-1), (1,-1, 1,0, 2,0, 2,1)],
[(0,1, 0,2, 0,3, 0,4), (1,0, 2,0, 3,0, 4,0)],
[(1,0, 1,1, 1,2, 1,3), (1,0, 2,0, 3,-1, 3,0),
(0,1, 0,2, 0,3, 1,3), (0,1, 1,0, 2,0, 3,0), (0,1, 1,1, 2,1, 3,1),
(0,1, 0,2, 0,3, 1,0), (1,0, 2,0, 3,0, 3,1), (1,-3, 1,-2, 1,-1, 1,0)],
[(0,1, 1,-2, 1,-1, 1,0), (1,0, 1,1, 2,1, 3,1),
(0,1, 0,2, 1,-1, 1,0), (1,0, 2,0, 2,1, 3,1), (0,1, 1,1, 1,2, 1,3),
(1,0, 2,-1, 2,0, 3,-1), (0,1, 0,2, 1,2, 1,3), (1,-1, 1,0, 2,-1, 3,-1)],
[(0,1, 1,0, 1,1, 2,1), (0,1, 0,2, 1,0, 1,1),
(1,0, 1,1, 2,0, 2,1), (0,1, 1,-1, 1,0, 1,1), (0,1, 1,0, 1,1, 1,2),
(1,-1, 1,0, 2,-1, 2,0), (0,1, 0,2, 1,1, 1,2), (0,1, 1,0, 1,1, 2,0)],
[(0,1, 0,2, 1,1, 2,1), (1,-2, 1,-1, 1,0, 2,0),
(1,0, 2,-1, 2,0, 2,1), (1,0, 1,1, 1,2, 2,0)],
[(0,1, 0,2, 1,0, 1,2), (0,1, 1,1, 2,0, 2,1),
(0,2, 1,0, 1,1, 1,2), (0,1, 1,0, 2,0, 2,1)],
[(1,0, 2,0, 2,1, 2,2), (0,1, 0,2, 1,0, 2,0),
(1,0, 2,-2, 2,-1, 2,0), (0,1, 0,2, 1,2, 2,2)],
[(1,0, 1,1, 2,1, 2,2), (1,-1, 1,0, 2,-2, 2,-1),
(0,1, 1,1, 1,2, 2,2), (0,1, 1,-1, 1,0, 2,-1)],
[(1,-1, 1,0, 1,1, 2,0)],
[(1,-2, 1,-1, 1,0, 1,1), (1,-1, 1,0, 2,0, 3,0),
(0,1, 0,2, 0,3, 1,1), (1,0, 2,0, 2,1, 3,0), (0,1, 0,2, 0,3, 1,2),
(1,0, 1,1, 2,0, 3,0), (1,-1, 1,0, 1,1, 1,2), (1,0, 2,-1, 2,0, 3,0)],
[(0,1, 1,0, 2,-1, 2,0), (1,0, 1,1, 1,2, 2,2),
(0,1, 1,1, 2,1, 2,2), (1,-2, 1,-1, 1,0, 2,-2)]]
const shapes = Dict{Char,Vector{Vector{GridPoint}}}()
const placed = Dict{Char,Bool}()
for (ltr, vec) in zip(shapeletters, shapevec)
shapes[ltr] = [[GridPoint(v[i], v[i + 1]) for i in 1:2:7] for v in vec]
placed[ltr] = false
end
printgrid(m, w, h) = for x in 1:w for y in 1:h print(m[x, y], " ") end; println() end
function tryplaceorientation(o, R, C, shapeindex)
for p in o
r, c = R + p.x, C + p.y
if r < 1 || r > nrows || c < 1 || c > ncols || grid[r, c] != '*'
return false
end
end
grid[R, C] = shapeindex
for p in o
grid[R + p.x, C + p.y] = shapeindex
end
true
end
function removeorientation(o, r, c)
grid[r, c] = '*'
for p in o
grid[r + p.x, c + p.y] = '*'
end
end
function solve(pos, nplaced)
if nplaced == target
return true
end
row, col = divrem(pos, ncols) .+ 1
if grid[row, col] != '*'
return solve(pos + 1, nplaced)
end
for i in keys((shapes))
if !placed[i]
for orientation in shapes[i]
if tryplaceorientation(orientation, row, col, i)
placed[i] = true
if solve(pos + 1, nplaced + 1)
return true
else
removeorientation(orientation, row, col)
placed[i] = false
end
end
end
end
end
false
end
function placepentominoes()
for p in zip(shuffle(collect(1:nrows))[1:4], shuffle(collect(1:ncols))[1:4])
grid[p[1], p[2]] = ' '
end
if solve(0, 0)
printgrid(grid, nrows, ncols)
else
println("No solution found.")
end
end
placepentominoes()
- Output:
Z Z X P P P V I Z X X X P P V I Z Z X L V V V I T T T L L L L I N T F F U U I N T W F F U N N W W F Y U U N W W Y Y Y Y
Kotlin
// Version 1.1.4-3
import java.util.Random
val F = arrayOf(
intArrayOf(1, -1, 1, 0, 1, 1, 2, 1), intArrayOf(0, 1, 1, -1, 1, 0, 2, 0),
intArrayOf(1, 0, 1, 1, 1, 2, 2, 1), intArrayOf(1, 0, 1, 1, 2, -1, 2, 0),
intArrayOf(1, -2, 1, -1, 1, 0, 2, -1), intArrayOf(0, 1, 1, 1, 1, 2, 2, 1),
intArrayOf(1, -1, 1, 0, 1, 1, 2, -1), intArrayOf(1, -1, 1, 0, 2, 0, 2, 1)
)
val I = arrayOf(
intArrayOf(0, 1, 0, 2, 0, 3, 0, 4), intArrayOf(1, 0, 2, 0, 3, 0, 4, 0)
)
val L = arrayOf(
intArrayOf(1, 0, 1, 1, 1, 2, 1, 3), intArrayOf(1, 0, 2, 0, 3, -1, 3, 0),
intArrayOf(0, 1, 0, 2, 0, 3, 1, 3), intArrayOf(0, 1, 1, 0, 2, 0, 3, 0),
intArrayOf(0, 1, 1, 1, 2, 1, 3, 1), intArrayOf(0, 1, 0, 2, 0, 3, 1, 0),
intArrayOf(1, 0, 2, 0, 3, 0, 3, 1), intArrayOf(1, -3, 1, -2, 1, -1, 1, 0)
)
val N = arrayOf(
intArrayOf(0, 1, 1, -2, 1, -1, 1, 0), intArrayOf(1, 0, 1, 1, 2, 1, 3, 1),
intArrayOf(0, 1, 0, 2, 1, -1, 1, 0), intArrayOf(1, 0, 2, 0, 2, 1, 3, 1),
intArrayOf(0, 1, 1, 1, 1, 2, 1, 3), intArrayOf(1, 0, 2, -1, 2, 0, 3, -1),
intArrayOf(0, 1, 0, 2, 1, 2, 1, 3), intArrayOf(1, -1, 1, 0, 2, -1, 3, -1)
)
val P = arrayOf(
intArrayOf(0, 1, 1, 0, 1, 1, 2, 1), intArrayOf(0, 1, 0, 2, 1, 0, 1, 1),
intArrayOf(1, 0, 1, 1, 2, 0, 2, 1), intArrayOf(0, 1, 1, -1, 1, 0, 1, 1),
intArrayOf(0, 1, 1, 0, 1, 1, 1, 2), intArrayOf(1, -1, 1, 0, 2, -1, 2, 0),
intArrayOf(0, 1, 0, 2, 1, 1, 1, 2), intArrayOf(0, 1, 1, 0, 1, 1, 2, 0)
)
val T = arrayOf(
intArrayOf(0, 1, 0, 2, 1, 1, 2, 1), intArrayOf(1, -2, 1, -1, 1, 0, 2, 0),
intArrayOf(1, 0, 2, -1, 2, 0, 2, 1), intArrayOf(1, 0, 1, 1, 1, 2, 2, 0)
)
val U = arrayOf(
intArrayOf(0, 1, 0, 2, 1, 0, 1, 2), intArrayOf(0, 1, 1, 1, 2, 0, 2, 1),
intArrayOf(0, 2, 1, 0, 1, 1, 1, 2), intArrayOf(0, 1, 1, 0, 2, 0, 2, 1)
)
val V = arrayOf(
intArrayOf(1, 0, 2, 0, 2, 1, 2, 2), intArrayOf(0, 1, 0, 2, 1, 0, 2, 0),
intArrayOf(1, 0, 2, -2, 2, -1, 2, 0), intArrayOf(0, 1, 0, 2, 1, 2, 2, 2)
)
val W = arrayOf(
intArrayOf(1, 0, 1, 1, 2, 1, 2, 2), intArrayOf(1, -1, 1, 0, 2, -2, 2, -1),
intArrayOf(0, 1, 1, 1, 1, 2, 2, 2), intArrayOf(0, 1, 1, -1, 1, 0, 2, -1)
)
val X = arrayOf(intArrayOf(1, -1, 1, 0, 1, 1, 2, 0))
val Y = arrayOf(
intArrayOf(1, -2, 1, -1, 1, 0, 1, 1), intArrayOf(1, -1, 1, 0, 2, 0, 3, 0),
intArrayOf(0, 1, 0, 2, 0, 3, 1, 1), intArrayOf(1, 0, 2, 0, 2, 1, 3, 0),
intArrayOf(0, 1, 0, 2, 0, 3, 1, 2), intArrayOf(1, 0, 1, 1, 2, 0, 3, 0),
intArrayOf(1, -1, 1, 0, 1, 1, 1, 2), intArrayOf(1, 0, 2, -1, 2, 0, 3, 0)
)
val Z = arrayOf(
intArrayOf(0, 1, 1, 0, 2, -1, 2, 0), intArrayOf(1, 0, 1, 1, 1, 2, 2, 2),
intArrayOf(0, 1, 1, 1, 2, 1, 2, 2), intArrayOf(1, -2, 1, -1, 1, 0, 2, -2)
)
val shapes = arrayOf(F, I, L, N, P, T, U, V, W, X, Y, Z)
val rand = Random()
val symbols = "FILNPTUVWXYZ-".toCharArray()
val nRows = 8
val nCols = 8
val blank = 12
val grid = Array(nRows) { IntArray(nCols) }
val placed = BooleanArray(symbols.size - 1)
fun tryPlaceOrientation(o: IntArray, r: Int, c: Int, shapeIndex: Int): Boolean {
for (i in 0 until o.size step 2) {
val x = c + o[i + 1]
val y = r + o[i]
if (x !in (0 until nCols) || y !in (0 until nRows) || grid[y][x] != - 1) return false
}
grid[r][c] = shapeIndex
for (i in 0 until o.size step 2) grid[r + o[i]][c + o[i + 1]] = shapeIndex
return true
}
fun removeOrientation(o: IntArray, r: Int, c: Int) {
grid[r][c] = -1
for (i in 0 until o.size step 2) grid[r + o[i]][c + o[i + 1]] = -1
}
fun solve(pos: Int, numPlaced: Int): Boolean {
if (numPlaced == shapes.size) return true
val row = pos / nCols
val col = pos % nCols
if (grid[row][col] != -1) return solve(pos + 1, numPlaced)
for (i in 0 until shapes.size) {
if (!placed[i]) {
for (orientation in shapes[i]) {
if (!tryPlaceOrientation(orientation, row, col, i)) continue
placed[i] = true
if (solve(pos + 1, numPlaced + 1)) return true
removeOrientation(orientation, row, col)
placed[i] = false
}
}
}
return false
}
fun shuffleShapes() {
var n = shapes.size
while (n > 1) {
val r = rand.nextInt(n--)
val tmp = shapes[r]
shapes[r] = shapes[n]
shapes[n] = tmp
val tmpSymbol= symbols[r]
symbols[r] = symbols[n]
symbols[n] = tmpSymbol
}
}
fun printResult() {
for (r in grid) {
for (i in r) print("${symbols[i]} ")
println()
}
}
fun main(args: Array<String>) {
shuffleShapes()
for (r in 0 until nRows) grid[r].fill(-1)
for (i in 0..3) {
var randRow: Int
var randCol: Int
do {
randRow = rand.nextInt(nRows)
randCol = rand.nextInt(nCols)
}
while (grid[randRow][randCol] == blank)
grid[randRow][randCol] = blank
}
if (solve(0, 0)) printResult()
else println("No solution")
}
Sample output:
I I I I I F - W N N N F F F W W U U N N F W W - - U V L L L L T U U V L Z T T T V V V X Z Z Z T P P X X X Y Z - P P P X Y Y Y Y
Nim
import random, sequtils, strutils
const
F = @[[1, -1, 1, 0, 1, 1, 2, 1], [0, 1, 1, -1, 1, 0, 2, 0],
[1, 0, 1, 1, 1, 2, 2, 1], [1, 0, 1, 1, 2, -1, 2, 0],
[1, -2, 1, -1, 1, 0, 2, -1], [0, 1, 1, 1, 1, 2, 2, 1],
[1, -1, 1, 0, 1, 1, 2, -1], [1, -1, 1, 0, 2, 0, 2, 1]]
I = @[[0, 1, 0, 2, 0, 3, 0, 4], [1, 0, 2, 0, 3, 0, 4, 0]]
L = @[[1, 0, 1, 1, 1, 2, 1, 3], [1, 0, 2, 0, 3, -1, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 3], [0, 1, 1, 0, 2, 0, 3, 0],
[0, 1, 1, 1, 2, 1, 3, 1], [0, 1, 0, 2, 0, 3, 1, 0],
[1, 0, 2, 0, 3, 0, 3, 1], [1, -3, 1, -2, 1, -1, 1, 0]]
N = @[[0, 1, 1, -2, 1, -1, 1, 0], [1, 0, 1, 1, 2, 1, 3, 1],
[0, 1, 0, 2, 1, -1, 1, 0], [1, 0, 2, 0, 2, 1, 3, 1],
[0, 1, 1, 1, 1, 2, 1, 3], [1, 0, 2, -1, 2, 0, 3, -1],
[0, 1, 0, 2, 1, 2, 1, 3], [1, -1, 1, 0, 2, -1, 3, -1]]
P = @[[0, 1, 1, 0, 1, 1, 2, 1], [0, 1, 0, 2, 1, 0, 1, 1],
[1, 0, 1, 1, 2, 0, 2, 1], [0, 1, 1, -1, 1, 0, 1, 1],
[0, 1, 1, 0, 1, 1, 1, 2], [1, -1, 1, 0, 2, -1, 2, 0],
[0, 1, 0, 2, 1, 1, 1, 2], [0, 1, 1, 0, 1, 1, 2, 0]]
T = @[[0, 1, 0, 2, 1, 1, 2, 1], [1, -2, 1, -1, 1, 0, 2, 0],
[1, 0, 2, -1, 2, 0, 2, 1], [1, 0, 1, 1, 1, 2, 2, 0]]
U = @[[0, 1, 0, 2, 1, 0, 1, 2], [0, 1, 1, 1, 2, 0, 2, 1],
[0, 2, 1, 0, 1, 1, 1, 2], [0, 1, 1, 0, 2, 0, 2, 1]]
V = @[[1, 0, 2, 0, 2, 1, 2, 2], [0, 1, 0, 2, 1, 0, 2, 0],
[1, 0, 2, -2, 2, -1, 2, 0], [0, 1, 0, 2, 1, 2, 2, 2]]
W = @[[1, 0, 1, 1, 2, 1, 2, 2], [1, -1, 1, 0, 2, -2, 2, -1],
[0, 1, 1, 1, 1, 2, 2, 2], [0, 1, 1, -1, 1, 0, 2, -1]]
X = @[[1, -1, 1, 0, 1, 1, 2, 0]]
Y = @[[1, -2, 1, -1, 1, 0, 1, 1], [1, -1, 1, 0, 2, 0, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 1], [1, 0, 2, 0, 2, 1, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 2], [1, 0, 1, 1, 2, 0, 3, 0],
[1, -1, 1, 0, 1, 1, 1, 2], [1, 0, 2, -1, 2, 0, 3, 0]]
Z = @[[0, 1, 1, 0, 2, -1, 2, 0], [1, 0, 1, 1, 1, 2, 2, 2],
[0, 1, 1, 1, 2, 1, 2, 2], [1, -2, 1, -1, 1, 0, 2, -2]]
Shapes = [F, I, L, N, P, T, U, V, W, X, Y, Z]
Symbols = @"FILNPTUVWXYZ-"
NRows = 8
NCols = 8
Blank = Shapes.len
type Tiling = object
shapes: array[Shapes.len, seq[array[8, int]]] # Shuffled shapes.
symbols: array[Symbols.len, char] # Associated symbols.
grid: array[NRows, array[NCols, int]]
placed: array[Shapes.len, bool]
proc initTiling(): Tiling =
# Build list of shapes and symbols.
var indexes = toSeq(0..11)
indexes.shuffle()
for i, index in indexes:
result.shapes[i] = Shapes[index]
result.symbols[i] = Symbols[index]
result.symbols[^1] = Symbols[^1]
# Fill grid.
for r in result.grid.mitems:
for c in r.mitems:
c = -1
for i in 0..3:
while true:
let randRow = rand(NRows - 1)
let randCol = rand(NCols - 1)
if result.grid[randRow][randCol] != Blank:
result.grid[randRow][randCol] = Blank
break
func tryPlaceOrientation(t: var Tiling; o: openArray[int]; r, c, shapeIndex: int): bool =
for i in countup(0, o.len - 2, 2):
let x = c + o[i + 1]
let y = r + o[i]
if x notin 0..<NCols or y notin 0..<NRows or t.grid[y][x] != - 1: return false
t.grid[r][c] = shapeIndex
for i in countup(0, o.len - 2, 2): t.grid[r + o[i]][c + o[i + 1]] = shapeIndex
result = true
func removeOrientation(t: var Tiling; o: openArray[int]; r, c: int) =
t.grid[r][c] = -1
for i in countup(0, o.len - 2, 2): t.grid[r + o[i]][c + o[i + 1]] = -1
func solve(t: var Tiling; pos, numPlaced: int): bool =
if numPlaced == t.shapes.len: return true
let row = pos div NCols
let col = pos mod NCols
if t.grid[row][col] != -1: return t.solve(pos + 1, numPlaced)
for i in 0..<t.shapes.len:
if not t.placed[i]:
for orientation in t.shapes[i]:
if not t.tryPlaceOrientation(orientation, row, col, i): continue
t.placed[i] = true
if t.solve(pos + 1, numPlaced + 1): return true
t.removeOrientation(orientation, row, col)
t.placed[i] = false
proc printResult(t: Tiling) =
for r in t.grid:
echo r.mapIt(t.symbols[it]).join(" ")
when isMainModule:
randomize()
var tiling = initTiling()
if tiling.solve(0, 0): tiling.printResult
else: echo "No solution"
- Output:
T T T F - P P P Y T F F F X P P Y T F W X X X - Y Y W W U X U I Y W W Z U U U I - Z Z Z N N V I L Z N N N - V I L L L L V V V I
Perl
Generates one tiling at random. To generate more during one run, change the "exit" to "return".
use strict;
use warnings;
use feature 'bitwise';
my $size = shift // 8;
sub rotate
{
local $_ = shift;
my $ans = '';
$ans .= "\n" while s/.$/$ans .= $&; ''/gem;
$ans;
}
sub topattern
{
local $_ = shift;
s/.+/ $& . ' ' x ($size - length $&)/ge;
s/^\s+|\s+\z//g;
[ tr/ \nA-Z/.. /r, lc tr/ \n/\0/r, substr $_, 0, 1 ]; # pattern, xor-update
}
my %all;
@all{ " FF\nFF \n F \n", "IIIII\n", "LLLL\nL \n", "NNN \n NN\n",
"PPP\nPP \n", "TTT\n T \n T \n", "UUU\nU U\n", "VVV\nV \nV \n",
"WW \n WW\n W\n", " X \nXXX\n X \n", "YYYY\n Y \n", "ZZ \n Z \n ZZ\n",
} = ();
@all{map rotate($_), keys %all} = () for 1 .. 3; # all four rotations
@all{map s/.+/reverse $&/ger, keys %all} = (); # mirror
my @all = map topattern($_), keys %all;
my $grid = ( ' ' x $size . "\n" ) x $size;
my %used;
find( $grid );
# looks for the first open space
sub find
{
my $grid = shift;
%used >= 12 and exit not print $grid;
for ( grep ! $used{ $_->[2] }, @all )
{
my ($pattern, $pentomino, $letter) = @$_;
local $used{$letter} = 1;
$grid =~ /^[^ ]*\K$pattern/s and find( $grid ^. "\0" x $-[0] . $pentomino );
}
}
- Output:
FNNNTTTP FFFNNTPP IFUUZTPP ILLUZZZY ILUUWWZY ILVWWXYY ILVWXXXY VVVX
Phix
Apart from the shape table creation, the solving part is a translation of Go.
I also added a fast unsolveable() check routine, not that it desperately needed it.
with javascript_semantics constant pentominoes = split(""" ......I................................................................ ......I.....L......N.........................................Y......... .FF...I.....L.....NN....PP....TTT...........V.....W....X....YY.....ZZ.. FF....I.....L.....N.....PP.....T....U.U.....V....WW...XXX....Y.....Z... .F....I.....LL....N.....P......T....UUU...VVV...WW.....X.....Y....ZZ...""",'\n') ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- function get_shapes() sequence res = {} for offset=0 to length(pentominoes[1]) by 6 do -- -- scan left/right, and up/down, both ways, to give 8 orientations -- (computes the equivalent of those hard-coded tables in -- other examples, albeit in a slightly different order.) -- sequence shapes = {} integer letter for orientation=0 to 7 do sequence shape = {} bool found = false integer fr, fc for r=1 to 5 do for c=1 to 5 do integer rr = iff(and_bits(orientation,#01)?6-r:r), cc = iff(and_bits(orientation,#02)?6-c:c) if and_bits(orientation,#04) then {rr,cc} = {cc,rr} end if integer ch = pentominoes[rr,offset+cc] if ch!='.' then if not found then {found,fr,fc,letter} = {true,r,c,ch} else shape &= {r-fr,c-fc} end if end if end for end for if not find(shape,shapes) then shapes = append(shapes,shape) end if end for res = append(res,{letter&"",shapes}) end for return res end function constant shapes = get_shapes(), nRows = 8, nCols = 8 sequence grid = repeat(repeat(' ',nCols),nRows), placed = repeat(false,length(shapes)) procedure re_place(sequence o, integer r, c, ch=' ') grid[r][c] = ch for i=1 to length(o) by 2 do grid[r+o[i]][c+o[i+1]] = ch end for end procedure function can_place(sequence o, integer r, c, ch) for i=1 to length(o) by 2 do integer x := c + o[i+1], y := r + o[i] if x<1 or x>nCols or y<1 or y>nRows or grid[y][x]!=' ' then return false end if end for re_place(o,r,c,ch) return true end function function solve(integer pos=0, numPlaced=0) if numPlaced == length(shapes) then return true end if integer row = floor(pos/8)+1, col = mod(pos,8)+1 if grid[row][col]!=' ' then return solve(pos+1, numPlaced) end if for i=1 to length(shapes) do if not placed[i] then integer ch = shapes[i][1][1] for j=1 to length(shapes[i][2]) do sequence o = shapes[i][2][j] if can_place(o, row, col, ch) then placed[i] = true if solve(pos+1, numPlaced+1) then return true end if re_place(o, row, col) placed[i] = false end if end for end if end for return false end function function unsolveable() -- -- The only unsolvable grids seen have -- -.- or -..- or -... at edge/corner, -- - -- --- - -- or somewhere in the middle a -.- -- - -- -- Simply place all shapes at all positions/orientations, -- all the while checking for any untouchable cells. -- sequence griddled = deep_copy(grid) for r=1 to 8 do for c=1 to 8 do if grid[r][c]=' ' then for i=1 to length(shapes) do integer ch = shapes[i][1][1] for j=1 to length(shapes[i][2]) do sequence o = shapes[i][2][j] if can_place(o, r, c, ch) then grid[r][c] = ' ' griddled[r][c] = '-' for k=1 to length(o) by 2 do grid[r+o[k]][c+o[k+1]] = ' ' griddled[r+o[k]][c+o[k+1]] = '-' end for end if end for end for if griddled[r][c]!='-' then return true end if end if end for end for return false end function procedure add_four_randomly() integer count = 0 while count<4 do integer r = rand(8), c = rand(8) if grid[r][c]=' ' then grid[r][c] = '-' count += 1 end if end while end procedure procedure main() add_four_randomly() if unsolveable() then puts(1,"No solution\n") else if not solve() then ?9/0 end if end if puts(1,join(grid,"\n")&"\n") end procedure main()
- Output:
FFPPPVVV YFFPPX-V YFUUXXXV YYU-ZX-I YTUUZZZI -TTTWWZI LTNNNWWI LLLLNNWI
Picat
import sat, util.
rotate(Q) = Res => % rotate right by 90 degrees
NZ = len(Q[1]), NS = len(Q), Res = new_array(NZ,NS),
foreach(Z in 1..NZ, S in 1..NS) Res[Z,S] = Q[S,NZ+1-Z] end.
matprint(Q) =>
NZ = len(Q), NS = len(Q[1]),
foreach(Z in 1..NZ, S in 1..NS)
printf("%d|", Q[Z,S]),
if S=NS then nl end
end, nl.
generate(Res) =>
P0 = [{{1,1,1,1}, % L
{1,0,0,0}},
{{0,1,1,1}, % N
{1,1,0,0}},
{{1,1,1,1}, % Y
{0,1,0,0}},
{{1,1,0}, % F
{0,1,1},
{0,1,0}},
{{1,1,1}, % T
{0,1,0},
{0,1,0}},
{{0,0,1}, % W
{0,1,1},
{1,1,0}},
{{1,1,1}, % P
{1,1,0}},
{{0,0,1}, % V
{0,0,1},
{1,1,1}},
{{1,0,1}, % U
{1,1,1}},
{{1,0,0}, % Z
{1,1,1},
{0,0,1}},
{{1,1,1,1,1}}, % I
{{0,1,0}, % X
{1,1,1},
{0,1,0}}],
Np = len(P0), P = [],
foreach(I in 1..Np)
VarI = [P0[I]],
foreach(_ in 1..3) VarI := [rotate(head(VarI))|VarI] end,
P := [VarI|P]
end,
Res = P.
main =>
N = 8, M = new_array(N+4,N+4),
foreach(R in N+1..N+4, C in 1..N) M[R,C] #= 0 end,
foreach(R in 1..N, C in N+1..N+4) M[R,C] #= 0 end,
generate(P), % P[1] = X-Pentomino, then P[2] = I, P[3] = Z, and so on U, V, P, X, W, T, F, Y, N, L
Np = len(P), M :: 0..Np,
foreach(I in 1..Np) count(I, vars(M), 5) end, % 12 pentomino
Idx = new_list(Np), % X has 1 rotation variant, I and Z each 2, the rest 4:
Idx[1] #= 1, [Idx[2],Idx[3]] :: 1..2, Idx :: 1..4,
DZ = new_list(Np), DZ :: 0..N-1, % translation of I.th pentomino
DS = new_list(Np), DS :: 0..N-1,
foreach(I in 1..Np, J in 1..4) % Constraint only if Idx[I] #= J!
NZ = len(P[I,J]), NS = len(P[I,J,1]),
foreach(DZI in 0..N-1, DSI in 0..N-1, Z in 1..NZ, S in 1..NS, P[I,J,Z,S]=1)
(Idx[I] #= J #/\ DZ[I] #= DZI #/\ DS[I] #= DSI) #=> M[DZI+Z,DSI+S] #= I
end
end,
solve(vars(M) ++ DZ ++ DS ++ Idx),
Chr = " XIZUVPWTFYNL",
foreach(Z in 1..N)
foreach(S in 1..N)
printf("%c|", Chr[1 + M[Z,S]])
end, nl
end.
Output:
Y|Y|Y|Y|P|P|Z|Z| L|Y|X|P|P|P|Z|I| L|X|X|X|F|Z|Z|I| L| |X|F|F|U|U|I| L|L|T|W|F|F|U|I| V| |T|W|W|U|U|I| V|T|T|T|W|W|N|N| V|V|V| |N|N|N| |
Racket
(although purely functional, so no need to undo the tiling attempts)
#lang racket
(require racket/hash)
(module+ main (Pentomino-tiling))
(define n-rows 8)
(define n-cols 8)
(define blank '-)
(define (build-grid)
(for/fold ((grid (for*/hash ((r n-rows) (c n-cols)) (values (cons r c) #f)))) ((_ 4))
(hash-set grid (cons (random n-rows) (random n-cols)) blank)))
(define (make-shapes-map)
(hash 'F (F) 'I (I) 'L (L) 'N (N) 'P (P) 'T (T) 'U (U) 'V (V) 'W (W) 'X (X) 'Y (Y) 'Z (Z)))
(define (print-grid grid)
(for ((r n-rows) #:when (when (positive? r) (newline)) (c n-cols))
(write (hash-ref grid (cons r c))))
(newline))
(define (Pentomino-tiling (grid (build-grid)))
(define solution (solve 0 grid (make-shapes-map)))
(if solution (print-grid solution) (displayln "no solution")))
(define (solve p grid shapes (failed-shapes (hash)))
(define-values (r c) (quotient/remainder p n-cols))
(cond [(not grid) #f]
[(hash-empty? shapes) (and (hash-empty? failed-shapes) grid)]
[(hash-ref grid (cons r c) #f) (solve (add1 p) grid shapes failed-shapes)]
[else
(define s (car (hash-keys shapes)))
(define os (hash-ref shapes s))
(define shapes-s (hash-remove shapes s))
(define (try-place-orientation o)
(and (for/and ((dy.dx o))
(let ((y (+ r (car dy.dx))) (x (+ c (cdr dy.dx))))
(and (>= x 0) (>= y 0) (< x n-cols) (< y n-rows) (not (hash-ref grid (cons y x))))))
(for/fold ((grid (hash-set grid (cons r c) s))) ((dy.dx o))
(hash-set grid (cons (+ r (car dy.dx)) (+ c (cdr dy.dx))) s))))
(or (for*/first
((o os)
(solution (in-value (solve (add1 p)
(try-place-orientation o)
(hash-union shapes-s failed-shapes))))
#:when solution)
solution)
(solve p grid shapes-s (hash-set failed-shapes s os)))]))
(define (F) '(((1 . -1) (1 . 0) (1 . 1) (2 . 1))
((0 . 1) (1 . -1) (1 . 0) (2 . 0))
((1 . 0) (1 . 1) (1 . 2) (2 . 1))
((1 . 0) (1 . 1) (2 . -1) (2 . 0))
((1 . -2) (1 . -1) (1 . 0) (2 . -1))
((0 . 1) (1 . 1) (1 . 2) (2 . 1))
((1 . -1) (1 . 0) (1 . 1) (2 . -1))
((1 . -1) (1 . 0) (2 . 0) (2 . 1))))
(define (I) '(((0 . 1) (0 . 2) (0 . 3) (0 . 4))
((1 . 0) (2 . 0) (3 . 0) (4 . 0))))
(define (L) '(((1 . 0) (1 . 1) (1 . 2) (1 . 3))
((1 . 0) (2 . 0) (3 . -1) (3 . 0))
((0 . 1) (0 . 2) (0 . 3) (1 . 3))
((0 . 1) (1 . 0) (2 . 0) (3 . 0))
((0 . 1) (1 . 1) (2 . 1) (3 . 1))
((0 . 1) (0 . 2) (0 . 3) (1 . 0))
((1 . 0) (2 . 0) (3 . 0) (3 . 1))
((1 . -3) (1 . -2) (1 . -1) (1 . 0))))
(define (N) '(((0 . 1) (1 . -2) (1 . -1) (1 . 0))
((1 . 0) (1 . 1) (2 . 1) (3 . 1))
((0 . 1) (0 . 2) (1 . -1) (1 . 0))
((1 . 0) (2 . 0) (2 . 1) (3 . 1))
((0 . 1) (1 . 1) (1 . 2) (1 . 3))
((1 . 0) (2 . -1) (2 . 0) (3 . -1))
((0 . 1) (0 . 2) (1 . 2) (1 . 3))
((1 . -1) (1 . 0) (2 . -1) (3 . -1))))
(define (P) '(((0 . 1) (1 . 0) (1 . 1) (2 . 1))
((0 . 1) (0 . 2) (1 . 0) (1 . 1))
((1 . 0) (1 . 1) (2 . 0) (2 . 1))
((0 . 1) (1 . -1) (1 . 0) (1 . 1))
((0 . 1) (1 . 0) (1 . 1) (1 . 2))
((1 . -1) (1 . 0) (2 . -1) (2 . 0))
((0 . 1) (0 . 2) (1 . 1) (1 . 2))
((0 . 1) (1 . 0) (1 . 1) (2 . 0))))
(define (T) '(((0 . 1) (0 . 2) (1 . 1) (2 . 1))
((1 . -2) (1 . -1) (1 . 0) (2 . 0))
((1 . 0) (2 . -1) (2 . 0) (2 . 1))
((1 . 0) (1 . 1) (1 . 2) (2 . 0))))
(define (U) '(((0 . 1) (0 . 2) (1 . 0) (1 . 2))
((0 . 1) (1 . 1) (2 . 0) (2 . 1))
((0 . 2) (1 . 0) (1 . 1) (1 . 2))
((0 . 1) (1 . 0) (2 . 0) (2 . 1))))
(define (V) '(((1 . 0) (2 . 0) (2 . 1) (2 . 2))
((0 . 1) (0 . 2) (1 . 0) (2 . 0))
((1 . 0) (2 . -2) (2 . -1) (2 . 0))
((0 . 1) (0 . 2) (1 . 2) (2 . 2))))
(define (W) '(((1 . 0) (1 . 1) (2 . 1) (2 . 2))
((1 . -1) (1 . 0) (2 . -2) (2 . -1))
((0 . 1) (1 . 1) (1 . 2) (2 . 2))
((0 . 1) (1 . -1) (1 . 0) (2 . -1))))
(define (X) '(((1 . -1) (1 . 0) (1 . 1) (2 . 0))))
(define (Y) '(((1 . -2) (1 . -1) (1 . 0) (1 . 1))
((1 . -1) (1 . 0) (2 . 0) (3 . 0))
((0 . 1) (0 . 2) (0 . 3) (1 . 1))
((1 . 0) (2 . 0) (2 . 1) (3 . 0))
((0 . 1) (0 . 2) (0 . 3) (1 . 2))
((1 . 0) (1 . 1) (2 . 0) (3 . 0))
((1 . -1) (1 . 0) (1 . 1) (1 . 2))
((1 . 0) (2 . -1) (2 . 0) (3 . 0))))
(define (Z) '(((0 . 1) (1 . 0) (2 . -1) (2 . 0))
((1 . 0) (1 . 1) (1 . 2) (2 . 2))
((0 . 1) (1 . 1) (2 . 1) (2 . 2))
((1 . -2) (1 . -1) (1 . 0) (2 . -2))))
- Output:
-UUUPPPI NUXUPPTI NXXXTTTI NNXVVVTI -NZ-WVFI ZZZWWVFF ZYWWLFF- YYYYLLLL
Python
from itertools import product
minos = (((197123, 7, 6), (1797, 6, 7), (1287, 6, 7), (196867, 7, 6)),
((263937, 6, 6), (197126, 6, 6), (393731, 6, 6), (67332, 6, 6)),
((16843011, 7, 5), (2063, 5, 7), (3841, 5, 7), (271, 5, 7), (3848, 5, 7), (50463234, 7, 5), (50397441, 7, 5), (33686019, 7, 5)),
((131843, 7, 6), (1798, 6, 7), (775, 6, 7), (1795, 6, 7), (1543, 6, 7), (197377, 7, 6), (197378, 7, 6), (66307, 7, 6)),
((132865, 6, 6), (131846, 6, 6), (198146, 6, 6), (132611, 6, 6), (393986, 6, 6), (263938, 6, 6), (67330, 6, 6), (132868, 6, 6)),
((1039, 5, 7), (33751554, 7, 5), (16843521, 7, 5), (16974081, 7, 5), (33686274, 7, 5), (3842, 5, 7), (3844, 5, 7), (527, 5, 7)),
((1804, 5, 7), (33751297, 7, 5), (33686273, 7, 5), (16974338, 7, 5), (16843522, 7, 5), (782, 5, 7), (3079, 5, 7), (3587, 5, 7)),
((263683, 6, 6), (198148, 6, 6), (66310, 6, 6), (393985, 6, 6)),
((67329, 6, 6), (131591, 6, 6), (459266, 6, 6), (263940, 6, 6)),
((459780, 6, 6), (459009, 6, 6), (263175, 6, 6), (65799, 6, 6)),
((4311810305, 8, 4), (31, 4, 8)),
((132866, 6, 6),))
boxchar_double_width = ' ╶╺╵└┕╹┖┗╴─╼┘┴┶┚┸┺╸╾━┙┵┷┛┹┻╷┌┍│├┝╿┞┡┐┬┮┤┼┾┦╀╄┑┭┯┥┽┿┩╃╇╻┎┏╽┟┢┃┠┣┒┰┲┧╁╆┨╂╊┓┱┳┪╅╈┫╉╋'
boxchar_single_width = [c + ' ─━'[i%3] for i, c in enumerate(boxchar_double_width)]
# choose drawing alphabet based on terminal font
patterns = boxchar_single_width
tiles = []
for row in reversed(minos):
tiles.append([])
for n, x, y in row:
for shift in (b*8 + a for a, b in product(range(x), range(y))):
tiles[-1].append(n << shift)
def img(seq):
b = [[0]*10 for _ in range(10)]
for i, s in enumerate(seq):
for j, k in product(range(8), range(8)):
if s & (1<<(j*8 + k)):
b[j + 1][k + 1] = i + 1
idices = [[0]*9 for _ in range(9)]
for i, j in product(range(9), range(9)):
n = (b[i+1][j+1], b[i][j+1], b[i][j], b[i+1][j], b[i+1][j+1])
idices[i][j] = sum((a != b)*(1 + (not a or not b))*3**i for i, (a,b) in enumerate(zip(n, n[1:])))
return '\n'.join(''.join(patterns[i] for i in row) for row in idices)
def tile(board=0, seq=tuple(), tiles=tiles):
if not tiles:
yield img(seq)
return
for c in tiles[0]:
b = board | c
tnext = [] # not using list comprehension ...
for t in tiles[1:]:
tnext.append(tuple(n for n in t if not n&b))
if not tnext[-1]: break # because early break is faster
else:
yield from tile(b, seq + (c,), tnext)
for x in tile():
print(x)
- Output:
┏━┯━━━┯━━━━━━━┓ ┏━┛ └─┐ └─┬─┐ ┌─┨ ┠─┐ ┌─╆━┓ │ └─┘ ┃ ┃ ├─┤ ┗━┹─╆━┱───┨ ┃ │ └───┐ ┡━┹─┐ ┃ ┃ │ ┌─┬─┴─┘ ┌─┤ ┃ ┃ ┢━┪ ├───┬─┘ │ ┃ ┠─┺━┛ │ └─┐ └─┨ ┗━━━━━┷━━━━━┷━━━┛ ┏━┯━━━┓ ┏━┯━━━┓ ┏━┛ └─┐ ┗━┩ └─┐ ┃ ┠─┐ ┌─╆━┓ │ ┌─┘ ┃ ┃ ├─┤ ┗━┹─┤ ├───┨ ┃ │ └───┐ ├─┴─┐ ┃ ┃ │ ┌─┬─┴─┘ ┌─┤ ┃ ┃ ┢━┪ ├───┬─┘ │ ┃ ┠─┺━┛ │ └─┐ └─┨ ┗━━━━━┷━━━━━┷━━━┛ (goes on and on)
Raku
# 20201028 Raku programming solution
my \F = [ <1 -1 1 0 1 1 2 1>, <0 1 1 -1 1 0 2 0>, <1 0 1 1 1 2 2 1>,
<1 0 1 1 2 -1 2 0>, <1 -2 1 -1 1 0 2 -1>, <0 1 1 1 1 2 2 1>,
<1 -1 1 0 1 1 2 -1>, <1 -1 1 0 2 0 2 1> ];
my \I = [ <0 1 0 2 0 3 0 4>, <1 0 2 0 3 0 4 0> ];
my \L = [ <1 0 1 1 1 2 1 3>, <1 0 2 0 3 0 3 1>, <0 1 0 2 0 3 1 3>,
<0 1 1 0 2 0 3 0>, <0 1 1 1 2 1 3 1>, <0 1 0 2 0 3 1 0>,
<1 0 2 0 3 -1 3 0>, <1 -3 1 -2 1 -1 1 0> ];
my \N = [ <0 1 1 -2 1 -1 1 0>, <1 0 1 1 2 1 3 1>, <0 1 0 2 1 -1 1 0>,
<1 0 2 0 2 1 3 1>, <0 1 1 1 1 2 1 3>, <1 0 2 -1 2 0 3 -1>,
<0 1 0 2 1 2 1 3>, <1 -1 1 0 2 -1 3 -1> ];
my \P = [ <0 1 1 0 1 1 2 1>, <0 1 0 2 1 0 1 1>, <1 0 1 1 2 0 2 1>,
<0 1 1 -1 1 0 1 1>, <0 1 1 0 1 1 1 2>, <1 -1 1 0 2 -1 2 0>,
<0 1 0 2 1 1 1 2>, <0 1 1 0 1 1 2 0> ];
my \T = [ <0 1 0 2 1 1 2 1>, <1 -2 1 -1 1 0 2 0>,
<1 0 2 -1 2 0 2 1>, <1 0 1 1 1 2 2 0> ];
my \U = [ <0 1 0 2 1 0 1 2>, <0 1 1 1 2 0 2 1>,
<0 2 1 0 1 1 1 2>, <0 1 1 0 2 0 2 1> ];
my \V = [ <1 0 2 0 2 1 2 2>, <0 1 0 2 1 0 2 0>,
<1 0 2 -2 2 -1 2 0>, <0 1 0 2 1 2 2 2> ];
my \W = [ <1 0 1 1 2 1 2 2>, <1 -1 1 0 2 -2 2 -1>,
<0 1 1 1 1 2 2 2>, <0 1 1 -1 1 0 2 -1> ];
my \X = [ <1 -1 1 0 1 1 2 0> , ]; # self-ref: reddit.com/r/rakulang/comments/jpys5p/gbi71jt/
my \Y = [ <1 -2 1 -1 1 0 1 1>, <1 -1 1 0 2 0 3 0>, <0 1 0 2 0 3 1 1>,
<1 0 2 0 2 1 3 0>, <0 1 0 2 0 3 1 2>, <1 0 1 1 2 0 3 0>,
<1 -1 1 0 1 1 1 2>, <1 0 2 -1 2 0 3 0> ];
my \Z = [ <0 1 1 0 2 -1 2 0>, <1 0 1 1 1 2 2 2>,
<0 1 1 1 2 1 2 2>, <1 -2 1 -1 1 0 2 -2> ];
our @shapes = F, I, L, N, P, T, U, V, W, X, Y, Z ;
my @symbols = "FILNPTUVWXYZ-".comb;
my %symbols = @symbols.pairs;
my $nRows = my $nCols = 8; my $blank = 12;
my @grid = [ [-1 xx $nCols ] xx $nRows ];
my @placed;
sub shuffleShapes {
my @rand = (0 ..^+@shapes).pick(*);
for (0 ..^+@shapes) -> \i {
(@shapes[i], @shapes[@rand[i]]) = (@shapes[@rand[i]], @shapes[i]);
(@symbols[i], @symbols[@rand[i]]) = (@symbols[@rand[i]], @symbols[i])
}
}
sub solve($pos,$numPlaced) {
return True if $numPlaced == +@shapes;
my \row = $pos div $nCols;
my \col = $pos mod $nCols;
return solve($pos + 1, $numPlaced) if @grid[row;col] != -1;
for ^+@shapes -> \i {
if !@placed[i] {
for @shapes[i] -> @orientation {
for @orientation -> @o {
next if !tryPlaceOrientation(@o, row, col, i);
@placed[i] = True;
return True if solve($pos + 1, $numPlaced + 1);
removeOrientation(@o, row, col);
@placed[i] = False;
}
}
}
}
return False
}
sub tryPlaceOrientation (@o, $r, $c, $shapeIndex) {
loop (my $i = 0; $i < +@o; $i += 2) {
my \x = $c + @o[$i + 1];
my \y = $r + @o[$i];
return False if
(x < 0 or x ≥ $nCols or y < 0 or y ≥ $nRows or @grid[y;x] != -1)
}
@grid[$r;$c] = $shapeIndex;
loop ($i = 0; $i < +@o; $i += 2) {
@grid[ $r + @o[$i] ; $c + @o[$i + 1] ] = $shapeIndex;
}
return True
}
sub removeOrientation(@o, $r, $c) {
@grid[$r;$c] = -1;
loop (my $i = 0; $i < +@o; $i += 2) {
@grid[ $r + @o[$i] ; $c + @o[$i + 1] ] = -1;
}
}
sub PrintResult {
my $output;
for @grid[*] -> @line {
$output ~= "%symbols{$_} " for @line;
$output ~= "\n"
}
if my \Embedded_Marketing_Mode = True {
$output .= subst('-', $_.chr) for < 0x24c7 0x24b6 0x24c0 0x24ca >
}
say $output
}
#shuffleShapes(); # xkcd.com/221
for ^4 {
loop {
if @grid[my \R = (^$nRows).roll;my \C = (^$nCols).roll] != $blank
{ @grid[R;C] = $blank and last }
}
}
PrintResult() if solve 0,0
- Output:
F F Ⓡ I I I I I Ⓐ F F N L L L L P F N N X U U L P P N X X X U Ⓚ P P N W X U U T V Z Ⓤ W W T T T V Z Z Z W W Y T V V V Z Y Y Y Y
Wren
import "random" for Random
import "./iterate" for Stepped
var F = [
[1, -1, 1, 0, 1, 1, 2, 1], [0, 1, 1, -1, 1, 0, 2, 0],
[1, 0, 1, 1, 1, 2, 2, 1], [1, 0, 1, 1, 2, -1, 2, 0],
[1, -2, 1, -1, 1, 0, 2, -1], [0, 1, 1, 1, 1, 2, 2, 1],
[1, -1, 1, 0, 1, 1, 2, -1], [1, -1, 1, 0, 2, 0, 2, 1]
]
var I = [
[0, 1, 0, 2, 0, 3, 0, 4], [1, 0, 2, 0, 3, 0, 4, 0]
]
var L = [
[1, 0, 1, 1, 1, 2, 1, 3], [1, 0, 2, 0, 3, -1, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 3], [0, 1, 1, 0, 2, 0, 3, 0],
[0, 1, 1, 1, 2, 1, 3, 1], [0, 1, 0, 2, 0, 3, 1, 0],
[1, 0, 2, 0, 3, 0, 3, 1], [1, -3, 1, -2, 1, -1, 1, 0]
]
var N = [
[0, 1, 1, -2, 1, -1, 1, 0], [1, 0, 1, 1, 2, 1, 3, 1],
[0, 1, 0, 2, 1, -1, 1, 0], [1, 0, 2, 0, 2, 1, 3, 1],
[0, 1, 1, 1, 1, 2, 1, 3], [1, 0, 2, -1, 2, 0, 3, -1],
[0, 1, 0, 2, 1, 2, 1, 3], [1, -1, 1, 0, 2, -1, 3, -1]
]
var P = [
[0, 1, 1, 0, 1, 1, 2, 1], [0, 1, 0, 2, 1, 0, 1, 1],
[1, 0, 1, 1, 2, 0, 2, 1], [0, 1, 1, -1, 1, 0, 1, 1],
[0, 1, 1, 0, 1, 1, 1, 2], [1, -1, 1, 0, 2, -1, 2, 0],
[0, 1, 0, 2, 1, 1, 1, 2], [0, 1, 1, 0, 1, 1, 2, 0]
]
var T = [
[0, 1, 0, 2, 1, 1, 2, 1], [1, -2, 1, -1, 1, 0, 2, 0],
[1, 0, 2, -1, 2, 0, 2, 1], [1, 0, 1, 1, 1, 2, 2, 0]
]
var U = [
[0, 1, 0, 2, 1, 0, 1, 2], [0, 1, 1, 1, 2, 0, 2, 1],
[0, 2, 1, 0, 1, 1, 1, 2], [0, 1, 1, 0, 2, 0, 2, 1]
]
var V = [
[1, 0, 2, 0, 2, 1, 2, 2], [0, 1, 0, 2, 1, 0, 2, 0],
[1, 0, 2, -2, 2, -1, 2, 0], [0, 1, 0, 2, 1, 2, 2, 2]
]
var W = [
[1, 0, 1, 1, 2, 1, 2, 2], [1, -1, 1, 0, 2, -2, 2, -1],
[0, 1, 1, 1, 1, 2, 2, 2], [0, 1, 1, -1, 1, 0, 2, -1]
]
var X = [[1, -1, 1, 0, 1, 1, 2, 0]]
var Y = [
[1, -2, 1, -1, 1, 0, 1, 1], [1, -1, 1, 0, 2, 0, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 1], [1, 0, 2, 0, 2, 1, 3, 0],
[0, 1, 0, 2, 0, 3, 1, 2], [1, 0, 1, 1, 2, 0, 3, 0],
[1, -1, 1, 0, 1, 1, 1, 2], [1, 0, 2, -1, 2, 0, 3, 0]
]
var Z = [
[0, 1, 1, 0, 2, -1, 2, 0], [1, 0, 1, 1, 1, 2, 2, 2],
[0, 1, 1, 1, 2, 1, 2, 2], [1, -2, 1, -1, 1, 0, 2, -2]
]
var shapes = [F, I, L, N, P, T, U, V, W, X, Y, Z]
var rand = Random.new()
var symbols = "FILNPTUVWXYZ-".toList
var nRows = 8
var nCols = 8
var blank = 12
var grid = List.filled(nRows, null)
for (i in 0...nRows) grid[i] = List.filled(nCols, 0)
var placed = List.filled(symbols.count - 1, false)
var tryPlaceOrientation = Fn.new { |o, r, c, shapeIndex|
for (i in Stepped.new(0...o.count, 2)) {
var x = c + o[i + 1]
var y = r + o[i]
if (x < 0 || x >= nCols || y < 0 || y >= nRows || grid[y][x] != - 1) return false
}
grid[r][c] = shapeIndex
for (i in Stepped.new(0...o.count, 2)) grid[r + o[i]][c + o[i + 1]] = shapeIndex
return true
}
var removeOrientation = Fn.new { |o, r, c|
grid[r][c] = -1
for (i in Stepped.new(0...o.count, 2)) grid[r + o[i]][c + o[i + 1]] = -1
}
var solve // recursive
solve = Fn.new { |pos, numPlaced|
if (numPlaced == shapes.count) return true
var row = (pos / nCols).floor
var col = pos % nCols
if (grid[row][col] != -1) return solve.call(pos + 1, numPlaced)
for (i in 0...shapes.count) {
if (!placed[i]) {
for (orientation in shapes[i]) {
if (!tryPlaceOrientation.call(orientation, row, col, i)) continue
placed[i] = true
if (solve.call(pos + 1, numPlaced + 1)) return true
removeOrientation.call(orientation, row, col)
placed[i] = false
}
}
}
return false
}
var shuffleShapes = Fn.new {
var n = shapes.count
while (n > 1) {
var r = rand.int(n)
n = n - 1
shapes.swap(r, n)
symbols.swap(r, n)
}
}
var printResult = Fn.new {
for (r in grid) {
for (i in r) System.write("%(symbols[i]) ")
System.print()
}
}
shuffleShapes.call()
for (r in 0...nRows) {
for (c in 0...grid[r].count) grid[r][c] = -1
}
for (i in 0..3) {
var randRow
var randCol
while (true) {
randRow = rand.int(nRows)
randCol = rand.int(nCols)
if (grid[randRow][randCol] != blank) break
}
grid[randRow][randCol] = blank
}
if (solve.call(0, 0)) printResult.call() else System.print("No solution")
- Output:
Sample run:
L L L L V U U U Y Z Z L V U - U Y Y Z - V V V T Y W Z Z X T T T Y W W X X X F T P P W W X F F F P P N N N F - - P N N I I I I I
zkl
fcn printResult
{ foreach row in (grid){ row.apply(symbols.get).concat(" ").println() } }
fcn tryPlaceOrientation(o, R,C, shapeIndex){
foreach ro,co in (o){ r,c:=R+ro, C+co;
if(r<0 or r>=nRows or c<0 or c>=nCols or grid[r][c]!=-1) return(False);
}
grid[R][C]=shapeIndex; foreach ro,co in (o){ grid[R+ro][C+co]=shapeIndex }
True
}
fcn removeOrientation(o, r,c)
{ grid[r][c]=-1; foreach ro,co in (o){ grid[r+ro][c+co]=-1 } }
fcn solve(pos,numPlaced){
if(numPlaced==target) return(True);
row,col:=pos.divr(nCols);
if(grid[row][col]!=-1) return(solve(pos+1,numPlaced));
foreach i in (shapes.len()){
if(not placed[i]){
foreach orientation in (shapes[i]){
if(not tryPlaceOrientation(orientation, row,col, i)) continue;
placed[i]=True;
if(solve(pos+1,numPlaced+1)) return(True);
removeOrientation(orientation, row,col);
placed[i]=False;
}
}
}
False
}
reg [private] // the shapes are made of groups of 4 (r,c) pairs
_F=T(T(1,-1, 1,0, 1,1, 2,1), T(0,1, 1,-1, 1,0, 2,0),
T(1,0 , 1,1, 1,2, 2,1), T(1,0, 1,1, 2,-1, 2,0), T(1,-2, 1,-1, 1,0, 2,-1),
T(0,1, 1,1, 1,2, 2,1), T(1,-1, 1,0, 1,1, 2,-1), T(1,-1, 1,0, 2,0, 2,1)),
_I=T(T(0,1, 0,2, 0,3, 0,4), T(1,0, 2,0, 3,0, 4,0)),
_L=T(T(1,0, 1,1, 1,2, 1,3), T(1,0, 2,0, 3,-1, 3,0),
T(0,1, 0,2, 0,3, 1,3), T(0,1, 1,0, 2,0, 3,0), T(0,1, 1,1, 2,1, 3,1),
T(0,1, 0,2, 0,3, 1,0), T(1,0, 2,0, 3,0, 3,1), T(1,-3, 1,-2, 1,-1, 1,0)),
_N=T(T(0,1, 1,-2, 1,-1, 1,0), T(1,0, 1,1, 2,1, 3,1),
T(0,1, 0,2, 1,-1, 1,0), T(1,0, 2,0, 2,1, 3,1), T(0,1, 1,1, 1,2, 1,3),
T(1,0, 2,-1, 2,0, 3,-1),T(0,1, 0,2, 1,2, 1,3), T(1,-1, 1,0, 2,-1, 3,-1)),
_P=T(T(0,1, 1,0, 1,1, 2,1), T(0,1, 0,2, 1,0, 1,1),
T(1,0, 1,1, 2,0, 2,1), T(0,1, 1,-1, 1,0, 1,1), T(0,1, 1,0, 1,1, 1,2),
T(1,-1, 1,0, 2,-1, 2,0), T(0,1, 0,2, 1,1, 1,2), T(0,1, 1,0, 1,1, 2,0)),
_T=T(T(0,1, 0,2, 1,1, 2,1), T(1,-2, 1,-1, 1,0, 2,0),
T(1,0, 2,-1, 2,0, 2,1), T(1,0, 1,1, 1,2, 2,0)),
_U=T(T(0,1, 0,2, 1,0, 1,2), T(0,1, 1,1, 2,0, 2,1),
T(0,2, 1,0, 1,1, 1,2), T(0,1, 1,0, 2,0, 2,1)),
_V=T(T(1,0, 2,0, 2,1, 2,2), T(0,1, 0,2, 1,0, 2,0),
T(1,0, 2,-2, 2,-1, 2,0), T(0,1, 0,2, 1,2, 2,2)),
_W=T(T(1,0, 1,1, 2,1, 2,2), T(1,-1, 1,0, 2,-2, 2,-1),
T(0,1, 1,1, 1,2, 2,2), T(0,1, 1,-1, 1,0, 2,-1)),
_X=T(T(1,-1, 1,0, 1,1, 2,0)),
_Y=T(T(1,-2, 1,-1, 1,0, 1,1), T(1,-1, 1,0, 2,0, 3,0),
T(0,1, 0,2, 0,3, 1,1), T(1,0, 2,0, 2,1, 3,0), T(0,1, 0,2, 0,3, 1,2),
T(1,0, 1,1, 2,0, 3,0), T(1,-1, 1,0, 1,1, 1,2), T(1,0, 2,-1, 2,0, 3,0)),
_Z=T(T(0,1, 1,0, 2,-1, 2,0), T(1,0, 1,1, 1,2, 2,2),
T(0,1, 1,1, 2,1, 2,2), T(1,-2, 1,-1, 1,0, 2,-2));
const nRows=8, nCols=8, target=12, blank=12;
var [const]
grid = nRows.pump(List(),nCols.pump(List(),-1).copy),
placed = target.pump(List(),False),
symbols="FILNPTUVWXYZ-".split(""),
shapes=T(_F,_I,_L,_N,_P,_T,_U,_V,_W,_X,_Y,_Z) // ((a,b, c,d))-->(((a,b),(c,d)))
.pump(List,List("pump",List,List("pump",List,Void.Read,T.create)));
foreach r,c in ([0..nRows-1].walk().shuffle().zip([0..nCols-1].walk().shuffle())[0,4])
{ grid[r][c]=blank } // make sure 4 unique random spots
if(solve(0,0)) printResult();
else println("No solution");
- Output:
F Y Y Y Y U U U F F F Y - U X U I F W W L X X X I W W N L - X T I W N N L T T T I V N L L Z Z T I V N P P P Z - - V V V P P Z Z