Encontre os caminhos!

10

Você deve escrever um programa ou função.

A entrada é um 'mapa' de números. Você pode escolher o mapa como uma sequência com novos caracteres de linha ( \n) ou uma matriz 2D de sequências.

Todos os mapas têm 5 caracteres por 5 caracteres, e os caracteres sempre são dígitos maiores que 0 ou espaços.

Aqui está um exemplo de mapa:

12 45
11233
  233
    1
2 899

Sua tarefa é encontrar os componentes conectados no mapa. Um componente válido é uma série de pelo menos três dígitos idênticos conectados horizontal e / ou verticalmente ( não na diagonal ) ( não espaços ). Você precisará substituir os caracteres dos componentes conectados válidos por xs e imprimir ou retornar esse resultado.

Portanto, a saída para o exemplo acima seria:

x2 45
xx2xx
  2xx
    1
2 899

Aqui está outro caso de teste (graças a Martin Ender):

Input:
2   3
    4
 1  5
111 6
11  7

Output:
2   3
    4
 x  5
xxx 6
xx  7

Este é o código de golfe, então o código mais curto em bytes ganha!

Daniel
fonte
Os embutidos são permitidos?
13136 Ioannes
@ Joannes, sim.
187 Daniel Daniel

Respostas:

1

JavaScript (ES6), 171 161 139 137 136 133 132 bytes

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>

Esta é uma tradução da minha resposta do Python. E / S como matrizes de caracteres.

Pena que não há maneira eficiente de fazer sum...

PurkkaKoodari
fonte
5

Python 3, 238 237 200 199 192 181 bytes

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

Define uma função f(a)que recebe a entrada como uma matriz de caracteres e retorna a mesma matriz modificada. ( Matrizes de caracteres são aceitáveis ​​como seqüências de caracteres por padrão. )

Ungolfed com explicação

O código modificado é recursivo, mas funciona da mesma maneira.

# 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
fonte
2 bytes para bater a solução mathematica ...
FlipTack
11
@FlipTack Yeah. Não acho que esteja acontecendo hoje, mas estou traduzindo isso para JS e parece promissor.
precisa saber é o seguinte
3

Ruby, 304 bytes

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

exemplo de uso:

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

o código reutiliza o método 'blot' para calcular o comprimento do caminho.

variáveis ​​/ métodos:

  • f (s): função para converter a sequência do mapa, retorna um novo mapa com 'x'
  • ps (i): tamanho do caminho do índice do mapa i (onde x = i% 6, y = i / 6)
  • s: sequência de entrada, linhas do mapa separadas por "\ n"
  • z: cópia da sequência de entrada
  • b (s, i): função 'blot': escreve 'x' do índice do mapa i nos caminhos
  • @v: array 'visitado'

Tente uma explicação mais detalhada:

faça uma cópia da string de entrada, que usamos para encontrar o comprimento do caminho a partir de qualquer ponto no mapa.

z = s.dup

defina uma função anônima 'ps' (comprimento do caminho) (lambda) que leva o índice do mapa i como argumento. retorna o comprimento do caminho a partir desse ponto. isso é feito chamando o método 'b' (blot) para inserir x em uma cópia do mapa original e, em seguida, contando o número de x na string retornada.

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

a parte a seguir itera sobre cada caractere no mapa (índice i, caractere s [i]). chama a função 'b' (borrão) na posição do mapa i se o comprimento do caminho da posição i for maior que 2 e se não for um caractere de espaço ou nova linha.

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

a função b (blot) pega a sequência do mapa e um índice como argumento. inicializa @v (matriz visitada) e chama a função auxiliar b2.

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

a função b2 pega a sequência do mapa, a posição do mapa (i) e um caractere no caminho atual (c). ele se chama recursivamente para substituir seções conectadas de dígitos pelo caractere 'x'. retorna a sequência de entrada (para que a função ps possa chamar scan () no valor retornado).

esta instrução if está verificando se a posição do mapa (i) fornecida está dentro dos limites da string (0 ... s.size) e se o caractere em s [i] é o mesmo que o caractere inicial. também @v [i] está marcado para evitar recursões infinitas.

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

este é o bit que substitui o caractere no índice (i) pelo caractere 'x'. também marca esse índice como visitado.

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

é aqui que o b2 se chama recursivamente procurando o caminho. i + 1 é um caractere à direita, i-1 é um caractere à esquerda, i + 6 é uma linha abaixo (5 dígitos + 1 nova linha = 6 caracteres), i-6 é uma linha acima.

[1,-1,6,-6].each { |j| b2(s, i+j, c) }
Andrew
fonte
1

C (Ansi), 243 233 179 188 bytes

Golfe:

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

Com anotações:

#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*/

}

Entrada:

Espera uma nova linha no início e no final da string.

Exemplo de entrada:

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

Saída de exemplo:

x2 45
xx2xx
  2xx
    1
2 899

Atualizar

Fazer a grade fixa me permitiu cortar quase 60 bytes.

dj0wns
fonte
Eu acho que pode salvar como 22 caracteres se eu mudar isto para um correções mapear tamanho - Eu vou mudar isso se eu encontrar qualquer outra coisa que eu quero mudar
dj0wns
1

Mathematica, 180 bytes

(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]&

Explicação:

(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
]&

Função pura que aceita uma 5x5matriz. é o caractere de uso privado de 3 bytes que U+F3C7representa o operador de transposição do postfix \[Transpose].

(f=Flatten@#;p=Partition): Nivela a lista de entrada e a armazena f. Define p = Partitione retorna.

g=p[r,5]: A matriz {{1,2,3,4,5}, ..., {21,22,23,24,25}}(isso ocorre porque ré definido como Range@25).

Join[g=p[r,5],g]: a lista de linhas e colunas de g.

p[#,2,1]&: Função pura que divide a lista #em sublistas de comprimento 2com sobreposição 1; ou seja, a lista de pares adjacentes em #.

##&@@p[#,2,1]&: O mesmo que acima, exceto que retorna a Sequence.

##&@@p[#,2,1]&/@Join[g=p[r,5],g]: Mapeia a função anterior das linhas e colunas de gpara obter uma lista de todas as entradas adjacentes em g. Meu intestino diz que há uma maneira mais curta de fazer isso.

r~Graph~Cases[...]: Gráfico cujos vértices são os números inteiros 1, ..., 25e cujas arestas são as arestas entre entradas adjacentes nas gquais têm as mesmas entradas correspondentes na matriz de entrada (diferente de " ")

{a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ": Padrão que corresponde a {a,b}tal que f[[a]] == f[[b]](mesmo valor na matriz de entrada) e que não é igual a " ". Defina A = f[[a]]para salvar o 1byte.

...:>a<->b: Substitua todas as correspondências por uma borda não direcionada de a a b.

VertexComponent: Retorna o componente conectado do segundo argumento (um vértice) no primeiro argumento (um gráfico).

Tr[1^VertexComponent[...]]: O tamanho do componente conectado. Salva 1byte de Length@VertexComponent[...].

If[Tr[...]<3,f[[#]],"x"]&: Função pura que leva uma entrada #no g. Se o tamanho do componente conectado for menor que 3, substitua-o pela entrada correspondente na entrada. Caso contrário, substitua-o por "x".

(f=Flatten@#;p=Partition)[...,5]: E, finalmente, remodelar o resultado para ser uma 5x5matriz.

ngenisis
fonte
0

Clojure, 188 bytes

Isso é bastante esmagador: 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))%))

Chamado assim (é necessário um vetor 1D de caracteres):

(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")))))

Com preguiça de desenredá-lo, mas basicamente for[m(range 30)]visita cada índice e, para cada índice, o interior let[n(for[p[-1 -6 1 6]...(+ m p))]faz uma lista de 0 a 4 elementos que lista os locais que tinham o mesmo valor (1 - 9) que o local do meio. Se mais de um vizinho corresponder à parte intermediária, significa que todos eles formarão um cluster; portanto, esses locais serão adicionados ao conjunto usado em (if((set(flatten(...)))i). Se o índice ifor encontrado no conjunto, ele \xserá emitido e o valor original, caso contrário. Isso :when( ... )é bem interessante ...

NikoNyrh
fonte