在结构中定义2D网格并访问单元格

时间:2017-05-28 09:52:41

标签: c

我尝试在结构中定义一个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;
}

我想我没有正确使用我的结构,非常感谢任何帮助实现这一点,非常感谢!

编辑:

我通过提供有关我的课程的更多详细信息以及最后尝试实现的内容来更新我的主要请求。最终输出是一个名为“生命游戏”的游戏项目。

我用评论更新了下面的代码,描述了什么是生命游戏,具有更多功能的详细关键点以及显示缺失内容的许多评论代码。我很抱歉再次被阻止,但由于新的要求(例如一个单元格也必须是一个结构),我很难管理单元格的使用。

以下是更新后的代码:

/*
 * 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;
}

非常感谢!

2 个答案:

答案 0 :(得分: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点“矩阵”。所以,基本上它意味着它没有被优化,如果你搞乱X和Y的大小问题可能会出现。

如上所述,现在你只有一个100点(sizeX * sizeY)的数组,你将在clearTable上初始化。此函数将x,y值设置为您想要的任何值,在这种情况下将是您的n乘n矩阵(其中n = 10)。

printTable执行相同操作,但会打印值。

编译并测试它......然后根据您的需要进行调整。

输出:

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

确认here

修改

回答你的第二个问题......请不要再这样做了:/还有改进的余地。试着去理解吧!

/*
 * 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 :(得分:1)

我认为你在这里混合了一些东西。为什么需要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声明,因为您正在创建一个全局变量,因此您根本不需要它。