Код Гольф: Новогодний фейерверк [закрыто]


2009 год подходит к концу, и с экономикой и всем, мы сэкономим наши деньги и вместо того, чтобы покупать дорогие фейерверки, мы будем праздновать в ASCII art в этом году.

вызов

учитывая набор фейерверков и время, сфотографируйте фейерверк в это самое время и нарисуйте его на консоли.

лучшее решение, введенное до полуночи в канун Нового года (UTC), получит награду в размере 500 rep. это код golf, поэтому количество персонажей имеет большое значение; однако так же голосуют сообщества, и я оставляю за собой окончательное решение о том, что лучше/круче/наиболее креативно/и т. д.

Исходные Данные

обратите внимание, что наша система координат слева направо, снизу вверх, поэтому все фейерверки будут запущены в y-координата 0 (ноль).

входные данные состоят из фейерверков формы

(x, speed_x, speed_y, launch_time, detonation_time)

здесь

  • x позиция (колонка) где запускают фейерверк,
  • speed_x и speed_y горизонтальная и вертикальная скорость фейерверк во время запуска
  • launch_time это момент времени, когда этот фейерверк запускается,
  • detonation_time это момент времени, когда этот фейерверк взорвется.

данные фейерверка могут быть жестко закодированы в вашей программе в виде списка из 5 кортежей (или эквивалента на вашем языке), не считая вашего персонажа рассчитывать. Оно должно, однако, быть легко для того чтобы изменить эти данные.

вы можете сделать следующие предположения:

  • есть разумное количество фейерверков (скажем, меньше сотни)
  • для каждого фейерверка все пять чисел являются целыми числами в разумном диапазоне (скажем, 16 бит будет достаточно для каждый),
  • -20 <= x <= 820
  • -20 <= speed_x <= 20
  • 0 < speed_y <= 20
  • launch_time >= 0
  • launch_time < detonation_time < launch_time + 50

единственный дополнительный фрагмент входных данных-это точка времени, которая должна быть отображена. Это неотрицательное целое число, которое дается вам через стандартный ввод или аргумент командной строки (Что бы вы ни выбрали).

идея заключается в том, что (предполагая, что ваша программа является скриптом python под названием firework.py) это Баш скрипт дает вам хороший фейерверк анимации:

#!/bin/bash
I=0
while (( 1 )) ; do
    python firework.py $I
    I=$(( $I + 1 ))
done

(не стесняйтесь ставить эквивалент .BAT файл здесь).

жизнь фейерверк

жизнь фейерверк выглядит следующим образом:

  • до момента запуска, его можно игнорировать.
  • во время запуска, ракета на должность (x, 0) и вектор скорости (speed_x, speed_y).
  • для каждого временного шага вектор скорости добавляется к позиции. С небольшой натяжкой применять законы Ньютона, мы предполагаем, что скорость остается постоянной.
  • во время детонации ракета взрывается на девять искр. Все девять искр имеют одинаковое положение в этот момент времени (это положение, которое было бы у ракеты, если бы она не взорвалась), но их скорости различны. Каждая скорость основана на скорости ракеты, с добавлением -20, 0 или 20 к speed_x и -10, 0, или 10 добавлено к speed_y. Это девять возможных комбинаций.
  • после взрыва , гравитация начинает тянуть: с каждым временным шагом гравитационная постоянная, которая оказывается 2( два), вычитается из каждой искры speed_y. Горизонталь speed_x остается постоянной.
  • для каждого шага времени после времени детонации, вы первый добавить вектор скорости в положение,затем вычесть 2 от speed_y.
  • когда искра y положение опускается ниже нуля, вы можете забыть о оно.

выход

то, что мы хотим, это изображение фейерверка, как он выглядит в данный момент времени. Мы только смотрим на кадр 0 <= x <= 789 и 0 <= y <= 239, сопоставляя его с выводом символов 79x24.

Итак, если ракета или искра имеет позицию (247, 130), мы рисуем символ в столбце 24 (на основе нуля, так что это 25-й столбец), строка 13 (на основе нуля и подсчет снизу, так что это строка 23-13 = 10, 11-я строка из выход.)

какой символ рисуется зависит от текущей скорости ракеты / искры:

  • если движение горизонтальное*, т. е. speed_y == 0 or abs(speed_x) / abs(speed_y) > 2, литера "-".
  • если движение вертикальное*, т. е. speed_x == 0 or abs(speed_y) / abs(speed_x) > 2, литера "|".
  • в противном случае движение по диагонали, и символ "" или "/" (вы угадаете правильный).
  • Если же он обращается к более чем один раз (даже если это один и тот же символ), мы ставим "X" вместо этого. Так что если у вас есть искра на (536, 119) и один в (531, 115), вы рисуете "X", независимо от их скорости.

* update: это целочисленные деления, поэтому наклон должен быть не менее 3 или не более 1/3 соответственно

вывод (записанный в стандартный вывод) - это 24 строки, каждая из которых заканчивается символом новой строки. Конечные пробелы игнорируются, так что вы можете, но не нужно, прокладку на ширину 79. Длина строк не должна превышать 79 символов (за исключением новой строки). Все внутренние интервалы должны быть пробелами (ASCII 32).

Пример Данных

фейерверк:

fireworks = [(628, 6, 6, 3, 33),
             (586, 7, 11, 11, 23),
             (185, -1, 17, 24, 28),
             (189, 14, 10, 50, 83),
             (180, 7, 5, 70, 77),
             (538, -7, 7, 70, 105),
             (510, -11, 19, 71, 106),
             (220, -9, 7, 77, 100),
             (136, 4, 14, 80, 91),
             (337, -13, 20, 106, 128)]

выход в момент 33:






                |         /                                                   


                                                      /                       

       -         |         /                                                   




       -         |         -                                                   


                                                      /                       





выход в момент времени 77:













                                                                              






                                                                              
                      X                                                        


                                                                              

выход в момент 93:




                 |   /                                                        

                 /   /                                                        

              -   -   -                                                       




                                                                              







  /                                                                          



обновление: я загрузил ожидаемый результат в моменты от 0 до 99, чтобы firework.ü-wie-geek.de/NUMBER.html, где число-это время. Он включает в себя отладочную информацию; нажмите на частицу, чтобы увидеть ее текущее положение, скорость и т. д. И да, это домен умлаута. Если Ваш браузер не может справиться с этим (поскольку очевидно, что ни один не может переполнить стек), попробуйте firework.xn---wie-geek-p9a.de.

другие новости: как намекали в комментариях ниже, более длинный фейерверк теперь доступен на YouTube. Оно был создан с модифицированной версией записи MizardX, с общим количеством фейерверков 170 (да, это больше, чем требовала спецификация, но программа справилась с этим изящно). За исключением цвета, музыки и конечного экрана, анимация может быть воссоздана любой записью в этом коде golf. Итак, если вы достаточно выродок, чтобы наслаждаться фейерверком ASCII art (вы знаете, что это так): получайте удовольствие и счастливый Новый год для всех!

14 63

14 ответов:

вот мое решение в Python:

c = [(628, 6, 6, 3, 33),
    (586, 7, 11, 11, 23),
    (185, -1, 17, 24, 28),
    (189, 14, 10, 50, 83),
    (180, 7, 5, 70, 77),
    (538, -7, 7, 70, 105),
    (510, -11, 19, 71, 106),
    (220, -9, 7, 77, 100),
    (136, 4, 14, 80, 91),
    (337, -13, 20, 106, 128)]
t=input()
z=' '
s=([z]*79+['\n'])*23+[z]*79
def p(x,y,i,j):
    if 0<=x<790 and 0<=y<240:p=x/10+(23-y/10)*80;I=abs(i);J=abs(j);s[p]='X-|\/'[[s[p]!=z,I>=3*J,J>=3*I,i*j<0,1].index(1)]
for x,i,j,l,d in c:
    T=t-l;x+=i*T
    if t>=d:e=t-d;[p(x+X*e,j*T+e*(Y-e+1),i+X,j+Y-2*e)for X in -20,0,20 for Y in -10,0,10]
    elif t>=l:p(x,j*T,i,j)
print ''.join(s)

занимает время от stdin, и он имеет хорошее количество символов 342. Я все еще пытаюсь представить, как ОП получил 320 :P

изменить: Это лучшее, что я мог получить, 322 символа в соответствии с wc

t=input()
s=([' ']*79+['\n'])*24
def p(x,y,i,j):
 if 790>x>-1<y<240:p=x/10+(23-y/10)*80;I=abs(i);J=abs(j);s[p]='X-|\/'[[s[p]>' ',I>=3*J,J>=3*I,i*j<0,1].index(1)]
for x,i,j,l,d in c:
 T=t-l;x+=i*T;e=t-d
 if t>=d:[p(x+X*e,j*T+e*(Y-e+1),i+X,j+Y-2*e)for X in-20,0,20for Y in-10,0,10]
 elif t>=l:p(x,j*T,i,j)
print''.join(s),

теперь победитель выбрано-поздравляем Хуана-вот мое собственное решение, 304 символа в Python:

t=input()
Q=range
for y in Q(24):print"".join((["\/|-"[3*(h*h>=9*v*v)or(v*v>=9*h*h)*2or h*v>0]for X,H,V,L,D in F for s,Z,K,P,u in[(t-D,t>D,t-L,G%3*20-20,G/3*10-10)for G in[Q(9),[4]][t<D]]for h,v in[[P+H,u+V-2*s*Z]]if((X+H*K+P*s)/10,23-(V*K-s*(Z*s-Z-u))/10)==(x,y)][:2]+[" ","X"])[::3][-1]for x in Q(79))

это не очень быстро, потому что для каждой точки На дисплее 79x24 он проходит через все фейерверки, чтобы увидеть, виден ли какой-либо из них в этой точке.

вот версия, которая пытается объяснить, что происходит:

t=input()
Q=range
for y in Q(24):
    line = ""
    for x in Q(79):
        chars = [] # will hold all characters that should be drawn at (x, y)
        for X,H,V,L,D in F: # loop through the fireworks
            s = t - D
            Z = t > D
            K = t - L

            # if t < D, i.e. the rocket hasn't exploded yet, this is just [(0, 0)];
            # otherwise it's all combinations of (-20, 0, 20) for x and (-10, 0, 10)
            speed_deltas = [(G % 3 * 20 - 20, G / 3 * 10 -10) for G in [Q(9), [4]][t < D]]

            for P, u in speed_deltas:
                if x == (X + H*K + P*s)/10 and y == 23 - (V*K - s*(Z*s - Z - u))/10:

                    # the current horizontal and vertical speed of the particle
                    h = P + H
                    v = u + V - 2*s*Z

                    # this is identical to (but shorter than) abs(h) >= 3 * abs(v)
                    is_horizontal = h*h >= 9*v*v

                    is_vertical = v*v >= 9*h*h
                    is_northeast_southwest = h*v > 0

                    # a shorter way of saying
                    # char_index = (3 if is_horizontal else 2 if is_vertical else 1
                    #               if is_northeast_southwest else 0)
                    char_index = 3 * is_horizontal or 2 * is_vertical or is_northeast_southwest

                    chars.append("\/|-"[char_index])

        # chars now contains all characters to be drawn to this point. So we have
        # three possibilities: If chars is empty, we draw a space. If chars has
        # one element, that's what we draw. And if chars has more than one element,
        # we draw an "X".

        actual_char = (chars[:2] + [" ", "X"])[::3][-1] # Yes, this does the trick.
        line += actual_char

    print line

Python:

fireworks = [(628, 6, 6, 3, 33),
             (586, 7, 11, 11, 23),
             (185, -1, 17, 24, 28),
             (189, 14, 10, 50, 83),
             (180, 7, 5, 70, 77),
             (538, -7, 7, 70, 105),
             (510, -11, 19, 71, 106),
             (220, -9, 7, 77, 100),
             (136, 4, 14, 80, 91),
             (337, -13, 20, 106, 128)]
import sys
t = int(sys.argv[1])
particles = []
for x, speed_x, speed_y, launch_time, detonation_time in fireworks:
    if t < launch_time:
        pass
    elif t < detonation_time:
        x += speed_x * (t - launch_time)
        y  = speed_y * (t - launch_time)
        particles.append((x, y, speed_x, speed_y))
    else:
        travel_time = t - detonation_time
        x += (t - launch_time) * speed_x
        y  = (t - launch_time) * speed_y - travel_time * (travel_time - 1)
        for dx in (-20, 0, 20):
            for dy in (-10, 0, 10):
                x1 = x + dx * travel_time
                y1 = y + dy * travel_time
                speed_x_1 = speed_x + dx
                speed_y_1 = speed_y + dy - 2 * travel_time
                particles.append((x1, y1, speed_x_1, speed_y_1))
rows = [[' '] * 79 for y in xrange(24)]
for x, y, speed_x, speed_y in particles:
    x, y = x // 10, y // 10
    if 0 <= x < 79 and 0 <= y < 24:
        row = rows[23 - y]
        if row[x] != ' ': row[x] = 'X'
        elif speed_y == 0 or abs(speed_x) // abs(speed_y) > 2: row[x] = '-'
        elif speed_x == 0 or abs(speed_y) // abs(speed_x) > 2: row[x] = '|'
        elif speed_x * speed_y < 0: row[x] = '\'
        else: row[x] = '/'
print '\n'.join(''.join(row) for row in rows)

если удалить начальное объявление fireworks, сжать имена переменных до одиночных символов и пробелов до минимума, можно получить 590 символов.

C:

С удалением всех ненужных пробелов (632 байта, исключая объявление fireworks):

#define N 10
int F[][5]={628,6,6,3,33,586,7,11,11,23,185,-1,17,24,28,189,14,10,50,83,180,7,5,70,77,538,-7,7,70,105,510,-11,19,71,106,220,-9,7,77,100,136,4,14,80,91,337,-13,20,106,128};
#define G F[i]
#define R P[p]
g(x,y){if(y==0||abs(x)/abs(y)>2)return 45;if(x==0||abs(y)/abs(x)>2)return'|';if(x*y<0)return 92;return 47;}main(int A,char**B){int a,b,c,C[24][79]={},d,i,j,p=0,P[N*9][3],Q,t=atoi(B[1]),x,y;for(i=0;i<N;i++){if(t>=G[3]){a=t-G[3];x=G[0]+G[1]*a;y=G[2]*a;if(t<G[4]){R[0]=x;R[1]=y;R[2]=g(G[1],G[2]);p++;}else{b=t-G[4];y-=b*(b-1);for(c=-20;c<=20;c+=20){for(d=-10;d<=10;d+=10){R[0]=x+c*b;R[1]=y+d*b;R[2]=g(G[1]+c,G[2]+d-2*b);p++;}}}}}Q=p;for(p=0;p<Q;p++){x=R[0]/10;y=R[1]/10;if(R[0]>=0&&x<79&&R[1]>=0&&y<24)C[y][x]=C[y][x]?88:R[2];}for(i=23;i>=0;i--){for(j=0;j<79;j++)putchar(C[i][j]?C[i][j]:32);putchar(10);}}

и вот точно такой же код с пробелами, добавленными для удобства чтения:

#define N 10

int F[][5] = {
    628, 6, 6, 3, 33,
    586, 7, 11, 11, 23,
    185, -1, 17, 24, 28,
    189, 14, 10, 50, 83,
    180, 7, 5, 70, 77,
    538, -7, 7, 70, 105,
    510, -11, 19, 71, 106,
    220, -9, 7, 77, 100,
    136, 4, 14, 80, 91,
    337, -13, 20, 106, 128
};

#define G F[i]
#define R P[p]

g(x, y) {
    if(y == 0 || abs(x)/abs(y) > 2)
        return 45;
    if(x == 0 || abs(y)/abs(x) > 2)
        return '|';
    if(x*y < 0)
        return 92;
    return 47;
}

main(int A, char**B){
    int a, b, c, C[24][79] = {}, d, i, j, p = 0, P[N*9][3], Q, t = atoi(B[1]), x, y;

    for(i = 0; i < N; i++) {
        if(t >= G[3]) {
            a = t - G[3];
            x = G[0] + G[1]*a;
            y = G[2]*a;
            if(t < G[4]) {
                R[0] = x;
                R[1] = y;
                R[2] = g(G[1], G[2]);
                p++;
            } else {
                b = t - G[4];
                y -= b*(b-1);
                for(c = -20; c <= 20; c += 20) {
                    for(d =- 10; d <= 10; d += 10) {
                        R[0] = x + c*b;
                        R[1] = y + d*b;
                        R[2] = g(G[1] + c, G[2] + d - 2*b);
                        p++;
                    }
                }
            }
        }
    }

    Q = p;

    for(p = 0; p < Q; p++) {
        x = R[0]/10;
        y = R[1]/10;
        if(R[0] >= 0 && x < 79 && R[1] >= 0 && y < 24)
            C[y][x] = C[y][x] ? 88 : R[2];
    }

    for(i = 23; i >= 0; i--) {
        for(j = 0; j < 79; j++)
            putchar(C[i][j] ? C[i][j] : 32);
        putchar(10);
    }
}

для Python решение @MizardX приятно, но явно не оптимизировано для codegolf-кроме того," не считайте " 333 символа префикса, а именно:

fireworks = [(628, 6, 6, 3, 33),
    (586, 7, 11, 11, 23),
    (185, -1, 17, 24, 28),
    (189, 14, 10, 50, 83),
    (180, 7, 5, 70, 77),
    (538, -7, 7, 70, 105),
    (510, -11, 19, 71, 106),
    (220, -9, 7, 77, 100),
    (136, 4, 14, 80, 91),
    (337, -13, 20, 106, 128)]
f = fireworks
### int sys argv append abs join f xrange

(последний комментарий является помощником для моего небольшого скрипта codegolf-aux, который делает все возможные имена 1-char механически - ему нужно сказать, какие имена не уменьшать; -), самое короткое, что я могу сделать, сжимая пробелы, - это 592 символа (достаточно близко к 590 @MizardX претензии.)

вытаскивая все остановки ("рефакторинг" кода в настроении codegolf), я получаю, после префикса (я использовал нижний регистр для односимвольных имен, которые я вручную вводил или заменял, верхний регистр для тех, кого мой скрипт codegolf-aux заменил автоматически):

import sys 
Z=int(sys.argv[1])
Y=[]
e=Y.extend
for X,W,V,U,T in f:
 if Z>=U:
  z=Z-U;X+=W*z
  if Z<T:e(((X,V*z,W,V),))
  else:R=Z-T;e((X+Q*R,z*V-R*(R-1)+P*R,W+Q,V+P-2*R)for Q in(-20,0,20)for P in(-10,0,10))
K=[79*[' ']for S in range(24)]
for X,S,W,V in Y:
 X,S=X/10,S/10 
 if(0<=X<79)&(0<=S<24):
  J=K[23-S];v=abs(V);w=abs(W)
  J[X]='X'if J[X]!=' 'else'-'if V==0 or w/v>2 else'|'if W==0 or v/w>2 else '\'if W*V<0 else'/'
print '\n'.join(''.join(J)for J in K)

который измеряет в 460 символов - это сокращение 130, т. е. 130/590 = 22%.

помимо 1-символьных имен и очевидных способов минимизации интервалов, ключевые идеи включают в себя: один / для разделения (то же самое, что и лучше // для ints в Python 2.*), с if/else выражение вместо if/elif/else заявление extend С помощью genexp, а не вложенного цикла с append (позволяет удалить некоторые пробелы и знаки препинания), не привязка к имени подвыражения, которые происходят только один раз, привязка к имени подвыражения, которые в противном случае будут повторяться (в том числе .extend поиск атрибутов), точки с запятой, а не новые строки, где это возможно (только если отдельные строки должны быть с отступом, в противном случае, считая новую строку как 1 символ, нет сохранения).

да, читаемость немного страдает, но это вряд ли удивительно в code golf;-).

Edit: после гораздо большего затягивания, у меня теперь есть меньшая программа (тот же префикс):

Z=input()
K=[79*[' ']for S in range(24)];a=-10,0,10
def g(X,S,W,V):
 X/=10;S/=10
 if(0<=X<79)&(0<=S<24):J=K[23-S];v=abs(V);w=abs(W);J[X]=[[['/\'[W*V<0],'|'][v>2.9*w],'-'][w>2.9*v],'X'][J[X]!=' ']
for X,W,V,U,T in f:
 if Z>=U:
  z=Z-U;X+=W*z
  if Z<T:g(X,V*z,W,V)
  else:R=Z-T;[g(X+Q*2*R,z*V-R*(R-1)+P*R,W+Q*2,V+P-2*R)for Q in a for P in a]
print'\n'.join(''.join(J)for J in K)

все тот же вывод, но теперь 360 символов-ровно на 100 меньше, чем мое предыдущее решение, которое я оставил в качестве первой части этого ответа (все еще намного выше 320 ОП говорит, что у него есть!-).

я воспользовался степенью свободы, позволяющей значение времени ввода поступать из stdin (input намного жестче, чем импорт sys и с помощью sys.argv[1]!- ), исключил промежуточный список (с расширенными вызовами и заключительным циклом его) в пользу новой функции g который вызывается напрямую и обновляет K, когда мы идем, нашел и удалил некоторую общность, рефакторировал вложенное выражение if / else в a сложное (но более сжатое;-) построение и индексация вложенных списков, используется тот факт, что v>2.9*w более кратким, чем w==0 or v/w>2 (и всегда дает тот же результат в диапазон значений, которые должны быть рассмотрены).

Edit: превращение K ("изображение на экране") в 1-D список сохраняет еще 26 символов, сокращая следующее решение до 334 (все еще 14 выше OP, но закрывается...!- ):

Z=input()
K=list(24*(' '*79+'\n'))
a=-10,0,10
def g(X,S,W,V):
 if(0<=X<790)&(0<=S<240):j=80*(23-S/10)+X/10;v=abs(V);w=abs(W);K[j]=[[['/\'[W*V<0],'|'][v>2.9*w],'-'][w>2.9*v],'X'][K[j]!=' ']
for X,W,V,U,T in f:
 if Z>=U:
  z=Z-U;X+=W*z
  if Z<T:g(X,V*z,W,V)
  else:R=Z-T;[g(X+Q*2*R,z*V-R*(R-1)+P*R,W+Q*2,V+P-2*R)for Q in a for P in a]
print ''.join(K),

Сделано в F# в 957 * символов, и это уродливо, как грех:

массив фейерверков:

let F = [(628,6,6,3,33);(586,7,11,11,23);(185,-1,17,24,28);(189,14,10,50,83);(180,7,5,70,77);(538,-7,7,70,105);(510,-11,19,71,106);(220,-9,7,77,100);(136,4,14,80,91);(337,-13,20,106,128)]

остальной код

let M=List.map
let C=List.concat
let P=List.partition
let L t f r=(let s=P(fun(_,_,_,u,_)->not(t=u))f
(fst s, r@(M(fun(x,v,w,_,t)->x,0,v,w,t)(snd s))))
let X d e (x,y,v,w)=C(M(fun(x,y,v,w)->[x,y,v-d,w;x,y,v,w;x,y,v+d,w])[x,y,v,w-e;x,y,v,w;x,y,v,w+e])
let D t r s=(let P=P(fun(_,_,_,_,u)->not(t=u))r
(fst P,s@C(M(fun(x,y,v,w,_)->(X 20 10(x,y,v,w)))(snd P))))
let rec E t l f r s=(
let(a,m)=L t f (M(fun(x,y,v,w,t)->x+v,y+w,v,w,t)r)
let(b,c)=D t m (M(fun(x,y,v,w)->x+v,y+w,v,w-2)s)
if(t=l)then(a,b,c)else E(t+1)l a b c)
let N=printf
let G t=(
let(f,r,s)=E 0 t F [] []
let os=s@(M(fun(x,y,v,w,_)->(x,y,v,w))r)
for y=23 downto 0 do (
for x=0 to 79 do (
let o=List.filter(fun(v,w,_,_)->((v/10)=x)&&((w/10)=y))os
let l=o.Length
if l=0 then N" "
elif l=1 then
let(_,_,x,y)=o.Head
N(
if y=0||abs(x)/abs(y)>2 then"-"
elif x=0||abs(y)/abs(x)>2 then"|"
elif y*x>0 then"/"
else"\")
elif o.Length>1 then N"X")
N"\n"))
[<EntryPointAttribute>]
let Z a=
 G (int(a.[0]))
 0

"довольно" код:

let fxs  = [(628,6,6,3,33);(586,7,11,11,23);(185,-1,17,24,28);(189,14,10,50,83);(180,7,5,70,77);(538,-7,7,70,105);(510,-11,19,71,106);(220,-9,7,77,100);(136,4,14,80,91);(337,-13,20,106,128)]

let movs xs = 
  List.map (fun (x, y, vx, vy) -> (x + vx, y + vy, vx, vy-2)) xs

let movr xs =
  List.map (fun (x, y, vx, vy, dt) -> (x + vx, y + vy, vx, vy, dt)) xs

let launch t fs rs =
  let split = List.partition(fun (lx, sx, sy, lt, dt) -> not (t = lt)) fs
  (fst split, rs @ (List.map(fun (lx, sx, sy, lt, dt) -> (lx, 0, sx, sy, dt)) (snd split)))

let split dx dy (x,y,sx,sy) =
  List.concat (List.map (fun (x,y,sx,sy)->[(x,y,sx-dx,sy);(x,y,sx,sy);(x,y,sx+dx,sy)]) [(x,y,sx,sy-dy);(x,y,sx,sy);(x,y,sx,sy+dy)])

let detonate t rs ss =
  let tmp = List.partition (fun (x, y, sx, sy, dt) -> not (t = dt)) rs
  (fst tmp, ss @ List.concat (List.map(fun (x, y, sx, sy, dt) -> (split 20 10 (x, y, sx, sy))) (snd tmp)))

let rec simulate t l fs rs ss =
  let (nfs, trs) = launch t fs (movr rs)
  let (nrs, nss) = detonate t trs (movs ss)
  if (t = l) then (nfs,nrs,nss)
  else 
    simulate (t+1) l nfs nrs nss

let screen t =
  let (fs, rs, ss) = simulate 0 t fxs [] []
  let os = ss @ (List.map(fun (x, y, sx, sy,_) -> (x, y, sx, sy)) rs)
  for y = 23 downto 0 do 
    for x = 0 to 79 do
      let o = List.filter(fun (px,py,_,_)->((px/10)=x) && ((py/10)=y)) os
      if o.Length = 0 then printf " "
      elif o.Length = 1 then
        let (_,_,sx,sy) = o.Head
        printf (
          if sy = 0 || abs(sx) / abs(sy) > 2 then "-"
          elif sx = 0 || abs(sy) / abs(sx) > 2 then "|"
          elif sy * sx > 0 then "/"
          else"\"
        )
      elif o.Length > 1 then printf "X"
    printfn ""

[<EntryPointAttribute>]
let main args =
  screen (int(args.[0]))
  0

полностью укралипереписан с новой и улучшенной логикой. Это так близко, как я мог добраться до Python. Вы можете видеть слабость F#, не ориентированного на специальные сценарии здесь, где я должен явно преобразовать V и W в float, объявить основную функцию с уродливым атрибут для получения args командной строки, и я должен ссылаться на систему .NET.Приставка.Напишите, чтобы получить довольно выход.

Ну что ж, хорошее упражнение для изучения языка.

вот новый код, в 544 байт:

let Q p t f=if p then t else f
let K=[|for i in 1..1920->Q(i%80>0)' ''\n'|]
let g(X,S,W,V)=
 if(X>=0&&X<790&&S>=0&&S<240)then(
let (j,v,w)=(80*(23-S/10)+X/10,abs(float V),abs(float W))
Array.set K j (Q(K.[j]=' ')(Q(w>2.9*v)'-'(Q(v>2.9*w)'|'(Q(W*V>0)'/''\')))'X'))
let a=[-10;0;10]
[<EntryPointAttribute>]
let m s=
 let Z=int s.[0]
 for (X,W,V,U,T) in F do(
if Z>=U then
 let z,R=Z-U,Z-T
 let x=X+W*z
 if(Z<T)then(g(x,V*z,W,V))else(for e in[|for i in a do for j in a->(x+j*2*R,z*V-R*(R-1)+i*R,W+j*2,V+i-2*R)|]do g e))
 System.Console.Write K
 0

Haskell

import Data.List
f=[(628,6,6,3,33),(586,7,11,11,23),(185,-1,17,24,28),(189,14,10,50,83),(180,7,5,70,77),(538,-7,7,70,105),(510,-11,19,71,106),(220,-9,7,77,100),(136,4,14,80,91),(337,-13,20,106,128)]
c=filter
d=True
e=map
a(_,_,_,t,_)=t
b(_,_,_,_,t)=t
aa(_,y,_,_)=y
ab(x,t,y,_,u)=(x,0,t,y,u)
ac(x,y,t,u,_)=[(x,y,t+20,u+10),(x,y,t,u+10),(x,y,t-20,u+10),(x,y,t+20,u),(x,y,t,u),(x,y,t-20,u),(x,y,t+20,u-10),(x,y,t,u-10),(x,y,t-20,u-10)]
g(x,y,t,u,v)=(x+t,y+u,t,u,v)
h(x,y,t,u)=(x+t,y+u,t,u-2)
i=(1,f,[],[])
j s 0=s
j(t,u,v,w)i=j(t+1,c((/=t).a)u,c((> t).b)x++(e ab.c((==t).a))u,c((>0).aa)(e h w)++(concat.e ac.c((==t).b))x)(i-1)
 where x=e g v
k x y
 |x==0='|'
 |3*abs y<=abs x='-'
 |3*abs x<=abs y='|'
 |(y<0&&x>0)||(y>0&&x<0)='\'
 |d='/'
l(x,y,t,u,_)=m(x,y,t,u)
m(x,y,t,u)=(div x 10,23-div y 10,k t u)
n(x,y,_)(u,v,_)
 |z==EQ=compare x u
 |d=z
 where z=compare y v
o((x,y,t):(u,v,w):z)
 |x==u&&y==v=o((x,y,'X'):z)
 |d=(x,y,t):(o((u,v,w):z))
o x=x
q _ y []
 |y==23=""
 |d='\n':(q 0(y+1)[])
q v u((x,y,z):t)
 |u>22=""
 |v>78='\n':(q 0(u+1)((x,y,z):t))
 |u/=y='\n':(q 0(u+1)((x,y,z):t))
 |v/=x=' ':(q(v+1)u((x,y,z):t))
 |d = z:(q(v+1)u t)
p(_,_,v,w)=q 0 0((c z.o.sortBy n)((e l v)++(e m w)))
 where z(x,y,_)=x>=0&&x<79&&y>=0
r x=do{z <- getChar;(putStr.p)x}
s=e(r.j i)[1..]
main=foldr(>>)(return())s

не так впечатляет, как MizardX, приходя в 1068 символов, если вы удалите f=… объявление, но черт возьми, это было весело. У меня давно не было возможности поиграть с Хаскеллом.

(немного) красивее версия также доступен.

Edit: Ack. Перечитывая, я не совсем соответствую спецификации.: эта версия печатает новый экран фейерверка каждый раз, когда вы нажимаете клавишу, и требует ^C to уйти; он не принимает аргумент командной строки и распечатать соответствующий экран.

Perl

предполагая, что данные фейерверка определяются как:

@f = (
   [628, 6, 6, 3, 33],
   [586, 7, 11, 11, 23],
   [185, -1, 17, 24, 28],
   [189, 14, 10, 50, 83],
   [180, 7, 5, 70, 77],
   [538, -7, 7, 70, 105],
   [510, -11, 19, 71, 106],
   [220, -9, 7, 77, 100],
   [136, 4, 14, 80, 91],
   [337, -13, 20, 106, 128]
);

$t=shift;
for(@f){
    ($x,$c,$d,$l,$e)=@$_;
    $u=$t-$l;
    next if$u<0;
    $x+=$c*$u;
    $h=$t-$e;
    push@p,$t<$e?[$x,$d*$u,$c,$d]:map{$f=$_;map{[$x+$f*$h,($u*$d-$h*($h-1))+$_*$h,$c+$f,$d+$_-2*$h]}(-10,0,10)}(-20,0,20)
}
push@r,[($")x79]for(1..24);
for(@p){
   ($x,$y,$c,$d)=@$_;
   if (0 <= $x && ($x=int$x/10) < 79 && 0 <= $y && ($y=int$y/10) < 24) {
      @$_[$x]=@$_[$x]ne$"?'X':!$d||abs int$c/$d>2?'-':!$c||abs int$d/$c>2?'|':$c*$d<0?'\':'/'for$r[23 - $y]
   }
}
$"='';
print$.,map{"@$_\n"}@r

сжатый, он поставляется в 433 символов. (см. раздел правки для истории)

это основано на фрагментах нескольких предыдущих ответов (в основном MizardX) и определенно может быть улучшено. Вина за то, что я откладываю другие, связанные с работой задачи, означает, что я должен отказаться от этого сейчас.


простите редактирование -- вытаскивая все трюки я знаю, это можно сжать до 356 символов:

sub p{
  ($X,$=,$C,$D)=@_;
  if(0<=$X&($X/=10)<79&0<=$=&($=/=10)<24){
    @$_[$X]=@$_[$X]ne$"?X:$D&&abs$C/$D<3?$C&&abs$D/$C<3?
    $C*$D<0?'\':'/':'|':'-'for$r[23-$=]
  }
}
@r=map[($")x79],1..24;
$t=pop;
for(@f){
  ($x,$c,$d,$u,$e)=@$_;
  $x-=$c*($u-=$t);
  $u>0?1:($h=$t-$e)<0
  ?p$x,-$d*$u,$c,$d
  :map{for$g(-10,0,10){p$x+$_*$h,$h*(1-$h+$g)-$u*$d,$c+$_,$d+$g-2*$h}}-20,0,20
}
print@$_,$/for@r

$= - Это специальная переменная Perl (вместе с $%,$- и $?), которые могут принимать только целочисленные значения. Использование его устраняет необходимость использовать

Фортран 77

из отдела доисторических языков, вот моя запись в FORTRAN 77.

2570 символов, включая инициализацию, несколько пробелов и некоторые ненужные пробелы, но я не думаю, что это может выиграть для краткости. Тем более, что, например, 6 ведущих пробелов в каждой строке являются обязательными.

я назвал этот файл fireworks.ftn и скомпилировал его с gfortran в системе Linux.

  implicit integer(a-z)
  parameter (n=10)
  integer fw(5,n) / 
 + 628, 6, 6, 3, 33,
 + 586, 7, 11, 11, 23,
 + 185, -1, 17, 24, 28,
 + 189, 14, 10, 50, 83,
 + 180, 7, 5, 70, 77,
 + 538, -7, 7, 70, 105,
 + 510, -11, 19, 71, 106,
 + 220, -9, 7, 77, 100,
 + 136, 4, 14, 80, 91,
 + 337, -13, 20, 106, 128
 + /
  integer p(6, 1000) / 6000 * -1 / 
  character*79 s(0:23)
  character z
c Transform input
      do 10 r=1,n
         p(1, r) = 0
         do 10 c=1,5
   10       p(c+1, r) = fw(c, r)
c Input end time
      read *, t9
c Iterate from 1 to end time
      do 62 t=1,t9
         do 61 q=1,1000
            if (p(1,q) .lt. 0 .or. t .lt. p(5,q)) goto 61
            if (p(6,q).gt.0.and.t.gt.p(5,q) .or. t.gt.abs(p(6,q))) then
               p(1,q) = p(1,q) + p(4,q)
               p(2,q) = p(2,q) + p(3,q)
            endif
            if (t .lt. abs(p(6,q))) goto 61
            if (t .gt. abs(p(6,q))) then
               p(4,q) = p(4,q) - 2
            elseif (t .eq. p(6,q)) then
c Detonation: Build 9 sparks            
               do 52 m=-1,1
                  do 51 k=-1,1
c Find a free entry in p and fill it with a spark
                     do 40 f=1,1000
                        if (p(1,f) .lt. 0) then
                           do 20 j=1,6
   20                      p(j,f) = p(j,q)
                           p(3,f) = p(3,q) + 20 * m
                           p(4,f) = p(4,q) + 10 * k
                           p(6,f) = -p(6,q)
                           goto 51
                        endif
   40                continue
   51             continue
   52          continue
c Delete the original firework
               p(1,q) = -1
            endif
   61    continue
   62 continue
c Prepare output
      do 70 r=0,23
   70 s(r) = ' '
      do 80 q=1,1000
         if (p(1,q) .lt. 0) goto 80
         if (p(5,q) .gt. t9) goto 80
         y = p(1,q) / 10
         if (y .lt. 0 .or. y .gt. 23) goto 80
         x = p(2,q) / 10
         if (x .lt. 0 .or. x .gt. 79) goto 80
         if (s(y)(x+1:x+1) .ne. ' ') then
            z = 'X'
         elseif ((p(4,q) .eq. 0) .or. abs(p(3,q) / p(4,q)) .gt. 2) then
            z = '-'
         elseif ((p(3,q) .eq. 0) .or. abs(p(4,q) / p(3,q)) .gt. 2) then
            z = '|'
         elseif (sign(1, p(3,q)) .eq. sign(1, p(4,q))) then
            z = '/'
         else
            z = '\'
         endif
         s(y)(x+1:x+1) = z
   80 continue
c Output
      do 90 r=23,0,-1
   90 print *, s(r)
      end

вот меньшая реализация Haskell. Это 911 символов; минус определение фейерверка, это 732 символа:

import System
z=789
w=239
r=replicate
i=foldl
main=do{a<-getArgs;p(f[(628,6,6,3,33),(586,7,11,11,23),(185,-1,17,24,28),(189,14,10,50,83),(180,7,5,70,77),(538,-7,7,70,105),(510,-11,19,71,106),(220,-9,7,77,100),(136,4,14,80,91),(337,-13,20,106,128)](read(a!!0)::Int));}
p[]=return()
p(f:g)=do{putStrLn f;p g}
f s t=i(a t)(r 24(r 79' '))s
a t f(x,s,y,l,d)=if t<l then f else if t<d then c f((x+s*u,y*u),(s,y))else i c f(map(v(t-d)(o(d-l)(x,0)(s,y)))[(g s,h y)|g<-[id,(subtract 20),(+20)],h<-[id,(subtract 10),(+10)]])where u=t-l
v 0(x,y)(vx,vy)=((x,y),(vx,vy))
v t(x,y)(vx,vy)=v(t-1)(x+vx,y+vy)(vx,vy-2)
o t(x,y)(vx,vy)=(x+(vx*t),y+(vy*t))
c f((x,y),(vx,vy))=if x<0||x>=z||y<0||y>=w then f else(take m f)++[(take n r)++[if d/=' 'then 'x'else if vy==0||abs(vx`div`vy)>2 then '-'else if vx==0||abs(vy`div`vx)>2 then '|'else if vx*vy>=0 then '/'else '\']++(drop(n+1)r)]++(drop(m+1)f)where{s=w-y;n=x`div`10;m=s`div`10;r=f!!m;d=r!!n}

вот несжатая версия для любопытных:

import System

sizeX = 789
sizeY = 239

main = do
    args <- getArgs
    printFrame (frame fireworks (read (args !! 0) :: Int))
    where 
        fireworks = [
            (628, 6, 6, 3, 33),
            (586, 7, 11, 11, 23),
            (185, -1, 17, 24, 28),
            (189, 14, 10, 50, 83),
            (180, 7, 5, 70, 77),
            (538, -7, 7, 70, 105),
            (510, -11, 19, 71, 106),
            (220, -9, 7, 77, 100),
            (136, 4, 14, 80, 91),
            (337, -13, 20, 106, 128)]

printFrame :: [String] -> IO ()
printFrame [] = return ()
printFrame (f:fs) = do
    putStrLn f
    printFrame fs

frame :: [(Int,Int,Int,Int,Int)] -> Int -> [String]
frame specs time = 
    foldl (applyFirework time) 
        (replicate 24 (replicate 79 ' ')) specs

applyFirework :: Int -> [String] -> (Int,Int,Int,Int,Int) -> [String]
applyFirework time frame (x,sx,sy,lt,dt) =
    if time < lt then frame
    else if time < dt then 
        drawChar frame 
            ((x + sx * timeSinceLaunch, sy * timeSinceLaunch), (sx,sy))
    else
        foldl drawChar frame 
            (
                map 
                    (
                        posVelOverTime (time - dt) 
                        (posOverTime (dt - lt) (x,0) (sx, sy))
                    ) 
                    [ 
                        (fx sx, fy sy) | 
                            fx <- [id,(subtract 20),(+20)],  
                            fy <- [id,(subtract 10),(+10)]
                    ]
            )
    where timeSinceLaunch = time - lt

posVelOverTime :: Int -> (Int,Int) -> (Int,Int) -> ((Int,Int),(Int,Int))
posVelOverTime 0 (x,y) (vx,vy) = ((x,y),(vx,vy))
posVelOverTime time (x,y) (vx,vy) = 
    posVelOverTime (time - 1) (x+vx, y+vy) (vx, vy - 2)

posOverTime :: Int -> (Int,Int) -> (Int,Int) -> (Int,Int)
posOverTime time (x,y) (vx, vy) = (x + (vx * time), y + (vy * time))

drawChar :: [String] -> ((Int,Int),(Int,Int)) -> [String]
drawChar frame ((x,y),(vx,vy)) =
    if x < 0 || x >= sizeX || y < 0 || y >= sizeY then frame
    else 
        (take mappedY frame) 
        ++ 
            [
                (take mappedX row) 
                ++ 
                    [
                        if char /= ' '                           then 'x'
                        else if vy == 0 || abs (vx `div` vy) > 2 then '-'
                        else if vx == 0 || abs (vy `div` vx) > 2 then '|'
                        else if vx * vy >= 0                     then '/'
                        else                                          '\'
                    ]
                ++ (drop (mappedX + 1) row) 
            ] 
        ++ (drop (mappedY + 1) frame)
    where 
        reversedY = sizeY - y
        mappedX = x `div` 10
        mappedY = reversedY `div` 10
        row = frame !! mappedY
        char = row !! mappedX

первый черновик в tcl8. 5 913 байт исключая фейерверк определение:

set F {
    628   6    6   3   33
    586   7   11  11   23
    185  -1   17  24   28
    189  14   10  50   83
    180   7    5  70   77
    538  -7    7  70  105
    510 -11   19  71  106
    220  -9    7  77  100
    136   4   14  80   91
    337 -13   20 106  128
}

namespace import tcl::mathop::*
proc @ {a args} {interp alias {} $a {} {*}$args}
@ : proc
@ = set
@ D d p
@ up upvar 1
@ < append out
@ _ foreach
@ e info exists
@ ? if
: P {s d t l} {+ $s [* $d [- $t $l]]}
: > x {= x}
: d {P x X y Y} {up $P p
= x [/ $x 10]
= y [/ $y 10]
= p($x,$y) [? [e p($x,$y)] {> X} elseif {
$Y==0||abs($X)/abs($Y)>2} {> -} elseif {
$X==0||abs($Y)/abs($X)>2} {> |} elseif {
$X*$Y<0} {> \} {> /}]}
: r {P} {up $P p
= out ""
for {= y 23} {$y >= 0} {incr y -1} {
for {= x 0} {$x < 79} {incr x} {? {[e p($x,$y)]} {< $p($x,$y)} {< " "}}
< "\n"}
puts $out}
: s {F t} {array set p {}
_ {x X Y l d} $F {? {$t >= $l} {? {$t < $d} {= x [P $x $X $t $l]
= y [P 0 $Y $t $l]
D $x $X $y $Y} {= x [P $x $X $d $l]
= y [P 0 $Y $d $l]
= v [- $t $d]
_ dx {-20 0 20} {_ dy {-10 0 10} {= A [+ $X $dx]
= B [- [+ $Y $dy] [* 2 $v]]
= xx [P $x $A $v 0]
= yy [P $y $B $v 0]
D $xx $A $yy $B}}}}}
r p}
s $F [lindex $argv 0]

оптимизирован до нечитаемости. Все еще ищу место для улучшения. Большая часть сжатия в основном использует псевдонимы команд, заменяя имена команд одиночными символами. Например, определения функций выполняются с использованием синтаксиса Forth-like:.

вот несжатая версия:

namespace import tcl::mathop::*

set fireworks {
    628   6    6   3   33
    586   7   11  11   23
    185  -1   17  24   28
    189  14   10  50   83
    180   7    5  70   77
    538  -7    7  70  105
    510 -11   19  71  106
    220  -9    7  77  100
    136   4   14  80   91
    337 -13   20 106  128
}

proc position {start speed time launch} {
    + $start [* $speed [- $time $launch]]
}

proc give {x} {return $x}

proc draw {particles x speedX y speedY} {
    upvar 1 $particles p
    set x [/ $x 10]
    set y [/ $y 10]
    set p($x,$y) [if [info exists p($x,$y)] {
            give X
        } elseif {$speedY == 0 || abs(double($speedX))/abs($speedY) > 2} {
            give -
        } elseif {$speedX == 0 || abs(double($speedY))/abs($speedX) > 2} {
            give |
        } elseif {$speedX * $speedY < 0} {
            give \
        } else {
            give /
        }
    ]
}

proc render {particles} {
    upvar 1 $particles p
    set out ""
    for {set y 23} {$y >= 0} {incr y -1} {
        for {set x 0} {$x < 79} {incr x} {
            if {[info exists p($x,$y)]} {
                append out $p($x,$y)
            } else {
                append out " "
            }
        }
        append out "\n"
    }
    puts $out
}

proc show {fireworks time} {
    array set particles {}
    foreach {x speedX speedY launch detonate} $fireworks {
        if {$time >= $launch} {
            if {$time < $detonate} {
                set x [position $x $speedX $time $launch]
                set y [position 0 $speedY $time $launch]
                draw particles $x $speedX $y $speedY
            } else {
                set x [position $x $speedX $detonate $launch]
                set y [position 0 $speedY $detonate $launch]
                set travel [- $time $detonate]
                foreach dx {-20 0 20} {
                    foreach dy {-10 0 10} {
                        set speedXX [+ $speedX $dx]
                        set speedYY [- [+ $speedY $dy] [* 2 $travel]]
                        set xx [position $x $speedXX $travel 0]
                        set yy [position $y $speedYY $travel 0]
                        draw particles $xx $speedXX $yy $speedYY
                    }
                }
            }
        }
    }
    render particles
}
show $fireworks [lindex $argv 0]

первый пост хахаха http://zipts.com/position.php?s=0 не мое окончательное подчинение, но не мог устоять

кстати: символы 937 не считая пробелов (мы считаем пробелы? )

мой ответ на http://www.starenterprise.se/fireworks.html все сделано на javascript. и нет, я не потрудился сделать это ashortap, я просто хотел посмотреть, смогу ли я.

Clojure

без привязки, без ввода-вывода и ненужных пробелов, он доходит до 640 символов - точно удваивает лучшее значение :( таким образом, я не предоставляю "пустую оптимизированную" версию в попытке выиграть краткость.

(def fw [
[628 6 6 3 33]
[586 7 11 11 23]
[185 -1 17 24 28]
[189 14 10 50 83]
[180 7 5 70 77]
[538 -7 7 70 105]
[510 -11 19 71 106]
[220 -9 7 77 100]
[136 4 14 80 91]
[337 -13 20 106 128]
])
(defn rr [x y u v dt g] (if (<= dt 0) [x y u v] (recur (+ x u) (+ y v) u (+ v g) (dec dt) g)))

(defn pp [t f]
  (let [y 0 [x u v a d] f r1 (rr x y u v (- (min t d) a) 0)]
    (if (< t a)
      '()
      (if (< t d)
        (list r1)
        (for [m '(-20 0 20) n '(-10 0 10)]
          (let [[x y u v] r1]
            (rr x y (+ u m) (+ v n) (- t d) -2)))))))

(defn at [x y t]
  (filter #(and (= x (quot (first %) 10)) (= y (quot (second %) 10))) (apply concat (map #(pp t %) fw))))

(defn g [h]
  (if (empty? h) \space
    (if (next h) \X
      (let [[x y u v] (first h)]
        (cond
          (or (zero? v) (> (* (/ u v) (/ u v)) 4)) \-
          (or (zero? u) (> (* (/ v u) (/ v u)) 4)) \|
          (= (neg? u) (neg? v)) \/
          :else \
        )))))

(defn q [t]
  (doseq [r (range 23 -1 -1)]
    (doseq [c (range 0 80)]
      (print (g (at c r t))))
    (println)))

(q 93)