terminalzshascii-art

Bash/Zsh - How to randomly color letters in ascii art block text?


I am writing a zsh script to display ascii art in different colors.

Basically I have ascii text written in block letters and I want to write a script that randomizes the colors of each one using color escaped characters.

The text is

 [like this](https://pastebin.com/nCs6kNzu) 

1$$$$$$$\ 2 $$$$$$$$\ 3$$\   $$\ 4 $$$$$$\  5$$\       6$$$$$$$\  
1$$  __$$\2 $$  _____|3$$ |  $$ |4$$  __$$\ 5$$ |      6$$  __$$\ 
1$$ |  $$ 2|$$ |      3$$ |  $$ |4$$ /  $$ |5$$ |      6$$ |  $$ |
1$$$$$$$\ 2|$$$$$\    3$$$$$$$$ |4$$ |  $$ |5$$ |      6$$ |  $$ |
1$$  __$$\2 $$  __|   3$$  __$$ |4$$ |  $$ |5$$ |      6$$ |  $$ |
1$$ |  $$ 2|$$ |      3$$ |  $$ |4$$ |  $$ |5$$ |      6$$ |  $$ |
1$$$$$$$  2|$$$$$$$$\ 3$$ |  $$ |4 $$$$$$  |5$$$$$$$$\ 6$$$$$$$  |
1\_______/2 \________|3\__|  \__|4 \______/ 5\________|6\_______/ 

I want to make a script that:

  1. Creates an array of six random colors

  2. Randomizes the order of the colors

  3. You'll notice in the ascii there are number characters before each letter e.g. 1 is before 'B', 2 is before 'E'. I want to replace each one with a color so that each 'letter' of the ascii art is a different color.

  4. This is my attempt on the code so far and it's not working:


# Define array of colors
colors=("[31m" "[32m" "[33m" "[34m" "[35m" "[36m")

# Randomize the order of colors in the array
colors=($(printf "%s\n" "${colors[@]}" | shuf))

# Read ASCII art from file or source
ascii_art=$(<ascii_art.txt)

# Function to replace number characters with colors
replace_numbers_with_colors() {
    local text="$1"
    local result=""
    local index=0
    for ((i = 0; i < ${#text}; i++)); do
        local char="${text:i:1}"
        if [[ $char =~ [0-9] ]]; then
            result="${result}${colors[index]}$char[0m"
            ((index++))
        else
            result="${result}$char"
        fi
    done
    echo "$result"
}

# Replace numbers with colors in ASCII art
colored_ascii_art=$(replace_numbers_with_colors "$ascii_art")

# Print the colored ASCII art
echo -e "$colored_ascii_art"

So far it only colors one letter and doesn't delete the numbers.

The output looks like this

and only the first letter of the first line is colored.

Please let me know how to approach this.

I also thought keeping the text in six different elements of an array, then I could iterate through it two dimensionally; by array element and by line number


Solution

  • This can be done as a set of text substitutions: for each part of an ascii-art letter, change a number followed by some text to color codes followed by that text (and maybe some closing color codes).

    With that in mind, we can use a zsh text replacement expansion. Try this:

    #!/usr/bin/env zsh
    
    colorByNumbers() {
     local c=(red green blue cyan magenta yellow black white)
     c=( /(e['reply=("$c[@]")']noe['REPLY=$RANDOM']) )
     print -Pr -- \
     ${(*)1//(#b)([[:digit:]])([^[:digit:]]##)/%F{${c[match[1]]}}${match[2]//\%/%%}%f}
    }
    
    
    text='1$$$$$$$\ 2 $$$$$$$$\ 3$$\   $$\ 4 $$$$$$\  5$$\       6$$$$$$$\  
    1$$  __$$\2 $$  _____|3$$ |  $$ |4$$  __$$\ 5$$ |      6$$  __$$\ 
    1$$ |  $$ 2|$$ |      3$$ |  $$ |4$$ /  $$ |5$$ |      6$$ |  $$ |
    1$$$$$$$\ 2|$$$$$\    3$$$$$$$$ |4$$ |  $$ |5$$ |      6$$ |  $$ |
    1$$  __$$\2 $$  __|   3$$  __$$ |4$$ |  $$ |5$$ |      6$$ |  $$ |
    1$$ |  $$ 2|$$ |      3$$ |  $$ |4$$ |  $$ |5$$ |      6$$ |  $$ |
    1$$$$$$$  2|$$$$$$$$\ 3$$ |  $$ |4 $$$$$$  |5$$$$$$$$\ 6$$$$$$$  |
    1\_______/2 \________|3\__|  \__|4 \______/ 5\________|6\_______/ '
    
    colorByNumbers $text
    

    Some references: