|
发表于 2006-2-24 00:57:15
|
显示全部楼层
一个演示汉诺塔的脚本
主要是练习用 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
复制代码 |
|