ドミノのように落ちる


22

あなたは80文字幅の端末内に住んでいます。あなたは退屈しているので、ドミノをプレイすることにします。いいえ、Scrabbleのように見える退屈な種類ではなく、1時間をかけてそれらを見るためにそれらを設定する楽しい種類です。

ターミナルでは、ドミノは次のようになります。

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

ご存知のように、傾斜したドミノが直立したドミノに触れると、2番目のドミノも傾斜します。唯一の例外は、2つの傾斜したドミノがそれに触れる場合です。

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

この遷移に100ミリ秒かかるように、端末の重力定数を調整します。

傾斜したドミノが別のドミノまたはターミナルの壁に支えられている場合、その旅は終了します。

傾斜ドミノはありません

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

(80文字)が移動します。これは、最も外側に傾いた2つのドミノがターミナルの壁でサポートされ、他のすべてが他のドミノでサポートされているためです。

ただし、傾斜方向のスペースが空の場合、ドミノは落下します。

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

ターミナル。重力定数。あなたはポイントを得る...

最後に、左からわずかな風が吹いているので、右に傾いたドミノは左に傾いたドミノよりも速く落下します。

|/ \| --> |__\|

仕事

ターミナルでドミノをプレイするアニメーションを表示するプログラム/関数を作成します。

コードは次のことを行う必要があります。

  1. 入力から文字列を読み取り、ドミノの初期状態を表します。

    この文字列は80文字以下で、上記のドミノと空のスペースのみで構成されます。

  2. 状態を印刷し、100ミリ秒待機します。

  3. 上記で説明したように状態を変換します。

  4. 状態が変更された場合は、2に戻ります。

追加のルール

  • 入力文字列の長さは、端末の幅には影響しません。文字列が80文字より短い場合でも、端末の壁は80文字離れています。

  • ステップ2が実行されるたびに、状態は同じ場所に印刷され、前の状態が上書きされます。

  • 一部の言語では正確に 100ミリ秒待機することはできないため、50ミリ秒から1000ミリ秒までの間は自由に待機してください。

  • 標準の規則が適用されます。

  • 初期状態

     ||\/||
    

    以下を印刷します(重ねて):

     ||\/||
     |\\//|
     \\\///
    __\\//__
    
  • 初期状態

    /||||\
    

    以下を印刷する

    /||||\
    //||\\
    ///\\\
    
  • 初期状態

    /|||\
    

    以下を印刷する

    /|||\
    //|\\
    
  • 初期状態

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

    次を印刷します。

    |__\|__\|__\|__\|
    
  • 初期状態(80文字)

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

    以下を印刷する

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

回答:


13

網膜87 86 85バイト

1バイトを節約してくれたDennisに感謝します。

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

<ESC>実際の制御文字(0x1B)に置き換える必要があります。<empty>空の末尾行を表します。その後、-sフラグを使用して単一のファイルから上記のコードを実行できます。

コードには、ANSIエスケープコードをサポートする端末が必要です。Retinaの出力でラインフィードを抑制できないため、<ESC>c毎回コンソール全体をクリアする必要があります。Retinaを実行するためにMonoを使用してbashでコードをテストしました。

説明

^.{0,79}$
$0 

入力に含まれる文字が80文字未満の場合は、スペースを追加することから始めます。これは/、右端のa を個別に処理する必要がないようにするためです。

:`^
<ESC>c

次に<ESC>c、端末をクリアするためのANSIエスケープコードである文字列の先頭に追加します。そのため、文字列が印刷されるたびに、端末の上部で印刷されます。は、:`Retinaにこの置換の結果、つまり初期構成を出力するように指示します。

(`/ | \\
__

(`ループを開始します。一致するものがないため)、ループはプログラムの最後のステージまで進むと想定されます。各反復は、ドミノが落下し、少し「スリープ」するステップをシミュレートします。この第一段階は、置き換え/\にスペースの隣に__。これ/ \は、一致が重複することはなく、左から右に検索されるため、大文字と小文字を自動的に正しく処理します。したがって、/<sp>は一致し、一致しない__ように変換され\、正しいが取得されます__\

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

このターン/|への//提供は一切ありません\、それに隣接しています。aこの新しいもの/が次の段階を混乱させないように追加します(この段階ではまだこの変更を「認識」してはいけません)。

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

逆の状況:ターン|\への\\提供は一切ありません/横に。aシミュレーションのこのステップは完了しているため、ここに配置する必要はありません。

さて、眠っている部分...

$
aaaaa

aコードの最後にさらに5を追加します。

a
aaaa

それぞれaを4 a秒に変換するためa、最後に20 秒を取得します。

(a+)+b|a
<empty>

さて、楽しい部分は、壊滅的なバックトラックの助けを借りて少し眠ります。(a+)+グループの繰り返し間で一致を分割する指数関数的な方法があります。これbにより一致が失敗するため、エンジンはそれらの組み合わせのすべてを組み合わせてバックトラックし、一致しないと判断する前に試行し(a+)+bます。a最後の20 秒間は、0.5秒ほどかかります。

同時に、正規表現が単一のに一致することを許可しますaが、これはバックトラッキングを実行した後でのみです。一致する場合、空の文字列に置き換え、a何らかの理由で挿入したすべてのsを文字列から削除します。

これにより、ループの反復の最後に文字列が出力されます。ここで、Retinaのループの印刷動作をまだ修正していないことが役立ちます。現在、各ステージに「印刷」または「印刷しない」というフラグが1つだけあります。デフォルトは「印刷しない」です。ただし、プログラムの最後のステージはデフォルトで「印刷する」です。ただし、ステージはループされているため、各反復で現在の文字列が実際に出力されます。通常、これは非常に面倒です。最終結果だけが必要な場合は、ほとんどの場合、最後に空のステージを追加する必要がありますが、ここでは4バイトを節約できます。


6

Javascript(ES6)、206 148 129 158バイト

最終的にはかなり低いポイントまで下げましたが、コンソールをクリアしたり、余分なスペースを追加したりしませんでした。これらの問題は現在修正されています。

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で動作する代替の153バイトバージョン:

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

私見、遊ぶのはとても楽しいです。ここでHTMLバージョンを試してください:

おそらくゴルフをする余地が十分にあるでしょう。提案を歓迎します!


私の時間の10分を無駄にした実行可能なデモの場合は+1、ランダマイザー機能の場合は+1。ただし、デニスが述べているように、最初のテストケースでは失敗します。/または/|を試してみると、タイルが本来のように完全に落ちないことがわかります。
dberm22

@Dennisこれらの問題を指摘してくれてありがとう。両方を修正したと思います。
-ETHproductions

Nodeは太い矢印に満足していませんが、それ以外は正常に機能します。\033リテラルESCバイトに置き換えて、3バイト節約できます。
デニス

2

Perl 5、154 146

2つの正規表現の間で状態を維持するために一時的な文字を使用する必要がありました。
/ |のようなものがリスクに対処するために | | \は/ / |ではなく/ / / \ \になります \ \。

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

テスト

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

1
スラッシュ以外の区切り文字を使用する場合、たとえば、s, \\|/ ,__,g代わりに、いくつかのバックスラッシュを削除できますs/ \\|\/ /__/g
ホッブズ

良いヒント。そのトリックを忘れました。そして、否定セットを使用することにより、余分な数バイトがカットされました。
LukStorms

2

ES6220の 218 195バイト

縮小

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

より読みやすい

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
プログラミングパズルとコードゴルフへようこそ!1. ES6表記を使用している理由がわかりません。() = > {そして}()単にあなたのコードから削除することができます。2.アラートボックスは、アニメーションの許容可能な出力形式ではないと思います。JSをHTMLに埋め込むか、コマンドラインから機能するように必要な変更を加えることができます。3.いずれの場合も、コードは約1秒間待機する必要があります。ある状態と次の状態を印刷する間の100ミリ秒。
デニス

2
PPCGへようこそ!ゴルフを改善するために、この投稿この投稿を確認することをお勧めします。
-jrich

ゴルフのヒントへの提案とリンクをありがとう。まだ少し長いですが、少し短くしてタイマーを追加しました。ヒントをさらに詳しく説明し、短縮できるものを確認します。
user3000806

1
これで端末で動作するはずですが、更新された状態が古い状態で出力されることはありません。Linuxでは、console.log("^[c"+d)代わりに^[ESC文字(1バイト)を呼び出すことでこれを修正できます。
デニス

1
最初の.replace[R='replace']に変更すると、後続の各をに変更すると、[R]かなり削減されます。setTimeout(f,100,d)現在のセットアップの代わりに使用することで、数バイトを節約することもできます。
-ETHproductions

2

C#、335バイト

言語の素晴らしい選択ではありません。

2桁の数字を選択するために、50〜1000の間で許可されている遅延を悪用しました。

明確にするために新しい行とインデントが追加されました。

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バイト

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

未縮小:

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

基本的に正規表現ゴルフ。最初に、スペースのある落下するドミノを平らにします(そして、左から右への一致順序のために、「風」が吹く)。その後、い部分が来る(呪いあなたはスラッシュ!)

  • 一致/|\してからスキップします。
  • 一致(/)|して置換//
  • 一致|(\)して置換\\

これにより、ドミノが落下します。最後に、次のステップまで100ms待ちます。

()正規表現で区切り文字として使用することは、/エスケープする必要がないことを意味し、最小限に役立ちます!


100文字ではなく50ミリ秒待機して1文字を節約できます;)PHPでは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

これは2つの部分に分かれています。ドミノを倒す主な作業は、標準的なsedパターンの置換であり、ホールドスペースにラインを蓄積します。私たちは、一時的にオン/|\/:\終わりに回復し、それを保護します。

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

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

x
y/:/|/

以来 sed(私がのterminfo / termcapのに見えたが、任意の標準的な方法を見つけることができませんでした)遅延を挿入する任意の方法を持っていない、私は、各ラインをラップprintf "...\r"; sleep .1 ラインごとに100ミリ秒を印刷します。コマンド内の文字は転倒の置換のいずれにも触れられないため、実際に最初にこれを行います。

すべてが使用してテストdashおよびGNU coreutilsで、POSIXLY_CORRECT環境中のセット。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.