static inline unsigned int is_alive(struct field * f, unsigned int x, unsigned int y) { unsigned int count; unsigned int i, j; unsigned char *p; count = 0; for (i = x - 1; i <= x + 1; i++) { for (j = y - 1; j <= y + 1; j++) { if (y != j || x != i) { count += cell_value(*cell_at(f, i, j), f->max_age); } } } p = cell_at(f, x, y); if (*p) { if (count == 2 || count == 3) { return ((*p) + 1); } else { return (0); } } else { if (count == 3) { return (1); } else { return (0); } } }
static void populate_edges(struct field * f, unsigned int p) { unsigned int i; for (i = f->width; i--;) { *cell_at(f, i, 0) = random_cell(p); *cell_at(f, i, f->height - 1) = random_cell(p); } for (i = f->height; i--;) { *cell_at(f, f->width - 1, i) = random_cell(p); *cell_at(f, 0, i) = random_cell(p); } }
void level::define_connect_status(const unsigned short x, const unsigned short y) { cell& cell_curr = cell_at(x, y); if (cell_curr.active() || cell_curr.rotation_in_progress()) return; //Already connected or rotate in progress cell_curr.set_active(true); //to up if (cell_curr.top_connected()) { if (_wrap_mode || y > 0) { const unsigned short next_y = y > 0 ? y - 1 : _size_cell - 1; cell& cell_next = cell_at(x, next_y); if (cell_next.bottom_connected()) define_connect_status(x, next_y); } } //to down if (cell_curr.bottom_connected()) { if (_wrap_mode || y < _size_cell - 1) { const unsigned short next_y = (y + 1) % _size_cell; cell& cell_next = cell_at(x, next_y); if (cell_next.top_connected()) define_connect_status(x, next_y); } } //to left if (cell_curr.left_connected()) { if (_wrap_mode || x > 0) { const unsigned short next_x = x > 0 ? x - 1 : _size_cell - 1; cell& cell_next = cell_at(next_x, y); if (cell_next.right_connected()) define_connect_status(next_x, y); } } //to right if (cell_curr.right_connected()) { if (_wrap_mode || x < _size_cell - 1) { const unsigned short next_x = (x + 1) % _size_cell; cell& cell_next = cell_at(next_x, y); if (cell_next.left_connected()) define_connect_status(next_x, y); } } }
void level::install_sender() { do { _senderX = static_cast<unsigned short>(mtrandom::random(0, static_cast<int>(_size_cell))); _senderY = static_cast<unsigned short>(mtrandom::random(0, static_cast<int>(_size_cell))); } while (!_wrap_mode && (_senderX == 0 || _senderX == _size_cell - 1 || _senderY == 0 || _senderY == _size_cell - 1)); cell& srv = cell_at(_senderX, _senderY); srv.set_type_sender(); //Define zero point (sender output cell) _zeroX = _senderX; _zeroY = _senderY; switch (mtrandom::random(0, 4)) { case 0: _zeroX = (_zeroX + 1) % _size_cell; break; case 1: _zeroX = _zeroX == 0 ? _size_cell - 1 : _zeroX - 1; break; case 2: _zeroY = (_zeroY + 1) % _size_cell; break; case 3: _zeroY = _zeroY == 0 ? _size_cell - 1 : _zeroY - 1; break; default: assert(false); break; } make_connection(_senderX, _senderY, _zeroX, _zeroY); }
struct world *init_world(struct world_init *init) { if (init==NULL) return NULL; struct world *ret = malloc(sizeof(*ret)); if (ret==NULL) return NULL; ret->init = init; ret->cells = malloc(init->size_x * init->size_y * sizeof(struct world_cell)); memset(ret->cells, 0, init->size_x * init->size_y * sizeof(struct world_cell)); if (ret->cells==NULL) { free(ret); return NULL; } uint16_t x, y, k; for (y=0; y<init->size_y; y++) for (x=0; x<init->size_x; x++) for (k=0; k<init->n_sources; k++) cell_at(ret, x, y)->values[init->sources[k].property] += propagated_value_at(init->sources[k].intensity, init->sources[k].x, init->sources[k].y, x, y, world_property_propagation[init->sources[k].property]); return ret; }
void dump_world(const struct world *world) { printf("Dumping world: size_x=%d, size_y=%d, start_x=%d, start_y=%d\n", world->init->size_x, world->init->size_y, world->init->start_x, world->init->start_y); printf("A world with %d cells: \n", world->init->size_x * world->init->size_y); uint16_t x, y, k; printf(" "); for (x=0; x<world->init->size_x; x++) printf(" %03d", x); printf("\n"); printf(" "); for (x=0; x<world->init->size_x; x++) printf(" ==="); printf("\n"); for (y=0; y<world->init->size_y; y++) { for (k=0; k<WORLD_PROPERTY_COUNT; k++) { if (k==0) printf(" %03d", y); else printf(" "); for (x=0; x<world->init->size_x; x++) { struct world_cell *cell = cell_at(world, x, y); if (cell->values[k]!=0) printf(" %03d", cell->values[k]); else printf(" ..."); } printf("\n"); } } }
const char *cell_info (struct world *world, struct position *pos) { static char info[100]; static char *team[NUM_COLONIES] = { "friendly", "enemy" }; static char *direction[6] = { "left", "down left", "down right", "right", "up right", "up left" }; char *s; struct cell *cell; cell = cell_at (world, pos); if (!cell) return "(pointer out of range)"; s = info; s += sprintf (s, "cell (%d/%d)", pos->x, pos->y); if (cell->rocky) s += sprintf (s, " (rock)"); if (cell->home_of_colony != -1) s += sprintf (s, " (#%d %s homebase)", cell->home_of_colony, team [cell->home_of_colony]); if (cell->food) s += sprintf (s, " (%d food)", cell->food); if (cell->ant) { s += sprintf (s, " (%s ant", team [cell->ant->colony]); s += sprintf (s, ", heading %s", direction [cell->ant->direction]); s += sprintf (s, ", id %d, state %d", cell->ant->id, cell->ant->state); s += sprintf (s, ")"); } return info; }
int display_world (struct world *world) { int ret; struct position p; struct cell *cell; int team; if ((ret=display_map (world)) != 0) return ret; for (p.x=0;p.x<world->size_x;p.x++) { for (p.y=0;p.y<world->size_y;p.y++) { cell = cell_at (world, &p); if (cell->food > 0) v_set_food (&p, cell); for (team=0; team<NUM_COLONIES; team++) { if (cell->markers[team] > 0) { v_set_marker (&p, cell->markers); } } if (cell->ant) { v_set_ant (cell->ant); } } } return v_redisplay_everything (); }
static int display_map (struct world *world) /* Helper function to genereate ASCII map from world. and feed it into v_load_map. */ { char *tmp_map; char c; struct position p; struct cell *cell; int ret; tmp_map = (char *)malloc (world->size_x*world->size_y); memset (tmp_map, ' ', world->size_x*world->size_y); for (p.x=0;p.x<world->size_x;p.x++) { for (p.y=0;p.y<world->size_y;p.y++) { cell = cell_at (world, &p); if (cell->home_of_colony != -1) { c = colony_home_chars[cell->home_of_colony]; } else if (cell->rocky) { c = ROCK_CELL; } else c = EMPTY_CELL; tmp_map[p.y*world->size_x+p.x] = c; } } ret = v_load_map (world->size_x, world->size_y, tmp_map); free (tmp_map); return ret; }
/** * Set the value of a grid cell. * * @param grid Grid to set cell on * @param square Value to set. Valid inputs: @a SQUARE_BOMB, @a SQUARE_EMPTY */ void grid_set(grid_t *grid, int x, int y, square_t square) { assert(square_is_bomb(square) || square_value(square) == 0); assert(grid != NULL); assert(grid->data != NULL); assert(x != 0); assert(y != 0); if (x > grid->width || y > grid->height) { /* Don't overflow into wrong row or, worse, unallocated memory */ return; } *cell_at(x, y) = square; /* Increment adjacent cells */ incr_cell(x-1, y-1); incr_cell(x, y-1); incr_cell(x+1, y-1); incr_cell(x-1, y); incr_cell(x+1, y); incr_cell(x-1, y+1); incr_cell(x, y+1); incr_cell(x+1, y+1); }
bool level::make_route(const unsigned short x, const unsigned short y) { unsigned short next_x = 0, next_y = 0; //Next coordinates bool result = false; int try_counter = 5; while (try_counter && !result) { short i, j; do { i = 1 - static_cast<unsigned short>(mtrandom::random(0, 3)); j = 1 - static_cast<unsigned short>(mtrandom::random(0, 3)); } while ((i && j) || (!i && !j)); //Diagonal if (!_wrap_mode) { if ((j < 0 && x == 0) || (j > 0 && x == _size_cell - 1) || (i < 0 && y == 0) || (i > 0 && y == _size_cell - 1)) { --try_counter; continue; } } const unsigned short cp_x = (j < 0 && x == 0) ? _size_cell - 1 : (x + j) % _size_cell; const unsigned short cp_y = (i < 0 && y == 0) ? _size_cell - 1 : (y + i) % _size_cell; cell& cell = cell_at(cp_x, cp_y); if (!cell.is_used() && cell.can_add_tube()) { result = true; next_x = cp_x; next_y = cp_y; } --try_counter; } if (!result) return false; //min point - we don't have a route make_connection(x, y, next_x, next_y); cell_at(x, y).set_used(true); if (cell_at(next_x, next_y).tube_type() == cell::tt_joiner || (next_x == _zeroX && next_y == _zeroY)) return true; return make_route(next_x, next_y); }
uint8_t value_at(const struct world *world, uint16_t x, uint16_t y, enum world_property_names k) { struct world_cell *cell = cell_at(world, x, y); if (cell==NULL) return -1; return cell->values[k]; }
void level::rotate(const unsigned short x, const unsigned short y, const bool dir) { cell& c = cell_at(x, y); if (c.cell_type() != cell::ct_free) { c.rotate(dir); define_connect_status(); } }
static inline void incr_cell_f(grid_t *grid, int x, int y) { /* 0-1 is UINT_MAX, so when setting cells on the edges of the grid, this * won't modify other rows or, even worse, unallocated pages. * Not an assert because it's vital to proper functioning. */ assert(grid != NULL); assert(grid->data != NULL); if (x >= grid->width || x <= 0) { return; } if (y >= grid->height || y <= 0) { return; } if (!square_is_bomb(*cell_at(x, y))) { square_value(*cell_at(x, y)) += 1; } }
void level::make_connection(const unsigned short curr_x, const unsigned short curr_y, const unsigned short next_x, const unsigned short next_y) { assert(curr_x == next_x || curr_y == next_y); assert(curr_x != next_x || curr_y != next_y); cell& cell_curr = cell_at(curr_x, curr_y); cell& cell_next = cell_at(next_x, next_y); //Wrapping if (next_x == 0 && curr_x == _size_cell - 1) { cell_curr.add_tube(cell::cs_right); cell_next.add_tube(cell::cs_left); } else if (next_x == _size_cell - 1 && curr_x == 0) { cell_curr.add_tube(cell::cs_left); cell_next.add_tube(cell::cs_right); } else if (next_y == 0 && curr_y == _size_cell - 1) { cell_curr.add_tube(cell::cs_bottom); cell_next.add_tube(cell::cs_top); } else if (next_y == _size_cell - 1 && curr_y == 0) { cell_curr.add_tube(cell::cs_top); cell_next.add_tube(cell::cs_bottom); } //Non-wrapping else if (next_x < curr_x) { cell_curr.add_tube(cell::cs_left); cell_next.add_tube(cell::cs_right); } else if (next_x > curr_x) { cell_curr.add_tube(cell::cs_right); cell_next.add_tube(cell::cs_left); } else if (next_y < curr_y) { cell_curr.add_tube(cell::cs_top); cell_next.add_tube(cell::cs_bottom); } else if (next_y > curr_y) { cell_curr.add_tube(cell::cs_bottom); cell_next.add_tube(cell::cs_top); } }
/** * Get the value of a grid cell. * * @param grid Grid to get cell from * @returns The square at (x,y) */ square_t grid_get(grid_t *grid, int x, int y) { assert(grid != NULL); assert(x <= grid->width); assert(y <= grid->height); assert(x > 0); assert(y > 0); assert(grid->data != NULL); return *cell_at(x, y); }
static void populate_field(struct field * f, unsigned int p) { unsigned int x, y; for (x = 0; x < f->width; x++) { for (y = 0; y < f->height; y++) { *cell_at(f, x, y) = random_cell(p); } } }
/** * 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--; } }
int show_state_in_editor (struct world *world) { struct position *pos; struct cell *cell; v_query_pointer (pos); cell = cell_at (world, pos); if (!cell) return -1; return 0; }
bool level::install_receiver() { //Get free cells vector< pair<unsigned short, unsigned short> > free_cells; for (unsigned short x = 0; x < _size_cell; ++x) { for (unsigned short y = 0; y < _size_cell; ++y) { cell& c = cell_at(x, y); if (c.cell_type() == cell::ct_free) free_cells.push_back(make_pair(x, y)); c.set_used(false); } } if (free_cells.empty()) return true; //No more free cells bool result = false; int try_counter = _size_cell * 2; while (try_counter-- && !result) { //Backup current map state const cells backup = _cells; const int free_cell_ind = mtrandom::random(0, static_cast<int>(free_cells.size())); const unsigned short free_x = free_cells[free_cell_ind].first; const unsigned short free_y = free_cells[free_cell_ind].second; cell& rcv = cell_at(free_x, free_y); rcv.set_type_receiver(); result = make_route(free_x, free_y); if (!result) //Restore map _cells = backup; } return result; }
/** * Reveal a sqaure. * * @param grid Grid to reveal cell on * @returns Value of the cell at (x,y). Result will be -(value + 1) if there * is a bomb in the cell */ int grid_reveal(grid_t *grid, int x, int y) { assert(grid != NULL); assert(grid->data != NULL); if (x > grid->width || y > grid->height) { return 0; } if (x < 1 || y < 1) { return 0; } square_t *cell = cell_at(x, y); int old_hidden = cell->hidden; cell->hidden = 0; if (cell->bomb) { return -(cell->value+1); } if (old_hidden == 0) { return cell->value; } /* Don't do a potentially expensive operation */ if(cell->value == 0) { /* 0 cells have their neighbors revealed as well * XXX: this code has a pathlogical case of large contiguous * blocks of 0's. grid_reveal will be called for each square * mulptile times. This is inefficient, and also has a high * probability of blowing the stack for large grids. */ grid_reveal(grid, x-1, y-1); grid_reveal(grid, x, y-1); grid_reveal(grid, x+1, y-1); grid_reveal(grid, x-1, y); grid_reveal(grid, x+1, y); grid_reveal(grid, x-1, y+1); grid_reveal(grid, x, y+1); grid_reveal(grid, x+1, y+1); } return cell->value; }
bool level::load(const unsigned long id, const size sz, const bool wrap_mode, const string& state) { assert(id >= 1 && id <= PW_MAX_LEVEL_NUMBER); assert(!state.empty()); _id = id; sprintf(_id_text, "%08u", static_cast<unsigned int>(_id)); _wrap_mode = wrap_mode; _size_type = sz; _size_cell = size_from_type(sz); const size_t cell_count = _size_cell * _size_cell; _cells.resize(cell_count); if (state.length() != cell_count * 2) return false; for (size_t i = 0; i < cell_count; ++i) { _cells[i].reset(); unsigned char cell_state; cell_state = C2H(state[i * 2]); cell_state = cell_state << 4; cell_state |= C2H(state[i * 2 + 1]); if (!_cells[i].load(cell_state)) return false; } for (unsigned short y = 0; y < _size_cell; ++y) { for (unsigned short x = 0; x < _size_cell; ++x) { cell& c = cell_at(x, y); if (c.cell_type() == cell::ct_sender) { _senderX = x; _senderY = y; break; } } } define_connect_status(); _solved = false; return true; }
int update_everything (struct world *world) { struct position p; struct cell *cell; int team; int need_display; for (p.x=0; p.x<world->size_x; p.x++) { for (p.y=0; p.y<world->size_y; p.y++) { cell = cell_at (world, &p); need_display = 0; if (cell->ant_needs_update) { if (cell->ant) { v_set_ant (cell->ant); } else { v_remove_ant (&p); } cell->ant_needs_update = 0; need_display = 1; } if (cell->food_needs_update) { v_set_food (&p, cell->food); cell->food_needs_update = 0; need_display = 1; } if (cell->markers_need_update) { for (team=0; team<NUM_COLONIES; team++) { v_set_marker (&p, team, cell->markers[team]); } cell->markers_need_update = 0; need_display = 1; } if (need_display) v_display_cell (&p); } } return 0; }
static void draw_field(struct state *st, struct field * f) { unsigned int x, y; unsigned int rx, ry = 0; /* random amount to offset the dot */ unsigned int size = 1 << f->cell_size; unsigned int mask = size - 1; unsigned int fg_count, bg_count; /* columns 0 and width-1 are off screen and not drawn. */ for (y = 1; y < f->height - 1; y++) { fg_count = 0; bg_count = 0; /* rows 0 and height-1 are off screen and not drawn. */ for (x = 1; x < f->width - 1; x++) { rx = random(); ry = rx >> f->cell_size; rx &= mask; ry &= mask; if (*cell_at(f, x, y)) { st->fg_points[fg_count].x = (short) x *size - rx - 1; st->fg_points[fg_count].y = (short) y *size - ry - 1; fg_count++; } else { st->bg_points[bg_count].x = (short) x *size - rx - 1; st->bg_points[bg_count].y = (short) y *size - ry - 1; bg_count++; } } XDrawPoints(st->dpy, st->window, st->fgc, st->fg_points, fg_count, CoordModeOrigin); XDrawPoints(st->dpy, st->window, st->bgc, st->bg_points, bg_count, CoordModeOrigin); } }
void level::reverse_lock(const unsigned short x, const unsigned short y) { cell& c = cell_at(x, y); if (c.cell_type() != cell::ct_free) c.reverse_lock(); }
Cell* next_cell(const Cell* cell, geom2d::Direction d) { return cell_at(point(cell) + d.to_vector()); }
/** * Return the value of the cell at OFFSET from the current cell in * TAPE. */ char get_tape (tape *tape, int offset) { char *cell = cell_at (tape, offset); return *cell; }
/** * Set the cell in TAPE at OFFSET from the current cell to VALUE. */ void set_tape (tape *tape, int offset, char value) { char *cell = cell_at (tape, offset); *cell = value; }
int execute_step (struct world *world, int display, int move_forward) { struct position new_pos; struct cell *cell; int ret; enum ant_action action; int new_direction, direction; int new_marker; if (!world->cursor) { fprintf (stderr, "Internal error: cursor is NULL\n"); return -1; } if (move_forward) { skip_round_markers (world, 1); if (!world->cursor->next) { fprintf (stderr, "Already at the end of simulation\n"); return -1; } } else { if (!world->cursor->prev) { fprintf (stderr, "Already at the beginning of simulation\n"); return -1; } world->cursor = world->cursor->prev; skip_round_markers (world, 0); if (!world->cursor->ant) { fprintf (stderr, "Already at the beginning of simulation (file starts with round marker)\n"); world->round--; return -1; } world->step--; } if (!world->cursor) { fprintf (stderr, "Internal error: cursor is NULL\n"); return -1; } cell = cell_at (world, &world->cursor->ant->pos); if (world->cursor->ant != cell->ant) { fprintf (stderr, "Error in internal data structure: Ant not at cell.\n"); return -1; } if (move_forward) { world->cursor->old_ant_state = cell->ant->state; cell->ant->state = world->cursor->new_ant_state; } else { cell->ant->state = world->cursor->old_ant_state; } action = world->cursor->action; if (!move_forward) { if (world->cursor->action_had_no_side_effects) { if (warnings) { fprintf (stderr, "Stepping back an action without side effects.\n"); } return 0; } action=reverse_action[action]; } switch (action) { case MOVE_FORWARD: case MOVE_BACKWARD: new_pos = world->cursor->ant->pos; direction = world->cursor->ant->direction; if (action == MOVE_BACKWARD) direction+=3; position_move (&new_pos, direction); if ((ret = verify_ant_position (world, &new_pos)) != 0) { if (warnings) { fprintf (stderr, "Ant crashing into another ant or rock!\n"); } if (move_forward) { world->cursor->action_had_no_side_effects = 1; } break; /* this is a valid condition. */ } if (display) { if ((ret=v_move_ant (world->cursor->ant, &new_pos, world->cursor->ant->direction)) != 0) { return ret; } } cell->ant = NULL; if (!display) cell->ant_needs_update = 1; world->cursor->ant->pos = new_pos; cell = cell_at (world, &new_pos); cell->ant = world->cursor->ant; if (!display) cell->ant_needs_update = 1; if ((ret=handle_dead_ants_around (&new_pos))!=0) return ret; break; case TURN_LEFT: case TURN_RIGHT: new_direction = world->cursor->ant->direction; if (action == TURN_RIGHT) { new_direction++; } else { new_direction--; } if (new_direction < 0) new_direction+=6; if (new_direction > 5) new_direction-=6; if (display) { if ((ret=v_move_ant (world->cursor->ant, &world->cursor->ant->pos, new_direction)) != 0) { return ret; } } world->cursor->ant->direction = new_direction; if (!display) cell->ant_needs_update = 1; break; case PICKUP_FOOD: if (world->cursor->ant->carries_food) { if (warnings) { fprintf (stderr, "Ant carriing food attempts to pick up food.\n"); } if (move_forward) { world->cursor->action_had_no_side_effects = 1; } break; } if (cell->food == 0) { if (warnings) { fprintf (stderr, "Ant attepmts to pick up food but there is none.\n"); } if (move_forward) { world->cursor->action_had_no_side_effects = 1; } world->cursor->action_had_no_side_effects = 1; break; } if (display) { if ((ret=v_ant_picks_up_food (world->cursor->ant, cell->food, cell->food-1)) != 0) { return ret; } } cell->food--; if (!display) cell->food_needs_update = 1; world->cursor->ant->carries_food++; break; case DROP_FOOD: if (!world->cursor->ant->carries_food) { if (warnings) { fprintf (stderr, "Ant carriing no food attempts to drop food.\n"); } if (move_forward) { world->cursor->action_had_no_side_effects = 1; } world->cursor->action_had_no_side_effects = 1; break; } cell = cell_at (world, &world->cursor->ant->pos); if (display) { if ((ret=v_ant_drops_food (world->cursor->ant, cell->food, cell->food+1)) != 0) { return ret; } } cell->food++; if (!display) cell->food_needs_update = 1; world->cursor->ant->carries_food--; break; case SET_MARKER: case CLEAR_MARKER: new_marker = cell->markers[world->cursor->ant->colony]; if (action == SET_MARKER) { new_marker |= (1<<world->cursor->marker); } else { new_marker &= ~(1<<world->cursor->marker); } if (new_marker == cell->markers[world->cursor->ant->colony]) { if (warnings) { fprintf (stderr, "Ant setting/clearing marker but it is already set/cleared.\n"); } if (move_forward) { world->cursor->action_had_no_side_effects = 1; } break; } if (display) { if ((ret=v_ant_changes_marker (world->cursor->ant, cell->markers[world->cursor->ant->colony], new_marker)) != 0) { return ret; } } cell->markers[world->cursor->ant->colony] = new_marker; if (!display) cell->markers_need_update = 1; break; default: fprintf (stderr, "Illegal ant action\n"); return -1; } if (move_forward) { if (world->cursor->next) world->cursor = world->cursor->next; world->step++; } /* when moving backwards this already has been done at the beginning. */ return 0; }
/** * Alter the cell in TAPE at OFFSET from the current cell by CHANGE * amount. */ void alter_tape (tape *tape, int offset, char change) { char *cell = cell_at (tape, offset); *cell += change; }