void dijkstra_distance_target(grid *distances, grid *target, const pos *targets, int count, int neighbors, cost_function_t cost_function, void *userdata){ grid_fill(distances, distances->x0, distances->y0, distances->width, distances->height, DBL_MAX); if(target != NULL) grid_fill(target, target->x0, target->y0, target->width, target->height, -1); queue open_set = queue_create(sizeof(pos)); for(int i = 0;i<count;++i) { grid_set(distances, targets[i].x, targets[i].y, 0.0); if(target != NULL) grid_set(target, targets[i].x, targets[i].y, i); queue_push(&open_set, targets+i); } while(!queue_empty(&open_set)) { pos cur = *(pos*)queue_front(&open_set); double curdist = grid_get(distances, cur.x, cur.y); queue_pop(&open_set); for(int i = 0;i<neighbors;++i) { pos neigh = {cur.x+offsets[i].x, cur.y+offsets[i].y}; if(!grid_contains(distances, neigh.x, neigh.y)) continue; double neighdist = grid_get(distances, neigh.x, neigh.y); double cost = cost_function(cur.x, cur.y, neigh.x, neigh.y, userdata); if(neighdist > curdist + cost) { grid_set(distances, neigh.x, neigh.y, curdist + cost); if(target != NULL) grid_set(target, neigh.x, neigh.y, grid_get(target, cur.x, cur.y)); queue_push(&open_set, &neigh); } } } queue_destroy(open_set); }
void grid_assign_grid(grid *g1, grid *g2) { int x0 = clamp(g2->x0, g1->x0, g1->x0 + g1->width); int y0 = clamp(g2->y0, g1->y0, g1->y0 + g1->height); int x1 = clamp(g2->x0 + g2->width, g1->x0, g1->x0 + g1->width); int y1 = clamp(g2->y0 + g2->height, g1->y0, g1->y0 + g1->height); for(int x = x0;x<x1;++x) for(int y = y0;y<y1;++y) grid_set(g1, x, y, grid_get(g2, x, y)); }
void grid_mul_number(grid *g1, double value) { 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) grid_set(g1, x, y, grid_get(g1, x, y)*value); }
void grid_step(grid *g1, double threshold) { 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) grid_set(g1, x, y, grid_get(g1, x, y)>threshold?1.0:0.0); }
void grid_clamp(grid *g1, double low, double high) { 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) grid_set(g1, x, y, clampd(grid_get(g1, x, y), low, high)); }
// 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); } }
// Randomize the state of all cells. static void randomize_grid(struct grid *grid) { int stride = grid_stride(grid); for (int col = 0; col < grid->width; ++col) { for (int row = 0; row < grid->height; ++row) { grid_set(grid, row, col, rand() % 2); } } }
/** * Randomly place bombs on a grid. * * @param grid Grid to place bombs on * @param bombs Number of bombs to place */ void grid_add_bombs(grid_t *grid, unsigned int bombs) { int x, y; while (bombs != 0) { do { x = (random() % grid->width) + 1; y = (random() % grid->height) + 1; } while (square_is_bomb(*cell_at(x, y))); grid_set(grid, x, y, SQUARE_BOMB); bombs--; } }
static int grid_set_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"); if(top<4 || !lua_isnumber(L, 4)) return typerror(L, 4, "number"); grid *g = lua_touserdata(L, 1); int x = lua_tointeger(L, 2); int y = lua_tointeger(L, 3); double value = lua_tonumber(L, 4); grid_set(g, x, y, value); return 0; }
struct grid_t *init_grid_from_random() { struct grid_t *grid; int cols, rows, i, j; srandom(time(NULL)); /* TODO range */ cols = random() % 21 + 40; rows = random() % 21 + 40; grid = grid_init(rows, cols); grid_fill(grid, 0); for (i = 0;i < rows;i++) for (j = 0;j < cols;j++) grid_set(grid, i, j, random() % 2); return grid; }
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 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); }
struct grid_t *init_grid_from_file(char *fname, int max_cols, \ char comment, char alive, char dead) { struct grid_t *grid; FILE *stream; int cols, rows, counter; char *line, *c; stream = fopen(fname, "r"); assert(stream != NULL); line = malloc(sizeof(char) * max_cols); cols = -1; rows = -1; counter = 0; for(;getline(&line, (size_t *) &max_cols, stream) != -1;) { if (line[0] != comment) { if (rows == -1) { rows = atoi(line); assert(rows != -1); } else if (cols == -1) { cols = atoi(line); assert(cols != -1); grid = grid_init(rows, cols); grid_fill(grid, 0); } else if (counter < rows * cols) { /* read the grid */ assert(rows != -1 && cols != -1); for (c = line;*c != '\n' && *c != EOF;c++, counter++) grid_set(grid, counter / cols, counter % cols,\ (*c == alive) ? (1) : (0)); } } } assert(rows != -1 && cols != -1 && grid != NULL); fclose(stream); return grid; }
// 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]); } }
thing_th *Set(thing_th *grid, const char *kw, thing_th *val) { if(!grid || th_kind(grid)!=grid_k) return NULL; return grid_set((grid_th *)grid, kw, val); }