เคลื่อนไหว ASCII Ladder ของบันได Jacob


23

คุณอาจเคยเห็นบันไดของยาโคบในพิพิธภัณฑ์วิทยาศาสตร์สำหรับเด็ก หากคุณไม่คุ้นเคยกับสิ่งที่พวกเขามีลักษณะเหมือนมีภาพหลายภาพและวิดีโอตัวอย่างในวิกิพีเดีย ความท้าทายในวันนี้คือการสร้างอุปกรณ์ไฟฟ้ารุ่น ASCII แบบเคลื่อนไหว ในท้ายที่สุดควรมีลักษณะดังนี้:

LadderGIFExample


การก่อสร้างบันได

นี่คือรูปร่างพื้นฐานของบันไดที่มีความสูง ( H ) 6:

6   \            /
5    \          /
4     \        /
3      \      /
2       \    /
1        \  /
0         ¯¯

ตัวเลขทางด้านซ้ายแสดงถึงหมายเลขแถวของตัวอย่างนี้และไม่ควรรวมอยู่ในผลลัพธ์ เราจะอ้างถึงแถวที่กำหนดโดยหมายเลข ( R ) 0 ¯¯แถวเป็นด้านล่าง แต่ละแถว 1 ถึงHประกอบด้วยสี่ส่วน:

  • มีการเว้นวรรค(U + 0020) ซ้ำ ( H - R ) ครั้ง
  • สแลชหลัง\(U + 005C)
  • เว้นวรรค(U + 0020) ซ้ำแล้วซ้ำอีก (2 * R ) ครั้ง
  • สแลช/(U + 002F)

แถว 0 เหมือนกันยกเว้นทั้งสองสแลชจะถูกแทนที่ด้วย macron ¯(U + 00AF) ช่องว่างต่อท้ายที่ส่วนท้ายของแต่ละบรรทัดหรือใต้บันไดนั้นก็โอเค ช่องว่างชั้นนำไม่ใช่


การก่อสร้างส่วนโค้ง

เมื่อสร้างบันไดแล้วคุณสามารถสร้างส่วนโค้งระหว่างด้านซ้ายและด้านขวา หนึ่งโค้งมีทั้งที่อยู่ในแถวและแทนที่ช่องว่างระหว่างชั้นนำและต่อท้าย\ /ดังนั้นแถวที่ 2 จะมี 4 อักขระในส่วนโค้งแถวที่ 3 จะมี 6 ตัวและอื่น ๆ แต่ละส่วนโค้งประกอบด้วยกฎต่อไปนี้:

  • อักขระที่ใช้ได้คือ_/¯\(U + 005F, U + 002F, U + 00AF, U + 005C)
  • เพื่อให้แน่ใจว่ามีลักษณะที่ราบรื่นใด ๆ¯หรือ/ต้องตามมาด้วย¯หรือ\
  • เพื่อให้แน่ใจว่ามีลักษณะที่ราบรื่นใด ๆ_หรือ\ต้องตามมาด้วย_หรือ/
  • กฎทั้งสองข้างต้นนำไปใช้กับขอบของบันไดเช่นกัน
  • กฎทั้งสามดังกล่าวข้างต้นได้อย่างมีประสิทธิภาพหมายความว่าตัวอักษรตัวแรกในโค้งต้อง_หรือ/และตัวอักษรตัวสุดท้ายจะต้องเป็น_หรือ\( \¯\_//ไม่ถูกต้องที่ปลายทั้งสอง แต่\_/¯\/ก็โอเค)
  • ต้องมีโอกาสที่ไม่เป็นศูนย์สำหรับแต่ละอักขระที่อนุญาตที่จะเกิดขึ้น ณ จุดที่กำหนด
  • แต่ละส่วนโค้งเป็นอิสระจากส่วนโค้งอื่น ๆ

นิเมชั่น

ชีวิตของส่วนโค้งเดียวถูกสร้างขึ้นโดยเริ่มจากแถวที่ 1 และ "ย้าย" แถวขึ้นทีละครั้งจนกว่าจะถึงด้านบน IE แรกสร้างส่วนโค้งที่แถว 1 จากนั้นตั้งค่ากลับเป็นช่องว่างและสร้างส่วนโค้งที่แถว 2 และอื่น ๆ ให้ส่วนโค้งที่จะแสดง ( N ) จำนวนหนึ่งแสดงชีวิตที่สมบูรณ์ของส่วนโค้งจำนวนมากทีละรายการโดยใช้แนวทางต่อไปนี้:

  • หนึ่งอาร์คควรจะ "มีชีวิตอยู่" ในเวลาใดก็ได้ ส่วนต่อไปไม่สามารถเริ่มได้จนกว่าอันที่มีอยู่จะไปถึงด้านบนแล้วดับ
  • ชีวิตของอาร์คแต่ละแถวควรแสดงในหนึ่งเฟรม
  • ควรมีหนึ่งเฟรมของแค่บันไดขั้นพื้นฐาน (โดยไม่มีส่วนโค้ง) ก่อนที่จะเริ่มการอาร์คใหม่ (ไม่จำเป็นก่อนการอาร์คครั้งแรก)
  • อนิเมชั่นควรแสดงชีวิตที่เต็มไปด้วยอาร์คN ถ้าN = 0 มันจะสุ่มอาร์คแบบเคลื่อนไหวตลอดไปจนกว่าจะหยุด
  • หากN > 0 คุณอาจยังคงวนลูปภาพเคลื่อนไหวตลอดไป แต่ต้องเป็นลูปของส่วนโค้งเดียวกันซ้ำไปซ้ำมา (ตัวอย่าง GIF ที่ด้านบนของโพสต์นี้มีH = 6 และN = 3 แต่มันวนซ้ำตลอดไป)
  • ภาพเคลื่อนไหวควรเกิดขึ้นในสถานที่ กล่าวคือแต่ละเฟรมควรเขียนทับเฟรมถัดไปโดยสมบูรณ์และอยู่ในตำแหน่งเดียวกัน
  • ความยาวของแต่ละเฟรมสามารถเป็นสิ่งที่คุณต้องการ แต่ทำให้มันสามารถมองเห็นได้โดยมนุษย์ (IE ใช้สามัญสำนึกของคุณ: 0.01 วินาที / เฟรมและ 30 วินาที / เฟรมนั้นไม่สามารถยอมรับได้)

อินพุต / เอาต์พุต

  • อินพุตและเอาต์พุตสามารถอยู่ในรูปแบบมาตรฐานใด ๆ
  • คุณสามารถส่งออก GIF เขียนข้อความไปที่หน้าจอส่งออกไฟล์เดียวสำหรับแต่ละเฟรมหรือวิธีการอื่นที่เหมาะสม
  • ช่องโหว่มาตรฐานเป็นสิ่งต้องห้าม
  • ความสูงของบันไดHจะเป็นจำนวนเต็มบวก
  • จำนวนของอาร์คเพื่อแสดงNจะเป็นจำนวนเต็มไม่เป็นลบ
  • ทั้งHและNถูกนำมาเป็นอินพุตในลำดับใด ๆ ที่คุณเลือก (โปรดระบุคำสั่งในคำตอบของคุณ)

สภาพการชนะ

นี่คือเพื่อให้โค้ดที่สั้นที่สุดชนะ

Sandbox


1
อาร์คสามารถสร้างสมมาตรโดยศูนย์กลางของมันได้หรือไม่? ฉันไม่เห็นข้อ จำกัด ในกฎ
Dead Possum

ฉันสามารถพิมพ์เฟรมแต่ละเฟรมหลังจากนั้นให้คอนโซลได้หรือไม่
TFeld

@DeadPossum ผมก็คิดว่าคุณมีสิทธิที่แม้จะมีความจริงที่ว่ามันจะดูไม่มากฟ้าผ่าปี แต่ก็ไม่ได้รับอนุญาตจริงโดยการรวมกันของสองกฎ: และthe first character in the arc must be _ or / and the last character must be _ or \ There must be a non-zero chance for each allowable character to occur at a given pointเพื่อให้มีความสมมาตรตัวละครทั้งตัวแรกและตัวสุดท้ายจะต้องเป็น_ทุกครั้งซึ่งหมายความว่าไม่มีโอกาส/เกิดขึ้นหรือ `` ` เป็นศูนย์
Engineer Toast

@TFeld ตราบใดที่แต่ละเฟรมปรากฏในตำแหน่งเดียวกันบนหน้าจอใช่ ซึ่งหมายความว่าคุณจะต้องล้างคอนโซล (หรืออาจเลื่อนลงถ้าเป็นไปได้) ในแต่ละครั้ง
Engineer Toast

2
ข้อกำหนดของ macron หมายความว่า QBasic ไม่สามารถแข่งขันได้หรือไม่ มันใช้CP437ซึ่งในจุดรหัสคือ0xAF »
DLosc

คำตอบ:


5

Python 2 , 287 271 270 276 275 ไบต์

import time,random
r,n=input()
c=n*-~r or-r
while c:
 c-=1;L=[list(' '*i+'\\'+'  '*(r-i)+'/')for i in range(r)];x=c%-~r;time.sleep(1);y=x+1;exec"L[x][y]=random.choice('\xaf/\_'[L[x][y-1]in'\_'::2][y==2*r-x:]);y+=1;"*2*(r-x)
 for l in['']*99+L+[' '*r+'\xaf'*2]:print''.join(l)

ลองออนไลน์!

ไม่ล้างหน้าจอบน tio แต่ทำงานได้ในคอนโซล

Gif ของมันทำงาน:

ป้อนคำอธิบายรูปภาพที่นี่


บิตลับๆล่อๆ แต่คุณสามารถใช้print'\n'*99แทนos.system('cls')และสูญเสียosการนำเข้า ยังใช้งานไม่ได้กับ TIO แต่ทำงานได้ทั้งบนคอนโซล Windows และ Linux
ElPedro

1
ควรมี [จะ] กรอบหนึ่งในเพียงบันไดขั้นพื้นฐาน (ไม่มีโค้ง) ก่อนที่จะเริ่มต้นใหม่โค้ง (ตัวเลือกก่อนโค้งแรก)
wastl

5
ฉันคิดว่าคุณกำลังใช้ยัติภังค์ (U + 002D) แทน macrons (U + 00AF) ฉันไม่คิดว่ามันจะเพิ่มจำนวนไบต์ของคุณเพื่อแก้ไข นอกจากนี้ตามที่ @wastl ชี้ให้เห็นไม่มีกรอบบันไดที่ว่างเปล่าระหว่างส่วนโค้ง
Engineer Toast

แถวด้านล่างใช้ macrons แต่ส่วนโค้งไม่มี
Engineer Toast

1
@EngineerToast แก้ไขแล้ว :)
TFeld

4

JavaScript (ES6), 245 ไบต์

f=(o,h,n,i=0)=>(o.innerText=[...Array(h+1)].map((_,j)=>` `.repeat(j)+(j<h?`\\${[...Array(w--*2)].map((_,k)=>h+~j-i?` `:k>w*2|Math.random()<.5?s[s=t,1]:s[s=`¯\\`,0],s=t=`/_`).join``}/`:`¯¯`),w=h).join`
`,(++i<h||--n)&&setTimeout(f,250,o,h,n,i%h))
Height: <input type=number min=1 value=6 id=h><br>Arcs: <input type=number min=0 value=3 id=n><br><input type=button value=Go! onclick=f(o,+h.value,+n.value)><pre id=o></pre>

จำนวนไบต์ถือว่าการเข้ารหัส ISO-8859-1


เป็นไปได้ที่จะลดลงเหลือ 242 โดยกำหนดA=x=>[...Array(x)].map;จุดเริ่มต้นและแทนที่ประเพณีทั้งสอง
Bary12

@ Bary12 คุณไม่สามารถกลับมาmapนั่นเป็นเพียงทรัพย์สินของArray.prototypeและไม่มีประโยชน์ในตัวเอง ฉันลองใช้งานเวอร์ชัน แต่พวกมันทั้งหมดนานกว่า 245 ไบต์
Neil

3

C (gcc) 406 ไบต์

#define p(X) printf(X),usleep(999)
#define x(X) do{s[X]=0;p(s);s[X]=' ';}while(0)
char c[2][2]={95,47,92,'¯'};R;i;j;k;a(){char s[2]={92,0};for(j=0;j<2*R-1;++j,p(s))*s=c[*s<50][rand()%2];*s=c[*s<50][0];p(s);}f(H,N){char s[99];for(i=0;i<99;++i)s[i]=' ';p("\e[s");for(i=0;;++i){i%=(N?N:i+1);srand(i^H^N);for(k=1;k<H;++k){for(R=H;--R;){x(H-R+1);p("\\");if(R==k)a();else x(2*R);p("/\n");}x(H);p(" ¯¯\n\e[u");}}}

ลองออนไลน์!

รายละเอียด:

#define p(X) printf(X),usleep(999)              // Define p to printf(p) + delay
#define x(X) do{s[X]=0;p(s);s[X]=' ';}while(0)  // Define x(X) to print X spaces
                                                // This uses a string s full of
                                                // spaces and adds the null
                                                // terminator where approrpiate
char c[2][2]={95,47,92,'¯'};                    // 2d array of 'next arc' options
R;i;j;k;                                        // Variables
a(){                                            // a() -> print arc for row R
    char s[2]={92,0};                           // s is a string of next char
                                                // initialize to backslash
    for(j=0;j<2*R-1;++j                         // loop over each character
            ,p(s))                              // printing s each time
        *s=c[*s<50][rand()%2];                  // set s to the next arc char
    *s=c[*s<50][0];                             // set s to the 'first' arc char
                                                // note that in definition of c
                                                // first means appropriate as
                                                // final character before /
    p(s);}                                      // print the last character
f(H,N){                                         // f(H,N) -> print jacob ladder
    char s[99];for(i=0;i<99;++i)s[i]=' ';       // this is the space string for x
    p("\e[s");                                  // ANSI terminal save position
    for(i=0;;++i){i%=(N?N:i+1);                 // loop i->N (or i->INT_MAX if N=0)
        srand(i^H^N);                           // seed random with i XOR H XOR N
        for(k=1;k<H;++k){                       // for each row (bottom to top)
            for(R=H;--R;){                      // for each row (top to bottom)
                x(H-R+1);p("\\");               // print left "    \"
                if(R==k)                        // if on the arc row
                    a();                        // print the arc
                else x(2*R);                    // otherwise print spaces
                p("/\n");}                      // finish off the row
            x(H);p(" ¯¯\n\e[u");}}}             // print bottom line and move back

หมายเหตุ: ใช้งานได้จริงใน Xterm ... เทอร์มินัลอีมูเลเตอร์จำนวนมากไม่รองรับตำแหน่งบันทึก / กู้คืน
LambdaBeta

แถวด้านล่างคือแถว 0 และมีสอง macrons เท่านั้น \--/มันไม่ได้เป็น นั่นอาจเป็นการแก้ไขที่ง่าย คุณสามารถจับภาพและโพสต์ GIF ที่ทำงานใน Xterm ได้หรือไม่?
Engineer Toast

น่าเศร้าที่ฉันไม่มีเครื่องมือในการทำเช่นนั้น (แค่เล่นในช่วงเวลาที่ทำงาน) ฉันจะอัปเดตด้วยแถวที่ถูกต้อง 0 แม้ว่าจะเป็นการแก้ไขที่ง่าย
LambdaBeta

ไม่ถูกต้อง: ควรมี [เป็น] หนึ่งเฟรมของบันไดขั้นพื้นฐาน (โดยไม่มีส่วนโค้ง) ก่อนที่จะเริ่มการอาร์คใหม่ (ไม่จำเป็นก่อนการอาร์คครั้งแรก)
wastl

การเปลี่ยน k = 1 ถึง k = 0 แก้ไขที่ ... 0 ไบต์ค่าใช้จ่าย จะอัปเดตในไม่ช้า
LambdaBeta

2

PowerShell , 347 319 ไบต์

filter c{Param($h,$n)if($n-eq0){$n=-1}for($x=0;$x++-ne$n;){($h..1)|%{$l=(($h..1)|%{"$(" "*($h-$_))\$(" "*$_*2)/"})+"$(" "*$h)¯¯"
$r="Get-Random"
$i=0
$z=-join((0..(($h-$_)*2))|%{$i=switch($i%3){0{&$r 0,1}default{&$r 2,3}}"_/¯\"[$i]})+"_\\_"[$i]
$l[$_-1]=($l[$_-1]).Substring(0,$_)+"$z/"
cls
$l
Sleep -m 250}}}

ลองออนไลน์! ไม่สามารถ$argsเล่นได้ดีดังนั้นลิงก์จึงเรียกใช้ฟังก์ชันโดยไม่ต้องล้างคอนโซล

Ungolfed

filter c{
    Param($h,$n)
    if($n -eq 0){$n=-1} # inelegant swap to allow for an infinite loop. 
                        # Curse you zero-indexing!
    for($x=0;$x++-ne$n;)
    {
        ($h..1) | % {         
            $l=(($h..1)|%{ # (( double paren is needed to induce each line 
                           # as a new array element
                "$(" "*($h-$_))\$(" "*$_*2)/" # offset by total height. 
                                              # N spaces + rung + N*2 spaces + rung
            })+"$(" "*$h)¯¯" # last line is the floor of the ladder

            $r="Get-Random" # shorter to declare once and execute with & operator

            $i=0 # initialize $i so we choose only _ or / for the first char

            $z=-join( # build an electric ZAP!
                (0..(($h-$_)*2))|%{                    
                    $i = switch($i%3) { # choose next char based on previous selection
                        0{&$r 0,1}
                        default{&$r 2,3}
                    }    
                    "_/¯\"[$i]
                }
            )+"_\\_"[$i] # final char is \ or _ to rejoin the ladder        
            $l[$_-1]=($l[$_-1]).Substring(0,$_)+"$z/" # select one rung of the ladder 
                                                      # append an electric ZAP!                
            cls # clear the console
            $l  # display the ladder
            Sleep -m 250
        }
    }
}

มันเป็นเรื่องเล็ก แต่แถวล่างเป็นยัติภังค์แทนที่จะเป็น macrons มันเป็นการเปลี่ยนแปลงแบบ zero-byte$l=(($h..1)|%{"$(" "*($h-$_))\$(" "*$_*2)/"})+"$(" "*$h)¯¯"
วิศวกร Toast

1
¯ \ (° _o) / ¯อุ๊ปส์! สลับเป็น macrons: p
Peter Vandivier

1
ฉันไม่รู้จัก PowerShell ดีเกินไป แต่คุณสามารถลบบรรทัดใหม่ได้เกือบทั้งหมด นอกจากนี้สามารถfor($x=0;$x-ne$n;$x++) for($x=0;$x++-ne$n;)ฉันทำได้ถึง324 ไบต์ (321 ตัวอักษร)ทำเช่นนั้น เคล็ดลับสำหรับการเล่นกอล์ฟใน <ทุกภาษา>และเคล็ดลับสำหรับการเล่นกอล์ฟใน PowerShellอาจน่าสนใจสำหรับการอ่านเช่นกัน
Kevin Cruijssen

1
sleep 1ประหยัดเล็กน้อย (เป็นค่าเริ่มต้นที่ - สองวินาที) แต่ค่อนข้างช้า แต่ก็ยังสมเหตุสมผล - ish sleep -m 99ค่อนข้างเร็ว แต่ก็สมเหตุสมผล บันทึก 5/1 ไบต์ขึ้นอยู่กับสิ่งที่คุณต้องการ ไม่ได้ตรวจสอบความพยายามของเควิน แต่functionจะfilterเป็นไบต์ฟรีเช่นกัน
Veskah

1

Rubyขนาด 293 ไบต์

m={}
"   __/\\_/¯¯\\/¯\\".chars.each_slice(3){|e|u,*v=e;m[u]=v}
a=->l,c{l<1?"/":(d=m[c].sample;c+a[l-1,d])}
n=gets.to_i
h=gets.to_i
o=0
while o<n||n<1
h.times{|i|puts (0...h).map{|j|" "*j+"\\"+a[2*(h-j),i==h-j-1?["_","/"].sample: " "]}*"\n";puts" "*h+"¯¯";sleep(0.3);puts"\n"*99}
o+=1
end

ลองออนไลน์!

ฉันอยู่บนหน้าต่างดังนั้นจึงพิมพ์ "\ n" จำนวนมากเพื่อล้างคอนโซล รับอาร์กิวเมนต์ 2 ตัวnและhเป็นสองบรรทัดบน stdin

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.