Trova i percorsi!


10

È necessario scrivere un programma o una funzione.

L'input è una "mappa" di numeri. Puoi scegliere di prendere la mappa come una stringa con nuovi caratteri di linea ( \n) o una matrice 2D di stringhe.

Tutte le mappe sono 5 caratteri per 5 caratteri e i caratteri sono sempre o cifre maggiori di 0 o spazi.

Ecco un esempio di una mappa:

12 45
11233
  233
    1
2 899

Il tuo compito è trovare i componenti collegati nella mappa. Un componente valido è una serie di almeno tre cifre identiche ( non spazi ) collegate orizzontalmente e / o verticalmente ( non in diagonale ). Sarà quindi necessario sostituire i caratteri dei componenti collegati validi con se stampare e restituire quel risultato.x

Quindi, l'output per l'esempio sopra sarebbe:

x2 45
xx2xx
  2xx
    1
2 899

Ecco un altro caso di test (grazie a Martin Ender):

Input:
2   3
    4
 1  5
111 6
11  7

Output:
2   3
    4
 x  5
xxx 6
xx  7

Questo è il codice golf, quindi vince il codice più breve in byte!



Sono ammessi i built-in?
Ioannes,

@Joannes, sì.
Daniel,

Risposte:


1

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

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>

Questa è una traduzione della mia risposta Python. I / O come array di caratteri.

Peccato che non ci sia un modo efficace di fare sum...


5

Python 3, 238 237 200 199 192 181 byte

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

Definisce una funzione f(a)che accetta l'input come una matrice di caratteri e restituisce la stessa matrice modificata. (Le matrici di caratteri sono accettabili come stringhe per impostazione predefinita. )

Ungolfed con spiegazione

Il codice modificato è ricorsivo, ma funziona allo stesso modo.

# 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

2 byte fuori per battere la soluzione di matematica ...
FlipTack

1
@FlipTack Sì. Non penso che stia succedendo oggi, ma sto traducendo questo in JS e sembra promettente.
PurkkaKoodari,

3

Rubino, 304 byte

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

esempio di utilizzo:

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

il codice riutilizza il metodo 'blot' per calcolare la lunghezza del percorso.

variabili / metodi:

  • f (s): funzione per convertire la stringa della mappa, restituisce una nuova mappa con 'x's
  • ps (i): dimensione del percorso dall'indice della mappa i (dove x = i% 6, y = i / 6)
  • s: stringa di input, linee della mappa separate da "\ n"
  • z: copia della stringa di input
  • b (s, i): funzione 'macchia': scrive 'x' dall'indice della mappa i su percorsi
  • @v: array "visitato"

Tentativo di spiegazione più dettagliata:

crea una copia della stringa di input, che usiamo per trovare la lunghezza del percorso da un dato punto della mappa.

z = s.dup

definire una funzione anonima (lunghezza del percorso) 'ps' (lambda) che considera l'indice della mappa i come argomento. restituisce la lunghezza del percorso da quel punto. lo fa chiamando il metodo 'b' (macchia) per inserire le x su una copia della mappa originale e quindi contando il numero di x nella stringa restituita.

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

la parte seguente scorre ogni carattere della mappa (indice i, carattere s [i]). chiama la funzione 'b' (macchia) sulla posizione della mappa i se la lunghezza del percorso dalla posizione i è maggiore di 2 e se non è uno spazio o un carattere di nuova riga.

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

la funzione b (macchia) accetta la stringa della mappa e un indice come argomento. inizializza @v (array visitato) e chiama la funzione helper b2.

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

la funzione b2 accetta la stringa della mappa, una posizione della mappa (i) e un carattere nel percorso corrente (c). si chiama ricorsivamente per sostituire sezioni di cifre collegate con il carattere 'x'. restituisce la stringa di input (in questo modo la funzione ps può chiamare scan () sul valore restituito).

questo se l'istruzione sta verificando che la posizione della mappa (i) fornita sia all'interno dei limiti della stringa (0 ... s.size) e che il carattere in s [i] sia uguale al carattere iniziale. anche @v [i] è controllato per evitare la ricorsione infinita.

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

questo è il bit che sostituisce il carattere nell'indice (i) con il carattere 'x'. contrassegna anche quell'indice come visitato.

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

questo è dove b2 si chiama ricorsivamente cercando il percorso. i + 1 è un carattere a destra, i-1 è un carattere a sinistra, i + 6 è una riga in basso (5 cifre + 1 riga nuova = 6 caratteri), i-6 è una riga in alto.

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

1

C (Ansi), 243 233 179 188 byte

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

Con annotazioni:

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

}

Ingresso:

Si aspetta una nuova riga all'inizio e alla fine della stringa.

Esempio di input:

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

Esempio di output:

x2 45
xx2xx
  2xx
    1
2 899

Aggiornare

Rendere fissa la griglia mi ha permesso di radere quasi 60 byte.


Immagino di poter salvare come 22 caratteri se lo cambio in una dimensione della mappa delle correzioni - lo cambierò se trovo qualcos'altro che voglio cambiare
dj0wns

1

Mathematica, 180 byte

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

Spiegazione:

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

Funzione pura che accetta un 5x5array. è il carattere di uso privato a 3 byte che U+F3C7rappresenta l'operatore di trasposizione postfix \[Transpose].

(f=Flatten@#;p=Partition): Appiattisce l'elenco di input e lo memorizza f. Imposta p = Partitione restituisce.

g=p[r,5]: L'array {{1,2,3,4,5}, ..., {21,22,23,24,25}}(questo perché rviene impostato su Range@25).

Join[g=p[r,5],g]: l'elenco di righe e colonne di g.

p[#,2,1]&: Funzione pura che suddivide l'elenco #in elenchi di lunghezza di lunghezza 2con sovrapposizione 1; cioè, l'elenco delle coppie adiacenti in #.

##&@@p[#,2,1]&: Come sopra, tranne per il fatto che restituisce a Sequence.

##&@@p[#,2,1]&/@Join[g=p[r,5],g]: Mappa la funzione precedente delle righe e delle colonne di gper ottenere un elenco di tutte le voci adiacenti in g. Il mio istinto dice che c'è un modo più breve per farlo.

r~Graph~Cases[...]: Grafico i cui vertici sono numeri interi 1, ..., 25e i cui bordi sono i bordi tra le voci adiacenti in gcui hanno le stesse voci corrispondenti nell'array di input (diverso da " ")

{a_,b_}/;(A=f[[a]])==f[[b]]&&A!=" ": Pattern che corrisponde a {a,b}tale f[[a]] == f[[b]](stesso valore nella matrice di input) e che non è uguale a " ". Imposta A = f[[a]]per salvare 1byte.

...:>a<->b: Sostituisci ogni partita con un bordo non orientato da a a b.

VertexComponent: Restituisce il componente collegato del secondo argomento (un vertice) nel primo argomento (un grafico).

Tr[1^VertexComponent[...]]: La dimensione del componente collegato. Salva 1byte da Length@VertexComponent[...].

If[Tr[...]<3,f[[#]],"x"]&: Pura funzione che prende una voce #in g. Se la dimensione del suo componente collegato è inferiore a 3, sostituirlo con la voce corrispondente nell'input. Altrimenti, sostituirlo con "x".

(f=Flatten@#;p=Partition)[...,5]: E infine rimodellare il risultato in un 5x5array.


0

Clojure, 188 byte

Questo è abbastanza travolgente: 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))%))

Chiamato in questo modo (richiede un vettore 1D di caratteri):

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

Troppo pigro per annullarlo, ma fondamentalmente for[m(range 30)]visita ogni indice e per ogni indice interno let[n(for[p[-1 -6 1 6]...(+ m p))]crea un elenco da 0 a 4 elementi che elenca posizioni che avevano lo stesso valore (1 - 9) della posizione centrale. Se più di 1 vicino corrisponde al pezzo intermedio significa che tutti questi formano un cluster, quindi tali posizioni vengono aggiunte all'insieme utilizzato in (if((set(flatten(...)))i). Se l'indice iviene trovato dal set, \xviene emesso e il valore originale altrimenti. È :when( ... )abbastanza interessante ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.