LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-30-2019, 11:09 AM   #1
teckk
Senior Member
 
Registered: Oct 2004
Distribution: FreeBSD Arch
Posts: 2,241

Rep: Reputation: 474Reputation: 474Reputation: 474Reputation: 474Reputation: 474
Bash practice for newer bash scripters.


Can I encourage some bash practice for some of our newer members, and try to make it a little fun?
I don't know if anyone is interested, but I'll give it a try.

Lets start with something amusing. Make it snow in the terminal.
Code:
#! /usr/bin/bash

declare -A snowflakes
declare -A lastflakes

clear

lines=$(tput lines)
columns=$(tput cols)

move_flake() {
    i="$1"
    if [ "${snowflakes[$i]}" = "" ] || [ "${snowflakes[$i]}" = "$lines" ]; then
        snowflakes[$i]=0
    else
        if [ "${lastflakes[$i]}" != "" ]; then
            printf "\033[%s;%sH \033[0;0H" "${lastflakes[$i]}" "$i"
        fi
    fi
    printf "\033[%s;%sH*\033[0;0H" "${snowflakes[$i]}" "$i"

    lastflakes[$i]="${snowflakes[$i]}"
    snowflakes[$i]="$((${snowflakes[$i]} + 1))"
}

while :; do
    i=$(($RANDOM % $columns))
    move_flake "$i"
    for x in "${!lastflakes[@]}"; do
        move_flake "$x"
    done
    sleep 0.1
done
And now for the practice.

1. Make the snow pile up on the ground to a greater depth over time.

2. Make the snow blow sideways a little.

3. Make the snowflakes fall at different rates of speed.

4. Make the sun come out and melt the snow slowly.

5. Make the snowflakes different colors.

6. Make the snow stop when the ground is fully covered.

There are arrays, variables, functions, loops, boolean logic, if then else, in that little script.

Go ahead, alter the snowfall and learn more about bash in the process.
 
Old 07-01-2019, 08:55 AM   #2
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 1,152

Rep: Reputation: 525Reputation: 525Reputation: 525Reputation: 525Reputation: 525Reputation: 525
Without (yet) understanding how it works - the following looks "sub optimal"
Code:
    if [ "${snowflakes[$i]}" = "" ] || [ "${snowflakes[$i]}" = "$lines" ]; then
        snowflakes[$i]=0
    else
        if [ "${lastflakes[$i]}" != "" ]; then
            printf "\033[%s;%sH \033[0;0H" "${lastflakes[$i]}" "$i"
        fi
    fi
Unless something is planned for the else branch that is outside the inner if-fi, it should become an elif
Code:
    if [ "${snowflakes[$i]}" = "" ] || [ "${snowflakes[$i]}" = "$lines" ]; then
        snowflakes[$i]=0
    elif [ "${lastflakes[$i]}" != "" ]; then
        printf "\033[%s;%sH \033[0;0H" "${lastflakes[$i]}" "$i"
    fi
 
Old 07-01-2019, 02:27 PM   #3
teckk
Senior Member
 
Registered: Oct 2004
Distribution: FreeBSD Arch
Posts: 2,241

Original Poster
Rep: Reputation: 474Reputation: 474Reputation: 474Reputation: 474Reputation: 474
@MadeInGermany, thank you.

Quote:
6. Make the snow stop when the ground is fully covered.
Here it snows until the ground is covered and then the snowfall stops.
Code:
#! /usr/bin/bash

declare -A snowflakes
declare -A lastflakes

clear

lines=$(($tput lines - 1))
columns=$(tput cols)

move_flake() {
    i="$1"
    if [ "${snowflakes[$i]}" = "" ] || [ "${snowflakes[$i]}" = "$lines" ]; then
        snowflakes[$i]=0
    elif [ "${lastflakes[$i]}" != "" ]; then
            printf "\033[%s;%sH \033[0;0H" "${lastflakes[$i]}" "$i"
    fi
    printf "\033[%s;%sH*\033[0;0H" "${snowflakes[$i]}" "$i"

    lastflakes[$i]="${snowflakes[$i]}"
    snowflakes[$i]="$((${snowflakes[$i]} + 1))"
}

while :; do
    i=$(($RANDOM % $columns))
    move_flake "$i"
    for x in "${!lastflakes[@]}"; do
        move_flake "$x"
    done
    sleep 0.1
done
Quote:
5. Make the snowflakes different colors.
Blue snow, brrrr cold.
Code:
#! /usr/bin/bash

declare -A snowflakes
declare -A lastflakes

clear

lines=$(tput lines)
columns=$(tput cols)
blue=$(tput setaf 4)

move_flake() {
    i="$1"
    if [ "${snowflakes[$i]}" = "" ] || [ "${snowflakes[$i]}" = "$lines" ]; then
        snowflakes[$i]=0
    elif [ "${lastflakes[$i]}" != "" ]; then
            printf "\033[%s;%sH \033[0;0H" "${lastflakes[$i]}" "$i"
    fi
    printf "${blue}\033[%s;%sH*\033[0;0H" "${snowflakes[$i]}" "$i"

    lastflakes[$i]="${snowflakes[$i]}"
    snowflakes[$i]="$((${snowflakes[$i]} + 1))"
}

while :; do
    i=$(($RANDOM % $columns))
    move_flake "$i"
    for x in "${!lastflakes[@]}"; do
        move_flake "$x"
    done
    sleep 0.1
done
 
Old 07-05-2019, 09:57 AM   #4
Stéphane Ascoët
Member
 
Registered: Feb 2004
Location: Fleury-les-Aubrais, 120 km south of Paris
Distribution: Devuan, Debian, Mandrake, Freeduc (the one I used to work on), Slackware, MacOS X
Posts: 245

Rep: Reputation: 47
I don't understand very much the code, especially without comments.

To assign a random color to each flake, you can define an array with the 16 colors, pick one at random and affect it to a flake(adding a column in flakes arrays) and then use it when displaying it instead of a fixed $blue.
 
Old 07-05-2019, 05:07 PM   #5
teckk
Senior Member
 
Registered: Oct 2004
Distribution: FreeBSD Arch
Posts: 2,241

Original Poster
Rep: Reputation: 474Reputation: 474Reputation: 474Reputation: 474Reputation: 474
Excellent answer. Something like this blowing multi color snow storm.
Code:
#! /usr/bin/bash

declare -A snowflakes
declare -A lastflakes

clear

lines=$(tput lines)
columns=$(tput cols)

move_flake() {
    i="$1"
    if [ "${snowflakes[$i]}" = "" ] || [ "${snowflakes[$i]}" = "$lines" ]; then
        snowflakes[$i]=0
    elif [ "${lastflakes[$i]}" != "" ]; then
            printf "\033[%s;%sH \033[0;0H" "${lastflakes[$i]}" "$i"
    fi
    
    printf "${color}\033[%s;%sH*\033[0;0H" "${snowflakes[$i]}" "$i"

    lastflakes[$i]="${snowflakes[$i]}"
    snowflakes[$i]="$((${snowflakes[$i]} + 1))"

}

while :; do
    for col in {1..7}; do
        color=$(tput setaf "$col")
        i=$(($RANDOM % $columns))
        move_flake "$i"
        for x in "${!lastflakes[@]}"; do
            move_flake "$x"
        done
        sleep 0.01
    done
done
Now make the snows depth on the ground increase over time.
 
Old 07-06-2019, 01:12 PM   #6
teckk
Senior Member
 
Registered: Oct 2004
Distribution: FreeBSD Arch
Posts: 2,241

Original Poster
Rep: Reputation: 474Reputation: 474Reputation: 474Reputation: 474Reputation: 474
Ok, next one.

Pipes in the terminal, like an old Microsoft windows machine screensaver.
Sparsely commented, you'll need to pick it apart and learn. The function
names are self explanatory.

There is math in this one, random numbers, loops, arrays. As you see, some
of the variables are not even assigned before usage. That's ok. They will
get a value when you make an equation with them.

Minimal script, you'll need to Ctrl+C to get out of it.
Code:
#!/usr/bin/env bash

pipes=("┃┏ ┓┛━┓  ┗┃┛┗ ┏━")

PIPES=()  

#Number of pipes
p=1

#Get term size
resize() {
    w=$(tput cols) 
    h=$(tput lines)
}

init_screen() {
    stty -echo
    tput smcup
    tput civis
    tput clear
    trap cleanup HUP TERM
    resize
    trap resize SIGWINCH
}

main() { 
    #Set term bg black
    tput setab 0
    #Pipe colors, leave out black
    C=(1 2 3 4 5 6 7)
    CN=${#C[@]}

    for ((i = 0; i < CN; i++)); do
        E[i]+=$(tput setaf ${C[i]})
    done

    for ((i = 0; i < ${#pipes[@]}; i++)); do
        for ((j = 0; j < 16; j++)); do
            PIPES+=("${pipes[i]:j:1}")
        done
    done

    init_screen
    t=0

    while :; do
        read -t 0.02 -n 1 2>/dev/null
        for ((i = 0; i < p; i++)); do
            ((l[i] % 2)) && ((x[i] += -l[i] + 2, 1)) || ((y[i] += l[i] - 1))
            
            # Loop at edge
            ((!0 && (x[i] >= w || x[i] < 0 || y[i] >= h || y[i] < 0))) \
            && { c[i]=${E[CN * RANDOM / 32768]}; ((v[i] = V[VN * RANDOM / 32768])); }
            ((x[i] = (x[i] + w) % w, y[i] = (y[i] + h) % h))

            ((
                n[i] = 13 * RANDOM / 32768 - 1,
                n[i] = n[i] >= 0 ? l[i] : l[i] + (2 * (RANDOM % 2) - 1),
                n[i] = (n[i] + 4) % 4
            ))
            
            printf '\e[%d;%dH%s%s' $((y[i] + 1)) $((x[i] + 1)) ${c[i]} \
                   "${PIPES[v[i] * 16 + l[i] * 4 + n[i]]}"
                   
            l[i]=${n[i]}
            t=$(($t + 1))
        done
        ((t > 3000)) && tput reset && tput civis && t=0 || ((t++))
    done
}

main "$@"
Now if you want the challenge.

1. Change the speed that the pipes are drawn.

2. Let more or fewer pipes be drawn before reset.

3. Change the pipe sizes.

4. Have the pipes loop before the edge of the terminal is reached.

5. Change the number of pipes drawn at once.

6. Whatever else you want to do with it.
 
Old 07-28-2019, 07:15 PM   #7
teckk
Senior Member
 
Registered: Oct 2004
Distribution: FreeBSD Arch
Posts: 2,241

Original Poster
Rep: Reputation: 474Reputation: 474Reputation: 474Reputation: 474Reputation: 474
Don't know if any bash learners are interested in this or not. The thread has 400 views, so someone is looking. Here is another one to play with, mess up, and learn.

Raining on the windshield.
Code:
#!/usr/bin/env bash

RAINS=("|" "│" "┃" "┆" "┇" "┊" "┋" "╽" "╿")
COLORS=("\e[37m" "\e[37;1m")
NCOLORS=${#COLORS[@]}
NRAINS=${#RAINS[@]}
NUM_RAIN=5
tput setab 0

setup() {
  TERM_WIDTH=$(tput cols)
  TERM_HEIGHT=$(tput lines)
  STEP=0.01
  ((MAX_RAINS = TERM_WIDTH * TERM_HEIGHT / 4))
  ((MAX_LENGTH = TERM_HEIGHT < 10 ? 1 : TERM_HEIGHT / 10))
  ((NEW_RAIN = TERM_HEIGHT > 50 ? 100 : TERM_HEIGHT * 2))
  ((NEW_RAIN = NEW_RAIN * 75 / 100))
  ((FALLING = TERM_HEIGHT > 25 ? 100 : TERM_HEIGHT * 4))
  ((FALLING = FALLING * 90 / 100))
}

render() {
    for ((i = 0; i < num_rains * NUM_RAIN; i += NUM_RAIN)); do
        X=${rains[i]}
        Y=${rains[i + 1]}
        LENGTH=${rains[i + 4]}
        for ((y = Y; y < Y + LENGTH; y++)); do
            (( y < 1 || y > TERM_HEIGHT )) && continue
            echo -ne "\e[${y};${X}H "
        done
    done

    for ((i = 0; i < num_rains * NUM_RAIN; i += NUM_RAIN)); do
        if ((100 * RANDOM / 32768 < FALLING)); then
            if ((++rains[i + 1] > TERM_HEIGHT)); then
                rains=("${rains[@]:0:i}" 
                        "${rains[@]:i+NUM_RAIN:num_rains*NUM_RAIN}")
            ((num_rains--))
            continue
            fi
        fi
    
        X=${rains[i]}
        Y=${rains[i + 1]}
        RAIN=${rains[i + 2]}
        COLOR=${rains[i + 3]}
        LENGTH=${rains[i + 4]}
    
        for ((y = Y; y < Y + LENGTH; y++)); do
            (( y < 1 || y > TERM_HEIGHT )) && continue
            echo -ne "\e[${y};${X}H${COLOR}${RAIN}"
        done
    done
}

echo -ne "\e[?25l"
clear
rains=()
setup

while :; do
    read -n 1 -t "$STEP"

    if ((num_rains < MAX_RAINS)) && ((100 * RANDOM / 32768 < NEW_RAIN)); then
        RAIN="${RAINS[NRAINS * RANDOM / 32768]}"
        COLOR="${COLORS[NCOLORS * RANDOM / 32768]}"
        LENGTH=$((MAX_LENGTH * RANDOM / 32768 + 1))
        X=$((TERM_WIDTH * RANDOM / 32768 + 1))
        Y=$((1 - LENGTH))
        rains=("${rains[@]}" "$X" "$Y" "$RAIN" "$COLOR" "$LENGTH")
        ((num_rains++))
    fi

    render
done
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Best practice for running newer version of software than what is available as maintained Slackbuild? otl Slackware 7 04-27-2016 08:10 PM
Challenging script (for me at least!) Calling all scripters! Norwood Linux - General 8 03-07-2010 03:35 PM
LXer: Python for Bash scripters: A well-kept secret LXer Syndicated Linux News 0 02-08-2008 05:10 AM
Any kdialog scripters here? dive Programming 3 06-24-2007 09:53 PM
Quick Challange for shell scripters! neocookie Programming 2 09-12-2005 10:13 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 11:19 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration