Visualizzazione del grafico delle dipendenze


22

L'obiettivo di questa sfida è scrivere un programma che visualizzi un grafico delle dipendenze sotto forma di un albero. Mentre "grafico delle dipendenze" in questo contesto non significa nient'altro che un grafico diretto, il metodo di visualizzazione qui descritto funziona meglio per i grafici che descrivono alcune relazioni di dipendenza (come esercizio, dopo aver letto la sfida, prova a invertire la direzione di uno dei i grafici di esempio e vedere se il risultato è altrettanto utile.)

L' input per il programma è costituito da una o più definizioni di destinazione , che sono linee del modulo

Target DirectDependency1 DirectDependency2 ...

, definendo un obiettivo e le eventuali dipendenze dirette associate . I target e le loro dipendenze sono chiamati collettivamente oggetti . Se un oggetto viene visualizzato solo come dipendenza e non come destinazione, non ha dipendenze. L'insieme di tutti gli oggetti che appaiono nell'input si chiama Γ . (Vedi la sezione Input e Output per maggiori dettagli sul formato di input.)

Per ogni coppia di oggetti, A e B , diciamo che:

  • A dipende da B (equivalentemente, B è richiesto da A ), se A dipende direttamente da B , o se A dipende direttamente da B ' , e B' dipende da B , per alcuni oggetti B ' ;
  • Un dipende correttamente su B (equivalentemente, B è correttamente richiesto da A ), se A dipende B e B non dipende A .

Definiamo un oggetto artificioso, ʀooᴛ , non in Γ, in modo tale che ʀooᴛ non sia richiesto direttamente da nessun oggetto e tale che, per tutti gli oggetti A , ʀooᴛ dipenda direttamente da A se e solo se A è in Γ e A non lo è correttamente richiesto da qualsiasi oggetto in Γ (in altre parole, ʀooᴛ dipende direttamente da A se nessun altro oggetto dipende da A o se tutti gli oggetti che dipendono da A sono richiesti anche da A. )

Albero di output

Costruiamo un albero , il cui nodo radice è ʀooᴛ, e in modo tale che i figli di ciascun nodo siano le sue dipendenze dirette. Ad esempio, dato l'input

Bread Dough Yeast
Dough Flour Water
Butter Milk

, l'albero risultante è

Esempio di albero di output

o, in forma ASCII,

ʀooᴛ
+-Bread
| +-Dough
| | +-Flour
| | +-Water
| +-Yeast
+-Butter
  +-Milk

. L' output del programma è l'albero sopra definito, stampato senza il nodo ʀooᴛ. Quindi, ad esempio, l'uscita corrispondente per l'ingresso sopra è

Bread
+-Dough
| +-Flour
| +-Water
+-Yeast
Butter
+-Milk

. Una descrizione dettagliata del layout dell'albero di output viene fornita in seguito.

Ordine dei nodi

I nodi figlio di un dato nodo genitore, P , dovrebbero essere ordinati , in modo tale che, per tutti i nodi figlio A e B di P , A appare prima di B se e solo se

  • esiste un nodo figlio C di P , tale che A sia correttamente richiesto da C , e C precede, o è uguale a, B , secondo lo stesso ordine; oppure ,
  • A precede alfabeticamente B (più precisamente, A precede B usando le regole di confronto ASCII) e non esiste alcun nodo figlio C di P , tale che B sia correttamente richiesto da C e C precede, o è uguale a, A , secondo lo stesso ordine .

(Le persone in cerca di una sfida matematica potrebbero voler dimostrare che questa relazione è ben definita e che in realtà è un ordine totale rigoroso. Non dimenticare che Γ è finito!)

Ad esempio, dato l'input

X D C B A
B D
C A

, l'output dovrebbe essere

X
+-A
+-D
+-B
| +-D
+-C
  +-A

. Aappare prima Be Bappare prima a Ccausa del loro ordine alfabetico; Dappare prima B, poiché è debitamente richiesto da essa, e dopo A, poiché lo segue in ordine alfabetico; Be Cnon appaiono prima D, anche se lo precedono in ordine alfabetico, poiché esiste un nodo, vale a dire B, che richiede correttamente De che equivale a B(cioè, se stesso) e precede C, secondo le stesse regole.

ripetizioni

Lo stesso oggetto, A , può apparire più di una volta nell'output, se, ad esempio, è richiesto da più di un oggetto. Se A non ha dipendenze proprie, in questo caso non è richiesta alcuna gestione speciale. Altrimenti, al fine di minimizzare la verbosità dell'output ed evitare la ricorsione infinita dovuta a dipendenze circolari, le dipendenze di A sono elencate solo al suo primo verificarsi per il quale nessuno degli antenati è fratello di un altro nodo A ; qualsiasi altra occorrenza di A non dovrebbe avere figli e dovrebbe apparire seguita da uno spazio e un puntino di sospensione, come in .A...

Ad esempio, dato l'input

IP Ethernet
TCP IP
UDP IP
WebRTC TCP UDP

, l'output dovrebbe essere

WebRTC
+-TCP
| +-IP
|   +-Ethernet
+-UDP
  +-IP ...

. Come altro esempio, caratterizzato sia dalla dipendenza circolare sia dalle considerazioni sugli antenati,

Rock Scissors
Paper Rock
Scissors Paper

, dovrebbe risultare in

Paper
+-Rock ...
Rock
+-Scissors ...
Scissors
+-Paper ...

. Si noti che, ad esempio, la prima occorrenza di Rocknon elenca le sue dipendenze, dal momento che è padre Paper, è un fratello di un altro Rocknodo. Il genitore del secondo Rocknodo, ʀooᴛ (che non appare nell'output), non ha Rockcome fratello, quindi le dipendenze di Rocksono elencate su questo nodo.

Layout dell'albero di output

Sono sicuro che hai capito come l'albero dovrebbe essere rappresentato come arte ASCII (e sentiti libero di saltare questa sezione se lo hai,) ma per completezza ...

I nodi figlio di ʀooᴛ sono stampati su righe separate, senza alcun rientro, in ordine. Ogni nodo è immediatamente seguito dai suoi figli, se presenti, stampati nello stesso modo, ricorsivamente, indentati da due caratteri a destra. Per ogni nodo che ha figli, una linea verticale, composta da caratteri |(pipe), si estende dal carattere direttamente sotto il primo carattere del nodo, fino alla riga del suo ultimo nodo figlio, senza includere i figli dell'ultimo nodo figlio. Se il rientro di un nodo è diverso da zero, è preceduto da +-(sullo stesso livello di rientro del suo genitore), sovrascrivendo la linea verticale sopra descritta.

Ingresso e uscita

È possibile leggere l'input tramite STDIN o utilizzando un metodo equivalente . Puoi presumere che non ci siano righe vuote e potresti richiedere che l'ultima riga termini o non termini in un carattere di nuova riga. Si può presumere che i nomi degli oggetti siano costituiti da caratteri ASCII stampabili (escluso lo spazio). Si può presumere che gli oggetti in una definizione di destinazione siano separati da un singolo carattere di spazio e che non vi siano spazi iniziali o finali . Si può presumere che ogni destinazione sia definita al massimo una volta e che non vi siano ripetizioni nel suo elenco di dipendenze.

È possibile scrivere l'output su STDOUT o utilizzare un metodo equivalente . Tutte le linee di output, ad eccezione del più lungo, possono includere spazi finali. L'ultima riga di output può o meno terminare con un carattere di nuova riga.

Punto

Questo è code-golf . La risposta più breve , in byte, vince.

Casi test

Il programma dovrebbe elaborare ciascuno dei seguenti casi di test in un periodo di tempo ragionevole.


Ingresso

Depender Dependee
Independent

Produzione

Depender
+-Dependee
Independent

Ingresso

Earth Turtle
Turtle Turtle

Produzione

Earth
+-Turtle
  +-Turtle ...

Ingresso

F A C B D I
A B
B A C
D E H
C
G F
J H G C E I
E D
H D
I G

Produzione

J
+-C
+-E
| +-D
|   +-E ...
|   +-H ...
+-H
| +-D ...
+-G
| +-F
|   +-C
|   +-A
|   | +-B ...
|   +-B
|   | +-C
|   | +-A ...
|   +-D ...
|   +-I ...
+-I
  +-G ...

Albero tecnologico di Civilization V

Ingresso

Produzione


Cygwin syslog-ng Grafico delle dipendenze dei pacchetti

Ingresso

Produzione


regex.cGrafico chiamate GNU grep

Ingresso

Output (Whoops! Troppo lungo per essere gestito da SE.)


5
Ben specificato!
Non che Charles, il

L'autoreferenzialità nella sezione Ordine dei nodi mi fa male alla testa.
ricorsivo

Risposte:


5

Haskell, 512 byte

import Data.List
r=reverse
n j|let(w,s)#p|let a?b=or[q!b<GT|(q,r)<-i,a==r,elem q(h p)>elem(a,q)i];a!b|a==b=EQ|a?b||(a<b)>b?a=LT;_!_=GT;l=nub.sortBy(!)$h p;m(v,s)q|h q==[]=(v,[q]:s)|elem q w=(v,[q++" ..."]:s)|(w,x:y)<-(v,[])#q=(w,(q:(u"| "=<<r y)++u"  "x):s)=foldl m(l++w,[])l;c(p,q)=z$p:q:h q;y=z=<<j;i=iterate(nub.sort.(c=<<))y!!length j;h""=[p|p<-id=<<j,and[elem(p,r)i|(r,q)<-i,p==q]];h p=[r|(q,r)<-y,p==q]=unlines=<<r(snd$mempty#"")
u s(x:y)=("+-"++x):map(s++)y
z(x:y)=(,)x<$>y
main=interact$n.map words.lines

Corri online su Ideone


Congratulazioni. Molto bella!
Ell
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.