È un vero albero?


20

È necessario scrivere un programma o una funzione che riceve una stringa come input e output o restituisce se l'input è un albero ASCII.

  _
\/  /
 \_/
  |
  |

Gli alberi ASCII sono composti da caratteri / \ | _ spacese newlines.

I caratteri non bianchi collegano due punti del bordo delle loro celle con un segmento di linea:

  • / collega gli angoli in basso a sinistra e in alto a destra
  • \ collega gli angoli in basso a destra e in alto a sinistra
  • | collega i punti centrali del bordo inferiore e del bordo superiore
  • _ collega gli angoli in basso a sinistra e in basso a destra e il punto centrale del bordo inferiore

(Si noti che ciò significa che |può connettersi solo con |o _ma non con /o \.)

Un'immagine ASCII è chiamata albero se si applicano le seguenti regole:

  • Esattamente un punto (la radice) di esattamente un carattere tocca il bordo inferiore dell'ultima riga.
  • Puoi raggiungere qualsiasi punto di qualsiasi segmento di linea:

    • a partire dalla radice
    • usando solo i segmenti di linea
    • mai andare verso il basso (nemmeno lateralmente verso il basso)

Ingresso

  • Una stringa composta dai caratteri / \ | _ spacee newlinecontenente almeno un carattere non di spazi bianchi.
  • Puoi scegliere tra due formati di input:

    • Nessuno spazio bianco non necessario attorno all'albero (come mostrato negli esempi).
    • Nessuno spazio bianco non necessario attorno all'albero (come visto negli esempi) tranne gli spazi sul lato destro delle file per rendere tutte le file della stessa lunghezza.
  • Il trascinamento di newline è facoltativo.

Produzione

  • Un valore di verità coerente se l'input è un albero ASCII.
  • Un valore falsy coerente se l'input non è un albero ASCII.

Esempi

Alberi validi:

|
  _
\/  /
 \_/
  |
  |
/ /    \/
\ \____/
 \/
 /
/
 \___/
 /   \
 \___/
   |
   |
   __/
 _/
/
____
  \  ___
 \ \/
  \/\_____/
 \/  \/
  \__/
    |
    |

Alberi non validi (con spiegazioni extra che non fanno parte degli input):

\/
 \_______/
  \__   /
   | \_/    <- reachable only on with downward route
   |
_           <- multiple roots
\/          <- multiple root characters
/\          <- multiple roots
|           <- unreachable part

|
 __/
/           <- unreachable parts
|
\____/
 |  |       <- multiple roots
_\__/       <- unreachable parts (_ and \ don't connect to each other)
|

Questo è code-golf, quindi vince l'ingresso più breve.

Risposte:


7

PMA / Lumache , 99 93

Stampa 1 se soddisfa la definizione "albero" o 0 in caso contrario. La forma rettangolare di input riempito con spazio è preferita, anche se costa solo un byte (usando l' Fopzione) per convertire la versione sfilacciata in un rettangolo pieno di spazio, che è stato utile nel test.

&
\ |{(\_|\|)d=\||(\\a7|\/d|\_da7)=\\|(\\d|\/a5|\_da5)=\/|(\_lr|\|d|\/l|\\r)=\_},^_!(r.,^ )d~

Versione non golfata e obsoleta (per il mio piacere personale di visione):

F&
\ |
{
  \_ (lr=\_|da5=\/|da7=\\|d=\|) | \/ (l=\_|a5=\/|d=\\) | 
    \\ (r=\_|a7=\\|d=\/) | \|d=(\_|\|)    
}, 
^_ !(r.,^ ) d~

Questo risulta essere abbastanza adatto alle caratteristiche della lingua corrente. Sfortunatamente, ho dovuto passare alcune ore a inseguire un bug di conteggio dei riferimenti prima che potesse funzionare.

L' &opzione significa che la partita deve avere successo su ogni personaggio. Da ogni punto di partenza non spaziale verifica la presenza di un percorso verso il basso verso il basso. Realizzare una macchina a stati finiti con una regex è fortunatamente molto più breve usando le asserzioni, qui =.... Nella riga inferiore, controlla che non ci siano caratteri non spaziali a destra.


10

Mathematica, 345 300 byte

Ancora piuttosto lungo, ma immagino sia un inizio ...

(s=StringSplit;v=Reverse;#=="|"||#=="\\"||#=="/"&[""<>s@#]&&(g={};i=0;(c={i,++j};d={i,j+1/2};e=2d-c;g=Join[g,Switch[#,"|",{d->{1,0}+d},"/",{c->c+1},"\\",{e->{i+1,j}},"_",{c->d,d->e,e->c},_,{}]])&/@Characters[++i;j=0;#]&/@{##};Sort@VertexOutComponent[Graph@g,g[[1,1]]]==Union@@List@@@g)&@@v@s[#,"
"])&

Ecco una versione leggermente non golfata:

(
  s = StringSplit;
  v = Reverse;
  # == "|" || # == "\\" || # == "/" &[
      "" <> s@#
      ] && (
      g = {};
      i = 0;
      (
           c = {i, ++j};
           d = {i, j + 1/2};
           e = 2 d - c;
           g = Join[g, Switch[#,
              "|", {d -> {1, 0} + d},
              "/", {c -> c + 1},
              "\\", {e -> {i + 1, j}},
              "_", {c -> d, d -> e, e -> c},
              _, {}
              ]]
           ) & /@ Characters[
          ++i;
          j = 0;
          #
          ] & /@ {##};
      Sort@VertexOutComponent[Graph@g, g[[1, 1]]] == 
       Union @@ List @@@ g
      ) & @@ v@s[#, "\n"]
) &

Questo definisce una funzione senza nome che accetta la stringa come input e restituisce Trueo False.

L'idea di base è prima di controllare che esista una singola radice, quindi di costruire un oggetto reale (diretto) Graphper verificare se tutti i vertici possono essere raggiunti dalla radice. Ecco come costruiamo il grafico:

Immagina una griglia di numeri interi sovrapposta all'arte ASCII, in cui le coordinate dei numeri interi corrispondono agli angoli delle celle dei caratteri. Quindi su ciascuna delle celle ci sono sei punti rilevanti che possono essere collegati. Ecco un esempio, in cui ho anche etichettato i punti aper f:

     |                 |
     |                 |
---(2,3)---(2.5,3)---(3,2)---
     | d      e      f |
     |                 |
     |                 |
     |                 |
     |                 |
     |                 |
     |                 |
     | a      b      c |
---(2,2)---(2.5,2)---(3,2)---
     |                 |
     |                 |

Quindi possiamo costruire un grafico i cui vertici sono queste coordinate a mezzo intero e i cui bordi sono determinati dai caratteri non spaziali nell'input. |collega ba e, /collega aalle fe \collega ca d. Nota che questi devono essere bordi diretti per garantire che non ci muoviamo mai verso il basso mentre attraversiamo il grafico in seguito. Per _possiamo andare in entrambi i casi, quindi in teoria abbiamo bisogno di quattro bordi a -> b, b -> a, b -> c, c -> b. Tuttavia, possiamo notare che tutto ciò che conta è che c'è un ciclo che contiene tutti e tre i vertici, in modo che possiamo ridurre questo per tre lati: a -> b, b -> c, c -> a.

Costruire questo grafico è abbastanza semplice in Mathematica, perché qualsiasi oggetto può fungere da vertice, quindi posso effettivamente costruire un grafico i cui vertici sono le coppie di coordinate.

Infine, controlliamo che ogni vertice sia raggiungibile dalla radice. Le coordinate della radice si trovano facilmente come il primo vertice che abbiamo aggiunto al grafico. Quindi il modo più breve che ho trovato per verificare se tutti i vertici possono essere raggiunti è verificare se la VertexOutComponentradice (ovvero l'insieme di tutti i vertici raggiungibile dalla radice) è identica all'insieme di tutti i vertici nel grafico.


1
300 byte possono essere lunghi, ma esattamente 300 è così soddisfacente!
Alex A.

2

Rubino 226227 228

->i{w=i.index(?\n)+1
t=[i.index(/[^ _] *\n\z/)]
a=->x,c{(i[x]==c||i[x]==?_)&&t<<x}
((x=t.pop)&&(s=x-w;c=i[x])<?0?(a[s+1,?/];a[s,?\\]):c<?]?(a[s-1,?\\];a[s,?/]):c<?`?(a[x-1,?\\];a[x+1,?/]):a[s,?|]
i[x]=' ')while t!=[]
!i[/\S/]}

Test online: http://ideone.com/Z7TLTt

Il programma procede come segue:

  • Ricerche di una radice (una \, /o |sull'ultima fila)
  • partendo da quella radice, scala l'albero usando le regole e sostituendo ogni carattere visitato con uno spazio
  • alla fine, vedi se la nostra stringa è completamente composta da spazi bianchi (che significa un albero valido) o no (albero non valido; non tutti i pezzi sono stati "visitati")

Qui è ungolfed:

F =-> input {
  row_size = input.index(?\n)+1

  root_coord = input.index /[^ _] *\n\z/

  # coordinates to process
  todo = [root_coord]

  add_todo = -> coord, char{
    if input[coord] == char || input[coord] == ?_
      todo << coord
    end
  }

  while todo.any?
    x = todo.pop

    next unless x # exit quickly if no root present

    case input[x]
    when ?|
      add_todo[x - row_size, ?|]
    when ?_
      add_todo[x - 1, ?\\]
      add_todo[x + 1, ?/]
    when ?/
      add_todo[x - row_size + 1, ?/]
      add_todo[x - row_size, ?\\]
    when ?\\
      add_todo[x - row_size - 1, ?\\]
      add_todo[x - row_size, ?/]
    end
    input[x]=' '
  end
  input.strip < ?*
}
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.