/* we change some priorities of the values before starting our backtrack */ void board_optimize(Board *board) { for (int row = 1; row < board->height - 1; row++) { for (int col = 1; col < board->width - 1; col++) { Cell *cell = board_get_cell(board, row, col); // Initial values of the corners if ((row == 1 && col == 1) || (row == 1 && col == board->width - 2) || (row == board->height - 2 && col == 1) || (row == board->height - 2 && col == board->width - 2)) { if (cell->degree == 1) { board_set_priority(board, cell, 1); } } //values of the edges - corners else if (row == 1 || col == 1 || row == board->height - 2 || col == board->width - 2) { if (cell->degree == 4) { board_set_priority(board, cell, 1); for (int i = 0; i < 4; i++) { Cell *neighbour = board_iter_neighbours(board, cell, i); if (neighbour) { board_set_priority(board, neighbour, 1); } } } } } } }
/* We get the next cell for assignation, TODO: implement heuristics ordering */ Cell *board_next_assignation(Board *board) { for (int row = 1; row < board->height - 1; row++) { for (int col = 1; col < board->width - 1; col++) { Cell * cell = board_get_cell(board, row, col); if (cell -> status == 0) { return cell; } } } return NULL; if (board->stack_a->count) { return stack_pop(board->stack_a); } else if (board->stack_b->count) { return stack_pop(board->stack_b); } else { return NULL; // in case we don't have any assignations left } }
/* Set the status of a given cell * with each assignation, we update the grafical interface and * update the count of the neighbours used in the neighbours branch prune * TODO: remove grafical interface update for performance? check this */ void board_set_status(Board *board, int row, int col, int status) { Cell *cell = board_get_cell(board, row, col); int old_status = cell->status; // we first update all of our neighbours with the appropiate info about the change in status board_update_neighbours(board, cell, old_status, status); cell->status = status; // we re-prioritize the neighbours and the cell, depending if it's empty or not // board_update_heuristics(board, cell); if (status) { if (old_status == 0) { board->count_empty -= 1; } watcher_set_cell_status(row, col, status - 1); } else { // TODO change this to work with two stacks if (cell->priority == 1) { stack_push(board->stack_a, cell); } else { stack_push(board->stack_b, cell); } board->count_empty += 1; watcher_clear_cell(row, col); } }
/* * Displays the current board in a curses window * * Parameters: const World_t* world, Lens_t* lens, WINDOW* display_area * Return: void */ void display_curses(const World_t* world, Lens_t* lens, WINDOW* window) { int x, y; int display_x, display_y; int display_width, display_height; int value; char display_value; // determine terminal's rows and columns. Display cell if in bounds getmaxyx(window, display_height, display_width); lens_set(lens, world->board, display_width, display_height); // clear the display of the old frame clear(); for(y = lens->min_y; y < lens->max_y; y++) { for(x = lens->min_x; x < lens->max_x; x++) { value = board_get_cell(world->board, x, y); // Adjust display coordinates by the BOARD_BORDER_SIZE offset display_x = x - lens->x_display_offset; display_y = y - lens->y_display_offset; move(display_y, display_x); // display o for each living cell within the terminal if (display_y < display_height && display_x < display_width) { display_value = world->rule->state_chars[value]; if (display_value != ' ') { insch(display_value); } } } } refresh(); }
/* Create our board and return a pointer to our object */ Board *board_init(int height, int width) { Board *board = malloc(sizeof(Board)); board->height = height; board->width = width; board->count_empty = 0; board->count_loyalist = 0; board->count_rebel = 0; board->count_empty = height * width; /* We allocate enough memory for the cells in our board * we store a simple array of pointers and use basic arithmetic two get the correct cell */ board->cells = (Cell *)malloc(board->height * board->width * sizeof(Cell)); board->stack_a = stack_init(); board->stack_b = stack_init(); /* We set the initial values of the cells in our board * on the first pass we just create an empty board */ for (int row = 0; row < board->height; row++) { for (int col = 0; col < board->width; col++) { Cell *cell = board_get_cell(board, row, col); cell->row = row; cell->col = col; cell->loyals = 0; cell->rebels = 0; cell->color = 0; cell->degree = 0; cell->empty = 4; cell->status = 0; // Initial values of the corners if ((!row && !col) || (!row && col + 1 == board->width) || (row + 1 == board->height && !col) || (row + 1 == board->height && col + 1 == board->width)) { cell->empty = 2; } //values of the edges - corners else if (!row || !col || row + 1 == board->height || col + 1 == board->width) { cell->empty = 3; } else { stack_push(board->stack_b, cell); } } } for (int row = 0; row < board->height; row++) { for (int col = 0; col < board->width; col++) { if (!row || !col || row + 1 == board->height || col + 1 == board->width) { board_set_status(board, row, col, 1); } } } return board; }
/* Helper function to return upper neighbour, returns NULL if it doesn't have one */ Cell *board_upper_neighbour(Board *board, Cell *cell) { Cell *neighbour = NULL; if (cell->row >= 1) { neighbour = board_get_cell(board, cell->row - 1, cell->col); } return neighbour; }
/* Used when creating out board, we set the apropiate info */ void board_set_degree(Board *board, int row, int col, int degree) { Cell *cell = board_get_cell(board, row, col); cell->degree = degree; if (cell->degree > 0) { watcher_set_cell_degree(row, col, cell->degree); } }
/* Helper function to return bottom neighbour, returns NULL if it doesn't have one */ Cell *board_bottom_neighbour(Board *board, Cell *cell) { Cell *neighbour = NULL; if (cell->row < board->height - 1) { neighbour = board_get_cell(board, cell->row + 1, cell->col); } return neighbour; }
/* Helper function to return right neighbour, returns NULL if it doesn't have one */ Cell *board_right_neighbour(Board *board, Cell *cell) { Cell *neighbour = NULL; if (cell->col < board->width - 1) { neighbour = board_get_cell(board, cell->row, cell->col + 1); } return neighbour; }
/* Helper function to return left neighbour, returns NULL if it doesn't have one */ Cell *board_left_neighbour(Board *board, Cell *cell) { Cell *neighbour = NULL; if (cell->col >= 1) { neighbour = board_get_cell(board, cell->row, cell->col - 1); } return neighbour; }
/* Debuging function */ void board_print_empty_count(Board *board) { for (int row = 0; row < board->height; row++) { for (int col = 0; col < board->width; col++) { printf("%d ", board_get_cell(board, row, col)->empty); } printf("\n"); } printf("\n"); }
/* * Determines the next state of a cell at x, y in the board of the given * `world` and applies it to next_board according to the world's rule. */ void handle_transition_rule(World_t* world, int x, int y) { int num_neighbors; Transition_t* transition; int index; unsigned char current_cell; int i, j; bool changed = false; index = y * world->board->width + x; current_cell = board_get_cell(world->board, x, y); // Go through each transition rule for (i = 0; i < world->rule->transition_length; i++) { transition = world->rule->transitions[i]; if (current_cell == transition->begin) { // If the rule involves neighbor counting if (transition->size > 0) { num_neighbors = world->rule->neighbor_func( world->board, x, y, transition->neighbor_state ); for (j = 0; j < transition->size; j++) { // Apply transition if count of neighbors matches // any in the list if (!transition->negator) { if (num_neighbors == transition->transitions[j]) { world->next_board->cells[index] = transition->end; changed = true; break; } } else { // Make the transition *unless* the right // number of neighbors are present changed = true; world->next_board->cells[index] = transition->end; if (num_neighbors == transition->transitions[j]) { world->next_board->cells[index] = current_cell; break; } } } } else { // Rule should occur regardless of neighbors world->next_board->cells[index] = transition->end; changed = true; } } } // The cell is unchanged so far, just copy the old value if (!changed) { world->next_board->cells[index] = current_cell; } }
static int proc_board_read (char *page, char **start, off_t off, int count, int *eof, void *data) { struct klife_board *board = data; int x, y; int val; char *p = page; *start = p; /* calculate starting point to dump board */ x = off % (board->side + 1); y = off / (board->side + 1); if (y >= board->side) { *eof = 1; return 0; } while (y < board->side) { while (x < board->side) { val = board_get_cell (board, x, y); *p = val ? '#' : '.'; p++; x++; count--; if (count <= 0) goto finish; } *p = '\n'; p++; count--; x = 0; y++; if (count <= 0) goto finish; } *eof = 1; finish: return p - page; }
/* Neighbour prunning, we iter through the cell and its neighbours calling cell_degree_check */ bool board_degree_prune(Board *board, int row, int col) { Cell *cell = board_get_cell(board, row, col); // first we check the cell its self if (!cell_degree_check(cell)) { return false; } for (int i = 0; i < 4; i++) { Cell *neighbour = board_iter_neighbours(board, cell, i); if (neighbour) { //printf("checking neighbour:\n"); //board_print_cell(neighbour); if (!cell_degree_check(neighbour)) { return false; } } } return true; }
/* Get the current status of a given cell */ int board_get_status(Board *board, int row, int col) { Cell *cell = board_get_cell(board, row, col); return cell->status; }
//! handles mouse clicks as well as key presses gint board_signal_handler (GtkWidget *widget, GdkEventButton *event, gpointer data) /* FIXME: clean up this function */ { int row, col, pixel_x, pixel_y, type; int status = 0; byte *move = NULL; int *rmove = NULL; GtkboardEvent our_event; MoveInfo minfo = {NULL, NULL, NULL, NULL, NULL}; if (!opt_game) return FALSE; if (ui_gameover) return FALSE; if (event->type == GDK_KEY_PRESS && !(((GdkEventKey *)event)->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))) { if (!game_getmove_kb && !game_event_handler) return FALSE; if (game_event_handler) { our_event.type = GTKBOARD_KEY_PRESS; our_event.key = ((GdkEventKey *)event)->keyval; status = game_event_handler (&cur_pos, &our_event, &minfo); move = minfo.move; rmove = minfo.rmove; } else //(if game_getmove_kb) status = game_getmove_kb (&cur_pos, ((GdkEventKey *)event)->keyval, &move, &rmove); } else { if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) { if (player_to_play != HUMAN) { sb_message ("Machine's turn", FALSE); return FALSE; } if (!impl_check()) { sb_error ("Not yet implemented", TRUE); return FALSE; } } if (!game_getmove && !game_event_handler) {return FALSE;} board_get_cell (event, &row, &col, &pixel_x, &pixel_y); if (!(row >= 0 && row < board_wid)) return FALSE; if (!(col >= 0 && col < board_heit)) return FALSE; switch (event->type) { case GDK_BUTTON_PRESS: type = GTKBOARD_BUTTON_PRESS; break; case GDK_BUTTON_RELEASE: type = GTKBOARD_BUTTON_RELEASE; break; case GDK_MOTION_NOTIFY: type = GTKBOARD_MOTION_NOTIFY; break; case GDK_LEAVE_NOTIFY: type = GTKBOARD_LEAVE_NOTIFY; break; default: return FALSE; } if (game_event_handler) { our_event.type = type; our_event.x = row; our_event.y = col; our_event.pixel_x = pixel_x; our_event.pixel_y = pixel_y; status = game_event_handler (&cur_pos, &our_event, &minfo); move = minfo.move; rmove = minfo.rmove; } else status = game_getmove (&cur_pos, row, col, type, cur_pos.player, &move, &rmove); if (status < 0) { gchar *tmpstr = minfo.help_message ? g_strdup_printf ("Illegal move: %s", minfo.help_message) : g_strdup_printf ("Illegal move"); sb_error (tmpstr, FALSE); g_free (tmpstr); sound_play (SOUND_ILLEGAL_MOVE); } } if (status <= 0) { ui_make_human_move (NULL, rmove); if (rmove) menu_start_stop_game (NULL, MENU_START_GAME); return FALSE; } sound_play (SOUND_USER_MOVE); menu_start_stop_game (NULL, MENU_START_GAME); ui_make_human_move (move, rmove); return FALSE; }
/* Get the degree of a given cell */ int board_get_degree(Board *board, int row, int col) { Cell *cell = board_get_cell(board, row, col); return cell->degree; }
/* DFS prunning to check if we have more than one group per status, we return true if it is, false in another case */ bool board_check_groups(Board *board) { /* color 0: unvisited node (white) * color 1: visited node (grey) * color 2: closed node (black) */ // Starting params board_reset_color(board); board->count_loyalist = 0; board->count_rebel = 0; /* Pointer to the first cell that we find that is rebel */ Cell *rebel = NULL; /* We add the top right corner to the stack, which is garanteed to be a loyalist cell */ Stack *stack = stack_init(); stack_push(stack, board_get_cell(board, 0, 0)); /* We count the loyalist cells first */ Cell *current_cell = stack_pop(stack); current_cell->color = 1; board->count_loyalist += 1; while (current_cell) { current_cell->color = 2; dfs_search_neighbours(board, current_cell, stack, &rebel, 1); current_cell = stack_pop(stack); } board_reset_color(board); /* Now we count the rebel cells starting from the pointer to rebel * empty cells are being counted twice, we also check if any rebel cells * have been assigned */ if (rebel != NULL) { current_cell = rebel; current_cell->color = 1; board->count_rebel += 1; while (current_cell) { current_cell->color = 2; dfs_search_neighbours(board, current_cell, stack, &rebel, 2); current_cell = stack_pop(stack); } } // free the memmory from our stack stack_destroy(stack); // return our value //printf("count empty: %d\n", board->count_empty); //printf("count rebels: %d\n", board->count_rebel); //printf("count loyals: %d\n", board->count_loyalist); if (board->count_empty + board->count_rebel + board->count_loyalist == board->width * board->height) { return true; } else { return false; } }
/* Set the color of a given cell */ void board_set_color(Board *board, int row, int col, int color) { Cell *cell = board_get_cell(board, row, col); cell->color = color; }
/* Get the color of a given cell */ int board_get_color(Board *board, int row, int col) { Cell *cell = board_get_cell(board, row, col); return cell->color; }