2 # sink.sh - a networked battleship game for Bourne-again shell.
4 # Copyright Gregory Bonik, 2009
7 # Beerware licence is well applicable.
10 # All external stuff we use. Change if needed.
16 ##############################################################################
18 ##############################################################################
38 echo "Sink'em all - a networked battleship game for Bourne-again shell."
39 echo "Version $VERSION"
40 echo "Usage: $EXENAME [ -serve | HOST ] [ -p PORT ]"
47 local MSG1_XXXXXXXXXXXXXXXXXXXXXXXXXXX
="$MSG1${SPACE:0:$((33 - ${#MSG1}))}"
48 local MSG2_XXXXXXXXXXXXXXXXXXXXXXXXXXX
="$MSG2${SPACE:0:$((33 - ${#MSG2}))}"
49 local MSG3_XXXXXXXXXXXXXXXXXXXXXXX
="$MSG3${SPACE:0:$((29 - ${#MSG3}))}"
50 local MSG4_XXXXXXXXXXXXXXXXXXXXXXX
="$MSG4${SPACE:0:$((29 - ${#MSG4}))}"
51 echo "O-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..O"
52 echo ") .- . | . , _ .'| | | | ("
53 echo ") \`; | |\\| |\`. (_' |\`| :-: | | . ("
54 echo ') .-. _`_ _ _ _ _________________`_`_`_`_ _ .-. ('
55 echo ") \`.' \`--' ,__ \`--' '.' ("
57 echo ") $MSG1_XXXXXXXXXXXXXXXXXXXXXXXXXXX ; ("
58 echo ") $MSG2_XXXXXXXXXXXXXXXXXXXXXXXXXXX |.------. ("
60 echo ") $MSG3_XXXXXXXXXXXXXXXXXXXXXXX | \`------\` ("
61 echo ") $MSG4_XXXXXXXXXXXXXXXXXXXXXXX \`---.------\\--- ("
62 echo ') ;-----| \\ | ('
64 echo ') / ;_______\ \ ('
65 echo ') ------.--------\ \ ('
66 echo ') / / / ; \ \ ('
67 echo ') / / / / ; \/ ('
68 echo ') / / / / /; .------/ ('
69 echo ") /-/-/-/-/-\`'_____//_, ("
71 echo ") / o o o o o o # | (C) 2009 G. B. ("
72 echo ") ~ ~~..~~.. ..~~~.. ~~. \`~~~~~....._____#_-' ~~.. ~~.. ..~~~... ~~.. ~~.. ~ ("
73 echo ") ~~ ..~~~.. ..~... ..~~~. ~~..~~ ~~..~~ ~~..~~ ~~..~~..~~..~ ~~ ~~ ~ ("
74 echo -n "O-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..O"
82 echo "O-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..O"
83 echo ") .- . | . , _ .'| | | | ("
84 echo ") \`; | |\\| |\`. (_' |\`| :-: | | . ("
85 echo ') .-. _`_ _ _ _ _________________`_`_`_`_ _ .-. ('
86 echo ") \`.' \`--' \`--' '.' ("
87 echo ") o~-~-~-~-~-~-~-~-~-~-~-~-~o o-~-~-~-~-~-~-~-~-~-~-~-~-o o-~-~-~-~-~-~-~-~-~o ("
88 echo ") ; a b c d e f g h i j | ; a b c d e f g h i j | ; $H${SPACE:0:$((16-${#H}))} | ("
91 for (( i
= 0; i
< 10; ++i
)) ; do
92 echo -n ") $S1 $(( (i + 1) % 10)) "
93 for (( j
= 0; j
< 10; ++j
)) ; do
94 echo -n "${THY[$((i*10 + j))]} "
96 echo -n " $S2 $S1 $(( (i + 1) % 10)) "
97 for (( j
= 0; j
< 10; ++j
)) ; do
98 echo -n "${FOE[$((i*10 + j))]} "
100 H
="${HINT[$((i + 1))]}"
101 local HINTX
="$H${SPACE:0:$((16 - ${#H}))}"
102 echo " $S2 $S1 $HINTX $S2 ("
107 echo ") o~-~-~-~-~-~-~-~-~-~-~-~-~o o-~-~-~-~-~-~-~-~-~-~-~-~-o o-~-~-~-~-~-~-~-~-~o ("
109 local MSGX
="$MSG${SPACE:0:$((72 - ${#MSG}))}"
110 local MSG2X
="$MSG2${SPACE:0:$((72 - ${#MSG2}))}"
111 echo ") o-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~o ("
113 echo ") | $MSG2X | ("
114 echo ") o~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-o ("
115 echo -n "O-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..-~-..O"
120 for (( i
= 0; i
< 100; ++i
)) ; do
127 local imin
=$
((ROW
- 1))
128 local jmin
=$
((COL
- 1))
129 local imax
=$
((ROW
+ H
+ 1))
130 local jmax
=$
((COL
+ W
+ 1))
133 ((imin
< 0)) && imin
=0
134 ((jmin
< 0)) && jmin
=0
135 ((imax
> 10)) && imax
=10
136 ((jmax
> 10)) && jmax
=10
139 for (( i
= imin
; i
< imax
; ++i
)) ; do
140 for (( j
= jmin
; j
< jmax
; ++j
)) ; do
141 [[ "${THY[$((i*10 + j))]}" == "$CHAR_SHIP" ]] && return 1
145 for (( i
= 0; i
< H
; ++i
)) ; do
146 for (( j
= 0; j
< W
; ++j
)) ; do
147 THY
[$
(((ROW
+ i
)*10 + j
+ COL
))]="$CHAR_SHIP"
148 THYSHIP
[$
(((ROW
+ i
)*10 + j
+ COL
))]=$
(( 10 - LEFT
))
154 (( SHIPS
[SHIP
] < 1 )) && (( ++SHIP
))
155 (( SHIP
> 3 )) && return 0
167 eval echo \
${$ARR[$IDX]}
177 local imin
="$((CELL / 10))"
178 local jmin
="$((CELL % 10))"
184 for (( c
= $CELL; imin
> 0; --imin )) ; do
185 [ "$(arrayget $1 $c)" == "$CHAR_DEAD" ] ||
break
188 for (( c
= $CELL; imax
< 9; ++imax
)) ; do
189 [ "$(arrayget $1 $c)" == "$CHAR_DEAD" ] ||
break
192 for (( c
= $CELL; jmin
> 0; --jmin )) ; do
193 [ "$(arrayget $1 $c)" == "$CHAR_DEAD" ] ||
break
196 for (( c
= $CELL; jmax
< 9; ++jmax
)) ; do
197 [ "$(arrayget $1 $c)" == "$CHAR_DEAD" ] ||
break
201 for (( i
= imin
; i
<= imax
; ++i
)) ; do
202 for (( j
= jmin
; j
<= jmax
; ++j
)) ; do
203 echo "$i $j $(arrayget $1 $((i*10 + j)) )"
204 if [ "$(arrayget $1 $((i*10 + j)) )" == "$CHAR_WATER" ] ; then
205 arrayset
$1 $
((i
*10 + j
)) "$CHAR_MISS"
212 if [ -z "$COPROC_PID" ] ; then
213 echo "Connection closed"
221 THYSHIPDECKS
=( 4 3 3 2 2 2 1 1 1 1 )
238 MSG
="Place your ships."
240 while (( LEFT
> 0 )) ; do
241 BACKUP
=( "${THY[@]}" )
242 for (( i
= 0; i
< H
; ++i
)); do
243 for (( j
= 0; j
< W
; ++j
)); do
244 THY
[$
(( (i
+ ROW
) * 10 + j
+ COL
))]="$CHAR_ACTIVE"
250 THY
=( "${BACKUP[@]}" )
252 if ! read -sn 1 KEY
; then
257 MSG
="Place your ships."
263 r
) TMP
=$W; W
=$H; H
=$TMP ;;
268 MSG
="Cannot place ship here because "
269 MSG
+="another ship is too close"
274 if (( ROW
< 0 )) ; then ROW
=0 ; fi
275 if (( COL
< 0 )) ; then COL
=0 ; fi
276 if (( ROW
+ H
> 10 )) ; then ((ROW
= 10 - H
)); fi
277 if (( COL
+ W
> 10 )) ; then ((COL
= 10 - W
)); fi
285 if ! read -u "${COPROC[0]}" CELL
; then
286 echo "Connection closed"
290 if (( CELL
< 0 || CELL
> 99 )) ; then
291 echo "Received malformed data, exiting"
297 if [ "${THY[$CELL]}" == "$CHAR_SHIP" ] ; then
298 THY
["$CELL"]="$CHAR_DEAD"
300 (( --THYSHIPDECKS[THYSHIP
[CELL
]] ))
302 if (( THYSHIPDECKS
[THYSHIP
[CELL
]] > 0 )) ; then
303 MSG
="Enemy has hit your ship!"
304 echo hit
>&"${COPROC[1]}"
306 MSG
="Enemy has sunk your ship!"
307 echo sunk
>&"${COPROC[1]}"
310 if (( THYDECKS
== 0 )) ; then
311 MSG
="All your ships have been sunk. You've lost the game :("
315 if [ "${THY[$CELL]}" == "$CHAR_WATER" ] ; then
316 THY
["$CELL"]="$CHAR_MISS"
319 MSG
="Enemy has missed. Your turn."
320 echo miss
>&"${COPROC[1]}"
330 FOE
["$CELL"]="$CHAR_DEAD"
332 if (( FOEDECKS
== 0 )) ; then
333 MSG
="Congratulations! You have won! :-)"
341 if [ "${FOE[$CELL]}" != "$CHAR_WATER" ] ; then
342 MSG
='Already shot there! Choose another target.'
348 echo "$CELL" >&"${COPROC[1]}"
351 if ! read -u "${COPROC[0]}" HIT
; then
352 echo "Connection closed"
356 if [ "$HIT" == "hit" ] ; then
357 MSG
="You have hit! Your turn again."
361 if [ "$HIT" == "sunk" ] ; then
362 MSG
="You have sunk enemy's ship! Your turn again."
369 FOE
["$CELL"]="$CHAR_MISS"
370 MSG
="You have missed. Now waiting enemy's turn..."
381 "w Up" "a Left" "s Down" "d Right" "f Fire"
385 CELL
=$
(( ROW
*10 + COL
))
386 BACKUP
="${FOE[$CELL]}"
387 FOE
[$CELL]="$CHAR_CROSSHAIR"
391 if ! read -sn 1 KEY
; then
404 (( ROW
< 0 )) && ROW
=0
405 (( COL
< 0 )) && COL
=0
406 (( ROW
>= 10 )) && ROW
=9
407 (( COL
>= 10 )) && COL
=9
415 # Parse command-line options
420 while (( $# > 0 )) ; do
426 if (( $# < 2 )); then usage
; fi
431 echo "Unknown option $1"
435 if [ -n "$HOST" ]; then usage
; fi
442 if [ -z "$HOST" ] && (( SERVE
== 0 )) ; then
443 echo "Need a hostname."
448 HELLOSTR
="Hi, I want to play a game with you"
450 if (( SERVE
== 1 )) ; then
451 MSG1
="Waiting for incoming"
452 MSG2
="connection on port $PORT..."
454 coproc
$NETCAT -q 0 -l -p "$PORT"
458 MSG2
="$HOST:$PORT..."
459 coproc
$NETCAT -w 5 -q 0 "$HOST" "$PORT"
463 echo "$HELLOSTR" >&${COPROC[1]}
466 if ! read -t "$READTIMEOUT" -u "${COPROC[0]}" HELLO
; then
467 echo "Failed to connect, exiting."
471 if [ "$HELLO" != "$HELLOSTR" ] ; then
472 echo "Unknown peer at the other end of connection, exiting."
476 #echo "Connected! Press ENTER to start placing ships!"
479 MSG3
="Press ENTER to start"
493 MSG
="All ships placed. Waiting for the enemy..."
498 echo "$THYNUMBER" >&${COPROC[1]}
501 if ! read -u "${COPROC[0]}" FOENUMBER
; then
502 echo "Connection closed"
506 if (( FOENUMBER
> THYNUMBER
)) ; then
507 MSG
="Enemy's turn is first. Waiting..."
513 while ((LOST
!= 1)); do
520 MSG2
="Play again? (y/n)"
523 while read -n 1 YESNO
; do
525 if [ "$YESNO" == 'y' ] ||
[ "$YESNO" == 'Y' ] ; then
528 if [ "$YESNO" == 'n' ] ||
[ "$YESNO" == 'N' ] ; then
535 if [ -n "$COPROC_PID" ] ; then