squa.sh - Pong clone in Bash

Squa.sh is a Bash shell script Pong clone that I clobbered together this Sunday evening. :)
This has probably been done before, and it is no fun to play at all, but it was quite fun to write.

The name squa.sh is quite appropiate as I have been too lazy to implement an opponent yet, therefore you score each time that you avoid the ball from hitting the wall behind you, and you loose a point when the ball hits this wall.

Squa.sh should work unmodified on Linux, I know for sure that it does not work on NetBSD yet, maybe I try to fix this later, or should you be so kind, send me a patch if you like to fix this yourself. ;)

On your VT100 squa.sh will look something like this: ;)


   score : 7
  ----------------------------------------------------
 |                                                    |
 |                                                    |
 |                                                    |
 |                                                    |
 |                                                 #  |
 |                                                 #  |
 |                                                 #  |
 |                                                 #  |
 |                                           o     #  |
 |                                                    |
 |                                                    |
 |                                                    |
 |                                                    |
 |                                                    |
 |                                                    |
 |                                                    |
 |                                                    |
 |                                                    |
 |                                                    |
 |                                                    |
 |                                                    |
  ----------------------------------------------------

		

You can download squa.sh from http://isquared.nl/src/squa.sh.
A newer that doesn't fork tput like it wants to kill your machine is available from http://isquared.nl/src/squa.sh-ng/squa.sh. For more information about this new version, see this article.
Below you find the source of the first squa.sh:

#!/bin/bash

# squa.sh - play squash in bash
# Hessel Schut, hessel@isquared.nl, 2009-04-19

cols=$(tput cols)
rows=$(tput lines)

norm=$(tput rmso)

trap cleanup EXIT TERM INT

cleanup() {
        tput rmso
        tput clear
        tput cnorm

	stty sane

        exit
}

draw_rect() {
	# draw_rect(row column rows columns)
	for ((row=0; row < $3; row++));
	do
		if [ $row -eq 0 ] || [ $row -eq $(($3 - 1)) ]
		then
			tput cup $(($1 + $row)) $(($2 + 1))
			for ((i=0; i < $4 - 2; i++)); do
                		echo -n '-'
        		done
		else
			tput cup $(($1 + $row)) $2
			echo -n "|"
			tput cup $(($1 + $row)) $(($2 + $4 - 1))
			echo -n "|"
		fi
	done
}

draw_paddle() {
	for ((row=pos; row <= pos + 4; row++)) 
	do
		tput cup $row $((cols - 4))
		echo -n "$1"
	done
}

upd_ball() {
	# bounce on corners
	[ $ball_row -le 2 ] && {
		((ball_dx = -ball_dx))
	}
	[ $ball_row -ge $((rows - 2)) ] && {
		((ball_dx = -ball_dx))
	}
	[ $ball_col -le 2 ] && {
		((ball_dy = -ball_dy))
	}
	[ $ball_col -ge $((cols - 2)) ] && {
		((ball_dy = -ball_dy))
		((score--)) 
		init_ball
	}

	# bounce on paddle
	[ $ball_col -eq $((cols - 5)) ] && {
		[ $ball_row -ge $pos ] && [ $ball_row -le $((pos + 5)) ] && {
			((ball_dx = -ball_dx))
			((ball_dy = -ball_dy))
			((score++))
		}
	}

	(( ball_row += ball_dx ))
	(( ball_col += ball_dy ))
}

init() {
	tput clear
	tput civis

	stty -echo -icanon time 0 min 0

	uparrow=$'\x1b[A'
	downarrow=$'\x1b[B'
	escape=$'\x1b'

	draw_rect 1 1 $((rows - 1)) $((cols - 1))

	pos=$((rows/2 - 2))
	draw_paddle "#"

	init_ball ; tput cup $ball_row $ball_col; echo -n "o"

	score=0
}

init_ball() {

	[ ! -z "$ball_row" ] && {
		tput cup $ball_row $ball_col; echo -n " "
	}
	
        ball_row=$((${RANDOM}%(rows - 8) + 4))
        ball_col=$((${RANDOM}%(cols - 8) + 4))
        ball_dx=-1
        ball_dy=-1
}

init
while [ == ]
do
	tput cup 0 3 ; echo -n "score : $score"

	key=$(dd bs=3 count=1 2>/dev/null)
	case "$key" in 
		$uparrow|w)
			draw_paddle " "
			[ $pos -gt 2 ] && ((pos--))
			draw_paddle "#"
		;;
		$downarrow|s)
			draw_paddle " "
			[ $((pos + 5)) -lt $((rows - 1)) ] && ((pos++))
			draw_paddle "#"
		;;
		$escape|q)
			cleanup
		;;
	esac

	tput cup $ball_row $ball_col; echo -n " "
	upd_ball
	tput cup $ball_row $ball_col; echo -n "o"
	
	sleep 0.1
done