Предсказать падающие скалы

18

В этом задании вам предоставляется карта двумерного ландшафта, если смотреть со стороны. К сожалению, некоторые части местности плавают в воздухе, что означает, что они рухнут. Ваша задача - предсказать, где они приземляются.

Вход

Ваш ввод - это одна или несколько строк одинаковой длины, разделенных символом новой строки, которые содержат только символы #(знак числа, обозначающий камень) или .(точку, обозначающую пустое пространство).

Выход

Ваш вывод имеет тот же формат, что и вход, но со следующей модификацией. Давайте рассмотрим входную строку как двумерную сетку камней. Каждая скала на входе, которая соединена с основанием сетки путем соседних скал, является твердой ; другие породы свободны . Диагонально смежные породы не считаются смежными. Все свободные камни упадут прямо вниз и окажутся в виде стека на вершине либо твердого камня, либо нижнего ряда. Рыхлые камни не прикреплены друг к другу, поэтому они падают по отдельности, а не как большие образования. На выходе получается результирующая сетка.

Примеры

  • Вход

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

    не содержит рыхлых камней, поэтому результат идентичен.

  • Вход

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

    содержит один свободный камень наверху, который падает на твердый камень под ним. Выход

    ......
    .#..#.
    .#..##
    .#.#.#
    .#####
    .#...#
    
  • Вход

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

    имеет большую группу рыхлых камней слева. Группа распадается, когда камни падают, поэтому результат

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

Разъяснения

  • Вы можете либо взять вход из STDIN и вывести в STDOUT, либо написать функцию.
  • Это код-гольф, поэтому самая короткая программа (в байтах) является победителем.
  • Стандартные лазейки запрещены.
Zgarb
источник

Ответы:

12

CJam, 180 ... 133 101 ... 94 90 87 байт

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

Определенно возможно много игры в гольф, но я хотел опубликовать ее первым после того, как полностью ее заработал.

Смотри, мама! Нет полос прокрутки!

Принимает сетку камней (составленную из .и #без завершающей строки) из STDIN и печатает вывод в STDOUT

ОБНОВЛЕНИЕ : Использование неэффективного, но более короткого частичного заполнения для определения твердых пород.

ОБНОВЛЕНИЕ 2 : Изменен алгоритм падения камней. Теперь короче!

ОБНОВЛЕНИЕ 3 : Сделал несколько небольших оптимизаций, и в конце я смог уменьшить количество байтов до половины исходного кода!

Как это работает :

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";

Для заливки мы перебираем время всей длины сетки (сетки). В каждой итерации мы гарантированно конвертируем по крайней мере 1, #которая непосредственно касается пробела, в (пробел). Пространство здесь представляет твердую рок-группу. Таким образом, в конце длинных (сеточных) итераций мы гарантируем, что все твердые породы представлены пробелами.

Попробуйте это онлайн здесь

оптимизатор
источник
15

Perl 5: 98

98, включая 2 флага командной строки.

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

Объяснение:

#!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
источник
@Optimizer Я полагаюсь на то, что последняя строка ввода правильно завершена, см .: ideone.com/7E3gQh Без этой зависимости это был бы один символ (или один более короткий, полагаясь на противоположное - отсутствие окончательного EOL).
Nutki
1
Побить CJam почти на 30%? Удивительный. Я поздравляю вас.
DLosc
@DLosc Больше нет: P
Оптимизатор
Избиение других императивных языков на 100-300%? Удивительный. Я поздравляю вас. ;)
DLosc
@DLosc Глядя на приведенный выше ответ, я больше не буду включать Perl в список обязательных языков: P
Оптимизатор,
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)}

Как функция со строковым параметром и возвращающая строку.

Сначала добавьте нижний ряд «1», чтобы определить линию заземления.
Первый цикл ищет фиксированные камни (которые находятся рядом с «1») и помечает их как «1». Поиск повторяется до тех пор, пока не будут найдены более твердые камни.
Второй цикл перемещает оставшиеся символы «#» к нижнему ряду. Опять же, это повторяется до тех пор, пока ни один камень не может быть перемещен.
Наконец, замените «1» на «#» снова и обрежьте нижний ряд.

Меньше гольфа

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)
}

Тест (Вы можете иметь доказательства того, какие камни твердые, а какие упали)

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
источник
3

APL, 130 119

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

Поскольку невозможно (насколько я знаю) вводить новые строки при запросе ввода, эта программа принимает в качестве входных данных матрицу символов.

Используемый алгоритм сначала преобразуется в двоичную матрицу ( 0это воздух и 1камень), а затем заливает заливку из нижнего ряда, чтобы отметить твердые камни как2 . Затем разбейте каждую колонку на «промежутки между твердыми камнями» и рассортируйте каждую перегородку, чтобы рыхлая скала «провалилась» в воздух.

Edit1: игра в гольф с использованием другого алгоритма заливки


Тестовые прогоны

Выполнить 1

Определите матрицу символов Aи напечатайте ее:

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

Затем введите Aв программу:

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

Run 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
источник
2

JS - 443 байта

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,"#")};

Наводнение заполняет камни со дна, а затем опускает незаполненные камни. Использует много рекурсии с заливкой, поэтому она может немного задержаться в вашем браузере.

Это функция - вызовите ее с g("input")

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

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

DankMemes
источник
1

Python 3, 364 байта

Я уверен, что из этого можно выжать больше ... но в любом случае он никогда не будет конкурировать с CJam и 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,"#")

Похож на другие ответы. Одна из странностей заключается в том, что сначала она переворачивает сетку вверх ногами (чтобы сделать индексы цикла более удобными) и добавляет дополнительную строку и столбец .(чтобы избежать проблем с переносом -1индексов). Беги по телефону P(string).

DLosc
источник