Guest User

horserace.sh

a guest
Jul 14th, 2020
307
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 11.25 KB | None | 0 0
  1. #!/bin/bash
  2. # horserace.sh: Very simple horserace simulation.
  3. # Author: Stefano Palmeri
  4. # Used with permission.
  5.  
  6. ################################################################
  7. #  Goals of the script:
  8. #  playing with escape sequences and terminal colors.
  9. #
  10. #  Exercise:
  11. #  Edit the script to make it run less randomly,
  12. #+ set up a fake betting shop . . .    
  13. #  Um . . . um . . . it's starting to remind me of a movie . . .
  14. #
  15. #  The script gives each horse a random handicap.
  16. #  The odds are calculated upon horse handicap
  17. #+ and are expressed in European(?) style.
  18. #  E.g., odds=3.75 means that if you bet $1 and win,
  19. #+ you receive $3.75.
  20. #
  21. #  The script has been tested with a GNU/Linux OS,
  22. #+ using xterm and rxvt, and konsole.
  23. #  On a machine with an AMD 900 MHz processor,
  24. #+ the average race time is 75 seconds.    
  25. #  On faster computers the race time would be lower.
  26. #  So, if you want more suspense, reset the USLEEP_ARG variable.
  27. #
  28. #  Script by Stefano Palmeri.
  29. ################################################################
  30.  
  31. E_RUNERR=65
  32.  
  33. # Check if md5sum and bc are installed.
  34. if ! which bc &> /dev/null; then
  35.    echo bc is not installed.  
  36.    echo "Can\'t run . . . "
  37.    exit $E_RUNERR
  38. fi
  39. if ! which md5sum &> /dev/null; then
  40.    echo md5sum is not installed.  
  41.    echo "Can\'t run . . . "
  42.    exit $E_RUNERR
  43. fi
  44.  
  45. #  Set the following variable to slow down script execution.
  46. #  It will be passed as the argument for usleep (man usleep)  
  47. #+ and is expressed in microseconds (500000 = half a second).
  48. SLEEP_ARG=0
  49.  
  50. #  Clean up the temp directory, restore terminal cursor and
  51. #+ terminal colors -- if script interrupted by Ctl-C.
  52. trap 'echo -en "\E[?25h"; echo -en "\E[0m"; stty echo;\
  53. tput cup 20 0; rm -fr  $HORSE_RACE_TMP_DIR'  TERM EXIT
  54. #  See the chapter on debugging for an explanation of 'trap.'
  55.  
  56. # Set a unique (paranoid) name for the temp directory the script needs.
  57. HORSE_RACE_TMP_DIR=$HOME/.horserace-`date +%s`-`head -c10 /dev/urandom \
  58. | md5sum | head -c30`
  59.  
  60. # Create the temp directory and move right in.
  61. mkdir $HORSE_RACE_TMP_DIR
  62. cd $HORSE_RACE_TMP_DIR
  63.  
  64.  
  65. #  This function moves the cursor to line $1 column $2 and then prints $3.
  66. #  E.g.: "move_and_echo 5 10 linux" is equivalent to
  67. #+ "tput cup 4 9; echo linux", but with one command instead of two.
  68. #  Note: "tput cup" defines 0 0 the upper left angle of the terminal,
  69. #+ echo defines 1 1 the upper left angle of the terminal.
  70. move_and_echo() {
  71.           echo -ne "\E[${1};${2}H""$3"
  72. }
  73.  
  74. # Function to generate a pseudo-random number between 1 and 9.
  75. random_1_9 ()
  76. {
  77.     head -c10 /dev/urandom | md5sum | tr -d [a-z] | tr -d 0 | cut -c1
  78. }
  79.  
  80. #  Two functions that simulate "movement," when drawing the horses.
  81. draw_horse_one() {
  82.                echo -n " "//$MOVE_HORSE//
  83. }
  84. draw_horse_two(){
  85.               echo -n " "\\\\$MOVE_HORSE\\\\
  86. }  
  87.  
  88.  
  89. # Define current terminal dimension.
  90. N_COLS=`tput cols`
  91. N_LINES=`tput lines`
  92.  
  93. # Need at least a 20-LINES X 80-COLUMNS terminal. Check it.
  94. if [ $N_COLS -lt 80 ] || [ $N_LINES -lt 20 ]; then
  95.    echo "`basename $0` needs a 80-cols X 20-lines terminal."
  96.    echo "Your terminal is ${N_COLS}-cols X ${N_LINES}-lines."
  97.    exit $E_RUNERR
  98. fi
  99.  
  100.  
  101. # Start drawing the race field.
  102.  
  103. # Need a string of 80 chars. See below.
  104. BLANK80=`seq -s "" 100 | head -c80`
  105.  
  106. clear
  107.  
  108. # Set foreground and background colors to white.
  109. echo -ne '\E[37;47m'
  110.  
  111. # Move the cursor on the upper left angle of the terminal.
  112. tput cup 0 0
  113.  
  114. # Draw six white lines.
  115. for n in `seq 5`; do
  116.       echo $BLANK80   # Use the 80 chars string to colorize the terminal.
  117. done
  118.  
  119. # Sets foreground color to black.
  120. echo -ne '\E[30m'
  121.  
  122. move_and_echo 3 1 "START  1"            
  123. move_and_echo 3 75 FINISH
  124. move_and_echo 1 5 "|"
  125. move_and_echo 1 80 "|"
  126. move_and_echo 2 5 "|"
  127. move_and_echo 2 80 "|"
  128. move_and_echo 4 5 "|  2"
  129. move_and_echo 4 80 "|"
  130. move_and_echo 5 5 "V  3"
  131. move_and_echo 5 80 "V"
  132.  
  133. # Set foreground color to red.
  134. echo -ne '\E[31m'
  135.  
  136. # Some ASCII art.
  137. move_and_echo 1 8 "..@@@..@@@@@...@@@@@.@...@..@@@@..."
  138. move_and_echo 2 8 ".@...@...@.......@...@...@.@......."
  139. move_and_echo 3 8 ".@@@@@...@.......@...@@@@@.@@@@...."
  140. move_and_echo 4 8 ".@...@...@.......@...@...@.@......."
  141. move_and_echo 5 8 ".@...@...@.......@...@...@..@@@@..."
  142. move_and_echo 1 43 "@@@@...@@@...@@@@..@@@@..@@@@."
  143. move_and_echo 2 43 "@...@.@...@.@.....@.....@....."
  144. move_and_echo 3 43 "@@@@..@@@@@.@.....@@@@...@@@.."
  145. move_and_echo 4 43 "@..@..@...@.@.....@.........@."
  146. move_and_echo 5 43 "@...@.@...@..@@@@..@@@@.@@@@.."
  147.  
  148.  
  149. # Set foreground and background colors to green.
  150. echo -ne '\E[32;42m'
  151.  
  152. # Draw  eleven green lines.
  153. tput cup 5 0
  154. for n in `seq 11`; do
  155.       echo $BLANK80
  156. done
  157.  
  158. # Set foreground color to black.
  159. echo -ne '\E[30m'
  160. tput cup 5 0
  161.  
  162. # Draw the fences.
  163. echo "++++++++++++++++++++++++++++++++++++++\
  164. ++++++++++++++++++++++++++++++++++++++++++"
  165.  
  166. tput cup 15 0
  167. echo "++++++++++++++++++++++++++++++++++++++\
  168. ++++++++++++++++++++++++++++++++++++++++++"
  169.  
  170. # Set foreground and background colors to white.
  171. echo -ne '\E[37;47m'
  172.  
  173. # Draw three white lines.
  174. for n in `seq 3`; do
  175.       echo $BLANK80
  176. done
  177.  
  178. # Set foreground color to black.
  179. echo -ne '\E[30m'
  180.  
  181. # Create 9 files to stores handicaps.
  182. for n in `seq 10 7 68`; do
  183.       touch $n
  184. done  
  185.  
  186. # Set the first type of "horse" the script will draw.
  187. HORSE_TYPE=2
  188.  
  189. #  Create position-file and odds-file for every "horse".
  190. #+ In these files, store the current position of the horse,
  191. #+ the type and the odds.
  192. for HN in `seq 9`; do
  193.       touch horse_${HN}_position
  194.       touch odds_${HN}
  195.       echo \-1 > horse_${HN}_position
  196.       echo $HORSE_TYPE >>  horse_${HN}_position
  197.       # Define a random handicap for horse.
  198.        HANDICAP=`random_1_9`
  199.       # Check if the random_1_9 function returned a good value.
  200.       while ! echo $HANDICAP | grep [1-9] &> /dev/null; do
  201.                 HANDICAP=`random_1_9`
  202.       done
  203.       # Define last handicap position for horse.
  204.       LHP=`expr $HANDICAP \* 7 + 3`
  205.       for FILE in `seq 10 7 $LHP`; do
  206.             echo $HN >> $FILE
  207.       done  
  208.      
  209.       # Calculate odds.
  210.       case $HANDICAP in
  211.               1) ODDS=`echo $HANDICAP \* 0.25 + 1.25 | bc`
  212.                                  echo $ODDS > odds_${HN}
  213.               ;;
  214.               2 | 3) ODDS=`echo $HANDICAP \* 0.40 + 1.25 | bc`
  215.                                        echo $ODDS > odds_${HN}
  216.               ;;
  217.               4 | 5 | 6) ODDS=`echo $HANDICAP \* 0.55 + 1.25 | bc`
  218.                                              echo $ODDS > odds_${HN}
  219.               ;;
  220.               7 | 8) ODDS=`echo $HANDICAP \* 0.75 + 1.25 | bc`
  221.                                        echo $ODDS > odds_${HN}
  222.               ;;
  223.               9) ODDS=`echo $HANDICAP \* 0.90 + 1.25 | bc`
  224.                                   echo $ODDS > odds_${HN}
  225.       esac
  226.  
  227.  
  228. done
  229.  
  230.  
  231. # Print odds.
  232. print_odds() {
  233. tput cup 6 0
  234. echo -ne '\E[30;42m'
  235. for HN in `seq 9`; do
  236.       echo "#$HN odds->" `cat odds_${HN}`
  237. done
  238. }
  239.  
  240. # Draw the horses at starting line.
  241. draw_horses() {
  242. tput cup 6 0
  243. echo -ne '\E[30;42m'
  244. for HN in `seq 9`; do
  245.       echo /\\$HN/\\"                               "
  246. done
  247. }
  248.  
  249. print_odds
  250.  
  251. echo -ne '\E[47m'
  252. # Wait for a enter key press to start the race.
  253. # The escape sequence '\E[?25l' disables the cursor.
  254. tput cup 17 0
  255. echo -e '\E[?25l'Press [enter] key to start the race...
  256. read -s
  257.  
  258. #  Disable normal echoing in the terminal.
  259. #  This avoids key presses that might "contaminate" the screen
  260. #+ during the race.  
  261. stty -echo
  262.  
  263. # --------------------------------------------------------
  264. # Start the race.
  265.  
  266. draw_horses
  267. echo -ne '\E[37;47m'
  268. move_and_echo 18 1 $BLANK80
  269. echo -ne '\E[30m'
  270. move_and_echo 18 1 Starting...
  271. sleep 1
  272.  
  273. # Set the column of the finish line.
  274. WINNING_POS=74
  275.  
  276. # Define the time the race started.
  277. START_TIME=`date +%s`
  278.  
  279. # COL variable needed by following "while" construct.
  280. COL=0    
  281.  
  282. while [ $COL -lt $WINNING_POS ]; do
  283.                  
  284.          MOVE_HORSE=0    
  285.          
  286.          # Check if the random_1_9 function has returned a good value.
  287.          while ! echo $MOVE_HORSE | grep [1-9] &> /dev/null; do
  288.                MOVE_HORSE=`random_1_9`
  289.          done
  290.          
  291.          # Define old type and position of the "randomized horse".
  292.          HORSE_TYPE=`cat  horse_${MOVE_HORSE}_position | tail -n 1`
  293.          COL=$(expr `cat  horse_${MOVE_HORSE}_position | head -n 1`)
  294.          
  295.          ADD_POS=1
  296.          # Check if the current position is an handicap position.
  297.          if seq 10 7 68 | grep -w $COL &> /dev/null; then
  298.                if grep -w $MOVE_HORSE $COL &> /dev/null; then
  299.                      ADD_POS=0
  300.                      grep -v -w  $MOVE_HORSE $COL > ${COL}_new
  301.                      rm -f $COL
  302.                      mv -f ${COL}_new $COL
  303.                      else ADD_POS=1
  304.                fi
  305.          else ADD_POS=1
  306.          fi
  307.          COL=`expr $COL + $ADD_POS`
  308.          echo $COL >  horse_${MOVE_HORSE}_position  # Store new position.
  309.                            
  310.         # Choose the type of horse to draw.        
  311.          case $HORSE_TYPE in
  312.                1) HORSE_TYPE=2; DRAW_HORSE=draw_horse_two
  313.                ;;
  314.                2) HORSE_TYPE=1; DRAW_HORSE=draw_horse_one
  315.          esac      
  316.          echo $HORSE_TYPE >>  horse_${MOVE_HORSE}_position
  317.          # Store current type.
  318.        
  319.          # Set foreground color to black and background to green.
  320.          echo -ne '\E[30;42m'
  321.          
  322.          # Move the cursor to new horse position.
  323.          tput cup `expr $MOVE_HORSE + 5` \
  324.       `cat  horse_${MOVE_HORSE}_position | head -n 1`
  325.          
  326.          # Draw the horse.
  327.          $DRAW_HORSE
  328.           sleep $SLEEP_ARG
  329.          
  330.           # When all horses have gone beyond field line 15, reprint odds.
  331.           touch fieldline15
  332.           if [ $COL = 15 ]; then
  333.             echo $MOVE_HORSE >> fieldline15  
  334.           fi
  335.           if [[ `wc -l fieldline15 | cut -f1 -d " "` = 9 ]]; then
  336.               print_odds
  337.               : > fieldline15
  338.           fi          
  339.          
  340.          # Define the leading horse.
  341.          HIGHEST_POS=`cat *position | sort -n | tail -1`          
  342.          
  343.          # Set background color to white.
  344.          echo -ne '\E[47m'
  345.          tput cup 17 0
  346.          echo -n Current leader: `grep -w $HIGHEST_POS *position | cut -c7`\
  347.       "                              "
  348.  
  349. done  
  350.  
  351. # Define the time the race finished.
  352. FINISH_TIME=`date +%s`
  353.  
  354. # Set background color to green and enable blinking text.
  355. echo -ne '\E[30;42m'
  356. echo -en '\E[5m'
  357.  
  358. # Make the winning horse blink.
  359. tput cup `expr $MOVE_HORSE + 5` \
  360. `cat  horse_${MOVE_HORSE}_position | head -n 1`
  361. $DRAW_HORSE
  362.  
  363. # Disable blinking text.
  364. echo -en '\E[25m'
  365.  
  366. # Set foreground and background color to white.
  367. echo -ne '\E[37;47m'
  368. move_and_echo 18 1 $BLANK80
  369.  
  370. # Set foreground color to black.
  371. echo -ne '\E[30m'
  372.  
  373. # Make winner blink.
  374. tput cup 17 0
  375. echo -e "\E[5mWINNER: $MOVE_HORSE\E[25m""  Odds: `cat odds_${MOVE_HORSE}`"\
  376. "  Race time: `expr $FINISH_TIME - $START_TIME` secs"
  377.  
  378. # Restore cursor and old colors.
  379. echo -en "\E[?25h"
  380. echo -en "\E[0m"
  381.  
  382. # Restore echoing.
  383. stty echo
  384.  
  385. # Remove race temp directory.
  386. rm -rf $HORSE_RACE_TMP_DIR
  387.  
  388. tput cup 19 0
  389.  
  390. exit 0
Add Comment
Please, Sign In to add comment