Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- # horserace.sh: Very simple horserace simulation.
- # Author: Stefano Palmeri
- # Used with permission.
- ################################################################
- # Goals of the script:
- # playing with escape sequences and terminal colors.
- #
- # Exercise:
- # Edit the script to make it run less randomly,
- #+ set up a fake betting shop . . .
- # Um . . . um . . . it's starting to remind me of a movie . . .
- #
- # The script gives each horse a random handicap.
- # The odds are calculated upon horse handicap
- #+ and are expressed in European(?) style.
- # E.g., odds=3.75 means that if you bet $1 and win,
- #+ you receive $3.75.
- #
- # The script has been tested with a GNU/Linux OS,
- #+ using xterm and rxvt, and konsole.
- # On a machine with an AMD 900 MHz processor,
- #+ the average race time is 75 seconds.
- # On faster computers the race time would be lower.
- # So, if you want more suspense, reset the USLEEP_ARG variable.
- #
- # Script by Stefano Palmeri.
- ################################################################
- E_RUNERR=65
- # Check if md5sum and bc are installed.
- if ! which bc &> /dev/null; then
- echo bc is not installed.
- echo "Can\'t run . . . "
- exit $E_RUNERR
- fi
- if ! which md5sum &> /dev/null; then
- echo md5sum is not installed.
- echo "Can\'t run . . . "
- exit $E_RUNERR
- fi
- # Set the following variable to slow down script execution.
- # It will be passed as the argument for usleep (man usleep)
- #+ and is expressed in microseconds (500000 = half a second).
- SLEEP_ARG=0
- # Clean up the temp directory, restore terminal cursor and
- #+ terminal colors -- if script interrupted by Ctl-C.
- trap 'echo -en "\E[?25h"; echo -en "\E[0m"; stty echo;\
- tput cup 20 0; rm -fr $HORSE_RACE_TMP_DIR' TERM EXIT
- # See the chapter on debugging for an explanation of 'trap.'
- # Set a unique (paranoid) name for the temp directory the script needs.
- HORSE_RACE_TMP_DIR=$HOME/.horserace-`date +%s`-`head -c10 /dev/urandom \
- | md5sum | head -c30`
- # Create the temp directory and move right in.
- mkdir $HORSE_RACE_TMP_DIR
- cd $HORSE_RACE_TMP_DIR
- # This function moves the cursor to line $1 column $2 and then prints $3.
- # E.g.: "move_and_echo 5 10 linux" is equivalent to
- #+ "tput cup 4 9; echo linux", but with one command instead of two.
- # Note: "tput cup" defines 0 0 the upper left angle of the terminal,
- #+ echo defines 1 1 the upper left angle of the terminal.
- move_and_echo() {
- echo -ne "\E[${1};${2}H""$3"
- }
- # Function to generate a pseudo-random number between 1 and 9.
- random_1_9 ()
- {
- head -c10 /dev/urandom | md5sum | tr -d [a-z] | tr -d 0 | cut -c1
- }
- # Two functions that simulate "movement," when drawing the horses.
- draw_horse_one() {
- echo -n " "//$MOVE_HORSE//
- }
- draw_horse_two(){
- echo -n " "\\\\$MOVE_HORSE\\\\
- }
- # Define current terminal dimension.
- N_COLS=`tput cols`
- N_LINES=`tput lines`
- # Need at least a 20-LINES X 80-COLUMNS terminal. Check it.
- if [ $N_COLS -lt 80 ] || [ $N_LINES -lt 20 ]; then
- echo "`basename $0` needs a 80-cols X 20-lines terminal."
- echo "Your terminal is ${N_COLS}-cols X ${N_LINES}-lines."
- exit $E_RUNERR
- fi
- # Start drawing the race field.
- # Need a string of 80 chars. See below.
- BLANK80=`seq -s "" 100 | head -c80`
- clear
- # Set foreground and background colors to white.
- echo -ne '\E[37;47m'
- # Move the cursor on the upper left angle of the terminal.
- tput cup 0 0
- # Draw six white lines.
- for n in `seq 5`; do
- echo $BLANK80 # Use the 80 chars string to colorize the terminal.
- done
- # Sets foreground color to black.
- echo -ne '\E[30m'
- move_and_echo 3 1 "START 1"
- move_and_echo 3 75 FINISH
- move_and_echo 1 5 "|"
- move_and_echo 1 80 "|"
- move_and_echo 2 5 "|"
- move_and_echo 2 80 "|"
- move_and_echo 4 5 "| 2"
- move_and_echo 4 80 "|"
- move_and_echo 5 5 "V 3"
- move_and_echo 5 80 "V"
- # Set foreground color to red.
- echo -ne '\E[31m'
- # Some ASCII art.
- move_and_echo 1 8 "..@@@..@@@@@...@@@@@.@...@..@@@@..."
- move_and_echo 2 8 ".@...@...@.......@...@...@.@......."
- move_and_echo 3 8 ".@@@@@...@.......@...@@@@@.@@@@...."
- move_and_echo 4 8 ".@...@...@.......@...@...@.@......."
- move_and_echo 5 8 ".@...@...@.......@...@...@..@@@@..."
- move_and_echo 1 43 "@@@@...@@@...@@@@..@@@@..@@@@."
- move_and_echo 2 43 "@...@.@...@.@.....@.....@....."
- move_and_echo 3 43 "@@@@..@@@@@.@.....@@@@...@@@.."
- move_and_echo 4 43 "@..@..@...@.@.....@.........@."
- move_and_echo 5 43 "@...@.@...@..@@@@..@@@@.@@@@.."
- # Set foreground and background colors to green.
- echo -ne '\E[32;42m'
- # Draw eleven green lines.
- tput cup 5 0
- for n in `seq 11`; do
- echo $BLANK80
- done
- # Set foreground color to black.
- echo -ne '\E[30m'
- tput cup 5 0
- # Draw the fences.
- echo "++++++++++++++++++++++++++++++++++++++\
- ++++++++++++++++++++++++++++++++++++++++++"
- tput cup 15 0
- echo "++++++++++++++++++++++++++++++++++++++\
- ++++++++++++++++++++++++++++++++++++++++++"
- # Set foreground and background colors to white.
- echo -ne '\E[37;47m'
- # Draw three white lines.
- for n in `seq 3`; do
- echo $BLANK80
- done
- # Set foreground color to black.
- echo -ne '\E[30m'
- # Create 9 files to stores handicaps.
- for n in `seq 10 7 68`; do
- touch $n
- done
- # Set the first type of "horse" the script will draw.
- HORSE_TYPE=2
- # Create position-file and odds-file for every "horse".
- #+ In these files, store the current position of the horse,
- #+ the type and the odds.
- for HN in `seq 9`; do
- touch horse_${HN}_position
- touch odds_${HN}
- echo \-1 > horse_${HN}_position
- echo $HORSE_TYPE >> horse_${HN}_position
- # Define a random handicap for horse.
- HANDICAP=`random_1_9`
- # Check if the random_1_9 function returned a good value.
- while ! echo $HANDICAP | grep [1-9] &> /dev/null; do
- HANDICAP=`random_1_9`
- done
- # Define last handicap position for horse.
- LHP=`expr $HANDICAP \* 7 + 3`
- for FILE in `seq 10 7 $LHP`; do
- echo $HN >> $FILE
- done
- # Calculate odds.
- case $HANDICAP in
- 1) ODDS=`echo $HANDICAP \* 0.25 + 1.25 | bc`
- echo $ODDS > odds_${HN}
- ;;
- 2 | 3) ODDS=`echo $HANDICAP \* 0.40 + 1.25 | bc`
- echo $ODDS > odds_${HN}
- ;;
- 4 | 5 | 6) ODDS=`echo $HANDICAP \* 0.55 + 1.25 | bc`
- echo $ODDS > odds_${HN}
- ;;
- 7 | 8) ODDS=`echo $HANDICAP \* 0.75 + 1.25 | bc`
- echo $ODDS > odds_${HN}
- ;;
- 9) ODDS=`echo $HANDICAP \* 0.90 + 1.25 | bc`
- echo $ODDS > odds_${HN}
- esac
- done
- # Print odds.
- print_odds() {
- tput cup 6 0
- echo -ne '\E[30;42m'
- for HN in `seq 9`; do
- echo "#$HN odds->" `cat odds_${HN}`
- done
- }
- # Draw the horses at starting line.
- draw_horses() {
- tput cup 6 0
- echo -ne '\E[30;42m'
- for HN in `seq 9`; do
- echo /\\$HN/\\" "
- done
- }
- print_odds
- echo -ne '\E[47m'
- # Wait for a enter key press to start the race.
- # The escape sequence '\E[?25l' disables the cursor.
- tput cup 17 0
- echo -e '\E[?25l'Press [enter] key to start the race...
- read -s
- # Disable normal echoing in the terminal.
- # This avoids key presses that might "contaminate" the screen
- #+ during the race.
- stty -echo
- # --------------------------------------------------------
- # Start the race.
- draw_horses
- echo -ne '\E[37;47m'
- move_and_echo 18 1 $BLANK80
- echo -ne '\E[30m'
- move_and_echo 18 1 Starting...
- sleep 1
- # Set the column of the finish line.
- WINNING_POS=74
- # Define the time the race started.
- START_TIME=`date +%s`
- # COL variable needed by following "while" construct.
- COL=0
- while [ $COL -lt $WINNING_POS ]; do
- MOVE_HORSE=0
- # Check if the random_1_9 function has returned a good value.
- while ! echo $MOVE_HORSE | grep [1-9] &> /dev/null; do
- MOVE_HORSE=`random_1_9`
- done
- # Define old type and position of the "randomized horse".
- HORSE_TYPE=`cat horse_${MOVE_HORSE}_position | tail -n 1`
- COL=$(expr `cat horse_${MOVE_HORSE}_position | head -n 1`)
- ADD_POS=1
- # Check if the current position is an handicap position.
- if seq 10 7 68 | grep -w $COL &> /dev/null; then
- if grep -w $MOVE_HORSE $COL &> /dev/null; then
- ADD_POS=0
- grep -v -w $MOVE_HORSE $COL > ${COL}_new
- rm -f $COL
- mv -f ${COL}_new $COL
- else ADD_POS=1
- fi
- else ADD_POS=1
- fi
- COL=`expr $COL + $ADD_POS`
- echo $COL > horse_${MOVE_HORSE}_position # Store new position.
- # Choose the type of horse to draw.
- case $HORSE_TYPE in
- 1) HORSE_TYPE=2; DRAW_HORSE=draw_horse_two
- ;;
- 2) HORSE_TYPE=1; DRAW_HORSE=draw_horse_one
- esac
- echo $HORSE_TYPE >> horse_${MOVE_HORSE}_position
- # Store current type.
- # Set foreground color to black and background to green.
- echo -ne '\E[30;42m'
- # Move the cursor to new horse position.
- tput cup `expr $MOVE_HORSE + 5` \
- `cat horse_${MOVE_HORSE}_position | head -n 1`
- # Draw the horse.
- $DRAW_HORSE
- sleep $SLEEP_ARG
- # When all horses have gone beyond field line 15, reprint odds.
- touch fieldline15
- if [ $COL = 15 ]; then
- echo $MOVE_HORSE >> fieldline15
- fi
- if [[ `wc -l fieldline15 | cut -f1 -d " "` = 9 ]]; then
- print_odds
- : > fieldline15
- fi
- # Define the leading horse.
- HIGHEST_POS=`cat *position | sort -n | tail -1`
- # Set background color to white.
- echo -ne '\E[47m'
- tput cup 17 0
- echo -n Current leader: `grep -w $HIGHEST_POS *position | cut -c7`\
- " "
- done
- # Define the time the race finished.
- FINISH_TIME=`date +%s`
- # Set background color to green and enable blinking text.
- echo -ne '\E[30;42m'
- echo -en '\E[5m'
- # Make the winning horse blink.
- tput cup `expr $MOVE_HORSE + 5` \
- `cat horse_${MOVE_HORSE}_position | head -n 1`
- $DRAW_HORSE
- # Disable blinking text.
- echo -en '\E[25m'
- # Set foreground and background color to white.
- echo -ne '\E[37;47m'
- move_and_echo 18 1 $BLANK80
- # Set foreground color to black.
- echo -ne '\E[30m'
- # Make winner blink.
- tput cup 17 0
- echo -e "\E[5mWINNER: $MOVE_HORSE\E[25m"" Odds: `cat odds_${MOVE_HORSE}`"\
- " Race time: `expr $FINISH_TIME - $START_TIME` secs"
- # Restore cursor and old colors.
- echo -en "\E[?25h"
- echo -en "\E[0m"
- # Restore echoing.
- stty echo
- # Remove race temp directory.
- rm -rf $HORSE_RACE_TMP_DIR
- tput cup 19 0
- exit 0
Add Comment
Please, Sign In to add comment