Prever as rochas que caem

18

Neste desafio, você recebe um mapa de um terreno bidimensional, visto de lado. Infelizmente, algumas partes do terreno estão flutuando no ar, o que significa que elas cairão. Seu trabalho é prever onde eles pousam.

A entrada

Sua entrada é uma ou mais sequências separadas por nova linha de comprimentos iguais, contendo apenas os caracteres #(um sinal de número, significando uma rocha) ou .(um ponto, significando espaço vazio).

A saída

Sua saída tem o mesmo formato que a entrada, mas com a seguinte modificação. Vamos ver a string de entrada como uma grade bidimensional de rochas. Toda rocha na entrada que é conectada ao fundo da grade por um caminho de rochas adjacentes é firme ; outras pedras estão soltas . Rochas diagonalmente adjacentes não são consideradas adjacentes. Todas as pedras soltas caem diretamente e terminam como uma pilha em cima de uma pedra firme ou da linha de baixo. As pedras soltas não são unidas uma à outra, então caem individualmente, não como grandes formações. A saída é a grade resultante.

Exemplos

  • A entrada

    ..###.
    .##.#.
    .#....
    .##.#.
    

    não contém pedras soltas, portanto a saída é idêntica a ela.

  • A entrada

    ...#..
    .#..#.
    .#..##
    .#...#
    .#####
    .#...#
    

    contém uma pedra solta no topo, que cai sobre a rocha firme sob ela. A saída é

    ......
    .#..#.
    .#..##
    .#.#.#
    .#####
    .#...#
    
  • A entrada

    .#####....
    .#....####
    ###.###..#
    #.#...##..
    .####..#.#
    ......###.
    ..#...#..#
    ..#...#..#
    

    tem um grande grupo de pedras soltas à esquerda. O grupo se decompõe quando as rochas caem, então a produção é

    ..........
    ....######
    ..#.###..#
    . #...##..
    .##....#..
    .##...####
    ####..#..#
    #####.#..#
    

Esclarecimentos

  • Você pode pegar a entrada de STDIN e enviar para STDOUT ou escrever uma função.
  • Este é o código-golfe, então o programa mais curto (em bytes) é o vencedor.
  • As brechas padrão não são permitidas.
Zgarb
fonte

Respostas:

12

CJam, 180 ... 133 101 ... 94 90 87 bytes

qN/~'#/S*_,):L;]N*_,_,*{:A1$='#={[W1LL~)]Af+{W>},1$f=S&,{ASct}*}*}/N/z{S/{$W%}%'#*}%zN*

Definitivamente, há muitas possibilidades de golfe, mas eu queria publicá-lo primeiro depois de fazê-lo funcionar completamente.

Olha ma! Sem barras de rolagem!

Pega a grade de rochas (composta .e #sem uma nova linha à direita) de STDIN e imprime a saída em STDOUT

ATUALIZAÇÃO : Usando um preenchimento parcial ineficiente, mas mais curto, para descobrir rochas firmes.

ATUALIZAÇÃO 2 : Foi alterado o algoritmo para fazer as pedras caírem. Muito mais curto agora!

ATUALIZAÇÃO 3 : Fiz várias otimizações pequenas e, no final, consegui reduzir a contagem de bytes para metade do código original!

Como funciona :

qN/~'#/S*_,):L;]N*             "Preparations";
qN/~                           "Read the input, split by new line and expand the array";
    '#/S*                      "In the last row, replace # by space";
         _,):L                 "Copy the last row and store length + 1 in L";
              ;]N*             "Pop the length, wrap everything in array and join by \n";

_,_,*{ ... }/                  "Flood fill";
_,                             "Copy the array and calculate its length";
  _,                           "Copy the length and calculate [0 - length] array";
    *                          "Repeat the above array, length times";
     { ... }/                  "Run the code block on each element of the array";

:A1$='#={ ... }*               "Process only #";
:A1$                           "Store the number in A and copy the input array to stack";
    =                          "Get Ath index element from input array";
     '#={ ... }*               "Run the code block if Ath element equals #";

[W1LL~)]Af+{W>},1$f=S&,{ASct}* "Flood fill spaces";
[W1LL~)]Af+                    "Get the indexes of the 4 elements on the cross formed by"
                               "the Ath index";
           {W>},               "Filter out the negative values";
                1$f=           "For each of the index, get the char from input string";
                    S&,        "Check if space is one of the 4 chars from above step";
                       {    }* "Run the code block if space is present";
                        ASct   "Make the Ath character of input string as space";

N/z{S/{$W%}%'#*}%zN*           "Let the rocks fall";
N/z                            "Split the resultant string by newlines and"
                               "transpose the matrix";
   {           }%              "Run the code block for each row (column of original)";
    S/{   }%                   "Split by space and run the code block for each part";
       $W%                     "Sort and reverse. This makes # come down and . to go up";
            '#*                "Join by 3, effectively replacing back spaces with #";
                 zN*           "Transpose to get back final matrix and join by newline";

Para o aterro, iteramos durante todo o tempo de comprimento da grade. Em cada iteração, garantimos a conversão de pelo menos 1 #que está tocando diretamente um espaço em (espaço). O espaço aqui representa um grupo de rock firme. Assim, no final das iterações de comprimento (grade), garantimos que todas as rochas firmes sejam representadas por espaços.

Experimente online aqui

Optimizer
fonte
15

Perl 5: 98

98, incluindo 2 sinalizadores de linha de comando.

#!perl -p0
1while/
/,($x="($`)")=~y!#!.!,s/#(.*
$)/%$1/+s/#$x?%|%$x?#/%$1$2%/s;1while s/#$x\./.$1#/s;y!%!#!

Explicação:

#!perl -p0 #read entire input to $_ and print at the end
/\n/;($x="($`)")=~y!#!.!; #calculate pattern matching space
                          #between two characters in the same column
                          #looks like "(......)" 
1 while s/#(.*\n$)/%$1/+s/#$x?%|%$x?#/%$1$2%/s;
                          #flood fill solid rock with %
1 while s/#$x\./.$1#/s;   #drop loose rock
y!%!#!                    #change % back to #
nutki
fonte
@Optimizer Confio na linha final de entrada sendo finalizada corretamente, consulte: ideone.com/7E3gQh Sem essa confiança, seria um char loner (ou um menor dependendo do oposto - falta de EOL final).
nutki
1
Vencer o CJam em quase 30%? Surpreendente. Eu te parabenizo.
DLosc
@DLosc Não é mais: P
Otimizador
Vencer outras línguas imperativas em 100-300%? Surpreendente. Eu te parabenizo. ;)
DLosc
@DLosc olhando para a resposta acima, eu não incluirá Perl na lista de linguagens imperativas mais: P
Optimizer
5

JavaScript (ES6) 232

s=>{for(s=[...s+'1'.repeat(r=1+s.search('\n'))];s=s.map((c,p)=>c=='#'&(s[p+1]|s[p-1]|s[p-r]|s[p+r])?f=1:c,f=0),f;);for(;s.map((c,p)=>c=='#'&s[p+r]=='.'&&(s[p]='.',f=s[p+r]=c),f=0),f;);return s.join('').replace(/1/g,rok).slice(0,-r)}

Como uma função com um parâmetro de string e retornando uma string.

Inicialmente, adicione uma linha inferior de '1' para identificar a linha de base.
O primeiro loop pesquisa as rochas fixas (que estão próximas de '1') e as marca como '1'. A pesquisa é repetida até que não sejam encontradas mais rochas firmes.
O segundo loop move os caracteres '#' restantes em direção à linha inferior. Novamente, isso é repetido até que nenhuma pedra possa ser movida.
Por fim, substitua o '1' por '#' novamente e corte a linha inferior.

Menos golfe

s=>{
  r = 1+s.search('\n');
  s = [...s+'1'.repeat(r)];
  for (; s = s.map((c,p) => c=='#' & (s[p+1]|s[p-1]|s[p-r]|s[p+r])?f=1:c,f=0),f; );
  for (; s.map((c,p) => c=='#' & s[p+r]=='.'&& (s[p] ='.', s[p+r]=c, f=1),f=0),f; );
  return s.join('')
    .replace(/1/g,'#')
    .slice(0,-r)
}

Teste (você pode ter evidências de quais rochas são firmes e quais caíram)

F=
s=>{for(s=[...s+'1'.repeat(r=1+s.search('\n'))];s=s.map((c,p)=>c=='#'&(s[p+1]|s[p-1]|s[p-r]|s[p+r])?f=1:c,f=0),f;);for(;s.map((c,p)=>c=='#'&s[p+r]=='.'&&(s[p]='.',f=s[p+r]=c),f=0),f;);return s.join('').replace(/1/g,rok).slice(0,-r)}

var rok // using rok that is 3 chars like '#'

function update() {
  rok = C.checked ? '@' : '#';
  O.textContent=F(I.textContent)
}

update()
td { padding: 5px }
pre { border: 1px solid #000; margin:0 }
<table><tr><td>Input</td><td>Output</td></tr>
<tr><td><pre id=I>.#####....
.#....####
###.###..#
#.#...##..
.####..#.#
......###.
..#...#..#
..#...#..#</pre></td>
<td><pre id=O></pre>
</td></tr></table>
<input type='checkbox' id=C oninput='update()'>Show firm rocks

edc65
fonte
3

APL, 130 119

'.##'[1+⊖1↓⍉↑↑{,/{⍵[⍒⍵]}¨x⊂⍨2=x←2,⍵}¨↓ ⍉⊃⌈/(1,¨⍳⍴⊃↓x){x←⍵⋄(⍺⌷x)∧←2⋄x≡⍵:x⋄⊃⌈/((⊂⍴⍵)⌊¨1⌈(,∘-⍨↓∘.=⍨⍳2)+⊂⍺)∇¨⊂x}¨⊂⊖'#'=x←⎕]

Como não é possível (tanto quanto eu saiba) inserir novas linhas quando a entrada é solicitada, este programa usa uma matriz de caracteres como entrada.

O algoritmo usado primeiro é convertido em uma matriz binária ( 0é ar e 1é rocha) e depois é preenchido pela linha inferior para marcar rochas firmes como 2. Em seguida, particione cada coluna em "espaços entre rochas firmes" e classifique cada partição para fazer com que a rocha solta "caia" no ar.

Edit1: Jogou golfe usando um algoritmo de preenchimento de inundação diferente


Execuções de teste

Execução 1

Defina uma matriz de caracteres Ae imprima-a:

      A←↑('.#####....') ('.#....####') ('###.###..#') ('#.#...##..') ('.####..#.#') ('......###.') ('..#...#..#') ('..#...#..#')
      A
.#####....
.#....####
###.###..#
#.#...##..
.####..#.#
......###.
..#...#..#
..#...#..#

Em seguida, alimente Ao programa:

      '.##'[1+⊖1↓⍉↑↑{,/{⍵[⍒⍵]}¨x⊂⍨2=x←2,⍵}¨↓⍉(1,¨⍳⊃⌽⍴x){⍵≡y←⊃⌈/x←⍺{x←⍵⋄(⍺⌷x)∧←2⋄x}¨⊂⍵:y⋄((⊂⍴⍵)⌊¨1⌈,(,∘-⍨↓∘.=⍨⍳2)∘.+⍺/⍨x≢¨⊂⍵)∇y}⊖'#'=x←⎕]
⎕:
      A
..........
....######
..#.###..#
..#...##..
.##....#..
.##...####
####..#..#
#####.#..#

Execução 2

      A←↑('#######')('#.....#')('#.#.#.#')('#.....#')('#######')
      A
#######
#.....#
#.#.#.#
#.....#
#######
      '.##'[1+⊖1↓⍉↑↑{,/{⍵[⍒⍵]}¨x⊂⍨2=x←2,⍵}¨↓⍉(1,¨⍳⊃⌽⍴x){⍵≡y←⊃⌈/x←⍺{x←⍵⋄(⍺⌷x)∧←2⋄x}¨⊂⍵:y⋄((⊂⍴⍵)⌊¨1⌈,(,∘-⍨↓∘.=⍨⍳2)∘.+⍺/⍨x≢¨⊂⍵)∇y}⊖'#'=x←⎕]
⎕:
      A
#######
#.....#
#.....#
#.#.#.#
#######
TwiNight
fonte
2

JS - 443 bytes

function g(b){function f(b,c,e){return b.substr(0,c)+e+b.substr(c+1)}function e(d,c){"#"==b[c][d]&&(b[c]=f(b[c],d,"F"),1<d&&e(d-1,c),d<w-1&&e(d+1,c),1<c&&e(d,c-1),c<h-1&&e(d,c+1))}b=b.split("\n");w=b[0].length;h=b.length;for(i=0;i<w;i++)"#"==b[h-1][i]&&e(i,h-1);for(j=h-2;-1<j;j--)for(i=0;i<w;i++)if(k=j+1,"#"==b[j][i]){for(;k<h&&"F"!=b[k][i]&&"#"!=b[k][i];)k++;k--;b[j]=f(b[j],i,".");b[k]=f(b[k],i,"#")}return b.join("\n").replace(/F/g,"#")};

A inundação preenche as rochas do fundo e depois derruba as rochas não preenchidas. Usa muita recursão com o preenchimento de inundação, para que o seu navegador fique um pouco lento.

É uma função - chame-o com g("input")

JSFiddle: http://jsfiddle.net/mh66xge6/1/

JSFiddle Ungolfed: http://jsfiddle.net/mh66xge6/

DankMemes
fonte
1

Python 3, 364 bytes

Tenho certeza de que mais poderia ser extraído disso ... mas nunca competirá com CJam e Perl.

z="%";R=range
def F(r,c,g):
 if z>g[r][c]:g[r][c]=z;[F(r+d%2*(d-2),c+(d%2-1)*(d-1),g)for d in R(4)]
def P(s):
 t=s.split()[::-1];w=len(t[0]);g=[list(r+".")for r in t+["."*w]];[F(0,c,g)for c in R(w)]
 for c in R(w):
  for r in R(len(g)):
   while g[r][c]<z<g[r-1][c]and r:g[r][c],g[r-1][c]=".#";r-=1
 return"\n".join(''.join(r[:w])for r in g[-2::-1]).replace(z,"#")

Semelhante a outras respostas. Uma peculiaridade é que ele vira a grade de cabeça para baixo primeiro (para tornar os índices de loop mais convenientes) e adiciona uma linha e coluna extra de .(para evitar problemas com os -1índices de quebra ). Execute chamando P(string).

DLosc
fonte