Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Função explodepilula não está atribuindo VAZIO ' . ' à posição da matriz. Ao executar o código e explodir a bomba o programa encerra.

Olá, todo o código estava funcionando normalmente até eu implementar a função 'explodepilula', após algumas horas colocando vários printf, consegui enxugar o problema em apenas uma única linha de código, mas não consegui resolver por conta própria. A linha de código em questão é: m.matriz[heroi.x][heroi.y+i] = ESPACO_VAZIO; da função explodepilula, bom, o único jeito que encontrei do jogo não encerrar foi deixando essa linha comentada.

Arquivo fogefoge.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "fogefoge.h"
#include "mapa.h"

MAPA m;
POSICAO heroi;
int tempilula = 0;

int praondeofantasmavai(int xatual, int yatual, int* xdestino, int* ydestino) {
    int opcoes[4][2] = {
        {xatual + 1, yatual},
        {xatual - 1, yatual},
        {xatual, yatual + 1},
        {xatual, yatual - 1}
    };

    srand(time(0));

    for(int i = 0; i < 10; i++){
        int posicao = rand() % 4;

        if(podeandar(&m, FANTASMA, opcoes[posicao][0], opcoes[posicao][1])) {
            *xdestino = opcoes[posicao][0];
            *ydestino = opcoes[posicao][1];
            return 1;
        }
    }
    return 0;
}

void fantasmas() {
    MAPA copia;

    copiamapa(&copia, &m);

    for(int i = 0; i < m.linhas; i++) {
        for(int j = 0; j < m.colunas; j++) {
            if(copia.matriz[i][j] == FANTASMA) {

                int xdestino;
                int ydestino;

                int encontrou = praondeofantasmavai(i, j, &xdestino, &ydestino);

                if(encontrou) {
                    andanomapa(&m, i, j, xdestino, ydestino);
                }
            }
        }
    }

    liberamapa(&copia);
}

int acabou(){
    POSICAO pos;
    int encontrouoheroi = encontramapa(&m, &pos, HEROI);

    return !encontrouoheroi;
}

int ehdirecao(char direcao) {
    return direcao == ESQUERDA ||
        direcao == CIMA ||
        direcao == BAIXO ||
        direcao == DIREITA;
}

void move(char direcao){

    int proximox = heroi.x;
    int proximoy = heroi.y;

    // validação da entrada o usuário, "reseta" toda vez que o usuário
    // digital alguma tecla diferente das direcionais.
    if (!ehdirecao(direcao))    {
        return;
    }

    switch(direcao){
        case ESQUERDA:
            proximoy--;
            break;
        case BAIXO:
            proximox++;
            break;
        case DIREITA:
            proximoy++;
            break;
        case CIMA:
            proximox--;
            break;
    }

    if(!podeandar(&m, HEROI, proximox, proximoy))
        return;

    if(ehpersonagem(&m, PILULA, proximox, proximoy)) {
        tempilula = 1;
    }

    andanomapa(&m, heroi.x, heroi.y, proximox, proximoy);
    heroi.x = proximox;
    heroi.y = proximoy;
}

void explodepilula(){
    for(int i = 0; i <= 3; i++) {
        if(ehvalida(&m, heroi.x, heroi.y+i)) {
            if(ehparede(&m, heroi.x, heroi.y+i)){
                break;
            }

            //m.matriz[heroi.x][heroi.y+i] = ESPACO_VAZIO;
        }
    }
}

void loop() {
    do{
        printf("Tem pilula: %s\n", (tempilula ? "Sim" : "Não"));        
        imprimemapa(&m);
        char comando;        
        scanf(" %c", &comando);        
        move(comando);        
        if(comando == BOMBA)
            explodepilula();
        fantasmas();
    } while(!acabou());
}

int main() {
    lemapa(&m);

    encontramapa(&m, &heroi, HEROI);

    loop();

    // Limpando memória alocada dinâmicamente.
    liberamapa(&m);
}

Arquivo fogefoge.h:

#define CIMA 'w'
#define ESQUERDA 'a'
#define DIREITA 'd'
#define BAIXO 's'
#define BOMBA 'b'

void explodepilula();
void fantasmas();
void loop();
void move(char direcao);

int acabou();
int ehdirecao(char direcao);
int praondeofantasmavai(int xatual, int yatual, int* xdestino, int* ydestino);
2 respostas

Arquivo mapa.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mapa.h"

void copiamapa(MAPA* destino, MAPA* origem) {

    destino->linhas = origem->linhas;
    destino->colunas = origem->colunas;

    alocamapa(destino);

    for(int i = 0; i < origem->linhas; i++) {
        strcpy(destino->matriz[i], origem->matriz[i]);
    }
}

void andanomapa(MAPA* m, int xorigem, int yorigem, int xdestino, int ydestino) {

    char personagem = m->matriz[xorigem][yorigem];
    m->matriz[xdestino][ydestino] = personagem;
    m->matriz[xorigem][yorigem] = ESPACO_VAZIO;
}

int ehparede(MAPA* m, int x, int y) {
    return (m->matriz[x][y] == PAREDE_VERTICAL ||
        m->matriz[x][y] == PAREDE_HORIZONTAL);
}

int ehpersonagem(MAPA* m, char personagem, int x, int y) {
    return m->matriz[x][y] == personagem;
}

int podeandar(MAPA* m, char personagem, int x, int y){
    return
        ehvalida(m, x, y) &&
        !ehparede(m, x, y) &&
        !ehpersonagem(m, personagem, x, y)
    ;
}

int ehvalida(MAPA* m, int x, int y) {

    if (x >= m->linhas)
        return 0;

    if (y >= m->colunas)
        return 0;

    return 1;
}

int ehvazia(MAPA* m, int x, int y) {
    if(m->matriz[x][y] != ESPACO_VAZIO)
        return 0;
    return 1;
}

int encontramapa(MAPA* m, POSICAO* p, char c) {
    // acha a posição do heroi
    for(int i = 0; i < m->linhas; i++){
        for(int j = 0; j < m->colunas; j++){
            if(m->matriz[i][j] == c){
                p->x = i;
                p->y = j;
                return 1;
            }
        }
    }
    return 0;
}

void liberamapa(MAPA* m) {
    for(int i = 0; i < m->linhas; i++) {
        free(m->matriz[i]);
    }
    free(m->matriz);
}

void alocamapa(MAPA* m){
    m->matriz = malloc(sizeof(char*) * m->linhas);
    for(int i = 0; i < m->linhas; i++){
        m->matriz[i] = malloc(sizeof(char) * (m->colunas + 1));
    }
}

void imprimemapa(MAPA* m) {
    for (int i = 0; i < m->linhas; i++)
        {
            printf("%s\n", m->matriz[i]);
        }
}

void lemapa(MAPA* m){
    FILE* file;

    file = fopen("mapa.txt", "r");
    if(file == 0) {
        printf("Erro na leitura do mapa.\n");
        exit(1);
    }

    // Lê a quantidade de linhas e colunas no mapa
    fscanf(file, "%d %d", &(m->linhas), &(m->colunas));

    /* Alocação dinâmica de memória 
     * a função malloc() server para alocar
     * memória dinâmicamente. A função free()
     * libera a memória alocada pela função
     * malloc()
     */

    alocamapa(m);

    /* FIM */

    for (int i = 0; i < m->linhas; i++)
    {
        fscanf(file, "%s", m->matriz[i]);
    }

    fclose(file);
}

Arquivo mapa.h:

#define ESPACO_VAZIO '.'
#define FANTASMA 'F'
#define HEROI '@'
#define PAREDE_VERTICAL '|'
#define PAREDE_HORIZONTAL '-'
#define PILULA 'P'

struct mapa {

    // matriz de 5 x 10
    char** matriz;
    int linhas;
    int colunas;

};

struct posicao {
    // guarda a posição do heroi dentro da matriz, mapa.
    int x;
    int y;
};

typedef struct mapa MAPA;
typedef struct posicao POSICAO;

void alocamapa(MAPA* m);
void andanomapa(MAPA* m, int xorigem, int yorigem, int xdestino, int ydestino);
void copiamapa(MAPA* origem, MAPA* destino);
void imprimemapa(MAPA* m);
void lemapa(MAPA* m);
void liberamapa(MAPA* m);

int ehparede(MAPA* m, int x, int y);
int ehpersonagem(MAPA* m, char personagem, int x, int y);
int ehvalida(MAPA* m, int x, int y);
int ehvazia(MAPA* m, int x, int y);
int encontramapa(MAPA* m, POSICAO* p, char c);
int podeandar(MAPA* m, char personagem, int x, int y);

Arquivo mapa.txt:

5 10
----------
|.F.|..-.|
|..-|@P..|
|..F..-..|
----------

Criei um segundo post, porque o sistema do fórum limitou a quantidade de caracteres em 5000.

solução!

Bom, não sei se a pandemia alterou alguma coisa aqui no fórum, parece estar vazio, mas após um longo período tentando achar uma solução para o problema mencionado aqui consegui contornar por hora, com "gambiarra", posteriormente irei melhorar o código.

O jogo estava encerrando porque quando estourava a pílula, a função explodepilula(), no for, estava contando 4 posições, antiga: for(int i = 0; i <= 3; ++i), acontece que quando o comando para explodir era usado, ele contava as 4 posições incluindo a posição do heroi, ao mesmo tempo que matava os fantasmas... acabava se 'suicidando'. consegui contornar modificando a definição do for para: for(int i = 0; i < 3; ++i) e também substituindo a linha antiga: m.matriz[heroi.x][(heroi.y + i] = ESPACO_VAZIO;, por: m.matriz[heroi.x][(heroi.y + 1) + i] = ESPACO_VAZIO;, dessa forma, a explosão começa da posição a frente do heroi e tem apenas 3 interações. Não gostei do aspecto que acabei deixando o código, pretendo melhorar, mas no momento está funcionando e assim posso finalmente continuar o curso. Uma semana para achar um error 'bobo' rsrs...

void explodepilula(){
    int rangebomba = 0;
    for(int i = 0; i < 3; ++i) {
        if(ehvalida(&m, heroi.x, heroi.y+i)) {
            if(ehparede(&m, heroi.x, heroi.y+i)){
                break;
            }
            m.matriz[heroi.x][(heroi.y+1)+i] = ESPACO_VAZIO;
        }
    }
}