/* tab:4 * * wator.sc - game of life fish source code * * Author: Steve Lumetta * Version: 1 * Creation Date: Wed May 26 15:37:22 1993 * Filename: transfer.sc * History: * SL 1 Wed May 26 15:37:33 1993 * First written */ #include #include #include #include /* fish_t is the structure which holds information for a single grid point. */ typedef int fish_t; /* These two values define the size of the block on each processor and the size of the display. Ghost boundaries are used for communication between processors and to simplify local computation loops. */ #define BLOCK_WIDTH 386 /* must be two greater than a multiple of PROCS */ #define BLOCK_HEIGHT ((BLOCK_WIDTH - 2)/PROCS + 2) /* The following value gives the chance of a particular cell having a fish inside. It is used only at initialization time. */ #define FISH_CHANCE 0.5 /* probability of a given cell having a fish */ /* The all_init_fish routine fills the grid randomly with fish. */ void all_init_fish(fish_t (*spread fish_array)[BLOCK_HEIGHT][BLOCK_WIDTH]) { int i, j; fish_t *a_fish; srandom(MYPROC*131); /* HAS_FISH decides randomly if a fish is present in a particular cell. */ #define HAS_FISH ((random()&65535)/65536.0 < FISH_CHANCE) for (i = 1; i < BLOCK_HEIGHT - 1; i++) for (j = 1, a_fish = (fish_t *)&fish_array[MYPROC][i][j]; j < BLOCK_WIDTH - 1; j++, a_fish++) *a_fish = HAS_FISH; } /* The all_move_fish routine plays the game of life for one step. First the boundary regions are communicated between processors, then each processor calculates the number of neighbors for each fish, and finally the rules are applied. */ void all_move_fish(fish_t (*spread fish_array)[BLOCK_HEIGHT][BLOCK_WIDTH]) { int next_proc, i, j; fish_t *ul_fish, *u_fish, *ur_fish; fish_t *l_fish, *a_fish, *r_fish; fish_t *bl_fish, *b_fish, *br_fish; fish_t neighbors[BLOCK_HEIGHT][BLOCK_WIDTH]; fish_t *n_neighbors; /* Send boundary regions to neighboring processors. */ next_proc = (MYPROC + PROCS - 1)%PROCS; bulk_store(&fish_array[next_proc][BLOCK_HEIGHT - 1][1], (fish_t *)&fish_array[MYPROC][1][1], (BLOCK_WIDTH - 2)*sizeof(fish_t)); next_proc = (MYPROC + 1)%PROCS; bulk_store(&fish_array[next_proc][0][1], (fish_t *)&fish_array[MYPROC][BLOCK_HEIGHT - 2][1], (BLOCK_WIDTH - 2)*sizeof(fish_t)); /* Wait for data to arrive from other processors. */ store_sync(2*(BLOCK_WIDTH - 2)*sizeof(fish_t)); /* Copy boundary regions to simplify local computation. */ for (i = 0; i < BLOCK_HEIGHT; i++) { fish_array[MYPROC][i][BLOCK_WIDTH - 1] = fish_array[MYPROC][i][1]; fish_array[MYPROC][i][0] = fish_array[MYPROC][i][BLOCK_WIDTH - 2]; } /* Count neighbors, accumulating the total in the neighbors array. */ for (i = 1; i < BLOCK_HEIGHT - 1; i++) { ul_fish = (fish_t *)&fish_array[MYPROC][i - 1][0]; u_fish = (fish_t *)&fish_array[MYPROC][i - 1][1]; ur_fish = (fish_t *)&fish_array[MYPROC][i - 1][2]; l_fish = (fish_t *)&fish_array[MYPROC][i][0]; a_fish = &neighbors[i][1]; r_fish = (fish_t *)&fish_array[MYPROC][i][2]; bl_fish = (fish_t *)&fish_array[MYPROC][i + 1][0]; b_fish = (fish_t *)&fish_array[MYPROC][i + 1][1]; br_fish = (fish_t *)&fish_array[MYPROC][i + 1][2]; for (j = 1; j < BLOCK_WIDTH - 1; j++) { *a_fish++ = *ul_fish++ + *u_fish++ + *ur_fish++ + *l_fish++ + *r_fish++ + *bl_fish++ + *b_fish++ + *br_fish++; } } /* Apply rules of life and death. */ for (i = 1; i < BLOCK_HEIGHT - 1; i++) { for (j = 1, a_fish = (fish_t *)&fish_array[MYPROC][i][j], n_neighbors = &neighbors[i][j]; j < BLOCK_WIDTH - 1; j++, a_fish++, n_neighbors++) { if (*a_fish) { if (*n_neighbors < 2 || *n_neighbors > 3) *a_fish = 0; /* blue */ } else { if (*n_neighbors == 3) *a_fish = 1; /* green--important to use '1' */ } } } } /* all_display_fish displays the fish grid, sending only the changes to the host. */ void all_display_fish(fish_t (*spread fish_array)[BLOCK_HEIGHT][BLOCK_WIDTH]) { static int init = 0; static fish_t (*old_map)[BLOCK_WIDTH]; int i, j; fish_t *old_fish, *new_fish; /* If this is the first time, open a window then allocate and clear the old map. */ if (!init) { init = 1; on_one {X_init(BLOCK_WIDTH - 2);} old_map = (fish_t (*)[BLOCK_WIDTH]) malloc(BLOCK_HEIGHT*BLOCK_WIDTH*sizeof(fish_t)); for (i = 1; i < BLOCK_HEIGHT - 1; i++) for (j = 1, old_fish = &old_map[i][j]; j < BLOCK_WIDTH - 1; j++, old_fish++) *old_fish = 0; } /* Send changes in map to host for display, and copy new map to old. */ for (i = 1; i < BLOCK_HEIGHT - 1; i++) { for (j = 1, old_fish = &old_map[i][j], new_fish = (fish_t *)&fish_array[MYPROC][i][j]; j < BLOCK_WIDTH - 1; j++, old_fish++, new_fish++) { if (*old_fish != *new_fish) X_point(j - 1, MYPROC*(BLOCK_HEIGHT - 2) + i - 1, *new_fish); *old_fish = *new_fish; } } } /* splitc_main contains the main body of the program. */ splitc_main() { fish_t (*spread fish_array)[BLOCK_HEIGHT][BLOCK_WIDTH]; fish_array = (fish_t (*spread)[BLOCK_HEIGHT][BLOCK_WIDTH]) all_spread_malloc(PROCS, BLOCK_HEIGHT*BLOCK_WIDTH*sizeof(fish_t)); /* Initialize fish randomly. */ all_init_fish(fish_array); while (1) { /* Send display data to host node. */ all_display_fish(fish_array); /* Synchronize to insure that host has all of the current display data. */ barrier(); /* Display the ocean. */ on_one {X_show();} /* Move fish according to the rules. */ all_move_fish(fish_array); } }