void test_board_clear() { puts("test_board_clear"); struct board pos; board_clear(&pos); assert((pos.occupied_co[0] | pos.occupied_co[1]) == 0); assert(pos.turn == true); }
struct board * board_init(char *fbookfile) { struct board *b = malloc2(sizeof(struct board)); board_setup(b); b->fbookfile = fbookfile; // Default setup b->size = 9 + 2; board_clear(b); return b; }
void test_board_shredder_fen() { puts("test_board_shredder_fen"); struct board pos; char fen[255]; board_reset(&pos); board_shredder_fen(&pos, fen); assert(strcmp(fen, "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w HAha - 0 1") == 0); board_clear(&pos); board_set_piece_at(&pos, SQ_D1, kQueen, kWhite); board_set_piece_at(&pos, SQ_D8, kQueen, kBlack); board_shredder_fen(&pos, fen); assert(strcmp(fen, "3q4/8/8/8/8/8/8/3Q4 w - - 0 1") == 0); }
/* 主程序,控制游戏流程。 */ int main (int argc, char * argv[]) { int put; int in_x,in_y; int judge=0; /*显示欢迎语句,清空并显示棋盘。*/ printf ("Welcome to play!\n"); board_clear(); board_display(); while (1)//主循环,由内部break语句控制退出。或许有更好的处理方式。 { /*用户输入落子坐标*/ scanf("%d",&in_x); scanf("%d",&in_y); printf("your input number is x=%d, y=%d\n",in_x,in_y); /*调用落子函数,由用户落下一子*/ //这里,落子函数接受的有效坐标为0~2,为了照顾人类习惯,人类输入的坐标有效值为1~3,在此转换 board_put(in_x-1,in_y-1,USER); /*用户落子后显示棋盘*/ board_display(); /*判断是否取胜*/ judge=board_judge(); if (judge!=0)//如果取胜,打印并退出 { printf("User %d win!\n",judge); break; } /*有AI计算落子位置*/ put=ai_think(&in_x,&in_y); printf("AI put: x=%d,y=%d\n",in_x,in_y); /*调用落子函数,由AI落下一子*/ board_put(in_x,in_y,AI); /*AI落子后显示棋盘*/ board_display(); /*判断是否取胜*/ judge=board_judge(); if (judge!=0)//如果取胜,打印并退出 { printf("User %d win!\n",judge); break; } } return 0; }
void board_from_fen(board_t * board, const char fen[]) { int pos; int file, rank, sq; int c; int i, len; int piece; int pawn; ASSERT(board!=NULL); ASSERT(fen!=NULL); board_clear(board); pos = 0; c = fen[pos]; // piece placement for (rank = Rank8; rank >= Rank1; rank--) { for (file = FileA; file <= FileH;) { if (c >= '1' && c <= '8') { // empty square(s) len = c - '0'; for (i = 0; i < len; i++) { if (file > FileH) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); board->square[SQUARE_MAKE(file,rank)] = Empty; file++; } } else { // piece piece = piece_from_char(c); if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); board->square[SQUARE_MAKE(file,rank)] = piece; file++; } c = fen[++pos]; } if (rank > Rank1) { if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; } } // active colour if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; switch (c) { case 'w': board->turn = White; break; case 'b': board->turn = Black; break; default: my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); break; } c = fen[++pos]; // castling if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; board->flags = FlagsNone; if (c == '-') { // no castling rights c = fen[++pos]; } else { if (c == 'K') { if (board->square[E1] == WK && board->square[H1] == WR) board->flags |= FlagsWhiteKingCastle; c = fen[++pos]; } if (c == 'Q') { if (board->square[E1] == WK && board->square[A1] == WR) board->flags |= FlagsWhiteQueenCastle; c = fen[++pos]; } if (c == 'k') { if (board->square[E8] == BK && board->square[H8] == BR) board->flags |= FlagsBlackKingCastle; c = fen[++pos]; } if (c == 'q') { if (board->square[E8] == BK && board->square[A8] == BR) board->flags |= FlagsBlackQueenCastle; c = fen[++pos]; } } // en-passant if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = fen[++pos]; if (c == '-') { // no en-passant sq = SquareNone; c = fen[++pos]; } else { if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); file = file_from_char(c); c = fen[++pos]; if (c != (COLOUR_IS_WHITE(board->turn) ? '6' : '3')) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); rank = rank_from_char(c); c = fen[++pos]; sq = SQUARE_MAKE(file,rank); pawn = SQUARE_EP_DUAL(sq); if (board->square[sq] != Empty || board->square[pawn] != PAWN_MAKE(COLOUR_OPP(board->turn)) || (board->square[pawn-1] != PAWN_MAKE(board->turn) && board->square[pawn+1] != PAWN_MAKE(board->turn))) { sq = SquareNone; } } board->ep_square = sq; // halfmove clock board->ply_nb = 0; if (c != ' ') { if (!Strict) goto update; my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); } c = fen[++pos]; if (!isdigit(c)) { if (!Strict) goto update; my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); } board->ply_nb = atoi(&fen[pos]); // board update update: board_init_list(board); }
void game_loop() { board_t a = {0}; board_t b = {0}; board_t *cur; board_t *next; int input; int AI_input; int score = 0; cur = &a; next = &b; board_rnd_gen_cell(*cur); while (1) { clear(); /* Draw the board */ board_dump(*cur, 4, 8); // stat_dump(); /* AI computation */ if (auto_play || suggestion) { AI_input = get_AI_input(*cur); const char *move_text[] = {"Left", "Right", "Up", "Down", "Game Over"}; mvprintw(1, 8, "Suggest: %s", move_text[AI_input]); } mvprintw(2, 8, "Score: %d", score); /* Update screen */ refresh(); /* Get input */ if (auto_play) { input = AI_input; } else { input = get_keyboard_input(); } int moved = 0; switch(input) { case UP: moved = move_up(*cur, *next); break; case LEFT: moved = move_left(*cur, *next); break; case DOWN: moved = move_down(*cur, *next); break; case RIGHT: moved = move_right(*cur, *next); break; case QUIT: return; default: continue; } if (!moved) continue; if (moved != 1) score += moved; /* Generate new cell */ board_rnd_gen_cell(*next); /* Switch cur and next */ board_t *temp = cur; cur = next; next = temp; board_clear(*next); } }
bool board_from_fen(board_t * board, const char string[]) { int pos; int file, rank, sq; int c; int i, len; int piece; int king_pos[ColourNb]; ASSERT(board!=NULL); ASSERT(string!=NULL); board_clear(board); king_pos[White] = SquareNone; king_pos[Black] = SquareNone; pos = 0; c = string[pos]; // piece placement for (rank = 7; rank >= 0; rank--) { for (file = 0; file < 8;) { sq = square_make(file,rank); if (c >= '1' && c <= '8') { // empty square(s) len = c - '0'; if (file + len > 8) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); for (i = 0; i < len; i++) { board->square[sq++] = Empty; file++; } } else { // piece piece = piece_from_char(c); if (piece == PieceNone256) my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); if (piece_is_king(piece)) king_pos[piece_colour(piece)] = sq; board->square[sq++] = piece; file++; } c = string[++pos]; } if (rank > 0) { if (c != '/') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = string[++pos]; } } // active colour if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = string[++pos]; switch (c) { case 'w': board->turn = White; break; case 'b': board->turn = Black; break; default: my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); break; } c = string[++pos]; // castling if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = string[++pos]; board->castle[White][SideH] = SquareNone; board->castle[White][SideA] = SquareNone; board->castle[Black][SideH] = SquareNone; board->castle[Black][SideA] = SquareNone; if (c == '-') { // no castling rights c = string[++pos]; } else { // TODO: filter out illegal rights do { if (false) { } else if (c == 'K') { for (sq = H1; sq > king_pos[White]; sq--) { if (board->square[sq] == WhiteRook256) { board->castle[White][SideH] = sq; break; } } } else if (c == 'Q') { for (sq = A1; sq < king_pos[White]; sq++) { if (board->square[sq] == WhiteRook256) { board->castle[White][SideA] = sq; break; } } } else if (c == 'k') { for (sq = H8; sq > king_pos[Black]; sq--) { if (board->square[sq] == BlackRook256) { board->castle[Black][SideH] = sq; break; } } } else if (c == 'q') { for (sq = A8; sq < king_pos[Black]; sq++) { if (board->square[sq] == BlackRook256) { board->castle[Black][SideA] = sq; break; } } } else if (c >= 'A' && c <= 'H') { // white castling right sq = square_make(file_from_char(tolower(c)),Rank1); if (sq > king_pos[White]) { // h side board->castle[White][SideH] = sq; } else { // a side board->castle[White][SideA] = sq; } } else if (c >= 'a' && c <= 'h') { // black castling right sq = square_make(file_from_char(tolower(c)),Rank8); if (sq > king_pos[Black]) { // h side board->castle[Black][SideH] = sq; } else { // a side board->castle[Black][SideA] = sq; } } else { my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); } c = string[++pos]; } while (c != ' '); } // en-passant if (c != ' ') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); c = string[++pos]; if (c == '-') { // no en-passant sq = SquareNone; c = string[++pos]; } else { if (c < 'a' || c > 'h') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); file = file_from_char(c); c = string[++pos]; if (c < '1' || c > '8') my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); rank = rank_from_char(c); c = string[++pos]; sq = square_make(file,rank); } board->ep_square = sq; // halfmove clock board->ply_nb = 0; board->move_nb = 0; // HACK, in case of broken syntax if (c != ' ') { if (!Strict) goto update; my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); } c = string[++pos]; if (!isdigit(c)) { if (!Strict) goto update; my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); } board->ply_nb = atoi(&string[pos]); do c = string[++pos]; while (isdigit(c)); // fullmove number board->move_nb = 0; if (c != ' ') { if (!Strict) goto update; my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); } c = string[++pos]; if (!isdigit(c)) { if (!Strict) goto update; my_fatal("board_from_fen(): bad FEN (pos=%d)\n",pos); } board->move_nb = atoi(&string[pos]) - 1; do c = string[++pos]; while (isdigit(c)); // board update update: board_init_list(board); return true; }
struct fbook * fbook_init(char *filename, struct board *b) { if (fbcache && fbcache->bsize == board_size(b) && fbcache->handicap == b->handicap) return fbcache; FILE *f = fopen(filename, "r"); if (!f) { perror(filename); return NULL; } struct fbook *fbook = calloc(1, sizeof(*fbook)); fbook->bsize = board_size(b); fbook->handicap = b->handicap; /* We do not set handicap=1 in case of too low komi on purpose; * we want to go with the no-handicap fbook for now. */ for (int i = 0; i < 1<<fbook_hash_bits; i++) fbook->moves[i] = pass; if (DEBUGL(1)) fprintf(stderr, "Loading opening fbook %s...\n", filename); /* Scratch board where we lay out the sequence; * one for each transposition. */ struct board *bs[8]; for (int i = 0; i < 8; i++) { bs[i] = board_init(NULL); board_resize(bs[i], fbook->bsize - 2); } char linebuf[1024]; while (fgets(linebuf, sizeof(linebuf), f)) { char *line = linebuf; linebuf[strlen(linebuf) - 1] = 0; // chop /* Format of line is: * BSIZE COORD COORD COORD... | COORD * BSIZE/HANDI COORD COORD COORD... | COORD * We descend up to |, then add the new node * with value minimax(1000), forcing UCT to * always pick that node immediately. */ int bsize = strtol(line, &line, 10); if (bsize != fbook->bsize - 2) continue; int handi = 0; if (*line == '/') { line++; handi = strtol(line, &line, 10); } if (handi != fbook->handicap) continue; while (isspace(*line)) line++; for (int i = 0; i < 8; i++) { board_clear(bs[i]); bs[i]->last_move.color = S_WHITE; } while (*line != '|') { coord_t *c = str2coord(line, fbook->bsize); for (int i = 0; i < 8; i++) { coord_t coord = coord_transform(b, *c, i); struct move m = { .coord = coord, .color = stone_other(bs[i]->last_move.color) }; int ret = board_play(bs[i], &m); assert(ret >= 0); } coord_done(c); while (!isspace(*line)) line++; while (isspace(*line)) line++; } line++; while (isspace(*line)) line++; /* In case of multiple candidates, pick one with * exponentially decreasing likelihood. */ while (strchr(line, ' ') && fast_random(2)) { line = strchr(line, ' '); while (isspace(*line)) line++; // fprintf(stderr, "<%s> skip to %s\n", linebuf, line); } coord_t *c = str2coord(line, fbook->bsize); for (int i = 0; i < 8; i++) { coord_t coord = coord_transform(b, *c, i); #if 0 char conflict = is_pass(fbook->moves[bs[i]->hash & fbook_hash_mask]) ? '+' : 'C'; if (conflict == 'C') for (int j = 0; j < i; j++) if (bs[i]->hash == bs[j]->hash) conflict = '+'; if (conflict == 'C') { hash_t hi = bs[i]->hash; while (!is_pass(fbook->moves[hi & fbook_hash_mask]) && fbook->hashes[hi & fbook_hash_mask] != bs[i]->hash) hi++; if (fbook->hashes[hi & fbook_hash_mask] == bs[i]->hash) hi = 'c'; } fprintf(stderr, "%c %"PRIhash":%"PRIhash" (<%d> %s)\n", conflict, bs[i]->hash & fbook_hash_mask, bs[i]->hash, i, linebuf); #endif hash_t hi = bs[i]->hash; while (!is_pass(fbook->moves[hi & fbook_hash_mask]) && fbook->hashes[hi & fbook_hash_mask] != bs[i]->hash) hi++; fbook->moves[hi & fbook_hash_mask] = coord; fbook->hashes[hi & fbook_hash_mask] = bs[i]->hash; fbook->movecnt++; } coord_done(c); } for (int i = 0; i < 8; i++) { board_done(bs[i]); } fclose(f); if (!fbook->movecnt) { /* Empty book is not worth the hassle. */ fbook_done(fbook); return NULL; } struct fbook *fbold = fbcache; fbcache = fbook; if (fbold) fbook_done(fbold); return fbook; } void fbook_done(struct fbook *fbook) { if (fbook != fbcache) free(fbook); }
static void board_load(struct board *b, FILE *f, unsigned int size) { board_printed = false; board_resize(b, size); board_clear(b); for (int y = size - 1; y >= 0; y--) { char line[256]; if (!fgets(line, sizeof(line), f)) { fprintf(stderr, "Premature EOF.\n"); exit(EXIT_FAILURE); } line[strlen(line) - 1] = 0; // chomp if (strlen(line) != size * 2 - 1) { fprintf(stderr, "Line not %d char long: %s\n", size * 2 - 1, line); exit(EXIT_FAILURE); } for (unsigned int i = 0; i < size * 2; i++) { enum stone s; switch (line[i]) { case '.': s = S_NONE; break; case 'X': s = S_BLACK; break; case 'O': s = S_WHITE; break; default: fprintf(stderr, "Invalid stone '%c'\n", line[i]); exit(EXIT_FAILURE); } i++; if (line[i] != ' ' && i/2 < size - 1) { fprintf(stderr, "No space after stone %i: '%c'\n", i/2 + 1, line[i]); exit(EXIT_FAILURE); } if (s == S_NONE) continue; struct move m = { .color = s, .coord = coord_xy(b, i/2 + 1, y + 1) }; if (board_play(b, &m) < 0) { fprintf(stderr, "Failed to play %s %s\n", stone2str(s), coord2sstr(m.coord, b)); board_print(b, stderr); exit(EXIT_FAILURE); } } } int suicides = b->captures[S_BLACK] || b->captures[S_WHITE]; assert(!suicides); } static void set_ko(struct board *b, char *arg) { assert(isalpha(*arg)); struct move last; last.coord = str2scoord(arg, board_size(b)); last.color = board_at(b, last.coord); assert(last.color == S_BLACK || last.color == S_WHITE); b->last_move = last; /* Sanity checks */ group_t g = group_at(b, last.coord); assert(board_group_info(b, g).libs == 1); assert(group_stone_count(b, g, 2) == 1); coord_t lib = board_group_info(b, g).lib[0]; assert(board_is_eyelike(b, lib, last.color)); b->ko.coord = lib; b->ko.color = stone_other(last.color); }