Bash-версия C64 Code Art: 10 PRINT CHR$(205,5+RND(1)); : ПЕРЕЙТИ К 10

Я взял экземпляр книги 10 PRINT CHR$(205,5+RND(1)); : ПЕРЕЙТИ К 10

В этой книге обсуждается искусство, созданное одной линейкой Commodore 64 BASIC:

10 PRINT CHR$(205.5+RND(1)); : GOTO 10

Это просто многократно выводит случайный символ 205 или 206 на экран из набора PETSCII:

Я не уверен, почему в оригинале используются символы 205 и 206 вместо идентичных 109 и 110. Кроме того, я предпочитаю в начале добавлять ясность. Вот что я обычно набираю в C64:

1?CHR$(147)
2?CHR$(109.5+RND(1));:GOTO2
RUN

Вы можете сами попробовать все это в эмуляторе, таком как этот, использующий Flash или JavaScript:


Я решил, что было бы забавно написать строку bash, чтобы сделать что-то подобное.

В настоящее время у меня есть:

clear; while :; do [ $(($RANDOM%2)) -eq 0 ] && (printf "\\") || (printf "/"); done;

Два вопроса:

  1. Любые предложения, чтобы сделать это более кратким?
  2. Любые предложения для лучшего выходного символа? Прямая и обратная косая черта не так красивы, поскольку их точки не совпадают. Символы, используемые в PETSCII, являются специальными символами, а не косой чертой. Я не видел ничего в ASCII, что могло бы работать, но, может быть, вы можете предложить способ вытащить символ из UTF-8 или что-то еще?

Лучшие ответы на данный момент

Самый короткий для bash (40 символов):

yes 'c=(╱ ╲);printf ${c[RANDOM%2]}'|bash

Вот короткий для zsh (53 символа):

c=(╱ ╲);clear;while :;do printf ${c[RANDOM%2+1]};done

Вот псевдоним, который я хотел бы добавить в свой .bashrc или .profile.

alias art='c=(╱ ╲);while :;do printf "%s" ${c[RANDOM%2]};done'

Забавно сравнивать это с самым коротким, который я могу сделать для C64 BASIC (23 символа):

1?C_(109.5+R_(1));:G_1

Символы подчеркивания — это shift+H, shift+N и shift+O соответственно. Я не могу вставить сюда персонажа, так как он специфичен для PETSCII. Кроме того, выход C64 выглядит красивее;)

Вы можете прочитать об аббревиатурах C64 BASIC здесь:


person Community    schedule 28.11.2012    source источник
comment
Вас также может заинтересовать генератор случайных лабиринтов. Он удаляет все недоступные комнаты больше 1 после создания лабиринта. Также доступен скринкаст.   -  person choroba    schedule 29.11.2012
comment
@choroba: Это действительно здорово, спасибо! Я, конечно, буду играть с этим.   -  person spex    schedule 29.11.2012
comment
Один из ваших второстепенных вопросов: почему 205 и 206 вместо 109 и 110? Книга подробно рассматривает это. Быстрый ответ: именно так программа была опубликована в то время (около 1982 г.). Авторы предполагают на странице 226: Вероятное объяснение можно найти в том, как Commodore 64 реагирует на PRINT ASC(X)... [пользователь] может ввести PRINT ASC(/), и компьютер ответит 206. Не совсем так. Ваш главный вопрос, но не удержался от ответа :)   -  person Steve Koch    schedule 20.04.2013
comment
Большое спасибо @SteveKoch   -  person spex    schedule 14.07.2013
comment
Если я правильно понимаю аббревиатуры BASIC, R_ в вашей самой короткой версии должно быть R<shift>N, а не R<shift>A (для RND).   -  person nneonneo    schedule 23.06.2016


Ответы (7)


Как насчет этого?

# The characters you want to use
chars=( $'\xe2\x95\xb1' $'\xe2\x95\xb2' )
# Precompute the size of the array chars
nchars=${#chars[@]}
# clear screen
clear
# The loop that prints it:
while :; do
    printf -- "${chars[RANDOM%nchars]}"
done

Как однострочник с более короткими именами переменных, чтобы сделать его более кратким:

c=($'\xe2\x95\xb1' $'\xe2\x95\xb2'); n=${#c[@]}; clear; while :; do printf -- "${c[RANDOM%n]}"; done

Вы можете избавиться от цикла, если заранее знаете, сколько символов нужно напечатать (здесь 80 * 24 = 1920).

c=($'\xe2\x95\xb1' $'\xe2\x95\xb2'); n=${#c[@]}; clear; printf "%s" "${c[RANDOM%n]"{1..1920}"}"

Или, если вы хотите включить символы напрямую вместо их кода:

c=(╱‬ ╲); n=${#c[@]}; clear; while :; do printf "${c[RANDOM%n]}"; done

Наконец, с предварительно вычисленным размером массива c и удалением ненужных пробелов и кавычек (и я не могу быть короче этого):

c=(╱‬ ╲);clear;while :;do printf ${c[RANDOM%2]};done

Количество байтов, используемых для этой строки:

$ wc -c <<< 'c=(╱‬ ╲);clear;while :;do printf ${c[RANDOM%2]};done'
59

Изменить. Забавный способ с помощью команды yes:

clear;yes 'c=(╱ ╲);printf ${c[RANDOM%2]}'|bash

Он использует 50 байт:

$ wc -c <<< "clear;yes 'c=(╱ ╲);printf \${c[RANDOM%2]}'|bash"
51

или 46 символов:

$ wc -m <<< "clear;yes 'c=(╱ ╲);printf \${c[RANDOM%2]}'|bash"
47
person gniourf_gniourf    schedule 28.11.2012
comment
Тонны отличной информации, спасибо. Тем не менее, ваш окончательный однострочный скрипт не заполняет экран. есть идеи? Кажется, это может быть проблема с прямым включением символов. c=($'\xe2\x95\xb1' $'\xe2\x95\xb2');clear;while :;do printf ${c[RANDOM%2]};done работает нормально. - person spex; 28.11.2012
comment
@spex Извините, я понятия не имею, почему это не работает при прямом включении символов! возможно, это как-то связано с методом ввода вашего терминала... Попробуйте передать строку через od: od -t x1 <<< 'c=(╱‬ ╲);clear;while :;do printf ${c[RANDOM%2]};done', чтобы увидеть, что на самом деле отправляет ваш терминал... первая строка вывода должна быть 63 3d 28 e2 95 b1 e2 80 ac 20 e2 95 b2 29 3b 63. - person gniourf_gniourf; 28.11.2012
comment
Сделал так, получил тот же вывод od 63 3d 28 e2 95 b1 e2 80 ac 20 e2 95 b2 29 3b 63 - person spex; 28.11.2012
comment
@spex о, тогда вам придется вводить код utf-8 с конструкцией $'...' вместо того, чтобы вставлять символ напрямую, извините за это. (но в Debian с bash 4.2.24 он отлично работает). - person gniourf_gniourf; 28.11.2012
comment
Да, это была проблема с копированием и вставкой, я не мог ее точно определить, но просто вручную реконструировал строку, чтобы заставить ее работать c=(╱ ╲);while :;do printf "%s" ${c[RANDOM%2]};done Спасибо! - person spex; 28.11.2012

После просмотра некоторых материалов UTF:

2571 BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT
2572 BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT

(╱ и ╲) кажутся лучшими.

f="╱╲";while :;do print -n ${f[(RANDOM % 2) + 1]};done

также работает в zsh (спасибо Клинту из OFTC за предоставленную информацию)

person paultag    schedule 28.11.2012
comment
Они определенно выглядят лучше clear; while :; do [ $(($RANDOM%2)) == 0 ] && (printf "╱") || (printf "╲"); done; Спасибо! По-прежнему открыты для других идей символов и делают код более кратким. Мне также интересно, есть ли лучший способ напечатать эти символы UTF-8... - person spex; 28.11.2012
comment
Ваш пример работает только в zsh. В Bash нет команды печати. - person spex; 29.11.2012

Вот мое 39-символьное решение командной строки, которое я только что отправил на @climagic:

grep -ao "[/\\]" /dev/urandom|tr -d \\n

В bash вы можете удалить двойные кавычки вокруг выражения соответствия [/\] и сделать его еще короче, чем решение C64, но я включил их для надежности и совместимости с разными оболочками. Если бы у grep была опция с одним символом, чтобы заставить grep обрезать новые строки, вы могли бы сделать это 27 символами.

Я знаю, что здесь не используются символы Unicode, поэтому, возможно, это не считается. Можно найти символы Unicode в /dev/urandom, но это займет много времени, потому что эта последовательность встречается реже, и если вы ее передаете, командный конвейер, вероятно, «застрянет» на некоторое время, прежде чем выдаст что-либо должное. для буферизации строк.

person Community    schedule 02.05.2013

Bash теперь поддерживает Unicode, поэтому нам не нужно использовать последовательности символов UTF-8, такие как $'\xe2\x95\xb1'.

Это моя самая правильная версия: она зацикливается, печатает либо /, либо \ на основе случайного числа, как это делают другие.

for((;;x=RANDOM%2+2571)){ printf "\U$x";}
41

Мой предыдущий лучший результат был:

while :;do printf "\U257"$((RANDOM%2+1));done
45

А этот «обманывает», используя встроенный Unicode (я думаю, что из-за очевидности, удобства сопровождения и простоты это мой фаворит).

Z=╱╲;for((;;)){ printf ${Z:RANDOM&1:1};}
40

Мой предыдущий лучший результат был:

while Z=╱╲;do printf ${Z:RANDOM&1:1};done
41

И вот еще несколько.

while :;do ((RANDOM&1))&&printf "\U2571"||printf "\U2572";done
while printf -v X "\\\U%d" $((2571+RANDOM%2));do printf $X;done
while :;do printf -v X "\\\U%d" $((2571+RANDOM%2));printf $X;done
while printf -v X '\\U%d' $((2571+RANDOM%2));do printf $X;done
c=('\U2571' '\U2572');while :;do printf ${c[RANDOM&1]};done
X="\U257";while :;do printf $X$((RANDOM%2+1));done

Теперь этот работает до тех пор, пока мы не получим переполнение стека (не другое!), поскольку bash, похоже, еще не поддерживает устранение хвостового вызова.

f(){ printf "\U257"$((RANDOM%2+1));f;};f
40

И это моя попытка реализовать грубую форму устранения хвостового процесса. Но когда вам надоест и вы нажмете ctrl-c, ваш терминал исчезнет.

f(){ printf "\U257"$((RANDOM%2+1));exec bash -c f;};export -f f;f

ОБНОВИТЬ:

И еще несколько.

X=(╱ ╲);echo -e "\b${X[RANDOM&1]"{1..1000}"}" 46
X=("\U2571" "\U2572");echo -e "\b${X[RANDOM&1]"{1..1000}"}" 60
X=(╱ ╲);while :;do echo -n ${X[RANDOM&1]};done 46
Z=╱╲;while :;do echo -n ${Z:RANDOM&1:1};done 44
person Community    schedule 02.05.2013
comment
Интересно отметить разницу в скорости между вашим 41-символьным решением while Z=╱╲;do printf ${Z:RANDOM&1:1};done и этим 40-символьным решением yes 'c=(╱ ╲);printf ${c[RANDOM%2]}'|bash - person spex; 21.01.2014
comment
Я думаю, что использование «да» немного обманывает, поскольку это не баш. Но мы учимся на этих проблемах. - person philcolbourn; 30.01.2014

Извините за некропостинг, но вот bash-версия в 38 символов.

yes 'printf \\u$[2571+RANDOM%2]'|bash

использование for вместо yes увеличивает это до 40 символов:

for((;;)){ printf \\u$[2571+RANDOM%2];}
person Community    schedule 03.03.2015
comment
Хороший вклад! К сожалению, чтобы это работало для версии Bash по умолчанию для Mac OS X, это должно быть yes 'printf \\xe2\\x95\\xb$[1+RANDOM%2]'|bash, что составляет 45 символов. - person spex; 24.03.2015
comment
Я пробовал это на 4.3. Я полагаю, что первая версия, поддерживающая экранирование \u в printf, была 4.1. - person lierdakil; 10.05.2015

109 chr для Python 3 Это было самое маленькое, что я мог получить.

#!/usr/bin/python3
import random
while True:
    if random.randrange(2)==1:print('\u2572',end='') 
    else:print('\u2571',end='')
person Community    schedule 13.03.2020

Вот версия для Batch, которая умещается в 127 символов:

cmd /v:on /c "for /l %a in (0,0,0) do @set /a "a=!random!%2" >nul & if "!a!"=="0" (set /p ".=/" <nul) else (set /p ".=\" <nul)"
person Community    schedule 09.08.2020