Jogo do Labirinto no Terminal
Publicado por Samuel Leonardo (última atualização em 14/05/2021)
[ Hits: 8.518 ]
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;
}
Modo Simples de Baixar e Usar o bash-completion
Monitorando o Preço do Bitcoin ou sua Cripto Favorita em Tempo Real com um Widget Flutuante
Adicionar botão "mostrar área de trabalho" no Zorin OS
Como montar um servidor de backup no linux
Trazendo de volta o Serviços em Segundo Plano no Plasma6
É normal não gostar de KDE? (21)
Servidor para arquivos e banco de dados (4)
780 mil usuários do Janelas baIxaram Linux em um mês (4)
Atualizei meu ubuntu e desliguei e ele não inicia corretamente (12)









