Free polyominoes enumeration: Difference between revisions

m
(alphabetize, minor clean-up)
m (→‎{{header|Wren}}: Minor tidy)
 
(8 intermediate revisions by 6 users not shown)
Line 32:
└─┘</pre>
 
For a slow but clear solution see this Haskell Wiki page: [http://www.haskell.org/haskellwiki/The_Monad.Reader/Issue5/Generating_Polyominoes Generating Polyominoes]
 
http://www.haskell.org/haskellwiki/The_Monad.Reader/Issue5/Generating_Polyominoes
 
<b>Bonus Task</b>: you can create an alternative program (or specialize your first program) to generate very quickly just the number of distinct free polyominoes, and to show a sequence like:
Line 39:
1, 1, 1, 2, 5, 12, 35, 108, 369, 1285, 4655, 17073, 63600, 238591, 901971, 3426576, ...
 
Number of free polyominoes (or square animals) with n cells: [[oeis:A000105|OEIS: A000105]]
http://oeis.org/A000105
 
 
Line 49 ⟶ 48:
{{trans|D}}
Turns out the source for the counting only version of the D code example could be tweaked to show solutions as well. The max rank can be changed by supplying a command line parameter. The free polyominos of any rank can be displayed by changing the variable named '''target''' to a reasonable number. This program will also indicate the estimated times for larger ranks.
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
Line 296 ⟶ 295:
}
}
</syntaxhighlight>
</lang>
{{out}}
<pre>Counting polyominoes to rank 11...
Line 335 ⟶ 334:
=={{header|D}}==
{{trans|Haskell}}
<langsyntaxhighlight lang="d">import std.stdio, std.range, std.algorithm, std.typecons, std.conv;
 
alias Coord = byte;
Line 416 ⟶ 415:
foreach (const poly; n.rank)
writefln("%-(%s\n%)\n", poly.textRepresentation);
}</langsyntaxhighlight>
{{out}}
<pre>[1, 1, 2, 5, 12, 35, 108, 369, 1285, 4655]
Line 477 ⟶ 476:
Translated and modified from C code: http://www.geocities.jp/tok12345/countomino.txt
 
<langsyntaxhighlight lang="d">import core.stdc.stdio: printf;
import core.stdc.stdlib: atoi;
 
Line 645 ⟶ 644:
 
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>1
Line 677 ⟶ 676:
=={{header|Elixir}}==
{{trans|Ruby}}
<langsyntaxhighlight lang="elixir">defmodule Polyominoes do
defp translate2origin(poly) do
# Finds the min x and y coordiate of a Polyomino.
Line 751 ⟶ 750:
IO.puts "\nAll free polyominoes of rank #{n}:"
Enum.sort(Polyominoes.rank(n))
|> Enum.each(fn poly -> IO.puts "#{Polyominoes.text_representation(poly)}\n" end)</langsyntaxhighlight>
 
{{out}}
Line 802 ⟶ 801:
=={{header|Go}}==
{{trans|Kotlin}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 976 ⟶ 975:
}
fmt.Println()
}</langsyntaxhighlight>
 
{{out}}
Line 1,003 ⟶ 1,002:
 
Code updated and slightly improved from: http://www.haskell.org/haskellwiki/The_Monad.Reader/Issue5/Generating_Polyominoes
<langsyntaxhighlight lang="haskell">import System.Environment (getArgs)
import Control.Arrow ((***), first)
import Data.Set (toList, fromList)
Line 1,099 ⟶ 1,098:
let n = bool (read $ head args :: Int) 5 (null args)
putStrLn ("\nAll free polyominoes of rank " ++ show n ++ ":")
mapM_ (putStrLn . textRepresentation) (rank n)</langsyntaxhighlight>
{{out}}
<pre>[1,1,2,5,12,35,108,369,1285,4655]
Line 1,161 ⟶ 1,160:
Generating polyominoes as ascii art:
 
<langsyntaxhighlight Jlang="j">polyominoes=:verb define
if. 1>y do. i.0 0 0 return.end.
if. 1=y do. 1 1 1$'#' return.end.
Line 1,199 ⟶ 1,198:
trim=:verb define&|:^:2
y#~+./"1 y~:' '
)</langsyntaxhighlight>
 
Example use (boxing each pentomino for display purposes):
 
<langsyntaxhighlight lang="j"> <"2 polyominoes 5
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│#####│## │# │### │## │## │### │ ## │ # │ # │ # │ ## │
Line 1,209 ⟶ 1,208:
│ │# │# │# │# │## │ │## │## │### │ # │# │
│ │# │# │ │ │ │ │ │ │ │ │ │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘</langsyntaxhighlight>
 
=={{header|Java}}==
Translation of [[Free_polyominoes_enumeration#Haskell|Haskell]] via [[Free_polyominoes_enumeration#D|D]]
{{works with|Java|8}}
<langsyntaxhighlight lang="java">import java.awt.Point;
import java.util.*;
import static java.util.Arrays.asList;
Line 1,317 ⟶ 1,316:
}
}
}</langsyntaxhighlight>
 
<pre>(0,0) (0,1) (1,1) (1,2) (2,1)
Line 1,331 ⟶ 1,330:
(0,0) (0,1) (0,2) (1,0) (2,0)
(0,0) (0,1) (0,2) (0,3) (0,4)</pre>
 
=={{header|JavaScript}}==
<syntaxhighlight lang="javascript">const width = window.innerWidth;
const height = window.innerHeight;
const p = Math.floor(width/140);
const verticalScrollbarWidth = 15;
const elementSize = 1;
 
let maxHeight;
let cellSize, xSpacing, ySpacing, xOffset, yOffset;
let test_poly, starting_poly;
let stored_polys;
let maxPolyLength;
let jsonData;
let polysFound;
let typeSelected, orderSelected, modeSelected, orderValue;
 
let canvas = document.createElement('canvas');
canvas.id = "myCanvas";
canvas.width = width;
canvas.height = height;
let parentDiv = document.getElementById("div_polys");
parentDiv.appendChild(canvas);
canvas.style.backgroundColor = "lightblue";
let ctx = canvas.getContext("2d"); // Get the 2D rendering context
 
let buttonBack = document.createElement("button");
buttonBack.innerHTML = "<b>Back</b>";
buttonBack.id = "back_button_id";
buttonBack.classList.add("back_button_class");
buttonBack.style.fontSize = (7*p).toString() + "px";
buttonBack.style.position = "absolute";
buttonBack.style.top = (3*p).toString() + "px";
buttonBack.style.right = (5*p).toString() + "px";
buttonBack.style.display = "none";
buttonBack.addEventListener("click", function() {
canvas.height = height;
document.getElementById("div_polys").style.display = "none";
document.getElementById("div_menu").style.display = "block";
window.scrollTo(0,0);
stored_polys = null;
jsonData = null;
});
document.getElementById("div_polys").style.display = "block";
parentDiv.appendChild(buttonBack);
 
let buttonBack2 = buttonBack.cloneNode(true);
buttonBack2.addEventListener("click", function() {
canvas.height = height;
document.getElementById("div_polys").style.display = "none";
document.getElementById("div_menu").style.display = "block";
window.scrollTo(0,0);
stored_polys = null;
jsonData = null;
});
parentDiv.appendChild(buttonBack2);
 
//hide the info bubble when the user taps outside it on Safari browser
document.body.addEventListener("click", function(event) {
const popUps = document.querySelectorAll(".pop-up");
popUps.forEach(popUp => {
if (popUp.style.display === "block") {
popUp.style.display = "none";
}
});
});
 
function iOS() {
return [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod'
].includes(navigator.platform)
// iPad on iOS 13 detection
|| (navigator.userAgent.includes("Mac") && "ontouchend" in document)
}
 
function showPolyDiv() {
document.getElementById("div_menu").style.display = "none";
document.getElementById("div_polys").style.display = "block";
window.scrollTo(0,0);
buttonBack.style.display = "none";
buttonBack2.style.display = "none";
ctx.clearRect(0, 0, canvas.width, canvas.height);
typeSelected = document.querySelector('input[name="type"]:checked').value;
orderSelected = document.querySelector('input[name="order"]:checked').value;
orderValue = parseInt(orderSelected);
modeSelected = document.querySelector('input[name="mode"]:checked').value;
 
if (iOS()) {
maxHeight = 16383;
} else {
maxHeight = 65535;
}
 
fetchPolys();
}
 
function fetchPolys() {
if (orderValue === 1) modeSelected = "1"; // So that it doesn't create the order-one polyomino because it cannot start from the previous order.
if (modeSelected === "2") {
orderSelected--;
}
cellSize = (14/(orderValue*0.35))*p; // size of each cell of a polyomino when displayed on screen
xSpacing = cellSize; ySpacing = cellSize; // horizontal and vertical spacing between polyominoes when they are displayed on screen
xOffset = xSpacing; yOffset = 20*p; // spaces between the polys displayed
canvas.width = width;
canvas.height = maxHeight; // max height
maxPolyLength = 0;
stored_polys = new Set(); // because it is set to null after returning to the menu screen
 
fetch(typeSelected + orderSelected + ".json")
.then(response => response.json())
.then(json => {
jsonData = json;
if (modeSelected === "1") displayPolys();
else if (modeSelected === "2") createPolys();
else console.log("no mode selected");
})
.catch(error => console.log(error));
}
 
function createJson(order, type, multitude, polys) {
let content =
{
order: order,
type: type,
multitude: multitude,
polys: polys
};
 
// ********** Save a JSON file with the FileSaver library (large files, more options) ************
let jsonString = JSON.stringify(content);
let blob = new Blob([jsonString], { type: "application/json;charset=utf-8" });
saveAs(blob, type + order.toString()+".json");
}
 
function createPolys() {
polysFound = 0;
for (let i = 0; i < jsonData.polys.length; i++) {
starting_poly = jsonData.polys[i];
nextOrderPolys(starting_poly);
}
if (yOffset + 3*ySpacing > maxHeight) { // max height
//canvas.height = maxHeight;
} else {
let imageData = ctx.getImageData(0, 0, canvas.width, yOffset + maxPolyLength*cellSize + ySpacing);
canvas.height = yOffset + maxPolyLength*cellSize + ySpacing;
ctx.putImageData(imageData, 0, 0);
}
ctx.fillStyle = "black";
ctx.font = (5*p).toString() + "px Verdana";
ctx.fillText(jsonData.type + " polyominoes of order " + orderValue + ": ", 6*p, 10*p);
ctx.fillText(polysFound, 6*p, 17*p);
console.log(jsonData.type + " polyominoes of order " + orderValue + " found: " + polysFound + ". Max canvas height: " + maxHeight);
let stored_polys_array = new Uint8Array(elementSize);
stored_polys_array = parseArray(stored_polys);
buttonBack2.style.top = (canvas.height - 15*p).toString() + "px";
buttonBack.style.display = "block";
if (canvas.height > height) {
buttonBack2.style.display = "block";
}
createJson(jsonData.order + 1, jsonData.type, polysFound, stored_polys_array);
}
 
function displayPolys() {
for (let i = 0; i < jsonData.polys.length; i++) {
starting_poly = jsonData.polys[i];
showPoly(starting_poly);
}
if (yOffset + 3*ySpacing > maxHeight) { // max height
//canvas.height = maxHeight;
} else {
let imageData = ctx.getImageData(0, 0, canvas.width, yOffset + maxPolyLength*cellSize + ySpacing);
canvas.height = yOffset + maxPolyLength*cellSize + ySpacing;
ctx.putImageData(imageData, 0, 0);
}
ctx.fillStyle = "black";
ctx.font = (5*p).toString() + "px Verdana";
ctx.fillText(jsonData.type + " polyominoes of order " + jsonData.order + ": ", 6*p, 10*p);
ctx.fillText(jsonData.polys.length, 6*p, 17*p);
console.log(jsonData.type + " polyominoes of order " + jsonData.order + ": " + jsonData.polys.length + ". Max canvas height: " + maxHeight);
buttonBack2.style.top = (canvas.height - 15*p).toString() + "px";
buttonBack.style.display = "block";
if (canvas.height > height) {
buttonBack2.style.display = "block";
}
}
 
function parseArray(stored) {
// gets a Set object of strings and returns an Array object of arrays
let arrayOfArrays = new Uint8Array(elementSize);
arrayOfArrays = [];
let arrayOfStrings = Array.from(stored);
for (let i = 0; i < arrayOfStrings.length; i++) {
arrayOfArrays.push(JSON.parse(arrayOfStrings[i]));
}
return arrayOfArrays;
}
 
function nextOrderPolys(poly) {
let poly1, poly2 = new Uint8Array(elementSize);
poly1 = addBlanksAroundPoly(poly);
 
for (let y = 0; y < poly1.length; y++) {
for (let x = 0; x < poly1[y].length; x++) {
if (poly1[y][x] === 0) {
try {
if (poly1[y+1][x] === 1) {
checkPoly(poly1, y, x);
}
} catch (error) { }
try {
if (poly1[y][x-1] === 1) {
checkPoly(poly1, y, x);
}
} catch (error) { }
try {
if (poly1[y-1][x] === 1) {
checkPoly(poly1, y, x);
}
} catch (error) { }
try {
if (poly1[y][x+1] === 1) {
checkPoly(poly1, y, x);
}
} catch (error) { }
}
}
}
 
}
 
function checkPoly(poly, i, j) {
let poly2, trunc_poly, rot_poly = new Uint8Array(elementSize);
let r;
poly2 = poly.map(subArray => subArray.slice()); //copies 2D array poly 1 to poly2
poly2[i][j] = 1; //2D array poly1 is not affected by this operation
trunc_poly = truncatePoly(poly2);
 
if (jsonData.type === "fixed") {
if (stored_polys.has(JSON.stringify(trunc_poly))) { // there is an identical poly in the Set
return;
}
} else if (jsonData.type === "one-sided") {
if (stored_polys.has(JSON.stringify(trunc_poly))) { // there is an identical poly in the Set
return;
}
rot_poly = trunc_poly;
for (r = 0; r < 3; r++) { // rotate the candidate poly 3 times and check if there is an identical poly in the Set
rot_poly = rotateLeftPoly(rot_poly);
if (stored_polys.has(JSON.stringify(rot_poly))) { // there is an identical poly in the Set
return;
}
}
} else if (jsonData.type === "free") {
if (stored_polys.has(JSON.stringify(trunc_poly))) { // there is an identical poly in the Set
return;
}
rot_poly = trunc_poly;
for (r = 0; r < 3; r++) { // rotate the candidate poly 3 times and check if there is an identical poly in the Set
rot_poly = rotateLeftPoly(rot_poly);
if (stored_polys.has(JSON.stringify(rot_poly))) { // there is an identical poly in the Set
return;
}
}
rot_poly = mirrorXPoly(rot_poly); // mirror candidate poly and check again
if (stored_polys.has(JSON.stringify(rot_poly))) { // there is an identical poly in the Set
return;
}
for (r = 0; r < 3; r++) { // rotate the candidate poly 3 times and check if there is an identical poly in the Set
rot_poly = rotateLeftPoly(rot_poly);
if (stored_polys.has(JSON.stringify(rot_poly))) { // there is an identical poly in the Set
return;
}
}
}
 
stored_polys.add(JSON.stringify(trunc_poly)); // The candidate poly is new. Store it in the Set
polysFound++;
showPoly(trunc_poly);
}
 
function showPoly(poly) {
ctx.lineWidth = 0.5*p;
 
//Check if the rightmost end of the new poly will be displayed outside the screen width and if yes, display the new poly in the next row
if (xOffset + poly[0].length*cellSize + verticalScrollbarWidth + ySpacing > width) {
xOffset = xSpacing;
yOffset += maxPolyLength*cellSize + ySpacing;
maxPolyLength = 0;
}
 
//display the new poly
let randomColor = "rgb("+(Math.random()*215+40)+","+(Math.random()*215+40)+","+(Math.random()*215+40)+")";
for (let y = 0; y < poly.length; y++) {
for (let x = 0; x < poly[y].length; x++) {
ctx.beginPath();
if (poly[y][x] === 1) {
ctx.fillStyle = randomColor;
ctx.strokeStyle = "black";
} else {
//ctx.fillStyle = "white";
ctx.fillStyle = "transparent";
ctx.strokeStyle = "transparent";
}
ctx.rect(xOffset + x*cellSize, yOffset + y*cellSize, cellSize, cellSize);
ctx.fill();
ctx.stroke();
}
}
 
xOffset += poly[0].length*cellSize + xSpacing; // set the left margin of the new poly to be displayed
//sets the next row for the new poly to be displayed as the maximum height from the previous row
if (poly.length > maxPolyLength) {
maxPolyLength = poly.length;
}
}
 
function truncatePoly(poly) {
let x, y;
let new_poly, transposedArray = new Uint8Array(elementSize);
//truncate rows
new_poly = [];
for (y = 0; y < poly.length; y++) {
for (x = 0; x < poly[y].length; x++) {
if (poly[y][x] === 1) {
new_poly.push(poly[y]); //copy this row to a new array
break;
}
}
}
//reverse rows and columns of the trancated array
transposedArray = new_poly[0].map((col, i) => new_poly.map(row => row[i]));
//truncate rows of the new array, so that we have trancated both rows and columns
new_poly = [];
for (y = 0; y < transposedArray.length; y++) {
for (x = 0; x < transposedArray[y].length; x++) {
if (transposedArray[y][x] === 1) {
new_poly.push(transposedArray[y]); //copy this row to a new array
break;
}
}
}
//reverse rows and columns of the trancated array again, so that the new array has the same orientation with the original
transposedArray = new_poly[0].map((col, i) => new_poly.map(row => row[i]));
return transposedArray;
}
 
function rotateLeftPoly(poly) {
let transposedArray = new Uint8Array(elementSize);
//reverse rows and columns of the original array
transposedArray = poly[0].map((col, i) => poly.map(row => row[i]));
//mirrors the transposed array
return transposedArray.slice().reverse();
}
 
function mirrorXPoly(poly) {
let mirr_poly = new Uint8Array(elementSize);
mirr_poly = poly.slice().reverse();
return mirr_poly;
}
 
function mirrorYPoly(poly) {
let mirr_poly = new Uint8Array(elementSize);
mirr_poly = poly.map(subArr => subArr.slice().reverse());
return mirr_poly;
}
 
function addBlanksAroundPoly(poly) {
//creates a loop of blank cells around a poly, so that new filled cells can be placed in the next poly order
let newLengthX = poly[0].length + 2;
let newLengthY = poly.length + 2;
let new_poly = new Uint8Array(elementSize);
new_poly = Array.from({length: newLengthY}, () => Array(newLengthX).fill(0)); //creates a 2D array filled with zeros
for (let y = 0; y < poly.length; y++) {
for (let x = 0; x < poly[y].length; x++) {
new_poly[y+1][x+1] = poly[y][x];
}
}
return new_poly;
}</syntaxhighlight>
 
{{out}}
*[https://grifoi.org/polyominoes/index.html A JavaScript polyomino maker application]
 
=={{header|Julia}}==
{{trans|Haskell}}
<langsyntaxhighlight lang="julia">import Base.show, Base.==, Base.hash
 
struct Point x::Float64; y::Float64 end
Line 1,423 ⟶ 1,810:
 
testpolys()
</langsyntaxhighlight>{{out}}
<pre>
[1, 1, 2, 5, 12, 35, 108, 369, 1285, 4655]
Line 1,472 ⟶ 1,859:
=={{header|Kotlin}}==
{{trans|Python}}
<langsyntaxhighlight lang="scala">// version 1.1.51
 
class Point(val x: Int, val y: Int) : Comparable<Point> {
Line 1,552 ⟶ 1,939:
for (i in 1..k) print("${rank(i).size} ")
println()
}</langsyntaxhighlight>
 
{{out}}
Line 1,575 ⟶ 1,962:
</pre>
 
=={{header|PhixNim}}==
{{trans|Kotlin}}
{{trans|C#}} ... but didn't bother with Wrap()
<syntaxhighlight lang="nim">import algorithm, sequtils, strutils, sugar
<lang Phix>-- demo\rosetta\Polyominoes.exw
integer n, ns, -- rank, rank squared
target, -- rank to display
clipAt, -- max columns for display
fSiz, fWid -- field size, width
sequence polys, -- results
AnyR, -- Any Rotation count
nFlip, -- Non-Flipped count
Frees, -- Free Polyominoes count
fChk, fCkR, -- field checks
dirs, -- directions
rotO, rotX, rotY -- rotations
 
type Point = tuple[x, y: int]
-- (character indexes only work properly in utf32:)
constant glyphs = utf8_to_utf32(" 12└4┘─┴8│┌├┐┤┬┼")
 
func rotate90(p: Point): Point = (p.y, -p.x)
function Puzzle(string a, string b) -- tests each intersection to determine correct corner symbol
func rotate180(p: Point): Point = (-p.x, -p.y)
sequence res = ""
func rotate270(p: Point): Point = (-p.y, p.x)
if length(a)>length(b) then b &= repeat(' ', length(a)-length(b)) end if
func reflect(p: Point): Point = (-p.x, p.y)
if length(a)<length(b) then a &= repeat(' ', length(b)-length(a)) end if
for i=1 to length(a)-1 do
integer n=i+1
res &= glyphs[iff(a[i]==a[n]?0:1) +
iff(b[n]==a[n]?0:2) +
iff(a[i]==b[i]?0:4) +
iff(b[i]==b[n]?0:8) + 1];
end for
return utf32_to_utf8(res)
end function
 
func `$`(p: Point): string = "($1, $2)".format(p.x, p.y)
function flipXY(sequence p) -- flips a small string
sequence res = repeat("",length(p[1]))
for i=1 to length(res) do
for j=1 to length(p) do res[i] &= p[j][i] end for
end for
return res
end function
 
function double_width(string s)
string t = ""
for i=1 to length(s) do
integer ch = s[i]
t &= ch&ch
end for
return t
end function
function Cornered(string s) -- converts plain ascii art into cornered version
sequence lines = split(s,'\n')
string res = ""
string line = repeat(' ', length(lines[1])*2), last
for i=1 to length(lines) do
last = line
line = double_width(lines[i])
res &= Puzzle(last, line) & '\n'
end for
res &= Puzzle(line, repeat(' ', length(lines[$])*2)) & '\n'
return res
end function
 
type Polyomino = seq[Point]
function Assemble(sequence p)
-- assembles string representation of polyominoes into larger horizontal band
sequence lines = repeat("",target)
for i=1 to length(p) do
sequence t = split(p[i],'\n')
if length(t)<length(t[1]) then t = flipXY(t) end if
for l=1 to length(lines) do
lines[l] &= iff(l<=length(t)?' '&t[l]&' ':repeat(' ',length(t[1])+2))
end for
end for
for i=length(lines) to 1 by -1 do
if find('#',lines[i])=0 then lines[i..i] = {} end if
end for
return Cornered(join(lines,"\n"))&"\n"
end function
function toStr(sequence field)
-- converts field into a minimal string
string res = repeat(' ',n*(fWid+1)-1)
for i=fWid+1 to length(res) by fWid+1 do res[i] = '\n' end for
integer i = 0, j = n-2
while i<length(field) do
if and_bits(field[i+1],1)=1 then res[j+1] = '#' end if
if mod(j,fWid+1)==fWid then i -= 1 end if
i += 1
j += 1
end while
sequence t = split(res,'\n')
integer nn = 100, m = 0, v, k = 0; -- trim down
for i = 1 to length(t) do
string s = t[i]
v = find('#',s)
if v=0 then exit end if
if v<nn then nn=v end if
v = rfind('#',s)
if v>m then m=v end if
k += 1
end for
t = t[1..k]
for i=1 to length(t) do
t[i] = t[i][nn..m]
end for
if platform()=WINDOWS then return t end if
res = join(t,'\n')
return res
end function
 
func minima(poly: Polyomino): (int, int) =
procedure CheckIt(sequence field, integer lv)
## Finds the min x and y coordinates of a polyomino.
AnyR[lv] += 1
(min(poly.mapIt(it.x)), min(poly.mapIt(it.y)))
for i=1 to ns do fChk[i] = 0 end for
integer x, y
bool bail = false
for x=n to fWid-1 do
for y=0 to fSiz-x by fWid do
bail = and_bits(field[x+y+1],1)=1
if bail then exit end if
end for
if bail then exit end if
end for
integer x2 = n - x, t, of1, of2, r
for i=1 to fSiz do
if and_bits(field[i],1)==1 then
t = (i + n - 3)
fChk[mod(t,fWid)+x2+floor(t/fWid)*n+1] = 1
end if
end for
for of1=1 to length(fChk) do if fChk[of1]!=0 then exit end if end for
bool c = true
for r=2 to 8 do
for x=0 to n-1 do
for y=0 to n-1 do
fCkR[rotO[r]+rotX[r]*x+rotY[r]*y+1] = fChk[x+y*n+1]
end for
end for
for of2=1 to length(fCkR) do if fCkR[of2]!=0 then exit end if end for
of2 -= of1
integer i = of1
while true do
if i>=ns-iff(of2>0?of2:0) then exit end if
if fChk[i+1]>fCkR[i+of2+1] then exit end if
if fChk[i+1]<fCkR[i+of2+1] then c = false; exit end if
i += 1
end while
if not c then exit end if
end for
if r>4 then nFlip[lv] +=1 end if
if c then
if lv==target+1 then polys=append(polys,toStr(field)) end if
Frees[lv] += 1
end if
end procedure
 
func translateToOrigin(poly: Polyomino): Polyomino =
function Recurse(integer lv, sequence field, putlist, integer putno, putlast)
let (minX, minY) = poly.minima
-- this is probably about ten times slower than C#...
result = sorted(poly.mapIt((it.x - minX, it.y - minY)))
-- (some you win, some you lose - it has certainly not helped converting
-- 0-based indexing to 1-based simply by adding +1 almost everywhere.)
CheckIt(field, lv)
if n<lv then return {field,putlist} end if
integer pos
for i=putno to putlast do
pos = putlist[i]
field[pos+1] = or_bits(field[pos+1],1)
integer k = 0
for d=1 to length(dirs) do
integer pos2 = pos + dirs[d]
if 0<=pos2 and pos2<fSiz and field[pos2+1]==0 then
field[pos2+1] = 2
k += 1
putlist[putlast+k] = pos2
end if
end for
{field,putlist} = Recurse(lv+1, field, putlist, i+1, putlast+k)
for j=1 to k do field[putlist[putlast+j]+1] = 0 end for
field[pos+1] = 2
end for
for i=putno to putlast do field[putlist[i]+1] = and_bits(field[putlist[i]+1],-2) end for
return {field,putlist}
end function
 
func rotationsAndReflections(poly: Polyomino): seq[Polyomino] =
procedure CountEm()
@[poly,
ns = n * n
poly.mapIt(it.rotate90),
AnyR = repeat(0,n+1)
poly.mapIt(it.rotate180),
nFlip = repeat(0,n+1)
poly.mapIt(it.rotate270),
Frees = repeat(0,n+1)
poly.mapIt(it.reflect),
fWid = n*2 - 2
poly.mapIt(it.rotate90.reflect),
fSiz = (n-1)*(n-1)*2 + 1
poly.mapIt(it.rotate180.reflect),
sequence pnField = repeat(0,fSiz),
poly.mapIt(it.rotate270.reflect)]
pnPutList = repeat(0,fSiz)
 
fChk = repeat(0,ns)
func canonical(poly: Polyomino): Polyomino =
fCkR = repeat(0,ns)
sortedByIt(poly.rotationsAndReflections.map(translateToOrigin), $it)[0]
dirs = {1, fWid, -1, -fWid}
 
rotO = {0, n-1, ns-1, ns-n, n-1, 0, ns-n, ns-1}
func contiguous(p: Point): array[4, Point] =
rotX = {1, n, -1, -n, -1, n, 1, -n}
# Return all four points in Von Neumann neighborhood.
rotY = {n, -1, -n, 1, n, 1, -n, -1}
[(p.x - {}1, =p.y), Recurse(p.x + 1, pnFieldp.y), pnPutList(p.x, p.y - 1), (p.x, p.y + 1)]
 
end procedure
func newPoints(poly: Polyomino): seq[Point] =
## Return all distinct points that can be added to a Polyomino.
result = collect(newSeq):
for point in poly:
for pt in point.contiguous():
if pt notin poly: pt
result = result.deduplicate()
 
func newPolys(poly: Polyomino): seq[Polyomino] =
collect(newSeq, for pt in poly.newPoints: canonical(poly & pt))
 
const Monominoes = @[@[(x: 0, y: 0)]]
 
func rank(n: Natural): seq[Polyomino] =
if n == 0: return newSeq[Polyomino]()
if n == 1: return Monominoes
result = collect(newSeq):
for poly in rank(n - 1):
for p in poly.newPolys(): p
result = sortedByIt(result, $it).deduplicate(true)
 
when isMainModule:
 
let n = 5
echo "All free polyominoes of rank $#:\n".format(n)
for poly in rank(n): echo poly.join(" ")
 
let k = 10
echo "\nNumber of free polyominoes of ranks 1 to $#:".format(k)
for i in 1..k: stdout.write rank(i).len, ' '
echo()</syntaxhighlight>
 
procedure main()
polys = {}
n = 11
target = 5
printf(1,"Counting polyominoes to rank %d...\n", n)
clipAt = 120
atom start = time()
CountEm()
atom ti = time()-start
if length(polys)>0 then
printf(1,"Displaying rank %d:\n", target);
if platform()=LINUX then
puts(1,Assemble(polys))
else
-- Windows consoles not so clever with unicode...
integer w = 0
sequence lines = {}
for i=1 to length(polys) do
for j=1 to length(polys[i]) do
if j>length(lines) then
lines = append(lines,repeat(' ',w))
end if
lines[j] &= repeat(' ',w-length(lines[j]))
if i>1 then lines[j] &= " " end if
lines[j] &= polys[i][j]
end for
w = length(lines[1])
end for
puts(1,join(lines,"\n")&"\n")
end if
end if
printf(1,"Displaying results:\n")
printf(1," n All Rotations Non-Flipped Free Polys\n")
for i=2 to n+1 do
printf(1,"%2d : %16d %15d %15d\n", {i-1, AnyR[i], nFlip[i], Frees[i]})
end for
printf(1,"Elapsed: %s\n",{elapsed(ti)})
atom ms = ti*1000
if ms>250 then
printf(1,"Estimated completion times:\n")
for i=n+1 to n+10 do
ms = (ms+44)*4
printf(1,"%2d : %s\n",{i,elapsed(ms/1000)})
end for
end if
{} = wait_key()
end procedure
main()</lang>
{{out}}
<pre>All free polyominoes of rank 5:
(windows)
 
(0, 0) (0, 1) (0, 2) (0, 3) (0, 4)
(0, 0) (0, 1) (0, 2) (0, 3) (1, 0)
(0, 0) (0, 1) (0, 2) (0, 3) (1, 1)
(0, 0) (0, 1) (0, 2) (1, 0) (1, 1)
(0, 0) (0, 1) (0, 2) (1, 0) (1, 2)
(0, 0) (0, 1) (0, 2) (1, 0) (2, 0)
(0, 0) (0, 1) (0, 2) (1, 1) (2, 1)
(0, 0) (0, 1) (0, 2) (1, 2) (1, 3)
(0, 0) (0, 1) (1, 1) (1, 2) (2, 1)
(0, 0) (0, 1) (1, 1) (1, 2) (2, 2)
(0, 0) (0, 1) (1, 1) (2, 1) (2, 2)
(0, 1) (1, 0) (1, 1) (1, 2) (2, 1)
 
Number of free polyominoes of ranks 1 to 10:
1 1 2 5 12 35 108 369 1285 4655 </pre>
 
=={{header|Perl}}==
Only shows the polyominoes up to rank 5.
<syntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict;
use warnings;
 
my @new = "#\n";
 
for my $N ( 2 .. 10 )
{
@new = find( @new );
my %allbest;
$allbest{best($_)}++ for @new;
my @show = @new = sort keys %allbest;
printf "rank: %2d count: %d\n\n", $N, scalar @show;
if( @show <= 12 )
{
my $fmt = join '', map({ /\n/; '%' . ($+[0] + 1) . 's' } @show), "\n";
grep $_, @show and printf $fmt, map s/(.*)\n// && $1, @show for 0 .. $N;
print "\n";
}
}
 
sub bare
{
local $_ = shift;
s/^ *\n//gm;
s/^ //gm until /^#/m;
s/ $//gm until /#$/m;
$_;
}
 
sub transpose
{
local $_ = shift;
my $t = '';
$t .= "\n" while s/^./ $t .= $&; '' /gem;
$t;
}
 
sub rotate
{
local $_ = shift;
my $t = '';
$t .= "\n" while s/.$/ $t .= $&; '' /gem;
$t;
}
 
sub best
{
my %all = (shift, 1);
for my $p (keys %all)
{
$all{ my $tmp = rotate $p }++;
$all{ rotate $tmp }++;
}
$all{ transpose $_ }++ for keys %all;
$all{ s/(.+)/reverse $1/ger }++ for keys %all; # mirror
(sort keys %all)[-1];
}
 
sub find
{
my @before = @_;
my %new;
for my $p ( @before )
{
local $_ = $p;
s/^/ /gm;
s/\n/ \n/g;
my $line = s/\n.*/\n/sr =~ tr/\n/ /cr;
$_ = $line . $_ . $line;
my $n = -1 + length $line;
my $gap = qr/.{$n}/s;
$new{ bare "$`#$'" }++ while / (?=#)/g;
$new{ bare "$`#$'" }++ while / (?=$gap#)/g;
$new{ bare "$`#$'" }++ while /(?<=#) /g;
$new{ bare "$`#$'" }++ while /(?<=#$gap) /g;
}
keys %new;
}</syntaxhighlight>
{{out}}
<pre>
rank: 2 count: 1
Counting polyominoes to rank 11...
 
Displaying rank 5:
##
### ### ### #### ### ## ## ## #### ### ##### #
 
## # ## # # # ## # ## # # ###
rank: 3 count: 2
# # ## # # #
 
Displaying results:
## ###
n All Rotations Non-Flipped Free Polys
#
1 : 1 1 1
 
2 : 2 1 1
rank: 4 count: 5
3 : 6 2 2
 
4 : 19 7 5
## ## ### ### ####
5 : 63 18 12
6 : ## ## # # 216 60 35
 
7 : 760 196 108
rank: 5 count: 12
8 : 2725 704 369
 
9 : 9910 2500 1285
10 : # ## ## ## 36446 ### ### ### ### ### 9189 #### #### 4655#####
11 : ### # ## 135268## # # # 33896# ## ## # # 17073
# ## # # # #
Elapsed: 5.8s
 
Estimated completion times:
rank: 6 count: 35
12 : 23.5s
 
13 : 1 minute and 34s
rank: 7 count: 108
14 : 6 minutes and 17s
 
15 : 25 minutes and 07s
rank: 8 count: 369
16 : 1 hour, 40 minutes and 28s
 
17 : 6 hours, 41 minutes and 52s
rank: 9 count: 1285
18 : 1 day, 2 hours, 47 minutes and 27s
 
19 : 4 days, 11 hours, 9 minutes and 49s
rank: 10 count: 4655
20 : 17 days, 20 hours, 39 minutes and 14s
 
21 : 71 days, 10 hours, 36 minutes and 57s
</pre>
 
=={{header|Phix}}==
Written for clarity over raw speed.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Polyominoes.exw</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">rotate90</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">x</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">reflectx</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">rotflect</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">xy</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #7060A8;">call_func</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">xy</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">rotationsAndReflections</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">poly</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- All the plane symmetries of a rectangular region.
-- (ie orig plus 3*90 plus reflect and another 3*90)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">poly</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">8</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">5</span><span style="color: #0000FF;">?</span><span style="color: #000000;">reflectx</span><span style="color: #0000FF;">:</span><span style="color: #000000;">rotate90</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">apply</span><span style="color: #0000FF;">(</span><span style="color: #004600;">true</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rotflect</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">translateToOrigin</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">poly</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- Ensure {minx,miny} is/move it to {1,1}</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">minx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">vslice</span><span style="color: #0000FF;">(</span><span style="color: #000000;">poly</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">))-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">miny</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">vslice</span><span style="color: #0000FF;">(</span><span style="color: #000000;">poly</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">))-</span><span style="color: #000000;">1</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">unique</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">apply</span><span style="color: #0000FF;">(</span><span style="color: #004600;">true</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">sq_sub</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">poly</span><span style="color: #0000FF;">,{{</span><span style="color: #000000;">minx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">miny</span><span style="color: #0000FF;">}}}))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">canonical_poly</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">poly</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- Returns unique/min representation, eg {{1,1},{1,2}} not {{1,1},{2,1}}</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">apply</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rotationsAndReflections</span><span style="color: #0000FF;">(</span><span style="color: #000000;">poly</span><span style="color: #0000FF;">),</span><span style="color: #000000;">translateToOrigin</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">contiguous</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">pt</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- All four points in Von Neumann neighborhood</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pt</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">new_points</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">poly</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- Finds all distinct points that can be added to a Polyomino.</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">poly</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">contiguous</span><span style="color: #0000FF;">(</span><span style="color: #000000;">poly</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">unique</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">new_polys</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- Finds all polys that can be created by adding one more point.</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">pts</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">new_points</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pts</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">pt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pts</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pt</span><span style="color: #0000FF;">,</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">poly</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">),</span><span style="color: #000000;">pt</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">canonical_poly</span><span style="color: #0000FF;">(</span><span style="color: #000000;">poly</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">ranks</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{{{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}}}}</span> <span style="color: #000080;font-style:italic;">-- (rank[1] = a single monomino)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">rank</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #0000FF;">{}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">></span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ranks</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ranks</span><span style="color: #0000FF;">[$],</span> <span style="color: #000080;font-style:italic;">-- (extend last)</span>
<span style="color: #000000;">polys</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">polys</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">new_polys</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">polys</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">unique</span><span style="color: #0000FF;">(</span><span style="color: #000000;">polys</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">ranks</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ranks</span><span style="color: #0000FF;">,</span><span style="color: #000000;">polys</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">ranks</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">print_polys</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- pp(p,{pp_Nest,1})</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">n</span><span style="color: #0000FF;">+</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),</span><span style="color: #000000;">l</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">n</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">pi</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pi</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pi</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">][</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)*(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'#'</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n%s\n\n"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">10</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">ri</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rank</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"rank:%d count:%d\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">)})</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">></span><span style="color: #000000;">0</span> <span style="color: #008080;">and</span> <span style="color: #000000;">i</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">5</span> <span style="color: #008080;">then</span> <span style="color: #000000;">print_polys</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ri</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
(linux)
<pre>
rank:1  count:1
Displaying rank 5:
 
┌───┐ ┌─────┐ ┌─┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┐ ┌─────┐ ┌─┐ ┌─┐
  # 
│ │ │ ┌───┘ ┌─┘ │ │ ┌─┘ │ ┌─┘ ┌─┘ ┌─┘ │ ┌─┘ ┌─┘ ┌─┘ │ └─┐ └─┐ ┌─┘ │ │ ┌─┘ └─┐
 
│ ┌─┘ │ │ │ ┌─┘ │ │ │ └─┐ └─┐ │ ┌─┘ │ │ ┌─┘ │ ┌─┘ │ │ │ │ └─┐ ┌─┘
rank:2  count:1
└─┘ └─┘ │ │ │ │ └───┘ └─┘ └───┘ └─┘ │ │ └─┘ │ │ └─┘
 
└─┘ └─┘ └─┘ │ │
  #  
└─┘
  #  
 
rank:3  count:2
 
  #   ##  
  #   #   
  #       
 
rank:4  count:5
 
  #    ##   #    ##   #    
  #    #    ##   ##   ##   
  #    #    #          #   
  #                        
 
rank:5  count:12
 
  #     ##    #     ##    ##    ###   #     #     #     #     #      #    
  #     #     ##    ##    #     #     ###   #     ###   ##    ###   ###   
  #     #     #     #     ##    #     #     ##     #     ##     #    #    
  #     #     #                              #                            
  #                                                                       
 
rank:6  count:35
rank:7  count:108
rank:8  count:369
rank:9  count:1285
rank:10  count:4655
</pre>
 
=={{header|Python}}==
{{trans|Haskell}}
<langsyntaxhighlight lang="python">from itertools import imap, imap, groupby, chain, imap
from operator import itemgetter
from sys import argv
Line 1,948 ⟶ 2,389:
print text_representation(poly), "\n"
 
main()</langsyntaxhighlight>
{{out}}
<pre>[1, 1, 2, 5, 12, 35, 108, 369, 1285, 4655]
Line 2,007 ⟶ 2,448:
not included in code below). But I think it's interesting nonetheless.
 
<langsyntaxhighlight lang="racket">#lang typed/racket
;; Inspired by C code in http://www.geocities.jp/tok12345/countomino.txt
;; but tries to take advantage of arbitrary width integers
Line 2,220 ⟶ 2,661:
(when (< n 6) (draw-polynominoes p))
(printf "count: ~a~%~%" (length (polynominoes-shapes p)))
(flush-output))))</langsyntaxhighlight>
 
{{out}}
Line 2,300 ⟶ 2,741:
=={{header|Ruby}}==
{{trans|Python}}
<langsyntaxhighlight lang="ruby">require 'set'
 
def translate2origin(poly)
Line 2,371 ⟶ 2,812:
n = ARGV[0] ? ARGV[0].to_i : 5
puts "\nAll free polyominoes of rank %d:" % n
rank(n).sort.each{|poly| puts text_representation(poly),""}</langsyntaxhighlight>
 
{{out}}
Line 2,423 ⟶ 2,864:
Translation of [[Free_polyominoes_enumeration#Haskell|Haskell]] via [[Free_polyominoes_enumeration#D|Java]]
{{works with|Scala|2.12}}
<langsyntaxhighlight Scalalang="scala">object Free {
type Point = (Int, Int)
type Polyomino = List[Point]
Line 2,491 ⟶ 2,932:
}
}
}</langsyntaxhighlight>
 
<pre>(0,0) (0,1) (1,1) (1,2) (2,1)
Line 2,508 ⟶ 2,949:
=={{header|Sidef}}==
{{trans|Ruby}}
<langsyntaxhighlight lang="ruby">func translate2origin(poly) {
# Finds the min x and y coordiate of a Polyomino.
var minx = poly.map(:head).min
Line 2,583 ⟶ 3,024:
var n = (ARGV[0] ? ARGV[0].to_i : 5)
say ("\nAll free polyominoes of rank %d:" % n)
rank(n).sort.each{|poly| say text_representation(poly).join("\n")+"\n" }</langsyntaxhighlight>
{{out}}
<pre style="height:250px">
Line 2,629 ⟶ 3,070:
###
#
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-trait}}
{{libheader|Wren-math}}
{{libheader|Wren-sort}}
{{libheader|Wren-seq}}
<syntaxhighlight lang="wren">import "./trait" for Comparable
import "./math" for Nums
import "./sort" for Sort, Cmp
import "./seq" for Lst
import "io" for Stdout
 
class Point is Comparable {
construct new(x, y) {
_x = x
_y = y
}
 
x { _x }
y { _y }
 
rotate90() { Point.new( _y, -_x) }
rotate180() { Point.new(-_x, -_y) }
rotate270() { Point.new(-_y, _x) }
reflect() { Point.new(-_x, _y) }
 
compare(other) {
if (other.type != Point) Fiber.abort("Argument must be a point.")
if (_x == other.x && _y == other.y) return 0
if (_x < other.x || (_x == other.x && _y < other.y)) return -1
return 1
}
 
// All four points in Von Neumann neighborhood
contiguous {
return [
Point.new(_x - 1, _y), Point.new(_x + 1, _y),
Point.new(_x, _y - 1), Point.new(_x, _y + 1)
]
}
 
toString { "(%(x), %(y))" }
}
 
var DistinctByString = Fn.new { |list|
var m = {}
for (e in list) m[e.toString] = e
return m.keys.map { |key| m[key] }.toList
}
 
class Polyomino {
construct new(points) {
_points = points
}
 
points { _points }
 
// Finds the min x and y coordinates of a Polyomino.
minima {
var minX = Nums.min(_points.map { |p| p.x })
var minY = Nums.min(_points.map { |p| p.y })
return [minX, minY]
}
 
translateToOrigin() {
var mins = minima
var points = _points.map { |p| Point.new(p.x - mins[0], p.y - mins[1]) }.toList
Sort.quick(points)
return Polyomino.new(points)
}
 
// All the plane symmetries of a rectangular region.
rotationsAndReflections {
return [
Polyomino.new(_points),
Polyomino.new(_points.map { |p| p.rotate90() }.toList),
Polyomino.new(_points.map { |p| p.rotate180() }.toList),
Polyomino.new(_points.map { |p| p.rotate270() }.toList),
Polyomino.new(_points.map { |p| p.reflect() }.toList),
Polyomino.new(_points.map { |p| p.rotate90().reflect() }.toList),
Polyomino.new(_points.map { |p| p.rotate180().reflect() }.toList),
Polyomino.new(_points.map { |p| p.rotate270().reflect() }.toList)
]
}
 
canonical {
var toos = rotationsAndReflections.map { |poly| poly.translateToOrigin() }.toList
var cmp = Fn.new { |i, j| Cmp.string.call(i.toString, j.toString) }
Sort.quick(toos, 0, toos.count - 1, cmp)
return toos[0]
}
 
// Finds all distinct points that can be added to a Polyomino.
newPoints {
var fn = Fn.new { |p| p.contiguous }
var t = Lst.flatMap(_points, fn).where { |p| !_points.contains(p) }.toList
return DistinctByString.call(t)
}
 
newPolys { newPoints.map { |p| Polyomino.new(_points + [p]).canonical }.toList }
 
toString { _points.map { |p| p.toString }.join(" ") }
}
 
var monomino = Polyomino.new([Point.new(0, 0)])
var monominoes = [monomino]
 
// Generates polyominoes of rank n recursively.
var rank
rank = Fn.new { |n|
if (n < 0) Fiber.abort("n cannot be negative.")
if (n == 0) return []
if (n == 1) return monominoes
var t = Lst.flatMap(rank.call(n-1)) { |poly| poly.newPolys }.toList
t = DistinctByString.call(t)
var cmp = Fn.new { |i, j| Cmp.string.call(i.toString, j.toString) }
Sort.quick(t, 0, t.count - 1, cmp)
return t
}
 
var n = 5
System.print("All free polyominoes of rank %(n):\n")
for (poly in rank.call(n)) {
for (pt in poly.points) System.write("%(pt) ")
System.print()
}
var k = 10
System.print("\nNumber of free polyominoes of ranks 1 to %(k):")
for (i in 1..k) {
System.write("%(rank.call(i).count) ")
Stdout.flush()
}
System.print()</syntaxhighlight>
 
{{out}}
<pre>
All free polyominoes of rank 5:
 
(0, 0) (0, 1) (0, 2) (0, 3) (0, 4)
(0, 0) (0, 1) (0, 2) (0, 3) (1, 0)
(0, 0) (0, 1) (0, 2) (0, 3) (1, 1)
(0, 0) (0, 1) (0, 2) (1, 0) (1, 1)
(0, 0) (0, 1) (0, 2) (1, 0) (1, 2)
(0, 0) (0, 1) (0, 2) (1, 0) (2, 0)
(0, 0) (0, 1) (0, 2) (1, 1) (2, 1)
(0, 0) (0, 1) (0, 2) (1, 2) (1, 3)
(0, 0) (0, 1) (1, 1) (1, 2) (2, 1)
(0, 0) (0, 1) (1, 1) (1, 2) (2, 2)
(0, 0) (0, 1) (1, 1) (2, 1) (2, 2)
(0, 1) (1, 0) (1, 1) (1, 2) (2, 1)
 
Number of free polyominoes of ranks 1 to 10:
1 1 2 5 12 35 108 369 1285 4655
</pre>
9,476

edits