Jogo do Labirinto no Terminal
Publicado por Samuel Leonardo (última atualização em 14/05/2021)
[ Hits: 7.671 ]
Homepage: localhost
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; }
Controlando o teclado enquanto mensagens são exibidas no console
Função switch q armazena sequencias
Enviar mensagem ao usuário trabalhando com as opções do php.ini
Meu Fork do Plugin de Integração do CVS para o KDevelop
Compartilhando a tela do Computador no Celular via Deskreen
Como Configurar um Túnel SSH Reverso para Acessar Sua Máquina Local a Partir de uma Máquina Remota
Configuração para desligamento automatizado de Computadores em um Ambiente Comercial
Compartilhamento de Rede com samba em modo Público/Anônimo de forma simples, rápido e fácil
Cups: Mapear/listar todas as impressoras de outro Servidor CUPS de forma rápida e fácil
Criando uma VPC na AWS via CLI
Tem como instalar o gerenciador AMD Adrenalin no Ubuntu 24.04? (7)