Home > front end >  How to undo a stack when the struct contains a char ** variable?
How to undo a stack when the struct contains a char ** variable?

Time:02-25

This code below is something like a candy crush game, where you pop similar letters in a cluster, then they'll disappear and you score. On main, I tried to play it one step ahead and then undo it, and it works since the score managed to undo (from 0 to some score then back to 0 again). However, I just can't figure out why the game board isn't updated?

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAX_ROWS 40
#define MAX_COLS 40

#define None ' '
#define A  'a'
#define B 'b'
#define C 'c'
#define D 'd'

typedef struct {
    char **board;
    int score;
} Instance;

typedef struct {
    int rs;
    int cs;
    Instance stack[10];
    int top;
} Game;

// creates a matrix (dynamically allocation) and populates it with random letters (a, b ,c or d)
extern Game *create(int nrows, int ncols) {
    if (nrows > MAX_ROWS || ncols > MAX_COLS) {
        return NULL;
    }
    Game *b;
    b->top = 0;
    b->rs = nrows;
    b->cs = ncols;
    b->stack[b->top].board = malloc(sizeof(int *) * nrows);
    for (int row = 0; row < nrows; row  ) {
        b->stack[b->top].board[row] = malloc(sizeof(int) * ncols);
    }
    srand(time(0));
    for (int row = 0; row < nrows; row  ) {
        for (int column = 0; column < ncols; column  ) {
            int random = rand() % 4;
            if (random == 0) {
                b->stack[b->top].board[row][column] = A;
            } else if (random == 1) {
                b->stack[b->top].board[row][column] = B;
            } else if (random == 2) {
                b->stack[b->top].board[row][column] = C;
            } else {
                b->stack[b->top].board[row][column] = D;
            }
        }
    }
    return b;
}

// Display the current matrix
extern void display(Game *b) {
    /** Prints top border **/
    printf("    -");
    for (int top = 0; top < b->cs; top  ) {
        printf("--");
    }
    printf(" \n");
    /** Prints the board **/
    for (int row = 0; row < b->rs; row  ) {
        if (row < 10) {
            printf("0%d | ", row);
        } else {
            printf("%d | ", row);
        }
        for (int column = 0; column < b->cs; column  ) {
            printf("%c ", b->stack[b->top].board[row][column]);
        }
        printf("|\n");
    }
    /** Prints bottom border **/
    printf("    -");
    for (int bot = 0; bot < b->cs; bot  ) {
        printf("--");
    }
    printf(" \n");
    /** Prints vertical column indices **/
    printf("     ");
    for (int tens = 0; tens < b->cs; tens  ) {
        printf("%d ", tens/10);
    }
    printf("\n");
    printf("     ");
    int count = 0;
    for (int ones = 0; ones < b->cs; ones  ) {
        if (count > 9) {
            count = 0;
        }
        printf("%d ", count);
        count  ;
    }
}

// Helper to select()
int recursive_helper(Game *b, int r, int c) {
    int n = 0;
    char colour = b->stack[b->top].board[r][c];
    n  ;
    b->stack[b->top].board[r][c] = None; // Replace it as None before the recursions to prevent it being recounted
    if (r 1 < b->rs && b->stack[b->top].board[r 1][c] == colour) { // r 1 equals to or greater than b->rs is out of bounds
        n  = recursive_helper(b, r 1, c);
    }
    if (r-1 >= 0 && b->stack[b->top].board[r-1][c] == colour) { // r-1 equals to or greater than 0 is out of bounds
        n  = recursive_helper(b, r-1, c);
    }
    if (c 1 < b->cs && b->stack[b->top].board[r][c 1] == colour) { // c 1 equals to or greater than b->cs is out of bounds
        n  = recursive_helper(b, r, c 1);
    }
    if (c-1 >= 0 && b->stack[b->top].board[r][c-1] == colour) { // c-1 equals to or greater than 0 is out of bounds
        n  = recursive_helper(b, r, c-1);
    }
    return n;
}

// select the letter on the game board
extern int select(Game *b, int r, int c) {
    b->stack[b->top 1] = b->stack[b->top];
    b->top  ;
    char colour = b->stack[b->top].board[r][c];
    int n = recursive_helper(b, r, c);
    // If the cluster contains only the selected balloon itself,
    // replace it back to its original form instead of popping it to None,
    // then return 0 since no balloons are popped.
    if (n == 1) {
        b->stack[b->top].board[r][c] = colour;
        return 0;
    }
    b->stack[b->top].score  = n*(n-1);
    return n;
}

extern int bp_score(Game *b) {
    return b->stack[b->top].score;
}

int main() {
    Game *b = create(5, 10);

    display(b);
    printf("\n");
    printf("%d", bp_score(b));
    printf("\n");

    select(b, 2, 2);
    display(b);
    printf("\n");
    printf("%d", bp_score(b));
    printf("\n");

    b->top--;
    display(b);
    printf("\n");
    printf("%d", bp_score(b));
    printf("\n");
}

CodePudding user response:

As pointed in the comments, your create function doesn't instantiate a Game struct, you need b = malloc(sizeof(Game));
Another error is that your mallocs use sizeof(int*) and sizeof(int) instead of sizeof(char*) and sizeof(char).

Other than that, your problem comes from the fact that b->stack[b->top 1] = b->stack[b->top]; copies a structure, but the board is a pointer and points to the same object! You only have one char** pointer and a single board in memory.
Thus, when you do b->top-- while you do access another struct, it still points to the same fully updated board.
You need to create a function Instance CopyInstance(Instance src) that creates a new board in the new struct and then copies each cell from the source board in the new one. That way each Instance will point to a different board!

  • Related