[转贴] tictactoe bash script
as below , from comp.unix.shell#!/bin/bash
# Sat Jul 12 16:52:30 EDT 2003
# NAME: ttt
# Copyright 2003, Chris F.A. Johnson
# Released under the terms of the GNU General Public License
ESC=$'\e'
tictactoe() {
[ $verbose -ge 1 ] && echo tictactoe $* >&2
board=`printf "%9.9s" " "`
mvnum=1
remainder=" 1 2 3 4 5 6 7 8 9 "
show "$board"
while :
do
status
eval \$player$P
[ $? -ne 0 ] && return
put $_MOVE "$board"
board=$_PUT
# show "$board"
mkbold "$_MOVE"
printat 0 0 $mvnum
printat $prompt
sleep $pause &
mlist="$mlist $_MOVE"
remainder=${remainder/ $_MOVE / }
checkboard "$board" && {
mkbold $win
printat $prompt "$cle"
eval winner \$player$P
return
}
[ $mvnum -eq 9 ] && {
B=$U mkbold "$_MOVE"
winner "Neither player"
return
}
wait
B=$U mkbold "$_MOVE"
if [ $P = O ]
then
P=X
OP=O
else
P=O
OP=X
fi
mvnum=$(( $mvnum + 1 ))
done
}
winner() {
[ $verbose -ge 1 ] && echo winner $* >&2
printat $prompt "$cle $* wins\n\n"
}
status() {
[ $verbose -ge 1 ] && echo status $* >&2
if [ $verbose -ge 1 ]
then
printat 4 0
printf "${cle}Move: %s Player: %s Board: \"%s\"Last move: %sMove list: %s" \
"$mvnum" "$P" "${board// /-}" "$_MOVE" "$mlist"
else
false
fi
}
show() {
[ $verbose -ge 1 ] && echo show $* >&2
printat 0 0 $mvnum
printat 0 $top##$(( ($LINES - 5) / 2 ))
printf "%${margin}.${margin}s | %1s | %1s\n" "${1:0:1}" "${1:1:1}" "${1:2:1}"
printf "%${margin}.${margin}s---+---+---\n" " "
printf "%${margin}.${margin}s | %1s | %1s\n" "${1:3:1}" "${1:4:1}" "${1:5:1}"
printf "%${margin}.${margin}s---+---+---\n" " "
printf "%${margin}.${margin}s | %1s | %1s\n" "${1:6:1}" "${1:7:1}" "${1:8:1}"
}
put() {
[ $verbose -ge 1 ] && echo put $1 \""$2"\" >&2
local n=$(( $1 - 1 ))
_PUT=${2:-$board}
[ "${_PUT:$n:1}" = " " ] &&
_PUT=${_PUT:0:$n}$P${_PUT:$1}
}
checkboard() {
[ $verbose -ge 1 ] && echo checkboard \"$*\" >&2
case $1 in
$P??$P??$P??) win="1 4 7" ;;
?$P??$P??$P?) win="2 5 8" ;;
??$P??$P??$P) win="3 6 9" ;;
??$P?$P?$P??) win="3 5 7" ;;
$P???$P???$P) win="1 5 9" ;;
$P$P$P??????) win="1 2 3" ;;
???$P$P$P???) win="4 5 6" ;;
??????$P$P$P) win="7 8 9" ;;
*) false ;;
esac
}
mkbold() {
[ $verbose -ge 1 ] && echo mkbold $* >&2
for sq in $*
do
row=$(( ($sq - 1) / 3 ))
col=$(( ($sq - 1) % 3 + 1 ))
printat $(( ($col * 4) + $margin - 2 )) $(( ($row * 2) + $top ))
printf "${B}$P${U}"
done
}
human() {
[ $verbose -ge 1 ] && echo human $* >&2
while :
do
key "Select ($remainder)"
# case $_MOVE in
# "$ESC") read -sn1; read -sn1 kp; continue ;;
# esac
_MOVE=$_KEY
case $_MOVE in
1|2|3|4|5|6|7|8|9) [ "${board:_MOVE-1:1}" = " " ] && break ;;
q|Q|x|X) echo; return 5 ;;
p) printat $prompt
KEYECHO= KEYMAX=$(( $COLUMNS - 10 )) key "Enter delay in seconds"
pause=$_KEY
;;
"") set -- $remainder
_MOVE=$1
[ $verbose -ge 1 ] && echo "|$_MOVE|" >&2
break ;;
*) printat $prompt
printf "\r%s%s\r" ""$cle" $_MOVE: Invalid move"
sleep 1
printf "%s\r" "$cle" ;;
esac
done
}
randy() {
[ $verbose -ge 1 ] && echo randy $* >&2
randstr $remainder
_MOVE=$_RANDSTR
}
key() {
[ $verbose -ge 1 ] && echo key $* >&2
printat $prompt "$cle$CVIS$beep"
read -${KEYECHO}n$KEYMAX -p "${1:-PAK}: " _KEY 2>&1
printf "$CINV"
}
getkey() {
local OKchars=${1:-${remainder// /}}
local kp2 kp3
stty -echo
while :
do
prompt="==>"
prompt
IFS= read -r -sn1 -p " " kp 2>&1 || exit 2 #cleanup
case $OKchars in
*"$kp"*)
case $kp in
$ESC)
read -st1 -n1 kp2
case $kp2 in
\[) read -st1 -n1 kp3
case $kp3 in
A) kp=$UP; break ;;
B) kp=$DN; break ;;
C) kp=$RT; break ;;
D) kp=$LF; break ;;
esac
;;
esac
;;
*) break ;;
esac
;;
esac
done
_KEY=$kp
}
randstr() {
[ $verbose -ge 1 ] && echo randstr $* >&2
# [ -n "$1" ] || return 1
n=$(( ($RANDOM % $#) + 1 ))
eval _RANDSTR=\${$n}
}
isblock() {
[ $verbose -ge 1 ] && echo isblock $* >&2
win=
block=
for _MOVE in $remainder
do
P=$OP put $_MOVE
P=$OP checkboard "$_PUT" && return
done
_MOVE=
}
block() {
[ $verbose -ge 1 ] && echo block $* >&2
block=
for _MOVE in $remainder
do
put $_MOVE
checkboard "$_PUT" && return
P=$OP put $_MOVE
P=$OP checkboard "$_PUT" && block=$_MOVE
done
[ "$block" ] && { _MOVE=$block; return; }
randy
}
computer() {
[ $verbose -ge 1 ] && echo computer $* >&2
local r c
case $mvnum in
1) randstr 1 3 7 9
_MOVE=$_RANDSTR ;;
2)
if [ "${board:4:1}" = " " ]
then
_MOVE=5
else
randstr 1 3 7 9
_MOVE=$_RANDSTR
fi
;;
3)r=${mlist// /}
c='1 3 7 9'
randstr ${c//[$r]/}
# randstr ${remainder//[$r]/}
_MOVE=$_RANDSTR
;;
4)
isblock
[ "$_MOVE" ] && return
r=${mlist// /}
c='2 4 6 8'
randstr ${remainder//[$r]/}
_MOVE=$_RANDSTR
;;
*) block ;;
esac
}
printat() { #== print arguments 3-... at Y=$2 X=$1
[ $verbose -ge 1 ] && echo printat $* >&2
[ $# -lt 2 ] && return 1
local y=$2
local x=$1
shift 2
msg="$*"
printf "\e[%d;%dH%b" $y $x "$msg"
}
version()
{
echo " $progname, version $version
Copyright $copyright, $author $email
This is free software, released under the terms of the GNU General
Public License.There is NO warranty; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
"
}
usage()
{
echo "
${B}NAME${U}:$progname - Tic-Tac-Toe
${B}USAGE${U}: $progname
${B}OPTIONS${U}:
-x player1 - specify first player
-o player2 - specify second player
-c player1,player2 - specify both players
-p seconds - time to pause between moves
-h, --help - help: print this message
-H, --help_long- help: print more detailed message (if available)
-v, --verbose - sends messsages to \$HOME/tttlog
-V, --version - print version information
Copyright 2003, Chris F.A. Johnson
"
}
verbose=0
longusage=0
version="1.0"
copyright=2003
author="Chris F.A. Johnson"
progname=${0##*/}
P=X
OP=O
playerX=human
playerO=computer
co=
li=
if tput ce >/dev/null 2>&1
then ## e.g. FreeBSD
co=co
li=li
elif tput el 2>/dev/null
then ## e.g. Linux
co=cols
li=lines
fi
UNBOLD=$'\E[0m'
standout=$'\E[0;1;7m'
cle=$'\E[K'
clb=$'\E[1K'
ULINE=$'\E[0;4m'
REVERSE=$'\E[0;7m'
BLINK=$'\E[0;5m'
BOLD=$'\E[0;1m'
CINV=$'\E[0;8m'
R=$REVERSE
U=$UNBOLD
B=$BOLD
BR=$B$R
Cl=$'\f'
if [ "$co" ]
then
tput reset
COLUMNS=${COLUMNS:=`tput $co`}
else
COLUMNS=${COLUMNS:-80}
fi
top=6
margin=11
prompt="3 $(( $top + 9 ))"
beep=#$'\a'
pause=1
KEYMAX=1
KEYECHO=s
while getopts vVhH-:xoX:O:c:p: var
do
case "$var" in
x) playerX=human
playerO-computer
;;
o) playerO=human
playerX=computer
;;
X) playerX=$OPTARG ;;
O) playerO=$OPTARG ;;
c|C) playerO=${OPTARG#*,}
playerX=${OPTARG%,*}
;;
p) pause=$OPTARG ;;
-) case $OPTARG in
help) usage; exit ;;
verbose) verbose=$(( $verbose + 1 )) ;;
version) version; exit ;;
esac
;;
h) usage; exit ;;
H) longusage=1; usage; exit ;;
v) verbose=$(( $verbose + 1 )) ;;
V) version; exit ;;
*);;
esac
done
shift $(( $OPTIND - 1 ))
if [ "$co" ]
then
COLUMNS=`tput $co`
else
COLUMNS=${COLUMNS:-80}
fi
margin=11##$(( ($COLUMNS - 11) / 2 ))
clear
if [ $verbose -ge 1 ]
then
exec 2>$HOME/tttlog
set -x
fi
tictactoe
printat $prompt "\n$CVIS\n" 已阅
页:
[1]