Ponownie uruchom wygaszacz ekranu systemu Windows ME jako ASCII

19

To wyzwanie jest inspirowane odpowiedzią na Ask Ubuntu Stack Exchange.

Wprowadzenie

Pamiętasz wygaszacz ekranu Windows ME z potokami ? Czas przywrócić nostalgię!

wprowadź opis zdjęcia tutaj

Wyzwanie

Powinieneś napisać program lub funkcję, która wyświetli reprezentację wygaszacza ekranu ASCII. W wygaszaczu ekranu powinna znajdować się pojedyncza rura, która będzie rosła w pół losowych kierunkach.
Początek rury zostanie losowo umieszczony na dowolnej krawędzi ekranu, a element rury powinien być prostopadły do ​​granicy (pierwsze narożne rury mogą być poziome lub pionowe). Przy każdym kleszczu rura będzie rosła w kierunku, w którym jest skierowana (poziomo / pionowo), przy 80%okazji lub rzutu rożnego przy 20%okazji.

Reprezentacja rur

Do utworzenia potoku zostanie użytych 6 znaków 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

Wejście

Program / funkcja pobierze 3 wartości wejściowe, które można zebrać na podstawie parametrów funkcji lub zapytać użytkownika.

  • Ilość kleszczy
  • Szerokość ekranu
  • Wysokość ekranu

Ilość kleszczy

Dla każdego tiku do ekranu zostanie dodany kawałek rury. Rury zastąpią stare elementy rur, jeśli odradzają się w tej samej pozycji.

Na przykład weź ekran o rozmiarze 3x3

ticks == 3
─┐ 
 ┘ 


ticks == 4
─┐ 
└┘ 


ticks == 5
│┐ 
└┘ 

Za każdym razem, gdy rura wychodzi z ekranu, jak w ostatnim przykładzie z 5 tyknięciami, nowa rura odradza się na losowej granicy. Na przykład:

ticks == 6
│┐ 
└┘ 
  ─

Nowa rura powinna mieć 50% szansy, że będzie pozioma lub pionowa.

Szerokość / wysokość ekranu

Szerokość i wysokość ekranu można połączyć w jedną wartość, jeśli jest to preferowane w wybranym języku. Szerokość i wysokość ekranu zawsze będą miały minimalną wartość 1 i maksymalną wartość 255. Jeśli wybrany język obsługuje ekran konsoli lub wyjścia, który jest mniejszy niż siatka znaków 255 x 255, możesz założyć, że szerokość i wysokość będą nigdy nie przekraczaj granic konsoli. (Przykład: okno systemu Windows 80x25 cmd)

Wynik

Dane wyjściowe programu / funkcji powinny zostać wydrukowane na ekranie lub zwrócone z funkcji. Dla każdego uruchomienia programu należy wygenerować inny zestaw potoków.

Przypadki testowe

Poniższe przypadki testowe są przypadkowymi przykładami prawidłowych wyników

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

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

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

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

Oczywiście, im więcej tyknięć miało miejsce, tym trudniej jest udowodnić ważność twojego programu. Dlatego preferowane będzie opublikowanie gif z uruchomionym wyjściem. Jeśli nie jest to możliwe, proszę opublikować wersję kodu, która obejmuje wydruk danych wyjściowych. Oczywiście nie będzie to wliczane do twojego wyniku.

Zasady

  • To jest , wygrywa najmniejsza ilość bajtów
  • Obowiązują standardowe luki
  • Jeśli użyjesz znaków potoku Unicode w kodzie źródłowym, możesz je policzyć jako jeden bajt

Jest to dość trudne wyzwanie, które można rozwiązać na wiele kreatywnych sposobów, zachęcamy do napisania odpowiedzi w bardziej szczegółowym języku, nawet jeśli odpowiedzi są już w krótkich esolangach. Spowoduje to utworzenie katalogu najkrótszych odpowiedzi dla każdego języka. Dodatkowe głosy za fantazyjne kolorowe gify;)

Miłej gry w golfa!

Uwaga: Zdaję sobie sprawę, że znaki Unicode nie są ASCII, ale ze względu na brak lepszej nazwy po prostu nazywam to sztuką ASCII. Sugestie są mile widziane :)

Bassdrop Cumberwubwubwub
źródło
9
Znaki Unicode, które chcesz w danych wyjściowych, nie są ASCII.
Wheat Wizard
2
Myślę, że to powinno być oznaczone ascii-artzamiast graphical-output- referencja
AdmBorkBork
13
Nostalgia i Windows ME nie pasują dobrze do tej samej linii
Luis Mendo
1
Wygaszacz ekranu z rur 3D wcześniejszy niż Windows ME.
Neil
1
@Jordan Myślałem, że miał na myśli krotki.
KarlKastor,

Odpowiedzi:

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`
`)

Liczenie znaków rysunkowych w Unicode jako 1 bajt każdy. (Jak określono przez OP)

Mniej golfa

(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`
}

Animowany test

Uwaga: starając się utrzymać czas animacji poniżej 30 sekund, więcej zagajników przyspiesza tempo animacji

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>

edc65
źródło
Właśnie wtedy, gdy pomyślałem, że QBasic może wygrać wyzwanie w golfa. ;) Poproś o opinię.
DLosc
12

Nic nie mówi o nostalgii tak jak ...

QBasic, 332 bajty

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 jest właściwym językiem dla tego zadania, ponieważ:

  • Jego kodowanie obejmuje znaki do rysowania w ramkach - nie wymaga Unicode
  • LOCATE pozwala drukować w dowolnym miejscu na ekranie, zastępując to, co było wcześniej
  • Microsoft ®

Specyfika

To jest gra w golfa QBasic, napisana i przetestowana na QB64 z wyłączonym autoformatowaniem. Jeśli wpiszesz / wkleisz do rzeczywistego IDE QBasic, doda kilka spacji i rozszerzy ?się PRINT, ale powinno działać dokładnie tak samo.

Program wprowadza trzy wartości oddzielone przecinkami: tiki, szerokość i wysokość. Następnie prosi o ziarno o losowej liczbie. (Jeśli to zachowanie jest nie do przyjęcia, zmień drugą linię RANDOMIZE TIMERna +6 bajtów.) Na koniec rysuje rury na ekranie.

Maksymalne wymiary, które można wprowadzić, to 80 (szerokość) na 25 (wysokość). Podanie wysokości 25 spowoduje odcięcie dolnego rzędu, gdy QBasic powie „Naciśnij dowolny klawisz, aby kontynuować”.

W jaki sposób?

TL; DR: Dużo matematyki.

Bieżącym wierszem i kolumną są ri c; obecny kierunek to di poprzedni kierunek to b. Wartości kierunku 0-3 są w dół, w prawo, w górę, w lewo. Arytmetyka przekłada te wartości na poprawne wartości kroku dla roraz c, a także na prawidłowe współrzędne krawędzi na początku.

Znaki rysujące ramki │┐└─┘┌to punkty kodowe 179, 191, 192, 196, 217 i 218 w QBasic. Wydają się dość losowe, ale nadal używało mniej znaków do generowania liczb z pewną matematyką (dość skomplikowaną, nie jestem pewien, a nawet rozumiem) niż do wykonywania szeregu instrukcji warunkowych.

Kod zmiany kierunku generuje liczbę losową z przedziału od -0,125 do 1,125 i zabiera głos. To daje -110% czasu, 080% czasu i 110% czasu. Następnie dodajemy to do bieżącej wartości dmod 4. Dodanie 0 utrzymuje bieżący kierunek; dodanie +/- 1 powoduje zwrot.

Jeśli chodzi o przepływ kontrolny, WHILE t ... WENDjest to główna pętla; sekcja przed nim, zaczynająca się od numeru linii 1( 1b=INT(RND*4)), ponownie uruchamia potok na losowej krawędzi. Ilekroć ri csą poza okno, my GOTO 1.

Pokaż mi GIF!

Proszę bardzo:

Rury!

Zostało to wygenerowane przez nieco nie golfową wersję z animacją, kolorem i automatycznym losowym ziarnem:

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
DLosc
źródło
Wpisałem to w mojej maszynie wirtualnej MS-DOS v6.22 :-)
Neil,
9

Python 2.7, 624 616 569 548 552 bajtów

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

Pierwszy parametr to ziarno, te same nasiona wygenerują tę samą moc wyjściową, drukując każdy krok z opóźnieniem 500 ms.

  • -10 bajtów dzięki @TuukkaX

zastąp to

Przykładowy przebieg

f(5,6,3,3)

wyjdzie

   

 ─┐ 
   

──┐ 
   

┘─┐ 
   
┐  
┘─┐ 

pełna wersja

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
Pręt
źródło
1
Jest bezużyteczny biały znak w if x*y<0 or. 0.5można zredukować do .5. import *może być import*. ''.join(k) forma bezużyteczne białe znaki. Powinieneś także mieć możliwość przechowywania dictzmiennej i wywoływania jej za każdym razem, gdy z niej korzystasz. Nie testowałem, ile to oszczędza, ale zapisując dict(zip(a,b))lambda, która wykonuje pracę dla dwóch łańcuchów (a, b), powinno trochę posiekać. +1.
Yytsi
7

C (GCC / linux), 402 353 352 302 300 298 296 288 bajtów

#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;}

Podziękowania dla edc65 za zapisanie kierunku w jednym 4-bitowym numerze.

Odczytuje szerokość / wysokość na stdin przed zapętleniem wygaszacza ekranu na zawsze. Na przykład:

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

Lub dla wygaszacza ekranu na pełnym ekranie:

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

Dla czytelności dodałem nowe linie. Wymaga maszyny linux z terminalem respektującym kody ANSI. Ma kolory! Usunięcie obsługi kolorów kosztuje 17 bajtów mniej.

przykład

orlp
źródło
5

Rubinowy, 413 403 396 bajtów

Rury Rubinowe

Funkcja, która pobiera liczbę tyknięć i szerokość jako dane wejściowe i zwraca ostatni ekran jako ciąg znaków. Bez wątpienia można grać w golfa więcej.

->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]}

Zobacz na repl.it: https://repl.it/Db5h/4

Aby zobaczyć to w akcji, wstaw następujący wiersz po linii, która się zaczyna b[n*w+n+m]=:

puts b; sleep 0.2

... następnie przypisz lambda do zmiennej np. pipes=->...i nazwij ją tak pipes[100,20](dla 100 tyknięć i ekranu 20x20).

Nie golf i wyjaśnienia

# 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]
}
Jordania
źródło