Sieh zu, wie sie wie Dominosteine ​​fallen

22

Sie wohnen in einem Terminal mit einer Breite von 80 Zeichen. Sie langweilen sich und entscheiden sich, Domino zu spielen. Nein, nicht die langweilige Art, die aussieht wie Scrabble, die lustige Art, in der Sie eine Stunde damit verbringen, sie einzustellen, um zu sehen, wie sie in einer Sekunde fallen.

In Terminals sehen Dominosteine ​​folgendermaßen aus:

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

Wie wir alle wissen, wird, wenn ein geneigter Domino einen aufrechten berührt, auch der zweite Domino geneigt. Die einzige Ausnahme ist, wenn zwei geneigte Dominosteine ​​es berühren:

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

Passen Sie die Gravitationskonstante Ihres Terminals so an, dass dieser Übergang 100 ms dauert.

Wenn ein geneigter Domino von einem anderen Domino oder den Wänden des Terminals gestützt wird, endet seine Reise.

Keiner der gekippten Dominosteine

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

(80 Zeichen) werden verschoben, da die beiden äußersten geneigten Dominosteine ​​von den Wänden des Terminals und alle anderen von anderen Dominosteinen unterstützt werden.

Wenn jedoch der Raum in der Kipprichtung leer ist, fällt der Domino herunter:

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

Terminal. Gravitationskonstante. Sie verstehen, worum es geht ...

Schließlich gibt es einen leichten Wind von links, so dass nach rechts geneigte Dominosteine ​​schneller fallen als nach links geneigte:

|/ \| --> |__\|

Aufgabe

Schreiben Sie ein Programm / eine Funktion, die eine Animation zum Spielen von Dominosteinen in einem Terminal zeigt.

Ihr Code sollte Folgendes tun:

  1. Liest eine Zeichenfolge aus der Eingabe, die den Anfangszustand der Dominosteine ​​darstellt.

    Diese Zeichenfolge enthält nicht mehr als 80 Zeichen und besteht ausschließlich aus den oben beschriebenen Dominosteinen und leeren Leerzeichen.

  2. Drucken Sie den Status und warten Sie 100 ms.

  3. Transformiere den Zustand wie oben beschrieben.

  4. Wenn sich der Status geändert hat, kehren Sie zu 2 zurück.

Zusätzliche Regeln

  • Die Länge der Eingabezeichenfolge wirkt sich nicht auf die Breite des Terminals aus. Auch wenn die Zeichenfolge kürzer als 80 Zeichen ist, sind die Wände des Terminals immer noch 80 Zeichen voneinander entfernt.

  • Bei jeder Ausführung von Schritt 2 sollte der Status an derselben Stelle gedruckt werden und den vorherigen Status überschreiben.

  • Da einige Sprachen nicht in der Lage sind, genau 100 ms zu warten, können Sie zwischen 50 und 1000 ms warten.

  • Es gelten die Standardregeln für .

Beispiele

  • Für den Ausgangszustand

     ||\/||
    

    drucke folgendes (übereinander):

     ||\/||
     |\\//|
     \\\///
    __\\//__
    
  • Für den Ausgangszustand

    /||||\
    

    Drucken Sie Folgendes aus

    /||||\
    //||\\
    ///\\\
    
  • Für den Ausgangszustand

    /|||\
    

    Drucken Sie Folgendes aus

    /|||\
    //|\\
    
  • Für den Ausgangszustand

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

    drucke folgendes aus:

    |__\|__\|__\|__\|
    
  • Für den Ausgangszustand (80 Zeichen)

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

    Drucken Sie Folgendes aus

    \||||____||||/__                /|\    /\    /|\                __\||||____||||/
    
Dennis
quelle

Antworten:

13

Retina , 87 86 85 Bytes

Vielen Dank an Dennis für das Speichern von 1 Byte.

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

<ESC>sollte durch das eigentliche Steuerzeichen (0x1B) ersetzt werden. <empty>steht für eine leere abschließende Zeile. Sie können den obigen Code dann aus einer einzelnen Datei mit dem -sFlag ausführen .

Der Code erfordert ein Terminal, das ANSI-Escape-Codes unterstützt. Ich kann den Zeilenvorschub in der Retina-Ausgabe nicht unterdrücken, daher muss <ESC>cjedes Mal die gesamte Konsole gelöscht werden. Ich habe den Code in Bash mit Mono getestet, um Retina auszuführen.

Erläuterung

^.{0,79}$
$0 

Wir beginnen mit dem Anhängen eines Leerzeichens, wenn die Eingabe weniger als 80 Zeichen enthält. Dies ist so, dass ein /am rechten Ende nicht gesondert behandelt werden muss.

:`^
<ESC>c

Jetzt stellen wir <ESC>cden String voran , der der ANSI-Escape-Code zum Löschen des Terminals ist. Jedes Mal, wenn die Zeichenfolge gedruckt wird, wird dies am oberen Rand des Terminals durchgeführt. Das :`weist Retina an, das Ergebnis dieser Ersetzung, dh die Erstkonfiguration, auszudrucken.

(`/ | \\
__

(`beginnt eine Schleife. Da es keine Übereinstimmung gibt ), wird davon ausgegangen, dass die Schleife bis zur letzten Stufe des Programms reicht. Jede Iteration simuliert einen Schritt des Herunterfallens der Dominosteine ​​und "schläft" dann ein wenig. Diese erste Stufe ersetzt /und \neben einem Raum in __. Dies behandelt den / \Fall automatisch korrekt, da Übereinstimmungen nicht überlappen können und von links nach rechts gesucht werden. Das /<sp>würde also passen und __so werden, dass das \nicht passt und wir das richtige bekommen __\.

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

Damit wird /|in //sofern es nicht \daneben. Wir fügen eine asolche hinzu, dass diese neue /nicht mit der nächsten Phase in Konflikt gerät (die noch nichts über diese Änderung wissen sollte).

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

Die gegenteilige Situation: Biegen Sie |\in \\vorausgesetzt, es gibt keine/ daneben. Wir müssen hier kein einfügen a, da wir mit diesem Schritt der Simulation fertig sind.

Nun der schlafende Teil ...

$
aaaaa

Fügt 5 weitere as an das Ende des Codes an.

a
aaaa

Wird jeweils azu 4 as, so dass wir aam Ende 20 s bekommen .

(a+)+b|a
<empty>

Jetzt der lustige Teil ... wir schlafen ein bisschen mit Hilfe von katastrophalem Backtracking . Es gibt eine exponentielle Anzahl von Möglichkeiten, eine Übereinstimmung (a+)+zwischen Wiederholungen der Gruppe aufzuteilen . Da das bMatch dadurch fehlschlägt, wird die Engine jede einzelne dieser Kombinationen zurückverfolgen und versuchen, bevor sie dies entscheidet(a+)+b eine Übereinstimmung nicht möglich ist. Für die zwanziger aam Ende dauert das ungefähr eine halbe Sekunde.

Gleichzeitig lassen wir zu, dass der reguläre Ausdruck mit einem einzelnen übereinstimmt a, jedoch erst, nachdem das Backtracking durchgeführt wurde. Wenn dies zutrifft, ersetzen wir es durch eine leere Zeichenfolge und entfernen allea s, die wir aus dem einen oder anderen Grund eingefügt haben, aus der Zeichenfolge.

Dadurch wird die Zeichenfolge am Ende der Schleifeniteration gedruckt. Hier ist es praktisch, dass ich das Druckverhalten von Loops in Retina noch nicht behoben habe. Derzeit gibt es nur ein Flag für jede Stufe, das "Drucken" oder "Nicht drucken" lautet. Die Standardeinstellung ist "Nicht drucken", mit Ausnahme der letzten Stufe des Programms, die standardmäßig "Drucken" ist. Die Bühne ist jedoch geloopt, was bedeutet, dass die aktuelle Zeichenfolge bei jeder Iteration gedruckt wird. Normalerweise ist das sehr ärgerlich, und Sie müssen fast immer eine zusätzliche leere Stufe am Ende einfügen, wenn Sie nur das Endergebnis erhalten möchten. Hier kann ich jedoch vier Bytes einsparen.

Martin Ender
quelle
6

Javascript (ES6), 206 148 129 158 Bytes

Ich hatte es endlich auf einen netten Tiefpunkt gebracht, aber es würde weder die Konsole leeren noch einen zusätzlichen Raum anhängen; Diese Probleme wurden jetzt behoben.

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

Alternative 153-Byte-Version, die in Node.JS funktionieren sollte:

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, es macht Spaß, damit zu spielen. Probieren Sie hier eine HTML-Version aus:

Es gibt wahrscheinlich ein bisschen mehr Platz zum Golfen. Vorschläge willkommen!

ETHproductions
quelle
+1 für die lauffähige Demo, die 10 Minuten meiner Zeit verschwendet hat, und +1 für die Randomizer-Funktion. Dennis erwähnt jedoch, dass es für den ersten Testfall fehlschlägt. Versuchen Sie es mit /oder /|und Sie werden sehen, dass die Kacheln nicht so fallen, wie sie sollten.
dberm22
@Dennis Danke, dass du auf diese Probleme aufmerksam gemacht hast. Ich glaube, ich habe beide jetzt behoben.
ETHproductions
Node freut sich nicht über den fetten Pfeil, aber ansonsten funktioniert er einwandfrei. Sie können \033mit einem wörtlichen ESC-Byte ersetzen , wodurch 3 Byte eingespart werden.
Dennis
2

Perl 5, 154, 146

Musste ein temporäres Zeichen verwenden, um den Zustand zwischen 2 regulären Ausdrücken aufrechtzuerhalten.
Um mit dem Risiko umzugehen, dass so etwas wie / | | | \ würde als / / / \ \ anstelle von / / | enden \ \.

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

Prüfung

$ perl dominos.pl '|\ |\/|||\/|'
|\__\//|\\/__
LukStorms
quelle
1
Sie können mehrere Backslashes entfernen, wenn Sie ein anderes Trennzeichen als einen Schrägstrich verwenden - z . B. s, \\|/ ,__,ganstelle von s/ \\|\/ /__/g.
Hobbs
Guter Tipp. Ich habe diesen Trick vergessen. Ein paar Bytes mehr wurden mit negierten Sätzen gekürzt.
LukStorms
2

ES6 , 220 218 195 Bytes

Minimiert

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

Mehr lesbar

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);
};
user3000806
quelle
2
Willkommen bei Programming Puzzles & Code Golf! 1. Ich bin mir nicht sicher, warum Sie die ES6-Notation verwenden. () = > {und }()kann einfach aus Ihrem Code entfernt werden. 2. Ich denke nicht, dass Warnungsfelder ein akzeptables Ausgabeformat für eine Animation sind. Sie können Ihre JS entweder in HTML einbetten oder die erforderlichen Änderungen vornehmen, damit sie von der Befehlszeile aus funktionieren. 3. In beiden Fällen muss Ihr Code ca. 100 ms zwischen dem Drucken eines Zustands und dem nächsten.
Dennis
2
Willkommen bei PPCG! Ich würde vorschlagen, diesen Beitrag und diesen Beitrag zu lesen, um Ihr Golfspiel zu verbessern.
jrich
Vielen Dank für die Anregungen und Links zu Golftipps. Es ist immer noch ein bisschen lang, aber ich habe es ein bisschen gekürzt und den Timer hinzugefügt. Ich werde die Tipps genauer durchgehen und sehen, was ich kürzen kann.
user3000806
1
Das sollte jetzt in einem Terminal funktionieren, aber es wird immer noch nicht den aktualisierten Status über den alten drucken. Unter Linux können Sie dies beheben, indem Sie console.log("^[c"+d)stattdessen aufrufen , wo ^[sich das ESC-Zeichen befindet (ein Byte).
Dennis
1
Wenn Sie zuerst .replaceauf [R='replace']und dann auf ändern [R], verringert sich dies erheblich. Sie können auch ein paar Bytes einsparen, indem Sie setTimeout(f,100,d)anstelle des aktuellen Setups verwenden.
ETHproductions
2

C #, 335 Bytes

Keine gute Wahl der Sprache.

Ich habe die Verzögerung zwischen 50 und 1000 missbraucht, um eine zweistellige Zahl zu wählen.

Neue Zeilen und Einrückungen zur Verdeutlichung hinzugefügt:

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);
            }
        }
    }
}
Hand-E-Food
quelle
1

PHP, 175 Bytes

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

Nicht minimiert:

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

Grundsätzlich Regex Golf. Zerflacht zuerst alle fallenden Dominosteine, die Platz haben (und aufgrund der Reihenfolge von links nach rechts weht der "Wind"). Dann kommt der hässliche Teil (Fluch du schneidest!)

  • Spiel /|\ , dann überspringe es.
  • Abgleichen (/)|und durch ersetzen//
  • Abgleichen |(\)und durch ersetzen\\

Dadurch fallen die Dominosteine. Warten Sie zum Schluss nur 100ms bis zum nächsten Schritt.

Die Verwendung ()als Begrenzer für die Regex bedeutet, dass das /s nicht entkommen muss, was nur minimal hilft!

Niet the Dark Absol
quelle
Du darfst 50ms statt 100 warten und 1 Zeichen sparen;) Erlaubt 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

Dies besteht aus zwei Teilen. Die Hauptaufgabe beim Umstürzen der Dominosteine ​​ist seddas Ersetzen von Standardmustern , bei dem Linien im Laderaum gesammelt werden. Wir vorübergehend /|\in /:\sie zu schützen, am Ende gewinnt.

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

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

x
y/:/|/

Da sedes keine Möglichkeit zum Einfügen von Verzögerungen gibt (ich habe in terminfo / termcap nachgesehen, aber keine Standardmethode gefunden), printf "...\r"; sleep .1 füge ich jede Zeile ein, um alle 100 ms eine Zeile zu drucken. Ich mache das eigentlich zuerst, wenn wir nur eine Zeile haben, da die Zeichen im Befehl von keiner der Substitutionen des Umkippens berührt werden.

Alle getestet mit dashund GNU coreutils, mit POSIXLY_CORRECTin der Umgebung eingestellt.

Toby Speight
quelle