Ulirkan Kata, Segitiga!

Sep 02 2020

Tantangan

Diberikan string dengan panjang berapa pun, tulislah sebagai segitiga, dari tengahnya membentuk spiral. Misalnya abcdefghijklmnopmenjadi:

   g  
  fah
 edcbi
ponmlkj

Atau lebih eksplisit:

Jika Anda suka, Anda dapat memutar berlawanan arah jarum jam:

   g  
  haf
 ibcde
jklmnop

Atau tambahkan spasi secara seragam:

      g   

    f a h 

  e d c b i  

p o n m l k j 

Karakter masukan akan menjadi ascii, tetapi mungkin termasuk spasi. Selain itu, jumlah karakter mungkin bukan kuadrat sempurna ( Hello World!):

  W
  Ho
oller
   !dl

Beberapa kasus tepi lainnya. 2 masukan huruf ab:

 a
  b

Dan masukan 3 huruf abc:

 a
 cb

Deskripsi Prosedural

Jika contoh di atas tidak jelas, berikut adalah deskripsi prosedural prosesnya:

  1. Letakkan surat awal Anda.
  2. Bergerak ke bawah dan ke kanan secara diagonal (yaitu, arah ini \). Jadi jika Anda mulai di (0,0), Anda sekarang akan berada di (1, -1). Letakkan surat kedua Anda.
  3. Pindah ke kiri satu spasi setiap kali, jatuhkan satu huruf di setiap spasi, dengan total 3 spasi. Artinya, drop huruf pada (0,-1), (-1,-1), dan (-2, -1).
  4. Selanjutnya pindah secara diagonal ke atas dan ke kanan /dua spasi, jatuhkan huruf ke atas (-1,0)dan (0,1).
  5. Sekarang siklus kembali untuk bergerak secara diagonal ke bawah dan ke kanan, lanjutkan ke langkah dan jatuhkan huruf selama posisi Anda saat ini di kiri-kanan berdekatan dengan huruf yang ada.
  6. Selanjutnya pindah ke kiri lagi, lanjutkan ke langkah dan jatuhkan huruf selama Anda secara diagonal berdekatan /dengan huruf yang sudah ada.
  7. Pindah secara diagonal ke atas dan ke kanan lagi /, melangkah dan turunkan huruf selama posisi Anda saat ini di kiri-kanan berdekatan dengan huruf yang ada.
  8. Ulangi langkah 5-7 sampai semua huruf habis.

Lebih banyak contoh

Aturan

  • Kode golf, aturan standar berlaku.
  • Spasi atau baris baru tidak apa-apa.
  • Spasi atau baris baru yang konsisten juga diperbolehkan, selama bentuk segitiga dipertahankan.

Jawaban

8 KevinCruijssen Sep 02 2020 at 15:48

05AB1E , 24 20 15 13 byte

2Iā¨t·îŽOGsèΛ

-7 byte oleh port @ Neil 's Charcoal jawaban , menggunakan @att ' s rumus , jadi pastikan untuk upvote mereka berdua juga!

Cobalah secara online. Tidak ada rangkaian pengujian, karena builtin akan menyimpan konten sebelumnya dan tidak ada cara untuk mengatur ulang ( seperti inilah tampilannya .

Penjelasan:

2              # Push a 2
 I             # Push the input-string
  ā            # Push a list in the range [1,length] (without popping)
   ¨           # Remove the last value to change the range to [1,length)
    t          # Take the square-root of each value
     ·         # Double each
      î        # Ceil each
       ŽOG     # Push compressed integer 6136
          s    # Swap so the list is at the top of the stack again
           è   # Index each value (0-based and modulair) into the 6136
            Λ  # Pop all three and use the Canvas builtin,
               # after which the result is implicitly output immediately afterwards

Lihat ini 05AB1E ujung tambang (bagian Cara kompres bilangan bulat besar? ) Untuk memahami mengapa ŽOGadalah 6136.

Canvas builtin menggunakan tiga argumen untuk menggambar bentuk:

  • Karakter / string untuk menggambar: input dalam kasus ini
  • Panjang garis yang akan kita gambar: 2dalam kasus ini
  • Arah untuk menarik: [3,6,6,6,1,1,3,3,3,6,6,6,6,6,6,6,1,1,1,1,3,...].

Lihat jawaban asli di bawah untuk penjelasan tentang Canvas builtin. Berbeda dengan program di bawah yang daftar panjangnya mengarah, di sini daftar petunjuk arah mengarah karena kita menggunakan satu panjang 2.


Jawaban asli 24 20 byte :

ā·Ð·s>ø.ι˜DŠOð׫₆1ªΛ

Berisi spasi di depan / di belakang dan baris baru (semakin panjang masukan, semakin banyak spasi / baris baru)

Cobalah secara online. Tidak ada rangkaian pengujian, karena builtin akan menyimpan konten sebelumnya dan tidak ada cara untuk mengatur ulang ( seperti inilah tampilannya , di mana kasus pengujian digambar di atas satu sama lain).

Penjelasan:

ā           # Push a list in the range [1, length] of the (implicit) input (without popping)
            #  i.e. "Hello World!" → "Hello World!" and [1,2,3,4,5,6,7,8,9,10,11,12]
 ·          # Double each value in this list
            #  → [2,4,6,8,10,12,14,16,18,20,22,24]
  Ð         # Triplicate it
   ·        # Double each value of the top copy
            #  → [4,8,12,16,20,24,28,32,36,40,44,48]
    s       # Swap to get the other copy
     >      # Increase each by 1
            #  → [3,5,6,9,11,13,15,17,19,21,23,25]
      ø     # Create pairs of the top two lists
            #  → [[4,3],[8,5],[12,7],[16,9],[20,11],[24,13],[28,15],[32,17],[36,19],[40,21],[44,23],[48,25]]
       .ι   # Interleave it with the third list
            #  → [2,[4,3],4,[8,5],6,[12,7],8,[16,9],10,[20,11],12,[24,13],14,[28,15],16,[32,17],18,[36,19],20,[40,21],22,[44,23],24,[48,25]]
         ˜  # Flatten
            #  → [2,4,3,4,8,5,6,12,7,8,16,9,10,20,11,12,24,13,14,28,15,16,32,17,18,36,19,20,40,21,22,44,23,24,48,25]
D           # Duplicate this list of integers
 Š          # Triple-swap, so the stack order is list,input,list
  O         # Pop and sum the top list
            #  → 636
   ð×       # Create a string of that many spaces
     «      # And append it to the string
₆           # Push builtin 36
 1ª         # Convert it to a list of digits, and append 1: [3,6,1]
Λ           # Use the Canvas builtin with these three arguments,
            # after which the result is implicitly output immediately afterwards

Canvas builtin menggunakan tiga argumen untuk menggambar bentuk:

  • Karakter / string yang akan digambar: input dalam hal ini, ditambahkan dengan spasi tambahan
  • Panjang garis yang akan kita gambar: daftar [2,4,3,4,8,5,6,12,7,8,16,9,10,20,11,...]
  • Arah untuk menarik: [3,6,1]. Angka dalam rentang \$[0,7]\$ masing-masing mewakili arah tertentu:
7   0   1
  ↖ ↑ ↗
6 ← X → 2
  ↙ ↓ ↘
5   4   3

Jadi [3,6,1]dalam hal ini terjemahkan ke arah \$[↘,←,↗]\$.

Berikut penjelasan langkah demi langkah tentang output (kami akan menggunakan input "Hello_World!"sebagai contoh di sini):

Langkah 1: Gambar 2 karakter ( "He") ke arah 3↘:

H
 e

Langkah 2: Gambar 4-1 karakter ( "llo") ke arah 6←:

  H
olle

Langkah 3: Gambar 3-1 karakter ( "_W") ke arah 1↗:

  W
 _H
olle

Langkah 4: Gambar 4-1 karakter ( "orl") ke arah 3↘:

  W
 _Ho
oller
     l

Langkah 5: Gambar 8-1 karakter ( "d! ") ke arah 6←:

   W
  _Ho
 oller
    !dl

Dan lain-lain untuk semua spasi tambahan lainnya.

Lihat ujung 05AB1E saya ini untuk penjelasan mendalam tentang kanvas bawaan.

14 att Sep 02 2020 at 11:56

Bahasa Wolfram (Mathematica) , 99 byte

sPrint@@@Array[s[[4# #-2#+1-#2&@@If[Abs@#2<2#,!##,#-Abs@#2|-#2]]]/._@__->" "&,2{L=Tr[1^s],L},-L]

Cobalah secara online!

Secara langsung menghitung indeks dari setiap posisi: dalam koordinat Kartesius, \$\operatorname{index}(x,y)=\textit{offset}+\begin{cases}2y(2y+1)-x,&|x|<-2y\\ 2\left(y+|x|\right)\left(2\left(y+|x|\right)+1\right)+x,&\text{else}\end{cases}\$

dimana \$\textit{offset}\$ adalah indeks dari karakter "pertama" (1, dalam Mathematica).

Mengambil daftar karakter sebagai input.


Pendekatan yang lebih tua, 123 122 109 107 bytes

Print@@@Normal@SparseArray[i=0;p=2Length@#;(p+=ReIm[I[2+I,1-I][[⌈2√i++⌉~Mod~4-1]]-1])->#&/@#,2p," "]&

Cobalah secara online!

Arah karakter (1-indeks) irelatif terhadap karakter sebelumnya dapat dihitung dengan \$\Big\lceil2\sqrt i\Big\rceil\bmod 4\$:

  • 1: ↗
  • 2: ↘
  • 3,0: ​​←
9 Neil Sep 02 2020 at 07:00

Arang , 37 36 21 byte

GH✳✳E⊖LθI§4174⌈⊗₂⊕ι²θ

Cobalah secara online! Tidak ada tautan verbose karena deverbosifier mengeluarkan ✳σalih-alih ✳✳, menghasilkan kode ringkas yang tidak valid yang tidak dijalankan dengan benar, tetapi jika berhasil maka itu akan terjadi PolygonHollow(Directions(Map(Decremented(Length(q)), Cast(AtIndex("4174", Ceiling(Doubled(SquareRoot(Incremented(i)))))))), 2, q);. Terinspirasi oleh solusi 05AB1E @ KevinCruijssen, tetapi kemudian menggunakan rumus @ att untuk menghasilkan petunjuk arah. Penjelasan:

       θ                Input string
      L                 Length
     ⊖                  Decremented
    E                   Map over implicit range
                  ι     Current index (0-indexed)
                 ⊕      Incremented (i.e. 1-indexed)
                ₂       Square rooted
               ⊗        Doubled
              ⌈         Ceiling
         §4174          Cyclically index to find direction
        I               Cast to integer
  ✳✳                    Convert to directions
GH                 ²θ   Draw path using input string

Perintah menggambar jalan menggambar satu karakter untuk awal dan kemudian n-1karakter untuk setiap arah dalam larik. Sayangnya tidak ada string karakter tunggal yang mewakili arah diagonal jadi saya harus menggunakan integer sebagai gantinya; ini dimulai di 0kanan dan kenaikan untuk setiap 45 ° searah jarum jam.

Solusi 37 byte sebelumnya:

≔⮌⪪S¹θFLθF³F§⟦⊕⊗ι⁺³×⁴ι⊗⊕ι⟧κ¿θ✳⁻⁷׳κ⊟θ

Cobalah secara online! Tautan adalah untuk verbose versi kode. Penjelasan:

≔⮌⪪S¹θ

Pisahkan masukan menjadi karakter dan balikkan daftar.

FLθ

Ulangi dalam jumlah yang cukup banyak.

F³

Lingkaran untuk setiap sisi segitiga.

F§⟦⊕⊗ι⁺³×⁴ι⊗⊕ι⟧κ

Lingkaran untuk ukuran sisinya.

¿θ

Periksa apakah masih ada yang tersisa untuk dicetak.

✳⁻⁷׳κ⊟θ

Cetak karakter berikutnya ke arah yang sesuai.

7 MatthewJensen Sep 02 2020 at 07:04

JavaScript (V8) , 222 byte

s=>(g=(a,b,n=1)=>b?g([(c=(b+' '.repeat(n*8)).slice(0,n*8))[n*6-1],...[...a,c.slice(0,n*4-1)].map((l,i)=>c[n*6+i]+l+c[n*6-2-i])],b.slice(n*8),n+1):a)([s[0]],s.slice(1)).reduce((p,l,i,a)=>p+' '.repeat(a.length-i-1)+l+`
`,'')

Cobalah secara online!

Ini pasti bisa bermain golf lebih banyak.
Saya menggunakan algoritma rekursif, membagi keluaran menjadi 'lapisan' segitiga, di mana setiap lapisan adalah bungkus lengkap (tiga sisi) dari segitiga sebelumnya.

Ungolfed

s=>(g=(a,b,n=1)=> // g is a recursive function; a: previous; b: rest; n: increment
  b ? // if there is more string to wrap
    g([ // wrap b around a as a triangle and recurse
        (c=(b+' '.repeat(n*8)).slice(0,n*8))[n*6-1],
        ...[...a,c.slice(0,n*4-1)].map((l,i)=>c[n*6+i]+l+c[n*6-2-i])
      ],
      b.slice(n*8),
      n+1)
  :a // otherwise return the triangle
  )
  ([s[0]],s.slice(1)) // run the function with the first letter and the rest
  .reduce((p,l,i,a)=>p+' '.repeat(a.length-i-1)+l+'\n','') // step the triangle to make it look like it is meant to
7 Arnauld Sep 02 2020 at 19:09

JavaScript (ES8), 137 byte

Mengharapkan array karakter. Mengembalikan string.

Versi ini didasarkan pada formula yang digunakan oleh @att , dimodifikasi agar lebih ramah golf di JS.

a=>a.map((c,n)=>(m[y+=~(d=2*n**.5-1/n)%4%3?d&++x/x||-1:!x--]=m[y]||[...''.padEnd(x)])[x]=c,m=[],x=y=a.length)&&m.map(r=>r.join``).join`
`

Cobalah secara online! (keluaran mentah)

Cobalah secara online! (dengan spasi ekstra dihapus)

Bagaimana?

Mengingat posisi \$n\$karakter, arah \$0\le d\le 2\$ dapat dihitung dengan:

$$d=\left(\left\lfloor2\sqrt{n}+1-\frac{1}{n}\right\rfloor\bmod 4\right)\bmod 3$$

Implementasi JS yang sebenarnya adalah:

~(2 * n ** 0.5 - 1 / n) % 4 % 3

yang mengevaluasi ke \$0\$, \$-1\$atau \$-2\$.


JavaScript (ES8),  163157  byte

Mengharapkan array karakter. Mengembalikan string.

a=>a.map(c=>((m[y]=m[y]||[...''.padEnd(x)])[x]=c,j%3%2?x--:y+=!!++x-j%3,k?k--:k=(n=j/3<<1)+(j++%3||n+2)),m=[],j=k=0,x=y=a.length)&&m.map(r=>r.join``).join`
`

Cobalah secara online! (keluaran mentah)

Cobalah secara online! (dengan spasi ekstra dihapus)

Bagaimana?

Ini adalah algoritme yang cukup sederhana yang menggambar karakter keluaran demi karakter dalam matriks \$m[\:]\$, melacak posisi \$(x,y)\$pena, arah ke \$\{0,1,2\}\$dan nomornya \$k\$ karakter untuk menggambar sebelum perubahan arah berikutnya.

Kami bergerak sesuai dengan tabel berikut:

 direction | moving towards | distance
-----------+----------------+----------
     0     | South-East     |  2t + 1       (t = turn number)
     1     | West           |  4t + 3
     2     | North-East     |  2t + 2

Pemberian yang mana:

t = 0     t = 1        t = 2            t = 3

                                          2       
                         2               2.       
            2           2.              2..0      
  2        2.          2..0            2....0     
 2X       2.X0        2..X.0          2...X..0    
1110     2....0      2......0        2........0   
        11111110    2........0      2..........0  
                   111111111110    2............0 
                                  1111111111111110

Dalam implementasi JS, kami tidak menyimpan arah secara eksplisit. Sebagai gantinya, kami menggunakan penghitung \$j\$pergi dari \$0\$ke \$+\infty\$dan gunakan \$j\bmod 3\$untuk mengetahui arah arus. Kami juga tidak menyimpan nomor belokan tetapi menghitung \$n=2\cdot\lfloor j/3\rfloor\$, menggunakan nilai \$j\$ sebelum ditambahkan untuk memperhitungkan perubahan arah (yang berarti \$n\$sama dengan \$2(t-1)\$daripada \$2t\$ketika arahnya membungkus menjadi \$0\$).

Oleh karena itu tabel berikut:

     j mod 3     |  (j + 1) mod 3  |                     | new starting
 (old direction) | (new direction) |    new distance     | value for k
-----------------+-----------------+---------------------+--------------
        2        |        0        | (n + 2) + 1 = n + 3 |     n + 2
        0        |        1        |      2n + 3         |    2n + 2
        1        |        2        |       n + 2         |     n + 1

Dan ekspresi yang sesuai untuk diperbarui \$k\$:

k = (n = j / 3 << 1) + (j++ % 3 || n + 2)

Koordinat diperbarui dengan:

j % 3 % 2 ?          // if the direction is 1:
  x--                //   decrement x
:                    // else:
  y += !!++x - j % 3 //   increment y if the direction is 0
                     //   or decrement y if it's 2
                     //   increment x in both cases
5 att Sep 04 2020 at 00:19

R , 205 153 147 136 132 126 bytes

-52 dari Dominic van Essen.
-4 dari Giuseppe.
-4 sekali lagi berkat Giuseppe.
-5 Terima kasih lebih lanjut kepada Dominic van Essen

function(s,n=nchar(s))for(y in(x=-n:n)*2)cat(ifelse((i=(t=y-2*(r=abs(x))*!r<y)*t-t-2*(r<y)*x+x+1)>n," ",substring(s,i,i)),"
")

Cobalah secara online!

4 DLosc Sep 03 2020 at 09:31

Pip -l , 70 byte

sMC:Y#ax:w:y/2-/2Ly*2L++i/2{I++v<ys@w@x:a@vi%4%3?++x&i%4=1?--w++w--x}s

Cobalah secara online!

... Saya tidak yakin ingin mencoba menjelaskan monstrositas ini secara detail. Ide dasarnya adalah untuk membuat array 2D yang sangat besar dari spasi ( sMC:#a) dan kemudian menempatkan karakter dari string input ke dalam array pada indeks yang tepat ( s@w@x:a@v). Sisa kode menjelaskan apa itu "indeks yang tepat".


Pendekatan alternatif, 77 byte:

a.:sX#aW<|a{UpaWa^@YxNl?v+1++v%2?v*2+1vl:xNl?RV^p.:lv%2?lPEpl.^pAEx}RVsX,#l.l

Cobalah secara online!

Membangun segitiga sebagai daftar garis, bergantian antara menambahkan garis ke depan / akhir daftar dan menambahkan karakter ke depan / akhir setiap baris. Saya berharap cara ini mungkin lebih pendek, tetapi sejauh ini tampaknya tidak.

4 Bubbler Sep 03 2020 at 13:54

J , 60 byte

4 :'x(<"1(#x)++/\(3|4|>.2*%:i.#x){<:3 3#:3 2 8)}y',~' '"0/,~

Cobalah secara online!

Jawaban wajib J karena itu tantangan Yunus.

Karena "ganti posisi tertentu di dalam larik dengan nilai" bukanlah kata kerja melainkan kata keterangan, kata itu tidak bisa digunakan dalam train apa adanya, sehingga dibungkus di dalam kata kerja sebaris eksplisit.

Menggunakan rumus att untuk menyusun arah.

Bagaimana itu bekerja

NB. input: a string (character vector) of length n

,~' '"0/,~  NB. create a large enough canvas (blank matrix of size 2n*2n)
        ,~  NB. concatenate two copies of self
       /    NB. outer product by...
  ' '"0     NB.   a constant function that returns blank per character
,~          NB. concatenate two copies of self

4 :'...'  NB. a dyadic explicit verb, where x is the input string and
          NB. y is the canvas generated above
x(...)}y    NB. replace some places of y by contents of x...
3|4|>.2*%:i.#x  NB. formula by att (gives 0, 1, or 2 per index)
(...){          NB. select the directions based on the above...
<:3 3#:3 2 8    NB. the matrix (0 -1)(-1 1)(1 1) i.e. L/RU/RD
(#x)++/\        NB. take cumulative sum (giving coords to place each char)
                NB. and add n to all elements
<"1             NB. enclose each row to satisfy the input format of }
4 DominicvanEssen Sep 02 2020 at 20:06

R , 270 265 252 243 232 227 225 bytes

Saya akhirnya berhasil menghapus 2 karakter lagi untuk membawa total ke angka yang dapat direpresentasikan dalam bentuk segitiga (seperti yang ditunjukkan di sini). Kode harus diformat secara konvensional untuk dijalankan (seperti pada contoh di TIO); '•' mewakili karakter baris baru ( \n).

              f
             unc
            tion(
           s,`~`=c
          bind,m=ma
         trix){n=nch
        ar(s)+1;p=m(,
       n^2,2);while(T<
      n){a=4*F;p[T+0:a,
     ]=c(F:-F,(-F:F)[-1]
    )~0:a-2*F;p[T+a+-2:a+
   3,]=(F=F+1)~(b=2*F-1):-
  b;T=T+2*a+4};m=m(" ",n,n)
 ;m[p[2:n-1,]+b+1]=el(strspl
it(s,''));apply(m,1,cat,"•")}

Cobalah secara online!

Perhatikan bahwa pendekatan ini telah dikalahkan secara komprehensif oleh pendekatan att , meskipun sebagai penghiburan baik itu maupun jawaban saat ini lainnya tidak dapat direpresentasikan sebagai segitiga ...

Bekerja dengan menyusun koordinat untuk setiap huruf, kemudian menggunakannya untuk meletakkan huruf-huruf tersebut ke dalam matriks kosong.

Berkomentar:

triangle=
function(s){n=nchar(s)          # n is the number of letters
s=el(strsplit(s,''))            # first split the string into individual letters
p=matrix(,2,n^2)                # initialize p as a 2-row matrix to hold the coordinates
                                # (with plenty of columns so that we've enough to go all 
                                # the way round the outermost triangle)
                                # now, F is the current loop, starting at 0
while(T<=n){                    # T is the current letter index
a=4*F+1                         # a=the size of the 'arch' (number of letters going up & over)
p[,T+1:a-1]=                    # set the coordinates for the arch letters...
  rbind(                        # ...(rbind combines rows for y & x coordinates)...
    c(F:-F,(-F:F)[-1]),         # ...to y = F..-F, and then -F+1..F (so: up & then down again)
    1:a-2*F-1)                  # ...and x = across the arch from -2*F to +2*F
a=a+2                           # a=now the width of the base = size of arch + 2
p[,T+a+1:a-3]=                  # now set the coordinates of the base letters...
  rbind(                        #
    F+1,                        # ... base y = row F+1
    (b=2*F+1):-b)               # ... and x = goes (backwards) from 2*F+1..-2*F-1
T=T+2*a-2                       # update the current letter index
F=F+1}                          # increment the loop
p=p[,1:n]                       # delete any excess coordinates
p=p-min(p)+1                    # re-zero the coordinates to remove negatives
m=matrix(" ",b<-max(p),b)       # create a new matrix filled with " "
m[t(p)]=s                       # and fill it with the letters at the right positions
n=apply(m,1,cat,"               # finally, print each row
")}
2 user Sep 03 2020 at 01:33

Scala, 322.318 byte

s=>((s zip Seq.unfold((0,0,0->0)){case(r,n,y->x)=>Option.when(n<s.size){val(c,t)=(math.sqrt(n).toInt%2,r+1-math.abs(x.sign))
(y->x,(t,n+1,(y+(c-1)*(1-t%2*2),x+1-c*2)))}}groupBy(_._2._1)toSeq)sortBy(_._1)map(_._2.sortBy(_._2._2)map(_._1)mkString)zipWithIndex)map{t=>" "*(math.sqrt(s.size).toInt-t._2)+t._1}mkString "\n"

Cobalah di Scastie (tidak berfungsi di TIO)

1 KjetilS. Sep 06 2020 at 10:57

Perl 5 , 163 byte

sub f{                    #newlines and indentation added here for readability. 
  $_=' 'x1e3; @L=(51,$a=-1,-49)x($p=225); for$c(pop=~/./g){
    $P=$p+$L[1]; $a++>0&&s/^(.{$P}) /$1$c/s&&($p=$P,$a=0,shift@L)||substr$_,$p+=$L[0],1,$c
  }
  s/.{50}/$&\n/gr
}

Singkatnya, ia menambahkan karakter berikutnya dari input ke arah saat ini kecuali jika ia menemukan saatnya untuk mengubah arah.

Cobalah secara online!