Search code examples
bashc64

Bash Version of C64 Code Art: 10 PRINT CHR$(205.5+RND(1)); : GOTO 10


I picked up a copy of the book 10 PRINT CHR$(205.5+RND(1)); : GOTO 10

This book discusses the art produced by the single line of Commodore 64 BASIC:

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

This just repeatedly prints randomly character 205 or 206 to the screen from the PETSCII set:

I'm not sure why the original uses the characters 205 and 206 instead of the identical 109 and 110. Also, I prefer to add a clear at the beginning. This is what I usually type into the C64:

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

You can try this all for yourself in an emulator, such as this one using Flash or JavaScript:


I decided it would be amusing to write a bash line to do something similar.

I currently have:

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

Two questions:

  1. Any suggestions for making this more concise?
  2. Any suggestions for a better output character? The forward and backward slash are not nearly as beautiful since their points don't line up. The characters used from PETSCII are special characters, not slashes. I didn't see anything in ASCII that could work as well, but maybe you can suggest a way to pull in a character from UTF-8 or something else?

Best ANSWERS So Far

Shortest for bash (40 characters):

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

Here is a short one for zsh (53 characters):

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

Here is an alias I like to put in my .bashrc or .profile

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

Funny comparing this to the shortest I can do for C64 BASIC (23 characters):

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

The underscores are shift+H, shift+N, and shift+O respectively. I can't paste the character here since they are specific to PETSCII. Also, the C64 output looks prettier ;)

You can read about the C64 BASIC abbreviations here:


Solution

  • How about this?

    # 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
    

    As a one-liner with shorter variable names to make it more concise:

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

    You can get rid of the loop if you know in advance how many characters to print (here 80*24=1920)

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

    Or, if you want to include the characters directly instead of their code:

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

    Finally, with the size of the array c precomputed and removing unnecessary spaces and quotes (and I can't get shorter than this):

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

    Number of bytes used for this line:

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

    Edit. A funny way using the command yes:

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

    It uses 50 bytes:

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

    or 46 characters:

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