Screenshot of terminal running the game
Before I made this game I had been teaching myself how to use the terminal in Linux and found myself deep in the world of shell scripting. I was really enjoying the things I was learning, however, beyond scripting menial tasks and custom live linux usb drives I didn't really know of a way to code something that applied and challenged my knowledge of bash. So I thought, "Why not make a game?" And that's what I did.
I started by just making a terminal based tic-tac-toe game. But when I came to the point of wanting to program a computer player I realized that tic-tac-toe can be perfected. Basically it would be too easy to make an unbeatable computer. So I decided to change the game.
This new game is played and won like traditional tic-tac-toe with one twist. Each filled spot can be overwritten once. The way this is illustrated in this game is with different colored symbols. When you first mark in a spot the X or O is green. This means that it can still be overwritten. Once a green symbol is overwritten the new symbol is red, meaning that square is locked. This single rule adds much more complexity to the game.
Usually to prevent losing O-player would choose spot 2
But in this game X-player could just overwrite the green O in spot 2 to win
So instead O should choose the middle spot (4) and since the O will be red they player-X can't overwrite it and win this turn
BASH Tic-Tac-Toe Code
Download
#!/bin/bash
# Tic Tac Toe Program
# Creator: Willem Van Dam
# Date Started: 10/4/2019
# Purpose: To play tic-tac-toe of course!
# Init Cases
main () {
case $1 in
-[Hh]*) clear; echo -e "Tic Tac Toe Game created by Willem Van Dam
\n\n-h : help message\n\n-m : multiplayer\n\n-s : solo game vs computer\n\n";;
-[Mm]*) initGame 1;;
-[Ss]*) initGame 0;;
*) clear; read -p "Tic Tac Toe Game created by Willem Van Dam
What game mode would you like to play?
Solo (vs. CPU)
Multiplayer
Choice: " mode
success=0
while test $success -eq 0
do
if [[ $mode = [Ss]* ]]
then
initGame 0
success=1
elif [[ $mode = [Mm]* ]]
then
initGame 1
success=1
else
read -p "Sorry that is not an option.
Please choose Solo (s) or Multiplayer (m)
Choice: " mode
fi
done
;;
esac
}
initGame () {
#$1=solo (0) or multi(1)
cpu=$1
cap=3
redlimit=(0 $cap $cap)
refboard=(0 1 2 3 4 5 6 7 8)
dgrey='\033[0m'
green='\033[0;32m'
red='\033[1;31m'
yellow='\033[1;33m'
nocolor='\033[0m'
formboard=("|" "|" "\n-----------\n" "|" "|" "\n-----------\n" "|" "|" "\n")
xo=0
winboard=(0 0 0 0 0 0 0 0)
config=("l1" "l2" "l3" "l4" "l5" "l6" "l7" "l8")
l1=(0 1 2)
l2=(3 4 5)
l3=(6 7 8)
l4=(0 3 6)
l5=(1 4 7)
l6=(2 5 8)
l7=(0 4 8)
l8=(2 4 6)
for i in {0..8}
do
iroboard[$i]="$dgrey"
refboard[$i]="$i"
done
#turn=1
#choice=0
#markBoard "X"
#choice=1
#markBoard "X"
#choice=0
#markBoard "X"
#choice=1
#markBoard "X"
#choice=8
#markBoard "X"
win=0
gameturn=0
turn=1 #1=player1 2=player2 or CPU
while test $win -eq 0
do
clear
#for j in {0..7}
#do
#echo "${winboard[$j]}"
#done
dispBoard
#echo "$gameturn"
if test $turn -eq 1 #P1 turn
then
echo -e "Player 1, choose a spot. You are Xs.\n"
read -p "Choice: " choice
markBoard "X"
turn=2
else #P2 or CPU turn
if test $1 -eq 0 #CPU turn
then
botdecide
markBoard "O"
else #P2 turn
echo -e "Player 2, choose a spot. You are Os.\n"
read -p "Choice: " choice
markBoard "O"
fi
turn=1
fi
gameturn=$(($gameturn + 1))
done
clear
dispBoard
if test $win -eq 3
then
echo -e "${yellow}Well... It looks like you tied...${nocolor}"
elif (( cpu == 0 && win == 2 ))
then
echo -e "${red}The CPU has crushed your dreams of winning\nYOU LOSE!!!${nocolor}"
else
echo -e "${green}Congratulations Player ${win}. You won!!!${nocolor}"
fi
read -p "Would you like to play again? (y/n)
" replay
if [[ $replay = [Nn]* ]]
then
quit=1
fi
}
dispBoard () {
echo -e "\n"
for d in {0..8}
do
echo -en " ${iroboard[$d]}${refboard[$d]}$nocolor ${formboard[$d]}"
done
echo -e "\n"
}
markBoard () {
mark=$1
change=1
if [[ "$mark" = "X" ]]
then
xo=1
else
xo=2
fi
while test $change -eq 1
do
if [[ "${iroboard[$choice]}" = "$dgrey" ]]
then
iroboard[$choice]="$green"
refboard[$choice]=$mark
change=0; iro=0;
elif [[ "${iroboard[$choice]}" = "$green" ]]
then
if test ${redlimit[$turn]} -gt 0
then
iroboard[$choice]="$red"
refboard[$choice]=$mark
redlimit[$turn]=$((${redlimit[$turn]} - 1))
change=0; iro=3
else
read -p "Sorry you have run out of red caps.
Please choose a blank spot: " choice
fi
else
read -p "Sorry that spot is locked.
Please choose a different spot: " choice
fi
done
lcount=0
for l in ${config[@]}
do
temp="${l}[@]"
tcount=0
for t in "${!temp}"
do
if test $choice -eq ${t}
then
calcwin $lcount $tcount
split ${winboard[$lcount]}
if (( ones%3 == xo && tens%3 == xo && hundreds%3 == xo ))
then
win=$turn
return
fi
fi
tcount=$(($tcount + 1))
done
lcount=$(($lcount + 1))
done
fullcheck
}
fullcheck () {
filled=0
for tie in ${refboard[@]}
do
if [[ "$tie" = "X" || "$tie" = "O" ]]
then
filled=$(($filled + 1))
fi
done
if test $filled -eq 9
then
win=3
return
fi
}
calcwin () {
lx=$1
li=$2
case $li in
0)winboard[$lx]=$(( ${winboard[$lx]} % 100 + ($xo + $iro) * 100 ));;
1)winboard[$lx]=$((${winboard[$lx]} % 10 + (${winboard[$lx]} - ${winboard[$lx]} % 100 ) + ($xo + $iro) * 10 ));;
2)winboard[$lx]=$(((${winboard[$lx]} - ${winboard[$lx]} % 10) + $xo + $iro));;
*) echo "Error!!!"; exit;;
esac
}
split () {
full=$1
ones=$(($full % 10))
tens=$((($full % 100 - $ones)/10))
hundreds=$((($full - $tens - $ones)/100))
}
botdecide () {
decision=0
#echo "hey"
#goforthewin
goforthewin
if test $decision -ne 0
then
return
fi
#stop death
stopdeath
if test $decision -ne 0
then
return
fi
#NOGO
nogo=(0 0 0 0 0 0 0 0 0)
#nogolock
#centeraftertheyout include take c if open
#randomnogo
#random
random
if test $decision -ne 0
then
return
fi
#echo "gg"
}
goforthewin () {
#echo "winnnnnn"
wincount=0
for lx in ${winboard[@]}
do
split $lx
#echo "$hundreds:$tens:$ones"
aname=${config[$wincount]}
if (( ones%3 == 2 && tens%3 == 2 && hundreds != 4 && ( hundreds == 0 || (hundreds == 1 && redlimit[2] > 0) ) ))
then
#echo "ahahund"
aloc=$aname[0]
choice=${!aloc}
decision=1
break
elif (( ones%3 == 2 && hundreds%3 == 2 && tens != 4 && ( tens == 0 || (tens == 1 && redlimit[2] > 0) ) ))
then
#echo "ahaten"
aloc=$aname[1]
choice=${!aloc}
decision=1
break
elif (( hundreds%3 == 2 && tens%3 == 2 && ones != 4 && ( ones == 0 || (ones == 1 && redlimit[2] > 0) ) ))
then
#echo "ahaone"
aloc=$aname[2]
choice=${!aloc}
decision=1
break
fi
wincount=$(($wincount + 1))
done
}
stopdeath () {
wincount=0
for lx in ${winboard[@]}
do
aname=${config[$wincount]}
if test ${redlimit[2]} -eq 0
then
case $lx in
011 | 014 | 041) rando=0;;
104 | 401 | 104) rando=1;;
110 | 410 | 140) rando=2;;
*) ;;
esac
else
decision=1
case $lx in
140 | 142 | 104 | 124) rando=0
break
;;
410 | 412 | 014 | 214) rando=1
break
;;
041 | 241 | 401 | 421) rando=2
break
;;
110 | 112) rando=$((RANDOM % 2))
break
;;
011 | 211) rando=$((RANDOM%2+1))
break
;;
101 | 121)rando=1
while test $rando -eq 1
do
rando=$((RANDOM%3))
done
break
;;
*) decision=0;;
esac
fi
wincount=$(($wincount + 1))
done
if test $decision -eq 1
then
aloc=$aname[$rando]
choice=${!aloc}
fi
}
random () {
echo "rando"
change=0
while test $change == 0
do
rando=$(( RANDOM % 9 ))
if { [ "${iroboard[$rando]}" == "$green" ] && [ ${redlimit[2]} -gt 0 ];} || [ "${iroboard[$rando]}" != "$red" ]
then
choice=$rando
change=1
decision=1
fi
done
}
#start execute
quit=0
while test $quit -eq 0
do
main $1
done
clear
exit