I wrote this two player tic-tac-toe program in bash. To make a move you enter a number between 0 and 8 which corresponds to the square:
0|1|2
3|4|5
6|7|8
This is my code:
#!/usr/bin/env bash
declare -r BOARD_SIZE=9
declare -r DEFAULT_SQUARE_VALUE=-
declare -ra PLAYERS=(O X)
draw_board() {
for i in {1..3}
do
echo "${1:- }|${2:- }|${3:- }"
shift 3
done
}
get_placement() {
while :
do
echo "Please enter a valid move (0-$((BOARD_SIZE - 1)))"
read n
echo
digit_pattern="^[0-$((BOARD_SIZE-1))]\$"
args=("$@")
if [[ $n =~ $digit_pattern ]] && [[ ${args[$n]} == $DEFAULT_SQUARE_VALUE ]]
then
placement=$n
return
fi
done
}
# sets $ended to whether the game has ended and $winner to the winner
get_winner() {
ended=1
possible_draw=1
# check for draw
for square in $@
do
if [[ $square == $DEFAULT_SQUARE_VALUE ]]
then
possible_draw=0
break
fi
done
# check for winners
if [[ ${PLAYERS[*]} =~ "$1" ]] && [[ ${PLAYERS[*]} =~ "$5" ]] && [[ ${PLAYERS[*]} =~ "$9" ]]
then
if [[ "$1" == "$5" ]] && [[ "$5" == "$9" ]]
then
winner=$1
return
fi
fi
if [[ ${PLAYERS[*]} =~ "$3" ]] && [[ ${PLAYERS[*]} =~ "$5" ]] && [[ ${PLAYERS[*]} =~ "$7" ]]
then
if [[ "$3" == "$5" ]] && [[ "$5" == "$7" ]]
then
winner=$3
return
fi
fi
for i in {1..3}
do
if [[ ${PLAYERS[*]} =~ "$1" ]] && [[ ${PLAYERS[*]} =~ "$2" ]] && [[ ${PLAYERS[*]} =~ "$3" ]]
then
if [[ "$1" == "$2" ]] && [[ "$2" == "$3" ]]
then
winner=$1
return
fi
fi
if [[ ${PLAYERS[*]} =~ "$1" ]] && [[ ${PLAYERS[*]} =~ "$4" ]] && [[ ${PLAYERS[*]} =~ "$7" ]]
then
if [[ "$1" == "$4" ]] && [[ "$4" == "$7" ]]
then
winner=$1
return
fi
fi
shift 3
done
winner=''
if [[ $possible_draw == 1 ]]
then
return
fi
ended=0
}
board=( $(for i in $(seq 1 $BOARD_SIZE); do echo "$DEFAULT_SQUARE_VALUE"; done) )
current_turn="O"
while :
do
draw_board ${board[@]}
get_placement ${board[@]}
board[$placement]=$current_turn
get_winner ${board[@]}
if [[ "$ended" == 1 ]]
then
if [ -n "$winner" ]
then
echo "$winner has won!"
echo
draw_board ${board[@]}
else
echo "Draw!"
echo
draw_board ${board[@]}
fi
exit
fi
[[ $current_turn == ${PLAYERS[0]} ]] && current_turn=${PLAYERS[1]} || current_turn=${PLAYERS[0]}
echo -en "\n\n\n"
done
Example game:
-|-|-
-|-|-
-|-|-
Please enter a valid move (0-8)
0
O|-|-
-|-|-
-|-|-
Please enter a valid move (0-8)
8
O|-|-
-|-|-
-|-|X
Please enter a valid move (0-8)
6
O|-|-
-|-|-
O|-|X
Please enter a valid move (0-8)
3
O|-|-
X|-|-
O|-|X
Please enter a valid move (0-8)
2
O|-|O
X|-|-
O|-|X
Please enter a valid move (0-8)
4
O|-|O
X|X|-
O|-|X
Please enter a valid move (0-8)
1
O has won!
O|O|O
X|X|-
O|-|X
I do not know much about bash, so any feedback would be much appreciated.