Untitled
unknown
plain_text
15 days ago
11 kB
7
Indexable
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #include <ctype.h> #define TMAX_MATRIZ 26 typedef struct estado { char tabuleiro[TMAX_MATRIZ][TMAX_MATRIZ]; int linhas, colunas; bool carregouTabuleiro; bool looping; struct estado *ultimoEstado; // ultimoEstado aponta pra um estado(que é o estado imediatamente anterior) } Estado; // Define um tipo de ponteiro chamado comando que aponta para uma função que retorna bool e recebe aqueles argumentos // Comando já é o próprio ponteiro typedef bool (*Comando)(char cmd, char *arg, Estado *e); void guardarEstado(Estado *atual) { Estado *estadoGuardar = malloc(sizeof(Estado)); // aloca a memoria pro estado que é pra guardar if (estadoGuardar != NULL) { memcpy(estadoGuardar, atual, sizeof(Estado)); // copia o estado atual para o o estadoGuardar atual->ultimoEstado = estadoGuardar; // atualiza o ponteiro do estado atual para o estado que foi guardado } } void mostrarTabuleiro(Estado *e) { printf("\n"); for (int i = 0; i < e->linhas; i++) { for (int j = 0; j < e->colunas; j++) { printf("%c ", e->tabuleiro[i][j]); } printf("\n"); } printf("\n"); } bool cmdLer(char cmd, char *arg, Estado *e) { if (cmd != 'l' || arg == NULL) return false; // ficheiro é ponteiro para o tipo file (fopen retorna endereco) FILE *ficheiro = fopen(arg, "r"); if (ficheiro == NULL) { printf("Erro ao abrir %s\n", arg); return true; // o comando foi reconhecido apesar de ter havido erro } // armazena no estado -> linhas if (fscanf(ficheiro, "%d %d", &(e->linhas), &(e->colunas)) != 2) { fclose(ficheiro); printf("Formato inválido no ficheiro\n"); return true; } if (e->linhas <= 0 || e->colunas <= 0 || e->linhas > TMAX_MATRIZ || e->colunas > TMAX_MATRIZ) { printf("As dimensões do tabuleiro são inválidas\n"); fclose(ficheiro); return true; } while (fgetc(ficheiro) != '\n'); // retira os espaços e passa o "cursor" para depois do \n char linha[TMAX_MATRIZ + 2]; // adiciona o \n e o \0 bool linhaValida = true; for (int i = 0; i < e->linhas && linhaValida; i++) { if (fgets(linha, sizeof(linha), ficheiro) == NULL) { printf("Erro ao ler a linha %d\n", i+1); linhaValida = false; } // remove o '\n' no final (strcspn retorna o indice do \n) p possibilitar futura comparacao linha[strcspn(linha, "\n")] = '\0'; for (int j = 0; j < e->colunas && linhaValida; j++) { if (linha[j] == '\0') { printf("Aviso linha %d menor que o esperado\n", i); // se introduziu uma dimensao e depois a linha era dif linhaValida = false; } e->tabuleiro[i][j] = linha[j]; } } fclose(ficheiro); if (linhaValida == false) return true; // se a linha n era valida n carrega o tabuleiro mas identifica o comando e->carregouTabuleiro = true; printf("\nTabuleiro inicial %dx%d carregado:\n", e->linhas, e->colunas); mostrarTabuleiro(e); return true; } bool cmdGravar(char cmd, char *arg, Estado *e) { if (cmd != 'g' || arg == NULL) return false; // ficheiro é ponteiro para o tipo file (fopen retorna endereco) FILE *ficheiro = fopen(arg, "w"); fprintf(ficheiro, "%d %d\n", e->linhas, e->colunas); for (int i = 0; i < e->linhas; i++) { for (int j = 0; j < e->colunas; j++) { fprintf(ficheiro, "%c", e->tabuleiro[i][j]); } fprintf(ficheiro, "\n"); // a cada linha que escrever escreve o \n } fclose(ficheiro); printf("Tabuleiro gravado em %s\n", arg); return true; } bool cmdSair(char cmd, char *arg, Estado *e) { if (cmd == 's' && arg == NULL) { e->looping = false; return true; // comando foi reconhecido } return false; // comando não foi reconhecido } bool cmdUndo(char cmd, char *arg, Estado *e) { if (cmd == 'd' && arg == NULL) { if (e->ultimoEstado == NULL) { printf("Não há estados anteriores para desfazer.\n"); return true; // comando foi reconhecido apesar de n fzr nd } Estado *estadoAnterior = e->ultimoEstado; // pega o estado anterior memcpy(e, estadoAnterior, sizeof(Estado)); // restaura o estado anterior e->ultimoEstado = estadoAnterior->ultimoEstado; // digo que o estado anterior passa a ser o anterior do anterior free(estadoAnterior); // libera a memória do estado anterior mostrarTabuleiro(e); return true; } return false; } bool cmdPintar(char cmd, char *arg, Estado *e) { if (cmd != 'b' || e->carregouTabuleiro == false) return false; int x; char y; if (sscanf(arg, "%c%d", &y, &x) != 2) return false; int coluna = y - 'a'; // 'a' corresponde a 0, 'b' a 1 etc if (x >= 0 && x < e->linhas && coluna >= 0 && coluna < e->colunas) { guardarEstado(e); // guarda o estado atual (antes de fazer a alteração) e->tabuleiro[x][coluna] = toupper(e->tabuleiro[x][coluna]); mostrarTabuleiro(e); return true; } return false; } bool cmdRiscar(char cmd, char *arg, Estado *e) { if (cmd != 'r' || e->carregouTabuleiro == false) return false; int x; char y; if (sscanf(arg, "%c%d", &y, &x) != 2) return false; int coluna = y - 'a'; if (x >= 0 && x < e->linhas && coluna >= 0 && coluna < e->colunas) { guardarEstado(e); // guarda o estado atual (antes de fazer a alteração) e->tabuleiro[x][coluna] = '#'; mostrarTabuleiro(e); return true; } return false; } bool cmdVerificarRestricoes(char cmd, char *arg, Estado *e) { if (cmd != 'v' || arg != NULL || !e->carregouTabuleiro) return false; bool violacoesEncontradas = false; // 1. Verificar letras brancas repetidas na mesma linha/coluna for (int i = 0; i < e->linhas; i++) { for (int j = 0; j < e->colunas; j++) { char celula = e->tabuleiro[i][j]; // Verificar apenas células brancas (letras maiúsculas) if (isupper(celula)) { // Verificar mesma linha for (int k = 0; k < e->colunas; k++) { if (k != j && e->tabuleiro[i][k] == celula) { printf("Violação: Letra '%c' repetida na linha %d (colunas %c e %c)\n", celula, i+1, 'a'+j, 'a'+k); violacoesEncontradas = true; } } // Verificar mesma coluna for (int k = 0; k < e->linhas; k++) { if (k != i && e->tabuleiro[k][j] == celula) { printf("Violação: Letra '%c' repetida na coluna %c (linhas %d e %d)\n", celula, 'a'+j, i+1, k+1); violacoesEncontradas = true; } } } } } // 2. Verificar células riscadas vizinhas ortogonalmente for (int i = 0; i < e->linhas; i++) { for (int j = 0; j < e->colunas; j++) { if (e->tabuleiro[i][j] == '#') { // Verificar vizinhança ortogonal (cima, baixo, esquerda, direita) if (i > 0 && e->tabuleiro[i-1][j] == '#') { // Cima printf("Violação: Células riscadas vizinhas em (%c%d, %c%d)\n", 'a'+j, i+1, 'a'+j, i); violacoesEncontradas = true; } if (i < e->linhas-1 && e->tabuleiro[i+1][j] == '#') { // Baixo printf("Violação: Células riscadas vizinhas em (%c%d, %c%d)\n", 'a'+j, i+1, 'a'+j, i+2); violacoesEncontradas = true; } if (j > 0 && e->tabuleiro[i][j-1] == '#') { // Esquerda printf("Violação: Células riscadas vizinhas em (%c%d, %c%d)\n", 'a'+j, i+1, 'a'+j-1, i+1); violacoesEncontradas = true; } if (j < e->colunas-1 && e->tabuleiro[i][j+1] == '#') { // Direita printf("Violação: Células riscadas vizinhas em (%c%d, %c%d)\n", 'a'+j, i+1, 'a'+j+1, i+1); violacoesEncontradas = true; } } } } if (!violacoesEncontradas) { printf("Nenhuma violação encontrada. Tabuleiro válido!\n"); } return true; } #ifndef TESTING int main() { Estado estado = {0}; // inicializa todos os campos com zero estado.looping = true; // array de comandos (ponteiros para funções) Comando comandos[] = {cmdLer,cmdGravar,cmdSair,cmdUndo,cmdPintar,cmdRiscar,cmdVerificarRestricoes,NULL}; char input[100]; printf("Escreva l [arquivo] para carregar o tabuleiro:\n"); while (estado.looping) { // le o que foi introduzido (stdin) e armazena em input (para quando chega no \n ou ultrapassa o sizeof) e retorna o ponteiro if (fgets(input, sizeof(input), stdin) == NULL) estado.looping = false; // Quando escrevemos b a1 e damos enter o ultimo caractere é o \n, precisamos remove-lo. int length = strlen(input); if (length > 0 && input[length-1] == '\n') { // se for \n substitui. input[length-1] = '\0'; } char cmd = '\0'; char arg[100] = {0}; // vai ler da string input (%99s para usar no máx 99 caracteres (precisa de espaço pro \0 no fim)) int argsLido = sscanf(input, "%c %99s", &cmd, arg); bool temArgumento = (cmd == 'l' || cmd == 'g' || cmd == 'b' || cmd == 'r'); // ver se leu o comando if (argsLido < 1) { printf("Comando inválido!\n"); } // ver se era necessário argumento e não havia else if (temArgumento && argsLido < 2) { printf("Este comando requer um argumento!\n"); } else { bool reconhecido = false; // é uma flag (reconhecido só vira true quando um comando é reconhecido (é bem passado)) // enquanto não chegar ao fim da lista de comandos e não houver nenhum que foi reconhecido procura o comando for (int i = 0; comandos[i] != NULL && !reconhecido; i++) { if (argsLido > 1) { reconhecido = comandos[i](cmd, arg, &estado); } else { // se não tiver argumentos passa o ponteiro nulo reconhecido = comandos[i](cmd, NULL, &estado); } } if (!reconhecido) { // se não houve nenhum reconhecido então é inválido printf("Comando inválido.\n"); } } } printf("Jogo encerrado.\n"); return 0; } #endif
Editor is loading...
Leave a Comment