New Version of Squa.sh

I’ve made some changes to squa.sh, my Bash script Pong clone.

The first version made extensivce use of tput to update the terminal cursor position. I compared the resulting control sequences sent to various terminal versions, and all seemed to be in the format:

1
^[${row};${column}H

Therefore this new version uses pre cooked control sequences instead of forking tput like mad. dd is still spawned each iteration of the main loop to capture user input, read smallest timeout is 1 second, so this is no option, or the game would be no much fun. ;)

Also terminal size detection is fixed for NetBSD now, which means that the new version of squa.sh runs on all hardware in my house right now!

The code and a download link for the new version follows below:

squa.sh link
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/bin/bash

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

case "$(uname -s)" in
  NetBSD)
      cols=$(stty -e | head -1 | cut -d\  -f6)
      rows=$(stty -e | head -1 | cut -d\  -f4)
  ;;
  Linux|*)
      cols=$(tput cols)
      rows=$(tput rows)
  ;;
esac

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)
  horchar="-"; vertchar="|"
  for ((row=1; row < $3; row++)) {
      [ $row -eq 1 ] || [ $row -eq $(($3 - 1)) ] && {
          echo -n "$escape[$(($1 + $row));$(($2 + 2))H"
          for ((i=0; i < $4 - 2; i++)); do
                      echo -n $horchar
              done
      } || {
          echo -n "$escape[$(($1 + $row));${2}H$vertchar"
          echo -n "$escape[$(($1 + $row));$(($2 + $4))H$vertchar"
      }
  }
}

draw_paddle() {
  for ((row=pos; row <= pos + 4; row++)) {
      echo -n "$escape[$((row + 1));$((cols - 4))H${1}"
  }
}

upd_ball() {
  # bounce on walls
  [ $ball_row -le 3 ] &&  ((ball_dx = -ball_dx))
  [ $ball_row -ge $((rows - 1)) ] && ((ball_dx = -ball_dx))
  [ $ball_col -le 2 ] && ((ball_dy = -ball_dy))
  # back wall, decrement score too
  [ $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'

  space=" "
  ball="o"
  paddle="#"

  draw_rect 1 0 $rows $cols

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

  init_ball ; echo -n "$escape[$ball_row;${ball_col}H$ball"

  score=0
}

init_ball() {

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

init
while :
do
  echo -n "$escape[0;3Hscore :       "
  echo -n "$escape[0;3Hscore : $score"

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

  echo -n "$escape[$ball_row;${ball_col}H${space}"
  upd_ball
  echo -n "$escape[$ball_row;${ball_col}H${ball}"
  
done

Comments