Lihat mereka jatuh seperti kartu domino

22

Anda tinggal di dalam terminal yang lebar 80 karakter. Anda bosan, jadi Anda memutuskan untuk bermain kartu domino. Tidak, bukan jenis membosankan yang terlihat seperti Scrabble, jenis kesenangan di mana Anda menghabiskan waktu satu jam mengatur mereka untuk menonton mereka jatuh dalam sedetik.

Di terminal, domino terlihat seperti ini:

|   upright domino
\   left-tilted domino
/   right-tilted domino
__  fallen domino

Seperti kita ketahui, jika domino miring menyentuh yang tegak, domino kedua juga dimiringkan. Satu-satunya pengecualian untuk ini adalah jika dua domino miring menyentuhnya:

|\ --> \\        /| --> //        /|\ --> /|\

Sesuaikan konstanta gravitasi terminal Anda sehingga transisi ini membutuhkan 100 ms.

Jika domino miring dimiringkan oleh domino lain atau dinding terminal, perjalanannya berakhir.

Tidak ada domino miring di

\||||____||||/__                /|\    /\    /|\                __\||||____||||/

(80 karakter) akan bergerak, karena dua kartu domino miring paling luar didukung oleh dinding terminal dan semua yang lain didukung oleh kartu domino lainnya.

Namun, jika ruang dalam arah miring kosong, domino jatuh:

| \\ --> |__\        // | --> /__|

Terminal. Konstanta gravitasi. Anda mengerti maksudnya ...

Akhirnya, ada angin sepoi-sepoi dari kiri, jadi domino miring kanan jatuh lebih cepat daripada yang miring kiri:

|/ \| --> |__\|

Tugas

Tulis program / fungsi yang menunjukkan animasi bermain domino di terminal.

Kode Anda harus melakukan hal berikut:

  1. Baca string dari input, yang mewakili keadaan awal domino.

    String ini akan berisi tidak lebih dari 80 karakter dan hanya terdiri dari domino yang dijelaskan di atas dan ruang kosong.

  2. Cetak status dan tunggu 100 ms.

  3. Ubah status seperti dijelaskan di atas.

  4. Jika status berubah, kembali ke 2.

Aturan tambahan

  • Panjang string input tidak mempengaruhi lebar terminal; bahkan jika string lebih pendek dari 80 karakter, dinding terminal masih terpisah 80 karakter.

  • Setiap kali langkah 2 dijalankan, negara harus dicetak ke lokasi yang sama, menimpa negara sebelumnya.

  • Karena beberapa bahasa tidak mampu menunggu tepat 100 ms, jangan ragu untuk menunggu jumlah antara 50 dan 1000 ms.

  • Aturan standar berlaku.

Contohnya

  • Untuk kondisi awal

     ||\/||
    

    cetak yang berikut ini (satu di atas yang lain):

     ||\/||
     |\\//|
     \\\///
    __\\//__
    
  • Untuk kondisi awal

    /||||\
    

    cetak yang berikut ini

    /||||\
    //||\\
    ///\\\
    
  • Untuk kondisi awal

    /|||\
    

    cetak yang berikut ini

    /|||\
    //|\\
    
  • Untuk kondisi awal

    |/ \|/ \|/ \|/ \|
    

    cetak yang berikut ini:

    |__\|__\|__\|__\|
    
  • Untuk keadaan awal (80 karakter)

    \||||____||||/__                /|\    /\    /|\                __\||||____||||/
    

    cetak yang berikut ini

    \||||____||||/__                /|\    /\    /|\                __\||||____||||/
    
Dennis
sumber

Jawaban:

13

Retina , 87 86 85 byte

Terima kasih kepada Dennis untuk menghemat 1 byte.

^.{0,79}$
$0 
:`^
<ESC>c
(`/ | \\
__
/\|(?!\\)
//a
(?<!/)\|\\
\\
$
aaaaa
a
aaaa
(a+)+b|a
<empty>

<ESC>harus diganti dengan karakter kontrol aktual (0x1B). <empty>mewakili garis trailing kosong. Anda kemudian dapat menjalankan kode di atas dari satu file dengan -sbendera.

Kode membutuhkan terminal yang mendukung kode pelarian ANSI. Saya tidak bisa menekan umpan baris dalam output Retina jadi saya harus menghapus seluruh konsol <ESC>csetiap kali. Saya telah menguji kode dalam bash menggunakan Mono untuk menjalankan Retina.

Penjelasan

^.{0,79}$
$0 

Kami mulai dengan menambahkan spasi jika input berisi kurang dari 80 karakter. Ini agar a /di ujung kanan tidak harus diperlakukan secara terpisah.

:`^
<ESC>c

Sekarang kita menambahkan <ESC>cstring, yang merupakan kode pelarian ANSI untuk membersihkan terminal. Jadi setiap kali string dicetak akan melakukannya di bagian atas terminal. The :`menginstruksikan Retina untuk mencetak hasil substitusi ini, yaitu konfigurasi awal.

(`/ | \\
__

(`memulai satu putaran. Karena tidak ada yang cocok ), loop diasumsikan pergi sampai tahap terakhir dari program. Setiap iterasi akan mensimulasikan satu langkah domino jatuh dan kemudian "tidur" sedikit. Tahap pertama ini menggantikan /dan di \sebelah spasi menjadi __. Ini secara otomatis menangani kasing dengan / \benar, karena kecocokan tidak dapat tumpang tindih dan dicari dari kiri ke kanan. Jadi /<sp>akan dicocokkan dan diubah menjadi __sedemikian sehingga \tidak dapat dicocokkan, dan kami mendapatkan yang benar __\.

/\|(?!\\)
//a

Ini berubah /|menjadi //asalkan tidak ada di \sebelahnya. Kami menambahkan asedemikian rupa sehingga yang baru /ini tidak mengacaukan dengan tahap berikutnya (yang seharusnya belum "tahu" tentang perubahan ini).

(?<!/)\|\\
\\

Situasi sebaliknya: berubah |\menjadi \\asalkan tidak ada di /sebelahnya. Kita tidak perlu meletakkan di asini, karena kita sudah selesai dengan langkah simulasi ini.

Sekarang bagian tidur ...

$
aaaaa

Tambahkan 5 lagi ake akhir kode.

a
aaaa

Mengubah masing a- masing menjadi 4 adetik, jadi kami mendapatkan 20 adetik di akhir.

(a+)+b|a
<empty>

Sekarang bagian yang menyenangkan ... kita tidur sebentar dengan bantuan backtracking bencana . Ada sejumlah cara eksponensial untuk membagi kecocokan (a+)+antara pengulangan grup. Karena bpenyebab kecocokan gagal, mesin akan mundur dan mencoba setiap kombinasi sebelum memutuskan yang (a+)+btidak cocok. Untuk dua puluh adetik di akhir yang membutuhkan sekitar setengah detik.

Pada saat yang sama, kami mengizinkan regex untuk mencocokkan satu a, tetapi hanya setelah melakukan backtracking. Ketika itu cocok, kami menggantinya dengan string kosong, menghapus semua yang akami masukkan karena satu atau lain alasan dari string.

Yang meninggalkan mencetak string di akhir perulangan loop. Ini dia berguna bahwa saya belum memperbaiki perilaku pencetakan loop di Retina. Saat ini, hanya ada satu bendera untuk setiap tahap, yang mengatakan "cetak" atau "jangan cetak". Standarnya adalah "jangan cetak" kecuali untuk tahap terakhir dalam program, yang secara default adalah "cetak". Tapi stage diulang, jadi itu berarti benar-benar mencetak string saat ini pada setiap iterasi. Biasanya, itu benar-benar menjengkelkan, dan Anda hampir selalu perlu menyertakan tahap kosong tambahan di akhir jika Anda hanya menginginkan hasil akhir, tetapi di sini memungkinkan saya menghemat empat byte.

Martin Ender
sumber
6

Javascript (ES6), 206 148 129 158 byte

Akhirnya saya menurunkannya ke titik rendah, tetapi tidak menghapus konsol atau menambahkan ruang ekstra; masalah ini telah diperbaiki sekarang.

c=console;d=s=>{c.clear(s[79]||(s+=' ')),c.log(s),t=s[R='replace'](/\/ | \\/g,'__')[R](/\/\|/g,'//a')[R](/\|\\/g,'\\\\')[R](/a/g,'');t!=s&&setTimeout(d,99,t)}

Alternatif versi 153 byte yang seharusnya berfungsi di Node.JS:

d=s=>{s[79]||(s+=' '),console.log("\033c"+s),t=s[R='replace'](/\/ | \\/g,'__')[R](/\/\|/g,'//a')[R](/\|\\/g,'\\\\')[R](/a/g,'');t!=s&&setTimeout(d,99,t)}

IMHO, ini cukup menyenangkan untuk dimainkan. Coba versi HTML di sini:

Mungkin ada lebih banyak ruang untuk bermain golf. Saran diterima!

Produksi ETH
sumber
+1 untuk demo runnable yang menghabiskan 10 menit waktu saya, dan +1 untuk fungsi pengacak. Namun, seperti yang disebutkan Dennis, gagal untuk test case pertama. Coba /atau /|dan Anda akan melihat ubin tidak jatuh sepanjang jalan sebagaimana mestinya.
dberm22
@ Dennis Terima kasih telah menunjukkan masalah ini. Saya yakin saya sudah memperbaiki keduanya sekarang.
ETHproduksi
Node tidak senang dengan panah gemuk, tetapi jika tidak berhasil, Anda dapat mengganti \033dengan byte ESC literal, menghemat 3 byte.
Dennis
2

Perl 5, 154 146

Harus menggunakan karakter sementara untuk mempertahankan negara antara 2 regex.
Untuk menghadapi risiko sesuatu seperti / | | | \ akan berakhir sebagai / / / \ \ daripada / / | \ \.

$_=substr(pop.' ',0,80);$|++;while($}ne$_){print"$_\r";$}=$_;s@ \\|/ @__@g;s@/\|(?=[^\\])@/F@g;s@([^/])\|\\@$1\\\\@g;tr@F@/@;select($\,$\,$\,0.1)}

Uji

$ perl dominos.pl '|\ |\/|||\/|'
|\__\//|\\/__
LukStorms
sumber
1
Anda dapat menghilangkan beberapa garis miring terbalik jika Anda menggunakan pembatas selain garis miring - misalnya s, \\|/ ,__,gbukan s/ \\|\/ /__/g.
hobbs
Tip yang bagus. Lupa trik itu. Dan beberapa byte tambahan dipotong dengan menggunakan set yang dinegasikan.
LukStorms
2

ES6 , 220 218 195 byte

Diperkecil

f=d=>{var e,c=console;if(!d[79])d+=' ';c.clear();c.log(d);e=d;d=d[R='replace'](/\/\|\\/g,'a')[R](/\/ | \\/g,'__')[R](/\/\|/g,'//')[R](/\|\\/g,'\\\\')[R]('a','/|\\');if(e!=d)setTimeout(f,100,d);};

Lebih mudah dibaca

f=d=> {
    var e,
    c=console;
    if(!d[79])
        d+=' ';
    c.clear();
    c.log(d);
    e=d;
    d = d[R='replace'](/\/\|\\/g, 'a')  //Substitute '/|\' with 'a' so it doesn't get replaced
        [R](/\/ |  \\/g, '__')     //Replace '/ ' and ' \' with '__'
        [R](/\/\|/g, '//')    //Replace '/|' with '//'
        [R](/\|\\/g, '\\\\')  //Replace '|\' with '\\'
        [R]('a', '/|\\');     //Put '/|\' back
    if(e!=d)
        setTimeout(f,100,d);
};
pengguna3000806
sumber
2
Selamat Datang di Programming Puzzles & Code Golf! 1. Saya tidak yakin mengapa Anda menggunakan notasi ES6. () = > {dan }()dapat dengan mudah dihapus dari kode Anda. 2. Saya tidak berpikir kotak peringatan adalah format output yang dapat diterima untuk animasi. Anda bisa menyematkan JS Anda dalam HTML atau membuat perubahan yang diperlukan sehingga akan bekerja dari baris perintah. 3. Dalam kedua kasus, kode Anda harus menunggu sekitar. 100 ms antara mencetak satu negara dan berikutnya.
Dennis
2
Selamat datang di PPCG! Saya sarankan memeriksa posting ini dan posting ini untuk membantu meningkatkan golf Anda.
jrich
Terima kasih atas saran dan tautan ke tips golf. Ini masih agak panjang, tapi saya mempersingkatnya dan menambahkan timer. Saya akan membahas tips lebih mendalam dan melihat apa yang bisa saya persingkat.
user3000806
1
Itu seharusnya bekerja di terminal sekarang, tetapi masih tidak akan mencetak status yang diperbarui dari yang lama. Di Linux, Anda dapat memperbaikinya dengan memanggil console.log("^[c"+d)saja, di mana ^[karakter ESC (satu byte).
Dennis
1
Jika Anda mengubah yang pertama .replaceke [R='replace'], lalu setiap yang berikutnya menjadi [R], ini akan mengurangi sedikit. Anda juga dapat menyimpan beberapa byte dengan menggunakan setTimeout(f,100,d)tempat pengaturan saat ini.
ETHproduksi
2

C #, 335 byte

Bukan pilihan bahasa yang bagus.

Saya menyalahgunakan penundaan yang diizinkan antara 50 dan 1000 untuk memilih nomor dua digit.

Baris dan lekukan baru ditambahkan untuk kejelasan:

namespace System.Threading{
    class P{
        static void Main(string[]z){
            var c=@"/|\,/|\,/|,//,|\,\\,/ ,__, \,__".Split(',');
            for(string a=z[0].PadRight(80),b="";a!=b;){
                Console.Clear();
                Console.Write(b=a);
                Thread.Sleep(99);
                a="";
                for(int i,j;(i=a.Length)<80;)
                    a+=(j=Array.FindIndex(c,d=>b.Substring(i).StartsWith(d)))%2==0
                        ?c[j+1]
                        :b.Substring(i,1);
            }
        }
    }
}
Makanan Tangan
sumber
1

PHP, 175 byte

$i=sprintf("%-80s",$argv[1]);$p='preg_replace';do{echo($o=$i)."\r";$i=$p('(/\|\\\\(*SKIP)(?!)|(?|(/)\||\|(\\\\)))','$1$1',$p('(/ | \\\\)','__',$i));usleep(1e5);}while($i!=$o);

Tidak dicincang:

$input = sprintf("%-80s",$argv[1]);
do {
  echo $input."\r";
  $old = $input;
  $input = preg_replace('(/ | \\\\)','__',$input);
  $input = preg_replace('(/\|\\\\(*SKIP)(?!)|(?|(/)\||\|(\\\\)))','$1$1',$input);
  usleep(100000);
}
while( $input != $old);

Pada dasarnya golf regex. Pertama ratakan setiap domino yang jatuh yang memiliki ruang (dan karena urutan yang cocok dari kiri ke kanan, "angin" berhembus). Lalu datanglah bagian yang jelek (kutukan kamu tebas!)

  • Cocokkan /|\, lalu lewati.
  • Cocokkan (/)|dan ganti dengan//
  • Cocokkan |(\)dan ganti dengan\\

Ini membuat domino jatuh. Akhirnya, tunggu saja 100 ms untuk langkah selanjutnya.

Menggunakan ()sebagai pembatas pada regex berarti /s tidak perlu melarikan diri, yang membantu minimal!

Niet the Dark Absol
sumber
Anda diizinkan untuk menunggu 50 ms alih-alih 100, menghemat 1 char;) Apakah PHP mengizinkan 10 ^ 5?
BlueCacti
1

POSIX shell + sed, 144

sed 's/^.\{1,79\}$/& /;s/.*/printf '"'&\\r'"';sleep .1/;h;:;s,/|\\,/:\\,g;s,\(/ \| \\\),__,g;s,/|,//,g;s,|\\,\\\\,g;H;t;x;y/:/|/;s/\\/\\\\/g'|sh

Ini ada dua bagian. Pekerjaan utama menggulingkan domino adalah sedpenggantian pola standar , mengumpulkan garis ke ruang penahanan. Kami sementara berubah /|\menjadi /:\untuk melindunginya, pulih pada akhirnya.

s/^.\{0,79\}$/& /
h

:
s,/|\\,/:\\,g
s,\(/ \| \\\),__,g
s,/|,//,g
s,|\\,\\\\,g
H
t

x
y/:/|/

Karena sedtidak ada cara memasukkan penundaan (saya melihat ke terminfo / termcap, tetapi tidak dapat menemukan cara standar), saya membungkus setiap baris printf "...\r"; sleep .1 untuk mencetak baris setiap 100ms. Saya benar-benar melakukan ini terlebih dahulu, ketika kita hanya memiliki satu baris, karena karakter dalam perintah tidak akan tersentuh oleh salah satu pengganti dari menjatuhkan.

Semua diuji menggunakan dashdan GNU coreutils, dengan POSIXLY_CORRECTpengaturan di lingkungan.

Toby Speight
sumber