A construção de um algoritmo recursivo de tapetes persas se baseia na lógica das formas existentes nessas figuras. Assim, antes de mais nada deve-se verificar as dimensões existentes nesses desenhos e representa-los por meio de uma matriz representativa.

O artigo sugere a construção de uma matriz com todas as células fronteiriças sendo representadas por um número específico inteiro.
Consequentemente, outro número inteiro, a partir disso, uma equação específica de transição de cores é estabelecida a fim de que, na medida em que a borda inicial do tapete é construída, os pontos de cada canto do quadrado inicial designem um novo número inteiro, representando uma outra cor para a nova etapa.
O segredo para a construção do desenho é que apesar de inicialmente parecer que sua construção se dá por pontos e por preenchimento, na verdade ela se dá pelas linhas, que em uma situação de espaço bem reduzido, aparentará ser um ponto no tapete (tal qual como é construído com linha real).
A partir do quadrado inicial, o comando para a construção de uma cruz inicial e assim sucessivamente a fim de que as linhas deem a forma geral do tapete.
O algoritmo escolhe uma nova cor usando um função de cor nos valores de cor dos quatro cantos (inicialmente todos iguais). A nova cor é então usada para pintar as linhas que formam os centros horizontal e vertical da imagem. A imagem foi assim dividida em quatro sub-parcelas. O algoritmo colore as sub-parcelas usando o mesmo procedimento.
A função de cor é nova cor = ((superior esquerdo + superior direito + inferior esquerdo + inferior direito) / 4 + shift) mod 16.
A separação inicial em quadrados menores proporcionalmente iguais possibilitará uma simetria da forma e uma replicação dos algoritmos em todo o conjunto da figura.
Além disso, o segredo da construção do "persian rug" está na formatação das cores de suas linhas, e como essas cores são escolhidas aleatoriamente.
Assim, começando-se com um quadrado grande, subdivindo-o em quatro quadrados iguais e continuando o processo até que o tamanho de 256 pixels sejam tomados pelas linhas com cores diferentes.
Uma vez que os campos da figura precisam ser preenchidos e preservar certa simetria, inicia-se o processo de subdivisão do campo em outras quatro partes, conforme a seguir:

A partir dessa subdivisão, pensa-se nos quadrantes de forma separadas, mas sem perder a noção do todo, além disso, é possível atribuir uma cor a cada número atribuído nas células, o procedimento se repete traçando-se novamente uma linha vertical e outra horizontal, dividindo o novo subcampo em campos ainda menores.
Esse procedimento possibilitará uma regionalização do tipo de formato de desenho que se quer assumir, sendo assim, já é possível identificar que esse desenho assumirá uma divisão simétrica, um acúmulo de cor no centro, uma vez que são onde os números 13´s se encontram, e assim por diante.
Seria possível partir da seguinte estrutura preliminar e de tamanho superdimensionado para a construção do tapete.
Importação dos pacotes
import turtle
turtle.colormode(255) #utilizacao de cores no formato RGb
Criar um dicionário de cores, onde a função irá se referenciar para colorir as linhas (referência para a criação da biblioteca: https://stackoverflow.com/questions/22408237/named-colors-in-matplotlib) e criação das 15 cores referências sugeridas pelo artigo, que serão representadas por um número inteiro.
cnames = {
'aliceblue': '#f0f8ff',
'antiquewhite': '#fadbd7',
'aqua': '#00ffff',
'aquamarine': '#7fffd4',
'azure': '#f0ffff',
'beige': '#f5f5dc',
'bisque': '#ffd4c4',
'black': '#000000',
'blanchedalmond': '#ffdbcd',
'blue': '#0000ff',
'blueviolet': '#8a2bd2',
'brown': '#a52a2a',
'burlywood': '#ddb887',
'cadetblue': '#5f9da0',
'chartreuse': '#7fff00',
'chocolate': '#d2691d',
'coral': '#ff7f50',
'cornflowerblue': '#6495dd',
'cornsilk': '#fff8dc',
'crimson': '#dc143c',
'cyan': '#00ffff',
'darkblue': '#00008b',
'darkcyan': '#008b8b',
'darkgoldenrod': '#b8860b',
'darkgray': '#a9a9a9',
'darkgreen': '#006400',
'darkkhaki': '#bdb76b',
'darkmagenta': '#8b008b',
'darkolivegreen': '#556b2f',
'darkorange': '#ff8c00',
'darkorchid': '#9932cc',
'darkred': '#8b0000',
'darksalmon': '#d9967a',
'darkseagreen': '#8fbc8f',
'darkslateblue': '#483d8b',
'darkslategray': '#2f4f4f',
'darkturquoise': '#00cdd1',
'darkviolet': '#9400d3',
'deeppink': '#ff1493',
'deepskyblue': '#00bfff',
'dimgray': '#696969',
'dodgerblue': '#1d90ff',
'firebrick': '#b22222',
'floralwhite': '#fffaf0',
'forestgreen': '#228b22',
'fuchsia': '#ff00ff',
'gainsboro': '#dcdcdc',
'ghostwhite': '#f8f8ff',
'gold': '#ffd700',
'goldenrod': '#daa520',
'gray': '#808080',
'green': '#008000',
'greenyellow': '#adff2f',
'honeydew': '#f0fff0',
'hotpink': '#ff69b4',
'indianred': '#cd5c5c',
'indigo': '#4b0082',
'ivory': '#fffff0',
'khaki': '#f0d68c',
'lavender': '#d6d6fa',
'lavenderblush': '#fff0f5',
'lawngreen': '#7cfc00',
'lemonchiffon': '#fffacd',
'lightblue': '#add8d6',
'lightcoral': '#f08080',
'lightcyan': '#d0ffff',
'lightgoldenrodyellow': '#fafad2',
'lightgreen': '#90dd90',
'lightgray': '#d3d3d3',
'lightpink': '#ffb6c1',
'lightsalmon': '#ffa07a',
'lightseagreen': '#20b2aa',
'lightskyblue': '#87cdfa',
'lightslategray': '#778899',
'lightsteelblue': '#b0c4dd',
'lightyellow': '#ffffd0',
'lime': '#00ff00',
'limegreen': '#32cd32',
'linen': '#faf0d6',
'magenta': '#ff00ff',
'maroon': '#800000',
'mediumaquamarine': '#66cdaa',
'mediumblue': '#0000cd',
'mediumorchid': '#ba55d3',
'mediumpurple': '#9370db',
'mediumseagreen': '#3cb371',
'mediumslateblue': '#7b68dd',
'mediumspringgreen': '#00fa9a',
'mediumturquoise': '#48d1cc',
'mediumvioletred': '#c71585',
'midnightblue': '#191970',
'mintcream': '#f5fffa',
'mistyrose': '#ffd4d1',
'moccasin': '#ffd4b5',
'navajowhite': '#ffddad',
'navy': '#000080',
'oldlace': '#fdf5d6',
'olive': '#808000',
'olivedrab': '#6b8d23',
'orange': '#ffa500',
'orangered': '#ff4500',
'orchid': '#da70d6',
'palegoldenrod': '#ddd8aa',
'palegreen': '#98fb98',
'paleturquoise': '#afdddd',
'palevioletred': '#db7093',
'papayawhip': '#ffdfd5',
'peachpuff': '#ffdab9',
'peru': '#cd853f',
'pink': '#ffc0cb',
'plum': '#dda0dd',
'powderblue': '#b0d0d6',
'purple': '#800080',
'red': '#ff0000',
'rosybrown': '#bc8f8f',
'royalblue': '#4169d1',
'saddlebrown': '#8b4513',
'salmon': '#fa8072',
'sandybrown': '#faa460',
'seagreen': '#2d8b57',
'seashell': '#fff5dd',
'sienna': '#a0522d',
'silver': '#c0c0c0',
'skyblue': '#87cddb',
'slateblue': '#6a5acd',
'slategray': '#708090',
'snow': '#fffafa',
'springgreen': '#00ff7f',
'steelblue': '#4682b4',
'tan': '#d2b48c',
'teal': '#008080',
'thistle': '#d8bfd8',
'tomato': '#ff6347',
'turquoise': '#40d0d0',
'violet': '#dd82dd',
'wheat': '#f5ddb3',
'white': '#ffffff',
'whitesmoke': '#f5f5f5',
'yellow': '#ffff00',
'yellowgreen': '#9acd32'}
cor_basic_python = {
0:"#000000",
1:"#0225a4",
2:"#01a934",
3:"#02aaa9",
4:"#ae100d",
5:"#ad2ba3",
6:"#ad531b",
7:"#aaaaaa",
8:"#555555",
9:"#555af5",
10:"#3df970",
11:"#3cfefe",
12:"#ff5257",
13:"#ff58f6",
14:"#fffa73",
15:"#ffffff"}
cores_no_basic = {
"#000000":0,
"#0225a4":1,
"#01a934":2,
"#02aaa9":3,
"#ae100d":4,
"#ad2ba3":5,
"#ad531b":6,
"#aaaaaa":7,
"#555555":8,
"#555af5":9,
"#3df970":10,
"#3cfefe":11,
"#ff5257":12,
"#ff58f6":13,
"#fffa73":14,
"#ffffff":15}
Atribuindo as cores aos números inteiros (fonte de pesquisa: https://stackoverflow.com/questions/29643352/converting-hex-to-rgb-value-in-python)
Esse procedimento converte o código hexadecimal em valores RGb.
def hex2rgb(h):
h = h.lstrip("#")
return tuple(int(h[i:i+2], 16) for i in (0, 2 ,4)) #retorna um tuple
def get_pixel_color(x, y):
# canvas use different coordinates
y = -y
canvas = turtle.getcanvas()
ids = canvas.find_overlapping(x, y, x, y)
if ids: # if list is not empty
index = ids[-1]
color = canvas.itemcget(index,"fill")
if color != '':
try:
return cnames[(color.lower())]
except:
return color.lower()
return "#ffffff" # default color white
Até aqui, o código apenas trata das questões de transformações de cores, a partir daqui, começa-se o processo recursivo tratado inicialmente, com a construção do quadrado inicial, atribuindo-lhe uma cor e depois a cruz central, atribuindo-lhe uma cor a partir das cores das pontas do quadrado, e assim por diante:
def linha(xi,yi,xf,yf,cor):
#utilizando coorenadas (x,y) para desenhar linha
turtle.pensize(width=None)
cor = cor_basic_python[cor] #dado o indice do basic retorna o nome da cor no python
turtle.pencolor(cor) #padrao do basic de 1 a 15
turtle.penup()
turtle.goto(xi,yi)
turtle.pendown()
turtle.goto(xf,yf)
turtle.penup()
def quadrado(lado_quadrado,cor):
turtle.penup()
turtle.goto(0,0)
turtle.pendown()
turtle.color(cor) #formato RGb
turtle.begin_fill()
turtle.forward(lado_quadrado)
turtle.left(90)
turtle.forward(lado_quadrado)
turtle.left(90)
turtle.forward(lado_quadrado)
turtle.left(90)
turtle.forward(lado_quadrado)
turtle.left(90)
turtle.end_fill()
def f(esquerda,direita,acima,abaixo):
a = int(3)
m = (16)
c1 = cores_no_basic[get_pixel_color(esquerda,acima)]
c2 = cores_no_basic[get_pixel_color(direita,acima)]
c3 = cores_no_basic[get_pixel_color(esquerda,abaixo)]
c4 = cores_no_basic[get_pixel_color(direita,abaixo)]
p = c1+c2+c3+c4
print (int(p/int(4)+a % m), ":", cor_basic_python[(int(p/int(4)+a) % m)])
return int((p/4+a) % m) # % = MOd
def colorgrid(esquerda,direita,acima,abaixo,passo):
if esquerda < direita-passo:
cor = f(esquerda,direita,acima,abaixo)
coluna_meio = (esquerda+direita)/int(2)
linha_meio = (acima+abaixo)/int(2)
linha(esquerda+passo,linha_meio,direita-passo,linha_meio,cor)
linha(coluna_meio,acima+passo,coluna_meio,abaixo-passo,cor)
colorgrid(esquerda,coluna_meio,acima,linha_meio,passo)
colorgrid(coluna_meio,direita,acima,linha_meio,passo)
colorgrid(esquerda,coluna_meio,linha_meio,abaixo,passo)
colorgrid(coluna_meio,direita,linha_meio,abaixo,passo)
#principal código
cor = input("cor da borda de 0 a 15:")
cor = int(cor)
esquerda = int(0)
direita = int(256)
acima = int(0)
abaixo = int(256)
print("borda nr.: ", cor, ": ", cor_basic_python[cor])
linha(esquerda,acima,direita,acima,cor)
linha(esquerda,abaixo,direita,abaixo,cor)
linha(esquerda,acima,esquerda,abaixo,cor)
linha(direita,acima,direita,abaixo,cor)
colorgrid(esquerda,direita,acima,abaixo,float(0.5))
ts = turtle.getscreen()
ts.getcanvas().postscript(file='turtle.eps', colormode='color')
turtle.done()
O resultado de um dos desenhos segue abaixo:

Na medida em que se altera o número do input, novos formatos são gerados.