Найди пути!

10

Вы должны написать программу или функцию.

Вход представляет собой «карту» чисел. Вы можете взять карту в виде строки с символами новой строки (\n ) или двухмерного массива строк.

Все карты 5 символов на 5 символов, и символы всегда либо цифры больше 0, либо пробелы.

Вот пример карты:

12 45
11233
  233
    1
2 899

Ваша задача - найти подключенные компоненты на карте. Допустимый компонент - это серия, состоящая как минимум из трех горизонтально и / или вертикально ( не по диагонали ) соединенных одинаковых цифр ( не пробелов ). Затем вам нужно будет заменить символы действительных подключенных компонентов на xs и напечатать или вернуть этот результат.

Итак, вывод для приведенного выше примера будет:

x2 45
xx2xx
  2xx
    1
2 899

Вот еще один тестовый пример (спасибо Мартину Эндеру):

Input:
2   3
    4
 1  5
111 6
11  7

Output:
2   3
    4
 x  5
xxx 6
xx  7

Это код гольф, поэтому выигрывает самый короткий код в байтах!

Даниил
источник
Разрешены ли встроенные модули?
Иоанн
@Джоанн, да.
Даниэль

Ответы:

1

JavaScript (ES6), 171 161 139 137 136 133 132 байта

f=(a,i=0)=>(F=i=>" "<c&&a[i]===c&&(a[i]=n,1+F(i-1)+F(i+1)+F(i-6)+F(i+6)),n=1,c=a[i],n=F(i)>2?"x":c,c=1,F(i),i>28?a:f(a,++i+(i%6>4)))
<!-- this HTML included just for testing --><textarea rows=5 cols=6 oninput="document.querySelector`pre`.innerHTML=this.value.length==29?f([...this.value]).join``:'invalid input'">12 45&#10;11233&#10;  233&#10;    1&#10;2 899</textarea><br/><pre></pre>

Это перевод моего Python ответа. Ввод / вывод как символьные массивы.

Жаль, что нет эффективного способа сделать sum...

PurkkaKoodari
источник
5

Python 3, 238 237 200 199 192 181 байт

def f(a,i=0):F=lambda i,n,c:29>i>=0!=" "!=a[i]==c!=n and(a.__setitem__(i,n)or-~sum(F(i+j,n,c)for j in[-1,1,-6,6]));j=i+i//5;F(j,[a[j],"x"][2<F(j,1,a[j])],1);i>23or f(a,i+1);return a

Определяет функцию, f(a)которая принимает входные данные в виде массива символов и возвращает тот же модифицированный массив. ( Массивы символов по умолчанию допустимы в качестве строк. )

Неуравновешенный объяснением

Измененный код является рекурсивным, но работает так же.

# The main function; fills all continuous nonempty areas of size >= 3 in array
# with x's. Both modifies and returns array.
def findpaths(array):
    # Fills a continuous area of curr_char in array with new_char, starting
    # from index. Returns the number of cells affected.
    def floodfill(index, new_char, curr_char):
        if (0 <= index < 29                   # Check that the position is in bounds
                and (index + 1) % 6 != 0      # Don't fill newlines
                and array[index] != " "       # Don't fill empty cells
                and array[index] == curr_char # Don't fill over other characters
                and curr_char != new_char):   # Don't fill already filled-in cells
            array[index] = new_char # Fill current position
            return (1 # Add neighboring cells' results, plus 1 for this cell
                    + floodfill(index + 1, new_char, curr_char)  # Next char
                    + floodfill(index - 1, new_char, curr_char)  # Previous char
                    + floodfill(index + 6, new_char, curr_char)  # Next line
                    + floodfill(index - 6, new_char, curr_char)) # Previous line
        return 0 # Nothing was filled. The golfed solution returns False here,
                 # but that's coerced to 0 when adding.

    for i in range(25): # Loop through the 25 cells
        i += i // 5 # Accommodate for newlines in input
        curr_char = array[i] # Get the cell's contents
        # Fill the area from the cell with dummies
        area_size = floodfill(i, 1, curr_char)
        # Convert dummies to "x" if area was large enough, back to original otherwise
        fill_char = "x" if 2 < area_size else curr_char
        floodfill(i, fill_char, 1)
    return array
PurkkaKoodari
источник
2 байта, чтобы победить решение
Mathematica
1
@ FlipTack Да. Я не думаю, что это происходит сегодня, но я перевожу это на JS, и это выглядит многообещающе.
PurkkaKoodari
3

Рубин, 304 байта

def b(s,i)
  @v=[]
  b2(s,i,s[i])
end
def b2(s,i,c)
  if(0...s.size)===i&&s[i]==c&&!@v[i]
    @v[i]=s[i]='x'
    [1,-1,6,-6].each{|j|b2(s,i+j,c)}
  end
  s
end
def f(s)
  z = s.dup
  ps = ->(i){b(z.dup,i).scan('x').size}
  (0...s.size).each{|i|b(s, i)if ![' ',"\n"].include?(s[i])&&ps.call(i)>2}
  s
end

пример использования:

puts f(File.read("map.txt"))

код использует метод blot для вычисления длины пути.

переменные / методы:

  • f (s): функция для преобразования строки карты, возвращает новую карту с 'x's
  • ps (i): размер пути из индекса карты i (где x = i% 6, y = i / 6)
  • s: входная строка, строки карты, разделенные "\ n"
  • z: копия входной строки
  • b (s, i): функция 'blot': записывает 'x' из индекса карты i по путям
  • @v: массив посещенных

Попытка более подробного объяснения:

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

z = s.dup

определить анонимную функцию «ps» (длина пути) (лямбда), которая принимает индекс карты i в качестве аргумента. он возвращает длину пути от этой точки. он делает это, вызывая метод 'b' (blot), чтобы вставить x в копию исходной карты, а затем подсчитать количество x в возвращенной строке.

  ps = ->(i){b(z.dup,i).scan('x').size}

следующая часть перебирает каждый символ на карте (индекс i, символ s [i]). он вызывает функцию 'b' (blot) в позиции i карты, если длина пути от позиции i больше 2, и если это не пробел или символ новой строки.

  (0...s.size).each { |i|
     b(s, i) if ![' ',"\n"].include?(s[i]) && ps.call(i) > 2
  }

функция b (blot) принимает строку карты и индекс в качестве аргумента. он инициализирует @v (посещаемый массив) и вызывает вспомогательную функцию b2.

def b(s,i)
  @v=[]
  b2(s,i,s[i])
end

функция b2 принимает строку карты, позицию карты (i) и символ в текущем пути (c). он вызывает себя рекурсивно, чтобы заменить связанные разделы цифр символом «x». он возвращает входную строку (это так, чтобы функция ps могла вызвать scan () возвращаемого значения).

оператор if проверяет, что заданная позиция карты (i) находится в пределах строки (0 ... s.size) и что символ в s [i] совпадает с начальным символом. также @v [i] проверяется, чтобы избежать бесконечной рекурсии.

if(0...s.size) === i && s[i] == c && !@v[i]

это бит, который заменяет символ в индексе (i) на символ «x». он также помечает этот индекс как посещенный.

@v[i] = s[i] = 'x'

это где b2 вызывает себя рекурсивно в поисках пути. i + 1 - один символ справа, i-1 - один символ слева, i + 6 - одна строка вниз (5 цифр + 1 новая строка = 6 символов), i-6 - одна строка вверх.

[1,-1,6,-6].each { |j| b2(s, i+j, c) }
Эндрю
источник
1

С (Анси) 243 233 179 188 байт

Golfed:

#define O o[1][l]
x,n,l,L;r(o,l)char**o;{if(!(l>L|l<0|O<47|O!=x))n++,O++,r(o,l-1),r(o,l+6),r(o,l-6),r(o,l+1),n>2?O='x':O--;}main(g,o)char**o;{for(;(L=30)>l;l++)n=0,x=O,r(o,l);puts(o[1]);}

С аннотациями:

#define O o[1][l]
x,n,l,L;      /*-------------------------- Globals*/
r(o,l)char**o;{ /*------------------------ Recursive Function*/
    if(!(l>L|l<0|O<47|O!=x)) /*----------- if this cell is valid(in
                                              range, is a number, is the 
                                              same as the parent number*/
    n++,     /*--------------------------- Increment count*/
    O++,     /*--------------------------- Increment character to mark*/
    r(o,l-1),  /*------------------------- Recurse left*/
    r(o,l+6),  /*------------------------- Recurse down*/
    r(o,l-6),  /*------------------------- Recurse down*/
    r(o,l+1),  /*------------------------- Recurse right*/
    n>2?O='x':O--;  /*---------------------If greater than 3, replace with x, else decrement character*/ 
}          /*----------------------------- Return*/

main(g,o)char**o;{ /*--------------------- Main*/
    for(;l<(L=30);l++){ /*---------------- For entire string and set L*/
        n=0;
        x=O;        /*-------------------- set counter to 0*/
        r(o,l); /*------------------------ Recurse*/
    } /*---------------------------------- End While*/
    puts(o[1]); /*------------------------ Print*/

}

Входные данные:

Ожидается новая строка в начале и конце строки.

Пример ввода:

./findPaths "
12 45
11233
  233
    1
2 899
"

Пример вывода:

x2 45
xx2xx
  2xx
    1
2 899

Обновить

Исправление сетки позволило мне сбрить почти 60 байтов.

dj0wns
источник
Я думаю, я могу сохранить как 22 символа, если я изменю это на размер карты исправлений - я изменю это, если я найду что-нибудь еще, что я хочу изменить
dj0wns
1

Mathematica, 180 байт

(f=Flatten@#;p=Partition)[If[Tr[1^VertexComponent[r~Graph~Cases[##&@@p[#,2,1]&/@Join[g=p[r,5],g],{a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ":>a<->b],#]]<3,f[[#]],"x"]&/@(r=Range@25),5]&

Объяснение:

(f=Flatten@#;p=Partition)[
  If[
    Tr[1^VertexComponent[
        r~Graph~Cases[
          ##&@@p[#,2,1]&/@Join[g=p[r,5],g],
          {a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ":>a<->b
        ],
        #
      ]]<3,
    f[[#]],
    "x"
  ]&/@(r=Range@25),
  5
]&

Чистая функция, которая принимает 5x5массив. 3-байтовый символ частного использования, U+F3C7представляющий оператор транспонирования postfix\[Transpose] .

(f=Flatten@#;p=Partition): Выравнивает список ввода и сохраняет его в f. Устанавливает p = Partitionи возвращает его.

g=p[r,5]: Массив {{1,2,3,4,5}, ..., {21,22,23,24,25}}(это потому, что rустанавливается в Range@25).

Join[g=p[r,5],g]: список строк и столбцов g.

p[#,2,1]&: Pure функция, которая разбивает список #на подсписки длины 2с перекрытием 1; т.е. список соседних пар в #.

##&@@p[#,2,1]&: То же, что и выше, но возвращает a Sequence.

##&@@p[#,2,1]&/@Join[g=p[r,5],g]: Сопоставляет предыдущую функцию строк и столбцов, gчтобы получить список всех смежных записей в g. Моя интуиция говорит, что есть более короткий способ сделать это.

r~Graph~Cases[...]: Граф, вершины которого являются целыми числами, 1, ..., 25а ребра - ребрами между смежными записями, в gкоторых есть одинаковые соответствующие записи во входном массиве (кроме " ")

{a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ": Шаблон, который соответствует {a,b}такому f[[a]] == f[[b]](то же значение во входном массиве) и который не равен " ". Установите, A = f[[a]]чтобы сохранить 1байт.

...:>a<->b: Заменять каждое совпадение ненаправленным ребром от a до b.

VertexComponentВозвращает связанный компонент второго аргумента (вершины) в первом аргументе (графе).

Tr[1^VertexComponent[...]]: Размер подключенного компонента. Сохраняет 1байт из Length@VertexComponent[...].

If[Tr[...]<3,f[[#]],"x"]&: Чистая функция, которая принимает запись #в g. Если размер подключенного компонента меньше чем 3, замените его соответствующей записью на входе. В противном случае замените его на "x".

(f=Flatten@#;p=Partition)[...,5]И, наконец, измените результат в 5x5массив.

ngenisis
источник
0

Clojure, 188 байт

Это довольно подавляюще: D

#(apply str(map-indexed(fn[i v](if((set(flatten(for[m(range 30)](let[n(for[p[-1 -6 1 6]:when(=(get %(+ m p)0)((set"123456789")(% m)))](+ m p))](if(< 1(count n))(conj n m)[])))))i)\x v))%))

Вызывается так (требуется 1D вектор символов):

(def f #(apply str(...))

(print (str "\n" (f (vec (str "12 45\n"
                              "11233\n"
                              "  233\n"
                              "    1\n"
                              "2 899\n")))))

(print (str "\n" (f (vec (str "2   3\n"
                              "    4\n"
                              " 1  5\n"
                              "111 6\n"
                              "11  7\n")))))

Слишком лениво, чтобы разгрузить его, но в основном for[m(range 30)]посещает каждый индекс, и для каждого индекса внутренний let[n(for[p[-1 -6 1 6]...(+ m p))]создает список от 0 до 4 элементов, в котором перечислены местоположения, которые имеют то же значение (1 - 9), что и среднее местоположение. Если более одного соседа соответствует средней части, это означает, что все они образуют кластер, поэтому эти местоположения добавляются в набор, используемый в (if((set(flatten(...)))i). Если индекс iнайден из набора, то \xиспускается, а исходное значение в противном случае. Это :when( ... )довольно интересно ...

NikoNyrh
источник