Skip to content

Instantly share code, notes, and snippets.

@knuxify
Created January 20, 2021 18:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save knuxify/1ff38f417f57ce7b409f37e31f2a818f to your computer and use it in GitHub Desktop.
Save knuxify/1ff38f417f57ce7b409f37e31f2a818f to your computer and use it in GitHub Desktop.
#!/bin/bash
trap exit INT
########################
# #
# ARRAY-LESS TICTACTOE #
# #
########################
# Beware: this thing is a monstrosity.
# Chances are, your eyes are going to burn as you read this,
# and you will ping me saying "What the hell is this crap??
# I could make something way better in pure bash with full
# busybox compatibility in 1 minute!!!"
# Just trust me on this one, it doesn't wipe your computer.
tmpdir="/tmp/tictactoe"
[[ ! -e "$tmpdir" ]] && mkdir -p "$tmpdir"
clean_up() {
[[ "$tmpdir" ]] && rm -rf "$tmpdir/$password"
clear
exit 0
}
checkwin(){
for p in $player $oplayer; do
if [[ "$map" =~ $p\ $p\ $p\ [0-9]\ [0-9]\ [0-9]\ [0-9]\ [0-9]\ [0-9] ]]; then echo "$p" > "$gamedir/winner";
elif [[ "$map" =~ [0-9]\ [0-9]\ [0-9]\ $p\ $p\ $p\ [0-9]\ [0-9]\ [0-9] ]]; then echo "$p" > "$gamedir/winner";
elif [[ "$map" =~ [0-9]\ [0-9]\ [0-9]\ [0-9]\ [0-9]\ [0-9]\ $p\ $p\ $p ]]; then echo "$p" > "$gamedir/winner";
elif [[ "$map" =~ $p\ [0-9]\ [0-9]\ $p\ [0-9]\ [0-9]\ $p\ [0-9]\ [0-9] ]]; then echo "$p" > "$gamedir/winner";
elif [[ "$map" =~ [0-9]\ $p\ [0-9]\ [0-9]\ $p\ [0-9]\ [0-9]\ $p\ [0-9] ]]; then echo "$p" > "$gamedir/winner";
elif [[ "$map" =~ [0-9]\ [0-9]\ $p\ [0-9]\ [0-9]\ $p\ [0-9]\ [0-9]\ $p ]]; then echo "$p" > "$gamedir/winner";
elif [[ "$map" =~ $p\ [0-9]\ [0-9]\ [0-9]\ $p\ [0-9]\ [0-9]\ [0-9]\ $p ]]; then echo "$p" > "$gamedir/winner";
elif [[ "$map" =~ [0-9]\ [0-9]\ $p\ [0-9]\ $p\ [0-9]\ $p\ [0-9]\ [0-9] ]]; then echo "$p" > "$gamedir/winner";
fi
done
[[ "$map" != *"0"* ]] && [[ "$(cat $gamedir/winner)" == "0" ]] && echo "3" > "$gamedir/winner"
if [[ "$(cat $gamedir/winner)" != "0" ]]; then return 0; else return 1; fi
}
tttgame() {
case $player in
1) oplayer=2; mark="O";;
2) oplayer=1; mark="X";;
*) echo "Broken player number" && exit 1;;
esac
if [[ "$player" == "1" ]]; then
echo "Waiting for another player to join..."
until [[ "$(cat $gamedir/players)" == "2" ]]; do
sleep 0.5s
done
fi
map="$(cat $gamedir/map)"
until [[ "$(cat $gamedir/winner)" != "0" ]]; do
echo "Waiting for player $oplayer..."
until [[ "$(cat $gamedir/turn)" == "$player" ]]; do
checkwin && break="1" && break
[[ ! -e "$gamedir" ]] && clear && echo "The other player has disconnected." && exit 1
sleep 0.5s
done
[[ break = "1" ]] && break
map="$(cat $gamedir/map)"
clear
unset blockid checkid block available availableraw
for mapblock in $map; do
# 0 - Empty space
# 1 - Player 1's space
# 2 - Player 2's space
let blockid++
case $blockid in
1) echo " a b c"; printf "1 ";;
4) printf "2 ";;
7) printf "3 ";;
esac
printf "|"
case $mapblock in
0) printf " "; availableraw="$availableraw 1";;
1) printf "O"; availableraw="$availableraw 0";;
2) printf "X"; availableraw="$availableraw 0";;
esac
if [[ "$blockid" == "3" ]] || [[ "$blockid" == "6" ]] || [[ "$blockid" == "9" ]]; then
printf "|\n"
fi
done
availableraw=$(echo "$availableraw" | sed -e 's/^[ \t]*//')
for tocheck in $availableraw; do
let checkid++
if [[ "$tocheck" != "0" ]]; then
case $checkid in
1) available="$available 1a";;
2) available="$available 1b";;
3) available="$available 1c";;
4) available="$available 2a";;
5) available="$available 2b";;
6) available="$available 2c";;
7) available="$available 3a";;
8) available="$available 3b";;
9) available="$available 3c";;
esac
fi
done
available=$(echo "$available" | sed -e 's/^[ \t]*//')
checkwin && break
echo "You are player $player. Your blocks are marked with $mark."
until [[ "$block" ]] && [[ "$available" == *"$block"* ]]; do
read -p "Where do you want to place your block? (Available options: $available) > " -re block
[[ ! -e "$gamedir" ]] && clear && echo "The other player has disconnected." && exit 1
[[ "$available" != *"$block"* ]] && echo "Invalid block."
done
[[ ! -e "$gamedir" ]] && clear && echo "The other player has disconnected." && exit 1
case $block in
1a) echo "$map" | awk -v r="$player" '{$1=r}1' > "$gamedir/map";;
1b) echo "$map" | awk -v r="$player" '{$2=r}1' > "$gamedir/map";;
1c) echo "$map" | awk -v r="$player" '{$3=r}1' > "$gamedir/map";;
2a) echo "$map" | awk -v r="$player" '{$4=r}1' > "$gamedir/map";;
2b) echo "$map" | awk -v r="$player" '{$5=r}1' > "$gamedir/map";;
2c) echo "$map" | awk -v r="$player" '{$6=r}1' > "$gamedir/map";;
3a) echo "$map" | awk -v r="$player" '{$7=r}1' > "$gamedir/map";;
3b) echo "$map" | awk -v r="$player" '{$8=r}1' > "$gamedir/map";;
3c) echo "$map" | awk -v r="$player" '{$9=r}1' > "$gamedir/map";;
*) echo "Wrong block"; exit 1;;
esac
clear
echo "$oplayer" > "$gamedir/turn"
checkwin && break
done
echo "The winner is:"
gamewinner="$(cat $gamedir/winner)"
sleep 1s
case $gamewinner in
1) echo "Player 1!";;
2) echo "Player 2!";;
3) echo "Nobody, it's a match!";;
esac
sleep 2s
clean_up &>/dev/null
exit 0
}
clear
echo "=== TIC TAC TOE ==="
echo "Type in your password (a nonexistent password will start a new game):"
read -re password
[[ -z "$password" ]] && echo "Password empty!" && exit 1
trap clean_up INT
if [[ -d "$tmpdir/$password" ]]; then
if [[ "$(cat $tmpdir/$password/players)" = "2" ]]; then
echo "Game $password full!"
exit 1
else
echo -e "Joining $password..."
player=2
gamedir="$tmpdir/$password"
echo "2" > "$gamedir/players"
tttgame
fi
else
echo -e "Creating new game."
mkdir "$tmpdir/$password"
player=1
gamedir="$tmpdir/$password"
echo "1" > "$gamedir/turn"
echo "0 0 0 0 0 0 0 0 0" > "$gamedir/map"
echo "1" > "$gamedir/players"
echo "0" > "$gamedir/winner"
tttgame
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment