Jogo do Labirinto no Terminal
Publicado por Samuel Leonardo (última atualização em 14/05/2021)
[ Hits: 8.160 ]
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; }
Cálculo da circunferência de um círculo
Utilizando arrays, funções e arquivos de texto
Fibonacci - Modo muito simples
Aprenda a Gerenciar Permissões de Arquivos no Linux
Como transformar um áudio em vídeo com efeito de forma de onda (wave form)
Como aprovar Pull Requests em seu repositório Github via linha de comando
Visualizar arquivos em formato markdown (ex.: README.md) pelo terminal
Dando - teoricamente - um gás no Gnome-Shell do Arch Linux
Como instalar o Google Cloud CLI no Ubuntu/Debian
Mantenha seu Sistema Leve e Rápido com a Limpeza do APT!
Procurando vídeos de YouTube pelo terminal e assistindo via mpv (2025)
Alguém já testou plataformas de investimento voltadas para a América d... (0)
Zorin OS - Virtual Box não consigo abrir maquinas virtuais (6)
Iinstalar o Scanner Kodak i940 no Linux Mint 19/20? (3)