Apakah Ini Pohon Asli?

20

Anda harus menulis program atau fungsi yang menerima string sebagai input dan output atau mengembalikan jika inputnya adalah pohon ASCII.

  _
\/  /
 \_/
  |
  |

Pohon ASCII terdiri dari karakter / \ | _ spacesdan newlines.

Karakter non-spasi putih menghubungkan dua titik tepi sel mereka dengan segmen garis:

  • / menghubungkan sudut kiri bawah dan kanan atas
  • \ menghubungkan sudut kanan bawah dan kiri atas
  • | menghubungkan titik tengah dari tepi bawah dan tepi atas
  • _ menghubungkan sudut kiri bawah dan kanan bawah dan titik tengah tepi bawah

(Perhatikan bahwa ini berarti bahwa |hanya dapat terhubung dengan |atau _tetapi tidak dengan /atau \.)

Gambar ASCII disebut pohon jika aturan berikut ini berlaku:

  • Tepat satu titik (root) tepat satu karakter menyentuh ke tepi bawah baris terakhir.
  • Anda dapat mencapai titik mana pun dari segmen garis apa pun dengan:

    • mulai dari root
    • hanya menggunakan segmen garis
    • tidak pernah pergi ke arah bawah (bahkan tidak menyamping ke bawah)

Memasukkan

  • String yang terdiri dari karakter / \ | _ spacedan newlinemengandung setidaknya satu karakter non-spasi.
  • Anda dapat memilih dua format input:

    • Tidak ada spasi putih yang tidak perlu di sekitar pohon (seperti terlihat pada contoh).
    • Tidak ada spasi putih yang tidak perlu di sekitar pohon (seperti terlihat dalam contoh) kecuali spasi di sisi kanan baris untuk membuat semua baris memiliki panjang yang sama.
  • Mengejar baris baru adalah opsional.

Keluaran

  • Nilai kebenaran yang konsisten jika inputnya adalah pohon ascii.
  • Nilai falsy yang konsisten jika input bukan pohon ascii.

Contohnya

Pohon yang valid:

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

Pohon tidak valid (dengan penjelasan tambahan yang bukan bagian dari 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)
|

Ini adalah kode-golf sehingga entri terpendek menang.

randomra
sumber

Jawaban:

7

PMA / Siput , 99 93

Mencetak 1 jika memenuhi definisi "tree" atau 0 jika tidak. Bentuk input ruang-empuk persegi panjang lebih disukai, meskipun biayanya hanya satu byte (menggunakan Fopsi) untuk mengkonversi versi kasar ke persegi panjang yang diisi ruang, yang berguna dalam pengujian.

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

Versi ungolfed, ketinggalan jaman (untuk kesenangan menonton pribadi saya):

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

Ini ternyata cukup sesuai dengan fitur bahasa saat ini. Sayangnya, saya harus menghabiskan beberapa jam mengejar bug penghitungan referensi sebelum bisa bekerja.

The &pilihan berarti bahwa pertandingan harus berhasil pada setiap karakter. Dari setiap titik awal non-ruang memeriksa untuk jalur ke bawah ke bawah. Membuat mesin negara terbatas dengan regex untungnya jauh lebih pendek dengan menggunakan pernyataan, di sini =.... Di baris bawah, ini memeriksa bahwa tidak ada karakter non-spasi di sebelah kanan.

feersum
sumber
10

Mathematica, 345 300 byte

Masih cukup lama, tapi kurasa ini awal ...

(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[#,"
"])&

Berikut ini adalah versi yang sedikit tidak diubah:

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

Ini mendefinisikan fungsi tanpa nama yang mengambil string sebagai input dan mengembalikan Trueatau False.

Ide dasarnya adalah pertama-tama untuk memeriksa bahwa ada satu root, dan kemudian membangun objek (diarahkan) yang sebenarnya Graphuntuk memeriksa apakah semua simpul dapat dicapai dari root. Inilah cara kami membuat grafik:

Bayangkan sebuah grid integer yang dilapis ke dalam seni ASCII, di mana koordinat integer sesuai dengan sudut sel karakter. Kemudian pada masing-masing sel ada enam titik relevan yang bisa dihubungkan. Berikut ini sebuah contoh, di mana saya juga memberi label poin-poin auntuk f:

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

Jadi kita bisa membuat grafik yang simpulnya adalah koordinat setengah bilangan bulat ini, dan ujung-ujungnya ditentukan oleh karakter non-spasi dalam input. |menghubungkan bke e, /menghubungkan ake fdan \menghubungkan cke d. Perhatikan bahwa ini harus diarahkan tepi untuk memastikan bahwa kita tidak pernah bergerak ke bawah saat melintasi grafik nanti. Untuk _kita bisa jalan baik, sehingga dalam teori kita perlu empat sisi a -> b, b -> a, b -> c, c -> b. Namun, kita dapat melihat bahwa semua yang penting adalah bahwa ada siklus yang berisi semua tiga simpul, sehingga kita dapat mempersingkat ini untuk tiga tepi: a -> b, b -> c, c -> a.

Membangun grafik ini cukup sederhana di Mathematica, karena objek apa pun dapat bertindak sebagai simpul, jadi saya benar-benar dapat membuat grafik yang simpulnya adalah pasangan koordinat.

Akhirnya, kami memeriksa bahwa setiap titik dapat dicapai dari root. Koordinat root mudah ditemukan sebagai titik pertama yang kami tambahkan ke grafik. Maka cara terpendek yang saya temukan untuk memeriksa apakah semua simpul dapat dicapai adalah dengan memeriksa apakah VertexOutComponentroot (yaitu himpunan semua simpul yang dapat dijangkau dari root) identik dengan himpunan semua simpul dalam grafik.

Martin Ender
sumber
1
300 byte mungkin lama, tapi persis 300 begitu memuaskan!
Alex A.
2

Ruby 226 227 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/]}

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

Program melakukan hal berikut:

  • pencarian untuk akar (a \, /atau |pada baris terakhir)
  • mulai dari root itu, memanjat pohon menggunakan aturan dan mengganti setiap char yang dikunjungi dengan spasi
  • pada akhirnya, lihat apakah string kami sepenuhnya terdiri dari spasi putih (berarti pohon yang valid), atau tidak (pohon tidak valid; tidak semua bagian telah "dikunjungi")

Ini dia 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 < ?*
}
Cristian Lupascu
sumber