Код Гольф: Новогодний фейерверк [закрыто]
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 ответов:
вот мое решение в 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)