Я пытаюсь определить 2D-массив в структуре. Используя массив, он работает хорошо:

#include <stdio.h>
#define sizeY 10
#define sizeX 10
#define LIVE 1
#define DEAD 0

typedef int TableType[sizeY][sizeX];

void printTable(TableType grid) {
    int height, width;

    for (height = 0; height < sizeY; height++) {
        for (width = 0; width < sizeX; width++) {
            if (grid[height][width] == LIVE) {
                printf("X");
            } else {
                printf("-");
            }
        }
        printf("\n");
    }
    printf("\n");
}

void clearTable(TableType grid) {
    int height, width;
    for (height = 0; height < sizeY; height++) {
        for (width = 0; width < sizeX; width++) {
            grid[height][width] = DEAD;
        }
    }
}

int main(void) {
    TableType table;

    clearTable(table);
    printTable(table);

    return 0;
}

Но используя структуру, я получил ошибку, используя код ниже:

||=== Build file: "no target" in "no project" (compiler: unknown) ===|
||In function 'printTable':|
|17|error: used struct type value where scalar is required|
|17|error: expected ')' before '{' token|
In function 'clearTable':|
|32|error: expected ';' before '{' token|
||=== Build failed: 3 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

Это еще одна версия кода:

#include <stdio.h>
#define sizeY 10
#define sizeX 10
#define LIVE 1
#define DEAD 0

typedef struct {
    int y;
    int x;
} TableType;

void printTable(TableType grid) {
    int height, width;

    for (height = 0; height < sizeY; height++) {
        for (width = 0; width < sizeX; width++) {
            if (grid{height, width} == LIVE) {
                printf("X");
            } else {
                printf("-");
            }
        }
        printf("\n");
    }
    printf("\n");
}

void clearTable(TableType grid) {
    int height, width;
    for (height = 0; height < sizeY; height++) {
        for (width = 0; width < sizeX; width++) {
            grid{height, width} = DEAD;
        }
    }
}

int main(void) {
    TableType table;

    clearTable(table);
    printTable(table);

    return 0;
}

Я полагаю, что я не правильно использую свою структуру и буду очень признателен за любую помощь в достижении этого, большое спасибо!


РЕДАКТИРОВАТЬ :

Я обновляю свой основной запрос, предоставляя более подробную информацию о моем курсе и о том, чего я пытаюсь достичь в конце. Окончательный результат - игровой проект под названием «Game Of Life».

Я обновил код ниже с комментариями, описывающими, что такое Game Of Life, подробными ключевыми моментами с большим количеством функций и большим количеством прокомментированного кода, который показывает, чего не хватает. Мне жаль, что меня снова блокируют, но у меня возникают трудности с управлением использованием ячеек, поскольку новые требования (например, ячейка также должна быть структурой).

Вот обновленный код:

/*
 * The Game of Life
 * http://en.wikipedia.org/wiki/Conway's_Game_of_Life
 *
 * Key requirements :
 * - Limit the size of the world to 10x10 cells
 * - The world (grid) must be a struct composed by cells
 * - A cell must be a struct
 * - Each cell is in one of two possible states : Live or Dead
 * - Any live cell with fewer than two live neighbours dies, as if caused by under-population
 * - Any live cell with two or three live neighbours lives on to the next generation
 * - Any live cell with more than three live neighbours dies, as if by overcrowding
 * - Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction
 * - Between each generation, ask if it's necessary to restart the next generation or to leave the game
 * - Having dedicated function displayWorld() to display a representation of this world
 * - Having dedicated function newGeneration() to generate next step of the world
 * - In the function above, implement conditions based on cell's neighbors to define if each cell is alive or dead
 * - Alive cells are represented by a "+"
 * - Dead cells are represented by a "-"
 * - New borned cells are represented by a "0"
 */

#include <stdio.h>
#define sizeY 10
#define sizeX 10
#define LIVE 1
#define DEAD 0

// A world must be a struct
typedef struct {
  // @ToDo Missing: a cell must be a struct too
  // Means we have a world struct that includes a cell struct
  int y;
  int x;
  unsigned char status;
} World;

void displayWorld(World grid[], int table_size) {
  int i;
  for (i = 0; i < table_size; i++) {
    //printf ("P(%d,%d) = ", grid[i].x, grzid[i].y);

    if (i % sizeY == 0 && i != 0) {
      printf("\n");
    }

    // Missing a third state here;
    // When a cell become LIVE for the first time, it must be shown with a "0" char
    if (grid[i].status == LIVE) {
      printf("+");
    } else {
      printf("-");
    }
  }

  printf("\n");
}

void clearTable(World grid[], int table_size) {
  int i = 0;
  int height, width;
  for (height = 0; height < sizeY; height++) {
    for (width = 0; width < sizeX; width++) {
      grid[i].y = height;
      grid[i].x = width;
      grid[i].status = DEAD;
      //printf ("Setting P(%d,%d) to DEAD\n", width, height);
      i++;
    }
  }
}

int getNeighborValue(World grid[], int row, int col) {
    // if (row < 0 || row >= HEIGHT
    //  || col < 0 || col >= WIDTH
    //  || table[row][col] != LIVE )
    // {
    //  return 0;
    // } else {
    //  return 1;
    // }
}

// We count here how many neighbors a cell have
int getNeighborCount(World grid[], int row, int col) {
  int neighbor = 0;

  // This is not finished and will not work that way
  // neighbor += getNeighborValue(grid, row - 1, col - 1);
  // neighbor += getNeighborValue(grid, row - 1, col);
  // neighbor += getNeighborValue(grid, row - 1, col + 1);
  // neighbor += getNeighborValue(grid, row, col - 1);
  // neighbor += getNeighborValue(grid, row, col + 1);
  // neighbor += getNeighborValue(grid, row + 1, col - 1);
  // neighbor += getNeighborValue(grid, row + 1, col);
  // neighbor += getNeighborValue(grid, row + 1, col + 1);

  return neighbor;
}

// Here we define which cells become LIVE OR DEAD on next generation;
// based on cell's neighbors function above
void newGeneration(World gridA[], int table_size) {
  World gridB;
    int neighbor, height, width;

    // for (height = 0; height < table_size; height++) {
    //  for (width = 0; width < table_size; width++) {
    //      neighbor = getNeighborCount(gridA, height, width);
    //      if (neighbor==3) {
    //          gridB[height][width] = LIVE;
    //      } else if (neighbor == 2 && tableA[height][width] == LIFE_YES) {
    //          gridB[height][width] = LIVE;
    //      } else {
    //          gridB[height][width] = DEAD;
    //      }
    //  }
    // }
  //
    // for (height = 0; height < table_size; height++) {
    //  for (width = 0; width < table_size; width++) {
    //      gridA[height][width] = gridB[height][width];
    //  }
    // }
}

// Instead of using hardcoded loadStartData below, we ask the user to define organisms
void askUser(World grid[], int table_size) {
    // int i;
    // int n;
    // int height, width;
  //
    // printf("Enter the amount of initial organisms: ");
    // scanf("%d", &n);
    // for (i = 0; i < n; i++) {
    //  printf("Enter dimensions (x y) where organism %d will live: ", i + 1);
    //  scanf("%d %d", &height, &width);
    //  grid[height][width] = LIVE;
    // }
  //
    // displayWorld(grid);
    // printf("Generation 0");
}

// Here I will define starting LIFE_YES cells data called by main()
void loadStartData(World grid[], int table_size) {
  // for (i = 0; i < table_size; i++) {
  //   switch (grid) {
  //     Switch case the cells we want to set LIVE on it
  //     using findIndexForPoint function...
  //     case /* value */:
  //   }
  // }
}

int findIndexForPoint(World grid[], int table_size, int x, int y) {
  int i;
  for (i = 0; i < table_size; i++) {
    if (grid[i].x == x && grid[i].y == y) {
      // found it
      return i;
    }
  }

   // not found, return -1;
  return -1;
}

int main() {
  World grid[sizeX*sizeY] = {0};
  char end;
  int generation = 0;

  clearTable(grid, sizeX * sizeY);

  // Or we load hardcoded start data or we let the user chose ...
  // loadStartData(grid, sizeX * sizeY);
  // askUser(grid, sizeX * sizeY)

  // Keeping that example
  int index = findIndexForPoint(grid,sizeX*sizeY,5,3);
  if (index != -1) {
    grid[index].status = LIVE;
  }

  displayWorld(grid, sizeX*sizeY);

  do {
      //newGeneration(grid);
    //displayWorld(grid, sizeX * sizeY);
        printf("Generation %d\n", ++generation);
        printf("Press q to quit or 1 to continue: ");
        scanf(" %c", &end);
    } while (end != 'q') ;

    return 0;
}

Спасибо, в любом случае !

c
1
NoX 28 Май 2017 в 12:52

2 ответа

Лучший ответ

Поскольку это кажется вашей «домашней работой», я буду использовать очень упрощенный подход:

#include <stdio.h>
#define sizeY 10
#define sizeX 10
#define LIVE 1
#define DEAD 0

typedef struct {
    int y;
    int x;
    unsigned char status;
} TableType;


void printTable(TableType grid[], int table_size) {
    int i;
    for (i = 0; i < table_size; i++) {
      //printf ("P(%d,%d) = ", grid[i].x, grid[i].y); 

      if (i % sizeY == 0 && i != 0) {
          printf("\n");
      }

      if (grid[i].status == LIVE) {
          printf("X");
      } else {
          printf("-");
      }
    }
    printf("\n");
}

void clearTable(TableType grid[], int table_size) {
    int i = 0;
    int height, width;
    for (height = 0; height < sizeY; height++) {
        for (width = 0; width < sizeX; width++) {
            grid[i].y = height;
            grid[i].x = width;
            grid[i].status = DEAD;
            //printf ("Setting P(%d,%d) to DEAD\n", width, height);
            i++;
        }
    }
}

int findIndexForPoint(TableType grid[], int table_size, int x, int y) {
   int i;
   for (i = 0; i < table_size; i++) {
      if (grid[i].x == x && grid[i].y == y) {
         // found it
         return i;
      }
   }

   // not found, return -1;
   return -1;
}


int main () {
   TableType grid[sizeX*sizeY] = {0};
   clearTable(grid, sizeX*sizeY);

   // access via index but you are not sure which x,y
   grid[10].status = LIVE; 

   // This way you know exactly which x,y
   int index = findIndexForPoint (grid,sizeX*sizeY,5,3);
   if (index != -1) {
      grid[index].status = LIVE;
   }

   printTable(grid, sizeX*sizeY);
}

Размер таблицы - sizeX * sizeY, и мы используем этот особый случай, когда я пытаюсь повторно использовать большую часть вашего кода и предполагаю «матрицу» n, n Points. Таким образом, в основном это означает, что он не оптимизирован, и если вы возитесь с размерами X и Y, могут возникнуть проблемы.

Как уже говорилось, теперь у вас есть массив из 100 точек (sizeX * sizeY), который вы инициализируете в clearTable. Эта функция установит значения x, y на то, что вы хотите, в этом случае будет ваша матрица n на n (где n = 10).

PrintTable делает то же самое, но печатает значения.

Скомпилируйте и протестируйте .. затем адаптируйте его под свои нужды.

Выход:

----------
X---------
----------
-----X----
----------
----------
----------
----------
----------
----------

Подтвердите это здесь

< Сильный > EDIT :

Ответьте на свой второй вопрос ... пожалуйста, не делайте этого снова: / Есть возможности для улучшений. Постарайся понять это!

/*
 * The Game of Life
 * http://en.wikipedia.org/wiki/Conway's_Game_of_Life
 *
 * Key requirements :
 * - Limit the size of the world to 10x10 cells
 * - The world (grid) must be a struct composed by cells
 * - A cell must be a struct
 * - Each cell is in one of two possible states : Live or Dead
 * - Any live cell with fewer than two live neighbours dies, as if caused by under-population
 * - Any live cell with two or three live neighbours lives on to the next generation
 * - Any live cell with more than three live neighbours dies, as if by overcrowding
 * - Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction
 * - Between each generation, ask if it's necessary to restart the next generation or to leave the game
 * - Having dedicated function displayWorld() to display a representation of this world
 * - Having dedicated function newGeneration() to generate next step of the world
 * - In the function above, implement conditions based on cell's neighbors to define if each cell is alive or dead
 * - Alive cells are represented by a "+"
 * - Dead cells are represented by a "-"
 * - New borned cells are represented by a "0"
 */

#include <stdio.h>
#include <stdlib.h>
#define WORLD_HEIGHT 10
#define WORLD_WIDTH  10

typedef enum {
   CELL_STATE_INVALID=-1,
   CELL_STATE_DEAD   = 0,
   CELL_STATE_LIVE   = 1,
   CELL_STATE_NEWBORN= 2,
   CELL_N_STATES
} CellStateType;

typedef struct _cell {
  // @ToDo Missing: a cell must be a struct too
  // Means we have a world struct that includes a cell struct
  int y;
  int x;
  unsigned char status;
} Cell;

typedef struct _world {
   int width;
   int height;
   int generation;
   Cell *grid;
} World;

// helper function to find for x,y cell on cell array
int findIndexForCell(World world, int x, int y) {
   int i;
   for (i = 0; i < world.width * world.height; i++) {
      if (world.grid[i].x == x && world.grid[i].y == y) {
         // found it, return indice
         return i;
      }
   }

   // not found, return -1;
   return -1;
}


// function will get cell status for given x, y
// returns invalid status if x,y outside world dimensions
CellStateType getCellStatus(World world, int x, int y) {
   int index;

   index = findIndexForCell(world, x, y);

   if (index == -1) {
      return CELL_STATE_INVALID;
   } else {
      return world.grid[index].status;
   }
}


// function will set cell status and return true or false
// if able to set status or not.
int setCellStatus(World world, int x, int y, CellStateType status) {
   int index;

   index = findIndexForCell(world, x, y);

   if (index == -1) {
      return 0;
   } else {
      world.grid[index].status = status;
      return 1;
   }
}


// Create a new world
World createWorld (int width, int height) {
   World world;

   world.width = width;
   world.height = height;
   world.generation = 0;

   // Content of grid is not initialized
   world.grid = (Cell *) malloc (sizeof(Cell) * (world.width * world.height));

   return world;
}


void displayWorld(World world) {
  int i;
  int size_world = world.width * world.height;

  for (i = 0; i < size_world; i++) {
     if (i % world.width == 0 && i != 0) {
        printf("\n");
     }

     // Missing a third state here;
     // When a cell become LIVE for the first time, it must be shown with a "0" char
     switch (world.grid[i].status) {
        case CELL_STATE_NEWBORN:
           printf("0");
           break;
        case CELL_STATE_DEAD:
           printf("-");
           break;
        case CELL_STATE_LIVE:
           printf("+");
           break;
        default:
           printf("?");
           break;
     }
  }

  printf("\n");
}


void initWorld(World world) {
  int x,y;
  int i = 0;

  world.generation = 0;

  for (y = 0; y < world.height; y++) {
    for (x = 0; x < world.width; x++) {
      world.grid[i].y = y;
      world.grid[i].x = x;
      world.grid[i].status = CELL_STATE_DEAD;
      i++;
    }
  }
}

int getNeighborValue(World world, int row, int col) {
     if (row < 0 || row >= world.height 
      || col < 0 || col >= world.width 
      || getCellStatus(world, row, col) < CELL_STATE_LIVE)
     {
      return CELL_STATE_DEAD;
     } else {
      return CELL_STATE_LIVE;
     }
}

// We count here how many neighbors a cell have
int getNeighborCount(World world, int row, int col) {
   int neighbor = 0;

   // This is not finished and will not work that way
   neighbor += getNeighborValue(world, row - 1, col - 1);
   neighbor += getNeighborValue(world, row - 1, col);
   neighbor += getNeighborValue(world, row - 1, col + 1);
   neighbor += getNeighborValue(world, row, col - 1);
   neighbor += getNeighborValue(world, row, col + 1);
   neighbor += getNeighborValue(world, row + 1, col - 1);
   neighbor += getNeighborValue(world, row + 1, col);
   neighbor += getNeighborValue(world, row + 1, col + 1);

   return neighbor;
}

// Here we define which cells become LIVE OR DEAD on next generation;
// based on cell's neighbors function above
World newGeneration(World world) {
   World temp;
   temp = createWorld(world.width, world.height);
   initWorld(temp);

   int neighbor, height, width;

   for (height = 0; height < world.height; height++) {
      for (width = 0; width < world.width; width++) {
         neighbor = getNeighborCount(world, width, height);
         if (getCellStatus(world, width, height) >= CELL_STATE_LIVE) {
            if (neighbor == 2 || neighbor == 3) {
               setCellStatus(temp, width, height, CELL_STATE_LIVE);
            } else {
               setCellStatus(temp, width, height, CELL_STATE_DEAD);
            }
         } else {
            if (neighbor == 3) {
               setCellStatus(temp, width, height, CELL_STATE_NEWBORN);
            }
         }
      }
   }

   return temp;
}

// Instead of using hardcoded loadStartData below, we ask the user to define organisms
void askUser(World world) {
   int i;
   int n;
   int height, width;

   printf("Enter the amount of initial organisms: ");
   scanf("%d", &n);
   for (i = 0; i < n; i++) {
      do {
         printf("Enter dimensions (x y) where organism %d will live: ", i + 1);
         scanf("%d %d", &width, &height);
      } while (setCellStatus(world, width, height, CELL_STATE_LIVE) == 0); 
   }
}

// Here I will define starting LIFE_YES cells data called by main()
void loadStartData(World world) {

  // Let's check the Beacon:
  // **
  // **
  //   **
  //   **
  setCellStatus(world, 2,2, CELL_STATE_LIVE);
  setCellStatus(world, 3,2, CELL_STATE_LIVE);
  setCellStatus(world, 2,3, CELL_STATE_LIVE);
  setCellStatus(world, 3,3, CELL_STATE_LIVE);

  setCellStatus(world, 4,4, CELL_STATE_LIVE);
  setCellStatus(world, 5,4, CELL_STATE_LIVE);
  setCellStatus(world, 4,5, CELL_STATE_LIVE);
  setCellStatus(world, 5,5, CELL_STATE_LIVE);
}



int main() {
   char end;
   World myworld;
   int generation = 0;

   myworld = createWorld(WORLD_WIDTH, WORLD_HEIGHT);   
   initWorld(myworld);

   // Or we load hardcoded start data or we let the user chose ...
   loadStartData(myworld);
   //askUser(myworld);

   while (end != 'q') {
      displayWorld(myworld);
      myworld = newGeneration(myworld);
      printf("Generation %d\n", ++generation);
      printf("Press q to quit or 1 to continue: ");
      scanf(" %c", &end);
   }

   return 0;
}
1
José Fonte 8 Июн 2017 в 23:18

Я думаю, что вы смешиваете вещи здесь. Зачем вам нужен struct для решения проблемы, которая может быть решена только с помощью массива int?

Первая версия вашего кода хороша, но вы определяете глобальную переменную с typedef, которая вам не нужна, потому что int является стандартным типом. А затем, в основном, удалите table, который вы определили, потому что этот тип не существует.


Если вы вынуждены использовать структуру, то:

typedef struct {
    int y;
    int x;
    int is_dead;
} TableType;

Вы должны добавить переменную с состоянием ячейки.

Затем, когда вы хотите получить доступ к состоянию ячейки в циклах:

grid[height][width].is_dead

Также обратите внимание, что вы объявляете две разные вещи:

  • В начале: typedef int TableType[sizeY][sizeX];. Это неверно Это должно быть TableType table[sizeY][sizeX];.
  • В основном вы должны удалить объявление table, потому что вы создаете глобальную переменную, поэтому вам это не нужно.
1
28 Май 2017 в 11:17