Cảnh tuyết hoạt hình ASCII


22

Viết chương trình ngắn nhất để biến bất kỳ tác phẩm nghệ thuật ASCII nào thành cảnh tuyết hoạt hình bắt đầu hình thành từ tuyết rơi ( ví dụ JavaScript không chơi gôn được cập nhật lần cuối 2011-12-19).

Đặc tả đầu vào : Chương trình của bạn phải chấp nhận kết hợp tùy ý các khoảng trắng, dấu sao và dòng mới. Đầu vào sẽ chứa tối đa 23 dòng và 80 ký tự trên mỗi dòng. Sẽ không có dòng nào trống, nhưng dòng có thể chỉ bao gồm khoảng trắng. Một dòng mới duy nhất sẽ được bao gồm và phải được bỏ qua.

Đầu ra : Xuất các ký tự ASCII (dấu cách, dấu sao) và mã điều khiển (trả về vận chuyển, nguồn cấp dữ liệu, mã thoát ANSI, v.v.) cho bảng điều khiển văn bản hoặc trình giả lập thiết bị đầu cuối của hệ điều hành cho đến khi người dùng tự kết thúc chương trình. Bạn có thể giả sử cửa sổ đầu cuối là 80x24 ký tự nếu hệ điều hành của bạn cho phép cài đặt đó.

Quy tắc :

  • Hoạt hình phải mượt mà và nhanh chóng (ưu tiên 15 khung hình / giây).
  • Mật độ tuyết phải nằm trong khoảng từ 5% đến 15%.
  • Không quá một màn hình tuyết có thể cuộn mỗi giây. (Điều đó có nghĩa là không quá 24 dòng tuyết mới có thể được thêm vào trong bất kỳ khoảng thời gian một giây nào.)
  • Tuyết không được hiển thị bất kỳ mô hình rõ ràng nào khi nó đi vào phía trên màn hình; nó phải nhìn ngẫu nhiên
  • Chương trình phải lấp đầy tất cả các hàng của màn hình bằng tuyết càng nhanh càng tốt khi nó bắt đầu; Việc lấp đầy các hàng riêng lẻ của màn hình không được rõ ràng đối với người xem.
  • Góc dưới bên trái của nghệ thuật ASCII đầu vào phải ở góc dưới bên trái của màn hình (Hình 1 để làm rõ thêm).
  • Khu vực bên trong hoặc theo nghệ thuật ASCII không được lấp đầy vĩnh viễn bằng các dấu sao. Tuy nhiên, dấu hoa thị có thể (nhưng không bắt buộc) di chuyển qua khu vực này.
  • Tuyết không được tích tụ ở dưới cùng của màn hình hoặc trên đỉnh của tuyết hiện có trừ khi được hiển thị trong đầu vào.
  • Các không gian thấp hơn phải được lấp đầy trước các khoảng trên, vì điền vào các không gian theo thứ tự ngược lại làm cho hoạt hình cây Giáng sinh trông rất khác so với đầu ra của mã gốc của tôi. (đã thêm 2011-12-20)

Chúc mừng ngày lễ

Hình 1: các khu vực được gắn nhãn của màn hình 80x24

---------------------------New snow added on this line--------------------------
                                                                             |
                                                                             |
----------------------------------------------------------+                  |
                                                    ****  |                  |
    Snow MUST fall  Snow MAY fall ---------------->  **** |                  |
    through this    through these          ****      **** |  Snow MUST fall  |
    area.           areas of a              ****     **** |  through this    |
                    completed   \--------->  ****     ****|  area.           |
        ASCII art   scene.    \     ***        ****   ****|                  |
          area         \       \   *******      ****  ****|                  |
                        \       \    ********     ***  ***|  (ALL CAPS terms |
      (located in        \       \-->   *********  ***    |  have standard   |
       lower left         \     *******     ******  MAY   |     RFC 2119     |
       corner of           \    *************  **   fall  |    meanings.)    |
       screen)              \        ***********    here  |                  |
                         *** +--->          ****  ***     |                  |
                         *** | ****************   ***     |                  |
  | Snow MUST fall       *** | ****************   ***     |                  |
  | through this         *** +--->                ***     |                  |
  | area.                *** | ****************   ***     |                  |
--+---------------------+*** +--->                ***+----+------------------+--
  |   Snow MUST NOT     |****************************|      Snow MUST NOT    |
  V  accumulate here.   |****************************|     accumulate here.  V

Ví dụ đầu vào

Biểu ngữ Golf Code

 ******   *******  ********  ********     ******    *******  **       ******** 
**    ** **     ** **     ** **          **    **  **     ** **       **       
**       **     ** **     ** **          **        **     ** **       **       
**       **     ** **     ** ******      **   **** **     ** **       ******   
**       **     ** **     ** **          **    **  **     ** **       **       
**    ** **     ** **     ** **          **    **  **     ** **       **       
 ******   *******  ********  ********     ******    *******  ******** **       

Logo chồng chéo

                                                    ****
                                                     ****
                                           ****      ****
                                            ****     ****
                                             ****     ****
                                    ***        ****   ****
                                   *******      ****  ****
                                     ********     ***  ***
                                        *********  ***
                                *******     ******
                                *************  **
                                     ***********
                         ***                ****  ***
                         ***   ****************   ***
                         ***   ****************   ***
                         ***                      ***
                         ***   ****************   ***
                         ***                      ***
                         ****************************
                         ****************************

Cây thông Noel

                                        *
                                       ***                           *
                *                     *****                         ***
               ***                   *******           *           *****
              *****                 *********         ***            *
                *                  ***********       *****
                       *          *************     *******
        *             ***        ***************       *               *
       ***           *****      *****************                     ***
      *****         *******    *******************                   *****
     *******           *      *********************                 *******
    *********                           *                          *********
        *                                                              *

1
Cây Giáng sinh thứ ba bị gãy.
Bobby

Thử thách tốt đẹp! Tôi nghĩ rằng các quy tắc nên được liệt kê để tham khảo dễ dàng hơn và tôi không hiểu quy tắc thứ ba và thứ sáu ...
hallvabo

@hallvabo Tôi đã làm rõ hai quy tắc đó, sau là thêm một con số được dán nhãn.
Xin vui lòng khởi động

Yêu cầu làm rõ: dòng mới có được bao gồm trong độ dài dòng tối đa 80 char hay là tối đa 80 ký tự cộng với dòng mới? (Tôi giả sử cái sau, nhưng một số bài nộp dường như đã giả sử cái trước.)
Ilmari Karonen

@IlmariKaronen Cái sau.
Vui lòng khởi động

Câu trả lời:


5

Perl, 196/239 ký tự

chomp(@p=(@f=($"x80)x24,<>)[-24..-1]);{@s=(join("",map rand>.1?$":"*",1..80),@s);if(@s>23){$t=$f[$_],print$_?$/:"\e[H",($f[$_]|=$s[$_]&$p[$_])|($s[$_]&=~$t^$f[$_])for 0..23;select"","","",.1}redo}

Giải pháp này khác với ví dụ về JS của bạn ở chỗ mẫu được điền từ trên xuống thay vì từ dưới lên, nhưng tôi cho rằng điều đó ổn vì bạn không nói gì về quy tắc này.

Có thể thu được mức giảm 1 char tầm thường bằng cách thay thế \ebằng ký tự ESC theo nghĩa đen, nhưng điều đó làm cho mã khó đọc và chỉnh sửa hơn nhiều.


Cập nhật: Tôi đã quản lý để đưa ra một phiên bản lấp đầy mẫu từ dưới lên và không cho phép tuyết rơi qua các phần được lấp đầy của mẫu, như trong ví dụ triển khai JS, với chi phí là 43 ký tự bổ sung:

chomp(@p=(@q=@f=($"x80)x24,<>)[-24..-1]);{@s=(join("",map rand>.1?$":"*",1..80),@s);if(@s>23){my$q;$q[-1-$_]=($q|=$p[-$_]&~$f[-$_])for@a=0..23;print$_?$/:"\e[H",($f[$_]|=$s[$_]&$p[$_]&~$q[$_])|($s[$_]&=~$f[$_])for@a;select"","","",.1}redo}

Thay thế ($s[$_]&=~$f[$_])bằng chỉ $s[$_]giúp tiết kiệm 11 ký tự bằng cách cho tuyết rơi qua các phần được lấp đầy của mẫu (khớp với thông số kỹ thuật, nhưng không phải là triển khai ví dụ).


OK, vì tôi dường như vẫn dẫn đầu cuộc đua sau một tuần, tôi đoán tôi nên giải thích cách giải pháp của tôi hoạt động để khuyến khích cạnh tranh nhiều hơn. (Lưu ý: Giải thích này dành cho phiên bản điền từ trên xuống dưới 196 char. Tôi có thể sửa đổi nó để bao gồm phiên bản khác sau.)

Trước hết, một mẹo lớn mà giải pháp của tôi dựa trên đó là, do cách sắp xếp mã ký tự ASCII, 1 bit trong mã ASCII cho một khoảng trắng chỉ là một tập hợp con của mã trong một mã cho dấu hoa thị.

Do đó, các biểu thức sau đây là đúng: " " & "*" eq " "" " | "*" eq "*". Đây là những gì cho phép tôi sử dụng các thao tác chuỗi bitwise để kết hợp các phần tĩnh và chuyển động của cảnh mà không phải lặp qua các ký tự riêng lẻ.

Vì vậy, ngoài ý muốn đó, chúng ta hãy đi qua mã. Đây là phiên bản khử golf của nó:

chomp(@p = (@f = ($" x 80) x 24, <ARGV>)[-24..-1]);
{
    @s = (join('', map((rand > 0.1 ? $" : '*'), 1..80)), @s);
    if (@s > 23) {
        foreach (0 .. 23) {
            $t = $f[$_];
            print( $_ ? $/ : "\e[H" );
            print( ($f[$_] |= $s[$_] & $p[$_]) | ($s[$_] &= ~$t ^ $f[$_]) );
        }
        select '', '', '', 0.1;
    }
    redo;
}

Dòng đầu tiên thiết lập các mảng @f(cho "cố định") và @p(cho "mẫu"). @fsẽ tạo thành phần cố định của màn hình và bắt đầu không chứa gì ngoài khoảng trắng, trong khi @p, không được hiển thị trực tiếp, có chứa mẫu đầu vào; khi hoạt hình tiếp tục, chúng ta sẽ thêm ngày càng nhiều dấu sao cho @fđến khi cuối cùng nó trông giống như vậy @p.

Cụ thể, @f = ($" x 80) x 23đặt @fthành 24 chuỗi gồm 80 khoảng cách mỗi chuỗi. ( $"là một biến Perl đặc biệt có giá trị mặc định chỉ là một khoảng trắng.) Sau đó chúng tôi lấy danh sách này, nối các dòng đầu vào vào nó bằng toán tử readline <>, lấy 24 dòng cuối của danh sách kết hợp này và gán cho @p: một cách nhỏ gọn để đệm @pvới các dòng trống để mô hình xuất hiện ở nơi cần thiết. Cuối cùng, chúng tôi sẽ chompnhập các dòng đầu vào @pđể loại bỏ bất kỳ dòng mới nào để chúng không gây ra sự cố sau này.

Bây giờ, hãy nhìn vào vòng lặp chính. Nó chỉ ra rằng đó {...;redo}là một cách ngắn hơn để viết một vòng lặp vô hạn hơn while(1){...}hoặc thậm chí for(;;){...}, đặc biệt là nếu chúng ta bỏ qua dấu chấm phẩy trước đó redobởi vì nó ngay lập tức đi theo một ifkhối.

Dòng đầu tiên của vòng lặp chính giới thiệu mảng @s(tất nhiên là "tuyết"), trong đó nó có một chuỗi 80 ký tự ngẫu nhiên gồm 90% khoảng trắng và 10% dấu hoa thị trên mỗi lần lặp. (Để lưu một vài ký tự, tôi không bao giờ thực sự bật các dòng thừa ra khỏi phần cuối của @smảng, vì vậy nó sẽ ngày càng dài hơn. Cuối cùng, điều đó sẽ khiến chương trình tạm dừng vì mảng quá dài để phù hợp với bộ nhớ, nhưng điều đó sẽ mất nhiều thời gian hơn hầu hết mọi người từng xem hoạt hình này. Thêm một pop@s;tuyên bố trước khi selectsửa nó với giá bảy ký tự.)

Phần còn lại của vòng lặp chính được gói trong một ifkhối, do đó nó chỉ chạy khi @smảng chứa ít nhất 24 dòng. Đây là một cách đơn giản để tuân thủ thông số kỹ thuật, đòi hỏi toàn bộ màn hình phải được phủ tuyết rơi từ đầu và cũng đơn giản hóa các thao tác bitwise một chút.

Tiếp đến là một foreachvòng lặp, trong phiên bản golf thực sự là một tuyên bố duy nhất với một for 0..23sửa đổi. Vì nội dung của vòng lặp có thể cần một số lời giải thích, tôi sẽ giải nén nó thêm một chút bên dưới:

foreach (0 .. 23) {
    print $_ ? $/ : "\e[H";     # move cursor top left before first line, else print newline
    $t = $f[$_];                # save the previous fixed snowflakes
    $f[$_] |= $s[$_] & $p[$_];  # snowflakes that hit the pattern become fixed 
    $s[$_] &= ~$t ^ $f[$_];     # ...and are removed from the moving part
    print $f[$_] | $s[$_];      # print both moving and fixed snowflakes ORed together
}

Trước hết, $_là biến đếm vòng lặp mặc định trong Perl trừ khi một biến khác được chỉ định. Ở đây nó chạy từ 0 đến 23, tức là qua 24 dòng trong khung hiển thị. $foo[$_]biểu thị phần tử được lập chỉ mục bởi $_trong mảng @foo.

Trên dòng đầu tiên của vòng lặp khử golf, chúng tôi in một dòng mới (thu được một cách thuận tiện từ $/biến đặc biệt) hoặc, khi $_bằng 0, chuỗi "\e[H", trong đó \ebiểu thị một ký tự ESC. Đây là mã điều khiển đầu cuối ANSI để di chuyển con trỏ đến góc trên cùng bên trái của màn hình. Về mặt kỹ thuật, chúng tôi có thể bỏ qua rằng nếu chúng tôi giả định kích thước màn hình cụ thể, nhưng tôi vẫn giữ nó trong phiên bản này vì điều đó có nghĩa là tôi không phải thay đổi kích thước thiết bị đầu cuối của mình để chạy hoạt hình.

Trên $t = $f[$_]dòng, chúng ta chỉ lưu giá trị hiện tại của $f[$_]biến "tạm thời" (do đó $t) trước khi có khả năng thay đổi nó trong dòng tiếp theo, trong đó $s[$_] & $p[$_]cung cấp giao điểm (bitwise AND) của tuyết rơi và mẫu đầu vào và |=toán tử OR mà vào dòng đầu ra cố định $f[$_].

Trên dòng bên dưới, $t ^ $f[$_]đưa ra XOR bitwise của các giá trị trước đó và hiện tại của $f[$_], tức là danh sách các bit chúng ta đã thay đổi trong dòng trước, nếu có, và phủ định một trong hai chuỗi đầu vào có ~phủ định đầu ra. Do đó, những gì chúng ta nhận được là một bitmask với tất cả các bit được đặt thành 1 ngoại trừ những bit mà chúng ta vừa thêm $f[$_]vào trên dòng trước đó. ANDing bitmask lên để $s[$_]loại bỏ các bit đó khỏi nó; thực tế, điều này có nghĩa là khi một bông tuyết rơi đầy vào một lỗ trên mẫu cố định, nó sẽ bị xóa khỏi mảng tuyết rơi.

Cuối cùng, print $f[$_] | $s[$_](trong phiên bản golf được triển khai bằng cách chỉ OR hai dòng trước đó với nhau) chỉ cần in liên kết (bitwise OR) của các bông tuyết cố định và di chuyển trên dòng hiện tại.

Một điều nữa để giải thích là select '', '', '', 0.1bên dưới vòng lặp bên trong. Đây chỉ là một cách klugy để ngủ 0,1 giây trong Perl; đối với một số lý do lịch sử ngớ ngẩn, sleeplệnh Perl tiêu chuẩn có độ phân giải một giây và việc nhập tốt hơn sleeptừ Time::HiResmô-đun sẽ mất nhiều ký tự hơn là lạm dụng 4-argselect .


Dường như có một lỗi nhỏ: dòng thứ 24 không được sử dụng và dòng dưới cùng của nghệ thuật ASCII là dòng thứ 23. Và nó thực sự nên lấp đầy không gian thấp hơn trước khi nó lấp đầy những khoảng trên, mặc dù ban đầu tôi không chỉ định điều đó.
Xin vui lòng

@PleaseStand: Tôi đã thay đổi mã để sử dụng tất cả 24 dòng (và tình cờ đã thoát khỏi say), với chi phí là 2 ký tự phụ. Tuy nhiên, tôi không nghĩ rằng tôi có thể thay đổi thứ tự điền rất dễ dàng; việc thực hiện của tôi về cơ bản gắn liền với nó.
Ilmari Karonen

Giải thích tuyệt vời! Tôi ước tôi có thể bỏ phiếu cho mục này một lần nữa.
Máy cắt Dillon

@PleaseStand: Tôi thực sự đã quản lý để tạo một phiên bản điền từ dưới lên, hiện tại trông khá giống với ví dụ về JS của bạn; nó dài hơn một chút so với mục từ trên xuống, nhưng vẫn ngắn hơn các mục khác cho đến nay.
Ilmari Karonen

3

HTML và JavaScript, 436 ký tự

Chuẩn bị nó cho đầu vào:

<body onload="for(a=[],b=[],c=document.body.firstChild,e=c[H='innerHTML'].split(N='\n'),f=e.length-1,g=24,h=g-f;f--;)for(X=80;X--;)b[80*(h+f)+X]='*'==e[f][X];for(setInterval(F='for(y=24;y--;)for(x=80;x--;)if(a[w=80*y+x]){d=1;if(b[w])for(d=0,z=y+1;24>z;++z)b[s=80*z+x]&&!a[s]&&(d=1);d&&(a[w]=0,a[w+80]=1)}for(x=80;x--;).1>Math.random(i=0)&&(a[x]=1);for(t=\'\';1920>i;++i)t+=\'* \'[+!a[i]],79==i%80&&(t+=N);c[H]=t',67);g--;)eval(F)"><pre>

Xem nó chạy cho từng ví dụ: mã golf , logo Stack Overflow , cây Giáng sinh . Người dùng Internet Explorer cần chạy phiên bản 9 và đặt "Chế độ tài liệu" thành "tiêu chuẩn IE9" (sử dụng các công cụ dành cho nhà phát triển F12) để bài đăng này hoạt động chính xác.


1
Cả 3 dường như bị phá vỡ? pasteall.org/pic/show.php?id=66297
CoDEmanX

1

Python, 299 ký tự

Điều này phải phù hợp với các quy tắc, giả sử dòng mới được bao gồm trong giới hạn 80 char.

import random,sys,time
C=1920
v=_,x=' *'
a=['']*C
f=lambda n:[random.choice(e*9+x)for e in _*n]
for e in sys.stdin:a+="%-80s"%e
a=a[-C:]
s=f(C)
while 1:
 z=0;t=''
 for e in s:
    t+=v[x<a[z]or e>_]
    if(e>_<a[z])>(x in a[z+80::80]):a[z]='+'
    t+=z%80/79*'\n';z+=1
 print t;s=f(80)+s[:-80];time.sleep(.1)

Đầu ra của bạn bị vênh nếu đầu vào có bất kỳ dòng nào dài chính xác 80 ký tự (cộng với dòng mới). Tôi đã yêu cầu PleaseStand làm rõ liệu điều đó có ổn không.
Ilmari Karonen

Điều này là do tôi bao gồm một dòng mới ở cuối mỗi dòng rộng 80 char. Mô tả không rõ ràng ở đây, vì nó chỉ định rằng các dòng mới phải được đưa vào, nhưng cũng có thể giả sử thiết bị đầu cuối rộng 80 ký tự (trong trường hợp đó người ta có thể bỏ qua các dòng mới và phụ thuộc vào gói tự động).
hallvabo

Tôi nghĩ vấn đề thực tế là bạn không loại bỏ các dòng mới trước khi đệm các dòng đầu vào thành 80 ký tự, do đó, một đầu vào 80 ký tự cộng với dòng mới kết thúc thực sự nối thêm 81 ký tự vào avà làm rối quá trình lập chỉ mục. Tôi vừa thử nó, và có vẻ như thay thế %ebằng %e.rstrip()dòng 6 đã khắc phục vấn đề. (Tất nhiên, có thể có một bản sửa lỗi ngắn hơn; Tôi không giỏi chơi gôn Python.)
Ilmari Karonen

Nếu bạn muốn hỗ trợ 81 dòng char, chỉ cần thay đổi số và nó hoạt động tốt. Chừng nào bạn còn dưới 100 ký tự trên mỗi dòng, nó sẽ không thay đổi số char :-)
hallvabo

Nếu tôi thay đổi mã của bạn để sử dụng các dòng 81 ký tự, nó sẽ không chạy chính xác trên thiết bị đầu cuối 80 cột, bây giờ thì sao? Bạn đang sản xuất đầu ra 80 cột tốt, chỉ là bạn không chấp nhận chính xác đầu vào 80 cột . Hãy thử: tạo một tệp đầu vào với một vài dòng với 80 dấu sao trên mỗi dòng và xem điều gì sẽ xảy ra. Không nên quá khó: giải pháp của tôi xử lý nó tốt.
Ilmari Karonen

0

Java, 625 ký tự

import java.io.*;import java.util.*;class s extends TimerTask {int _c,_k;char _i[],_o[];boolean _b[];public s(String f) throws IOException {_i=new char[23*80];_o=new char[80];_b=new boolean [23*80];BufferedReader br = new BufferedReader(new FileReader(f));while (br.read(_i,_c++*80,80)!=-1);} public void run(){_k=--_k<0?_c:_k;for(int i=0;i<80;_b[_k*80+i]=Math.random()>0.9?true:false,i++);for(int m=0;m<_c;m++){for(int n=0;n<80;_o[n]=_b[(_k+m)%_c*80+n]?'*':_i[m*80+n],n++);System.out.println(_o);}}public static void main(String[] a) throws IOException{Timer timer=new Timer();timer.scheduleAtFixedRate(new s(a[0]),0,500);}}

Một giải pháp đơn giản trong Java.


Đẹp, nhưng tôi không nghĩ rằng bạn đang tuân thủ thông số kỹ thuật. Cụ thể, bạn hiển thị toàn bộ mẫu ngay từ đầu - nó không "hình thành từ tuyết rơi" như trong bản demo mẫu. (Phải thừa nhận rằng điều này có thể được giải thích tốt hơn trong câu hỏi. Bạn thực sự cần xem bản demo để hiểu những gì nó nên làm.) Ngoài ra, tốc độ khung hình của bạn quá chậm, bạn không bắt đầu với một màn hình đầy tuyết, bạn dường như giả sử một định dạng đầu vào khác với các ví dụ đã cho và bạn thực sự phải đặt lại vị trí con trỏ giữa các khung (in "\033[H"nên thực hiện).
Ilmari Karonen
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.