mirror of https://github.com/tLDP/LDP
391 lines
11 KiB
Bash
391 lines
11 KiB
Bash
#!/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).
|
|
USLEEP_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
|
|
usleep $USLEEP_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
|