⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 horserace.sh

📁 BASH Shell 编程 经典教程 《高级SHELL脚本编程》中文版
💻 SH
字号:
#!/bin/bash# horserace.sh: 一个非常简单的模拟赛马的游戏. # 作者: Stefano Palmeri# 经过授权可以在本书中使用. #################################################################  脚本目的: #  使用转义序列和终端颜色进行游戏. ##  练习: #  编辑脚本, 使它运行起来更具随机性, #+ 建立一个假的赌场 . . .     #  嗯 . . . 嗯 . . . 这种开场让我联想起一部电影 . . .##  脚本将会给每匹马分配一个随机障碍. #  按照马的障碍来计算几率, #+ 并且使用一种欧洲(?)的风格表达出来. #  比如: 几率(odds)=3.75的话, 那就意味着如果你押$1,#+ 你就会赢得$3.75.# #  此脚本已经在GNU/Linux操作系统上测试过, #+ 测试终端有xterm, rxvt, 和konsole. #  测试机器上安装的是AMD 900 MHz处理器, #+ 平均比赛时间为75秒.    #  如果使用更快的机器, 那么比赛用时会更少. #  所以, 如果你想增加比赛的悬念, 可以重置变量USLEEP_ARG. ##  本脚本由Stefano Palmeri编写. ################################################################E_RUNERR=65# 检查一下md5sum和bc是否已经被安装. if ! which bc &> /dev/null; then   echo bc is not installed.     echo "Can\'t run . . . "   exit $E_RUNERRfiif ! which md5sum &> /dev/null; then   echo md5sum is not installed.     echo "Can\'t run . . . "   exit $E_RUNERRfi#  设置下面的变量将会降低脚本的运行速度. #  它会作为参数, 传递给usleep命令(man usleep),   #+ 并且单位是微秒(500000微秒 = 半秒).USLEEP_ARG=0  #  如果脚本被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#  请参考与调试相关的章节, 可以获得'trap'命令的详细用法. # 为脚本设置一个唯一的(实际上不是绝对唯一)临时目录名. HORSE_RACE_TMP_DIR=$HOME/.horserace-`date +%s`-`head -c10 /dev/urandom | md5sum | head -c30`# 创建临时目录, 并移动到该目录下. mkdir $HORSE_RACE_TMP_DIRcd $HORSE_RACE_TMP_DIR#  这个函数将会把光标移动到行为$1, 列为$2的位置上, 然后打印$3. #  例如: "move_and_echo 5 10 linux"等价与"tput cup 4 9; echo linux", #+ 但是使用一个命令代替了两个命令. #  注意: "tput cup"定义0 0位置, 为终端左上角, #+ 而echo定义1 1位置, 为终端左上角. move_and_echo() {          echo -ne "\E[${1};${2}H""$3" }# 此函数用来产生1-9之间的伪随机数. random_1_9 () {                head -c10 /dev/urandom | md5sum | tr -d [a-z] | tr -d 0 | cut -c1 }#  在画马的时候, 这两个函数用来模拟"移动". draw_horse_one() {               echo -n " "//$MOVE_HORSE//}draw_horse_two(){              echo -n " "\\\\$MOVE_HORSE\\\\ }   # 定义当前终端尺寸. N_COLS=`tput cols`N_LINES=`tput lines`# 至少需要一个20(行) X 80(列)的终端. 检查一下. 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_RUNERRfi# 开始画赛场. # 需要一个80字符的字符串. 见下面. BLANK80=`seq -s "" 100 | head -c80`clear# 将前景色与背景色设为白. echo -ne '\E[37;47m'# 将光标移动到终端的左上角. tput cup 0 0 # 画6条白线. for n in `seq 5`; do      echo $BLANK80        # 用这个80字符的字符串将终端变为彩色的. done# 将前景色设为黑色. echo -ne '\E[30m'move_and_echo 3 1 "START  1"            move_and_echo 3 75 FINISHmove_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"# 将前景色设置为红色. echo -ne '\E[31m'# 一些ASCII的艺术效果. 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 "@...@.@...@..@@@@..@@@@.@@@@.."# 将前景色和背景色设为绿色. echo -ne '\E[32;42m'# 画11行绿线. tput cup 5 0for n in `seq 11`; do      echo $BLANK80done# 将前景色设为黑色. echo -ne '\E[30m'tput cup 5 0# 画栅栏. echo "++++++++++++++++++++++++++++++++++++++\++++++++++++++++++++++++++++++++++++++++++"tput cup 15 0echo "++++++++++++++++++++++++++++++++++++++\++++++++++++++++++++++++++++++++++++++++++"# 将前景色和背景色设回白色. echo -ne '\E[37;47m'# 画3条白线. for n in `seq 3`; do      echo $BLANK80done# 将前景色设为黑色. echo -ne '\E[30m'# 创建9个文件, 用来保存障碍物. for n in `seq 10 7 68`; do      touch $ndone  # 将脚本所要画的"马"设置为第一种类型. HORSE_TYPE=2#  为每匹"马"创建位置文件和几率文件. #+ 在这些文件中, 保存马的当前位置, #+ 类型和几率. for HN in `seq 9`; do      touch horse_${HN}_position      touch odds_${HN}      echo \-1 > horse_${HN}_position      echo $HORSE_TYPE >>  horse_${HN}_position      # 给马定义随机障碍物.        HANDICAP=`random_1_9`      # 检查函数random_1_9是否返回一个有效值.       while ! echo $HANDICAP | grep [1-9] &> /dev/null; do                HANDICAP=`random_1_9`      done      # 给马定义最后一个障碍物的位置.       LHP=`expr $HANDICAP \* 7 + 3`      for FILE in `seq 10 7 $LHP`; do            echo $HN >> $FILE      done              # 计算几率.       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}      esacdone# 打印几率. print_odds() {tput cup 6 0echo -ne '\E[30;42m'for HN in `seq 9`; do      echo "#$HN odds->" `cat odds_${HN}`done}# 在起跑线上把马画出来. draw_horses() {tput cup 6 0echo -ne '\E[30;42m'for HN in `seq 9`; do      echo /\\$HN/\\"                               "done}print_oddsecho -ne '\E[47m'# 等待按下回车键, 按下之后就开始比赛. # 转义序列'\E[?25l'禁用光标. tput cup 17 0echo -e '\E[?25l'Press [enter] key to start the race...read -s#  禁用了终端的常规echo功能. #  这么做用来避免在比赛中, #+ 按键所导致的"花"屏. stty -echo# --------------------------------------------------------# 开始比赛. draw_horsesecho -ne '\E[37;47m'move_and_echo 18 1 $BLANK80echo -ne '\E[30m'move_and_echo 18 1 Starting...sleep 1# 设置终点线的列号. WINNING_POS=74# 定义比赛开始的时间. START_TIME=`date +%s`# 下面的"while"结构需要使用COL变量. COL=0    while [ $COL -lt $WINNING_POS ]; do                             MOVE_HORSE=0                         # 检查random_1_9函数是否返回了有效值.           while ! echo $MOVE_HORSE | grep [1-9] &> /dev/null; do                MOVE_HORSE=`random_1_9`          done                    # 定义"随机抽取的马"的原来类型和位置.           HORSE_TYPE=`cat  horse_${MOVE_HORSE}_position | tail -1`          COL=$(expr `cat  horse_${MOVE_HORSE}_position | head -1`)                     ADD_POS=1          # 判断当前位置是否存在障碍物.           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  # 保存新位置.                                      # 选择要画出来的马的类型.           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 # 保存当前类型.                    # 将前景色设为黑, 背景色设为绿.           echo -ne '\E[30;42m'                    # 将光标移动到马的新位置.           tput cup `expr $MOVE_HORSE + 5`  `cat  horse_${MOVE_HORSE}_position | head -1`                     # 画马.           $DRAW_HORSE           usleep $USLEEP_ARG                     # 当所有的马都越过第15行之后, 再次打印几率.            touch fieldline15           if [ $COL = 15 ]; then             echo $MOVE_HORSE >> fieldline15             fi           if [ `wc -l fieldline15 | cut -f1 -d " "` = 9 ]; then               print_odds               : > fieldline15           fi                               # 取得领头的马.           HIGHEST_POS=`cat *position | sort -n | tail -1`                              # 将背景色设为白.           echo -ne '\E[47m'          tput cup 17 0          echo -n Current leader: `grep -w $HIGHEST_POS *position | cut -c7`"                              "           done  # 定义比赛结束的时间. FINISH_TIME=`date +%s`# 将背景色设置为绿色, 并且开启闪烁文本的功能. echo -ne '\E[30;42m'echo -en '\E[5m'# 让获胜的马闪烁. tput cup `expr $MOVE_HORSE + 5` `cat  horse_${MOVE_HORSE}_position | head -1`$DRAW_HORSE# 禁用闪烁文本. echo -en '\E[25m'# 将前景色和背景色设置为白色. echo -ne '\E[37;47m'move_and_echo 18 1 $BLANK80# 将前景色设置为黑色. echo -ne '\E[30m'# 让获胜的马闪烁. tput cup 17 0echo -e "\E[5mWINNER: $MOVE_HORSE\E[25m""  Odds: `cat odds_${MOVE_HORSE}`"\"  Race time: `expr $FINISH_TIME - $START_TIME` secs"# 恢复光标, 恢复原来的颜色. echo -en "\E[?25h"echo -en "\E[0m"# 恢复打印功能. stty echo# 删除掉和赛马有关的临时文件. rm -rf $HORSE_RACE_TMP_DIRtput cup 19 0exit 0

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -