⬆️ ⬇️

Network game on bash: chess

I have long wanted to write some kind of online game on bash, and it is desirable that the control be convenient, from the keyboard, with the usual cursor keys. In general, the interaction topic in bash is deeper than β€œenter a number, pressβ€ž Enter β€œβ€ is not excavated. I had to invent and explore everything myself. I tried very hard to find something similar in the level of interactivity, but I did not find it.



Since the subtleties of control with the keyboard ate a lot of my time, I did not bother with the subtleties of compatibility, so the game was tested only under Mac OS X, there is a non-zero probability that it will work under Linux and certainly it can be finished there to working condition.



To work, the game requires nc (aka Netcat ) and a terminal with support for 256 colors (for Mac OS, I recommend iTerm2 ). If there is interest in the game, I finish the terminal with 16 colors and / dev / tcp. By the way, he began to lay out all his go-crafts on the GitHub .

')

Network Chess on Bash




Since the game is networked, it needs to specify two parameters, which it will tell about if it is launched without them. The first is the address of the enemy machine, the second is the port. The port is chosen the same on both machines. The game can be run on one machine, in two consoles (in the screenshot just such a case).



It is easy to play - only one board is active at a time (the right one in the screenshot, it has brighter letters and numbers around the board), on the active board the cursor moves the cursor keys - ←, β†’, ↑ and ↓, take a piece and put it on the board - on the space bar or Enter. As soon as you put the piece on the board, the move goes to the opponent. "Eat" the opponent's shape is easy - just put your piece on someone else's. The game has a defense - you can not "eat" your figure.



There is nothing besides this in the game - the correctness of the control of moves is not performed, there is no check for the completion of the game, you can even walk the opponent's pieces. It was very difficult to figure out how to handle clicks in the shell, so I just didn’t have time to do the rest, it didn’t fit in the β€œtoy in the evening” format.



I tried to provide my code with comments and write quite structured to be able to figure out how everything works independently.





#!/bin/bash # Network chess by Evgeny Stepanischev http://bolknote.ru 2011 if [ $# -ne 2 ]; then echo Usage: $0 host-of-opponent port exit fi #   HOST="$1" #   PORT="$2" #     SEQLEN=(1b5b4. [2-7]. [cd]... [89ab].{5} f.{7}) #  WHITE=(β™™ β™™ β™™ β™™ β™™ β™™ β™™ β™™ β™– β™˜ β™— β™• β™” β™— β™˜ β™–) BLACK=(β™œ β™ž ♝ β™› β™š ♝ β™ž β™œ β™Ÿ β™Ÿ β™Ÿ β™Ÿ β™Ÿ β™Ÿ β™Ÿ β™Ÿ) #  ? OURMOVE= #    ? MYCOLOR= #  declare -a XY #  CX=1 CY=7 TAKEN= #     KUP=1b5b41 KDOWN=1b5b42 KLEFT=1b5b44 KRIGHT=1b5b43 KSPACE=20 #   function Restore { echo -ne "\033[5B\033[5B\033[?25h\033[m" stty "$ORIG" 2>/dev/null (bind '"\r":accept-line' 2>/dev/null) } trap Restore EXIT #  Enter (bind -r '\r' 2>/dev/null) #    ORIG=`stty -g` stty -echo #   echo -e "\033[?25l" #      function ToNet { echo $1 | nc "$HOST" "$PORT" } #     function React { case $1 in $KLEFT) if [ $CX -gt 1 ]; then CX=$(($CX-1)) PrintBoard fi ;; $KRIGHT) if [ $CX -lt 8 ]; then CX=$(($CX+1)) PrintBoard fi ;; $KUP) if [ $CY -gt 1 ]; then CY=$(($CY-1)) PrintBoard fi ;; $KDOWN) if [ $CY -lt 8 ]; then CY=$(($CY+1)) PrintBoard fi esac #      [ "$OURMOVE" ] && ToNet $1 } #       function CheckCons { local i for i in ${SEQLEN[@]}; do if [[ $1 =~ ^$i ]]; then return 0 fi done return 1 } #    ,  React    , #  KSPACE β€”     function PressEvents { local real code action #   ,    , #         #   while true; do #     read      # akw NR==1||NR==4    β„–1 (  real)  β„–4 ( ) eval $( (time -p read -r -s -n1 ch; printf 'code %d\n' "'$ch") 2>&1 | awk 'NR==1||NR==4 {print $1 "=" $2}' | tr '\r\n' ' ') # read    Enter  ,    20, #        UTF8 if [ "$code" = 0 ]; then code=20 else [ $code -lt 0 ] && code=$((256+$code)) code=$(printf '%02x' $code) fi if [ $code = $KSPACE ]; then [ "$OURMOVE" ] && ToNet $KSPACE SpaceEvent && return continue fi #     (   ) if [ $real = 0.00 ]; then seq="$seq$code" if CheckCons $seq; then React $seq seq= fi #     (      ), #   ,    else [ "$seq" ] && React $seq seq=$code #       if CheckCons $seq; then React $seq seq= fi fi done } #      function CheckColor { echo -n ${1:0:1} } #    function FillBoard { local xy ch for y in {1..8}; do for x in {1..8}; do ch='S ' if [ $y -le 2 ]; then ch=B${BLACK[$x+8*$y-9]} else if [ $y -ge 7 ]; then ch=W${WHITE[$x+8*$y-57]} fi fi XY[$x+100*$y]=$ch done done } #      function PrintBoardLetters { local letters=abcdefgh [ -z "$OURMOVE" ] && echo -ne "\033[30m" || echo -ne "\033[0m" echo -n ' ' for x in {0..7}; do echo -n "${letters:$x:1} " done echo } #      function PrintBoardDigit { [ -z "$OURMOVE" ] && echo -ne "\033[30m" echo -en " $((9-$1))\033[0m " } #   function PrintBoard { local xyc ch local colors=('48;5;209;37;1' '48;5;94;37;1') PrintBoardLetters for y in {1..8}; do PrintBoardDigit $y for x in {1..8}; do c=${colors[($x+$y) & 1]} ch=${XY[$x+100*$y]} if [[ $CX == $x && $CY == $y ]]; then c="$c;7" [ "$TAKEN" ] && ch=$TAKEN [ $MYCOLOR == B ] && c="$c;38;5;16" fi [[ $(CheckColor "$ch") == "B" ]] && c="$c;38;5;16" echo -en "\033[${c}m${ch:1:1} \033[m" done PrintBoardDigit $y echo done PrintBoardLetters echo -e "\033[11A" } #   function NetListen { nc -l $PORT } #     function NetEvents { local code while true; do code=$(NetListen) [[ "$code" == "$KSPACE" ]] && SpaceEvent && return React $code done } #    Space  Enter β€”     function SpaceEvent { local xy # ,      let xy="$CX+$CY*100" #   if [ "${XY[$xy]:-S }" = "S " ]; then if [ -z "$TAKEN" ]; then echo -en "\007" else #   XY[$xy]=$TAKEN TAKEN= return 0 fi #   else #     «»   if [[ $(CheckColor "$TAKEN") == $(CheckColor "${XY[$xy]}") ]]; then echo -en "\007" else #   Β« Β»,  «»  if [ "$TAKEN" ]; then XY[$xy]=$TAKEN TAKEN= return 0 else # Β« Β»   ,    TAKEN=${XY[$xy]} XY[$xy]="S " fi fi fi return 1 } #    function ClearKeyboardBuffer { #  β€”  zsh which zsh &>/dev/null && zsh -c 'while {} {read -rstk1 || break}' && return #  β€”  bash local delta while true; do delta=`(time -p read -rs -n1 -t1) 2>&1 | awk 'NR==1{print $2}'` [[ "$delta" == "0.00" ]] || break done } FillBoard #     ToNet HI [[ "$(NetListen)" == "HI" ]] && OURMOVE=1 sleep 0.2 ToNet ULOOSE [ "$OURMOVE" ] && MYCOLOR=W || MYCOLOR=B PrintBoard #   β€”        while true; do if [ -n "$OURMOVE" ]; then ClearKeyboardBuffer PressEvents OURMOVE= else NetEvents OURMOVE=1 fi PrintBoard done 




I recorded a small video to show how it looks, unfortunately, all recordings put a heavy strain on my computer and the game begins to slow down, but you can get a general idea.



Source: https://habr.com/ru/post/128549/



All Articles