Encuentra los caminos!

10

Debes escribir un programa o función.

La entrada es un 'mapa' de números. Puede elegir tomar el mapa como una cadena con nuevos caracteres de línea ( \n) o como una matriz 2D de cadenas.

Todos los mapas tienen 5 caracteres por 5 caracteres, y los caracteres son siempre dígitos mayores que 0 o espacios.

Aquí hay un ejemplo de un mapa:

12 45
11233
  233
    1
2 899

Su tarea es encontrar los componentes conectados en el mapa. Un componente válido es una serie de al menos tres dígitos idénticos ( no espacios ) conectados horizontalmente y / o verticalmente ( no diagonalmente ). Luego deberá reemplazar los caracteres de los componentes conectados válidos con sy imprimir o devolver ese resultado.x

Entonces, la salida para el ejemplo anterior sería:

x2 45
xx2xx
  2xx
    1
2 899

Aquí hay otro caso de prueba (gracias a Martin Ender):

Input:
2   3
    4
 1  5
111 6
11  7

Output:
2   3
    4
 x  5
xxx 6
xx  7

Este es el código de golf, ¡el código más corto en bytes gana!

Daniel
fuente
¿Están permitidos los complementos?
Ioannes
@Joannes, sí.
Daniel

Respuestas:

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 es una traducción de mi respuesta de Python. E / S como matrices de caracteres.

Lástima que no haya una forma eficiente de hacerlo sum...

PurkkaKoodari
fuente
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 una función f(a)que toma la entrada como una matriz de caracteres y devuelve la misma matriz modificada. (Las matrices de caracteres son aceptables como cadenas de forma predeterminada ) .

Sin disculpas con la explicación

El código modificado es recursivo, pero funciona igual.

# 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
fuente
2 bytes desactivados para superar la solución matemática ...
FlipTack
1
@FlipTack Sí. No creo que esté sucediendo hoy, pero estoy traduciendo esto a JS y parece prometedor.
PurkkaKoodari
3

Rubí, 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

ejemplo de uso:

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

el código reutiliza el método 'blot' para calcular la longitud de la ruta.

variables / métodos:

  • f (s): función para convertir la cadena del mapa, devuelve un nuevo mapa con 'x'
  • ps (i): tamaño de ruta del índice del mapa i (donde x = i% 6, y = i / 6)
  • s: cadena de entrada, líneas de mapa separadas por "\ n"
  • z: copia de la cadena de entrada
  • b (s, i): función 'blot': escribe 'x' desde el índice del mapa i sobre rutas
  • @v: matriz 'visitada'

Intente una explicación más detallada:

haga una copia de la cadena de entrada, que usamos para encontrar la longitud de la ruta desde cualquier punto dado en el mapa.

z = s.dup

defina una función anónima 'ps' (longitud de ruta) (lambda) que tome el índice del mapa i como argumento. devuelve la longitud del camino desde ese punto. Lo hace llamando al método 'b' (blot) para insertar x en una copia del mapa original y luego contando el número de x en la cadena devuelta.

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

la siguiente parte itera sobre cada carácter en el mapa (índice i, carácter s [i]). llama a la función 'b' (blot) en la posición del mapa i si la longitud del camino desde la posición i es mayor que 2, y si no es un espacio o un carácter de nueva línea.

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

la función b (blot) toma la cadena del mapa y un índice como argumento. Inicializa @v (matriz visitada) y llama a la función auxiliar b2.

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

la función b2 toma la cadena del mapa, una posición del mapa (i) y un carácter en la ruta actual (c). se llama recursivamente para reemplazar secciones conectadas de dígitos con el carácter 'x'. devuelve la cadena de entrada (esto es para que la función ps pueda llamar a scan () en el valor de retorno).

esto si la declaración verifica que la posición del mapa (i) dada está dentro de los límites de la cadena (0 ... s.size) y que el carácter en s [i] es el mismo que el carácter inicial. también @v [i] está marcado para evitar una recursión infinita.

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

Este es el bit que reemplaza el carácter en el índice (i) con el carácter 'x'. También marca ese índice como visitado.

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

Aquí es donde b2 se llama a sí mismo buscando recursivamente la ruta. i + 1 es un carácter a la derecha, i-1 es un carácter a la izquierda, i + 6 está una fila hacia abajo (5 dígitos + 1 nueva línea = 6 caracteres), i-6 está una fila hacia arriba.

[1,-1,6,-6].each { |j| b2(s, i+j, c) }
Andrés
fuente
1

C (Ansi), 243 233 179 188 Bytes

Golfizado:

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

Con anotaciones:

#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 una nueva línea al principio y al final de la cadena.

Entrada de ejemplo:

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

Salida de ejemplo:

x2 45
xx2xx
  2xx
    1
2 899

Actualizar

La reparación de la cuadrícula me permitió reducir casi 60 bytes.

dj0wns
fuente
Creo que puedo guardar como 22 caracteres si cambio esto a un tamaño de correcciones de mapa - Voy a cambiar que si encuentro otra cosa que quiero cambiar
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]&

Explicación:

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

Función pura que acepta una 5x5matriz. es el carácter de uso privado de 3 bytes que U+F3C7representa el operador de transposición postfix\[Transpose] .

(f=Flatten@#;p=Partition): Aplana la lista de entrada y la almacena f. Lo establece p = Partitiony lo devuelve.

g=p[r,5]: La matriz {{1,2,3,4,5}, ..., {21,22,23,24,25}}(esto se debe a que rse establece en Range@25).

Join[g=p[r,5],g]: la lista de filas y columnas de g.

p[#,2,1]&: Función pura que divide la lista #en sublistas de longitud 2con superposición 1; es decir, la lista de pares adyacentes en #.

##&@@p[#,2,1]&: Igual que el anterior, excepto que devuelve a Sequence.

##&@@p[#,2,1]&/@Join[g=p[r,5],g]: Asigna la función anterior de las filas y columnas de gpara obtener una lista de todas las entradas adyacentes en g. Mi instinto dice que hay una forma más corta de hacer esto.

r~Graph~Cases[...]: Gráfico cuyos vértices son los enteros 1, ..., 25y cuyos bordes son los bordes entre las entradas adyacentes en las gque tienen las mismas entradas correspondientes en la matriz de entrada (que no sea" " )

{a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ": Patrón que coincide de {a,b}tal manera f[[a]] == f[[b]](mismo valor en la matriz de entrada) y que no son iguales a " ". Establecer A = f[[a]]para guardar el 1byte.

...:>a<->b: Reemplace cada partido con un borde no dirigido de a a b.

VertexComponent: Devuelve el componente conectado del segundo argumento (un vértice) en el primer argumento (un gráfico).

Tr[1^VertexComponent[...]]: El tamaño del componente conectado. Guarda 1byte de Length@VertexComponent[...].

If[Tr[...]<3,f[[#]],"x"]&: Función pura que tiene una entrada #en g. Si el tamaño de su componente conectado es menor que 3, reemplácelo con la entrada correspondiente en la entrada. De lo contrario, reemplácelo con"x" .

(f=Flatten@#;p=Partition)[...,5]: Y finalmente, rediseñar el resultado para que sea una 5x5matriz.

ngenisis
fuente
0

Clojure, 188 bytes

Esto es bastante abrumador: 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))%))

Llamado así (toma un vector 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")))))

Demasiado perezoso para deshacerse de él, pero básicamente for[m(range 30)]visita cada índice y para cada índice el interno let[n(for[p[-1 -6 1 6]...(+ m p))]hace una lista de 0 a 4 elementos que enumera las ubicaciones que tenían el mismo valor (1 - 9) que la ubicación intermedia. Si más de 1 vecino coincide con la pieza intermedia, significa que todos estos forman un grupo, por lo que esas ubicaciones se agregan al conjunto utilizado en (if((set(flatten(...)))i). Si ise encuentra el índice del conjunto, \xse emite y el valor original de lo contrario. Eso :when( ... )es bastante interesante ...

NikoNyrh
fuente