#include "go.h"
#define neighbor_count_at(ban, pos, color2) \
((ban->color[pos + D2DELTA[1]] == color2) + \
(ban->color[pos + D2DELTA[3]] == color2) + \
(ban->color[pos + D2DELTA[5]] == color2) + \
(ban->color[pos + D2DELTA[7]] == color2))
int outPos(const int pos)
{
fprintf(stderr, "(%d %d)", POS_TO_X(pos), POS_TO_Y(pos));
return 0;
}
int judgeKoNG(const int pos, goban_t *ban)
{
history_t *histInfo = &ban->histInfo[ban->tesuu - 1];
assert (ban->tesuu >= 1);
return (pos == histInfo->ko);
}
/* not judging KO ng move*/
int teOK(const int xy, goban_t *ban)
{
const int color = TBN2COLOR(ban->tbn);
int d;
if (xy == 0)
return 1;
if (IN_RANGE(0, xy, XY_SIZE - 1) && ban->color[xy] == SP){
for (d = 1; d < D_MAX; d += 2){ /* cross */
const int pos = xy + D2DELTA[d];
const int renID = ban->renID[pos];
const int colorD = ban->color[pos];
if (colorD == SP){
return 1;
}
if (colorD == color && ban->renInfo[renID].breathPoints > 1){
return 1;
}
if (colorD == GET_AITE(color) && ban->renInfo[renID].breathPoints == 1){
return 1;
}
}
}
return 0;
}
/* REQUIRE : ban->color[pos] == SP
合法手でなければ NG
合法手でも、四方を味方石で囲まれた位置は、
取られそうな場合(味方の呼吸点1の連に接する手)を除き NG (return 0),
そうでなければ return 1; */
int judge_eff_te(const int pos, goban_t *ban)
{
const int colorAite = GET_AITE(TBN2COLOR(ban->tbn));
int d, tgt, colorD;
if (neighbor_count_at(ban, pos, SP) >= 1){
return 1;
}
if (!teOK(pos, ban) || judgeKoNG(pos, ban)){
return 0;
}
for (d = 1; d < D_MAX; d += 2){
tgt = pos + D2DELTA[d];
colorD = ban->color[tgt];
if (colorD == OB)
continue;
if (colorD == SP || colorD == colorAite){
return 1;
}
if (ban->renInfo[ban->renID[tgt]].breathPoints == 1){
return 1;
}
}
return 0;
}
void writeBan(goban_t *ban)
{
int x, y;
for (x = 1; x <= BOARD_EDGE_SIZE; x++){
fprintf(stderr, "%.1s", &COLOR_NAME[ban->color[x]]);
}
fprintf(stderr, "\n [");
for (x = 1; x <= BOARD_EDGE_SIZE; x++){
fprintf(stderr, "%2d", x);
}
fprintf(stderr, "]\n");
for (y = 1; y <= BOARD_EDGE_SIZE ; y++){
fprintf(stderr, "[%2d] ", y);
for (x = 1; x <= BOARD_EDGE_SIZE; x++){
fprintf(stderr, "%.1s ", &COLOR_NAME[ban->color[X_Y_TO_POS(x, y)]]);
}
fprintf(stderr, "\n");
}
fprintf(stderr, "tbn = %.1s, tesuu = %d, bk: %d, wh: %d prev: %.1s",
&COLOR_NAME[ban->tbn + 1], ban->tesuu, ban->prisoner[TBN_BK], ban->prisoner[TBN_WH], &COLOR_NAME[GET_AITE(ban->tbn + 1)]);
outPos(ban->histInfo[ban->tesuu - 1].pos);
return;
}
#define LEADING_ONES(x) ((1ULL << (x)) - 1ULL)
int get_around_bb(bb_t *aroundBB, bb_t *inBB)
{
int k;
for (k = 0; k < BB_IDX_SIZE; k++){
aroundBB[k] =
(inBB[k] >> 1ULL) | (inBB[k] >> BB_EDGE)
| ((inBB[k] & LEADING_ONES(NUM_PER_BB - 1)) << 1ULL)
| ((inBB[k] & LEADING_ONES(NUM_PER_BB - BB_EDGE)) << BB_EDGE);
if (k < BB_IDX_SIZE - 1 && inBB[k + 1]){
aroundBB[k] |=
((inBB[k + 1] & LEADING_ONES(BB_EDGE)) << (NUM_PER_BB - BB_EDGE))
| ((inBB[k + 1] & LEADING_ONES(1)) << (NUM_PER_BB - 1));
}
if (k > 0 && inBB[k - 1]){
aroundBB[k] |=
(inBB[k - 1] >> (NUM_PER_BB - BB_EDGE))
|(inBB[k - 1] >> (NUM_PER_BB - 1));
}
}
return 0;
}
int is_danger_around(goban_t *ban, bb_t *target_occupiedBB, const int check_tbn)
{
int k, target;
bb_t aroundBB[BB_IDX_SIZE], bit;
get_around_bb(aroundBB, target_occupiedBB);
for (k = 0; k < BB_IDX_SIZE; k++){
for (bit = aroundBB[k] & ban->occupiedBB[check_tbn][k]; bit; bit &= (bit - 1)){
target = GET_POS(k, Get_FirstBit64(bit));
if (ban->renInfo[ban->renID[target]].breathPoints == 1){
return 1;
}
}
}
return 0;
}
int detect_suicide_or_capture(goban_t *ban, const int pos)
{
int d;
bb_t breathBB[BB_IDX_SIZE];
CLEAR_BB(breathBB);
ADD_AN_ELEMENT_TO_BB(breathBB, pos);
for (d = 1; d < D_MAX; d += 2){ /* CROSS */
const int target = pos + D2DELTA[d];
if (ban->color[target] == SP){
ADD_AN_ELEMENT_TO_BB(breathBB, target);
}
if (ban->color[target] == TBN2COLOR(ban->tbn)){
renInfo_t *renInfo2 = &ban->renInfo[ban->renID[target]];
MERGE_BB(breathBB, renInfo2->breathBB);
}
if (ban->color[target] == GET_AITE(TBN2COLOR(ban->tbn))){
renInfo_t *renInfo2 = &ban->renInfo[ban->renID[target]];
if (renInfo2->breathPoints == 1){ /* capture */
return 1;
}
}
}
int breathPoints = bb_pop_cnt(breathBB);
if (breathPoints >= 3){
return 0;
}
assert (breathPoints == 2);
return 1;
}
int check_kill(const int seme, const int escape, goban_t *ban)
{
const int prePos = ban->histInfo[ban->tesuu - 1].pos;
int res = 0;
assert (seme && escape);// && ban->color[seme] == SP && ban->color[escape] == SP);
if (!teOK(seme, ban)|| judgeKoNG(seme, ban) || detect_suicide_or_capture(ban, seme)){
return 0;
}
make_move(seme, ban);
renInfo_t *renInfo = &ban->renInfo[ban->renID[seme]];
if (renInfo->breathPoints >= 2 &&
check_dead(escape, ban)){
// semeの直前の相手石の連の、周囲の石(つまりsemeの方)を取られないかをcheck
renInfo_t *renInfo2 = &ban->renInfo[ban->renID[prePos]];
if (is_danger_around(ban, renInfo2->occupiedBB, AITE_TBN(ban->tbn))){
res = 0;
} else {
res = 1;
}
}
unmake_move(ban);
return res;
}
int check_dead(const int pos, goban_t *ban)
{
int res = 0, k, cand[2];
if (ban->tesuu >= TESUU_MAX - 2){
return 0;
}
make_move(pos, ban);
renInfo_t *renInfo = &ban->renInfo[ban->renID[pos]];
res = (renInfo->breathPoints == 1);
if (renInfo->breathPoints == 2){
get_double_pos(cand, renInfo->breathBB);
for (k = 0; k < 2; k++){
if (res == OFF){
res = check_kill(cand[k], cand[1 - k], ban);
}
}
}
unmake_move(ban);
return res;
}
int get_nb_stones(const int pos, int nb_num[4], int nb_stones[4][4], goban_t *ban)
{
int d, tgt, colorD;
assert(IN_RANGE(1, POS_TO_X(pos), BOARD_EDGE_SIZE) && IN_RANGE(1, POS_TO_Y(pos), BOARD_EDGE_SIZE));
nb_num[0] = nb_num[1] = nb_num[2] =nb_num[3] = 0;
for (d = 1; d < D_MAX; d += 2){ /* cross */
tgt = pos + D2DELTA[d];
colorD = ban->color[tgt];
nb_stones[colorD][nb_num[colorD]++] = tgt;
}
return 0;
}
int bb_pop_cnt(bb_t *targetBB)
{
int k, cnt = 0;
for (k = 0; k < BB_IDX_SIZE; k++)
cnt += pop_cnt(targetBB[k]);
return cnt;
}
int get_double_pos(int *cand, bb_t *targetBB)
{
int k, cnt = 0;
unsigned long long bit;
assert(bb_pop_cnt(targetBB) == 2);
for (k = 0; k < BB_IDX_SIZE; k++){
for (bit = targetBB[k]; bit; bit &= (bit - 1)){
cand[cnt++] = GET_POS(k, Get_FirstBit64(bit));
}
}
return 0;
}
int get_single_pos(bb_t *targetBB)
{
int k;
for (k = 0; k < BB_IDX_SIZE; k++){
if (targetBB[k]){
return GET_POS(k, Get_FirstBit64(targetBB[k]));
}
}
return 0;
}
int get_another_pos(bb_t *targetBB, const int exclude)
{
int cand[2];
get_double_pos(cand, targetBB);
if (cand[0] == exclude){
return cand[1];
} else {
return cand[0];
}
return 0;
}
double Tool_GetTimeNow()
{
return clock()/(double)(CLOCKS_PER_SEC);
}