主要是练习用tput来设置终端的前景,背景色,以及定位光标 水平菜,代码很长,让各位见笑了
代码: #!/bin/bash
##usage: sh $0 n ## ## ------------------->X ## | ## | ## | ## | disk 1 --------> () ## | disk 2 --------> (()) ## | disk 3 --------> ((())) ## | disk 4 --------> (((()))) ## | ............ .......... ## V disk n-1 --> ((((((())))))) ## Y disk n --> ___(((((((())))))))______ _________________________ ________________________ ## ground -->|_________________________| |_________________________| |________________________| ## A A A ## | | | ## | | | ## source,1 aid,2 destination,3
usage="sh $0 non-negative number" disks=$1 colums=$((($(tput cols)-4)/3))
## 底座的 Y 坐标 groundat=$(($(tput lines)-2))
## 底座source(或1)处,最顶层盘的中心坐标 sourcex=$(($colums/2)) sourcey=$(($groundat-$disks))
## 底座aid(或2)处,最顶层盘的中心坐标 aidx=$(($colums+2+$sourcex)) aidy=$(($groundat-1)) aidfirst=0
## 底座destination(或3)处,最顶层盘的中心坐标 destinationx=$(($colums*2+4+$sourcex)) destinationy=$(($groundat-1)) destinationfirst=0
coordinate=''
initdraw() { init_drawdisks init_drawground }
init_drawground() { index=1 tput cup $groundat 0 for i in 1 2 3 do tput setab $((1+$i)) while(($index<=$i*$colums+($i-1)*2)) do echo -ne ' ' index=$(($index+1)) done tput sgr0 echo -n ' ' index=$(($index+2)) done
tput cup $(tput lines) 0 }
init_drawdisks() { for((offset=0,n=$disks;n>0;n--,offset++)) do drawdisk $(($colums/2)) $(($groundat-1-$offset)) $((2+($n-1)*2)) $n done }
drawdisk() ## 画一个中心在 ($1,$2),长度为 $3 的盘子 ## 盘子的序号 $4 决定盘子的颜色 { disk='' for((tmp=$3/2;tmp>0;tmp--)); do disk=${disk}')'; done for((tmp=$3/2;tmp>0;tmp--)); do disk='('${disk}; done tput setab $(($4%8+1)) tput cup $2 $(($1-$3/2)) echo -n "$disk" tput sgr0 }
destroydisk() ## 将中心位置为 ($1,$2),长度为 $3 的盘子销毁 { tput cup $2 $(($1-$3/2)) empty='' for((tmp=$3;tmp>0;tmp--)); do empty=' '$empty; done echo -n "$empty" tput cup 0 0 }
moving() ## 将第 $5 个盘子从 ($1,$2) 移动到 ($3,$4) { verticaltop=$(($groundat-1-$disks)) horizspace=$(($3-$1)) x=$1 y=$2 length=$((2+($5-1)*2))
while(($y>=$verticaltop)) do destroydisk $x $y $length y=$(($y-1)) drawdisk $x $y $length $5 # sleep 0.5 done
sign=$(($horizspace<0?-1:1)) while(($3-$x!=0)) do destroydisk $x $y $length x=$(($x+1*$sign)) drawdisk $x $y $length $5 # sleep 0.5 done
while(($y<$4)) do destroydisk $x $y $length y=$(($y+1)) drawdisk $x $y $length $5 # sleep 0.5 done }
hanoi() { bool1=$(($disks%2)) for((s=1;s<2**$disks;s++)) { index=$(factor $s | sed 's/.*: //;s/2 /2\n/g' | grep '^2$' -c) step=$(((s/(2**$index)+1)/2)) index=$(($index+1)) bool2=$(($index%2)) fromtonum=''
## 求出第 s 步时,应将第 $index 个盘子从底座(1或2或3)移动到底座(1或2或3) if(($bool1==$bool2)) then case $(($step%3)) in 1) fromtonum='1 3';; 2) fromtonum='3 2';; 0) fromtonum='2 1';; esac else case $(($step%3)) in 1) fromtonum='1 2';; 2) fromtonum='2 3';; 0) fromtonum='3 1';; esac fi fromtonum=${fromtonum}" $index"
## 按照盘子序号和底座序号计算出移动的源及目的的坐标 coordinate _getcoordinat $fromtonum tput cup $groundat $(($colums+1+$colums/2)) tput setab 3 tput setaf 0 echo $s tput sgr0
## 移动盘子 moving $coordinate }
}
_getcoordinat() ## 第 $3 个盘子要从底座 $1 移动到底座 $2,据此计算出移动的源坐标和目的坐标 { case "$1" in 1) coordinate="$sourcex $sourcey " sourcey=$(($sourcey+1));; 2) coordinate="$aidx $aidy " aidy=$(($aidy+1));;
3) coordinate="$destinationx $destinationy " destinationy=$(($destinationy+1));; esac
case "$2" in 1) sourcey=$(($sourcey-1)) coordinate=${coordinate}"$sourcex $sourcey";; 2) aidy=$(($aidy-1*$aidfirst)) coordinate=${coordinate}"$aidx $aidy" aidfirst=1;; 3) destinationy=$(($destinationy-1*$destinationfirst)) coordinate=${coordinate}"$destinationx $destinationy" destinationfirst=1;; esac
coordinate=${coordinate}" $3" }
################ 开始 ##################### [[ -z "$disks" || "$disks" =~ [^[:digit:]] ]] && echo "usage: ""$usage" && exit (( $disks+2>$groundat || (2+($disks-1)*2)*3+4>$(tput cols))) && echo "screen is too small, reseize it" && exit tput clear tput civis initdraw stty -echo
sleep 0.5 for((i=5;i>=0;i--)) do tput cup $(($(tput lines)/2)) $(($(tput cols)/2-2)) tput setab $i echo ' '$i' ' sleep 0.6 tput sgr0 tput cup $(($(tput lines)/2)) $(($(tput cols)/2-2)) echo ' ' sleep 0.4 done tput sgr0 tput cup $(($(tput lines)/2)) $(($(tput cols)/2)) echo " " hanoi
stty echo tput reset tput sgr0 tput cup $(tput lines) 0 tput cnorm |