Pular para o conteúdo

Snake [ALFA] em Shell Script

Fala pessoal do VOL!

Como treinamento de lógica avançada de programação estou tentando recriar jogos clássicos sem olhar nenhum código fonte (ou seja, fazer na raça mesmo :P).
Com isso decidi que meu primeiro jogo seria nada mais nada menos do que aquele que todos jogavam nos seus "Tijorolas": Snake!
Sim, aquela cobra simpática que vai aumentando conforme come a ração. :P

Estou há aproximadamente 3 meses mexendo no GNU/Linux e aprendendo Shell Script desde então. Nunca havia visto nenhum dos dois antes. :o

Enfim, segue abaixo o meu código, lembrando que ainda está na VERSÃO ALFA, portanto, existem mil e um bugs que ainda precisam ser encontrados e resolvidos.

Obs.: para movimentar-se utilize as teclas WASD (para quem não conhece: W - cima; A - esquerda; S - baixo; D - direita).
Espero que gostem e me deem um feedback, Cya. :D
marcelo cavalca filho colgatera
Hits: 7.875 Categoria: Shell Script Subcategoria: Miscelânea
  • Download
  • Nova versão
  • Indicar
  • Denunciar

Descrição

Fala pessoal do VOL!

Como treinamento de lógica avançada de programação estou tentando recriar jogos clássicos sem olhar nenhum código fonte (ou seja, fazer na raça mesmo :P).
Com isso decidi que meu primeiro jogo seria nada mais nada menos do que aquele que todos jogavam nos seus "Tijorolas": Snake!
Sim, aquela cobra simpática que vai aumentando conforme come a ração. :P

Estou há aproximadamente 3 meses mexendo no GNU/Linux e aprendendo Shell Script desde então. Nunca havia visto nenhum dos dois antes. :o

Enfim, segue abaixo o meu código, lembrando que ainda está na VERSÃO ALFA, portanto, existem mil e um bugs que ainda precisam ser encontrados e resolvidos.

Obs.: para movimentar-se utilize as teclas WASD (para quem não conhece: W - cima; A - esquerda; S - baixo; D - direita).
Espero que gostem e me deem um feedback, Cya. :D
Download snake.bsh Enviar nova versão

Versões atualizadas deste script

marcelo cavalca filho

Versão 2 enviada por marcelo cavalca filho em 30/09/2013

Changelog: (ATUALIZADO)

Essa é a melhor versão de Snake feita em Shell Script (ou não hehe), ela agora não possui erros e é bem mais enxuta que a anterior.
Me digam o que acharam e no que ainda posso melhorá-lo.
Meu próximo jogo a ser feito em shell será TETRIS (também a partir do zero :P)

Download 1380562200.snake.bsh

Esconder código-fonte

#!/bin/bash

#=====================================================================================#
#
#       Programa: snake.bsh
#
#       Autor:    Cavalca Filho, Marcelo (15/09/2013)
#
#       Objetivo: Jogo snake em shell :D
#
#=====================================================================================#
#
#       Versão:   1.0 - 19/09/2013
#         > Utiliza um vetor para exibir a cobra e reinicia o mapa inteiro a
#           cada movimento.
#
#         1.1 - 21/09/2013
#         > Ideia para criação de uma nova lógica pois a versão 1.0 trava mais
#           conforme a cobra vai aumentando.
#           Agora a cobra se move sozinha com o tempo, não necessitando o
#           "readkey" para cada próximo movimento.
#
#         1.2 - 22/09/2013
#         > Lógica melhorada para a posição da "nova comida" pois antes gerava
#           comida nas bordas ou dentro da cobra, bugando o jogo.
#
#         1.3 - 25/09/2013
#         > Versão alfa completa!
#           Agora o jogo não gera "lag" devido ao aumento da cobra pois com a
#           nova lógica a cobra não é uma matriz e sim o próprio terreno, por
#           assim dizer.
#           Pode parecer simples mas a lógica para a movimentação da cobra
#           conforme ela faz curvas é um pouco complexa. Leia o apêndice abaixo
#
#=====================================================================================#

#=============================== CURVAS: COMO LIDAR ==================================#
#
#       O grande problema no início foi que a cobra era uma matriz e o terreno
#   era outra. Isso gerava um pequeno "lag" conforme a cobra aumentava. Foi pensada
#   então em uma lógica que fizesse com que a cobra fosse parte do terreno.
#   O maior empecilho para isso foi quando ela se curvava: Para onde o "rabo" dela
#   vai quando ela vira? E se ela fizer mais de uma curva?
#   Então foi pensada na seguinte lógica: Existe uma matriz que guarda as curvas
#   feitas. Existe também um vetor que vai indicar qual o próximo movimento da
#   cabeça e qual o próximo movimento do rabo. Uma posição de CURVA armazena a
#   quantidade de curvas que ela ainda tem de realizar. Conforme ela vai fazendo
#   as curvas esse valor é decrementado e o vetor é renovado para que ele saiba
#   para onde ir na próxima curva.
#
#   ex.: a cobra vira:
#   baixo - direita - cima - direita - baixo
#    [4]  -   [1]   - [3]  -   [1]   -  [4]
#
#   CURVA[0,0]= 5 (total)
#   CURVA[0,1]= 4 (valor de "baixo")
#
#   O rabo encontrou a posição onde ele deve ir para baixo logo a matriz será
#   atualizada para:
#
#   CURVA[0,0]= 4
#   CURVA[0,1]= 1 (valor de "direita")
#
#   Portanto, na próxima curva que ela chegar ela saberá que tem de ir para a
#   direita, e depois "cima", e por aí vai :)
#
#
#   tl;dr: Tem uma matriz que guarda o movimento da próxima curva. Ao chegar lá
#          essa matriz é atualizada para os valores das outras curvas.
#
#=====================================================================================#

#================================= GERAR TERRENO =====================================#

clear
# Declaração das matrizes do campo
declare -A CAMPO
declare -A CURVA
# Aqui voce pode alterar a altura e a largura conforme desejar
# ___________
#|           |
   HEIGHT=15        # ALTURA
   WIDTH=30     # LARGURA
#|___________|

# Verdadeira geração do terreno. Ele irá colocar o campo na tela e inserir os caracteres
# para uma boa visualização do mesmo.
let m=${HEIGHT}+1
let n=${WIDTH}+1
let i=$n
while [ $i -ge 0 ]; do
    let j=$m
    while [ $j -ge 0 ]; do
    if [ $i -eq 0 ] || [ $j -eq 0 ] || [ $i -eq $n ] || [ $j -eq $m ]; then
        if [ $i -eq 0 ] && [ $j -eq 0 ]; then
        tput cup $j $i
        echo -ne "#"
        elif [ $i -eq $n ] && [ $j -eq 0 ]; then
        tput cup $j $i
        echo -ne "#"
        elif [ $i -eq $n ] && [ $j -eq $m ]; then
        tput cup $j $i
        echo -ne "#"
        elif [ $i -eq 0 ] && [ $j -eq $m ]; then
        tput cup $j $i
        echo -ne "#"
        elif [ $i -eq 0 ] || [ $i -eq $n ]; then
        tput cup $j $i
        echo -ne "‖"
        else
        tput cup $j $i
        echo -ne "="
        fi
        CAMPO[$i,$j]=1
#       echo -ne "█"
    else
        CAMPO[$i,$j]=0
    fi
    let j=$j-1
    done
    let i=$i-1
done

#=====================================================================================#


#=============================== INICIALIZAR VARIAVEIS ===============================#

DIFIC=0.05          # Dificuldade ou velocidade de atualização do movimento

# [!] De preferência não alterar as variáveis abaixo, a menos que saiba o que esteja
#     fazendo
# _____________________________________________________________________________________
#|                                                                                     |
    y[0]=1
    x[0]=2
    x[1]=1
    y[1]=1
    CURVA[0,0]=0
    m=$((RANDOM%${WIDTH}+1))    # Gerando...
    n=$((RANDOM%${HEIGHT}+1))   # ...a primeira...
    CAMPO[$m,$n]=2          # ...bolinha dentro da caixa.
    LASTMOV[0]=1            # A cobra andará para a direita primeiramente.
    LASTMOV[1]=1
    PONT=0
    INPUT="d"           # Inicialização da entrada.
    WHATDO="d"          # Qual movimento será o primeiro.
    REVDO="a"           # Reverso do primeiro movimento para evitar cobra louca.
    LOSTGAME=false          # Detecção de game perdido.
    tput civis
    tput cup $n $m
    echo -ne "*"
    tput cup ${y[0]} ${x[0]}
    echo -ne "ᕙ"
    tput cup ${y[1]} ${x[1]}
    echo -ne "∎"
    let n=$HEIGHT+4         # Exibição dos controles.
    tput cup $n 1

#|_______________________________________________________________________________________|


#=====================================================================================#

read -s -n 1 INPUT
while :; do
    let n=$HEIGHT+2
    tput cup $n 3
    stty echo
    echo "   X[0]=${x[0]}     Y[0]=${y[0]}      "
    echo "     PONTUACAO = $PONT     "
    stty -echo
    read -s -t ${DIFIC} -n 1 INPUT
    if [ $INPUT = "d" ] 2>&- || [ $INPUT = "a" ] 2>&- || [ $INPUT = "s" ] 2>&- || [ $INPUT = "w" ] 2>&- ; then
    if [ $INPUT != $WHATDO ] && [ $INPUT != $REVDO ]; then
        WHATDO=$INPUT
    fi
    fi

    if [ ${CAMPO[${x[1]},${y[1]}]} -eq 3 ]; then
    CAMPO[${x[1]},${y[1]}]=1
    LASTMOV[1]=${CURVA[0,1]}
    let CURVA[0,0]=${CURVA[0,0]}-1
    CURVA[1,0]=1
    while [ ${CURVA[1,0]} -le ${CURVA[0,0]} ]; do
        let CURVA[1,1]=${CURVA[1,0]}+1
        CURVA[0,${CURVA[1,0]}]=${CURVA[0,${CURVA[1,1]}]}
        CURVA[0,${CURVA[1,1]}]=0
        let CURVA[1,0]=${CURVA[1,0]}+1
    done
    fi

    if [ $WHATDO = "d" ]; then
        let m=${x[0]}+1
        let n=${y[0]}
        REVDO="a"
        if [ ${LASTMOV[0]} -ne 1 ]; then
        CAMPO[${x[0]},${y[0]}]=3
        let CURVA[0,0]=${CURVA[0,0]}+1
        CURVA[0,${CURVA[0,0]}]=1
        fi
        case ${CAMPO[$m,$n]} in
        0 ) CAMPO[${x[1]},${y[1]}]=0
            tput cup ${y[1]} ${x[1]}
            stty echo
            echo -ne " "
            case ${LASTMOV[1]} in
            1) let x[1]=${x[1]}+1;;
            2) let x[1]=${x[1]}-1;;
            3) let y[1]=${y[1]}-1;;
            4) let y[1]=${y[1]}+1;;
            esac
            tput cup ${y[0]} ${x[0]}
            echo -ne "∎"
            x[0]=$m
            CAMPO[${x[0]},${y[0]}]=1
            tput cup ${y[0]} ${x[0]}
            echo -ne "ᕙ"
            stty -echo ;;
        1 ) LOSTGAME=true
            break ;;
        2 ) let PONT=$PONT+1
            stty echo
            tput cup ${y[0]} ${x[0]}
            echo -ne "∎"
            x[0]=$m
            CAMPO[${x[0]},${y[0]}]=1
            tput cup ${y[0]} ${x[0]}
            echo -ne "ᕙ"
            NOYOUCANT=true
            while [ $NOYOUCANT = true ]; do
            m=$((RANDOM%${WIDTH}+1))
            n=$((RANDOM%${HEIGHT}+1))
            if [ ${CAMPO[$m,$n]} -eq 0 ]; then
                tput cup $n $m
                NOYOUCANT=false
            fi
            done
            CAMPO[$m,$n]=2
            echo -ne "*"
            stty -echo ;;
        3 ) LOSTGAME=true
            break ;;
        esac
        LASTMOV[0]=1
    fi

    if [ $WHATDO = "a" ]; then
        let m=${x[0]}-1
        let n=${y[0]}
        REVDO="d"
        if [ ${LASTMOV[0]} -ne 2 ]; then
        CAMPO[${x[0]},${y[0]}]=3
        let CURVA[0,0]=${CURVA[0,0]}+1
        CURVA[0,${CURVA[0,0]}]=2
        fi
        case ${CAMPO[$m,$n]} in
        0 ) CAMPO[${x[1]},${y[1]}]=0
            tput cup ${y[1]} ${x[1]}
            stty echo
            echo -ne " "
            case ${LASTMOV[1]} in
            1) let x[1]=${x[1]}+1;;
            2) let x[1]=${x[1]}-1;;
            3) let y[1]=${y[1]}-1;;
            4) let y[1]=${y[1]}+1;;
            esac
            tput cup ${y[0]} ${x[0]}
            echo -ne "∎"
            x[0]=$m
            CAMPO[${x[0]},${y[0]}]=1
            tput cup ${y[0]} ${x[0]}
            echo -ne "ᕗ"
            stty -echo ;;
        1 ) LOSTGAME=true
            break ;;
        2 ) let PONT=$PONT+1
            stty echo
            tput cup ${y[0]} ${x[0]}
            echo -ne "∎"
            x[0]=$m
            CAMPO[${x[0]},${y[0]}]=1
            tput cup ${y[0]} ${x[0]}
            echo -ne "ᕗ"
            NOYOUCANT=true
            while [ $NOYOUCANT = true ]; do
            m=$((RANDOM%${WIDTH}+1))
            n=$((RANDOM%${HEIGHT}+1))
            if [ ${CAMPO[$m,$n]} -eq 0 ]; then
                tput cup $n $m
                NOYOUCANT=false
            fi
            done
            CAMPO[$m,$n]=2
            echo -ne "*"
            stty -echo ;;
        esac
        LASTMOV[0]=2
    fi

    if [ $WHATDO = "w" ]; then
        let m=${x[0]}
        let n=${y[0]}-1
        REVDO="s"
        if [ ${LASTMOV[0]} -ne 3 ]; then
        CAMPO[${x[0]},${y[0]}]=3
        let CURVA[0,0]=${CURVA[0,0]}+1
        CURVA[0,${CURVA[0,0]}]=3
        fi
        case ${CAMPO[$m,$n]} in
        0 ) CAMPO[${x[1]},${y[1]}]=0
            tput cup ${y[1]} ${x[1]}
            stty echo
            echo -ne " "
            case ${LASTMOV[1]} in
            1) let x[1]=${x[1]}+1;;
            2) let x[1]=${x[1]}-1;;
            3) let y[1]=${y[1]}-1;;
            4) let y[1]=${y[1]}+1;;
            esac
            tput cup ${y[0]} ${x[0]}
            echo -ne "∎"
            y[0]=$n
            CAMPO[${x[0]},${y[0]}]=1
            tput cup ${y[0]} ${x[0]}
            echo -ne "ᕓ"
            stty -echo ;;
        1 ) LOSTGAME=true
            break ;;
        2 ) let PONT=$PONT+1
            stty echo
            tput cup ${y[0]} ${x[0]}
            echo -ne "∎"
            y[0]=$n
            CAMPO[${x[0]},${y[0]}]=1
            tput cup ${y[0]} ${x[0]}
            echo -ne "ᕓ"
            NOYOUCANT=true
            while [ $NOYOUCANT = true ]; do
            m=$((RANDOM%${WIDTH}+1))
            n=$((RANDOM%${HEIGHT}+1))
            if [ ${CAMPO[$m,$n]} -eq 0 ]; then
                tput cup $n $m
                NOYOUCANT=false
            fi
            done
            CAMPO[$m,$n]=2
            echo -ne "*"
            stty -echo ;;
        esac
        LASTMOV[0]=3
    fi

    if [ $WHATDO = "s" ]; then
        let m=${x[0]}
        let n=${y[0]}+1
        REVDO="w"
        if [ ${LASTMOV[0]} -ne 4 ]; then
        CAMPO[${x[0]},${y[0]}]=3
        let CURVA[0,0]=${CURVA[0,0]}+1
        CURVA[0,${CURVA[0,0]}]=4
        fi
        case ${CAMPO[$m,$n]} in
        0 ) CAMPO[${x[1]},${y[1]}]=0
            tput cup ${y[1]} ${x[1]}
            stty echo
            echo -ne " "
            case ${LASTMOV[1]} in
            1) let x[1]=${x[1]}+1;;
            2) let x[1]=${x[1]}-1;;
            3) let y[1]=${y[1]}-1;;
            4) let y[1]=${y[1]}+1;;
            esac
            tput cup ${y[0]} ${x[0]}
            echo -ne "∎"
            y[0]=$n
            CAMPO[${x[0]},${y[0]}]=1
            tput cup ${y[0]} ${x[0]}
            echo -ne "ᕕ"
            stty -echo ;;
        1 ) LOSTGAME=true
            break ;;
        2 ) let PONT=$PONT+1
            stty echo
            tput cup ${y[0]} ${x[0]}
            echo -ne "∎"
            y[0]=$n
            CAMPO[${x[0]},${y[0]}]=1
            tput cup ${y[0]} ${x[0]}
            echo -ne "ᕕ"
            NOYOUCANT=true
            while [ $NOYOUCANT = true ]; do
            m=$((RANDOM%${WIDTH}+1))
            n=$((RANDOM%${HEIGHT}+1))
            if [ ${CAMPO[$m,$n]} -eq 0 ]; then
                tput cup $n $m
                NOYOUCANT=false
            fi
            done
            CAMPO[$m,$n]=2
            echo -ne "*"
            stty -echo ;;
        esac
        LASTMOV[0]=4
    fi

    if [ $INPUT = "q" ] 2>/dev/null; then
        clear
        tput cnorm
        exit 0
    fi
done
if [ $LOSTGAME ]; then
    clear
    echo "Voce perdeu! Conseguiu um total de $PONT pontos!"
    echo
fi
tput cnorm
exit

Análise de tráfego

BusqueM3P! - Download de músicas pelo shell

Ubuntu Edgy

Relógio Simples no Shell

Data e Hora (Observatório Nacional) usando o "Lynx"

#1 Comentário enviado por lcavalheiro em 26/09/2013 - 14:34h
Do [*****], meus parabéns!
#2 Comentário enviado por colgatera em 26/09/2013 - 14:44h
Obrigado @Icavalheiro :D espero que tenha mesmo gostado :)

O grande bug dele são essas letras que aparecem no meio do mapa devido ao shell estar sempre lendo o teclado(creio eu), ainda não encontrei um jeito de dar um 'silence' no teclado pra nao aparecer nada do que o usuario digita :/
#3 Comentário enviado por lcavalheiro em 26/09/2013 - 14:52h
Neste trecho
if [ $INPUT = "d" ] 2>&- || [ $INPUT = "a" ] 2>&- || [ $INPUT = "s" ] 2>&- || [ $INPUT = "w" ] 2>&- ; then
if [ $INPUT != $WHATDO ] && [ $INPUT != $REVDO ]; then
WHATDO=$INPUT
fi
fi

Inclua uma condição para jogar para /dev/null qualquer coisa digitada que não seja os comandos de movimento.
#4 Comentário enviado por colgatera em 30/09/2013 - 10:26h

[3] Comentário enviado por lcavalheiro em 26/09/2013 - 14:52h:

Neste trecho
if [ $INPUT = "d" ] 2>&- || [ $INPUT = "a" ] 2>&- || [ $INPUT = "s" ] 2>&- || [ $INPUT = "w" ] 2>&- ; then
if [ $INPUT != $WHATDO ] && [ $INPUT != $REVDO ]; then
WHATDO=$INPUT
fi
fi

Inclua uma condição para jogar para /dev/null qualquer coisa digitada que não seja os comandos de movimento.


Obrigado pela dica! Agora consegui anular as entradas do teclado hehe
Vou tentar postar a versão nova agora, que aliás está bem menor com relação a esta :D
#5 Comentário enviado por lcavalheiro em 30/09/2013 - 10:57h

[4] Comentário enviado por colgatera em 30/09/2013 - 10:26h:


[3] Comentário enviado por lcavalheiro em 26/09/2013 - 14:52h:

Neste trecho
if [ $INPUT = "d" ] 2>&- || [ $INPUT = "a" ] 2>&- || [ $INPUT = "s" ] 2>&- || [ $INPUT = "w" ] 2>&- ; then
if [ $INPUT != $WHATDO ] && [ $INPUT != $REVDO ]; then
WHATDO=$INPUT
fi
fi

Inclua uma condição para jogar para /dev/null qualquer coisa digitada que não seja os comandos de movimento.

Obrigado pela dica! Agora consegui anular as entradas do teclado hehe
Vou tentar postar a versão nova agora, que aliás está bem menor com relação a esta :D


Show de bola!

Contribuir com comentário

Entre na sua conta para comentar.