重新创建Windows ME屏幕保护程序为ASCII


19

这种挑战来自灵感这个答案在向Ubuntu的堆栈交换。

介绍

还记得带有管道Windows ME屏幕保护程序吗?是时候带回怀旧了!

在此处输入图片说明

挑战

您应该编写一个程序或函数来输出屏幕保护程序的ASCII表示。在屏幕保护程序中,应该有一个沿半随机方向增长的管道。
管道的起点将随机放置在屏幕的任何边界处,并且管件应垂直于边界(拐角的第一根管道可以是水平的也可以是垂直的)。每次滴答时,管道都会朝着其面对的方向(水平/垂直)生长,80%或者会偶然发生拐角20%

管道表示

要创建管道,将使用6个unicode字符

─    \u2500    horizontal pipe
│    \u2502    vertical pipe
┌    \u250C    upper left corner pipe
┐    \u2510    upper right corner pipe
└    \u2514    lower left corner pipe
┘    \u2518    lower right corner pipe

输入项

程序/功能将采用3个输入值,这些值可以通过功能参数收集或提示给用户。

  • 刻度线数量
  • 屏幕宽度
  • 屏幕高度

刻度线数量

对于每个刻度,都会在屏幕上添加一条管道。如果管道在同一位置生成,管道将覆盖旧管道。

例如,以3x3大小的屏幕

ticks == 3
─┐ 
 ┘ 


ticks == 4
─┐ 
└┘ 


ticks == 5
│┐ 
└┘ 

每当管道退出屏幕时(如上一个示例中的5个滴答所示),就会在随机边界处生成一个新管道。例如:

ticks == 6
│┐ 
└┘ 
  ─

新管道应具有50%的水平或垂直机会。

屏幕宽度/高度

如果您选择的语言更可取,则屏幕宽度和高度可以合并为一个值。屏幕的宽度和高度将始终具有最小值1和最大值255。如果您选择的语言支持的控制台或输出屏幕小于255x255的字符网格,则可以假定宽度和高度将为永远不要超出控制台的界限。(例如:Windows 80x25 cmd窗口)

输出量

程序/函数的输出应打印到屏幕上,或从函数返回。对于程序的每次运行,应生成一组不同的管道。

测试用例

以下测试用例均为有效输出的随机示例

f(4, 3, 3)
 │
─┘
  │

f(5, 3, 3)
 │
─┘┌
  │

f(6, 3, 3)
─│
─┘┌
  │

f(7, 3, 3)
──
─┘┌
  │

显然,出现的滴答声越多,证明程序有效性的难度就越大。因此,最好发布运行输出的gif文件。如果无法做到这一点,请发布您的代码版本,其中包括打印输出。显然,这不会计入您的分数。

规则

  • 这是,最短的字节数获胜
  • 适用标准漏洞
  • 如果您在源代码中使用unicode管道字符,则可以将它们视为一个字节

这是一个相当艰巨的挑战,可以通过许多创造性的方法来解决,尽管已经有简短的解决方案,但仍鼓励您用更加冗长的语言编写答案。这将创建每种语言的最短答案的目录。花式彩色gif的奖金投票;)

打高尔夫球快乐!

免责声明:我知道Unicode字符不是ASCII,但是由于缺少更好的名称,我将其称为ASCII艺术。欢迎提出建议:)


9
您要在输出中使用的unicode字符不是ASCII。
小麦巫师

2
我认为这应该加标签,ascii-art而不是graphical-output- 参考
AdmBorkBork

13
怀旧Windows ME不太适合在同一条线上
Luis Mendo

1
3D Pipes屏幕保护程序早于Windows ME。
尼尔

1
@乔丹我以为他的意思是元组。
KarlKastor

Answers:


9

的JavaScript(ES6),264 266 274 281

(t,w,h,r=n=>Math.random()*n|0,g=[...Array(h)].map(x=>Array(w).fill` `))=>((y=>{for(x=y;t--;d&1?y+=d-2:x+=d-1)x<w&y<h&&~x*~y?0:(d=r(4))&1?x=r(w,y=d&2?0:h-1):y=r(h,x=d?0:w-1),e=d,d=r(5)?d:2*r(2)-~d&3,g[y][x]="─└ ┌┐│┌  ┘─┐┘ └│"[e*4|d]})(w),g.map(x=>x.join``).join`
`)

将unicode绘图字符计数为每个1字节。(由OP指定)

少打高尔夫球

(t,w,h)=>{
  r=n=>Math.random()*n|0; // integer range random function
  g=[...Array(h)].map(x=>Array(w).fill(' ')); // display grid
  for (x=y=w;t--;)
    x<w & y<h && ~x*~y||( // if passed boundary
      d = r(4), // select random direction
      d & 1? (x=r(w), y=d&2?0:h-1) : (y=r(h), x=d?0:w-1) // choose start position 
    ),
    e=d, d=r(5)?d:2*r(2)-~d&3, // change direction 20% of times
    g[y][x]="─└ ┌┐│┌  ┘─┐┘ └│"[e*4|d], // use char based on current+prev direction
    d&1 ? y+=d-2 : x+=d-1 // change x,y position based on direction
  return g.map(x=>x.join``).join`\n`
}

动画测试

注意:尝试将动画时间保持在30秒以下,更厚的动画会使动画速度更快

f=(t,w,h,r=n=>Math.random()*n|0,g=[...Array(h)].map(x=>Array(w).fill` `))=>
{
  z=[]
  for(x=y=w;t--;d&1?y+=d-2:x+=d-1)
    x<w&y<h&&~x*~y?0:(d=r(4))&1?x=r(w,y=d&2?0:h-1):y=r(h,x=d?0:w-1),
    e=d,d=r(5)?d:2*r(2)-~d&3,g[y][x]="─└ ┌┐│┌  ┘─┐┘ └│"[e*4|d],
    z.push(g.map(x=>x.join``).join`\n`)
  return z
}

function go() {
  B.disabled=true
  var [t,w,h]=I.value.match(/\d+/g)
  var r=f(+t,+w,+h)
  O.style.width = w+'ch';
  var step=0
  var animate =_=>{
    S.textContent = step
    var frame= r[step++]
    if (frame) O.textContent = frame,setTimeout(animate, 30000/t);
    else   B.disabled=false
  }
  
  animate()
}

go()
#O { border: 1px solid #000 }
Input - ticks,width,height
<input value='600,70,10' id=I><button id=B onclick='go()'>GO</button>
<span id=S></span>
<pre id=O></pre>


就在我以为QBasic可能真正赢得高尔夫挑战赛时。;)进行投票。
DLosc

12

没有什么可以说怀旧了……

QBasic,332个字节

INPUT t,w,h
RANDOMIZE
CLS
1b=INT(RND*4)
d=b
IF b MOD 2THEN c=(b-1)/2*(w-1)+1:r=1+INT(RND*h)ELSE c=1+INT(RND*w):r=b/2*(h-1)+1
WHILE t
LOCATE r,c
m=(b+d)MOD 4
IF b=d THEN x=8.5*m ELSE x=13*m+(1<((b MOD m*3)+m)MOD 5)
?CHR$(179+x);
r=r-(d-1)MOD 2
c=c-(d-2)MOD 2
b=d
d=(4+d+INT(RND*1.25-.125))MOD 4
t=t-1
IF(r<=h)*(c<=w)*r*c=0GOTO 1
WEND

QBasic是适合该任务的语言,因为:

  • 它的编码包括方框图字符-无需Unicode
  • LOCATE 允许您打印到屏幕上的任何位置,覆盖以前的内容
  • 微软®

细节

这是高尔夫QBasic,在自动格式化关闭的情况下在QB64上编写和测试。如果将其键入/粘贴到实际的QBasic IDE中,它将添加一堆空格并扩展?PRINT,但是它应该运行完全相同。

程序输入三个逗号分隔的值:刻度,宽度和高度。然后,它要求一个随机数种子。(如果这种行为是不可接受的,请将第二行更改RANDOMIZE TIMER为+6个字节。)最后,它将管道绘制到屏幕上。

可以输入的最大尺寸为80(宽度)乘25(高度)。当QBasic说“按任意键继续”时,将高度设置为25将导致最下面一行被截断。

怎么样?

TL; DR:很多数学。

当前的行和列是rc; 当前方向是d,前一个方向是b。方向值0-3是向下,向右,向上,向左。算术运算将这些值转换为r和的正确步长值c以及开始的正确边缘坐标。

盒子绘图字符 │┐└─┘┌是QBasic中的代码点179、191、192、196、217和218。那些看起来很随机,但是与使用一堆条件语句相比,它使用更少的字符来生成带有一些(相当复杂,我什至不能理解)数学的数字。

用于更改方向的代码生成-0.125和1.125之间的随机数,并取其底值。这给出了-110%的时间,080%的时间和110%的时间。然后,将其与dmod 4 的当前值相加。加0会保持当前方向;反之亦然。加+/- 1会转一圈。

至于控制流程,则WHILE t ... WEND是主循环。从行号11b=INT(RND*4))开始的前一段在任意边重新启动管道。无论何时r,只要c不在窗外,我们GOTO 1

给我看看GIF!

干得好:

管道!

这是由带有动画,颜色和自动随机种子的略显粗糙的版本生成的:

INPUT t, w, h
RANDOMIZE TIMER
CLS

restart:
' Calculate an edge to start from

b = INT(RND * 4)
'0: top edge (moving down)
'1: left edge (moving right)
'2: bottom edge (moving up)
'3: right edge (moving left)
d = b

' Calculate column and row for a random point on that edge
IF b MOD 2 THEN
    c = (b - 1) / 2 * (w - 1) + 1
    r = 1 + INT(RND * h)
ELSE
    c = 1 + INT(RND * w)
    r = b / 2 * (h - 1) + 1
END IF
COLOR INT(RND * 15) + 1

WHILE t
    ' Mathemagic to generate the correct box-drawing character
    m = (b + d) MOD 4
    IF b = d THEN
        x = 17 * m / 2
    ELSE
        x = 13 * m + (1 < ((b MOD m * 3) + m) MOD 5)
    END IF
    LOCATE r, c
    PRINT CHR$(179 + x);

    ' Update row and column
    r = r - (d - 1) MOD 2
    c = c - (d - 2) MOD 2
    ' Generate new direction (10% turn one way, 10% turn the other way,
    ' 80% go straight)
    b = d
    d = (4 + d + INT(RND * 1.25 - .125)) MOD 4

    ' Pause
    z = TIMER
    WHILE TIMER < z + 0.01
        IF z > TIMER THEN z = z - 86400
    WEND

    t = t - 1
    IF r > h OR c > w OR r = 0 OR c = 0 THEN GOTO restart
WEND

我已经将此输入到我的MS-DOS v6.22 VM中:-)
Neil

9

Python 2.7版,624个 616 569 548 552字节

from random import*
from time import*
i=randint
z=lambda a,b:dict(zip(a,b))
c={'u':z('lur',u'┐│┌'),'d':z('ldr',u'┘│└'),'l':z('uld',u'└─┌'),'r':z('urd',u'┘─┐')}
m=z('udlr',[[0,-1],[0,1],[-1,0],[1,0]])
def f(e,t,w,h):
 seed(e);s=[w*[' ',]for _ in' '*h]
 while t>0:
  _=i(0,1);x,y=((i(0,w-1),i(0,1)*(h-1)),(i(0,1)*(w-1),i(0,h-1)))[_];o=('du'[y>0],'rl'[x>0])[_]
  while t>0:
   d=c[o].keys()[i(7,16)//8];s[y][x]=c[o][d];x+=m[d][0];y+=m[d][1];t-=1;sleep(.5);print'\n'.join([''.join(k)for k in s]);o=d
   if(x*y<0)+(x>=w)+(y>=h):break

第一个参数是种子,相同的种子将生成相同的输出,并以500毫秒的延迟打印每个步骤。

  • -10个字节,感谢@TuukkaX

重复

运行示例

f(5,6,3,3)

将输出

   

 ─┐ 
   

──┐ 
   

┘─┐ 
   
┐  
┘─┐ 

详细版本

import random as r
from time import *
char={
'u':{'u':'│','l':'┐','r':'┌'},
'd':{'d':'│','l':'┘','r':'└'},
'l':{'u':'└','d':'┌','l':'─'},
'r':{'u':'┘','d':'┐','r':'─'}
}
move={'u':[0,-1],'d':[0,1],'l':[-1,0],'r':[1,0]}
def f(seed,steps,w,h):
 r.seed(seed)
 screen=[[' ',]*w for _ in ' '*h]
 while steps > 0:
  if r.randint(0,1):
   x,y=r.randint(0,w-1),r.randint(0,1)*(h-1)
   origin='du'[y>0]  
  else:
   x,y=r.randint(0,1)*(w-1),r.randint(0,h-1)
   origin = 'rl'[x>0]
  while steps > 0:
   direction = char[origin].keys()[r.randint(0,2)]
   screen[y][x]=char[origin][direction]
   x+=move[direction][0]
   y+=move[direction][1]
   steps-=1
   sleep(0.5)
   print '\n'.join([''.join(k) for k in screen]),''
   if x<0 or y<0 or x>=w or y>=h:
    break
   origin=direction

1
处有一个无用的空格if x*y<0 or0.5可以减少到.5import *可能是import*''.join(k) for有一个无用的空格。您还应该保留dict一个变量,并在每次使用它时调用它。还没有测试这可以节省多少,但是通过将dict(zip(a,b))lambda 保存为两个字符串(a,b)可以完成的工作,它应该砍掉一些。+1。
Yytsi

7

C(GCC / Linux)的,402 353 352 302 300个 298 296 288字节

#define R rand()%
x,y,w,h,r;main(c){srand(time(0));scanf(
"%d%d",&w,&h);for(printf("\e[2J");x%~w*
(y%~h)||(c=R 8,(r=R 4)&1?x=1+R w,y=r&2
?1:h:(y=1+R h,x=r&2?1:w));usleep('??'))
printf("\e[%dm\e[%d;%dH\342\224%c\e[H\n",
30+c,y,x,2*"@J_FHAF__L@HL_JA"[r*4|(r^=R 5
?0:1|R 4)]),x+=--r%2,y+=~-r++%2;}

归功于edc65,用于将方向存储在单个4位数字中。

在永久循环屏幕保护程序之前,读取stdin上的宽度/高度。例如:

gcc -w golf.c && echo "25 25" | ./a.out

或对于全屏屏保:

gcc -w golf.c && resize | sed 's/[^0-9]*//g' | ./a.out

为了提高可读性,我添加了换行符。需要一台带有遵守ANSI代码的终端的Linux机器。有颜色!如果删除颜色支持,则它将减少17个字节。

例


5

红宝石,413个 403 396字节

红宝石管

该函数接受多个刻度线和一个宽度作为输入,并以字符串形式返回最终屏幕。无疑可以打更多的球。

->t,w{k=[-1,0,1,0,-1]
b=(" "*w+$/)*w
f=->t,a=[[0,m=rand(w),2],[w-1,m,0],[m,0,1],[m,w-1,3]].sample{n,m,i=a
d=k[i,2]
q=->n,m,i{_,g,j=rand>0.2?[[1,0],[3,0],[0,1],[2,1]].assoc(i):"021322033132243140251350".chars.map(&:to_i).each_slice(3).select{|c,|c==i}.sample
v,u=k[j||=i,2]
y=n+v
x=m+u
[g,y,x,j]}
g,y,x,j=q[n,m,i]
b[n*w+n+m]="─│┌┐┘└"[g]
y>=0&&y<w&&x>=0&&x<w ?t>1?f[t-1,[y,x,j]]:b:f[t]}
f[t]}

在repl.it上查看:https ://repl.it/Db5h/4

为了看到它的实际效果,请在开始的行之后插入以下内容b[n*w+n+m]=

puts b; sleep 0.2

...然后将lambda分配给一个变量,例如pipes=->...,调用它pipes[100,20](进行100次滴答和20x20的屏幕显示)。

取消说明

# Anonymous function
# t - Number of ticks
# w - Screen width
->t,w{
  # The cardinal directions ([y,x] vectors)
  # Up = k[0..1], Right = k[1..2] etc.
  k = [-1, 0, 1, 0, -1]

  # An empty screen as a string
  b = (" " * w + $/) * w

  # Main tick function (recursive)
  # t - The number of ticks remaining
  # a - The current position and vector index; if not given is generated randomly
  f = ->t,a=[[0,m=rand(w),2], [w-1,m,0], [m,0,1], [m,w-1,3]].sample{
    # Current row, column, and vector index
    n, m, i = a
    d = k[i,2] # Get vector by index

    # Function to get the next move based on the previous position (n,m) and direction (d)
    q = ->n,m,i{
      # Choose the next pipe (`g` for glyph) and get the subsequent vector index (j)
      _, g, j = (
        rand > 0.2 ?
          [[1,0], [3,0], [0,1], [2,1]].assoc(i) : # 80% of the time go straight
          "021322033132243140251350".chars.map(&:to_i).each_slice(3)
            .select{|c,|c==i}.sample
      )

      # Next vector (`v` for vertical, `u` for horizontal)
      # If straight, `j` will be nil so previous index `i` is used
      v, u = k[j||=i, 2]

      # Calculate next position
      y = n + v
      x = m + u

      # Return next glyph, position and vector index
      [g, y, x, j]
    }

    # Get next glyph, and subsequent position and vector index
    g, y, x, j = q[n, m, i]

    # Draw the glyph
    b[n * w + n + m] = "─│┌┐┘└"[g]

    # Check for out-of-bounds
    y >= 0 && y < w && x >=0 && x < w ?
      # In bounds; check number of ticks remaining
      t > 1 ?
        f[t-1, [y,x,j]] : # Ticks remain; start next iteration
        b : # No more ticks; return final screen

      # Out of bounds; repeat tick with new random start position
      f[t]
  }
  f[t]
}
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.