主要是练习用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