| 601 | } |
| 602 | |
| 603 | void getPosition(bool startThink) |
| 604 | { |
| 605 | board->newGame(options.rule); |
| 606 | options.multiPV = 1; |
| 607 | options.balanceMode = Search::SearchOptions::BALANCE_NONE; |
| 608 | |
| 609 | // Read position sequence |
| 610 | enum SideFlag { SELF = 1, OPPO = 2, WALL = 3 }; |
| 611 | std::vector<std::pair<Pos, SideFlag>> position; |
| 612 | |
| 613 | while (true) { |
| 614 | std::string coordStr; |
| 615 | std::cin >> coordStr; |
| 616 | upperInplace(coordStr); |
| 617 | |
| 618 | if (coordStr == "DONE" || std::cin.eof()) |
| 619 | break; |
| 620 | |
| 621 | std::optional<Pos> pos; |
| 622 | int color = -1; |
| 623 | { |
| 624 | std::stringstream ss; |
| 625 | char comma; |
| 626 | ss << coordStr; |
| 627 | pos = parseLegalCoord(ss, *board); |
| 628 | ss >> comma >> color; |
| 629 | } |
| 630 | |
| 631 | if (pos.has_value()) { |
| 632 | if (color == SELF || color == OPPO || color == WALL && *pos != Pos::NONE) |
| 633 | position.emplace_back(*pos, static_cast<SideFlag>(color)); |
| 634 | else |
| 635 | ERRORL("Color is not a valid value, must be one of [1, 2, 3]."); |
| 636 | } |
| 637 | } |
| 638 | |
| 639 | // The first move (either real move or pass) is always considered as BLACK |
| 640 | Color selfColor = BLACK; |
| 641 | for (auto [pos, side] : position) { |
| 642 | if (side != WALL) { |
| 643 | selfColor = side == SELF ? BLACK : WHITE; |
| 644 | break; |
| 645 | } |
| 646 | } |
| 647 | |
| 648 | // Put stones on board |
| 649 | for (auto [pos, side] : position) { |
| 650 | if (side == WALL) // Currently wall is not supported |
| 651 | continue; |
| 652 | |
| 653 | // Make sure current side to move correspond to the input side |
| 654 | // If not, we add an extra PASS move to flip the side |
| 655 | if (side == SELF && board->sideToMove() != selfColor |
| 656 | || side == OPPO && board->sideToMove() != ~selfColor) { |
| 657 | if (checkLastMoveIsNotPass(*board)) |
| 658 | return; |
| 659 | |
| 660 | board->move(options.rule, Pos::PASS); |
no test coverage detected