static int grid_get_lua(lua_State *L) { int top = lua_gettop(L); if(top<1) return typerror(L, 1, "grid"); if(top<2 || !lua_isnumber(L, 2)) return typerror(L, 2, "number"); if(top<3 || !lua_isnumber(L, 3)) return typerror(L, 3, "number"); grid *g = lua_touserdata(L, 1); int x = lua_tointeger(L, 2); int y = lua_tointeger(L, 3); lua_pushnumber(L, grid_get(g, x, y)); return 1; }
int grid_neighbors() { int x, y; grid_get(&x, &y); int n = -1; for (int dx = -1; dx <= 1; ++dx) { for (int dy = -1; dy <= 1; ++dy) { if (x+dx >= 0 && x+dx < grid_width && y+dy >= 0 && y+dy < grid_height) { ++n; } } } return n; }
void mpi_get_row(struct grid *grid, int col, int rank, int tag, int pos) { int size = grid->height; int column_cells[size]; for(int i = 0; i < size; i++) { column_cells[i] = grid_get(grid, i, col-1); } MPI_Request request; MPI_Status status; MPI_Isend(column_cells, size, MPI_UNSIGNED_CHAR, pos, rank, MPI_COMM_WORLD, &request); MPI_Irecv(column_cells, size, MPI_UNSIGNED_CHAR, pos, tag, MPI_COMM_WORLD, &request); MPI_Wait(&request, &status); for(int i = 0; i < size; i++) { grid_set(grid, i, col, column_cells[i]); } }
void kernel(int x, int y, int z, grid3d_real g, REAL ce, REAL cw, REAL cn, REAL cs, REAL ct, REAL cb, REAL cc) { int nx, ny, nz; nx = grid_dimx(g); ny = grid_dimy(g); nz = grid_dimz(g); REAL c, w, e, n, s, b, t; c = grid_get(g, 0, 0, 0); w = (x == 0) ? c : grid_get(g, -1, 0, 0); e = (x == nx-1) ? c : grid_get(g, 1, 0, 0); n = (y == 0) ? c : grid_get(g, 0, -1, 0); s = (y == ny-1) ? c : grid_get(g, 0, 1, 0); b = (z == 0) ? c : grid_get(g, 0, 0, -1); t = (z == nz-1) ? c : grid_get(g, 0, 0, 1); grid_emit(g, cc*c + cw*w + ce*e + cs*s + cn*n + cb*b + ct*t); return; }
void grid_dilate(grid *g1) { grid tmp = grid_clone(g1); int x0 = g1->x0; int y0 = g1->y0; int x1 = g1->x0 + g1->width; int y1 = g1->y0 + g1->height; for(int x = x0;x<x1;++x) { for(int y = y0;y<y1;++y) { double value = 0.0; for(int xoffset = -1;xoffset<=1;++xoffset) { for(int yoffset = -1;yoffset<=1;++yoffset) { int xn = x + xoffset; int yn = y + yoffset; if(grid_contains(&tmp, xn, yn) && grid_get(&tmp, xn, yn) != 0) value = 1.0; } } grid_set(g1, x, y, value); } } grid_destroy(tmp); }
// Count the number of live cells and return the count on rank 0. int gol_count_alive(void) { struct grid *grid = grids[cur_grid]; // Count the number of live cells in the local grid. int count = 0; for (int col = 0; col < grid->width; ++col) { for (int row = 0; row < grid->height; ++row) { if (ALIVE == grid_get(grid, row, col)) { count += 1; } } } // TODO Reduce the local counts to a global count on rank 0. int global_count = 0; MPI_Reduce(&count, &global_count, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); return global_count; }
int grid_dir2id(int dir) { int x, y; grid_get(&x, &y); switch (dir) { case GRID_TOP: y -= 1; break; case GRID_BOTTOM: y += 1; break; case GRID_LEFT: x -= 1; break; case GRID_RIGHT: x += 1; break; case GRID_TOP_LEFT: x -= 1; y -= 1; break; case GRID_TOP_RIGHT: x += 1; y -= 1; break; case GRID_BOTTOM_LEFT: x -= 1; y += 1; break; case GRID_BOTTOM_RIGHT: x += 1; y += 1; break; } if (x < 0 || x >= grid_width || y < 0 || y >= grid_height) { return -1; } return grid_grid2id(x, y); }
// Print the global grid to stdout from rank 0. void gol_print(int height, int width) { // TODO This function only works sequentially (one process). Need // to communicate remote cells to rank 0. int rank = 0, num_procs = 0; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &num_procs); int *grid_sizes, *offset; if(rank == 0) { grid_sizes = calloc(num_procs, sizeof(int)); offset = calloc(num_procs, sizeof(int)); } int grid_length = grids[0]->height * grids[0]->width; MPI_Gather(&grid_length, 1, MPI_INT, grid_sizes, 1, MPI_INT, 0, MPI_COMM_WORLD); char grid_cells[grids[0]->height * grids[0]->width]; char old_cells[grids[1]->height * grids[1]->width]; int index = 0; for(int row = 0; row < grids[0]->height; row++) { for(int col = 0; col < grids[0]->width; col++) { grid_cells[index] = grid_get(grids[0], row, col); old_cells[index] = grid_get(grids[1], row, col); index++; } } char *whole_grids_cells[2]; struct grid *whole_grids[2]; if(rank == 0) { whole_grids_cells[cur_grid] = calloc(height*width, sizeof(char)); whole_grids_cells[1-cur_grid] = calloc(height*width, sizeof(char)); whole_grids[0] = new_grid(height, width); whole_grids[1] = new_grid(height, width); offset[0] = 0; for(int i = 1; i < num_procs; i++) { offset[i] = grid_sizes[i-1] + offset[i-1]; } } MPI_Gatherv(grid_cells, grid_length, MPI_CHAR, whole_grids_cells[cur_grid], grid_sizes, offset, MPI_CHAR, 0, MPI_COMM_WORLD); MPI_Gatherv(old_cells, grid_length, MPI_CHAR, whole_grids_cells[1-cur_grid], grid_sizes, offset, MPI_CHAR, 0, MPI_COMM_WORLD); if(rank == 0) { index = 0; for(int row = 0; row < whole_grids[0]->height; row++) { for(int col = 0; col < whole_grids[1]->width; col++) { grid_set(whole_grids[0], row, col, whole_grids_cells[cur_grid][index]); grid_set(whole_grids[1], row, col, whole_grids_cells[1-cur_grid][index]); index++; } } struct grid *grid = whole_grids[cur_grid]; struct grid *old = whole_grids[1-cur_grid]; for (int row = 0; row < grid->height; ++row) { for (int col = 0; col < grid->width; ++col) { if (ALIVE == grid_get(grid, row, col)) { // Live cell. printf("o "); } else if (ALIVE == grid_get(old, row, col)) { // Dying cell (empty now but alive in the previous generation). printf("+ "); } else { // Dead cell. printf(". "); } } printf("\n"); } free(grid_sizes); free(offset); free(whole_grids_cells[0]); free(whole_grids_cells[1]); } }
// Advance a specified cell using the rules of Game of Life. static void advance_cell(struct grid *in, struct grid *out, int row, int col) { // Count alive neighbors. int count = 0; if (ALIVE == grid_get(in, row - 1, col - 1)) count += 1; if (ALIVE == grid_get(in, row - 1, col )) count += 1; if (ALIVE == grid_get(in, row - 1, col + 1)) count += 1; if (ALIVE == grid_get(in, row , col - 1)) count += 1; if (ALIVE == grid_get(in, row , col + 1)) count += 1; if (ALIVE == grid_get(in, row + 1, col - 1)) count += 1; if (ALIVE == grid_get(in, row + 1, col )) count += 1; if (ALIVE == grid_get(in, row + 1, col + 1)) count += 1; // Apply the rules (rule source: Wikipedia). // Copy cell from input to output. grid_set(out, row, col, grid_get(in, row, col)); // Rule 1: Any live cell with fewer than two live neighbours dies, as if caused by under-population. if (ALIVE == grid_get(in, row, col) && count < 2) { grid_set(out, row, col, EMPTY); } // Rule 2: Any live cell with two or three live neighbours lives on to the next generation. if (ALIVE == grid_get(in, row, col) && 2 <= count && count <= 3) { grid_set(out, row, col, ALIVE); } // Rule 3: Any live cell with more than three live neighbours dies, as if by overcrowding. if (ALIVE == grid_get(in, row, col) && count > 3) { grid_set(out, row, col, EMPTY); } // Rule 4: Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. if (EMPTY == grid_get(in, row, col) && count == 3) { grid_set(out, row, col, ALIVE); } }
thing_th *Get(thing_th *grid, const char *kw) { if(!grid || th_kind(grid)!=grid_k) return NULL; return grid_get((grid_th *)grid, kw); }