I got bored, and I've always wanted to write a game, that isn't text-based, in Bash, so I made this last night. Use the A and D keys to turn left and right (respectively), and press P to pause. To get the Play Again functionality to work, save the script and chmod it, then run it.
Code:
#!/bin/bash

function init() {
    stty -echo -icanon time 0 min 0
    echo -ne "\E[?25l"
    clear
    for((i=0;i<40;i++)); do
   echoat 40 $i "x"
   echoat $i 40 "x"
    done
}   

function readchar() {
    dd bs=1 count=1 2>/dev/null
}

function randapple() {
    x=$(($RANDOM % 39 + 1))
    y=$(($RANDOM % 39 + 1))
    echo "$x,$y"
}

function echoat() {
    thisx="$1"
    thisy="$2"
    thismsg="$3"
    echo -ne "\033[$thisy;$thisx""H$thismsg"
}

function end() {
    stty sane
    echo -ne "\E[?25h"
    clear
}

init
snakex=( 1 1 1 1 )
snakey=( 1 2 3 4 )
x=1
y=5
apple=$(randapple)
snakelen=3
score=0
dirsx=( 1 0 -1 0 )
dirsy=( 0 1 0 -1 )
dir=0
while true; do
    echoat $(echo $apple | sed "s/,/ /") "A"
    echoat 42 5 "Score: $score"
    echoat ${snakex[0]} ${snakey[0]} " "
    for i in $(seq 0 $(($snakelen - 1))); do
   if [ $x = ${snakex[i]} ] && [ $y = ${snakey[i]} ]; then
       break 2;
   fi
   snakex[$i]=${snakex[$(($i + 1))]}
   snakey[$i]=${snakey[$(($i + 1))]}
    done
    snakex[snakelen]=$x
    snakey[snakelen]=$y
    ((x=x+${dirsx[dir]}))
    ((y=y+${dirsy[dir]}))
    key=$(readchar)
    case $key in
   q) break;;
   d) ((dir++));;
   p) while [ ! "$(readchar)" = "p" ]; do true; done;;
   a) ((dir--));;
   *);;
    esac
    if [ $dir -gt 3 ] || [ $dir -lt 0 ]; then
   ((dir=(dir+4)%4))
    fi
    if [ $x -lt 1 ] || [ $x -gt 39 ] || [ $y -lt 1 ] || [ $y -gt 39 ]; then
   break
    fi
    if [ "$x,$y" = "$apple" ]; then
   ((score++))
   ((snakelen++))
   snakex[$snakelen]=${snakex[1]}
   snakey[$snakelen]=${snakey[1]}
   apple=$(randapple)
    fi
    echoat $x $y "X"
    if [ $score -gt 5 ]; then
   if [ $score -gt 8 ]; then
       sleep .07
   else
       sleep .1$((4 - $(($score - 5)) / 2))
   fi
    else
   sleep .$((3 - $score / 2))
    fi
done   
end
echo "You scored: $score"
read -p "Play again? [y/N] "
if echo "$REPLY" | egrep "[Yy]" &>/dev/null; then
    exec "$0"
else
    echo "Thanks for playing!"
fi
How does your readchar() routine work? It completely baffles me. It does look really well made, though, good job. I'll have to try this soon. Smile
In `init', it sets the terminal to not output characters, accept characters exactly as they are (ie, not waiting until a newline), and sets the max time it takes to get a key to 0, so that if you call the routine, and there isn't a key waiting, it will just let you move on. In other words, it makes it non-blocking. In `readchar', it uses `dd' to grab one byte from input (if it is there), if it isn't there, it will just leave the output blank. The routine also outputs a period, so that the call can finish (I think? I should try it without the period, too), and then the next line just removes the extra period.

Edit: It seems you can just use
Code:
function readchar() {
    dd bs=1 count=1 2>/dev/null
}
instead of
Code:
function readchar() {
    key=$(dd bs=1 count=1 2>/dev/null; printf ".")
    echo "${key%.}"
}
So, I am changing the code above to the more optimized function Smile

Edit2: Also, the `dd' program seems to default to if=/dev/stdin and of=/dev/stdout. The arguments are: blocksize=1 (byte), and number_of_blocks_to_get=1 (byte).
Oh man, this needs so very much more delay. I die instantly, even artificially trying to slow it down. Smile I'm sure I could figure it out myself if I use my brain, but what's your recommended fix for slowing everything down a bit?
I slowed my copy down by adding a "sleep .1" line in the main loop. That value could be adjusted for greater or lesser delay, obviously.
And, for an easy->hard game, I am using this:
Code:
    if [ $score -gt 5 ]; then
   if [ $score -gt 8 ]; then
       sleep .07
   else
       sleep .1$((4 - $(($score - 5)) / 2))
   fi
    else
   sleep .$((3 - $score / 2))
    fi
I'm going to go ahead and add that to the first post Smile
This probably needs ncurses, doesn't it?
My Cygwin is having problems playing it =p
*Goes to update Cygwin*

Well now it displays properly, but frames only update on keypress, so it runs nice and slowly for me Wink

Still; it's pretty cool. Good job Smile
Hmm, I guess that means that (And I guess it was to be expected) cgywin doesn't emulate the xterm (and now, pretty much all) cursor positioning special characters. It also seems to not emulate `stty' and changing the terminal's input and output controls. If you were to run it on a Linux machine, it'd work perfectly (I hope...) Razz
I tried it over SSH through PuTTY, and I'm unable to turn. Edit: I don't read instructions properly. The rotational movement is new to me, but it works pretty well. I like how the speed gradually increases now, very nice. I think there might be a bug, though: after eating 5 apples I randomly died when nowhere near a wall. Sad
Oh why didn't I think of that?
Yea, it works great over SSH. Very nice game.
I do agree with Kerm though; the difficulty should come from having such a fat tail, not from going over the extent screen in under a second.
Bleh, Kerm, I even fixed that in my copy, but forgot to post it here x.x Change

Code:
   snakex[$snakelen]=${snakex[oldlen]}
   snakey[$snakelen]=${snakex[oldlen]}
to
Code:
   snakex[$snakelen]=${snakex[1]}
   snakey[$snakelen]=${snakey[1]}

Adding that to the original post Smile
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement