Синусоїдальний текст ASCII-анімації


11

Мені дещо не вистачає тих старих демонстрацій, які показують можливості комп'ютерів, коли їх називали x86 замість i3, i5 та i7. Однією з перших, яку я переглянув у своєму 386 році, була демонстрація Unreal від Future Crew, яка зараз святкує своє 25-річчя. У хвилині 0:43 починається перша частина демонстрації, і ми бачимо прокручуваний текст, що йде за синусоїдальним шляхом. Спробуємо наслідувати цей ефект у мистецтві ASCII!

Змагання

З огляду на цей шлях:

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

і вхідний текст, намалюйте текст наступним шляхом:

Thi                                Golf! 
   s i                          de       Yay
      s                       Co            !
        P                     
         r                  d
         o                  n
          g                a
           ra            s 
             mmi      zle
                ng Puz

Зауважте, що пробіли вважаються символами на шляху, і шлях повторюється, якщо текст довший за зразок.

Анімаційна частина

Після того, як ви намалювали текст, зачекайте 100 мс (щоб створити анімацію близько 10 кадрів в секунду) і знову намалюйте текст, але починаючи з наступної позиції шляху. Отже, для кадру #nобчисліть n modulo 40і починайте малювати в наступному положенні шляху з текстом, завжди вирівняним зліва від полотна:

***                                ***
|  ***                          ***  |
|     **                      **     |
|       *                    *       |
|        *                  *        |
|        *                  *        |
|         *                *         |
|          **            **          |
|            ***      ***            |
|               ******               |
Position 0                 Position 39

Отже, для кадру 10 у нас буде:

                           and Co
                        es       de 
                      zl            Go
                     z                l
                    u                  f
T                   P                  !
 h                                       
  is             ng                       Ya
     is       mmi                           y!
        Progra

Примітки

  • Вхід буде одним string(або charмасивом, будь-яким) із текстом для анімації, і завжди матиме щонайменше 1 символ.
  • Дійсні символи для анімації - це ті, що містяться в наборі ASCII для друку .
  • Шлях, який слід слідувати, буде точно таким, як зазначено.
  • Текст завжди буде вирівнюватися зліва від полотна, тому ефектом буде текст, який махає як прапор, без зміщення тексту. Під полотном я маю на увазі екран або все, що ви використовуватимете для показу тексту . ;-)
  • Кадри повинні бути без будь-яких символів / пікселів з попередніх кадрів, якщо символ / піксель не є однаковим в обох кадрах.
  • Швидкість анімації не має значення, поки вона працює плавно або настільки швидко, наскільки може ваш пристрій (ми можемо встановити як мінімум 5 кадрів в секунду, але це не є вимогою). Просто відрегулюйте швидкість, щоб вона стала текучою, і не переживайте, якщо тривалість очікування точно не однакова.
  • Анімація буде нескінченною.

Це , тому може виграти найкоротша програма або функція, здатна анімувати текст!



1
Я можу порахувати 38 стовпців, а не 40.
Арнольд

1
@Arnauld це тому, що підраховують позиції на шляху, а не стовпці.
Чарлі

О Я бачу. Має сенс.
Арнольд

Є чи це добре , як вихід? Він відображає вхід у вигляді синусоїдальної хвилі і нескінченно замикається. Звичайно, оскільки відео у форматі Graphics Interchange, воно швидше в дійсності.
Р. Кап

Відповіді:


9

HTML + ES6, 241 244 237 байт

Зламатися:

  • HTML: 16 байт
  • Функція JS: 221 байт

let f =

s=>setInterval(_=>o.innerHTML=[...s].map((c,i)=>([j,y]=[...Array(40)].map((_,k)=>[j=k%20,y,y+=77732>>j&1?k<20||-1:0],y=0)[(i+p)%40],a[y]=a[y]||[...s].fill` `)[x]=(x+=j!=9,c),x=0,a=[],p++)&&a.map(r=>r.join``).join`
`,p=30)

f("This is Programming Puzzles and Code Golf! Yay!")
<pre id=o></pre>

Як?

Побудова шляху

Наступний код будує шлях:

[...Array(40)].map((_, k) =>
  [
    j = k % 20,
    y,
    y += 77732 >> j & 1 ? k < 20 || -1 : 0
  ],
  y = 0
)

Це дає масив масивів, [j, y, z]де j - модуль позиції 20, y - координата y в цьому положенні, а z не використовується пізніше (це просто відбувається обчислення тут, щоб зберегти деякі байти).

Оскільки шлях симетричний, нам потрібно лише кодувати 20 перших позицій. Ми робимо це, використовуючи двійкове число, де кожен 1біт означає, що y має бути оновлено (+1 для першої половини, -1 для другої половини).

001
   001
      01
        1
         1
         1
          1
           01
             001
                000

Коли перша позиція відображається на найменш значущий біт, це дає:

00010010111110100100 as binary = 77732 as decimal

Оскільки це бінарне число також само по собі є симетричним, ми можемо читати його в тому самому порядку для 2-ї половини.

Звідси формула:

y += (77732 >> j) & 1 ? (k < 20 ? 1 : -1) : 0

який також можна записати як:

y += (77732 >> j) & 1 ? k < 20 || -1 : 0

де k - положення, а j - модуль положення 20.

Оновлення x набагато простіше: ми просто маємо один особливий випадок для виявлення, порівнюючи позиційний модуль 20 з 9.

Малювання тексту

У наступному коді описаний вище код побудови шляху замінено pathзмінною для читабельності.

s => setInterval(                       // set a periodic timer:
  _ =>                                  //   with an anonymous callback
    o.innerHTML =                       //   which updates the content of 'o'
      [...s].map((c, i) => (            //   for each character c of the string s
          [j, y] = path[(i + p) % 40],  //     retrieve j and y from the path
          a[y] = a[y] || [...s].fill` ` //     initialize a[y] if it's undefined
        )[x] = (x += j! = 9, c),        //     update a[y][x] / update x
        x = 0,                          //     initialize x
        a = [],                         //     initialize a[]
        p++                             //     increment the phase
      ) &&                              //   end of map()
      a.map(r => r.join``).join`\n`,    //   join everything together
  p = 30                                //   initial phase = interval period = 30
)                                       // end of timer definition

Це геніально, і досить близько до заданого шляху, але шлях не зовсім той, який я намалював. Два стовпчики, які містять два *у вертикалі, не вирівнюються (на однаковій висоті), а інший невеликий ниткою. Але мушу сказати, що я досі не знаю, як ваш код створює хвильовий ефект (що y+=155464робити?). Вітаємо!
Чарлі

@CarlosAlejo Я думаю, що тепер слід виправити шлях. Чи можете ви подвійно перевірити? Я додам пояснення використовуваного методу.
Арнольд

1
Шлях перевірений, і дуже дякую за пояснення!
Чарлі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.