Caminhos aleatórios de encanamento

23

Escreva um programa ou função que consiga três números inteiros, largura w, altura he contagem de passos s. Você desenhará etapas de caminhada aleatória, sem interseção, sem uma imagem 5*wpor 5*hpixel, onde cada célula de 5 por 5 pixels está vazia (bege puro) ou um desses doze "tubos" simples:

tubos ampliados

A imagem acima é ampliada para mostrar detalhes. Aqui estão os tubos no tamanho real:

tubos

(As linhas cinza são apenas para separar os tipos de tubos.)

A caminhada aleatória será um único caminho de tubo contínuo que começa em um ponto final do tubo (um dos quatro tipos inferiores de tubos) e termina em outro ponto final do tubo.

Comece com um vazio wpela hgrade e escolha aleatoriamente uma célula para ser o ponto de partida. Em seguida, escolha aleatoriamente uma das quatro direções para iniciar e desenhe o ponto final do tubo correspondente. Essa célula inicial marca o primeiro passo em sua caminhada e toda vez que você desenha uma nova célula ou sobrescreve uma existente, conta como outra etapa executada.

Agora, repetidamente, escolha aleatoriamente ir para a direita, esquerda ou reta, desenhando a célula de tubo apropriada se a direção escolhida for válida. Volte e escolha novamente se uma direção não for válida até que o scaminho completo da etapa seja formado. O caminho deve terminar com um ponto final de canal, que pode estar em qualquer lugar da grade, dependendo do curso que o caminho percorreu.

É muito importante observar que apenas as duas células de tubo reto podem ser substituídas e somente pela célula de tubo reto de orientação oposta, o resultado sendo uma célula de interseção. Caso contrário, todos os tubos devem ser colocados em células vazias.

Quando uma interseção é desenhada, a parte do caminho mais distante da célula inicial deve ser desenhada na parte superior.

Cabe a você decidir se a grade possui ou não condições periódicas de contorno (PBC), ou seja, se um tubo saindo de um lado da grade sairá do outro lado. Sem o PBC, o limite da grade conta como uma barreira na qual você pode se deparar como outros tubos.

Casos especiais

  • Quando sé 0, nenhum tubo deve ser desenhado e a saída deve ficar em branco 5*wpor 5*himagem (ou seja, toda bege).
  • Quando sé 1 um esboço de tubo único

    ponta de tubo aumentada(Tamanho real: topo de tubo)

    deve ser desenhado na célula inicial escolhida aleatoriamente.

Outros detalhes

  • Você pode supor que isso sé, no máximo w*h, um caminho sempre será possível. (Embora caminhos mais longos sejam possíveis devido a interseções.)
  • we hsempre será positivo.
  • Todas as escolhas aleatórias devem ser uniformemente aleatórias. por exemplo, você não deve evitar interseções quando possível, mesmo que isso facilite o problema. Geradores de números pseudo-aleatórios são permitidos.
  • Quaisquer três cores visualmente distintas podem ser usadas no lugar do preto, azul e bege.
  • Suas imagens de saída podem ser ampliadas para que sejam realmente 5*w*kem 5*h*kpixels, onde ké um número inteiro positivo. (É recomendável ampliar qualquer exemplo que você publicar, mesmo que o seu kseja 1.)
  • Qualquer formato de arquivo de imagem sem perda comum pode ser usado e a imagem pode ser salva em um arquivo, exibida ou vomitada no modo stdout.

O código mais curto em bytes vence.

Exemplos

(Tudo ampliado em 500%.)

Se a entrada for w=2, h=1, s=0, a saída será sempre:

Se a entrada for w=2, h=1, s=1, a saída será uma dessas imagens com a mesma chance:

Se a entrada for w=2, h=1, s=2, a saída será

ou possivelmente

se a grade tiver PBC.

(Observe que iniciar o caminho tornaria impossível um segundo passo.)


Aqui estão algumas saídas possíveis para w=3, h=2, s=6, assumindo o PBC:


Aqui está uma saída possível para w=3, h=3, s=9, assumindo o PBC:

Observe que o caminho não precisava cobrir todas as células devido à interseção contando como duas etapas. Além disso, podemos deduzir que o ponto final do canto era a célula inicial, pois a passagem superior da interseção deve ter sido desenhada posteriormente. Assim, podemos inferir a sequência de escolhas aleatórias que foram feitas:

start at top left, facing east
go straight
go right
go right
go right
go straight
go left
go right
end

Finalmente, aqui estão exemplos de w=4, h=5, s=20e w=4, h=5, s=16:

Passatempos de Calvin
fonte
1
A idéia toda é apenas uma caminhada aleatória, certo?
Akangka
Linha 2: You will be drawing a non-self-intersecting random walk... é auto-interseção ou não?
Edc65
@ChristianIrwan Bem, na verdade não. Passeios aleatórios geralmente podem se dobrar, ou não se cruzam. Este é um caso único, pois são feitas interseções, mas elas não contam como refazer o mesmo terreno. E sim, isso pode estar em um formato ascii-art ou algo assim, mas eu gosto da ideia de criar imagens bonitas.
Calvin's Hobbies
2
@ChristianIrwan Eu já respondi que quando disse "E sim, isso pode estar em um formato de arte ascii ou algo assim, mas eu gosto da idéia de criar imagens com boa aparência". Eu escolho não envolver arte ascii.
Calvin's Hobbies
1
São permitidos "nós"?
Aditsu

Respostas:

4

CJam, 274

q~:K;:B;:A;{0aA*aB*:M5*5f*:I;K{[Bmr:QAmr:P]5f*:R;3Ym*{R.+:)2{1$0=I=2$W=@tI@0=@t:I;}:F~}/R2f+1FK({MQ=P=:EY4mr:D#&1{{MQMQ=PE2D#+tt:M;}:G~7,1>[W0_1_0_W]2/D=:Off*{[QP]5f*2f+.+_:H1F_OW%.+2FOW%.m2F}/H2FO~P+:P;Q+:Q;MQ=P=:E_5YD2%-*=!JK2-=+*1{D2+4%:D;G}?}?}fJ]}0?}g'P2NA5*SI,N2NI:+N*

Experimente online

Usa PBC, saídas no formato PGM. Você pode remover o :+próximo ao final para obter uma saída visual melhor no navegador.

É muito lento para entradas maiores, especialmente se a contagem de etapas estiver próxima à área.

Exemplo de resultado para entrada 4 3 10(com escala de 500%):

exemplo

Breve explicação:

A abordagem geral é:

  • repita todas as etapas a seguir até obter êxito:
  • inicialize 2 matrizes: uma gravação em que lados estão sendo usados ​​em cada célula e uma para a imagem
  • se s = 0, terminamos, senão:
  • escolha uma célula aleatória e desenhe um quadrado e faça o seguinte s-1 vezes:
  • escolha uma direção aleatória; se esse lado já estiver sendo usado, falhe e comece novamente
  • marque o lado como usado e desenhe o tubo real na imagem (desenhando 3 linhas adjacentes de comprimento 6, começando logo após o pixel central da célula atual e adicionando um ponto para cobrir a extremidade do tubo)
  • atualize a posição atual (movendo para a próxima célula)
  • verifique se a célula está vazia ou se é uma passagem válida; caso contrário, falhe e comece novamente
  • marque o lado na direção oposta, conforme usado nesta célula, e continue o loop
aditsu
fonte
1

QBasic, 517 516 bytes

RANDOMIZE TIMER
SCREEN 9
INPUT w,h,s
1CLS
IF s=0GOTO 9
x=5*INT(RND*w)
y=5*INT(RND*h)
GOSUB 7
FOR k=1TO s-1
r=INT(RND*4)+1
a=x+5*((r=2)-(r=4))
b=y+5*((r=1)-(r=3))
c=(POINT(a,b+2)*POINT(a+4,b+2)+POINT(a+2,b)*POINT(a+2,b+4))*(0=POINT((a+x)\2+2,(b+y)\2+2))
IF((0=POINT(a+2,b+2))+c)*(a>=0)*(b>=0)*(a<5*w)*(b<5*h)=0GOTO 1
x=a
y=b
GOSUB 7
o=1AND r
p=x-2+3*o-5*(r=2)
q=y+1-3*o-5*(r=1)
u=p+3-o
v=q+2+o
LINE(p,q)-(u,v),7,B
LINE(p+o,q+1-o)-(u-o,v-1+o),1
NEXT
9IF c GOTO 1
END
7LINE(x+1,y+1)-(x+3,y+3),7,B
PSET(x+2,y+2),1
RETURN
  • Recebe w, he sda entrada do usuário, separados por vírgula.
  • A saída é desenhada na tela. Enquanto o programa está procurando uma solução, você pode ver soluções parciais passando rapidamente.
  • Não usa condições de contorno periódicas. Achei mais fácil desenhar e testar a conexão de tubos sem ter que me preocupar com metade do tubo de um lado da grade e metade do outro.

A abordagem aqui é tentar uma direção aleatória em cada etapa e começar do zero se resultar em uma movimentação inválida. Desenhamos os tubos conforme as instruções são decididas e usamos POINTpara testar pontos na tela para verificar nossas condições de validade. Uma movimentação é válida se não ultrapassar os limites da grade e:

  1. A célula movida para está vazia; ou
  2. Ambos
    1. A célula movida para o contém um tubo passando direto, horizontal ou verticalmente, e
    2. A nova seção de tubo não duplica uma seção de tubo existente

Como a resposta CJam do aditsu , esse código é muito lento e pode ser incrivelmente lento se sfor uma fração significativa de w*h. Na minha configuração do QB64, ele vem com uma resposta com 5,5,19bastante rapidez, mas leva mais tempo do que eu estava disposto a esperar 5,5,20.

Se você deseja executar exemplos maiores / mais compactados, aqui está minha abordagem original usando uma pesquisa profunda . É muito mais eficiente, ao custo de 300 bytes extras.

RANDOMIZE TIMER
SCREEN 9
INPUT w,h,s
DIM t(s),m(s)
0
FOR z=1TO s
t(z)=-1
NEXT
i=5*INT(RND*w)
j=5*INT(RND*h)
k=1
1CLS
IF s=0GOTO 9
x=i
y=j
GOSUB 7
FOR z=1TO k-1
r=m(z)
GOSUB 6
x=a
y=b
GOSUB 7
o=1AND r
p=x-2+3*o-5*(r=2)
q=y+1-3*o-5*(r=1)
u=p+3-o
v=q+2+o
LINE(p,q)-(u,v),7,B
LINE(p+o,q+1-o)-(u-o,v-1+o),1
NEXT
IF c*(k=s)THEN k=k-1:GOTO 1 ELSE IF k=s GOTO 9
IF k<1GOTO 0
IF t(k)>=0GOTO 4
t(k)=0
f=30
WHILE f
r=INT(RND*4)+1
IF f AND 2^r THEN t(k)=t(k)*5+r:f=f-2^r
WEND
4r=t(k)MOD 5
m(k)=r
t(k)=t(k)\5
GOSUB 6
c=(POINT(a,b+2)*POINT(a+4,b+2)+POINT(a+2,b)*POINT(a+2,b+4))*(0=POINT((a+x)\2+2,(b+y)\2+2))
IF((0=POINT(a+2,b+2))+c)*(a>=0)*(b>=0)*(a<5*w)*(b<5*h)THEN k=k+1 ELSE IF t(k)>0GOTO 4 ELSE t(k)=-1:k=k-1
GOTO 1
6a=x+5*((r=2)-(r=4))
b=y+5*((r=1)-(r=3))
RETURN
7LINE(x+1,y+1)-(x+3,y+3),7,B
PSET(x+2,y+2),1
RETURN
9

Exemplo de saída para entradas 10, 10, 100, tamanho real:10x10 encanamento aleatório

Uma versão ainda mais sofisticada pode ser encontrada nesta essência . Além de ser totalmente destruído e completamente comentado, ele aumenta a saída por um fator constante e permite um atraso definido entre as etapas, permitindo que você assista o algoritmo DFS no trabalho. Aqui está um exemplo de execução:

deluxe plumbing.bas em ação

DLosc
fonte