diff --git a/bash/tictactoe b/bash/tictactoe new file mode 100755 index 0000000..c892384 --- /dev/null +++ b/bash/tictactoe @@ -0,0 +1,206 @@ +#!/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