正弦ASCII艺术动画文本


11

我有点想念那些展示计算机功能的旧演示,它们被称为x86而不是i3,i5和i7。我第一次在386上观看的电影之一是Future CrewUnreal演示,它正在庆祝其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 fps的动画)并从路径的下一个位置开始再次绘制文本。因此,对于frame #nn 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 fps,但这不是必须的)。只需调整速度使其流畅即可,不必担心等待时间不完全相同。
  • 动画将无限循环。

这是,所以最能使文本动画的程序或功能可能会赢!



1
我可以指望38列,而不是40
阿尔诺

1
@Arnauld那是因为重要的是路径中的位置,而不是列中的位置。
查理

原来如此。说得通。
Arnauld

这个没关系,输出?它以正弦波的形式显示输入并无限循环。当然,由于视频采用图形交换格式,因此实际速度更快。
R. Kap

Answers:


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

由于该二进制数本身也是对称的,因此我们可以在第二个一半中以相同的顺序读取它。

因此,公式为:

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我认为现在应该固定路径。你能再检查一遍吗?我将对使用的方法进行解释。
Arnauld

1
路径已检查,非常感谢您的解释!
查理
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.