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.874 Categoria: Shell Script Subcategoria: Miscelânea
  • Download
  • Nova versão
  • Indicar
  • Denunciar
O Viva o Linux depende da receita de anúncios para se manter. Ative os cookies aqui para nos patrocinar.
Não conseguimos carregar os anúncios. Se usa bloqueador, considere liberar o Viva o Linux para nos patrocinar.

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
O Viva o Linux depende da receita de anúncios para se manter. Ative os cookies aqui para nos patrocinar.
Não conseguimos carregar os anúncios. Se usa bloqueador, considere liberar o Viva o Linux para nos patrocinar.

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
O Viva o Linux depende da receita de anúncios para se manter. Ative os cookies aqui para nos patrocinar.
Não conseguimos carregar os anúncios. Se usa bloqueador, considere liberar o Viva o Linux para nos patrocinar.

wget com progressbar no kde

dcamt

Script para Gerenciamento de Pacotes no Slackware

Script Iniciador do PostgreSQL

BackUp Mensal de Relatórios Diários

#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.