bool ChessBoard::isLegalMove(int mv) { int sqSrc, sqDst, pcSrc, pcDst; sqSrc = SRC(mv); sqDst = DST(mv); if (sqSrc==sqDst) { return false; } pcSrc = m_data[sqSrc]; pcDst = m_data[sqDst]; if (side(pcSrc)==side(pcDst)) { return false; } Moves mvs; generateMoves(sqSrc, mvs); for(int i=0; i<mvs.count(); i++) { if (mvs[i]==mv) { return true; } } return false; }
int UltimateTicTacToeMontecarloAI::expand(int leafIndex, Nodes& nodes, int const player) const { Node& node = nodes[leafIndex]; node.children.reserve(maxChildren); Moves options = movementOptions(node.board, node.previousMove); int turn = node.previousMove > 0 ? otherPlayer(node.board.grids.at(node.previousMove)) : player; int mostPromisingChildIndex = -1; int mostPromisingChildScore = 0; while(node.children.size() < maxChildren && !options.empty()) { Move move = options.takeAt(qrand() % options.size()); int childIndex = nodes.size(); node.children.append(childIndex); Board newBoard(node.board); nodes.append( Node {0, 1, playMove(newBoard, move, turn), move, leafIndex, Node::Children()}); int score = scoreBoard(nodes.last().board, player); if(score > mostPromisingChildScore || mostPromisingChildIndex < 0) { mostPromisingChildIndex = childIndex; mostPromisingChildScore = score; } } return mostPromisingChildIndex; }
UltimateTicTacToeMontecarloAI::Moves UltimateTicTacToeMontecarloAI::movementOptions(Board const& board, int const previousMove) const { int gridIndex = previousMove % GRID_SIZE; bool playAny = previousMove < 0 || gridWinner(board.grids, gridIndex) || gridFull(board.grids, gridIndex); Moves options; if(playAny) { for(int i = 0; i < BOARD_SIZE; ++i) { if(board.grids.at(i) == 0) { options.append(i); } } //qDebug() << "Play to any grid," << options.size() << "options"; } else { for(int i = 0; i < GRID_SIZE; ++i) { int position = gridIndex * GRID_SIZE + i; if(board.grids.at(position) == 0) { options.append(position); } } //qDebug() << "Play to grid" << gridIndex << "," << options.size() << "options"; } return options; }
/** *1手前の指し手を取得 */ const MoveKif* Notation::getPrevMove() const { int pos; bool ret = false; pos = this->number() - (*this->current_moves_)[0].number(); ASSERT_MSG(pos >= 0, "内部状態が変?"); MoveKif& move = (*this->current_moves_)[pos]; pos--; Moves* moves = this->current_moves_; if (pos < 0 && moves->parent() != nullptr) { // 親の分岐を取得 moves = moves->parent(); pos = move.getParentNumber() - (*moves)[0].number(); } if (pos < 0) { return nullptr; } return &(*moves)[pos]; }
bool Board::IsCheck(Color side) { Moves* moves = new Moves(); int j = 0; for (int i = 0; i < BoardSize * BoardSize; i++) { if (this->Chesses[i] != NULL && this->Chesses[i]->GetPlayer()->GetSide() == side) this->Chesses[i]->GetAvailableMoves(this, moves, true); for (; j < moves->GetLength(); j++) { Move* move = moves->GetMove(j); Chess* captured = move->GetChessCaptured(); if (captured != NULL && captured->GetChessType() == King) { delete moves; return true; } } } delete moves; return false; }
int ChessBoard::test1_max(int depth, int& mv) { if (depth==0) { mv = 0; return m_vlBlack - m_vlRed; } Moves mvs; //int selfSide = m_sdPlayer; int best = -999999; generateMoves(mvs); for(int i=0; i<mvs.count(); i++) { int oldVal = m_vlBlack - m_vlRed; int pcCapture; if (makeMove(mvs[i], pcCapture)) { int temp_mv; int val = test1_min(depth-1, temp_mv); if (val>best) { best = val; mv = mvs[i]; } undoMakeMove(mvs[i], pcCapture); } int newVal = m_vlBlack - m_vlRed; Q_ASSERT(oldVal==newVal); } return best; }
Moves MoveGenerator::generateOpening(const Board& board) const { Moves result; if(board.getIdleCount() == 0) { QMessageBox::critical(0, "error", "idle == 0"); return result; } for(int i=0; i<23; ++i) { if(board.isEmpty(i)) { Board next = board.makeChild(); // a clone next.setManAt(i, board.getSelfColor()); if(next.closeMill(i)) { Moves removeMoves = generateRemove(next, board.getOpponentColor()); // remove 1 opponent chessman copy(removeMoves.begin(), removeMoves.end(), back_inserter(result)); } else result.push_back(next); } } return result; }
void ChessBoard::generatePawnMoves(ChessBoard& board, int sqSrc, Moves& mvs) { int sqDst; if (board.m_sdPlayer != SQ_SIDE(sqSrc)) { sqDst = sqSrc - 1; if (IN_BOARD(sqDst) && board.canMove(board, sqSrc, sqDst)) { mvs.append(ChessBoard::mv(sqSrc, sqDst)); } sqDst = sqSrc + 1; if (IN_BOARD(sqDst) && board.canMove(board, sqSrc, sqDst)) { mvs.append(ChessBoard::mv(sqSrc, sqDst)); } } if (board.m_sdPlayer==0) { sqDst = sqSrc - 16; } else{ sqDst = sqSrc + 16; } if (IN_BOARD(sqDst) && board.canMove(board, sqSrc, sqDst)) { mvs.append(ChessBoard::mv(sqSrc, sqDst)); } }
const ConnectThree::Move ConnectThree::CheckTwoOther(const std::bitset<3>& is_player_human) const { const Moves moves(GetAllPossibleMoves()); const int nMoves = moves.size(); if (nMoves==0) return CreateInvalidMove(); { //Get anti-human moves Moves v; BOOST_FOREACH(const Move& m, moves) { assert(CanDoMove(m)); //Player is human if (is_player_human[boost::tuples::get<2>(m)]) v.push_back(m); } //If there are anti-player moves, choose one at random if (!v.empty()) { const Move m = v[std::rand() % v.size()]; assert(CanDoMove(m)); return boost::tuples::make_tuple( boost::tuples::get<0>(m), boost::tuples::get<1>(m), boost::tuples::get<2>(m)); } }
/*-----------------------------------------------------------------------------*/ void MoveKif::AddBranch(Moves* parent, const Moves& moves) { this->branches_.emplace_back(new Moves(moves)); Moves* m = this->branches_.back().get(); m->set_parent(parent); }
Moves BoardC4::get_possible_moves(Token player) const { Moves moves; for (Size column=0; column<width; column++) { if (tokens[column]<=token_for_columns[column]) moves.push_back(new MoveC4(player,column)); } return moves; }
void Shogi::GenerateMoves1Step( Moves& moves, GEN_INFO& info, int dir ){ /************************************************ 任意の方向への着手可能手を列挙する。 ************************************************/ int from; // 移動元 int to; // 移動先 int n; int flag; bool nz; if( info.dir_p != 0 && dir != info.dir_p && dir != -info.dir_p ) return; from = info.addr; to = info.addr + dir; if( ban[to] == EMPTY || ban[to] & (ksengo^SENGO) ){ if( ( info.flag & MOVE_CAPTURE && ban[to] != EMPTY ) || ( info.flag & MOVE_NOCAPTURE && ban[to] == EMPTY ) // 新しいGenerateCheckOnBoard内で空き王手のチェックは行う。 /*|| ( info.flag & MOVE_CHECK && IsDiscCheckMove( info.ou2, to, from ) )*/ ){ flag = 1; } else{ flag = 0; } // 着手可能手追加 n = 0; if( !( info.koma & NARI ) && info.koma != SKI && info.koma != GKI && ( ( ksengo == SENTE && ( to <= BanAddr(9,3) || from <= BanAddr(9,3) ) ) || ( ksengo == GOTE && ( to >= BanAddr(1,7) || from >= BanAddr(1,7) ) ) ) ) { // 成る場合 if( flag || info.flag & MOVE_PROMOTE || ( info.flag & MOVE_CHECK && IsCheckMove( info.ou2, to, info.koma + NARI ) ) || ( info.flag & MOVE_NCHECK && !IsCheckMove( info.ou2, to, info.koma + NARI ) ) ){ moves.Add( from, to, 1, info.koma ); } n = 1; } nz = !n || Narazu( info.koma, to ); if( !MoveError( info.koma, to ) && // 王手の場合でも不成は生成しないように変更 ( /*info.flag & MOVE_CHECK ||*/ nz ) ) { // 成らない場合 if( flag || info.flag & MOVE_NOPROMOTE || ( info.flag & MOVE_CHECK && IsCheckMove( info.ou2, to, info.koma ) ) || ( nz && info.flag & MOVE_NCHECK && !IsCheckMove( info.ou2, to, info.koma ) ) ){ moves.Add( from, to, 0, info.koma ); } } } }
/*-----------------------------------------------------------------------------*/ void MoveKif::AddBranch(Moves* parent, const MoveKif& move) { this->branches_.emplace_back(new Moves()); Moves* moves = this->branches_.back().get(); moves->set_parent(parent); moves->push_back(move); }
void ConsoleManager::showMoves() const { Moves moves; MoveGenerator::generate(record_.getBoard(), moves); for (auto ite = moves.begin(); ite != moves.end(); ite++) { if (record_.getBoard().isValidMoveStrict(*ite)) { std::cout << ite->toString() << ' '; } } std::cout << std::endl; }
bool Board::HasMove(Color side) { Moves* moves = this->GetAllAvailableMoves(side); bool has_move = moves->GetLength() > 0; delete moves; return has_move; }
void build_path(ull_t v, const Searched & searched, Moves & steps) { Searched::const_iterator it = searched.find(v); while (it != searched.end()) { const State & s = it->second; steps.push_back(s.step); it = searched.find(s.parent); } //pop up the first step, which must be 0, rather than one of U,D,L,R steps.pop_back(); reverse(steps.begin(), steps.end()); }
/*-----------------------------------------------------------------------------*/ Moves* MoveKif::MakeBranch(Moves* parent) { this->branches_.emplace_back(new Moves()); this->current_ = this->branches_.size() - 1; // カレント変えとく Moves* moves = this->branches_.back().get(); moves->set_parent(parent); return moves; }
Move bestMove(const Moves& moves) { if (!moves.empty()) { return *min_element(moves.begin(), moves.end()); } else { return Move(Cost::infinity()); } }
TEST(MoveGeneratorTest, testDrop) { { // 先手の手 std::string src = "P1+TO-KE * * * * * * * \n" "P2 * * * * * * * * * \n" "P3 * * * -OU * * * -FU * \n" "P4 * * * * * * * * * \n" "P5 * * * +FU * -KI * * * \n" "P6 * * * * * * * * * \n" "P7 * * +FU * * * * +FU * \n" "P8 * * +OU * * * * * * \n" "P9 * * * * -KY * -RY * * \n" "P+00FU00FU00KY00KE00KA\n" "P-\n" "+\n"; std::istringstream iss(src); Board board; CsaReader::readBoard(iss, board); // FUx45 KYx63 KEx54 KAx70 Moves moves; MoveGenerator::generateDrop(board, moves); ASSERT_EQ(45+63+54+70, moves.size()); } { // 後手の手 std::string src = "P1 * * * * +KY * +RY * * \n" "P2 * * -OU * * * * * * \n" "P3 * * -FU * * * * -FU * \n" "P4 * * * * * * * * * \n" "P5 * * * -FU * +KI * * * \n" "P6 * * * * * * * * * \n" "P7 * * * +OU * * * +FU * \n" "P8 * * * * * * * * * \n" "P9-TO+KE * * * * * * * \n" "P+\n" "P-00FU00FU00KY00KE00KA\n" "-\n"; std::istringstream iss(src); Board board; CsaReader::readBoard(iss, board); // FUx45 KYx63 KEx54 KAx70 Moves moves; MoveGenerator::generateDrop(board, moves); ASSERT_EQ(45+63+54+70, moves.size()); } }
int Book::GetMoveAll( Shogi* pshogi, Moves& moves, TYPE type ){ /************************************************ 定跡手を列挙する。 ************************************************/ int i; int flag; list<BLIST>::iterator ib; list<MLIST>::iterator im; list<MLIST>* pmlist; uint64 hash = pshogi->GetHash(); MOVE mtemp; i = (int)( hash & BOOK_HASH_MASK ); // 局面が既にあるか調べる。 flag = 0; for( ib = blist[i].begin() ; ib != blist[i].end() ; ++ib ){ if( (*ib).hash == hash ){ flag = 1; break; } } if( flag == 0 ) return 0; // 指し手を列挙 pmlist = &(*ib).mlist; for( im = pmlist->begin() ; im != pmlist->end() ; ++im ){ mtemp.Import( (*im).mv ); if( pshogi->IsLegalMove( mtemp ) ){ switch( type ){ // 評価値を用いる場合 case TYPE_EVAL: mtemp.value = (*im).val; break; // 出現頻度を用いる場合 case TYPE_FREQ: default: mtemp.value = (*im).cnt * 100 / (*ib).cnt; break; } moves.Add( mtemp ); } } moves.Sort(); return moves.GetNumber(); }
Moves valid_moves() const { int i = space_index(); int row = i / 4; int col = i % 4; Moves cand; if (row != 0) cand.push_back('U'); if (row != 3) cand.push_back('D'); if (col != 0) cand.push_back('L'); if (col != 3) cand.push_back('R'); return cand; }
TEST(MoveGeneratorTest, testNoCap) { { std::string src = "P1-KY-KE-GI-KI * -KI * -KE-KY\n" "P2 * -OU * * * * * -HI * \n" "P3-FU-FU-FU-FU-FU * -KA * -FU\n" "P4 * * * * -GI-FU-FU+KA * \n" "P5 * * * * * * * * * \n" "P6+FU * +FU * +FU * * * * \n" "P7 * +FU+GI+FU * +FU+FU * +FU\n" "P8 * * +OU * +KI * * +HI * \n" "P9+KY+KE * +KI * * +GI+KE+KY\n" "P+00FU\n" "P-00FU\n" "+\n"; std::istringstream iss(src); Board board; CsaReader::readBoard(iss, board); Moves moves; MoveGenerator::generateNoCap(board, moves); ASSERT_EQ(40, moves.size()); } { // 先手の駒 銀から飛車まで std::string src = "P1 * * * * -OU+KA * * * \n" "P2+KI * * * * * * +HI * \n" "P3 * * +GI * * * * * * \n" "P4+GI * * * * * * * * \n" "P5 * * +KA * * * * * * \n" "P6 * * * * * * +HI * * \n" "P7 * * * * * * * * * \n" "P8 * * * * * * * * * \n" "P9 * * * * +OU * -TO * * \n" "P+\n" "P-\n" "+\n"; std::istringstream iss(src); Board board; CsaReader::readBoard(iss, board); Moves moves; MoveGenerator::generateNoCap(board, moves); ASSERT_EQ(43, moves.size()); } }
bool Board::IsCheckmate(Color side) { if (!this->IsCheck(side)) { return false; } Color opponent = side == White ? Black : White; Moves* moves = this->GetAllAvailableMoves(opponent); bool checkmate = moves->GetLength() == 0; delete moves; return checkmate; }
void Shogi::GenerateMovesDropKy( Moves& moves ){ /************************************************ 香車を打つ手を列挙する。 ************************************************/ KOMA koma; int to; int i, j; koma = KY | ksengo; if( dai[koma] == 0 ) return; for( j = 0x10 ; j <= 0x90 ; j += 0x10 ){ for( i = 1 ; i <= 9 ; i++ ){ to = i + j; if( ban[to] == EMPTY ){ // 合法手チェック if( ksengo == SENTE ){ if( to <= BanAddr(9,1) ) continue; } else{ if( to >= BanAddr(1,9) ) continue; } // 着手可能手追加 moves.Add( DAI + koma, to, 0, koma ); } } } }
void Shogi::GenerateTacticalMoves( Moves& moves ){ /************************************************ 戦略的な手を列挙する。 Capture, Promote, (King) ************************************************/ GEN_INFO info; // 生成する指し手の種類 SetGenInfo( info, MOVE_CAPTURE | MOVE_PROMOTE ); // ピン SetGenInfoPin( info ); if( !info.check ){ // 盤上 GenerateMovesOnBoard( moves, info ); } else if( info.check != DOUBLE_CHECK ){ GenerateCapEvasion( moves, info ); GenerateNoCapEvasion( moves, info ); } if( moves.GetNumber() == 0 ){ // 玉を動かす手 info.flag |= MOVE_KING; GenerateMovesOu( moves, info ); } }
void PlayerAI1::RequestMove() { Moves* moves = this->Game->CurrentBoard->GetAllAvailableMoves(this->Side); srand (time(NULL)); int index = rand() % moves->GetLength(); Move* move = moves->GetMove(index); Chess* before = move->GetChessBeforeMove(); Chess* after = move->GetChessAfterMove(); this->Game->MakeMove(before->GetX(), before->GetY(), after->GetX(), after->GetY(), after->GetChessType()); delete moves; CheckDraw(); }
/*-----------------------------------------------------------------------------*/ void Notation::AddBranch(const Moves& src_moves) { Moves* dest_moves = this->current_moves_; // 一旦カレントで作成 MoveKif* dest_move = this->move_current_; const MoveKif& last_move = dest_moves->back(); if (&last_move == dest_move) { // 追加先が末尾の場合 dest_moves->insert(dest_moves->end(), src_moves.begin(), src_moves.end()); } else { // 追加先が途中の場合 dest_move->AddBranch(dest_moves, src_moves); } }
Moves MoveGenerator::generateRemove(const Board& old, QChar color) const { Moves result; for(int i=0; i<23; ++i) { if(old.getManAt(i) == color) { if(!old.closeMill(i)) { // DO NOT use old.makeChild // next is a semi-finished product of a move Board next = old; next.setManAt(i, 'x'); result.push_back(next); } } } if(result.empty()) // no possible remove result.push_back(old); return result; }
/*-----------------------------------------------------------------------------*/ void Notation::DeleteBranch(int no) { MoveKif* move = this->move_current_; // 一旦カレントに対する操作にしておく Moves* moves = this->current_moves_; int num = this->number(); if (no == -1) { int pos = num - (*moves)[0].number(); // 次の要素から最後までを削除 moves->erase(moves->begin() + pos + 1, moves->end()); if (move->branches().size() != 0) { // ブランチをずらす moves->insert(moves->end(), move->branches()[0]->begin(), move->branches()[0]->end()); move->DeleteBranch(0); } } else { move->DeleteBranch(no); } }
bool ChessBoard::IsMate() { //qDebug()<<"check isMate side="<<m_sdPlayer; //int selfSide = m_sdPlayer; Moves mvs; generateMoves(mvs); for(int i=0; i<mvs.count(); i++) { //qDebug()<<"尝试解招:"<< mvString(mvs[i]); int pcCaptured = _movePiece(mvs[i]); if (!isChecked()) { _undoMovePiece(mvs[i], pcCaptured); //qDebug()<<"!!!解招:"<< mvString(mvs[i]); return false; } else{ _undoMovePiece(mvs[i], pcCaptured); } } return true; }