Domino gibi düştüğünü izle


22

80 karakter genişliğinde bir terminalin içinde yaşıyorsun. Sıkıldın, domino oynamaya karar verdin. Hayır, Scrabble'a benzeyen sıkıcı tür değil, bir saat içinde onları bir saniyede düşmelerini izleyeceğiniz eğlenceli tür.

Terminallerde, domino şunun gibi görünüyor:

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

Hepimizin bildiği gibi, eğer eğik bir domino dik bir dokunuşa dokunursa, ikinci domino da eğilir. Bunun tek istisnası iki eğik domino ona dokunmasıdır:

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

Terminalinizin çekim sabitini ayarlayın, böylece bu geçiş 100 ms sürer.

Eğik bir domino başka bir domino veya terminalin duvarları tarafından destekleniyorsa, yolculuğu sona erer.

İçerisindeki eğik dominoların hiçbiri

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

(80 karakter) hareket edecektir, çünkü en dışa eğilmiş iki domino terminalin duvarları tarafından desteklenir ve diğerleri de diğer dominolar tarafından desteklenir.

Ancak, eğer yatırma yönündeki alan boşsa, domino yere düşer:

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

Terminal. Yerçekimi sabiti. Sen anladın…

Sonunda, soldan hafif bir rüzgâr var, bu yüzden sağ yatırılmış dominolar sol yatırılmış olanlardan daha hızlı düşüyor:

|/ \| --> |__\|

Görev

Bir terminalde domino çalma animasyonunu gösteren bir program / işlev yazın.

Kodunuz aşağıdakileri yapmalıdır:

  1. Dominoların başlangıç ​​durumunu gösteren girdiden bir dize okuyun.

    Bu dize en fazla 80 karakter içerecek ve yalnızca yukarıda tanımlanan dominolardan ve boş alanlardan oluşacaktır.

  2. Durumu yazdırın ve 100 ms bekleyin.

  3. Devleti yukarıda açıklandığı gibi dönüştürün.

  4. Durum değiştiyse, 2'ye geri dönün.

Ek kurallar

  • Giriş dizesinin uzunluğu terminalin genişliğini etkilemez; Dize 80 karakterden kısa olsa bile, terminalin duvarları hala 80 karakterdir.

  • 2. adım her yürütüldüğünde, durum önceki konuma yazılarak aynı konuma yazdırılmalıdır.

  • Bazı diller tam olarak 100 ms beklemekte olmadığından, 50 ile 1000 ms arasında herhangi bir miktarda beklemekten çekinmeyin.

  • Standart kuralları geçerlidir.

Örnekler

  • İlk durum için

     ||\/||
    

    aşağıdakileri yazdırın (biri diğerine):

     ||\/||
     |\\//|
     \\\///
    __\\//__
    
  • İlk durum için

    /||||\
    

    aşağıdakileri yazdır

    /||||\
    //||\\
    ///\\\
    
  • İlk durum için

    /|||\
    

    aşağıdakileri yazdır

    /|||\
    //|\\
    
  • İlk durum için

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

    aşağıdakileri yazdırın:

    |__\|__\|__\|__\|
    
  • İlk durum için (80 karakter)

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

    aşağıdakileri yazdır

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

Yanıtlar:


13

Retina , 87 86 85 bayt

1 byte tasarruf için Dennis teşekkürler.

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

<ESC>gerçek kontrol karakteri (0x1B) ile değiştirilmelidir. <empty>boş bir takip çizgisini temsil eder. Daha sonra yukarıdaki kodu -sbayraklı tek bir dosyadan çalıştırabilirsiniz .

Kod ANSI çıkış kodlarını destekleyen bir terminal gerektirir. Retina'nın çıkışındaki satır beslemesini bastıramıyorum bu yüzden <ESC>cher seferinde tüm konsolu silmem gerekiyor . Kodu, Retina'yı çalıştırmak için Mono kullanarak bash'te test ettim.

açıklama

^.{0,79}$
$0 

Girdi 80'den az karakter içeriyorsa boşluk ekleyerek başlarız. Bu, /sağ taraftaki ucun ayrı olarak ele alınması gerekmediğinden öyledir .

:`^
<ESC>c

Şimdi <ESC>c, terminali temizlemek için kullanılan ANSI çıkış kodunu taşıyan dizgeyi hazırladık. Dize her basıldığında terminalin tepesinde gerçekleşir. :`Örneğin, ilk yapılandırma Bu ikamenin sonucu yazdırmak Retina talimatını verir.

(`/ | \\
__

(`bir döngü başlar. Eşleşme olmadığı )için programın son aşamasına kadar döngünün olduğu varsayılır. Her bir yineleme, düşen dominoların bir basamağını simüle edecek ve ardından biraz "uyuyacak". Bu aşama yerine geçer birinci /ve \içine bir boşluk yanında __. Bu / \durum , davayı otomatik olarak doğru şekilde işler , çünkü eşleşmeler üst üste gelemez ve soldan sağa doğru aranır. Yani /<sp>eşleşti ve açık içine olacağını __şekilde \uyumlu olamaz ve biz doğru olsun __\.

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

Bu dönüşler /|içine //sağlanan hiçbir orada \onun yanında. Biz bir ekleme abu yeni şekilde /(henüz bu değişiklikle ilgili "bilmek" gerekir) bir sonraki aşamaya ile karışıklık yok.

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

Tersi durum: dönüş |\içine \\sağlanan hiçbir orada /yanında. Koymak zorunda değiliza , çünkü simülasyonun bu aşamasını bitirdik.

Şimdi uyuyan kısım ...

$
aaaaa

aKodun sonuna 5 saniye daha ekler .

a
aaaa

Her abirini 4 asaniyeye çıkarır , bu yüzden asonunda 20 sn alırız .

(a+)+b|a
<empty>

Şimdi eğlenceli olan kısım ... feci geri dönüşün yardımı ile biraz uyuduk . (a+)+Grubun tekrarları arasında bir eşleşmeyi bölmenin ılımlı bir yolu vardır . Eşleşmenin bbaşarısız olmasına neden olduğu için, motor (a+)+beşleşmeyeceğine karar vermeden önce bu kombinasyonların her birini izler ve dener . Yirmi içinaSonunda saniye için bu yarım saniye gibi bir şey alır.

Aynı zamanda, regex'in bir taneyle eşleşmesine izin veriyoruz a, ancak yalnızca geri izlemeyi yaptıktan sonra . Bu eşleştiğinde, boş bir dizeyle değiştiririz, abir nedenden veya diğerinden dizgiden eklediğimiz bütünleri sileriz.

Bu, döngü yinelemenin sonunda dize yazdırmayı bırakır. Burada, henüz retinadaki ilmeklerin baskı davranışını düzelttiğim kullanışlı bir özellik. Şu anda, her aşama için "yazdır" veya "yazdırmıyor" yazan tek bir bayrak var. Varsayılan ayar, varsayılan olarak "yazdırmak" olan programın son aşaması dışında "yazdırma" dır. Fakat sahne alanı ilmeklidir, yani aslında her dize için geçerli dizeyi basar. Normalde, bu gerçekten can sıkıcı bir durum ve sonuçta sadece son sonucu istiyorsanız sonda ek bir boş aşama eklemeniz gerekiyor, ancak burada dört bayttan tasarruf etmeme izin veriyor.


6

Javascript (ES6), 206 148 129 158 bayt

Sonunda onu oldukça alçak bir noktaya indirdim, ancak konsolu temizlemeyecek ya da fazladan bir boşluk ekleyemeyecekti; bu sorunlar şimdi düzeltildi.

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)}

Node.JS'de çalışması gereken alternatif 153 bayt sürümü:

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, oynamak oldukça eğlenceli. Burada bir HTML sürümünü deneyin:

Golf için muhtemelen biraz daha fazla yer var. Önerilerinizi bekliyoruz!


Zamanımın 10 dakikasını boşa harcayan koşulabilir demo için +1 ve randomizer işlevi için +1. Ancak, Dennis'in dediği gibi, ilk sınavda başarısız olur. Deneyin /ya /|da göreceksiniz ki kiremit olması gerektiği gibi düşmüyor.
dberm22

@Dennis Bu sorunları belirttiğiniz için teşekkür ederiz. Şimdi ikisini de düzelttiğime inanıyorum.
ETHProductions

Düğüm, şişman oktan memnun değil, ama aksi takdirde iyi çalışıyor. \033Bir değişmez ESC baytı ile değiştirerek 3 bayttan tasarruf edebilirsiniz.
Dennis,

2

Perl 5, 154 146

2 regex arasında durumu korumak için geçici bir karakter kullanmak zorunda kaldım.
Gibi bir şey risk ile başa çıkmak için | | | \ / / | yerine / / / \ \ ile sonuçlanacaktı \ \.

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

Ölçek

$ perl dominos.pl '|\ |\/|||\/|'
|\__\//|\\/__

1
Eğik çizgiden başka bir sınırlayıcı kullanıyorsanız, örneğin s, \\|/ ,__,gbunun yerine birkaç ters eğik çizgiyi ortadan kaldırabilirsiniz s/ \\|\/ /__/g.
Ocaklar

İyi bahşiş. Bu numarayı unuttum. Ve birkaç byte fazlalığı negatif setler kullanılarak kesildi.
LukStorms

2

ES6 , 220 218 195 bayt

küçültülmüş

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);};

Daha okunabilir

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);
};

2
Programlama Bulmacaları ve Kod Golf'üne Hoş Geldiniz! 1. ES6 gösterimini neden kullandığınızdan emin değilim. () = > {ve }()basitçe kodunuzdan kaldırılabilir. 2. Uyarı kutularının bir animasyon için kabul edilebilir bir çıktı biçimi olduğunu sanmıyorum. JS'nizi HTML'ye gömebilir veya komut satırından çalışması için gerekli değişikliği yapabilirsiniz. 3. Her iki durumda da kodunuz yakl. Bir durumla diğeri yazdırma arasında 100 ms.
Dennis,

2
PPCG'ye Hoşgeldiniz! Golfünüzü iyileştirmek için bu yazıyı ve bu yazıyı gözden geçirmenizi tavsiye ederim .
Jrich,

Önerileriniz ve golf ipuçlarına verilen bağlantılar için teşekkür ederiz. Hala biraz uzun, ama biraz kısalttım ve zamanlayıcıyı ekledim. İpuçlarına daha derinlemesine bakacağım ve ne kısaltabileceğime bakacağım.
user3000806 18:15

1
Şimdi bir terminalde çalışması gerekiyor, ancak hala eskisi üzerinde güncellenmiş durumu yazdırmıyor. Linux'ta, console.log("^[c"+d)bunun yerine ^[ESC karakteri (bir bayt) nerede olduğunu arayarak bunu düzeltebilirsiniz .
Dennis,

1
İlk değiştirirseniz .replaceiçin [R='replace'], daha sonra sonraki her biri [R], bu biraz aşağı kesecek. setTimeout(f,100,d)Geçerli kurulum yerine birkaç bayt da kaydedebilirsiniz .
ETHProductions

2

C #, 335 bayt

Harika bir dil seçimi değil.

İki basamaklı bir sayı seçmek için 50 ile 1000 arasında izin verilen gecikmeyi kötüye kullandım.

Netlik için yeni çizgiler ve girintiler eklendi:

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);
            }
        }
    }
}

1

PHP, 175 bayt

$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);

Un-minified:

$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);

Temelde regex golf. Öncelikle boşluğu olan tüm dominoları düzleştirir (ve soldan sağa eşleşme sırasına göre, "rüzgar" esiyor). Sonra çirkin kısmı geliyor (eğik kesen lanet!)

  • Eşleştir /|\, sonra atla.
  • İle eşleştir (/)|ve değiştir//
  • İle eşleştir |(\)ve değiştir\\

Bu, dominoların düşmesine neden olur. Son olarak, bir sonraki adım için 100ms bekleyin.

()Regex'te sınırlayıcı olarak kullanmak , /kaçmaya ihtiyaç duymadığı anlamına gelir;


100 yerine 50ms beklemenize izin verilir, 1 karakter tasarruf edilir;) PHP 10 ^ 5 izin veriyor mu?
BlueCacti

1

POSIX kabuğu + 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

Bu iki bölümden oluşuyor. Dominoları devirmenin asıl işi, standart seddesen değiştirmedir, hatları tutma alanına toplar. Biz geçici olarak açmak /|\içine /:\sonunda kurtarma, onu korumak için.

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

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

x
y/:/|/

Yana sedgecikmeler ekleyerek herhangi bir şekilde bile yok, ben her satırı sarın (I terminfo'ya / termcap'a içine baktı, ancak herhangi standart bir yol bulamadım) printf "...\r"; sleep .1 bir çizgi her 100ms yazdırmak için. Aslında bunu ilk önce, sadece bir satırımız olduğunda, komuttaki karakterlere devrilme değişimlerinin hiçbirinden dokunulmayacağından.

Tüm kullanılarak test dashve GNU coreutilsile, POSIXLY_CORRECTortamda sette.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.