Xem chúng rơi như domino


22

Bạn sống trong một nhà ga rộng 80 ký tự. Bạn chán, vì vậy bạn quyết định chơi domino. Không, không phải loại nhàm chán trông giống như Scrabble, loại thú vị mà bạn dành một giờ để đặt chúng để xem chúng rơi trong một giây.

Trong các thiết bị đầu cuối, domino trông như thế này:

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

Như chúng ta đã biết, nếu một domino nghiêng chạm vào một cái thẳng đứng, thì domino thứ hai cũng bị nghiêng. Ngoại lệ duy nhất này là nếu hai domino nghiêng chạm vào nó:

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

Điều chỉnh hằng số hấp dẫn của thiết bị đầu cuối của bạn để quá trình chuyển đổi này mất 100 ms.

Nếu một domino nghiêng được hỗ trợ bởi một domino khác hoặc các bức tường của nhà ga, hành trình của nó kết thúc.

Không có domino nghiêng trong

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

(80 ký tự) sẽ di chuyển, vì hai domino nghiêng ngoài cùng được hỗ trợ bởi các bức tường của thiết bị đầu cuối và tất cả những thứ khác được hỗ trợ bởi các domino khác.

Tuy nhiên, nếu không gian theo hướng nghiêng trống, domino rơi xuống:

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

Thiết bị đầu cuối. Hằng số hấp dẫn. Bạn sẽ có được điểm…

Cuối cùng, có một cơn gió nhẹ từ bên trái, do đó, những chiếc domino nghiêng phải rơi nhanh hơn những chiếc nghiêng bên trái:

|/ \| --> |__\|

Bài tập

Viết chương trình / chức năng hiển thị hình ảnh động của trò chơi domino trong thiết bị đầu cuối.

Mã của bạn nên làm như sau:

  1. Đọc một chuỗi từ đầu vào, đại diện cho trạng thái ban đầu của domino.

    Chuỗi này sẽ chứa không quá 80 ký tự và chỉ bao gồm các domino được mô tả ở trên và các khoảng trống.

  2. In trạng thái và chờ trong 100 ms.

  3. Biến đổi trạng thái như đã giải thích ở trên.

  4. Nếu trạng thái thay đổi, quay trở lại 2.

Quy tắc bổ sung

  • Độ dài của chuỗi đầu vào không ảnh hưởng đến chiều rộng của thiết bị đầu cuối; ngay cả khi chuỗi ngắn hơn 80 ký tự, các bức tường của thiết bị đầu cuối vẫn cách nhau 80 ký tự.

  • Mỗi lần thực hiện bước 2, trạng thái sẽ được in đến cùng một vị trí, ghi đè trạng thái trước đó.

  • Vì một số ngôn ngữ không có khả năng chờ chính xác 100 ms, vui lòng chờ bất kỳ số tiền nào trong khoảng từ 50 đến 1000 ms.

  • Luật tiêu chuẩn được áp dụng.

Ví dụ

  • Đối với trạng thái ban đầu

     ||\/||
    

    in như sau (cái này qua cái kia):

     ||\/||
     |\\//|
     \\\///
    __\\//__
    
  • Đối với trạng thái ban đầu

    /||||\
    

    in như sau

    /||||\
    //||\\
    ///\\\
    
  • Đối với trạng thái ban đầu

    /|||\
    

    in như sau

    /|||\
    //|\\
    
  • Đối với trạng thái ban đầu

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

    in như sau:

    |__\|__\|__\|__\|
    
  • Đối với trạng thái ban đầu (80 ký tự)

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

    in như sau

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

Câu trả lời:


13

Võng mạc , 87 86 85 byte

Cảm ơn Dennis vì đã tiết kiệm 1 byte.

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

<ESC>nên được thay thế bằng ký tự điều khiển thực tế (0x1B). <empty>đại diện cho một dòng dấu trống. Sau đó, bạn có thể chạy mã trên từ một tệp duy nhất có -scờ.

Mã này yêu cầu một thiết bị đầu cuối hỗ trợ mã thoát ANSI. Tôi không thể chặn nguồn cấp dữ liệu trong đầu ra của Retina vì vậy tôi cần xóa toàn bộ bảng điều khiển <ESC>cmỗi lần. Tôi đã kiểm tra mã trong bash bằng Mono để chạy Retina.

Giải trình

^.{0,79}$
$0 

Chúng tôi bắt đầu bằng cách nối thêm một khoảng trắng nếu đầu vào chứa ít hơn 80 ký tự. Điều này là để một /đầu bên phải không phải được xử lý riêng.

:`^
<ESC>c

Bây giờ chúng tôi thêm vào <ESC>cchuỗi, đó là mã thoát ANSI để xóa thiết bị đầu cuối. Vì vậy, mỗi khi chuỗi được in, nó sẽ làm như vậy ở đầu thiết bị đầu cuối. Các :`chỉ thị Retina để in ra kết quả của sự thay thế này, tức là cấu hình ban đầu.

(`/ | \\
__

(`bắt đầu một vòng lặp. Vì không có kết quả khớp ), vòng lặp được giả sử sẽ đi đến giai đoạn cuối cùng của chương trình. Mỗi lần lặp sẽ mô phỏng một bước của domino rơi xuống và sau đó "ngủ" một chút. Giai đoạn đầu tiên này thay thế /\bên cạnh một không gian vào __. Điều này tự động xử lý / \trường hợp chính xác, bởi vì các kết quả khớp không thể trùng nhau và được tìm kiếm từ trái sang phải. Vì vậy, cái /<sp>sẽ được khớp và biến thành __cái \không thể khớp và chúng ta hiểu đúng __\.

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

Điều này biến /|thành //miễn là không có \bên cạnh nó. Chúng tôi nối thêm một cái asao cho cái mới /này không gây rối với giai đoạn tiếp theo (chưa nên "biết" về sự thay đổi này).

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

Tình huống ngược lại: biến |\thành \\cung cấp không có /bên cạnh nó. Chúng ta không cần phải đặt aở đây, bởi vì chúng ta đã hoàn thành bước mô phỏng này.

Bây giờ là phần ngủ ...

$
aaaaa

Nối thêm 5 agiây vào cuối mã.

a
aaaa

Biến mỗi lần athành 4 agiây, vì vậy chúng ta nhận được 20 agiây ở cuối.

(a+)+b|a
<empty>

Bây giờ là phần thú vị ... chúng tôi ngủ một chút với sự giúp đỡ của việc quay lại thảm khốc . Có một số cách theo cấp số nhân để phân chia một trận đấu (a+)+giữa các lần lặp lại của nhóm. Vì bnguyên nhân khiến trận đấu thất bại, động cơ sẽ quay lại và thử từng một trong những kết hợp đó trước khi quyết định (a+)+bkhông khớp. Trong hai mươi agiây ở cuối, mất khoảng nửa giây.

Đồng thời, chúng tôi cho phép regex khớp với một lần duy nhất a, nhưng chỉ sau khi thực hiện quay lui. Khi phù hợp, chúng tôi thay thế nó bằng một chuỗi trống, loại bỏ tất cả các as chúng tôi chèn vì lý do này hay lý do khác khỏi chuỗi.

Điều đó để lại việc in chuỗi ở cuối vòng lặp. Ở đây có ích khi tôi chưa khắc phục hành vi in ​​của các vòng trong Retina. Hiện tại, chỉ có một cờ cho mỗi giai đoạn có nội dung "in" hoặc "không in". Mặc định là "không in" ngoại trừ giai đoạn cuối cùng trong chương trình, mặc định là "in". Nhưng giai đoạn được lặp, vì vậy điều đó có nghĩa là nó thực sự in chuỗi hiện tại trên mỗi lần lặp. Thông thường, điều đó thực sự gây phiền nhiễu và hầu như bạn luôn cần bao gồm một giai đoạn trống bổ sung vào cuối nếu bạn chỉ muốn kết quả cuối cùng, nhưng ở đây nó cho phép tôi lưu bốn byte.


6

Javascript (ES6), 206 148 129 158 byte

Cuối cùng tôi đã đưa nó xuống một điểm thấp độc đáo, nhưng nó sẽ không xóa bảng điều khiển hoặc nối thêm một khoảng trống; những vấn đề này đã được sửa chữa

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

Phiên bản 153 byte thay thế sẽ hoạt động trong 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, nó khá thú vị để chơi với. Hãy thử một phiên bản HTML tại đây:

Có lẽ có thêm một chút chỗ để chơi gôn. Đề nghị chào mừng!


+1 cho bản chạy thử đã lãng phí 10 phút thời gian của tôi và +1 cho chức năng ngẫu nhiên hóa. Tuy nhiên, như Dennis đề cập, nó đã thất bại trong trường hợp thử nghiệm đầu tiên. Hãy thử /hoặc /|bạn sẽ thấy gạch không rơi hoàn toàn như bình thường.
dberm22

@Dennis Cảm ơn bạn đã chỉ ra những vấn đề này. Tôi tin rằng tôi đã sửa cả hai cái này ngay bây giờ.
Sản xuất ETH

Node không hài lòng về mũi tên béo, nhưng nó hoạt động tốt. Bạn có thể thay thế \033bằng một byte ESC bằng chữ, tiết kiệm 3 byte.
Dennis

2

Perl 5, 154 146

Phải sử dụng một ký tự tạm thời để duy trì trạng thái giữa 2 regex.
Để đối phó với rủi ro mà một cái gì đó như / | | | \ sẽ kết thúc là / / / \ \ thay vì / / | \ \.

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

Kiểm tra

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

1
Bạn có thể loại bỏ một vài dấu gạch chéo ngược nếu bạn sử dụng một dấu phân cách khác với dấu gạch chéo - ví dụ s, \\|/ ,__,gthay vì s/ \\|\/ /__/g.
hobbs

Mẹo tốt. Quên về mánh khóe đó. Và một vài byte thêm đã được cắt bằng cách sử dụng các tập phủ định.
LukStorms

2

ES6 , 220 218 195 byte

Giảm thiểu

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

Dễ đọc hơn

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
Chào mừng bạn đến với Câu đố lập trình & Code Golf! 1. Tôi không chắc tại sao bạn lại sử dụng ký hiệu ES6. () = > {}()đơn giản có thể được gỡ bỏ khỏi mã của bạn. 2. Tôi không nghĩ hộp cảnh báo là định dạng đầu ra chấp nhận được cho hình ảnh động. Bạn có thể nhúng JS của mình vào HTML hoặc thực hiện thay đổi cần thiết để nó hoạt động từ dòng lệnh. 3. Trong cả hai trường hợp, mã của bạn phải chờ khoảng. 100 ms giữa in một trạng thái và tiếp theo.
Dennis

2
Chào mừng đến với PPCG! Tôi sẽ đề nghị kiểm tra bài nàybài này để giúp cải thiện việc chơi golf của bạn.
jrich

Cảm ơn bạn đã gợi ý và liên kết đến các mẹo chơi golf. Nó vẫn còn hơi dài, nhưng tôi rút ngắn lại một chút và thêm bộ hẹn giờ. Tôi sẽ đi qua các mẹo sâu hơn và xem những gì tôi có thể rút ngắn.
user3000806

1
Điều đó sẽ hoạt động trong một thiết bị đầu cuối ngay bây giờ, nhưng nó vẫn không in trạng thái cập nhật so với trạng thái cũ. Trên Linux, bạn có thể khắc phục điều này bằng cách gọi console.log("^[c"+d)thay thế, ^[ký tự ESC ở đâu (một byte).
Dennis

1
Nếu bạn thay đổi người đầu tiên .replaceđến [R='replace'], sau đó mỗi người tiếp theo đến [R], điều này sẽ cắt giảm khá nhiều. Bạn cũng có thể lưu một vài byte bằng cách sử dụng setTimeout(f,100,d)thay cho thiết lập hiện tại.
Sản xuất ETH

2

C #, 335 byte

Không phải là một sự lựa chọn tuyệt vời của ngôn ngữ.

Tôi đã lạm dụng độ trễ được phép trong khoảng từ 50 đến 1000 để chọn một số có hai chữ số.

Các dòng mới và thụt lề được thêm vào cho rõ ràng:

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

Chưa rút gọn:

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

Về cơ bản golf regex. Đầu tiên làm phẳng bất kỳ domino rơi nào có không gian (và do thứ tự khớp từ trái sang phải, "gió" thổi). Rồi đến phần xấu xí (chửi bạn chém!)

  • Phù hợp /|\, sau đó bỏ qua nó.
  • Phù hợp (/)|và thay thế bằng//
  • Phù hợp |(\)và thay thế bằng\\

Điều này làm cho domino rơi xuống. Cuối cùng, chỉ cần đợi 100ms cho bước tiếp theo.

Sử dụng ()như dấu phân cách trên regex có nghĩa là /không cần thoát, điều này giúp giảm thiểu!


Bạn được phép đợi 50ms thay vì 100, tiết kiệm 1 char;) PHP có cho phép 10 ^ 5 không?
BlueCacti

1

Vỏ POSIX + 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

Đây là hai phần. Công việc chính của việc lật đổ domino là sedthay thế mẫu chuẩn , tích lũy các dòng vào không gian giữ. Chúng tôi tạm thời biến /|\thành /:\để bảo vệ nó, hồi phục vào cuối.

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

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

x
y/:/|/

sedkhông có cách nào để chèn độ trễ (tôi đã xem qua terminfo / termcap, nhưng không thể tìm thấy bất kỳ cách tiêu chuẩn nào), tôi bọc từng dòng printf "...\r"; sleep .1 để in một dòng cứ sau 100ms. Tôi thực sự làm điều này trước tiên, khi chúng ta chỉ có một dòng, vì các ký tự trong lệnh sẽ không bị chạm bởi bất kỳ sự thay thế nào của lật đổ.

Tất cả được thử nghiệm bằng cách sử dụng dashvà GNU coreutils, với POSIXLY_CORRECTthiết lập trong môi trường.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.