Jogo do Labirinto no Terminal

Publicado por Samuel Leonardo (última atualização em 14/05/2021)

[ Hits: 6.783 ]

Homepage: https://nerdki.blogspot.com/

Download labirintoC-1.0.0.tar.gz




Este é um pequeno programa que fiz há uns anos atrás. É apenas uma versão de jogo do labirinto em C. Você pode criar uma matriz de caracteres num arquivo chamado matrizLabirinto.txt e depois executar o jogo.

Para compilar:

$ gcc -o labirintoC labirintoC.c

Para executar:

$ ./labirintoC

Você pode baixar o pacote tar.gz e ver uma matriz de exemplo.

Se for criar a sua lembre que, a condição para ler a matriz é: ela deve ter o mesmo número de colunas. Ou seja, as linhas do matrizLabirinto.txt devem ter a mesma quantidade de caracteres. Os caracteres usados são o '.' (ponto) para caminho vazio, e o '#' para parede sólida, '@' é o jogador e a saída do labirinto é o 'E'.

  



Esconder código-fonte

/**
 * @file labirintoC.c
 * @author Samuel Leonardo (nerdki.blogspot.com.br)
 * @brief Pequeno jogo do labirinto em C
 * @version 1.0.0
 * @date 2019-11-15
 * 
 * @copyright Samuel Leonardo (c) 2019
 * para compilar use:
 *  gcc -o labirintoC labirintoC.c
 *
 */

//jogo do labirinto em C
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

//struct do mapa
typedef struct
{
   //largura atual do mapa
   int largura;
   //altura atual do mapa
   int altura;
   //largura máxima que este mapa pode ter
   int maxLargura;
   //altura máxima que este mapa pode ter
   int maxAltura;
   //a matriz que guarda os caracteres do mapa
   char **matriz;
} Mapa;

/**
  * Inicia um novo labirinto
   * jogadorCol/Linha é a posição do jogador dentro da matriz
 */
Mapa * criarMapa ( int largura, int altura )
{
   Mapa * mapa = NULL;

   //aloca memória para o mapa
   mapa = (Mapa *)malloc(sizeof(Mapa));
   if (!mapa)
   {
      printf("criarMapa::erro ao alocar novo mapa\n");
      exit(1);
   }

   mapa->largura = largura;
   mapa->altura = altura;
   mapa->maxLargura = largura;
   mapa->maxAltura = altura;
   //aloca uma matriz com 'altura' ponteiros;
   mapa->matriz = (char **)malloc(sizeof(char *) * altura);
   //agora aloca a matriz
   for (int i = 0; i < altura; i++)
   {
      //NOTA: coloquei o +1 aqui para dar espaço ao '\0' (caractere nulo)
      mapa->matriz[i] = (char *)malloc(sizeof(char) * (largura + 1));
      if (!mapa->matriz[i])
      {
         printf("mapa->matriz[%d] não foi alocada.\n", i);
         exit(1);
      }

      //agora inicia os elementos da linha com 0
      for (int j = 0; j < largura; j++)
         mapa->matriz[i][j] = 0;
   }

   //agora retorna o mapa
   return mapa;
}

void destruirMapa ( Mapa * mapa )
{
   if (mapa)
   {
      if (mapa->matriz)
      {
         //deleta a memoria da matriz
         int i = 0;
         for (; i < mapa->maxAltura; i++)
         {
            //deleta as linhas
            free(mapa->matriz[i]);
         }
         free(mapa->matriz);
         mapa->matriz = NULL;
      }
      free(mapa);
      mapa = NULL;
   }
}

//retorna 0 se der erro na leitura da matriz do arquivoMatriz
//retorn 1 em caso de conseguir ler o arquivoMatriz
int lerMatriz ( Mapa * mapa, const char * arquivoMatriz )
{
   if (!mapa)
      return 0;
   
   FILE * arquivo = fopen(arquivoMatriz, "r");
   //verifica se abriu o arquivo normalmente (sem erros)
   if (!arquivo)
   {
      //see ntrou aqui é porque teve problemas ao abrir o arquivo
      printf("lerMatriz, deu erro ao ler o arquivo %s\n", arquivoMatriz);
      return 0;
   }

   //se estamos aqui foi porque o arquivo abriu sem problemas
   //agora vamos ler as células da matriz
   //NOTA: lembre-se que, a matriz é no máximo a largura de mapa->largura e 
   //      altura máxima de mapa->altura
   //quantidade de caracteres lidos
   int qtdeLidos = 0;
   int linhas = 0;
   int colunas = 0;
   int caractere = 0;
   for (; caractere != EOF && qtdeLidos < mapa->maxAltura * mapa->maxLargura; )
   {
      caractere = fgetc(arquivo);
      //se não for um caractere visível
      if (isblank(caractere) || isprint(caractere) == 0 || caractere == EOF)
      {
         if (caractere == '\n' && colunas > 0)
         {
            if (colunas >= mapa->maxLargura)
            {
               printf("Erro temos uma linha com maior largura que o mapa");
               break;
            }
            mapa->largura = colunas;
            colunas = 0;

            linhas++;
            //verifica se estamos no máximo de linhas
            if (linhas >= mapa->maxAltura)
               //se sim, quebra o loop
               break;
         }

         //pule o loop
         continue;
      }
      

      colunas++;
      //agora incrementa o contador de caracteres lidos
      qtdeLidos++;
      //agora coloca o caractere na posição na matriz
      //primeiro pega a linha atual
      int linhaAtual = linhas;
      //agora pega a coluna atual
      int colunaAtual = colunas - 1;
      if (linhas != 0) 
         //essa coluna é somente o resto da divisão de qtdeLidos por mapa->largura
         colunaAtual = qtdeLidos % mapa->largura;
      
      //e por fim, bota o caractere no mapa
      mapa->matriz[linhaAtual][colunaAtual] = (char)caractere;
   }
   //por fim, fecha o arquivo
   fclose(arquivo);

   //se caso a gente ler menos linhas, coloca a nova altura
   if (linhas + 1 < mapa->maxAltura)
   {
      mapa->altura = linhas + 1;
      printf("lerMatriz::Leu um tamanho menor de matriz\nAgora o mapa tem tamanho: %dx%d\n", mapa->largura, mapa->altura);
   }

   //retorna 1 se der certo a leitura do mapa
   return 1;
}

typedef struct 
{
   int linhaAtual;
   int colunaAtual;
   int linhaInicial;
   int colunaInicial;
   char caractere;
   //caracteres do mapa que são sólidos, isso é pro player colidir
   char solidos[64];
} Jogador;

Jogador * criarJogador ( int linhaInicial, int colunaInicial, char caractere, const char * solidos )
{
   Jogador * jogador = NULL;

   jogador = (Jogador *)malloc(sizeof(Jogador));
   if (!jogador)
   {
      printf("criarJogador::deu erro ao criar novo jogador\n");
      exit(1);
   }

   jogador->linhaAtual = linhaInicial;
   jogador->colunaAtual = colunaInicial;
   jogador->linhaInicial = linhaInicial;
   jogador->colunaInicial = colunaInicial;
   jogador->caractere = caractere;
   strcpy(jogador->solidos, solidos);

   return jogador;
}

void destruirJogador ( Jogador * jogador )
{
   if (jogador)
   {
      free(jogador);
      jogador = NULL;
   }
}

int ehSolido ( Mapa * mapa, int linha, int coluna, char * solidos )
{
   //por padrão, retornamos 1 pro caso de estar fora dos limites do mapa->matriz
   if (linha < 0 || linha >= mapa->altura)
      return 1;

   if (coluna < 0 || coluna >= mapa->largura)
      return 1;
   
   //coloca o ponteiro no começo da string de sólidos
   char * c = solidos;
   for (; *c != '\0'; c++)
      //se achar o caractere, etnão é sólido
      if (*c == mapa->matriz[linha][coluna])
         return 1;

   //em linha coluna não é sólido
   return 0;
}

//retorna 0 se não pode mover na direcao
//retorna 1 se pode mover o jogador na direacao
int podeMover ( Mapa * mapa, int linhaAtual, int colunaAtual, char direcao, char * solidos )
{
   int ret = 0;

   switch (direcao)
   {
      case 'W':
      case 'w':
         if (linhaAtual - 1 >= 0)
            ret = 1;
         if (ehSolido(mapa, linhaAtual - 1, colunaAtual, solidos))
            ret = 0;
         break;
      
      case 'S':
      case 's':
         if (linhaAtual + 1 < mapa->altura)
            ret = 1;
         if (ehSolido(mapa, linhaAtual + 1, colunaAtual, solidos))
            ret = 0;
         break;
      
      case 'A':
      case 'a':
         if (colunaAtual - 1 >= 0)
            ret = 1;
         if (ehSolido(mapa, linhaAtual, colunaAtual - 1, solidos))
            ret = 0;
         break;
      
      case 'D':
      case 'd':
         if (colunaAtual + 1 < mapa->largura)
            ret = 1;
         if (ehSolido(mapa, linhaAtual, colunaAtual + 1, solidos))
            ret = 0;
         break;
   }

   return ret;
}

void limparEntrada (  )
{
   int c = 0;
   do
   {
      c = fgetc(stdin);
   }   while (c != EOF && c != '\n');
}

//faz mover o jogador
//retorna 1 se conseguir mover
//retorna 0 se não conseguir
int moverJogador ( Jogador * jogador, Mapa * mapa )
{
   char direcao = 0;

   printf("Depois de digitar a direção, aperte enter para mover\n");
   printf("Escolha a direção para mover:\n");
   printf("W ou w move pra cima\n");
   printf("S ou s move pra baixo\n");
   printf("A ou a move pra esquerda\n");
   printf("D ou d move pra direita\n");
   printf("Digite sua escolha: \n");
   direcao = (char)fgetc(stdin);
   limparEntrada();

   //verifica se pode mover o jogador na direcao
   if (podeMover(mapa, jogador->linhaAtual, jogador->colunaAtual, direcao, jogador->solidos))
   {
      //se sim, então, move o jogador na direção que ele pode mover
      switch (direcao)
      {
         //move o jogador pra cima
         case 'W':
         case 'w':
            jogador->linhaAtual--;
            return 1;
         //move o jogador pra baixo
         case 'S':
         case 's':
            jogador->linhaAtual++;
            return 1;
         //move o jogador para esquerda (esquerdopata!)
         case 'A':
         case 'a':
            jogador->colunaAtual--;
            return 1;
         //move o jogador para direita (coxinha!)
         case 'D':
         case 'd':
            jogador->colunaAtual++;
            return 1;
         //se não for uma direção válida, apenas sai do switch
         default:
            break;
      }
   }

   //se retornou 0 é porque não conseguiu mover o jogador
   return 0;
}

void desenharMapa (Mapa * mapa, Jogador * jogador)
{
   for (int i = 0; i < mapa->altura; i++)
   {
      for (int j = 0; j < mapa->largura; j++)
      {
         //verifica se é o caractere do jogador
         if (jogador && jogador->linhaAtual == i && jogador->colunaAtual == j)
         {
            printf("%c", jogador->caractere);
            continue;
         }

         //desenha um caractere da matriz
         printf("%c", mapa->matriz[i][j]);
      }
      //pula uma linha, mas apenas se não ler um '\n' no final de matriz[i]
      if (mapa->matriz[i][mapa->largura - 1] != '\n')
         printf("\n");
   }
}

//apenas uma pequena função auxiliar de limpar a tela
void limparTela (  )
{
   for (int i = 0; i < 200; i++)
   {
      printf("\n");
   }
}

//caso não saiba o que significa esses dois parâmetros:
//argc = numero de parametros passados depois do nome do executável: ex.: ./labirintoC parametro0
//argv = os parametros em forma de strings de char, 
//       tipo, "./labirintoC" será o argv[0], "parametro0" será o argv[1]
int main (int argc, char **argv)
{
   //cria um mapa de 100x100 caracteres
   Mapa * mapa = criarMapa(100, 100);
   //agora inicia a matriz do labirinto
   if (lerMatriz(mapa, "matrizLabirinto.txt") == 0)
   {
      printf("Erro ao ler arquivo de matriz\n");
      exit(1);
   }

   //cria um novo jogador na posição linha=0, coluna=0
   //era para apenas colocar sozinho o jogador na matriz
   //NOTA: rever código antes de postar no blog
   Jogador * jogador = criarJogador(0,0,'@',"#");

   //loop do jogo
   do
   {
      //primeiro limpa a tela
      limparTela();
      //depois desenha o mapa e o jogador juntos
      desenharMapa(mapa, jogador);
      //agora pergunta pra onde movber o jogador
      moverJogador(jogador, mapa);
      //veirifica se é o final do jogo
   } while (mapa->matriz[jogador->linhaAtual][jogador->colunaAtual] != 'E');

   //caso saida do loop
   //destrua o jogador (desaloque mem[oria dele])
   destruirJogador(jogador);
   //destrua o mapa (desaloca memoria da matriz)
   destruirMapa(mapa);

   return 0;
}

Scripts recomendados

Usando dois contadores em uma estrutura de repetição simples

Exemplo de gabaritos de função

Ordenando valores

[C] Manipulação de vetores/ponteiros

menu


  

Comentários
[1] Comentário enviado por maurixnovatrento em 14/05/2021 - 10:42h


Vou testar. Deve estar bem completo.

___________________________________________________________
[code]Conhecimento não se Leva para o Túmulo.
https://github.com/MauricioFerrari-NovaTrento [/code]

[2] Comentário enviado por Ta_PegandoFogo em 10/09/2021 - 16:26h

Parabéns!!!
@#.....####.....
....#.....#.....
...#...##.#.##.#
..#..#......#...
.####.###..##.#.
.#..##.#......#.
.#.#.#.#.#.#..E.
....#..#.#..#.../


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts