grimoire/bash/tictactoe

206 lines
3.2 KiB
Bash
Executable file

#!/usr/bin/env bash
clear() {
printf '\x1b\x5b\x48\x1b\x5b\x32\x4a'
}
red() {
if (( $# )); then
local red=$'\x1b\x5b\x33\x31\x6d'
local rst=$'\x1b\x28\x42\x1b\x5b\x6d'
printf %s%s%s "$red" "$1" "$rst"
fi
}
render() {
local pce=${pcs[$pos-1]}
if [[ $pce = " " ]]; then
pcs[$pos-1]=$(red "*")
else
pcs[$pos-1]=$(red "$pce")
fi
clear
printf "%s\n" "${brd[0]}"
printf "${brd[1]}\n" "${pcs[@]:0:3}"
printf "%s\n" "${brd[2]}"
printf "%s\n" "${brd[0]}"
printf "${brd[1]}\n" "${pcs[@]:3:3}"
printf "%s\n" "${brd[2]}"
printf "%s\n" "${brd[0]}"
printf "${brd[1]}\n" "${pcs[@]:6:3}"
printf "%s\n" "${brd[0]}"
pcs[$pos-1]=$pce
}
place() {
if (( $# )); then
local chr=$1 plc=$2 row win col
pcs[$plc]=$chr
for (( row = 0; row < 7; row += 3 )); do
if [[ ${pcs[*]:$row:3} = @(x x x|o o o) ]]; then
win=${pcs[$row]}
break
fi
done
if [[ -z $win ]]; then
for col in {0..2}; do
if [[ ${pcs[$col]}${pcs[$col+3]}${pcs[$col+6]} = @(xxx|ooo) ]]; then
win=${pcs[$col]}
break
fi
done
fi
if [[ -z $win ]]; then
if [[ ${pcs[0]}${pcs[4]}${pcs[8]} = @(xxx|ooo) ]]; then
win=${pcs[0]}
elif [[ ${pcs[2]}${pcs[4]}${pcs[6]} = @(xxx|ooo) ]]; then
win=${pcs[2]}
fi
fi
(( pld += 1 ))
if [[ -n $win ]]; then
case $win in
x)
res=1
;;
o)
res=2
esac
elif (( pld == 9 )); then
res=3
else
res=0
fi
return "$res"
fi
return 4
}
win=0 pld=0 pos=1
pcs=(
" " " " " "
" " " " " "
" " " " " "
)
brd=(
' | |'
' %s | %s | %s'
'___|___|___'
)
while ! (( win )); do
render
while true; do
read -rsn 1 key
dir=
case $key in
"")
if [[ ${pcs[$pos-1]} = " " ]]; then
break
fi
;;
$'\x1b')
read -rsn 2 arrow
case $arrow in
$'\x4f\x41'|$'\x5b\x41')
dir=up
;;
$'\x4f\x42'|$'\x5b\x42')
dir=down
;;
$'\x4f\x43'|$'\x5b\x43')
dir=right
;;
$'\x4f\x44'|$'\x5b\x44')
dir=left
;;
esac
;;
w|W)
dir=up
;;
s|S)
dir=down
;;
d|D)
dir=right
;;
a|A)
dir=left
;;
esac
if [[ -n $dir ]]; then
case $dir in
up)
if (( pos > 3 )); then
(( pos -= 3 ))
fi
;;
down)
if (( pos < 7 )); then
(( pos += 3 ))
fi
;;
right)
if (( pos % 3 )); then
(( pos += 1 ))
fi
;;
left)
if (( (pos % 3) != 1 )); then
(( pos -= 1 ))
fi
esac
fi
render
done
place x "$(( pos - 1 ))"
if ! (( res )); then
unu=( )
for (( cnt = 0; cnt < 9; ++cnt )); do
if [[ ${pcs[$cnt]} = " " ]]; then
unu+=( "$cnt" )
fi
done
ops=$(( RANDOM % ${#unu[@]} ))
place o "${unu[$ops]}"
fi
if (( $res )); then
render
case $res in
1)
printf 'x wins\n'
;;
2)
printf 'o wins\n'
;;
3)
printf 'tie game\n'
esac
exit
fi
done