bool legal_move_board (unsigned short pos, unsigned char color, bool allow_suicide) { /* you can always pass */ if (pos == PASS_POS) { return true; } if (!on_board (pos) || (color != BLACK && color != WHITE)) { return false; } if (pos == ko_pos && color == current_player) { return false; } if (get_point_board (pos) != EMPTY) { return false; } /* don't need to save the current state, because it's always empty since we tested for that above */ set_point_board (pos, color); /* if we have liberties, it can't be illegal */ if (get_liberties_board (pos) > 0 || /* if we can capture something, it can't be illegal */ (get_point_board (NORTH (pos)) == OTHER (color) && !get_liberties_board (NORTH (pos))) || (get_point_board (SOUTH (pos)) == OTHER (color) && !get_liberties_board (SOUTH (pos))) || (get_point_board (EAST (pos)) == OTHER (color) && !get_liberties_board (EAST (pos))) || (get_point_board (WEST (pos)) == OTHER (color) && !get_liberties_board (WEST (pos))) || /* if we're allowed to suicide, only multi-stone suicide is legal (no ruleset allows single-stone suicide that I know of) */ (allow_suicide && (get_point_board (NORTH (pos)) == color || get_point_board (SOUTH (pos)) == color || get_point_board (EAST (pos)) == color || get_point_board (WEST (pos)) == color))) { /* undo our previous set */ set_point_board (pos, EMPTY); return true; } else { /* undo our previous set */ set_point_board (pos, EMPTY); return false; } }
static aligned_t update(void *arg) { stencil_t *points = ((update_args_t *)arg)->points; size_t i = ((update_args_t *)arg)->i; size_t j = ((update_args_t *)arg)->j; size_t this_stage = ((update_args_t *)arg)->stage; size_t step = ((update_args_t *)arg)->step; size_t next_stage_id = next_stage(this_stage); // Perform local work perform_local_work(); aligned_t **prev = points->stage[prev_stage(this_stage)]; aligned_t sum = *(NORTH(prev, i, j)) + *(WEST(prev, i, j)) + *(HERE(prev, i, j)) + *(EAST(prev, i, j)) + *(SOUTH(prev, i, j)); // Empty the next stage for this index qthread_empty(&points->stage[next_stage_id][i][j]); // Update this point qthread_writeEF_const(&points->stage[this_stage][i][j], sum/NUM_NEIGHBORS); if (step < num_timesteps) { // Spawn next stage update_args_t args = {points, i, j, next_stage_id, step+1}; #ifdef BOUNDARY_SYNC qthread_fork_copyargs_precond(update, &args, sizeof(update_args_t), NULL, NUM_NEIGHBORS, NEIGHBORS(points->stage[this_stage],i,j)); #else if (i == 1) { // North edge if (j == 1) // West edge: EAST & SOUTH qthread_fork_copyargs_precond(update, &args, sizeof(update_args_t), NULL, 2, EAST(points->stage[this_stage],i,j), SOUTH(points->stage[this_stage],i,j)); else if (j == points->M-2) // East edge: WEST & SOUTH qthread_fork_copyargs_precond(update, &args, sizeof(update_args_t), NULL, 2, WEST(points->stage[this_stage],i,j), SOUTH(points->stage[this_stage],i,j)); else // Interior: WEST & EAST & SOUTH qthread_fork_copyargs_precond(update, &args, sizeof(update_args_t), NULL, 3, WEST(points->stage[this_stage],i,j), EAST(points->stage[this_stage],i,j), SOUTH(points->stage[this_stage],i,j)); } else if (i == points->N-2) { // South edge if (j == 1) // West edge: NORTH & EAST qthread_fork_copyargs_precond(update, &args, sizeof(update_args_t), NULL, 2, NORTH(points->stage[this_stage],i,j), EAST(points->stage[this_stage],i,j)); else if (j == points->M-2) // East edge: NORTH & WEST qthread_fork_copyargs_precond(update, &args, sizeof(update_args_t), NULL, 2, NORTH(points->stage[this_stage],i,j), WEST(points->stage[this_stage],i,j)); else // Interior: NORTH & WEST & EAST qthread_fork_copyargs_precond(update, &args, sizeof(update_args_t), NULL, 3, NORTH(points->stage[this_stage],i,j), WEST(points->stage[this_stage],i,j), EAST(points->stage[this_stage],i,j)); } else { // Interior if (j == 1) // West edge: NORTH & EAST & SOUTH qthread_fork_copyargs_precond(update, &args, sizeof(update_args_t), NULL, 3 , NORTH(points->stage[this_stage],i,j), EAST(points->stage[this_stage],i,j), SOUTH(points->stage[this_stage],i,j)); else if (j == points->M-2) // East edge: NORTH & WEST & SOUTH qthread_fork_copyargs_precond(update, &args, sizeof(update_args_t), NULL, 3, NORTH(points->stage[this_stage],i,j), WEST(points->stage[this_stage],i,j), SOUTH(points->stage[this_stage],i,j)); else // Interior: ALL qthread_fork_copyargs_precond(update, &args, sizeof(update_args_t), NULL, 4, NORTH(points->stage[this_stage],i,j), EAST(points->stage[this_stage],i,j), WEST(points->stage[this_stage],i,j), SOUTH(points->stage[this_stage],i,j)); } #endif } else qt_feb_barrier_enter(points->barrier); return 0; }
void move_display (unsigned short pos) { if (!on_board (pos)) { return; } while ((unsigned) I (pos) >= REAL_MAX_X) { cursor_pos = EAST (cursor_pos); cursor_updated (); } while ((unsigned) I (pos) < REAL_MIN_X) { cursor_pos = WEST (cursor_pos); cursor_updated (); } while ((unsigned) J (pos) >= REAL_MAX_Y) { cursor_pos = SOUTH (cursor_pos); cursor_updated (); } while ((unsigned) J (pos) < REAL_MIN_Y) { cursor_pos = NORTH (cursor_pos); cursor_updated (); } }
int flood_fill_board (unsigned short pos, unsigned char color) { if (!on_board (pos) || get_point_board (pos) == color) { return 0; } empty_stack (&parse_stack); int ret_val = 0; unsigned char orig_color = get_point_board (pos); set_point_board (pos, color); ++ret_val; push_pos_stack (&parse_stack, pos); while (pop_pos_stack (&parse_stack, &pos)) { ret_val += flood_fill_helper (NORTH (pos), orig_color, color); ret_val += flood_fill_helper (SOUTH (pos), orig_color, color); ret_val += flood_fill_helper (EAST (pos), orig_color, color); ret_val += flood_fill_helper (WEST (pos), orig_color, color); } return ret_val; }
int get_liberties_board (unsigned short pos) { if (!on_board (pos) || get_point_board (pos) == EMPTY) { return -1; } setup_marks (); int ret_val = 0; unsigned char orig_color = get_point_board (pos); empty_stack (&parse_stack); push_pos_stack (&parse_stack, pos); /* Since we only ever test for liberties in order to determine captures and the like, there's no reason to count any liberties higher than 2 (we sometimes need to know if something has 1 liberty for dealing with ko) */ while (pop_pos_stack (&parse_stack, &pos) && ret_val < 2) { ret_val += get_liberties_helper (NORTH (pos), orig_color); ret_val += get_liberties_helper (SOUTH (pos), orig_color); ret_val += get_liberties_helper (EAST (pos), orig_color); ret_val += get_liberties_helper (WEST (pos), orig_color); } /* if there's more than two liberties, the stack isn't empty, so empty it */ empty_stack (&parse_stack); return ret_val; }
/* Generate a move to definitely settle the position after the game * has been finished. The purpose of this is to robustly determine * life and death status and to distinguish between life in seki and * life with territory. * * The strategy is basically to turn all own living stones into * invincible ones and remove from the board all dead opponent stones. * Stones which cannot be removed, nor turned invincible, are alive in * seki. * * If do_capture_dead_stones is 0, opponent stones are not necessarily * removed from the board. This happens if they become unconditionally * dead anyway. * * Moves are generated in the following order of priority: * 0. Play edge liberties in certain positions. This is not really * necessary, but often it can simplify the tactical and strategical * reading substantially, making subsequent moves faster to generate. * 1. Capture an opponent string in atari and adjacent to own * invincible string. Moves leading to ko or snapback are excluded. * 2. Extend an invincible string to a liberty of an opponent string. * 3. Connect a non-invincible string to an invincible string. * 4. Extend an invincible string towards an opponent string or an own * non-invincible string. * 5. Split a big eyespace of an alive own dragon without invincible * strings into smaller pieces. * 6. Play a liberty of a dead opponent dragon. * * Steps 2--4 are interleaved to try to optimize the efficiency of the * moves. In step 5 too, efforts are made to play efficient moves. By * efficient we here mean moves which are effectively settling the * position and simplify the tactical and strategical reading for * subsequent moves. * * Steps 1--4 are guaranteed to be completely safe. Step 0 and 5 * should also be risk-free. Step 6 on the other hand definitely * isn't. Consider for example this position: * * .XXXXX. * XXOOOXX * XOO.OOX * XOXXXOX * XO.XXOX * ------- * * In order to remove the O stones, it is necessary to play on one of * the inner liberties, but one of them lets O live. Thus we have to * check carefully for blunders at this step. * * Update: Step 0 is only safe against blunders if care is taken not * to get into a shortage of liberties. * Step 5 also has some risks. Consider this position: * * |XXXXX. * |OOOOXX * |..O.OX * |OX*OOX * +------ * * Playing at * allows X to make seki. * * IMPORTANT RESTRICTION: * Before calling this function it is mandatory to call genmove() or * genmove_conservative(). For this function to be meaningful, the * genmove() call should return pass. */ int aftermath_genmove(int *aftermath_move, int color, int under_control[BOARDMAX], int do_capture_dead_stones) { int k; int other = OTHER_COLOR(color); int distance[BOARDMAX]; int score[BOARDMAX]; float owl_hotspot[BOARDMAX]; float reading_hotspot[BOARDMAX]; int dragons[BOARDMAX]; int something_found; int closest_opponent = NO_MOVE; int closest_own = NO_MOVE; int d; int move = NO_MOVE; int pos = NO_MOVE; int best_score; int best_scoring_move; owl_hotspots(owl_hotspot); reading_hotspots(reading_hotspot); /* As a preparation we compute a distance map to the invincible strings. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (!ON_BOARD(pos)) continue; else if (board[pos] == color && worm[pos].invincible) distance[pos] = 0; else if (!do_capture_dead_stones && ((board[pos] == other && worm[pos].unconditional_status == DEAD) || (board[pos] == color && worm[pos].unconditional_status == ALIVE))) distance[pos] = 0; else distance[pos] = -1; } d = 0; do { something_found = 0; for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (ON_BOARD(pos) && distance[pos] == -1) { for (k = 0; k < 4; k++) { int pos2 = pos + delta[k]; if (!ON_BOARD(pos2)) continue; if ((d == 0 || board[pos2] == EMPTY) && distance[pos2] == d) { if (d > 0 && board[pos] == other) { distance[pos] = d + 1; if (closest_opponent == NO_MOVE) closest_opponent = pos; } else if (d > 0 && board[pos] == color) { distance[pos] = d + 1; if (closest_own == NO_MOVE) closest_own = pos; } else if (board[pos] == EMPTY) { distance[pos] = d + 1; something_found = 1; } break; } } } } d++; } while (something_found); if (under_control) { for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (!ON_BOARD(pos)) continue; else if (distance[pos] == -1) under_control[pos] = 0; else under_control[pos] = 1; } } if (debug & DEBUG_AFTERMATH) { int m, n; for (m = 0; m < board_size; m++) { for (n = 0; n < board_size; n++) { pos = POS(m, n); if (distance[pos] > 0) fprintf(stderr, "%2d", distance[pos]); else if (distance[pos] == 0) { if (board[pos] == WHITE) gprintf(" o"); else if (board[pos] == BLACK) gprintf(" x"); else gprintf(" ?"); } else { if (board[pos] == WHITE) gprintf(" O"); else if (board[pos] == BLACK) gprintf(" X"); else gprintf(" ."); } } gprintf("\n"); } gprintf("Closest opponent %1m", closest_opponent); if (closest_opponent != NO_MOVE) gprintf(", distance %d\n", distance[closest_opponent]); else gprintf("\n"); gprintf("Closest own %1m", closest_own); if (closest_own != NO_MOVE) gprintf(", distance %d\n", distance[closest_own]); else gprintf("\n"); } /* Case 0. This is a special measure to avoid a certain kind of * tactical reading inefficiency. * * Here we play on edge liberties in the configuration * * XO. * .*. * --- * * to stop X from "leaking" out along the edge. Sometimes this can * save huge amounts of tactical reading for later moves. */ best_scoring_move = NO_MOVE; best_score = 5; for (pos = BOARDMIN; pos < BOARDMAX; pos++) { int libs; if (board[pos] != EMPTY || distance[pos] == 0) continue; libs = approxlib(pos, color, 3, NULL); if (libs < 3) continue; if (is_self_atari(pos, other)) continue; for (k = 0; k < 4; k++) { int dir = delta[k]; int right = delta[(k+1)%4]; if (!ON_BOARD(pos - dir) && board[pos + dir] == color && board[pos + dir + right] == other && board[pos + dir - right] == other && (libs > countlib(pos + dir) || (libs > 4 && libs == countlib(pos + dir))) && (DRAGON2(pos + dir).safety == INVINCIBLE || DRAGON2(pos + dir).safety == STRONGLY_ALIVE)) { int this_score = 20 * (owl_hotspot[pos] + reading_hotspot[pos]); if (this_score > best_score) { best_score = this_score; best_scoring_move = pos; } } } } if (best_scoring_move != NO_MOVE && safe_move(best_scoring_move, color) == WIN) { *aftermath_move = best_scoring_move; DEBUG(DEBUG_AFTERMATH, "Closing edge at %1m\n", best_scoring_move); return 1; } /* Case 1. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { int lib; if (board[pos] == other && worm[pos].unconditional_status != DEAD && countlib(pos) == 1 && ((ON_BOARD(SOUTH(pos)) && distance[SOUTH(pos)] == 0) || (ON_BOARD(WEST(pos)) && distance[WEST(pos)] == 0) || (ON_BOARD(NORTH(pos)) && distance[NORTH(pos)] == 0) || (ON_BOARD(EAST(pos)) && distance[EAST(pos)] == 0))) { findlib(pos, 1, &lib); /* Make sure we don't play into a ko or a (proper) snapback. */ if (countstones(pos) > 1 || !is_self_atari(lib, color)) { *aftermath_move = lib; return 1; } } } /* Cases 2--4. */ if (closest_opponent != NO_MOVE || closest_own != NO_MOVE) { if (closest_own == NO_MOVE) move = closest_opponent; else move = closest_own; /* if we're about to play at distance 1, try to optimize the move. */ if (distance[move] == 2) { char mx[BOARDMAX]; char mark = 0; memset(mx, 0, sizeof(mx)); best_score = 0; best_scoring_move = move; for (pos = BOARDMIN; pos < BOARDMAX; pos++) { int score = 0; int move_ok = 0; if (!ON_BOARD(pos) || distance[pos] != 1) continue; mark++; for (k = 0; k < 4; k++) { int pos2 = pos + delta[k]; if (!ON_BOARD(pos2)) continue; if (distance[pos2] < 1) score--; else if (board[pos2] == EMPTY) score++; else if (mx[pos2] == mark) score--; else { if (board[pos2] == color) { move_ok = 1; score += 7; if (countstones(pos2) > 2) score++; if (countstones(pos2) > 4) score++; if (countlib(pos2) < 4) score++; if (countlib(pos2) < 3) score++; } else { int deltalib = (approxlib(pos, other, MAXLIBS, NULL) - countlib(pos2)); move_ok = 1; score++; if (deltalib >= 0) score++; if (deltalib > 0) score++; } mark_string(pos2, mx, mark); } } if (is_suicide(pos, other)) score -= 3; if (0) gprintf("Score %1m = %d\n", pos, score); if (move_ok && score > best_score) { best_score = score; best_scoring_move = pos; } } move = best_scoring_move; } while (distance[move] > 1) { for (k = 0; k < 4; k++) { int pos2 = move + delta[k]; if (ON_BOARD(pos2) && board[pos2] == EMPTY && distance[pos2] == distance[move] - 1) { move = pos2; break; } } } *aftermath_move = move; return 1; } /* Case 5. * If we reach here, either all strings of a dragon are invincible * or no string is. Next we try to make alive dragons invincible by * splitting big eyes into smaller ones. Our strategy is to search * for an empty vertex with as many eye points as possible adjacent * and with at least one alive but not invincible stone adjacent or * diagonal. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { int eyespace_neighbors = 0; int own_neighbors = 0; int own_diagonals = 0; int opponent_dragons = 0; int own_worms = 0; int safety = UNKNOWN; int bonus = 0; int mx[BOARDMAX]; score[pos] = 0; if (board[pos] != EMPTY || distance[pos] != -1) continue; memset(mx, 0, sizeof(mx)); for (k = 0; k < 8; k++) { int pos2 = pos + delta[k]; if (!ON_BOARD(pos2)) continue; if (board[pos2] == EMPTY) { if (k < 4) eyespace_neighbors++; continue; } if (board[pos2] == other) { int origin = dragon[pos2].origin; if (k < 4) { if (dragon[pos2].status == ALIVE) { safety = DEAD; break; } else if (!mx[origin]) { eyespace_neighbors++; opponent_dragons++; } } if (!mx[origin] && dragon[pos2].status == DEAD) { bonus++; if (k < 4 && countlib(pos2) <= 2 && countstones(pos2) >= 3) bonus++; if (k < 4 && countlib(pos2) == 1) bonus += 3; } mx[origin] = 1; } else if (board[pos2] == color) { dragons[pos] = pos2; if (safety == UNKNOWN && dragon[pos2].status == ALIVE) safety = ALIVE; if (DRAGON2(pos2).safety == INVINCIBLE) safety = INVINCIBLE; if (k < 4) { int apos = worm[pos2].origin; if (!mx[apos]) { own_worms++; if (countstones(apos) == 1) bonus += 2; if (countlib(apos) < 6 && approxlib(pos, color, 5, NULL) < countlib(apos)) bonus -= 5; mx[apos] = 1; } if (countlib(apos) <= 2) { int r; int important = 0; int safe_atari = 0; for (r = 0; r < 4; r++) { d = delta[r]; if (!ON_BOARD(apos+d)) continue; if (board[apos+d] == other && dragon[apos+d].status == DEAD) important = 1; else if (board[apos+d] == EMPTY && !is_self_atari(apos+d, other)) safe_atari = 1; } if (approxlib(pos, color, 3, NULL) > 2) { bonus++; if (important) { bonus += 2; if (safe_atari) bonus += 2; } } } own_neighbors++; } else own_diagonals++; } } if (safety == DEAD || safety == UNKNOWN || eyespace_neighbors == 0 || (own_neighbors + own_diagonals) == 0) continue; if (bonus < 0) bonus = 0; score[pos] = 4 * eyespace_neighbors + bonus; if (safety == INVINCIBLE) { score[pos] += own_neighbors; if (own_neighbors < 2) score[pos] += own_diagonals; if (own_worms > 1 && eyespace_neighbors >= 1) score[pos] += 10 + 5 * (own_worms - 2); } else if (eyespace_neighbors > 2) score[pos] += own_diagonals; /* Splitting bonus. */ if (opponent_dragons > 1) score[pos] += 10 * (opponent_dragons - 1); /* Hotspot bonus. */ { int owl_hotspot_bonus = (int) (20.0 * owl_hotspot[pos]); int reading_hotspot_bonus = (int) (20.0 * reading_hotspot[pos]); int hotspot_bonus = owl_hotspot_bonus + reading_hotspot_bonus; /* Don't allow the hotspot bonus to turn a positive score into * a non-positive one. */ if (score[pos] > 0 && score[pos] + hotspot_bonus <= 0) hotspot_bonus = 1 - score[pos]; score[pos] += hotspot_bonus; if (1 && (debug & DEBUG_AFTERMATH)) gprintf("Score %1M = %d (hotspot bonus %d + %d)\n", pos, score[pos], owl_hotspot_bonus, reading_hotspot_bonus); } /* Avoid taking ko. */ if (is_ko(pos, color, NULL)) score[pos] = (score[pos] + 1) / 2; } while (1) { int bb; best_score = 0; move = NO_MOVE; for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (ON_BOARD(pos) && score[pos] > best_score) { best_score = score[pos]; move = pos; } } if (move == NO_MOVE) break; bb = dragons[move]; if (is_illegal_ko_capture(move, color) || !safe_move(move, color) || (DRAGON2(bb).safety != INVINCIBLE && DRAGON2(bb).safety != STRONGLY_ALIVE && owl_does_defend(move, bb, NULL) != WIN) || (!confirm_safety(move, color, NULL, NULL))) { score[move] = 0; } else { /* If we're getting short of liberties, we must be more careful. * Check that no adjacent string or dragon gets more alive by * the move. */ int libs = approxlib(move, color, 5, NULL); int move_ok = 1; if (libs < 5) { for (k = 0; k < 4; k++) { if (board[move + delta[k]] == color && countlib(move + delta[k]) > libs) break; } if (k < 4) { if (trymove(move, color, "aftermath-B", move + delta[k])) { int adjs[MAXCHAIN]; int neighbors; int r; neighbors = chainlinks(move, adjs); for (r = 0; r < neighbors; r++) { if (worm[adjs[r]].attack_codes[0] != 0 && (find_defense(adjs[r], NULL) > worm[adjs[r]].defense_codes[0])) { DEBUG(DEBUG_AFTERMATH, "Blunder: %1m becomes tactically safer after %1m\n", adjs[r], move); move_ok = 0; } } popgo(); for (r = 0; r < neighbors && move_ok; r++) { if (dragon[adjs[r]].status == DEAD && !owl_does_attack(move, adjs[r], NULL)) { DEBUG(DEBUG_AFTERMATH, "Blunder: %1m becomes more alive after %1m\n", adjs[r], move); move_ok = 0; } } } } } if (!move_ok) score[move] = 0; else { *aftermath_move = move; DEBUG(DEBUG_AFTERMATH, "Splitting eyespace at %1m\n", move); return 1; } } } /* Case 6. * Finally we try to play on liberties of remaining DEAD opponent * dragons, carefully checking against mistakes. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { int target; int cc = NO_MOVE; int self_atari_ok = 0; if (board[pos] != EMPTY || distance[pos] != -1) continue; target = NO_MOVE; for (k = 0; k < 4; k++) { int pos2 = pos + delta[k]; if (!ON_BOARD(pos2)) continue; if (board[pos2] == other && dragon[pos2].status != ALIVE && (do_capture_dead_stones || worm[pos2].unconditional_status != DEAD) && DRAGON2(pos2).safety != INESSENTIAL) { target = pos2; break; } } if (target == NO_MOVE) continue; /* At this point, (pos) is a move that potentially may capture * a dead opponent string at (target). */ if (!trymove(pos, color, "aftermath-A", target)) continue; /* It is frequently necessary to sacrifice own stones in order * to force the opponent's stones to be removed from the board, * e.g. by adding stones to fill up a nakade shape. However, we * should only play into a self atari if the sacrificed stones * are classified as INESSENTIAL. Thus it would be ok for O to * try a self atari in this position: * * |OOOO * |XXXO * |..XO * |OOXO * +---- * * but not in this one: * * |XXX.. * |OOXX. * |.OOXX * |XXOOX * |.O.OX * +----- */ self_atari_ok = 1; for (k = 0; k < 4; k++) { if (board[pos + delta[k]] == color && DRAGON2(pos + delta[k]).safety != INESSENTIAL) { self_atari_ok = 0; cc = pos + delta[k]; break; } } /* Copy the potential move to (move). */ move = pos; /* If the move is a self atari, but that isn't okay, try to * recursively find a backfilling move which later makes the * potential move possible. */ if (!self_atari_ok) { while (countlib(pos) == 1) { int lib; findlib(pos, 1, &lib); move = lib; if (!trymove(move, color, "aftermath-B", target)) break; } if (countlib(pos) == 1) move = NO_MOVE; } while (stackp > 0) popgo(); if (move == NO_MOVE) continue; /* Make sure that the potential move really isn't a self * atari. In the case of a move found after backfilling this * could happen (because the backfilling moves happened to * capture some stones). */ if (!self_atari_ok && is_self_atari(move, color)) continue; /* Consult the owl code to determine whether the considered move * really is effective. Blunders should be detected here. */ if (owl_does_attack(move, target, NULL) == WIN) { /* If we have an adjacent own dragon, which is not inessential, * verify that it remains safe. */ if (cc != NO_MOVE && !owl_does_defend(move, cc, NULL)) continue; /* If we don't allow self atari, also call confirm safety to * avoid setting up combination attacks. */ if (!self_atari_ok && !confirm_safety(move, color, NULL, NULL)) continue; *aftermath_move = move; DEBUG(DEBUG_AFTERMATH, "Filling opponent liberty at %1m\n", move); return 1; } } /* Case 7. * In very rare cases it turns out we need yet another pass. An * example is this position: * * |..... * |OOOO. * |XXXO. * |.OXO. * |O.XO. * +----- * * Here the X stones are found tactically dead and therefore the * corner O stones have been amalgamated with the surrounding * stones. Since the previous case only allows sacrificing * INESSENTIAL stones, it fails to take X off the board. * * The solution is to look for tactically attackable opponent stones * that still remain on the board but should be removed. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (board[pos] == other && (worm[pos].unconditional_status == UNKNOWN || do_capture_dead_stones) && (DRAGON2(pos).safety == DEAD || DRAGON2(pos).safety == TACTICALLY_DEAD) && worm[pos].attack_codes[0] != 0 && !is_illegal_ko_capture(worm[pos].attack_points[0], color)) { *aftermath_move = worm[pos].attack_points[0]; DEBUG(DEBUG_AFTERMATH, "Tactically attack %1m at %1m\n", pos, *aftermath_move); return 1; } } /* No move found. */ return -1; }
void store_persistent_owl_cache(int routine, int apos, int bpos, int cpos, int result, int move, int move2, int certain, int tactical_nodes, char goal[BOARDMAX], int goal_color) { char active[BOARDMAX]; int pos; int k; int r; int other = OTHER_COLOR(goal_color); gg_assert(stackp == 0); /* If cache is full, first try to purge it. */ if (persistent_owl_cache_size == MAX_OWL_CACHE_SIZE) purge_persistent_owl_cache(); /* FIXME: Kick out oldest or least expensive entry instead of giving up. */ if (persistent_owl_cache_size == MAX_OWL_CACHE_SIZE) { TRACE_OWL_PERFORMANCE("Persistent owl cache full.\n"); return; } persistent_owl_cache[persistent_owl_cache_size].boardsize = board_size; persistent_owl_cache[persistent_owl_cache_size].routine = routine; persistent_owl_cache[persistent_owl_cache_size].apos = apos; persistent_owl_cache[persistent_owl_cache_size].bpos = bpos; persistent_owl_cache[persistent_owl_cache_size].cpos = cpos; persistent_owl_cache[persistent_owl_cache_size].result = result; persistent_owl_cache[persistent_owl_cache_size].result_certain = certain; persistent_owl_cache[persistent_owl_cache_size].move = move; persistent_owl_cache[persistent_owl_cache_size].move2 = move2; persistent_owl_cache[persistent_owl_cache_size].tactical_nodes = tactical_nodes; persistent_owl_cache[persistent_owl_cache_size].movenum = movenum; /* Remains to set the board. We let the active area be * the goal + * distance four expansion through empty intersections and own stones + * adjacent opponent strings + * liberties of adjacent opponent strings with less than five liberties + * liberties of low liberty neighbors of adjacent opponent strings * with less than five liberties. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) if (ON_BOARD(pos)) active[pos] = (goal[pos] != 0); /* Also add critical moves to the active area. */ if (ON_BOARD1(move)) active[move] = 1; if (ON_BOARD1(move2)) active[move2] = 1; /* Distance four expansion through empty intersections and own stones. */ for (k = 1; k < 5; k++) { for (pos = BOARDMIN; pos < BOARDMAX; pos++){ if (!ON_BOARD(pos) || board[pos] == other || active[pos] != 0) continue; if ((ON_BOARD(SOUTH(pos)) && active[SOUTH(pos)] == k) || (ON_BOARD(WEST(pos)) && active[WEST(pos)] == k) || (ON_BOARD(NORTH(pos)) && active[NORTH(pos)] == k) || (ON_BOARD(EAST(pos)) && active[EAST(pos)] == k)) { if (board[pos] == EMPTY) active[pos] = k + 1; else mark_string(pos, active, (char) (k + 1)); } } } /* Adjacent opponent strings. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (board[pos] != other || active[pos] != 0) continue; for (r = 0; r < 4; r++) { int pos2 = pos + delta[r]; if (ON_BOARD(pos2) && board[pos2] != other && active[pos2] != 0) { mark_string(pos, active, (char) 1); break; } } } /* Liberties of adjacent opponent strings with less than five liberties + * liberties of low liberty neighbors of adjacent opponent strings * with less than five liberties. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (board[pos] == other && active[pos] != 0 && countlib(pos) < 5) { int libs[4]; int liberties = findlib(pos, 4, libs); int adjs[MAXCHAIN]; int adj; for (r = 0; r < liberties; r++) active[libs[r]] = 1; /* Also add liberties of neighbor strings if these are three * or less. */ adj = chainlinks(pos, adjs); for (r = 0; r < adj; r++) { if (countlib(adjs[r]) <= 3) { int s; liberties = findlib(adjs[r], 3, libs); for (s = 0; s < liberties; s++) active[libs[s]] = 1; } } } } for (pos = BOARDMIN; pos < BOARDMAX; pos++) { int value = board[pos]; if (!ON_BOARD(pos)) continue; if (!active[pos]) value = GRAY; else if (IS_STONE(board[pos]) && countlib(pos) > 4) value |= HIGH_LIBERTY_BIT; persistent_owl_cache[persistent_owl_cache_size].board[pos] = value; } if (debug & DEBUG_OWL_PERSISTENT_CACHE) { gprintf("%o Stored result in cache (entry %d):\n", persistent_owl_cache_size); print_persistent_owl_cache_entry(persistent_owl_cache_size); } persistent_owl_cache_size++; }
int palObs( size_t n, const char * c, char * ident, size_t identlen, char * name, size_t namelen, double * w, double * p, double * h ) { const struct telData telData[] = { /* AAT (Observer's Guide) AAT */ { EAST(149,3,57.91), SOUTH(31,16,37.34), 1164E0, "AAT", "Anglo-Australian 3.9m Telescope" }, /* WHT (Gemini, April 1987) LPO4.2 */ { WEST(17,52,53.9), NORTH(28,45,38.1), 2332E0, "LPO4.2", "William Herschel 4.2m Telescope" }, /* INT (Gemini, April 1987) LPO2.5 */ { WEST(17,52,39.5), NORTH(28,45,43.2), 2336E0, "LPO2.5", "Isaac Newton 2.5m Telescope" }, /* JKT (Gemini, April 1987) LPO1 */ { WEST(17,52,41.2), NORTH(28,45,39.9), 2364E0, "LPO1", "Jacobus Kapteyn 1m Telescope" }, /* Lick 120" (S.L.Allen, private communication, 2002) LICK120 */ { WEST(121,38,13.689), NORTH(37,20,34.931), 1286E0, "LICK120", "Lick 120 inch" }, /* MMT 6.5m conversion (MMT Observatory website) MMT */ { WEST(110,53,4.4), NORTH(31,41,19.6), 2608E0, "MMT", "MMT 6.5m, Mt Hopkins" }, /* Victoria B.C. 1.85m (1984 Almanac) DAO72 */ { WEST(123,25,1.18), NORTH(48,31,11.9), 238E0, "DAO72", "DAO Victoria BC 1.85 metre" }, /* Las Campanas (1983 Almanac) DUPONT */ { WEST(70,42,9.), SOUTH(29,0,11.), 2280E0, "DUPONT", "Du Pont 2.5m Telescope, Las Campanas" }, /* Mt Hopkins 1.5m (1983 Almanac) MTHOP1.5 */ { WEST(110,52,39.00), NORTH(31,40,51.4), 2344E0, "MTHOP1.5", "Mt Hopkins 1.5 metre" }, /* Mt Stromlo 74" (1983 Almanac) STROMLO74 */ { EAST(149,0,27.59), SOUTH(35,19,14.3), 767E0, "STROMLO74", "Mount Stromlo 74 inch" }, /* ANU 2.3m, SSO (Gary Hovey) ANU2.3 */ { EAST(149,3,40.3), SOUTH(31,16,24.1), 1149E0, "ANU2.3", "Siding Spring 2.3 metre" }, /* Greenbank 140' (1983 Almanac) GBVA140 */ { WEST(79,50,9.61), NORTH(38,26,15.4), 881E0, "GBVA140", "Greenbank 140 foot" }, /* Cerro Tololo 4m (1982 Almanac) TOLOLO4M */ { WEST(70,48,53.6), SOUTH(30,9,57.8), 2235E0, "TOLOLO4M", "Cerro Tololo 4 metre" }, /* Cerro Tololo 1.5m (1982 Almanac) TOLOLO1.5M */ { WEST(70,48,54.5), SOUTH(30,9,56.3), 2225E0, "TOLOLO1.5M", "Cerro Tololo 1.5 metre" }, /* Tidbinbilla 64m (1982 Almanac) TIDBINBLA */ { EAST(148,58,48.20), SOUTH(35,24,14.3), 670E0, "TIDBINBLA", "Tidbinbilla 64 metre" }, /* Bloemfontein 1.52m (1981 Almanac) BLOEMF */ { EAST(26,24,18.), SOUTH(29,2,18.), 1387E0, "BLOEMF", "Bloemfontein 1.52 metre" }, /* Bosque Alegre 1.54m (1981 Almanac) BOSQALEGRE */ { WEST(64,32,48.0), SOUTH(31,35,53.), 1250E0, "BOSQALEGRE", "Bosque Alegre 1.54 metre" }, /* USNO 61" astrographic reflector, Flagstaff (1981 Almanac) FLAGSTF61 */ { WEST(111,44,23.6), NORTH(35,11,2.5), 2316E0, "FLAGSTF61", "USNO 61 inch astrograph, Flagstaff" }, /* Lowell 72" (1981 Almanac) LOWELL72 */ { WEST(111,32,9.3), NORTH(35,5,48.6), 2198E0, "LOWELL72", "Perkins 72 inch, Lowell" }, /* Harvard 1.55m (1981 Almanac) HARVARD */ { WEST(71,33,29.32), NORTH(42,30,19.0), 185E0, "HARVARD", "Harvard College Observatory 1.55m" }, /* Okayama 1.88m (1981 Almanac) OKAYAMA */ { EAST(133,35,47.29), NORTH(34,34,26.1), 372E0, "OKAYAMA", "Okayama 1.88 metre" }, /* Kitt Peak Mayall 4m (1981 Almanac) KPNO158 */ { WEST(111,35,57.61), NORTH(31,57,50.3), 2120E0, "KPNO158", "Kitt Peak 158 inch" }, /* Kitt Peak 90 inch (1981 Almanac) KPNO90 */ { WEST(111,35,58.24), NORTH(31,57,46.9), 2071E0, "KPNO90", "Kitt Peak 90 inch" }, /* Kitt Peak 84 inch (1981 Almanac) KPNO84 */ { WEST(111,35,51.56), NORTH(31,57,29.2), 2096E0, "KPNO84", "Kitt Peak 84 inch" }, /* Kitt Peak 36 foot (1981 Almanac) KPNO36FT */ { WEST(111,36,51.12), NORTH(31,57,12.1), 1939E0, "KPNO36FT", "Kitt Peak 36 foot" }, /* Kottamia 74" (1981 Almanac) KOTTAMIA */ { EAST(31,49,30.), NORTH(29,55,54.), 476E0, "KOTTAMIA", "Kottamia 74 inch" }, /* La Silla 3.6m (1981 Almanac) ESO3.6 */ { WEST(70,43,36.), SOUTH(29,15,36.), 2428E0, "ESO3.6", "ESO 3.6 metre" }, /* Mauna Kea 88 inch MAUNAK88 */ /* (IfA website, Richard Wainscoat) */ { WEST(155,28,9.96), NORTH(19,49,22.77), 4213.6E0, "MAUNAK88", "Mauna Kea 88 inch" }, /* UKIRT (IfA website, Richard Wainscoat) UKIRT */ { WEST(155,28,13.18), NORTH(19,49,20.75), 4198.5E0, "UKIRT", "UK Infra Red Telescope" }, /* Quebec 1.6m (1981 Almanac) QUEBEC1.6 */ { WEST(71,9,9.7), NORTH(45,27,20.6), 1114E0, "QUEBEC1.6", "Quebec 1.6 metre" }, /* Mt Ekar 1.82m (1981 Almanac) MTEKAR */ { EAST(11,34,15.), NORTH(45,50,48.), 1365E0, "MTEKAR", "Mt Ekar 1.82 metre" }, /* Mt Lemmon 60" (1981 Almanac) MTLEMMON60 */ { WEST(110,42,16.9), NORTH(32,26,33.9), 2790E0, "MTLEMMON60", "Mt Lemmon 60 inch" }, /* Mt Locke 2.7m (1981 Almanac) MCDONLD2.7 */ { WEST(104,1,17.60), NORTH(30,40,17.7), 2075E0, "MCDONLD2.7", "McDonald 2.7 metre" }, /* Mt Locke 2.1m (1981 Almanac) MCDONLD2.1 */ { WEST(104,1,20.10), NORTH(30,40,17.7), 2075E0, "MCDONLD2.1", "McDonald 2.1 metre" }, /* Palomar 200" (1981 Almanac) PALOMAR200 */ { WEST(116,51,50.), NORTH(33,21,22.), 1706E0, "PALOMAR200", "Palomar 200 inch" }, /* Palomar 60" (1981 Almanac) PALOMAR60 */ { WEST(116,51,31.), NORTH(33,20,56.), 1706E0, "PALOMAR60", "Palomar 60 inch" }, /* David Dunlap 74" (1981 Almanac) DUNLAP74 */ { WEST(79,25,20.), NORTH(43,51,46.), 244E0, "DUNLAP74", "David Dunlap 74 inch" }, /* Haute Provence 1.93m (1981 Almanac) HPROV1.93 */ { EAST(5,42,46.75), NORTH(43,55,53.3), 665E0, "HPROV1.93", "Haute Provence 1.93 metre" }, /* Haute Provence 1.52m (1981 Almanac) HPROV1.52 */ { EAST(5,42,43.82), NORTH(43,56,0.2), 667E0, "HPROV1.52", "Haute Provence 1.52 metre" }, /* San Pedro Martir 83" (1981 Almanac) SANPM83 */ { WEST(115,27,47.), NORTH(31,2,38.), 2830E0, "SANPM83", "San Pedro Martir 83 inch" }, /* Sutherland 74" (1981 Almanac) SAAO74 */ { EAST(20,48,44.3), SOUTH(32,22,43.4), 1771E0, "SAAO74", "Sutherland 74 inch" }, /* Tautenburg 2m (1981 Almanac) TAUTNBG */ { EAST(11,42,45.), NORTH(50,58,51.), 331E0, "TAUTNBG", "Tautenburg 2 metre" }, /* Catalina 61" (1981 Almanac) CATALINA61 */ { WEST(110,43,55.1), NORTH(32,25,0.7), 2510E0, "CATALINA61", "Catalina 61 inch" }, /* Steward 90" (1981 Almanac) STEWARD90 */ { WEST(111,35,58.24), NORTH(31,57,46.9), 2071E0, "STEWARD90", "Steward 90 inch" }, /* Russian 6m (1981 Almanac) USSR6 */ { EAST(41,26,30.0), NORTH(43,39,12.), 2100E0, "USSR6", "USSR 6 metre" }, /* Arecibo 1000' (1981 Almanac) ARECIBO */ { WEST(66,45,11.1), NORTH(18,20,36.6), 496E0, "ARECIBO", "Arecibo 1000 foot" }, /* Cambridge 5km (1981 Almanac) CAMB5KM */ { EAST(0,2,37.23), NORTH(52,10,12.2), 17E0, "CAMB5KM", "Cambridge 5km" }, /* Cambridge 1 mile (1981 Almanac) CAMB1MILE */ { EAST(0,2,21.64), NORTH(52,9,47.3), 17E0, "CAMB1MILE", "Cambridge 1 mile" }, /* Bonn 100m (1981 Almanac) EFFELSBERG */ { EAST(6,53,1.5), NORTH(50,31,28.6), 366E0, "EFFELSBERG", "Effelsberg 100 metre" }, /* Greenbank 300' (1981 Almanac) GBVA300 (R.I.P.) */ { WEST(79,50,56.36), NORTH(38,25,46.3), 894E0, "(R.I.P.)", "Greenbank 300 foot" }, /* Jodrell Bank Mk 1 (1981 Almanac) JODRELL1 */ { WEST(2,18,25.), NORTH(53,14,10.5), 78E0, "JODRELL1", "Jodrell Bank 250 foot" }, /* Australia Telescope Parkes Observatory PARKES */ /* (Peter te Lintel Hekkert) */ { EAST(148,15,44.3591), SOUTH(32,59,59.8657), 391.79E0, "PARKES", "Parkes 64 metre" }, /* VLA (1981 Almanac) VLA */ { WEST(107,37,3.82), NORTH(34,4,43.5), 2124E0, "VLA", "Very Large Array" }, /* Sugar Grove 150' (1981 Almanac) SUGARGROVE */ { WEST(79,16,23.), NORTH(38,31,14.), 705E0, "SUGARGROVE", "Sugar Grove 150 foot" }, /* Russian 600' (1981 Almanac) USSR600 */ { EAST(41,35,25.5), NORTH(43,49,32.), 973E0, "USSR600", "USSR 600 foot" }, /* Nobeyama 45 metre mm dish (based on 1981 Almanac entry) NOBEYAMA */ { EAST(138,29,12.), NORTH(35,56,19.), 1350E0, "NOBEYAMA", "Nobeyama 45 metre" }, /* James Clerk Maxwell 15 metre mm telescope, Mauna Kea JCMT */ /* From GPS measurements on 11Apr2007 for eSMA setup (R. Tilanus) */ { WEST(155,28,37.30), NORTH(19,49,22.22), 4124.75E0, "JCMT", "JCMT 15 metre" }, /* ESO 3.5 metre NTT, La Silla (K.Wirenstrand) ESONTT */ { WEST(70,43,7.), SOUTH(29,15,30.), 2377E0, "ESONTT", "ESO 3.5 metre NTT" }, /* St Andrews University Observatory (1982 Almanac) ST.ANDREWS */ { WEST(2,48,52.5), NORTH(56,20,12.), 30E0, "ST.ANDREWS", "St Andrews" }, /* Apache Point 3.5 metre (R.Owen) APO3.5 */ { WEST(105,49,11.56), NORTH(32,46,48.96), 2809E0, "APO3.5", "Apache Point 3.5m" }, /* W.M.Keck Observatory, Telescope 1 KECK1 */ /* (William Lupton) */ { WEST(155,28,28.99), NORTH(19,49,33.41), 4160E0, "KECK1", "Keck 10m Telescope #1" }, /* Tautenberg Schmidt (1983 Almanac) TAUTSCHM */ { EAST(11,42,45.0), NORTH(50,58,51.0), 331E0, "TAUTSCHM", "Tautenberg 1.34 metre Schmidt" }, /* Palomar Schmidt (1981 Almanac) PALOMAR48 */ { WEST(116,51,32.0), NORTH(33,21,26.0), 1706E0, "PALOMAR48", "Palomar 48-inch Schmidt" }, /* UK Schmidt, Siding Spring (1983 Almanac) UKST */ { EAST(149,4,12.8), SOUTH(31,16,27.8), 1145E0, "UKST", "UK 1.2 metre Schmidt, Siding Spring" }, /* Kiso Schmidt, Japan (1981 Almanac) KISO */ { EAST(137,37,42.2), NORTH(35,47,38.7), 1130E0, "KISO", "Kiso 1.05 metre Schmidt, Japan" }, /* ESO Schmidt, La Silla (1981 Almanac) ESOSCHM */ { WEST(70,43,46.5), SOUTH(29,15,25.8), 2347E0, "ESOSCHM", "ESO 1 metre Schmidt, La Silla" }, /* Australia Telescope Compact Array ATCA */ /* (WGS84 coordinates of Station 35, Mark Calabretta) */ { EAST(149,33,0.500), SOUTH(30,18,46.385), 236.9E0, "ATCA", "Australia Telescope Compact Array" }, /* Australia Telescope Mopra Observatory MOPRA */ /* (Peter te Lintel Hekkert) */ { EAST(149,5,58.732), SOUTH(31,16,4.451), 850E0, "MOPRA", "ATNF Mopra Observatory" }, /* Subaru telescope, Mauna Kea SUBARU */ /* (IfA website, Richard Wainscoat) */ { WEST(155,28,33.67), NORTH(19,49,31.81), 4163E0, "SUBARU", "Subaru 8m telescope" }, /* Canada-France-Hawaii Telescope, Mauna Kea CFHT */ /* (IfA website, Richard Wainscoat) */ { WEST(155,28,7.95), NORTH(19,49,30.91), 4204.1E0, "CFHT", "Canada-France-Hawaii 3.6m Telescope" }, /* W.M.Keck Observatory, Telescope 2 KECK2 */ /* (William Lupton) */ { WEST(155,28,27.24), NORTH(19,49,35.62), 4159.6E0, "KECK2", "Keck 10m Telescope #2" }, /* Gemini North, Mauna Kea GEMININ */ /* (IfA website, Richard Wainscoat) */ { WEST(155,28,8.57), NORTH(19,49,25.69), 4213.4E0, "GEMININ", "Gemini North 8-m telescope" }, /* Five College Radio Astronomy Observatory FCRAO */ /* (Tim Jenness) */ { WEST(72,20,42.0), NORTH(42,23,30.0), 314E0, "FCRAO", "Five College Radio Astronomy Obs" }, /* NASA Infra Red Telescope Facility IRTF */ /* (IfA website, Richard Wainscoat) */ { WEST(155,28,19.20), NORTH(19,49,34.39), 4168.1E0, "IRTF", "NASA IR Telescope Facility, Mauna Kea" }, /* Caltech Submillimeter Observatory CSO */ /* (IfA website, Richard Wainscoat; height estimated) */ { WEST(155,28,31.79), NORTH(19,49,20.78), 4080E0, "CSO", "Caltech Sub-mm Observatory, Mauna Kea" }, /* ESO VLT, UT1 VLT1 */ /* (ESO website, VLT Whitebook Chapter 2) */ { WEST(70,24,11.642), SOUTH(24,37,33.117), 2635.43, "VLT1", "ESO VLT, Paranal, Chile: UT1" }, /* ESO VLT, UT2 VLT2 */ /* (ESO website, VLT Whitebook Chapter 2) */ { WEST(70,24,10.855), SOUTH(24,37,31.465), 2635.43, "VLT2", "ESO VLT, Paranal, Chile: UT2" }, /* ESO VLT, UT3 VLT3 */ /* (ESO website, VLT Whitebook Chapter 2) */ { WEST(70,24,9.896), SOUTH(24,37,30.300), 2635.43, "VLT3", "ESO VLT, Paranal, Chile: UT3" }, /* ESO VLT, UT4 VLT4 */ /* (ESO website, VLT Whitebook Chapter 2) */ { WEST(70,24,8.000), SOUTH(24,37,31.000), 2635.43, "VLT4", "ESO VLT, Paranal, Chile: UT4" }, /* Gemini South, Cerro Pachon GEMINIS */ /* (GPS readings by Patrick Wallace) */ { WEST(70,44,11.5), SOUTH(30,14,26.7), 2738E0, "GEMINIS", "Gemini South 8-m telescope" }, /* Cologne Observatory for Submillimeter Astronomy (KOSMA) KOSMA3M */ /* (Holger Jakob) */ { EAST(7,47,3.48), NORTH(45,58,59.772), 3141E0, "KOSMA3M", "KOSMA 3m telescope, Gornergrat" }, /* Magellan 1, 6.5m telescope at Las Campanas, Chile MAGELLAN1 */ /* (Skip Schaller) */ { WEST(70,41,31.9), SOUTH(29,0,51.7), 2408E0, "MAGELLAN1", "Magellan 1, 6.5m, Las Campanas" }, /* Magellan 2, 6.5m telescope at Las Campanas, Chile MAGELLAN2 */ /* (Skip Schaller) */ { WEST(70,41,33.5), SOUTH(29,0,50.3), 2408E0, "MAGELLAN2", "Magellan 2, 6.5m, Las Campanas" }, /* APEX - Atacama Pathfinder EXperiment, Llano de Chajnantor APEX */ /* (APEX web site) */ { WEST(67,45,33.0), SOUTH(23,0,20.8), 5105E0, "APEX", "APEX 12m telescope, Llano de Chajnantor" }, /* NANTEN2 Submillimeter Observatory, 4m telescope Atacame desert NANTEN2 */ /* (NANTEN2 web site) */ { WEST(67,42,8.0), SOUTH(22,57,47.0), 4865E0, "NANTEN2", "NANTEN2 4m telescope, Pampa la Bola" } }; int retval = -1; /* Return status. 0 if found. -1 if no match */ /* Work out the number of telescopes */ const size_t NTEL = sizeof(telData) / sizeof(struct telData); /* Prefill the return buffer in a pessimistic manner */ star_strellcpy( name, "?", namelen ); if (n > 0) { if (n <= NTEL) { /* Index into telData with correction for zero-based indexing */ struct telData thistel; thistel = telData[n-1]; *w = thistel.w; *p = thistel.p; *h = thistel.h; star_strellcpy( ident, thistel.shortname, identlen ); star_strellcpy( name, thistel.longname, namelen ); retval = 0; } } else { /* Searching */ size_t i; for (i=0; i<NTEL; i++) { struct telData thistel = telData[i]; if (strcasecmp( c, thistel.shortname) == 0) { /* a match */ *w = thistel.w; *p = thistel.p; *h = thistel.h; star_strellcpy( ident, thistel.shortname, identlen ); star_strellcpy( name, thistel.longname, namelen ); retval = 0; break; } } } return retval; }
void getstencil(MatGenFD g, HYPRE_Int ix, HYPRE_Int iy, HYPRE_Int iz) { HYPRE_Int k; double h = g->hh; double hhalf = h*0.5; double x = h*ix; double y = h*iy; double z = h*iz; double cntr = 0.0; double *stencil = g->stencil; double coeff; bool threeD = g->threeD; for (k=0; k<8; ++k) stencil[k] = 0.0; /* differentiation wrt x */ coeff = g->A(g->a, x+hhalf,y,z); EAST(stencil) += coeff; cntr += coeff; coeff = g->A(g->a, x-hhalf,y,z); WEST(stencil) += coeff; cntr += coeff; coeff = g->D(g->d, x,y,z)*hhalf; EAST(stencil) += coeff; WEST(stencil) -= coeff; /* differentiation wrt y */ coeff = g->B(g->b,x,y+hhalf,z); NORTH(stencil) += coeff; cntr += coeff; coeff = g->B(g->b,x,y-hhalf,z); SOUTH(stencil) += coeff; cntr += coeff; coeff = g->E(g->e,x,y,z)*hhalf; NORTH(stencil) += coeff; SOUTH(stencil) -= coeff; /* differentiation wrt z */ if (threeD) { coeff = g->C(g->c,x,y,z+hhalf); BACK(stencil) += coeff; cntr += coeff; coeff = g->C(g->c,x,y,z-hhalf); FRONT(stencil) += coeff; cntr += coeff; coeff = g->F(g->f,x,y,z)*hhalf; BACK(stencil) += coeff; FRONT(stencil) -= coeff; } /* contribution from function G: */ coeff = g->G(g->g,x,y,z); CENTER(stencil) = h*h*coeff - cntr; RHS(stencil) = h*h*g->H(g->h,x,y,z); }
void generateBlocked(MatGenFD mg, HYPRE_Int *rp, HYPRE_Int *cval, double *aval, Mat_dh A, Vec_dh b) { START_FUNC_DH bool applyBdry = true; double *stencil = mg->stencil; HYPRE_Int id = mg->id; bool threeD = mg->threeD; HYPRE_Int px = mg->px, py = mg->py, pz = mg->pz; /* processor grid dimensions */ HYPRE_Int p, q, r; /* this proc's position in processor grid */ HYPRE_Int cc = mg->cc; /* local grid dimension (grid of unknowns) */ HYPRE_Int nx = cc, ny = cc, nz = cc; HYPRE_Int lowerx, upperx, lowery, uppery, lowerz, upperz; HYPRE_Int startRow; HYPRE_Int x, y, z; bool debug = false; HYPRE_Int idx = 0, localRow = 0; /* nabor; */ HYPRE_Int naborx1, naborx2, nabory1, nabory2, naborz1, naborz2; double *rhs; double hhalf = 0.5 * mg->hh; double bcx1 = mg->bcX1; double bcx2 = mg->bcX2; double bcy1 = mg->bcY1; double bcy2 = mg->bcY2; /* double bcz1 = mg->bcZ1; */ /* double bcz2 = mg->bcZ2; */ Vec_dhInit(b, A->m); CHECK_V_ERROR; rhs = b->vals; if (mg->debug && logFile != NULL) debug = true; if (! threeD) nz = 1; /* compute p,q,r from P,Q,R and myid */ p = id % px; q = (( id - p)/px) % py; r = ( id - p - px*q)/( px*py ); if (debug) { hypre_sprintf(msgBuf_dh, "this proc's position in subdomain grid: p= %i q= %i r= %i", p,q,r); SET_INFO(msgBuf_dh); } /* compute ilower and iupper from p,q,r and nx,ny,nz */ /* zero-based */ lowerx = nx*p; upperx = lowerx + nx; lowery = ny*q; uppery = lowery + ny; lowerz = nz*r; upperz = lowerz + nz; if (debug) { hypre_sprintf(msgBuf_dh, "local grid parameters: lowerx= %i upperx= %i", lowerx, upperx); SET_INFO(msgBuf_dh); hypre_sprintf(msgBuf_dh, "local grid parameters: lowery= %i uppery= %i", lowery, uppery); SET_INFO(msgBuf_dh); hypre_sprintf(msgBuf_dh, "local grid parameters: lowerz= %i upperz= %i", lowerz, upperz); SET_INFO(msgBuf_dh); } startRow = mg->first; rp[0] = 0; for (z=lowerz; z<upperz; z++) { for (y=lowery; y<uppery; y++) { for (x=lowerx; x<upperx; x++) { if (debug) { hypre_fprintf(logFile, "row= %i x= %i y= %i z= %i\n", localRow+startRow+1, x, y, z); } /* compute row values and rhs, at the current node */ getstencil(mg,x,y,z); /* down plane */ if (threeD) { if (z > 0) { naborz1 = rownum(threeD, x,y,z-1,nx,ny,nz,px,py); cval[idx] = naborz1; aval[idx++] = FRONT(stencil); } } /* south */ if (y > 0) { nabory1 = rownum(threeD, x,y-1,z,nx,ny,nz,px,py); cval[idx] = nabory1; aval[idx++] = SOUTH(stencil); } /* west */ if (x > 0) { naborx1 = rownum(threeD, x-1,y,z,nx,ny,nz,px,py); cval[idx] = naborx1; aval[idx++] = WEST(stencil); /*hypre_fprintf(logFile, "--- row: %i; naborx1= %i\n", localRow+startRow+1, 1+naborx1); */ } /* else { hypre_fprintf(logFile, "--- row: %i; x >= nx*px-1; naborx1 has old value: %i\n", localRow+startRow+1,1+naborx1); } */ /* center node */ cval[idx] = localRow+startRow; aval[idx++] = CENTER(stencil); /* east */ if (x < nx*px-1) { naborx2 = rownum(threeD,x+1,y,z,nx,ny,nz,px,py); cval[idx] = naborx2; aval[idx++] = EAST(stencil); } /* else { hypre_fprintf(logFile, "--- row: %i; x >= nx*px-1; nobors2 has old value: %i\n", localRow+startRow,1+naborx2); } */ /* north */ if (y < ny*py-1) { nabory2 = rownum(threeD,x,y+1,z,nx,ny,nz,px,py); cval[idx] = nabory2; aval[idx++] = NORTH(stencil); } /* up plane */ if (threeD) { if (z < nz*pz-1) { naborz2 = rownum(threeD,x,y,z+1,nx,ny,nz,px,py); cval[idx] = naborz2; aval[idx++] = BACK(stencil); } } /* rhs[rhsIdx++] = RHS(stencil); */ rhs[localRow] = 0.0; ++localRow; rp[localRow] = idx; /* apply boundary conditions; only for 2D! */ if (!threeD && applyBdry) { HYPRE_Int globalRow = localRow+startRow-1; HYPRE_Int offset = rp[localRow-1]; HYPRE_Int len = rp[localRow] - rp[localRow-1]; double ctr, coeff; /* hypre_fprintf(logFile, "globalRow = %i; naborx2 = %i\n", globalRow+1, naborx2+1); */ if (x == 0) { /* if x1 */ coeff = mg->A(mg->a, x+hhalf,y,z); ctr = mg->A(mg->a, x-hhalf,y,z); setBoundary_private(globalRow, cval+offset, aval+offset, len, &(rhs[localRow-1]), bcx1, coeff, ctr, naborx2); } else if (x == nx*px-1) { /* if x2 */ coeff = mg->A(mg->a, x-hhalf,y,z); ctr = mg->A(mg->a, x+hhalf,y,z); setBoundary_private(globalRow, cval+offset, aval+offset, len, &(rhs[localRow-1]), bcx2, coeff, ctr, naborx1); } else if (y == 0) { /* if y1 */ coeff = mg->B(mg->b, x, y+hhalf,z); ctr = mg->B(mg->b, x, y-hhalf,z); setBoundary_private(globalRow, cval+offset, aval+offset, len, &(rhs[localRow-1]), bcy1, coeff, ctr, nabory2); } else if (y == ny*py-1) { /* if y2 */ coeff = mg->B(mg->b, x, y-hhalf,z); ctr = mg->B(mg->b, x, y+hhalf,z); setBoundary_private(globalRow, cval+offset, aval+offset, len, &(rhs[localRow-1]), bcy2, coeff, ctr, nabory1); } else if (threeD) { if (z == 0) { coeff = mg->B(mg->b, x, y, z+hhalf); ctr = mg->B(mg->b, x, y, z-hhalf); setBoundary_private(globalRow, cval+offset, aval+offset, len, &(rhs[localRow-1]), bcy1, coeff, ctr, naborz2); } else if (z == nz*nx-1) { coeff = mg->B(mg->b, x, y, z-hhalf); ctr = mg->B(mg->b, x, y, z+hhalf); setBoundary_private(globalRow, cval+offset, aval+offset, len, &(rhs[localRow-1]), bcy1, coeff, ctr, naborz1); } } } } } } END_FUNC_DH }
/* Store a new read result in the persistent cache. */ void store_persistent_reading_cache(int routine, int str, int result, int move, int nodes) { char active[BOARDMAX]; int k; int r; int score = nodes; struct reading_cache *entry; ASSERT1(result == 0 || (move == 0) || ON_BOARD(move), move); /* Never cache results at too great depth. */ if (stackp > MAX_READING_CACHE_DEPTH) return; /* If cache is still full, consider kicking out an old entry. */ if (persistent_reading_cache_size == MAX_READING_CACHE_SIZE) { int worst_entry = -1; int worst_score = score; for (k = 1; k < persistent_reading_cache_size; k++) { if (persistent_reading_cache[k].score < worst_score) { worst_score = persistent_reading_cache[k].score; worst_entry = k; } } if (worst_entry != -1) { /* Move the last entry in the cache here to make space. */ if (worst_entry < persistent_reading_cache_size - 1) persistent_reading_cache[worst_entry] = persistent_reading_cache[persistent_reading_cache_size - 1]; persistent_reading_cache_size--; } else return; } entry = &(persistent_reading_cache[persistent_reading_cache_size]); entry->boardsize = board_size; entry->movenum = movenum; entry->nodes = nodes; entry->score = score; entry->remaining_depth = depth - stackp; entry->routine = routine; entry->str = str; entry->result = result; entry->move = move; for (r = 0; r < MAX_READING_CACHE_DEPTH; r++) { if (r < stackp) get_move_from_stack(r, &(entry->stack[r]), &(entry->move_color[r])); else { entry->stack[r] = 0; entry->move_color[r] = EMPTY; } } /* Remains to set the board. We let the active area be the contested * string and reading shadow + adjacent empty and strings + * neighbors of active area so far + one more expansion from empty * to empty. */ for (k = BOARDMIN; k < BOARDMAX; k++) active[k] = shadow[k]; mark_string(str, active, 1); /* To be safe, also add the successful move. */ if (result != 0 && move != 0) active[move] = 1; /* Add adjacent strings and empty. */ for (k = BOARDMIN; k < BOARDMAX; k++) { if (!ON_BOARD(k)) continue; if (active[k] != 0) continue; if ((ON_BOARD(SOUTH(k)) && active[SOUTH(k)] == 1) || (ON_BOARD(WEST(k)) && active[WEST(k)] == 1) || (ON_BOARD(NORTH(k)) && active[NORTH(k)] == 1) || (ON_BOARD(EAST(k)) && active[EAST(k)] == 1)) { if (IS_STONE(board[k])) mark_string(k, active, 2); else active[k] = 2; } } /* Remove invincible strings. No point adding their liberties and * neighbors. */ for (k = BOARDMIN; k < BOARDMAX; k++) { if (!ON_BOARD(k)) continue; if (IS_STONE(board[k]) && worm[k].invincible) active[k] = 0; } /* Expand empty to empty. */ for (k = BOARDMIN; k < BOARDMAX; k++) { if (IS_STONE(board[k]) || active[k] != 0) continue; if ((board[SOUTH(k)] == EMPTY && active[SOUTH(k)] == 2) || (board[WEST(k)] == EMPTY && active[WEST(k)] == 2) || (board[NORTH(k)] == EMPTY && active[NORTH(k)] == 2) || (board[EAST(k)] == EMPTY && active[EAST(k)] == 2)) active[k] = 3; } /* Add neighbors of active area so far. */ for (k = BOARDMIN; k < BOARDMAX; k++) { if (!ON_BOARD(k)) continue; if (active[k] != 0) continue; if ((ON_BOARD(SOUTH(k)) && active[SOUTH(k)] > 0 && active[SOUTH(k)] < 4) || (ON_BOARD(WEST(k)) && active[WEST(k)] > 0 && active[WEST(k)] < 4) || (ON_BOARD(NORTH(k)) && active[NORTH(k)] > 0 && active[NORTH(k)] < 4) || (ON_BOARD(EAST(k)) && active[EAST(k)] > 0 && active[EAST(k)] < 4)) active[k] = 4; } /* Also add the previously played stones to the active area. */ for (r = 0; r < stackp; r++) active[entry->stack[r]] = 5; for (k = BOARDMIN; k < BOARDMAX; k++) { if (!ON_BOARD(k)) continue; entry->board[k] = active[k] != 0 ? board[k] : GRAY; } if (0) { gprintf("%o Stored result in cache (entry %d):\n", persistent_reading_cache_size); print_persistent_reading_cache_entry(persistent_reading_cache_size); gprintf("%o Reading shadow was:\n"); draw_reading_shadow(); } persistent_reading_cache_size++; }
void generateStriped(MatGenFD mg, HYPRE_Int *rp, HYPRE_Int *cval, double *aval, Mat_dh A, Vec_dh b) { START_FUNC_DH HYPRE_Int mGlobal; HYPRE_Int m = mg->m; HYPRE_Int beg_row, end_row; HYPRE_Int i, j, k, row; bool threeD = mg->threeD; HYPRE_Int idx = 0; double *stencil = mg->stencil; bool debug = false; HYPRE_Int plane, nodeRemainder; HYPRE_Int naborx1, naborx2, nabory1, nabory2; double *rhs; bool applyBdry = true; double hhalf; double bcx1 = mg->bcX1; double bcx2 = mg->bcX2; double bcy1 = mg->bcY1; double bcy2 = mg->bcY2; /* double bcz1 = mg->bcZ1; */ /* double bcz2 = mg->bcZ2; */ HYPRE_Int nx, ny; printf_dh("@@@ using striped partitioning\n"); if (mg->debug && logFile != NULL) debug = true; /* recompute values (yuck!) */ m = 9; Parser_dhReadInt(parser_dh,"-m", &m); /* global grid dimension */ mGlobal = m*m; /* global unkknowns */ if (threeD) mGlobal *= m; i = mGlobal/mg->np; /* unknowns per processor */ beg_row = i*mg->id; /* global number of 1st local row */ end_row = beg_row + i; if (mg->id == mg->np-1) end_row = mGlobal; nx = ny = m; mg->hh = 1.0/(m-1); hhalf = 0.5 * mg->hh; A->n = m*m; A->m = end_row - beg_row; A->beg_row = beg_row; Vec_dhInit(b, A->m); CHECK_V_ERROR; rhs = b->vals; plane = m*m; if (debug) { hypre_fprintf(logFile, "generateStriped: beg_row= %i; end_row= %i; m= %i\n", beg_row+1, end_row+1, m); } for (row = beg_row; row<end_row; ++row) { HYPRE_Int localRow = row-beg_row; /* compute current node's position in grid */ k = (row / plane); nodeRemainder = row - (k*plane); /* map row to 1st plane */ j = nodeRemainder / m; i = nodeRemainder % m; if (debug) { hypre_fprintf(logFile, "row= %i x= %i y= %i z= %i\n", row+1, i,j,k); } /* compute column values and rhs entry for the current node */ getstencil(mg,i,j,k); /* only homogenous Dirichlet boundary conditions presently supported */ /* down plane */ if (threeD) { if (k > 0) { cval[idx] = row - plane; aval[idx++] = BACK(stencil); } } /* south */ if (j > 0) { nabory1 = cval[idx] = row - m; aval[idx++] = SOUTH(stencil); } /* west */ if (i > 0) { naborx1 = cval[idx] = row - 1; aval[idx++] = WEST(stencil); } /* center node */ cval[idx] = row; aval[idx++] = CENTER(stencil); /* east */ if (i < m-1) { naborx2 = cval[idx] = row + 1; aval[idx++] = EAST(stencil); } /* north */ if (j < m-1) { nabory2 = cval[idx] = row + m; aval[idx++] = NORTH(stencil); } /* up plane */ if (threeD) { if (k < m-1) { cval[idx] = row + plane; aval[idx++] = FRONT(stencil); } } rhs[localRow] = 0.0; ++localRow; rp[localRow] = idx; /* apply boundary conditions; only for 2D! */ if (!threeD && applyBdry) { HYPRE_Int offset = rp[localRow-1]; HYPRE_Int len = rp[localRow] - rp[localRow-1]; double ctr, coeff; /* hypre_fprintf(logFile, "globalRow = %i; naborx2 = %i\n", row+1, row); */ if (i == 0) { /* if x1 */ coeff = mg->A(mg->a, i+hhalf,j,k); ctr = mg->A(mg->a, i-hhalf,j,k); setBoundary_private(row, cval+offset, aval+offset, len, &(rhs[localRow-1]), bcx1, coeff, ctr, naborx2); } else if (i == nx-1) { /* if x2 */ coeff = mg->A(mg->a, i-hhalf,j,k); ctr = mg->A(mg->a, i+hhalf,j,k); setBoundary_private(row, cval+offset, aval+offset, len, &(rhs[localRow-1]), bcx2, coeff, ctr, naborx1); } else if (j == 0) { /* if y1 */ coeff = mg->B(mg->b, i, j+hhalf,k); ctr = mg->B(mg->b, i, j-hhalf,k); setBoundary_private(row, cval+offset, aval+offset, len, &(rhs[localRow-1]), bcy1, coeff, ctr, nabory2); } else if (j == ny-1) { /* if y2 */ coeff = mg->B(mg->b, i, j-hhalf,k); ctr = mg->B(mg->b, i, j+hhalf,k); setBoundary_private(row, cval+offset, aval+offset, len, &(rhs[localRow-1]), bcy2, coeff, ctr, nabory1); } } } END_FUNC_DH }
/* Computes the active area for the current board position and the * read result that has just been stored in *entry. */ static void compute_active_breakin_area(struct persistent_cache_entry *entry, const char breakin_shadow[BOARDMAX], int dummy) { int pos; int k, r; signed char active[BOARDMAX]; int other = OTHER_COLOR(board[entry->apos]); UNUSED(dummy); /* We let the active area be * the string to connect + * the breakin shadow (which contains the goal) + * distance two expansion through empty intersections and own stones + * adjacent opponent strings + * liberties and neighbors of adjacent opponent strings with less than * five liberties + * liberties and neighbors of low liberty neighbors of adjacent opponent * strings with less than five liberties. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) active[pos] = breakin_shadow[pos]; signed_mark_string(entry->apos, active, 1); /* To be safe, also add the successful move. */ if (entry->result != 0 && entry->move != 0) active[entry->move] = 1; /* Distance two expansion through empty intersections and own stones. */ for (k = 1; k < 3; k++) { for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (!ON_BOARD(pos) || board[pos] == other || active[pos] != 0) continue; if ((ON_BOARD(SOUTH(pos)) && active[SOUTH(pos)] == k) || (ON_BOARD(WEST(pos)) && active[WEST(pos)] == k) || (ON_BOARD(NORTH(pos)) && active[NORTH(pos)] == k) || (ON_BOARD(EAST(pos)) && active[EAST(pos)] == k)) { if (board[pos] == EMPTY) active[pos] = k + 1; else signed_mark_string(pos, active, (signed char) (k + 1)); } } } /* Adjacent opponent strings. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (board[pos] != other || active[pos] != 0) continue; for (r = 0; r < 4; r++) { int pos2 = pos + delta[r]; if (ON_BOARD(pos2) && board[pos2] != other && active[pos2] && active[pos2] <= 2) { signed_mark_string(pos, active, 1); break; } } } /* Liberties of adjacent opponent strings with less than four liberties + * liberties of low liberty neighbors of adjacent opponent strings * with less than five liberties. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (board[pos] == other && active[pos] > 0 && countlib(pos) < 4) { int libs[4]; int liberties = findlib(pos, 3, libs); int adjs[MAXCHAIN]; int adj; for (r = 0; r < liberties; r++) active[libs[r]] = 1; /* Also add liberties of neighbor strings if these are three * or less. */ adj = chainlinks(pos, adjs); for (r = 0; r < adj; r++) { signed_mark_string(adjs[r], active, -1); if (countlib(adjs[r]) <= 3) { int s; int adjs2[MAXCHAIN]; int adj2; liberties = findlib(adjs[r], 3, libs); for (s = 0; s < liberties; s++) active[libs[s]] = 1; adj2 = chainlinks(pos, adjs2); for (s = 0; s < adj2; s++) signed_mark_string(adjs2[s], active, -1); } } } } for (pos = BOARDMIN; pos < BOARDMAX; pos++) { char value = board[pos]; if (!ON_BOARD(pos)) continue; if (!active[pos]) value = GRAY; else if (IS_STONE(board[pos]) && countlib(pos) > 3 && active[pos] > 0) value |= HIGH_LIBERTY_BIT2; entry->board[pos] = value; } }
static void compute_active_reading_area(struct persistent_cache_entry *entry, const char goal[BOARDMAX], int dummy) { signed char active[BOARDMAX]; int pos, r; UNUSED(dummy); /* Remains to set the board. We let the active area be the contested * string and reading shadow + adjacent empty and strings + * neighbors of active area so far + one more expansion from empty * to empty. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) active[pos] = goal[pos]; signed_mark_string(entry->apos, active, 1); /* To be safe, also add the successful move. */ if (entry->result != 0 && entry->move != 0) active[entry->move] = 1; /* Add adjacent strings and empty. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (!ON_BOARD(pos)) continue; if (active[pos] != 0) continue; if ((ON_BOARD(SOUTH(pos)) && active[SOUTH(pos)] == 1) || (ON_BOARD(WEST(pos)) && active[WEST(pos)] == 1) || (ON_BOARD(NORTH(pos)) && active[NORTH(pos)] == 1) || (ON_BOARD(EAST(pos)) && active[EAST(pos)] == 1)) { if (IS_STONE(board[pos])) signed_mark_string(pos, active, 2); else active[pos] = 2; } } /* Remove invincible strings. No point adding their liberties and * neighbors. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (!ON_BOARD(pos)) continue; if (IS_STONE(board[pos]) && worm[pos].invincible) active[pos] = 0; } /* Expand empty to empty. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (IS_STONE(board[pos]) || active[pos] != 0) continue; if ((board[SOUTH(pos)] == EMPTY && active[SOUTH(pos)] == 2) || (board[WEST(pos)] == EMPTY && active[WEST(pos)] == 2) || (board[NORTH(pos)] == EMPTY && active[NORTH(pos)] == 2) || (board[EAST(pos)] == EMPTY && active[EAST(pos)] == 2)) active[pos] = 3; } /* Add neighbors of active area so far. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (!ON_BOARD(pos)) continue; if (active[pos] != 0) continue; if ((ON_BOARD(SOUTH(pos)) && active[SOUTH(pos)] > 0 && active[SOUTH(pos)] < 4) || (ON_BOARD(WEST(pos)) && active[WEST(pos)] > 0 && active[WEST(pos)] < 4) || (ON_BOARD(NORTH(pos)) && active[NORTH(pos)] > 0 && active[NORTH(pos)] < 4) || (ON_BOARD(EAST(pos)) && active[EAST(pos)] > 0 && active[EAST(pos)] < 4)) active[pos] = 4; } /* Also add the previously played stones to the active area. */ for (r = 0; r < stackp; r++) active[entry->stack[r]] = 5; for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (!ON_BOARD(pos)) continue; entry->board[pos] = active[pos] != 0 ? board[pos] : GRAY; } }
static void compute_active_owl_area(struct persistent_cache_entry *entry, const char goal[BOARDMAX], int goal_color) { int k, r; int pos; int other = OTHER_COLOR(goal_color); signed char active[BOARDMAX]; /* We let the active area be the goal + * distance four expansion through empty intersections and own stones + * adjacent opponent strings + * liberties and neighbors of adjacent opponent strings with less than * five liberties + * liberties and neighbors of low liberty neighbors of adjacent opponent * strings with less than five liberties. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) if (ON_BOARD(pos)) active[pos] = (goal[pos] != 0); /* Also add critical moves to the active area. */ if (ON_BOARD1(entry->move)) active[entry->move] = 1; if (ON_BOARD1(entry->move2)) active[entry->move2] = 1; /* Distance four expansion through empty intersections and own stones. */ for (k = 1; k < 5; k++) { for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (!ON_BOARD(pos) || board[pos] == other || active[pos] > 0) continue; if ((ON_BOARD(SOUTH(pos)) && active[SOUTH(pos)] == k) || (ON_BOARD(WEST(pos)) && active[WEST(pos)] == k) || (ON_BOARD(NORTH(pos)) && active[NORTH(pos)] == k) || (ON_BOARD(EAST(pos)) && active[EAST(pos)] == k)) { if (board[pos] == EMPTY) active[pos] = k + 1; else signed_mark_string(pos, active, (signed char) (k + 1)); } } } /* Adjacent opponent strings. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (board[pos] != other || active[pos] != 0) continue; for (r = 0; r < 4; r++) { int pos2 = pos + delta[r]; if (ON_BOARD(pos2) && board[pos2] != other && active[pos2] != 0) { signed_mark_string(pos, active, 1); break; } } } /* Liberties of adjacent opponent strings with less than five liberties + * liberties of low liberty neighbors of adjacent opponent strings * with less than five liberties. */ for (pos = BOARDMIN; pos < BOARDMAX; pos++) { if (board[pos] == other && active[pos] > 0 && countlib(pos) < 5) { int libs[4]; int liberties = findlib(pos, 4, libs); int adjs[MAXCHAIN]; int adj; for (r = 0; r < liberties; r++) active[libs[r]] = 1; /* Also add liberties of neighbor strings if these are three * or less. */ adj = chainlinks(pos, adjs); for (r = 0; r < adj; r++) { signed_mark_string(adjs[r], active, -1); if (countlib(adjs[r]) <= 3) { int s; int adjs2[MAXCHAIN]; int adj2; liberties = findlib(adjs[r], 3, libs); for (s = 0; s < liberties; s++) active[libs[s]] = 1; adj2 = chainlinks(pos, adjs2); for (s = 0; s < adj2; s++) signed_mark_string(adjs2[s], active, -1); } } } } for (pos = BOARDMIN; pos < BOARDMAX; pos++) { int value = board[pos]; if (!ON_BOARD(pos)) continue; if (!active[pos]) value = GRAY; else if (IS_STONE(board[pos]) && countlib(pos) > 4 && active[pos] > 0) value |= HIGH_LIBERTY_BIT; entry->board[pos] = value; } }
int CompressMoves::compress_move( thc::Move mv, char *storage ) { int nbr_bytes=1; int code=0; int src = mv.src; int dst = mv.dst; int captured_sq = cr.squares[dst]<'A' ? -1 : dst; Tracker *pt = trackers[src]; int tracker_id = pt->tracker_id; char piece = pt->piece; switch( mv.special ) { case thc::NOT_SPECIAL: case thc::SPECIAL_BPAWN_2SQUARES: case thc::SPECIAL_WPAWN_2SQUARES: case thc::SPECIAL_KING_MOVE: default: { break; } case thc::SPECIAL_WK_CASTLING: { code = CODE_K_SPECIAL_WK_CASTLING; Tracker *rook = &white_pieces[TI_KR]; rook->sq = thc::f1; trackers[thc::f1] = rook; trackers[thc::h1] = NULL; break; } case thc::SPECIAL_BK_CASTLING: { code = CODE_K_SPECIAL_BK_CASTLING; Tracker *rook = &black_pieces[TI_KR]; rook->sq = thc::f8; trackers[thc::f8] = rook; trackers[thc::h8] = NULL; break; } case thc::SPECIAL_WQ_CASTLING: { code = CODE_K_SPECIAL_WQ_CASTLING; Tracker *rook = &white_pieces[TI_QR]; rook->sq = thc::d1; trackers[thc::d1] = rook; trackers[thc::a1] = NULL; break; } case thc::SPECIAL_BQ_CASTLING: { code = CODE_K_SPECIAL_BQ_CASTLING; Tracker *rook = &black_pieces[TI_QR]; rook->sq = thc::d8; trackers[thc::d8] = rook; trackers[thc::a8] = NULL; break; } case thc::SPECIAL_PROMOTION_QUEEN: { code = CODE_SPECIAL_PROMOTION_QUEEN; pt->piece = cr.white ? 'Q' : 'q'; Tracker *shadow = (cr.white ? &white_pieces[15] : &black_pieces[15]); for( int i=0; i<16; i++,shadow-- ) { if( !shadow->in_use ) { pt->shadow_rook = shadow; shadow->in_use = true; shadow->shadow_owner = pt; shadow->piece = cr.white ? 'R' : 'r'; // shadow is a phantom rook, handles rank and file moves for new queen break; // shadow successfully found, if no shadow available queen move might need two bytes } } break; } case thc::SPECIAL_PROMOTION_ROOK: { code = CODE_SPECIAL_PROMOTION_ROOK; pt->piece = cr.white ? 'R' : 'r'; break; } case thc::SPECIAL_PROMOTION_BISHOP: { code = CODE_SPECIAL_PROMOTION_BISHOP; pt->piece = cr.white ? 'B' : 'b'; break; } case thc::SPECIAL_PROMOTION_KNIGHT: { code = CODE_SPECIAL_PROMOTION_KNIGHT; pt->piece = cr.white ? 'N' : 'n'; break; } case thc::SPECIAL_WEN_PASSANT: { captured_sq = SOUTH(dst); break; } case thc::SPECIAL_BEN_PASSANT: { captured_sq = NORTH(dst); break; } } switch( piece ) { case 'P': { if( src-dst == 16 ) code = 3; // 2 square advance else code += (src-dst-7); // 9\,8| or 7/ -> 2,1 or 0 = NW,N,NE // Note += because may already have CODE_SPECIAL_PROMOTION_QUEEN etc break; } case 'p': { if( dst-src == 16 ) code = 3; // 2 square advance else code += (dst-src-7); // 9\,8| or 7/ -> 2,1 or 0 = SE,S,SW // Note += because may already have CODE_SPECIAL_PROMOTION_QUEEN etc break; } case 'K': case 'k': { switch( src-dst ) { case 9: code = CODE_K_VECTOR_0; break; // 9\ FALL case 8: code = CODE_K_VECTOR_1; break; // 8| case 7: code = CODE_K_VECTOR_2; break; // 7/ case 1: code = CODE_K_VECTOR_3; break; // 1- case -1: code = CODE_K_VECTOR_4; break; case -7: code = CODE_K_VECTOR_5; break; case -8: code = CODE_K_VECTOR_6; break; case -9: code = CODE_K_VECTOR_7; break; } } case 'N': case 'n': { switch( src-dst ) { case 17: code = CODE_N_VECTOR_0; break; case 15: code = CODE_N_VECTOR_1; break; case 10: code = CODE_N_VECTOR_2; break; case 6: code = CODE_N_VECTOR_3; break; case -17: code = CODE_N_VECTOR_4; break; case -15: code = CODE_N_VECTOR_5; break; case -10: code = CODE_N_VECTOR_6; break; case -6: code = CODE_N_VECTOR_7; break; } break; } case 'r': case 'R': { if( (src&7) == (dst&7) ) // same file ? code = CODE_SAME_FILE + ((dst>>3) & 7); // yes, so encode new rank else code = dst & 7; // no, so encode new file break; } case 'b': case 'B': { int abs = (src>dst ? src-dst : dst-src); if( abs%9 == 0 ) // do 9 first, as LCD of 9 and 7 is 63, i.e. diff between a8 and h1, a FALL\ diagonal { code = CODE_FALL + (dst&7); // fall( = \) + dst file } else // if abs%7 == 0 { code = (dst&7); // rise( = /) + dst file } break; } case 'q': case 'Q': { if( (src&7) == (dst&7) ) // same file ? { if( pt->shadow_rook ) { code = CODE_SAME_FILE + ((dst>>3)&7); // yes encode rank tracker_id = pt->shadow_rook->tracker_id; } else if( pt->shadow_rank ) { code = CODE_N_SHADOW + ((dst>>3)&7); // shadow knight encodes rank tracker_id = pt->shadow_rank->tracker_id; }
enum plugin_status plugin_start (const void *parameter) { int btn; rb->mkdir (DEFAULT_SAVE_DIR); global_setup (); #ifdef GBN_TEST run_tests (); return PLUGIN_OK; #endif if (!(parameter && load_game (parameter))) { if (parameter) { rb->splashf (2 * HZ, "Loading %s failed.", (char *) parameter); } if (!load_game (DEFAULT_SAVE)) { rb->strcpy (save_file, DEFAULT_SAVE); if (!setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, 0)) { return PLUGIN_ERROR; } } } else { /* game loaded */ if (rb->strcmp (save_file, DEFAULT_SAVE)) { /* delete the scratch file if we loaded a game and it wasn't * from the scratch file */ rb->remove (DEFAULT_SAVE); } } draw_screen_display (); autosave_counter = 0; for (;;) { btn = rb->button_get_w_tmo (HZ * 30); if (disable_shutdown) { /* tell rockbox we're not idle */ rb->reset_poweroff_timer (); } bool is_idle = false; switch (btn) { #if defined(GBN_BUTTON_NAV_MODE) case GBN_BUTTON_NAV_MODE: case GBN_BUTTON_NAV_MODE | BUTTON_REPEAT: if (nav_mode == NAV_MODE_TREE) { nav_mode = NAV_MODE_BOARD; rb->splash (2 * HZ / 3, "board navigation mode"); draw_screen_display (); } else { nav_mode = NAV_MODE_TREE; rb->splash (2 * HZ / 3, "tree navigation mode"); draw_screen_display (); } break; #endif #if defined(GBN_BUTTON_ADVANCE) case GBN_BUTTON_ADVANCE: case GBN_BUTTON_ADVANCE | BUTTON_REPEAT: if (has_more_nodes_sgf ()) { if (!redo_node_sgf ()) { rb->splash (2 * HZ, "redo failed"); } draw_screen_display (); } break; #endif #if defined(GBN_BUTTON_RETREAT) case GBN_BUTTON_RETREAT: case GBN_BUTTON_RETREAT | BUTTON_REPEAT: if (has_prev_nodes_sgf ()) { if (!undo_node_sgf ()) { rb->splash (3 * HZ / 2, "Undo Failed"); } draw_screen_display (); } break; #endif case GBN_BUTTON_PLAY: if (play_mode == MODE_PLAY || play_mode == MODE_FORCE_PLAY) { if (!play_move_sgf (cursor_pos, current_player)) { rb->splash (HZ / 3, "Illegal Move"); } } else if (play_mode == MODE_ADD_BLACK) { if (!add_stone_sgf (cursor_pos, BLACK)) { rb->splash (HZ / 3, "Illegal"); } } else if (play_mode == MODE_ADD_WHITE) { if (!add_stone_sgf (cursor_pos, WHITE)) { rb->splash (HZ / 3, "Illegal"); } } else if (play_mode == MODE_REMOVE) { if (!add_stone_sgf (cursor_pos, EMPTY)) { rb->splash (HZ / 3, "Illegal"); } } else if (play_mode == MODE_MARK) { if (!add_mark_sgf (cursor_pos, PROP_MARK)) { rb->splash (HZ / 3, "Couldn't Mark"); } } else if (play_mode == MODE_CIRCLE) { if (!add_mark_sgf (cursor_pos, PROP_CIRCLE)) { rb->splash (HZ / 3, "Couldn't Mark"); } } else if (play_mode == MODE_SQUARE) { if (!add_mark_sgf (cursor_pos, PROP_SQUARE)) { rb->splash (HZ / 3, "Couldn't Mark"); } } else if (play_mode == MODE_TRIANGLE) { if (!add_mark_sgf (cursor_pos, PROP_TRIANGLE)) { rb->splash (HZ / 3, "Couldn't Mark"); } } else if (play_mode == MODE_LABEL) { if (!add_mark_sgf (cursor_pos, PROP_LABEL)) { rb->splash (HZ / 3, "Couldn't Label"); } } else { rb->splash (HZ, "mode not implemented"); } draw_screen_display (); break; case GBN_BUTTON_RIGHT: case GBN_BUTTON_RIGHT | BUTTON_REPEAT: #if defined(GBN_BUTTON_NAV_MODE) if (nav_mode == NAV_MODE_TREE) { if (has_more_nodes_sgf ()) { if (!redo_node_sgf ()) { rb->splash (2 * HZ, "Redo Failed"); } draw_screen_display (); } } else { #endif cursor_pos = WRAP (EAST (cursor_pos)); draw_screen_display (); #if defined(GBN_BUTTON_NAV_MODE) } #endif break; case GBN_BUTTON_LEFT: case GBN_BUTTON_LEFT | BUTTON_REPEAT: #if defined(GBN_BUTTON_NAV_MODE) if (nav_mode == NAV_MODE_TREE) { if (has_prev_nodes_sgf ()) { if (!undo_node_sgf ()) { rb->splash (2 * HZ, "Undo Failed"); } draw_screen_display (); } } else { #endif cursor_pos = WRAP (WEST (cursor_pos)); draw_screen_display (); #if defined(GBN_BUTTON_NAV_MODE) } #endif break; case GBN_BUTTON_DOWN: case GBN_BUTTON_DOWN | BUTTON_REPEAT: cursor_pos = WRAP (SOUTH (cursor_pos)); draw_screen_display (); break; case GBN_BUTTON_UP: case GBN_BUTTON_UP | BUTTON_REPEAT: cursor_pos = WRAP (NORTH (cursor_pos)); draw_screen_display (); break; case GBN_BUTTON_MENU: if (do_main_menu ()) { save_game (DEFAULT_SAVE); global_cleanup (); return PLUGIN_OK; } draw_screen_display (); break; #if defined(GBN_BUTTON_CONTEXT) case GBN_BUTTON_CONTEXT: do_context_menu (); draw_screen_display (); break; #endif #if defined(GBN_BUTTON_NEXT_VAR) case GBN_BUTTON_NEXT_VAR: case GBN_BUTTON_NEXT_VAR | BUTTON_REPEAT: { int temp; if ((temp = next_variation_sgf ()) >= 0) { draw_screen_display (); rb->splashf (2 * HZ / 3, "%d of %d", temp, num_variations_sgf ()); draw_screen_display (); } else { if (num_variations_sgf () > 1) { rb->splashf (HZ, "Error %d in next_variation_sgf", temp); } draw_screen_display (); } break; } #endif case BUTTON_NONE: is_idle = true; default: if (rb->default_event_handler (btn) == SYS_USB_CONNECTED) { return PLUGIN_USB_CONNECTED; } break; }; if (is_idle && autosave_dirty) { ++autosave_counter; if (autosave_time != 0 && autosave_counter / 2 >= autosave_time) /* counter is in 30 second increments, autosave_time is in * minutes */ { DEBUGF("autosaving\n"); rb->splash(HZ / 4, "Autosaving..."); save_game(DEFAULT_SAVE); draw_screen_display(); autosave_counter = 0; } } else { autosave_counter = 0; } } return PLUGIN_OK; }