Jogo do Labirinto no Terminal
Publicado por Samuel Leonardo (última atualização em 14/05/2021)
[ Hits: 8.432 ]
Homepage: https://nerdki.blogspot.com.br/
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'.
/**
* @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;
}
Simulador de cronometro com 2 digitos - otimizado
Controlando o teclado enquanto mensagens são exibidas no console
IA Turbina o Desktop Linux enquanto distros renovam forças
Como extrair chaves TOTP 2FA a partir de QRCODE (Google Authenticator)
Linux em 2025: Segurança prática para o usuário
Desktop Linux em alta: novos apps, distros e privacidade marcam o sábado
IA chega ao desktop e impulsiona produtividade no mundo Linux
Atualizando o Fedora 42 para 43
Como saber se o seu e-mail já teve a senha vazada?
Como descobrir se a sua senha já foi vazada na internet?
Programa fora de escala na tela do pc (38)
\Boot sem espaço em disco (Fedora KDE Plasma 42) (1)
Mint Xfce não mantém a conexão no wi-fi (2)









