Membuka kode sumber Hexagony

52

pengantar

Jika Anda tidak terbiasa dengan Hexagony , itu adalah bahasa esoterik yang dibuat oleh Martin Büttner. Masalahnya adalah bahwa bahasa ini menerima beberapa bentuk untuk program ini. Semua program berikut ini setara:

abcdefg

dan

 a b
c d e
 f g

Jadi pada dasarnya, kode tersebut telah digulung menjadi segi enam biasa. Tetapi perhatikan bahwa menambahkan perintah baru ke kode, yang abcdefghakan menghasilkan program berikut:

  a b c
 d e f g
h . . . .
 . . . .
  . . .

Seperti yang Anda lihat, langkah pertama adalah menggulung kode menjadi segi enam, dan setelah itu segi enam diisi dengan no-ops ( .) ke nomor heksagonal tengah terpusat berikutnya .

Tugas Anda sederhana, ketika diberi string (kode sumber), mengeluarkan kode sumber segi enam lengkap.

Aturan

  • Anda dapat menyediakan program atau fungsi.
  • Ruang putih terkemuka diizinkan, tetapi hanya ketika segi enam tidak keluar dari bentuk
  • Trailing whitespace diizinkan.
  • Perhatikan bahwa spasi putih dalam program diabaikan . Begitu a b cjuga denganabc
  • Hanya karakter ASCII yang dapat dicetak ( 32 - 126) yang digunakan, jadi hanya Spacekarakter biasa yang diabaikan.
  • Asumsikan bahwa panjang string lebih besar dari 0.
  • Ini adalah , jadi pengiriman dengan jumlah byte paling sedikit menang!

Uji kasus

Input: ?({{&2'2':{):!/)'*/

Output:
  ? ( {
 { & 2 '
2 ' : { )
 : ! / )
  ' * /


Input: H;e;l;d;*;r;o;Wl;;o;*433;@.>;23<\4;*/

Output:
   H ; e ;
  l ; d ; *
 ; r ; o ; W
l ; ; o ; * 4
 3 3 ; @ . >
  ; 2 3 < \
   4 ; * /


Input: .?'.) .@@/'/ .!.>   +=(<.!)}    (  $>( <%

Output:
   . ? ' .
  ) . @ @ /
 ' / . ! . >
+ = ( < . ! )
 } ( $ > ( <
  % . . . .
   . . . .
Adnan
sumber
6
Juga, saya tidak yakin apakah Anda ingin menjadi pemilih itu, tetapi backticks diabaikan dalam proses menentukan lebar kode karena mereka membubuhi keterangan karakter berikutnya. Jadi abc`defgakan benar-benar menjadi pastebin.com/ZrdJmHiR
Martin Ender
2
@ MartinBüttner Oh, saya tidak tahu itu :). Untuk tantangan ini, backticks tidak akan diabaikan.
Adnan
18
Saya benar-benar ingin melihat jawaban dalam Hexagony untuk pertanyaan ini.
Arcturus
2
@Adnan Mungkin respons yang lebih baik adalah "Anda dapat berasumsi bahwa input tidak mengandung flag debug ( `karakter)."
Bersepeda
4
@Ampora Tanyakan dan Anda akan menerima.
Martin Ender

Jawaban:

13

Pyth, 57 54 50 49 48 46

V+UJfgh*6sUTlK-zd1_UtJ+*d-JNjd:.[K\.^TJZ=+Z+JN

Test Suite

Mencetak ruang terkemuka di setiap baris.

Versi ini membutuhkan bukti bahwa 10 ^ n> = 3n (n - 1) + 1 untuk semua n> = 1 . Terima kasih kepada ANerdI dan ErickWong karena memberikan bukti.

Berikut ini ketidaksetaraan: 10 ^ n> (1 + 3) ^ n = 1 + 3n + 9n (n - 1) + ...> 3n (n - 1) + 1 orang dapat dengan mudah melihat bahwa ini benar untuk n> = 2 . Memeriksa kasus n = 1 agak sepele, memberi 10> 1 .

Sebagai alternatif, mengambil turunan dari persamaan ini dua kali menunjukkan bahwa 10 ^ n memiliki turunan kedua yang lebih besar untuk semua n> = 1 , yang kemudian dapat diturunkan ke derivatif pertama, dan akhirnya ke persamaan asli.

Penjelasan

              ##  Implicit: z=input(); Z=0
Jf...1        ##  Save to J the side length of the hexagon the code fills up
              ##  by finding the first number such that:
gh*6sUT       ##  the the T'th hexagonal number is greater than...
              ##  Computes 6 * T'th triangular number (by using sum 1..T-1) + 1
    lK-zd     ##  ...the length of the code without spaces (also save the string value to K)
V+UJ_UtJ      ##  For loop over N = [0, 1, ..., J-1, ..., 0]:
+*d-JN        ##  append J - N spaces to the front of the line
jd            ##  riffle the result of the next operation with spaces
:.[K\.yJ      ##  slice the string given by K padded to be the length of the Jth hexagon
              ##  number with noops
Z=+Z+JN       ##  from Z to Z + J + N, then set Z to be Z + J + N
FryAmTheEggman
sumber
2
Pertama, Anda perlu membuktikan bahwa ln (10) * 10 ^ n> 6n-3 (turunannya) untuk n> = 1. Ini mudah, karena turunan dari ekspresi ini adalah ln (10) ^ 2 10 ^ n dan 6. Karena 10 ^ n meningkat secara monoton dan 10 ^ 1> 6 * 1, 10 ^ n lebih besar dari 6n-3 untuk semua n> = 1. Anda dapat menggunakan logika yang sama untuk melengkapi bukti untuk 10 ^ n dan 3n (n-1) +1.
Arcturus
@Ampora Terima kasih, saya telah mempertimbangkan untuk menggunakan turunan, tetapi sepertinya tidak bersih. Saya tidak dapat menemukan cara yang lebih baik, sangat dihargai!
FryAmTheEggman
Senang untuk membantu. Calc kadang-kadang bisa sangat jelek.
Arcturus
di tautan pyth.herokuapp.com/?code=etc di atas saya menemukan kompiler tidak berjalan ...
RosLuP
1
@FryAmTheEggman Ada cara yang sangat mudah untuk menunjukkan ikatan yang lebih kuat 4 ^ n> 3n (n-1) + 1 untuk n> = 1, tidak diperlukan kalkulus. Cukup gunakan fakta bahwa (1 + 3) ^ n = 1 + 3n + 9n (n-1) / 2 + ... dengan ekspansi binomial. Istilah pertama dan ketiga secara langsung mengambil jurusan 1 + 3n (n-1), sehingga ketidaksetaraan langsung terjadi jika istilah ketiga ada (yaitu, untuk n> = 2). Ini hanya menyisakan kasus n = 1 yang sepele karena RHS adalah 1.
Erick Wong
90

Hexagony , 271 byte

Saya persembahkan untuk Anda, 3% pertama dari penerjemah mandiri Hexagony ...

|./...\..._..>}{<$}=<;>'<..../;<_'\{*46\..8._~;/;{{;<..|M..'{.>{{=.<.).|.."~....._.>(=</.\=\'$/}{<}.\../>../..._>../_....@/{$|....>...</..~\.>,<$/'";{}({/>-'(<\=&\><${~-"~<$)<....'.>=&'*){=&')&}\'\'2"'23}}_}&<_3.>.'*)'-<>{=/{\*={(&)'){\$<....={\>}}}\&32'-<=._.)}=)+'_+'&<

Cobalah online! Anda juga dapat menjalankannya sendiri, tetapi akan memakan waktu sekitar 5-10 detik.

Pada prinsipnya ini mungkin cocok dengan panjang sisi 9 (untuk skor 217 atau kurang), karena ini hanya menggunakan 201 perintah, dan versi yang tidak di-serang yang saya tulis pertama kali (pada panjang sisi 30) hanya membutuhkan 178 perintah. Namun, saya cukup yakin akan butuh waktu lama untuk benar-benar membuat semuanya pas, jadi saya tidak yakin apakah saya benar-benar akan mencobanya.

Seharusnya juga memungkinkan untuk bermain golf ini sedikit dalam ukuran 10 dengan menghindari penggunaan satu atau dua baris terakhir, sehingga trailing no-ops dapat dihilangkan, tetapi itu akan membutuhkan penulisan ulang yang substansial, sebagai salah satu jalur pertama bergabung memanfaatkan sudut kiri bawah.

Penjelasan

Mari kita mulai dengan membuka kode dan membubuhi keterangan jalur alur kontrol:

masukkan deskripsi gambar di sini

Itu masih cukup berantakan, jadi di sini adalah diagram yang sama untuk kode "ungolfed" yang saya tulis pertama (sebenarnya, ini adalah sisi-panjang 20 dan awalnya saya menulis kode pada sisi-panjang 30 tapi itu sangat jarang sehingga tidak akan dapat meningkatkan keterbacaan sama sekali, jadi saya memadatkannya sedikit agar ukurannya lebih masuk akal):

masukkan deskripsi gambar di sini
Klik untuk versi yang lebih besar.

Warnanya persis sama terlepas dari beberapa detail yang sangat kecil, perintah non-kontrol-aliran juga persis sama. Jadi saya akan menjelaskan bagaimana ini bekerja berdasarkan versi yang tidak di-serigala, dan jika Anda benar-benar ingin tahu cara kerja golf, Anda dapat memeriksa bagian mana yang sesuai dengan yang ada di segi enam yang lebih besar. (Satu-satunya tangkapan adalah bahwa kode golf dimulai dengan cermin sehingga kode sebenarnya dimulai di sudut kanan ke kiri.)

Algoritma dasar hampir identik dengan jawaban CJam saya . Ada dua perbedaan:

  • Alih-alih memecahkan persamaan bilangan heksagonal terpusat, saya hanya menghitung angka heksagonal terpusat berturut-turut sampai satu sama dengan atau lebih besar dari panjang input. Ini karena Hexagony tidak memiliki cara sederhana untuk menghitung akar kuadrat.
  • Alih-alih melapisi input dengan no-ops segera, saya memeriksa nanti apakah saya sudah kehabisan perintah dalam input dan mencetak sebagai .gantinya jika saya punya.

Itu berarti ide dasar bermuara pada:

  • Baca dan simpan string input sambil menghitung panjangnya.
  • Temukan panjang sisi terkecil N(dan angka heksagonal tengah yang sesuai hex(N)) yang dapat menampung seluruh input.
  • Hitung diameternya 2N-1.
  • Untuk setiap baris, hitung indentasi dan jumlah sel (yang dijumlahkan 2N-1). Cetak indentasi, cetak sel (menggunakan .jika input sudah habis), cetak linefeed.

Perhatikan bahwa hanya ada no-ops sehingga kode aktual dimulai di sudut kiri ( $,, yang melompati >, jadi kita benar-benar mulai di ,dalam jalur abu-abu gelap).

Ini adalah kotak memori awal:

masukkan deskripsi gambar di sini

Jadi penunjuk memori dimulai pada input berlabel tepi , menunjuk Utara. ,membaca byte dari STDIN atau -1jika kita menekan EOF ke tepi itu. Oleh karena itu, <hak setelah adalah syarat untuk apakah kita sudah membaca semua input. Mari tetap di loop input untuk saat ini. Kode selanjutnya yang kita jalankan adalah

{&32'-

Ini menulis 32 ke dalam tepi berlabel ruang , dan kemudian menguranginya dari nilai input di tepi berlabel beda . Perhatikan bahwa ini tidak pernah dapat menjadi negatif karena kami dijamin bahwa input hanya berisi ASCII yang dapat dicetak. Ini akan menjadi nol ketika inputnya adalah spasi. (Seperti yang Timwi tunjukkan, ini akan tetap bekerja jika inputnya bisa berisi baris atau tab, tetapi juga akan menghapus semua karakter yang tidak patut lainnya dengan kode karakter kurang dari 32). Dalam hal ini, <defleksi penunjuk instruksi (IP) tersisa dan jalur abu-abu terang diambil. Jalur itu hanya menyetel ulang posisi MP dengan {=dan kemudian membaca karakter berikutnya - dengan demikian, spasi dilewati. Kalau tidak, jika karakter itu bukan spasi, kami mengeksekusi

=}}})&'+'+)=}

Ini langkah pertama sekitar segi enam melalui panjang tepi sampai kebalikannya yang diff tepi, dengan =}}}. Kemudian ia menyalin nilai dari berlawanan dengan tepi panjang ke tepi panjang , dan menambahkannya dengan )&'+'+). Kita akan melihat sebentar mengapa ini masuk akal. Akhirnya, kami memindahkan keunggulan baru dengan =}:

masukkan deskripsi gambar di sini

(Nilai tepi tertentu berasal dari test case terakhir yang diberikan dalam tantangan.) Pada titik ini, loop berulang, tetapi dengan semuanya bergeser satu hexagon timur laut. Jadi setelah membaca karakter lain, kita mendapatkan ini:

masukkan deskripsi gambar di sini

Sekarang Anda dapat melihat bahwa kami secara bertahap menulis input (spasi minus) di sepanjang diagonal timur laut, dengan karakter di setiap sisi lainnya, dan panjangnya hingga karakter tersebut disimpan sejajar dengan tepi berlabel panjang .

Ketika kita selesai dengan loop input, memori akan terlihat seperti ini (di mana saya sudah memberi label beberapa tepi baru untuk bagian selanjutnya):

masukkan deskripsi gambar di sini

Ini %adalah karakter terakhir yang kita baca, 29jumlah karakter non-spasi yang kita baca. Sekarang kita ingin menemukan panjang sisi segi enam. Pertama, ada beberapa kode inisialisasi linier di jalur hijau / abu-abu gelap:

=&''3{

Di sini, =&salin panjangnya (29 dalam contoh kami) ke tepi berlabel panjang . Kemudian ''3pindah ke tepi berlabel 3 dan tetapkan nilainya 3(yang kita perlukan sebagai konstanta dalam perhitungan). Akhirnya {pindah ke tepi berlabel N (N-1) .

Sekarang kita memasuki lingkaran biru. Peningkatan loop ini N(disimpan dalam sel berlabel N ) kemudian menghitung angka heksagonal terpusatnya dan mengurangkannya dari panjang input. Kode linear yang melakukan itu adalah:

{)')&({=*'*)'-

Di sini, {)bergerak ke dan bertahap N . ')&(pindah ke tepi berlabel N-1 , menyalin di Nsana dan menurunkannya. {=*menghitung produk mereka dalam N (N-1) . '*)mengalikannya dengan konstanta 3dan meningkatkan hasilnya di tepi berlabel hex (N) . Seperti yang diharapkan, ini adalah angka heksagonal terpusat ke-N. Akhirnya '-menghitung perbedaan antara itu dan panjang input. Jika hasilnya positif, panjang sisi belum cukup besar, dan loop berulang (di mana }}pindahkan MP kembali ke tepi berlabel N (N-1) ).

Setelah panjang sisi cukup besar, perbedaannya akan menjadi nol atau negatif dan kami mendapatkan ini:

masukkan deskripsi gambar di sini

Pertama, sekarang ada jalur hijau linier yang sangat panjang yang melakukan inisialisasi yang diperlukan untuk loop keluaran:

{=&}}}32'"2'=&'*){=&')&}}

The {=&dimulai dengan menyalin hasil dalam diff tepi ke dalam panjang tepi, karena kita kemudian membutuhkan sesuatu non-positif di sana. }}}32menulis 32 ke tepi berlabel ruang . '"2menulis konstanta 2 ke tepi unlabelled di atas diff . '=&salinan N-1ke tepi kedua dengan label yang sama. '*)mengalikannya dengan 2 dan menambahkannya sehingga kami mendapatkan nilai yang benar di tepi berlabel 2N-1 di bagian atas. Ini adalah diameter segi enam. {=&')&menyalin diameter ke tepi lainnya berlabel 2N-1 . Akhirnya }}bergerak kembali ke tepi berlabel 2N-1 di bagian atas.

Mari beri label ulang pada tepi-tepinya:

masukkan deskripsi gambar di sini

Tepi kita saat ini (yang masih memegang diameter segi enam) akan digunakan untuk beralih di atas garis output. Indentasi tepi berlabel akan menghitung berapa banyak ruang yang dibutuhkan pada baris saat ini. Tepi berlabel sel akan digunakan untuk beralih pada jumlah sel pada baris saat ini.

Kami sekarang berada di jalur merah muda yang menghitung lekukan . ('-mengurangi garis iterator dan menguranginya dari N-1 (ke tepi indentasi ). Cabang pendek biru / abu-abu dalam kode hanya menghitung modulus hasil ( ~meniadakan nilai jika negatif atau nol, dan tidak ada yang terjadi jika positif). Sisa dari jalur merah muda adalah "-~{yang mengurangi indentasi dari diameter ke tepi sel dan kemudian bergerak kembali ke tepi indent .

Jalan kuning kotor sekarang mencetak lekukan. Konten loop benar-benar adil

'";{}(

Di mana '"bergerak ke tepi ruang , ;mencetaknya, {}bergerak kembali ke indentasi dan (menurunkannya.

Ketika kita selesai dengan itu, jalur abu-abu gelap (kedua) mencari karakter berikutnya untuk dicetak. The =}bergerak dalam posisi (yang berarti, ke sel tepi, menunjuk Selatan). Kemudian kita memiliki loop {}yang sangat ketat yang hanya bergerak ke bawah dua sisi ke arah Barat Daya, sampai kita mencapai ujung string yang disimpan:

masukkan deskripsi gambar di sini

Perhatikan bahwa saya telah me-relabelled satu sisi EOF di sana ? . Setelah kami memproses karakter ini, kami akan membuat edge itu negatif, sehingga {}loop akan berakhir di sini alih-alih iterasi berikutnya:

masukkan deskripsi gambar di sini

Dalam kode, kita berada di ujung jalur abu-abu gelap, tempat 'bergerak mundur satu langkah ke karakter input. Jika situasinya adalah salah satu dari dua diagram terakhir (yaitu masih ada karakter dari input yang belum kami cetak), maka kami mengambil jalur hijau (yang paling bawah, untuk orang-orang yang tidak pandai dengan hijau dan biru). Yang itu cukup sederhana: ;mencetak karakter itu sendiri. 'pindah ke tepi ruang yang sesuai yang masih memegang 32 dari sebelumnya dan ;mencetak ruang itu. Lalu {~buat EOF kita ? negatif untuk iterasi berikutnya, 'bergerak mundur satu langkah sehingga kita dapat kembali ke ujung Utara-Barat string dengan }{loop ketat lain . Yang berakhir pada panjangsel (yang non-positif di bawah hex (N) . Akhirnya }bergerak kembali ke tepi sel .

Jika kita sudah kehabisan input, maka loop mana yang mencari EOF? akan benar-benar berakhir di sini:

masukkan deskripsi gambar di sini

Dalam hal ini 'bergerak ke sel panjang , dan kami mengambil jalur biru muda (atas), yang mencetak no-op. Kode di cabang ini linear:

{*46;{{;{{=

The {*46;menulis 46 ke tepi berlabel no-op dan mencetaknya (periode yaitu a). Kemudian {{;pindah ke tepi ruang dan cetak itu. The {{=bergerak kembali ke sel tepi untuk iterasi berikutnya.

Pada titik ini jalur bergabung kembali dan (mengurangi tepi sel . Jika iterator belum nol, kita akan mengambil jalur abu-abu terang, yang hanya membalik arah MP =dan kemudian mencari karakter berikutnya untuk dicetak.

Jika tidak, kami telah mencapai akhir dari baris saat ini, dan IP akan mengambil jalur ungu sebagai gantinya. Beginilah bentuk kotak memori pada saat itu:

masukkan deskripsi gambar di sini

Jalur ungu berisi ini:

=M8;~'"=

The =membalikkan arah MP lagi. M8set nilai set ke 778(karena kode karakter Mis 77dan digit akan menambahkan sendiri ke nilai saat ini). Ini kebetulan 10 (mod 256), jadi ketika kami mencetaknya ;, kami mendapat umpan baris. Kemudian ~buat tepi negatif lagi, '"bergerak kembali ke tepi garis dan =membalikkan MP sekali lagi.

Sekarang jika garis tepi nol, kita selesai. IP akan mengambil jalur merah (sangat pendek), tempat @menghentikan program. Kalau tidak, kita melanjutkan jalur ungu yang kembali ke jalur merah muda, untuk mencetak baris lain.


Diagram alir kontrol dibuat dengan HexagonyColorer Timwi . Diagram memori dibuat dengan debugger visual dalam IDE Esoteriknya .

Martin Ender
sumber
19
Saya menemukan diri saya mengatakan ini banyak pada jawaban hexagony: Hanya whoa.
Conor O'Brien
5
Hah ... tapi ... wat ... mind = blown
Adnan
Saya berharap seseorang akan melakukan ini dan ... Wow. Saya tidak dapat berkata-kata. Itu luar biasa.
Arcturus
19
Langkah dua - tulis 97% lainnya. :)
ASCIIThenANSI
Langkah tiga - sebagai jawaban dengan byte paling sedikit.
Tom M
19

CJam, 56 52 50 48 byte

Pikiran pertama saya adalah, "hei saya sudah punya kode untuk ini!" Tetapi kemudian saya tidak dapat diganggu untuk menarik potongan-potongan yang diperlukan dari kode Ruby, terutama karena mereka sepertinya tidak terlalu cocok untuk bermain golf. Jadi saya mencoba sesuatu yang lain di CJam sebagai gantinya ...

lS-{_,4*(3/mq:D1%}{'.+}wD{D(2/-z_S*D@-@/(S*N@s}/

Uji di sini.

Penjelasan

Sedikit matematika tentang angka heksagonal terpusat terlebih dahulu. Jika segi enam biasa memiliki panjang sisi N, maka akan berisi 3N(N-1)+1sel, yang harus sama dengan panjang kode sumber k. Kita dapat menyelesaikannya Nkarena persamaan kuadrat sederhana:

N = 1/2 ± √(1/4 + (k-1)/3)

Kita dapat mengabaikan akar negatif, karena itu memberi N. negatif. Untuk ini memiliki solusi, kita perlu akar kuadrat menjadi setengah bilangan bulat. Atau dengan kata lain, √(1 + 4(k-1)/3) = √((4k-1)/3)harus berupa bilangan bulat (untungnya, bilangan bulat ini kebetulan merupakan diameter D = 2N-1segi enam, yang bagaimanapun juga akan kita butuhkan). Jadi kita dapat berulang kali menambahkan satu .hingga kondisi itu terpenuhi.

Sisanya adalah loop sederhana yang menjabarkan segi enam. Pengamatan yang berguna untuk bagian ini adalah bahwa spasi di lekukan ditambah dengan non-spasi dalam kode di setiap baris bertambah hingga diameter.

lS-     e# Read input and remove spaces.
{       e# While the first block yields something truthy, evaluate the second...
  _,    e#   Duplicate the code and get its length k.
  4*(   e#   Compute 4k-1.
  3/    e#   Divide by 3.
  mq    e#   Take the square root.
  :D    e#   Store this in D, just in case we're done, because when we are, this happens
        e#   to be the diameter of the hexagon.
  1%    e#   Take modulo 1. This is 0 for integers, and non-zero for non-integers.
}{      e# ...
  '.+   e#   Append a no-op to the source code.
}w
D{      e# For every i from 0 to D-1...
  D(2/  e#   Compute (D-1)/2 = N, the side length.
  -z    e#   Subtract that from the current i and get its modulus. That's the size of the
        e#   indentation on this line.
  _S*   e#   Duplicate and get a string with that many spaces.
  D@-   e#   Subtract the other copy from D to get the number of characters of code
        e#   in the current line.
  @/    e#   Pull up the source code and split into chunks of this size.
  (S*   e#   Pull off the first chunk and riffle it with spaces.
  N     e#   Push a linefeed character.
  @s    e#   Pull up the remaining chunks and join them back into a single string.
}/

Ternyata kita tidak perlu menggunakan aritmatika ganda sama sekali (kecuali untuk akar kuadrat). Karena perkalian dengan 4, tidak ada tabrakan saat membaginya dengan 3, dan yang diinginkan kakan menjadi yang pertama menghasilkan akar kuadrat bilangan bulat.

Martin Ender
sumber
8

Perl, 203 200 198

termasuk +1 untuk -p

s/\s//g;{($l=y///c)>($h=1+3*++$n*($n-1))&&redo}$s=$_.'.'x($h-$l);for($a=$n;$a<($d=2*$n-1);$a++){$s=~s/.{$a}/$&\n/,$s=reverse($s)for 0..1}$_=join$/,map{(' 'x abs($n-$i++-1)).$_}$s=~/\S+/g;s/\S/ $&/g

jalankan sebagai: echo abc | perl -p file.pl

Pendekatan yang sangat naif:

#!/usr/bin/perl -p

s/\s//g;                            # ignore spaces and EOL etc.
{                                   # find the smallest hex number:
    ($l=y///c)                      # calc string length
    > ($h=1+3*++$n*($n-1))          # 
    && redo                         # (should use 'and', but..)
}

$s = $_                             # save $_ as it is used in the nested for
   . '.' x ($h-$l);                 # append dots to fill hexagon

for ( $a = $n; $a < ($d=2*$n-1); $a++ )
{
        $s=~s/.{$a}/$&\n/,          # split lines
        $s=reverse($s)              # mirror
    for 0..1                        # twice
}

$_ = join$/,                        # join using newline
map {                               # iterate the lines
    (' 'x abs($n-$i++-1)) .$_       # prepend padding
} $s=~/\S+/g;                       # match lines

s/\S/ $&/g                          # prepend spaces to characters
                                    # -p takes care of printing $_

  • perbarui 200 simpan satu byte tugas variabel bergerak, dan 2 lainnya dengan menghilangkan final ;; kode itu sendiri di bawah 200 byte sekarang!
  • perbarui 198 simpan 2 byte dengan menggunakan $s=~/\S+/galih-alihsplit/\n/,$s
Kenney
sumber
7

JavaScript (ES6), 162 172

Fungsi anonim

Ukuran segi enam ditemukan menyelesaikan persamaan dari wikipedia

3*n*(n-1)-1 = l

Rumus pemecahannya pada dasarnya

n = ceil(3+sqrt(12*l-3))/6)

Dengan beberapa aljabar dan beberapa perkiraan (thx to @ user18655 juga) menjadi

n = trunc(sqrt(l/3-1/12)+1.4999....)
s=>eval("s=s.match(/\\S/g);m=n=Math.sqrt(s.length/3-1/12)+1.49999|0;p=o=``;for(i=n+n;--i;i>n?++m:--m)for(o+=`\n`+` `.repeat(n+n-m),j=m;j--;o+=` `)o+=s[p++]||`.`")

Lebih mudah dibaca

s=>{
  s=s.match(/\S/g);
  m=n=Math.sqrt(s.length/3-1/12)+1.49999;
  p=o='';
  for(i=n+n; --i; i>n?++m:--m)
    for(o += '\n'+' '.repeat(n+n-m), j=m; j--; o += ' ')
      o+=s[p++]||'.';
  return o
}

Cuplikan uji (halaman penuh lebih baik - waktu berjalan ~ 1 menit)

f=s=>eval("s=s.match(/\\S/g);m=n=Math.sqrt(s.length/3-1/12)+1.49999|0;p=o=``;for(i=n+n;--i;i>n?++m:--m)for(o+=`\n`+` `.repeat(n+n-m),j=m;j--;o+=` `)o+=s[p++]||`.`")

t=0;
r='0';
(T=_=>t++<816?(O.innerHTML=f(r=t%10+r),setTimeout(T,20)):0)()
pre { font-size: 66% }
<pre id=O></pre>

edc65
sumber
1
Anda bisa menggunakan n=...+1-1e-9|0alih-alih n=Math.ceil(...)menyimpan 2 byte. Anda juga bisa pergi ES7 dan menggunakan **0.5bukannya Math.sqrttapi itu terserah Anda. Saya biasanya hanya menyimpan jawaban saya ES6 karena mereka berfungsi di browser saya haha!
user81655
@ user81655 petunjuk yang baik, terima kasih
edc65
5

Pyth, 52 51 byte

Jfgh**3TtTl=H-zd1=+H*\.*lHTV+UJt_UJAcH]+JN+*-JNdjdG

Cobalah online. Suite uji.

Setiap baris memiliki satu ruang pemimpin tambahan, sebagaimana diizinkan oleh OP.

Penjelasan

 f              1          |   find first number n for which
             -zd           |           remove spaces from input
           =H              |         put result in H
          l                |       length of input without spaces
  g                        |     is less than or equal to
   h**3TtT                 |       nth centered hexagonal number
J                          | put result (hexagon side length) in J
                           |
      *lHT                 |      ten times length of input without spaces
   *\.                     |   that amount of dots
=+H                        | append to H
                           |
  UJ                       |    numbers 0 up to side length - 1
 +  t_UJ                   |   add numbers side length - 2 down to 0
V                          | loop over result
            +JN            |       current loop number + side length
         cH]               |     split to two parts at that position
        A                  |   put parts to G and H
                 -JN       |       side length - current loop number - 1
                *   d      |     that many spaces
                     jdG   |     join code on the line (G) by spaces
               +           |   concatenate parts and print
PurkkaKoodari
sumber
5

Retina , 161 byte

Terima kasih kepada FryAmTheEggman karena telah menghemat 2 byte.

Jawaban ini tidak bersaing. Retina telah melihat beberapa pembaruan sejak tantangan ini, dan saya cukup yakin saya menggunakan beberapa fitur yang lebih baru (walaupun saya belum memeriksa).

Hitungan byte mengasumsikan penyandian ISO 8859-1. Baris pertama berisi satu ruang. Perhatikan bahwa sebagian besar ·sebenarnya adalah titik tengah (0xB7).

 

^
$._$*·¶
^·¶
¶
((^·|\2·)*)·\1{5}·+
$2·
^·*
$.&$* ·$&$&$.&$* 
M!&m`(?<=(?= *(·)+)^.*)(?<-1>.)+(?(1)!)|^.+$
+m`^( *·+)· *¶(?=\1)
$& 
·
 ·
O$`(·)|\S
$1
·
.
G-2`

Cobalah online!

Baik...

Penjelasan

Tampaknya paling mudah untuk membangun tata letak terlebih dahulu menggunakan hanya satu karakter ( ·dalam hal ini) dan kemudian mengisi tata letak yang dihasilkan dengan karakter input. Alasan utama untuk ini adalah bahwa menggunakan satu karakter memungkinkan saya memanfaatkan referensi-ulang dan pengulangan karakter, di mana meletakkan input secara langsung akan membutuhkan kelompok penyeimbang yang mahal.

 

Meskipun tidak terlihat banyak, tahap pertama ini menghilangkan spasi dari input.

^
$._$*·¶

Kita mulai dengan menambahkan baris tambahan yang berisi Mtitik-titik tengah, di mana Mpanjang input (setelah menghilangkan spasi).

^·¶
¶

Jika input adalah satu karakter, kami menghapus titik tengah itu lagi. Ini adalah kasus khusus yang tidak menguntungkan yang tidak dicakup oleh tahap selanjutnya.

((^·|\2·)*)·\1{5}·+
$2·

Ini menghitung panjang sisi yang dibutuhkan Nminus 1. Berikut ini cara kerjanya: bilangan heksagonal tengah berbentuk 3*N*(N-1) + 1. Karena bilangan segitiga adalah N*(N-1)/2, itu berarti bilangan heksagonal adalah enam kali angka segitiga ditambah 1. Itu nyaman karena mencocokkan angka segitiga (yang benar-benar adil 1 + 2 + 3 + ... + N) dalam sebuah regex cukup mudah dengan referensi ke depan. Yang (^·|\2·)*cocok dengan angka segitiga terbesar yang dimilikinya. Sebagai bonus yang bagus, $2maka akan memegang indeks nomor segitiga ini. Untuk mengalikannya dengan 6, kami menangkapnya menjadi grup 1dan mencocokkannya 5 kali lagi. Kami memastikan setidaknya ada dua lagi ·dengan ·dan·+. Dengan cara ini indeks bilangan segitiga yang ditemukan tidak meningkat sampai ada satu karakter lebih dari bilangan heksagonal terpusat.

Pada akhirnya, pertandingan ini memberi kita dua kurang dari panjang sisi segi enam yang diperlukan dalam grup $2, jadi kami menulisnya kembali bersama dengan satu lagi titik pusat untuk mendapatkan N-1.

^·*
$.&$* ·$&$&$.&$* 

Ini mengubah string N-1titik pusat kami menjadi N-1ruang, 2N-1titik pusat , dan N-1ruang lain . Perhatikan bahwa ini adalah lekukan maksimum, diikuti oleh diameter segi enam, diikuti oleh lekukan lagi.

M!&m`(?<=(?= *(·)+)^.*)(?<-1>.)+(?(1)!)|^.+$

Ini panjang tidak menyenangkan, tetapi pada dasarnya hanya memberi kita semua pertandingan yang tumpang tindih , yang 2N-1panjangnya a) karakter dan pada baris pertama atau b) baris kedua. Ini memperluas hasil dari tahap sebelumnya ke segi enam penuh, tapi aneh. Misalnya untuk input, 12345678kita akan mendapatkan:

  ···
 ····
·····
···· 
···  
12345678

Ini sebabnya kami perlu menambahkan spasi di tahap sebelumnya juga.

+m`^( *·+)· *¶(?=\1)
$& 

Ini memperbaiki lekukan garis setelah pusat, dengan berulang kali indentasi setiap garis yang lebih pendek dari sebelumnya (mengabaikan ruang trailing), jadi kami mendapatkan ini:

  ···
 ····
·····
 ···· 
  ···  
12345678

Sekarang kita cukup menyisipkan beberapa spasi

·
 ·

Yang memberi kita:

   · · ·
  · · · ·
 · · · · ·
  · · · · 
   · · ·  
12345678

Fiuh, sudah selesai.

O$`(·)|\S
$1

Saatnya mengisi string input ke titik-titik tengah. Ini dilakukan dengan bantuan semacam tahapan. Kami mencocokkan semua titik pusat dan setiap karakter pada baris terakhir, dan kami mengurutkannya berdasarkan hasil substitusi yang diberikan. Substitusi itu kosong untuk karakter pada baris terakhir dan ·untuk titik tengah, jadi yang terjadi adalah titik tengah hanya diurutkan hingga akhir (karena pengurutan stabil). Ini memindahkan karakter input ke tempatnya:

   1 2 3
  4 5 6 7
 8 · · · ·
  · · · · 
   · · ·  
········

Tinggal dua hal yang tersisa sekarang:

·
.

Ini mengubah titik pusat menjadi periode reguler.

G-2`

Dan ini membuang baris terakhir.

Martin Ender
sumber
1

JavaScript (ES6), 144 byte

(s,n=1,l=0,p=0,m=s.match(/\S/g))=>m[n]?f(s,n+6*++l,l):[...Array(l+l+1)].map((_,i,a)=>a.map((_,j)=>j<l-i|j<i-l?``:m[p++]||`.`).join` `).join`\n`

Dimana \nmewakili karakter baris baru literal. Menggunakan teknik untuk membuat hexagon yang sebelumnya saya gunakan pada beberapa jawaban lainnya . Untuk ES7 mengambil akar kuadrat berhasil sedikit lebih pendek daripada pendekatan rekursif:

(s,p=0,m=s.match(/\S/g),l=(~-m.length/3)**.5+.5|0)=>[...Array(l+l+1)].map((_,i,a)=>a.map((_,j)=>j<l-i|j<i-l?``:m[p++]||`.`).join` `).join`\n`
Neil
sumber
1

Python 3 , 144 byte

c=input().replace(' ','')
n=x=1
while x<len(c):x+=n*6;n+=1
c=c.ljust(x,'.')
while c:print(' '*(x-n)+' '.join(c[:n]));c=c[n:];n-=(len(c)<x/2)*2-1

Cobalah online!

Ini menggunakan jumlah spasi spasial yang agak bervariasi untuk ukuran segi enam yang berbeda, tetapi bentuk umum tetap bertahan.

Jo King
sumber