Windows MEスクリーンセーバーをASCIIとして再作成します


19

この課題は、Ask Ubuntu Stack Exchangeでのこの回答から着想を得てます。

イントロ

パイプを使用し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つの値に組み合わせることができます。画面の幅と高さの最小値は常に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のボーナスupvotes;)

ハッピーゴルフ!

免責事項:Unicode文字はASCIIではないことを承知していますが、より良い名前がないため、単にASCIIアートと呼びます。提案は大歓迎です:)


9
出力に必要なUnicode文字はASCIIではありません。
小麦ウィザード

2
私は、これがタグ付けされるべきだと思うascii-artの代わりにgraphical-output- 参照
AdmBorkBork

13
ノスタルジアWindowsのMEは、同じ行にうまく適合しない
ルイスMendo

1
3D Pipesスクリーンセーバーは、Windows MEより前のバージョンです。
ニール

1
@ジョーダン私は彼がタプルを意味すると思った。
カールカストール

回答:


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、に展開されますが、まったく同じように実行されるはずです。

プログラムは、目盛り、幅、高さの3つのコンマ区切り値を入力します。次に、乱数シードを要求します。(この動作が許容できない場合は、2行目RANDOMIZE TIMERを+6バイトに変更します。)最後に、画面にパイプを描画します。

入力できる最大寸法は、80(幅)x 25(高さ)です。高さを25にすると、QBasicが「続行するには任意のキーを押してください」と言ったときに一番下の行が切り取られます。

どうやって?

TL; DR:多くの数学。

現在の行と列はrand cです。現在の方向はdで、前の方向はbです。方向の値0〜3は、下、右、上、左です。算術演算は、これらをおよびの正しいステップ値、rおよびc開始する正しいエッジ座標に変換します。

ボックス描画文字│┐└─┘┌は、QBasicのコードポイント179、191、192、196、217、および218です。それらはかなりランダムに見えますが、いくつかの条件付きステートメントを実行するよりも、いくつかの(かなり複雑で、私は確信していません)数学で数値を生成するためにまだ少ない文字を使用しています。

方向を変更するためのコードは、-0.125から1.125の間の乱数を生成し、下限を取得します。これにより-1、時間の10%、時間の080%、時間の10%が得られ1ます。次に、これをdmod 4の現在の値に追加します。0を追加すると、現在の方向が維持されます。+/- 1を追加するとターンします。

制御フローに関してWHILE t ... WENDは、メインループです。その前のセクションは、行番号11b=INT(RND*4))で始まり、ランダムなエッジでパイプを再起動します。たびrc、窓の外に私たちです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にこれを入力しました:-)
ニール

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ミリ秒の遅延で各ステップを印刷します。

  • @TuukkaXのおかげで-10バイト

それを繰り返す

実行例

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 orます。0.5に減らすことができます.5import *可能性がありますimport*''.join(k) for無駄な空白があります。またdict、変数を保持し、使用するたびに呼び出すこともできるはずです。これがどれだけ節約されるかをテストしていませんdict(zip(a,b))が、2つの文字列(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;}

単一の4ビット数で方向を格納するためのedc65の功績。

スクリーンセーバーを永久にループする前に、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

...次に、ラムダを変数egに割り当て、次の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]
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.