Пример #1
0
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);
}
Пример #2
0
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;
}
Пример #3
0
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);
}
Пример #4
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;
}
Пример #5
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);
}
Пример #6
0
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);
    }

}
Пример #7
0
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;
}
Пример #8
0
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);
}
Пример #9
0
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);
}