void CopyMove(struct Move* moveDst,struct Move* moveSrc){ CopyBoard(moveDst->board_after_move, moveSrc->board_after_move); moveDst->dst = moveSrc->dst; moveDst->src = moveSrc->src; moveDst->prev = moveSrc->prev; moveDst->next = moveSrc->next; moveDst->promotion = moveSrc->promotion; }
void ClearGame(GAME *Game, const BOARD *StartBoard) { if (StartBoard == NULL) { ClearBoard(Game->StartBoard); } else { CopyBoard(StartBoard,Game->StartBoard); } CopyBoard(Game->StartBoard,Game->Board); Game->MoveNo = 0; Game->Move[0].Move = NO_MOVE; ElapsedTime[0] = 0.0; ElapsedTime[1] = 0.0; TurnBegin = CurrentTime(); }
void GotoGameMove(GAME *Game, int MoveNo) { CopyBoard(Game->StartBoard,Game->Board); if (RestoreClocks) ElapsedTime[0] = ElapsedTime[1] = 0.0; for (Game->MoveNo = 0; Game->MoveNo < MoveNo && Game->Move[Game->MoveNo].Move != NO_MOVE; Game->MoveNo++) { if (RestoreClocks) ElapsedTime[Game->Board->Colour>0] += Game->Move[Game->MoveNo].Time; DoMove(Game->Board,Game->Move[Game->MoveNo].Move); } TurnBegin = CurrentTime(); }
// Leaf expansion. // ============================= Expansion Related ================================== static BOOL send_to_cnn(ThreadInfo *info, TreeBlock *b, const Board *board) { // Send the current player to CNN for evaluation. // Check if someone else has sent it. TreeHandle *s = info->s; info->cnn_send_infunc ++; // If BIT_CNN_TRY_SEND has been set to 1, then someone else is sending the board, then we return. if (cnn_data_fetch_set_evaluated_bit(&b->cnn_data, BIT_CNN_TRY_SEND)) return FALSE; // Otherwise we got the token and send. if (b->cnn_data.seq == s->seq && cnn_data_get_evaluated_bit(&b->cnn_data, BIT_CNN_SENT)) { PRINT_DEBUG("b = %lx (%u) is already sent to the server, do not send again!\n", (uint64_t)b, ID(b)); cnn_data_clear_evaluated_bit(&b->cnn_data, BIT_CNN_TRY_SEND); return FALSE; } // If the sequence number is out-of-date, we just clear it. if (b->cnn_data.seq != s->seq) cnn_data_clear_evaluated_bit(&b->cnn_data, BIT_CNN_SENT); // Send the message. MBoard mboard; mboard.b = (uint64_t) b; mboard.seq = s->seq; CopyBoard(&mboard.board, board); /* ShowBoard(&mboard.board, SHOW_LAST_MOVE); if (info->cnn_send_infunc == 2) { exit(0); } */ info->cnn_send_attempt ++; b->cnn_data.seq = s->seq; cnn_data_set_evaluated_bit(&b->cnn_data, BIT_CNN_SENT); if (s->callbacks.callback_send_board(s->callbacks.context, info->ex_id, &mboard)) { // Note that in asynchronized version, Ideally, setting BIT_CNN_SENT and ExLocalClientSendBoard should be in the critical region. // Otherwise the board might get sent twice. But it should not harm too much. // Save the sent sequence. info->cnn_send_success ++; // Clear the evaluation TRY_SEND bit so that other people can enter the critical session. cnn_data_clear_evaluated_bit(&b->cnn_data, BIT_CNN_TRY_SEND); return TRUE; } else { cnn_data_clear_evaluated_bit(&b->cnn_data, BIT_CNN_SENT); // Release the token so that other thread can resend. cnn_data_clear_evaluated_bit(&b->cnn_data, BIT_CNN_TRY_SEND); return FALSE; } }
struct Move* createMove(int x, int y, int i, int j, char some_board[BOARD_SIZE][BOARD_SIZE], char promotion){ struct Move* newMove = calloc(1,sizeof(struct Move)); moveLeaks++; newMove->dst.x = i; newMove->dst.y = j; newMove->src.x = x; newMove->src.y = y; CopyBoard(newMove->board_after_move, some_board); newMove->board_after_move[i][j] = newMove->board_after_move[x][y]; newMove->board_after_move[x][y] = EMPTY; newMove->next = NULL; newMove->prev = NULL; if (promotion != NULL){ newMove->board_after_move[i][j] = promotion; } return newMove; }
// Fast rollout default policy. // For now we will just omit Region *r and max_depth, and simulate until the end of game. DefPolicyMove fast_rollout_def_policy(void *def_policy, void *context, RandFunc rand_func, Board* board, const Region *r, int max_depth, BOOL verbose) { if (verbose) printf("Init fast rollout def policy!\n"); void *be = PatternV2InitBoardExtra(def_policy, board); SampleSummary summary; if (verbose) printf("Start sampling.\n"); PatternV2SampleUntil(be, context, rand_func, NULL, &summary); if (verbose) printf("Copying final board back.\n"); CopyBoard(board, PatternV2GetBoard(be)); if (verbose) printf("Clean up.\n"); PatternV2DestroyBoardExtra(be); // Return the last move. DefPolicyMove move = { .m = board->_last_move, .gamma = 0, .type = NORMAL, .game_ended = IsGameEnd(board) }; return move; }
char *GetCaptureText(enum ChessPiece board[8][8], char *longmove) { char *letters = "abcdefgh"; char *numbers = "87654321"; char *pieces = "oPNBRQKpnbrqk"; char *submove; char txt[512]; enum ChessPiece tempboard[8][8]; txt[0] = '\0'; submove = strdup(longmove); /* filter for castling */ if (strlen(longmove) == 9 && longmove[4] == ' ') { int x1, y1, x2, y2; x1 = (int)(strchr(letters, longmove[0]) - letters); y1 = (int)(strchr(numbers, longmove[1]) - numbers); x2 = (int)(strchr(letters, longmove[5]) - letters); y2 = (int)(strchr(numbers, longmove[6]) - numbers); if ((board[x1][y1] == CP_WKING && board[x2][y2] == CP_WROOK) || (board[x1][y1] == CP_WROOK && board[x2][y2] == CP_WKING) || (board[x1][y1] == CP_BKING && board[x2][y2] == CP_BROOK) || (board[x1][y1] == CP_WROOK && board[x2][y2] == CP_WKING)) { return ""; } } CopyBoard(board, tempboard); do { char *space = strchr(submove, ' '); int x, y, len; enum ChessPiece captured; if (space) { len = space - submove; *space = '\0'; } else { len = strlen(submove); } if (len == 3) { x = (int)(strchr(letters, submove[0]) - letters); y = (int)(strchr(numbers, submove[1]) - numbers); } else { x = (int)(strchr(letters, submove[2]) - letters); y = (int)(strchr(numbers, submove[3]) - numbers); } captured = tempboard[x][y]; if (tempboard[x][y] != CP_NONE) { strncat(txt, &(pieces[captured]), 1); strncat(txt, &(letters[x]), 1); strncat(txt, &(numbers[y]), 1); } ExecuteMove(tempboard, submove, 0, NULL, NULL); if (space) { submove = space + 1; } else { submove = NULL; } } while (submove && *submove); return strdup(txt); }
int IsMoveLegal(enum ChessPiece board[8][8], int oldx, int oldy, int newx, int newy, enum ChessCastling *castling, char **enpassanttarget) { enum ChessPiece tempboard[8][8]; char *letters = "abcdefgh"; char *numbers = "87654321"; char move[5]; int iswhitemove = IsPieceWhite(board[oldx][oldy]); if (CanPieceMoveHere(board, oldx, oldy, newx, newy, castling, enpassanttarget)) { /* is this a castling move? Then check the intermediate square */ if (oldx == 4 && oldy == 7 && newy == 7 && (newx == 6 || newx == 2) && board[oldx][oldy] == CP_WKING) { CopyBoard(board, tempboard); if (newx == 6) { strcpy(move, "e8f8"); ExecuteMove(tempboard, move, 0, NULL, NULL); if (!IsPositionLegal(tempboard, !iswhitemove)) { return 0; } } if (newx == 2) { strcpy(move, "e8d8"); ExecuteMove(tempboard, move, 0, NULL, NULL); if (!IsPositionLegal(tempboard, !iswhitemove)) { return 0; } } } if (oldx == 4 && oldy == 7 && newy == 0 && (newx == 6 || newx == 2) && board[oldx][oldy] == CP_BKING) { CopyBoard(board, tempboard); if (newx == 6) { strcpy(move, "e1f1"); ExecuteMove(tempboard, move, 0, NULL, NULL); if (!IsPositionLegal(tempboard, !iswhitemove)) { return 0; } } if (newx == 2) { strcpy(move, "e1d1"); ExecuteMove(tempboard, move, 0, NULL, NULL); if (!IsPositionLegal(tempboard, !iswhitemove)) { return 0; } } } CopyBoard(board, tempboard); move[0] = letters[oldx]; move[1] = numbers[oldy]; move[2] = letters[newx]; move[3] = numbers[newy]; move[4] = '\0'; ExecuteMove(tempboard, move, 0, NULL, NULL); return IsPositionLegal(tempboard, !iswhitemove); } return 0; }
/* Build the list of games in the open file f. * Returns 0 for success or error number. */ int GameListBuild (FILE *f) { ChessMove cm, lastStart; int gameNumber; ListGame *currentListGame = NULL; int error, scratch=100, plyNr=0, fromX, fromY, toX, toY; int offset; char lastComment[MSG_SIZ], buf[MSG_SIZ]; TimeMark t, t2; GetTimeMark(&t); GameListFree(&gameList); yynewfile(f); gameNumber = 0; movePtr = 0; lastStart = (ChessMove) 0; yyskipmoves = FALSE; do { yyboardindex = scratch; offset = yyoffset(); quickFlag = plyNr + 1; cm = (ChessMove) Myylex(); switch (cm) { case GNUChessGame: if ((error = GameListNewGame(¤tListGame))) { rewind(f); yyskipmoves = FALSE; return(error); } currentListGame->number = ++gameNumber; currentListGame->offset = offset; if(1) { CopyBoard(boards[scratch], initialPosition); plyNr = 0; currentListGame->moves = PackGame(boards[scratch]); } if (currentListGame->gameInfo.event != NULL) { free(currentListGame->gameInfo.event); } currentListGame->gameInfo.event = StrSave(yy_text); lastStart = cm; break; case XBoardGame: lastStart = cm; break; case MoveNumberOne: switch (lastStart) { case GNUChessGame: break; /* ignore */ case PGNTag: lastStart = cm; break; /* Already started */ case (ChessMove) 0: case MoveNumberOne: case XBoardGame: if ((error = GameListNewGame(¤tListGame))) { rewind(f); yyskipmoves = FALSE; return(error); } currentListGame->number = ++gameNumber; currentListGame->offset = offset; if(1) { CopyBoard(boards[scratch], initialPosition); plyNr = 0; currentListGame->moves = PackGame(boards[scratch]); } lastStart = cm; break; default: break; /* impossible */ } break; case PGNTag: lastStart = cm; if ((error = GameListNewGame(¤tListGame))) { rewind(f); yyskipmoves = FALSE; return(error); } currentListGame->number = ++gameNumber; currentListGame->offset = offset; ParsePGNTag(yy_text, ¤tListGame->gameInfo); do { yyboardindex = 1; offset = yyoffset(); cm = (ChessMove) Myylex(); if (cm == PGNTag) { ParsePGNTag(yy_text, ¤tListGame->gameInfo); } } while (cm == PGNTag || cm == Comment); if(1) { int btm=0; if(currentListGame->gameInfo.fen) ParseFEN(boards[scratch], &btm, currentListGame->gameInfo.fen, FALSE); else CopyBoard(boards[scratch], initialPosition); plyNr = (btm != 0); currentListGame->moves = PackGame(boards[scratch]); } if(cm != NormalMove) break; case IllegalMove: if(appData.testLegality) break; case NormalMove: /* Allow the first game to start with an unnumbered move */ yyskipmoves = FALSE; if (lastStart == (ChessMove) 0) { if ((error = GameListNewGame(¤tListGame))) { rewind(f); yyskipmoves = FALSE; return(error); } currentListGame->number = ++gameNumber; currentListGame->offset = offset; if(1) { CopyBoard(boards[scratch], initialPosition); plyNr = 0; currentListGame->moves = PackGame(boards[scratch]); } lastStart = MoveNumberOne; } case WhiteCapturesEnPassant: case BlackCapturesEnPassant: case WhitePromotion: case BlackPromotion: case WhiteNonPromotion: case BlackNonPromotion: case WhiteKingSideCastle: case WhiteQueenSideCastle: case BlackKingSideCastle: case BlackQueenSideCastle: case WhiteKingSideCastleWild: case WhiteQueenSideCastleWild: case BlackKingSideCastleWild: case BlackQueenSideCastleWild: case WhiteHSideCastleFR: case WhiteASideCastleFR: case BlackHSideCastleFR: case BlackASideCastleFR: fromX = currentMoveString[0] - AAA; fromY = currentMoveString[1] - ONE; toX = currentMoveString[2] - AAA; toY = currentMoveString[3] - ONE; plyNr++; ApplyMove(fromX, fromY, toX, toY, currentMoveString[4], boards[scratch]); if(currentListGame && currentListGame->moves) PackMove(fromX, fromY, toX, toY, boards[scratch][toY][toX]); break; case WhiteWins: // [HGM] rescom: save last comment as result details case BlackWins: case GameIsDrawn: case GameUnfinished: if(!currentListGame) break; if(currentListGame->gameInfo.result == GameUnfinished) currentListGame->gameInfo.result = cm; // correct result tag with actual result if (currentListGame->gameInfo.resultDetails != NULL) { free(currentListGame->gameInfo.resultDetails); } if(yy_text[0] == '{') { char *p; safeStrCpy(lastComment, yy_text+1, sizeof(lastComment)/sizeof(lastComment[0])); if((p = strchr(lastComment, '}'))) *p = 0; currentListGame->gameInfo.resultDetails = StrSave(lastComment); } break; default: break; } if(gameNumber % 1000 == 0) { snprintf(buf, MSG_SIZ, _("Reading game file (%d)"), gameNumber); DisplayTitle(buf); DoEvents(); } } while (cm != (ChessMove) 0); if(currentListGame) { if(!currentListGame->moves) DisplayError("Game cache overflowed\nPosition-searching might not work properly", 0); if (appData.debugMode) { for (currentListGame = (ListGame *) gameList.head; currentListGame->node.succ; currentListGame = (ListGame *) currentListGame->node.succ) { fprintf(debugFP, "Parsed game number %d, offset %ld:\n", currentListGame->number, currentListGame->offset); PrintPGNTags(debugFP, ¤tListGame->gameInfo); } } } if(appData.debugMode) { GetTimeMark(&t2);printf("GameListBuild %ld msec\n", SubtractTimeMarks(&t2,&t)); } quickFlag = 0; PackGame(boards[scratch]); // for appending end-of-game marker. DisplayTitle("WinBoard"); rewind(f); yyskipmoves = FALSE; return 0; }
static bool middle_ladder_walk(Board *b, Board *bset, group_t laddered, Coord nextmove, Stone lcolor) { assert(group_at(b, laddered)->liberties == 1); /* First, escape. */ /* if (DEBUGL(6)) fprintf(stderr, " ladder escape %s\n", coord2sstr(nextmove, b)); */ GroupId4 ids; if (!TryPlay2(b, nextmove, &ids)) error("The play should never be wrong!"); Play(b, &ids); // laddered = group_at(b, laddered); /* if (DEBUGL(8)) { board_print(b, stderr); fprintf(stderr, "%s c %d\n", coord2sstr(laddered, b), board_group_info(b, laddered).libs); } */ int laddered_libs = b->_groups[laddered].liberties; if (laddered_libs == 1) { /* if (DEBUGL(6)) fprintf(stderr, "* we can capture now\n"); */ return true; } if (laddered_libs > 2) { /* if (DEBUGL(6)) fprintf(stderr, "* we are free now\n"); */ return false; } FOR4(nextmove, _, c) { if (board_at(b, c) == OPPONENT(lcolor) && group_at(b, c)->liberties == 1) { /* We can capture one of the ladder stones * anytime later. */ /* XXX: If we were very lucky, capturing * this stone will not help us escape. * That should be pretty rate. */ /* if (DEBUGL(6)) fprintf(stderr, "* can capture chaser\n"); */ return false; } } ENDFOR4 /* Now, consider alternatives. */ int liblist[2], libs = 0; Coord tmp_libs[2]; get_nlibs_of_group(b, laddered, 2, tmp_libs); for (int i = 0; i < 2; i++) { Coord ataristone = tmp_libs[i]; Coord escape = tmp_libs[1 - i]; if (immediate_liberty_count(b, escape) > 2 + NEIGHBOR4(ataristone, escape)) { /* Too much free space, ignore. */ continue; } liblist[libs++] = i; } /* Try out the alternatives. */ bool is_ladder = false; for (int i = 0; !is_ladder && i < libs; i++) { Board *b2 = b; if (i != libs - 1) { b2 = bset++; CopyBoard(b2, b); } Coord libs_b2[2]; get_nlibs_of_group(b2, laddered, 2, libs_b2); Coord ataristone = libs_b2[liblist[i]]; // Coord escape = board_group_info(b2, laddered).lib[1 - liblist[i]]; struct move m = { ataristone, OPPONENT(lcolor) }; bool play_successful = TryPlay2(b2, ataristone, &ids); if (play_successful) Play(b2, &ids); /* If we just played self-atari, abandon ship. */ /* XXX: If we were very lucky, capturing this stone will * not help us escape. That should be pretty rate. */ /* if (DEBUGL(6)) fprintf(stderr, "(%d=%d) ladder atari %s (%d libs)\n", i, res, coord2sstr(ataristone, b2), board_group_info(b2, group_at(b2, ataristone)).libs); */ if (play_successful && group_at(b2, ataristone)->liberties > 1) { Coord last_lib = get_nlibs_of_group(b2, laddered, 1, NULL); is_ladder = middle_ladder_walk(b2, bset, laddered, last_lib, lcolor); } /* Why we need to do deallocation? if (i != libs - 1) { board_done_noalloc(b2); } */ } /* if (DEBUGL(6)) fprintf(stderr, "propagating %d\n", is_ladder); */ return is_ladder; }
bool is_middle_ladder(Board *b, Coord coord, group_t laddered, Stone lcolor) { /* TODO: Remove the redundant parameters. */ assert(group_at(b, laddered)->liberties == 1); Coord last_lib = get_nlibs_of_group(b, laddered, 1, NULL); assert(last_lib == coord); assert(group_at(b, laddered)->color == lcolor); /* If we can move into empty space or do not have enough space * to escape, this is obviously not a ladder. */ if (immediate_liberty_count(b, coord) != 2) { /* if (DEBUGL(5)) fprintf(stderr, "no ladder, wrong free space\n"); */ return false; } /* A fair chance for a ladder. Group in atari, with some but limited * space to escape. Time for the expensive stuff - set up a temporary * board and start selective 2-liberty search. */ Board *bset = (Board *)malloc(BOARD_MAX_SIZE * 2 * sizeof(Board)); struct move_queue ccq = { .moves = 0 }; if (can_countercapture(b, lcolor, laddered, lcolor, &ccq, 0)) { /* We could escape by countercapturing a group. * Investigate. */ assert(ccq.moves > 0); for (unsigned int i = 0; i < ccq.moves; i++) { Board b2; CopyBoard(&b2, b); bool is_ladder = middle_ladder_walk(&b2, bset, laddered, ccq.move[i], lcolor); // board_done_noalloc(&b2); if (!is_ladder) { free(bset); return false; } } } Board b2; CopyBoard(&b2, b); Coord last_lib2 = get_nlibs_of_group(&b2, laddered, 1, NULL); bool is_ladder = middle_ladder_walk(&b2, bset, laddered, last_lib2, lcolor); // board_done_noalloc(&b2); free(bset); return is_ladder; } bool wouldbe_ladder(Board *b, group_t group, Coord escapelib, Coord chaselib, Stone lcolor) { assert(b->_groups[group].liberties == 2); assert(b->_groups[group].color == lcolor); /* if (DEBUGL(6)) fprintf(stderr, "would-be ladder check - does %s %s play out chasing move %s?\n", stone2str(lcolor), coord2sstr(escapelib, b), coord2sstr(chaselib, b)); */ if (!NEIGHBOR8(escapelib, chaselib)) { /* if (DEBUGL(5)) fprintf(stderr, "cannot determine ladder for remote simulated stone\n"); */ return false; } if (neighbor_count_at(b, chaselib, lcolor) != 1 || immediate_liberty_count(b, chaselib) != 2) { /* if (DEBUGL(5)) fprintf(stderr, "overly trivial for a ladder\n"); */ return false; } bool is_ladder = false; Board *bset = (Board *)malloc(BOARD_MAX_SIZE * 2 * sizeof(Board)); Board b2; CopyBoard(&b2, b); GroupId4 ids; if (TryPlay(&b2, X(chaselib), Y(chaselib), OPPONENT(lcolor), &ids)) { Play(&b2, &ids); Coord last_lib2 = get_nlibs_of_group(&b2, group, 1, NULL); is_ladder = middle_ladder_walk(&b2, bset, group, last_lib2, lcolor); } // board_done_noalloc(&b2); free(bset); return is_ladder; }