//------------------------------------------------------------------- // 初期化 //------------------------------------------------------------------- void cTitleScene::Init() { MyOutputDebugString( _T("タイトルシーン:初期化\n") ); select_ = Select_None; stateResult_ = StateResult_Continue; stateFunc_.setFunc( &cTitleScene::Idle ); pTitleBackGround = NEW cCharctor( _T("Data/Image/Back/TitleBackGround.img") ); pTitleCursor = NEW cCursorCharctor( _T("Data/Image/Parts/TitleCursor.img"), 3, 0, 72 ); pTitleCursor->m_spPosInfo->SetPos( 212.0f, 215.0f, 0.0f ); pTitleCursor->SetFirstPos(); Device->Draw.Append( pTitleBackGround ); Device->Draw.Append( pTitleCursor ); pTitleKeyConfigString = NEW cConfigCharctor; pTitleKeyConfigString->m_spPosInfo->SetPos( 190.0f, 255.0f, 0.0f ); pTitleKeyConfigString->SetIsDraw(FALSE); Device->Draw.Append( pTitleKeyConfigString ); Device->Sound.LoadBGM( _T("Data/Sound/Title.bgm") ); Device->Sound.PlayBGM(); FadeInCount = 0; FadeOutCount = FadeOutMaxCount; DxLib::SetDrawBright( 0, 0, 0 ); }
//------------------------------------------------------------------- // 実行中 //------------------------------------------------------------------- void cTitleScene::Idle() { if( !FadeIn() ) return; if( InputButton(Up) == 1 ){ Device->Sound.PlaySE(0); pTitleCursor->Up(); } if( InputButton(Down) == 1 ){ Device->Sound.PlaySE(0); pTitleCursor->Down(); } if( InputButton(Button1) == 1 ){ switch( pTitleCursor->GetSelectID() ){ case Select_GoSelect: Device->Sound.PlaySE(2); select_ = Select_GoSelect; stateFunc_.setFunc( &cTitleScene::End ); MyOutputDebugString( _T("タイトルシーン:アイドル終了\nセレクトシーンへ移行します\n") ); break; case Select_Config: pTitleKeyConfigString->SetIsDraw(TRUE); select_ = Select_Config; stateFunc_.setFunc( &cTitleScene::KeyConfig ); MyOutputDebugString( _T("タイトルシーン:キーコンフィグを起動します。\n") ); break; case Select_Exit: select_ = Select_Exit; stateFunc_.setFunc( &cTitleScene::End ); MyOutputDebugString( _T("タイトルシーン:アイドル終了\nアプリケーションを終了します\n") ); break; } } pTitleCursor->Updata(); if( DxLib::GetWindowUserCloseFlag( TRUE ) && (MessageBox( DxLib::GetMainWindowHandle(),WindowText, WindowTitleText, MB_YESNO|MB_ICONQUESTION ) == IDYES) ){ select_ = Select_Exit; stateFunc_.setFunc( &cTitleScene::End ); } }
// 利用可能時間を過ぎて探索している場合、Signals.stopをtrueにして探索を中止する void AI::checkTime() { // 経過時間 int elapsed = Time.elapsed(); if (elapsed > 60) { stop = true; MyOutputDebugString("stop!"); } }
int AI::thinkWrapper(const Field &self, const Field &enemy) { Time.reset(); stop = false; calls_count = 0; int timeLimit = 999999; if (enemy.flag(RENSA))// 敵が連鎖中 { // 連鎖が起こりきるまでの時間と思えばよい timeLimit = (enemy.chainMax() - enemy.chain()) * (CHAINTIME + FALLTIME); } LightField s(self); LightField e(enemy); // 世代を進める TT.newSearch(); hash_hit = 0; int depth; Move best_move; // 思考開始 for (Depth d = ONE_PLY; d <= depth_max_; ++d) { think(s, e, d, timeLimit); best_move = stop ? best_move : best_[d]; MyOutputDebugString("depth = %d, stop = %d\n", d, stop); if (stop) break; } // ベストな手はbest_[0]にはいっている // それを操作に変換 if (easy_ == 0) { operate_.generate(best_move, self); } else if (easy_ == 1) { operate_.easyGenerate(best_move, self); } else if (easy_ == 2) { operate_.veryEasyGenerate(best_move, self); } return 0; }
void MyTrace(LPCTSTR lpszFormat,...) { TCHAR szBuffer[512]; // it may be long buffer va_list args; va_start(args, lpszFormat); StringCbVPrintf(szBuffer, _countof(szBuffer), lpszFormat, args); MyOutputDebugString((LPCTSTR)szBuffer); va_end(args); }
//------------------------------------------------------------------- // キーコンフィグ中 //------------------------------------------------------------------- void cTitleScene::KeyConfig() { int PushedKeyNumber = 0; // 現在押されたキー番号 static int NowKeyNum = 0; // 設定するキー番号 if( NowKeyNum >= Device->Pad.VIRTUAL_MAX_BUTTON ){ NowKeyNum = 0; pTitleKeyConfigString->SetIsDraw(FALSE); select_ = Select_None; stateFunc_.setFunc( &cTitleScene::Idle ); MyOutputDebugString( _T("タイトルシーン:アイドルに移行します。\n") ); } else if( (PushedKeyNumber = Device->Pad.PushedButton()) != 0 ){ MyOutputDebugString( _T("%d,%d\n"),PushedKeyNumber,NowKeyNum ); Device->Pad.SetConfig( PushedKeyNumber, NowKeyNum ); ++NowKeyNum; pTitleKeyConfigString->Updata(); } if( DxLib::GetWindowUserCloseFlag( TRUE ) && (MessageBox( DxLib::GetMainWindowHandle(),WindowText, WindowTitleText, MB_YESNO|MB_ICONQUESTION ) == IDYES) ){ select_ = Select_Exit; stateFunc_.setFunc( &cTitleScene::End ); } }
//------------------------------------------------------------------- // 終了処理 //------------------------------------------------------------------- void cTitleScene::End() { if( select_ != Select_Exit && !FadeOut() ) return; pTitleBackGround->SetIsExit(TRUE); pTitleCursor->SetIsExit(TRUE); pTitleKeyConfigString->SetIsExit(TRUE); Device->Draw.Remove(); SAFE_DELETE( pTitleBackGround ); SAFE_DELETE( pTitleCursor ); SAFE_DELETE( pTitleKeyConfigString ); Device->Sound.StopBGM(); MyOutputDebugString( _T("タイトルシーン:終了\n\n") ); stateResult_ = StateResult_Finish; stateFunc_.setFunc( &cTitleScene::Init ); DxLib::SetDrawBright( 255, 255, 255 ); }
int AI::thinkWrapperEX(Field self, Field enemy) { Time.reset(); stop = false; calls_count = 0; int timeLimit = 999999; // 静かな局面になるまで局面を進める int my_remain_time = enemy.generateStaticState(self); // enemyが死んでいる局面の場合は-1が返ってくる if (my_remain_time == -1) { if (enemy.isDeath()) { operate_.clear(); // その時は探索は行わず、ずっと回転し続けることにする(煽りではない) for (int i = 0; i < 1000; i++) { if (i % 7 == 0) operate_.push(R_ROTATE); else operate_.push(0); } return 0; } } // 進めたことによりエラーが発生しないかどうか。 assert(self.examine()); assert(enemy.examine()); // 探索用に小さなサイズのフィールドにする LightField s(self); LightField e(enemy); assert(s.chainMax() == 0 && e.chainMax() == 0); assert(s.examine()); assert(e.examine()); ChainsList* c1 = new ChainsList(100); ChainsList* c2 = new ChainsList(100); s.setChains(c1); e.setChains(c2); // 世代を進める TT.newSearch(); Score alpha = -SCORE_INFINITE; // α:下限値 Score beta = SCORE_INFINITE; // β:上限値 Score delta = alpha; Score score = SCORE_ZERO; continue_self_num_ = 0; Move best_move; Move mlist[22]; int mcount = s.generateMoves(mlist); // 死んでいる局面ではないはず assert(mcount > 0); root_moves.clear(); for (int i = 0; i < mcount; ++i) { root_moves.push_back(Search::RootMove(mlist[i])); root_moves[i].player.push_back(self.player()); } // 反復深化 for (Depth d = ONE_PLY; d <= depth_max_; ++d) { if (stop) break; MyOutputDebugString("depth = %d, stop = %d\n", d, stop); // 前回のiterationでの指し手の点数をすべてコピー for (int i = 0; i < root_moves.size(); ++i) root_moves[i].previous_score = root_moves[i].score; #if 0 // aspiration search // alpha betaをある程度絞ることで、探索効率を上げる。 if (3 <= depth_max_ && abs(root_moves[0].previous_score) < SCORE_INFINITE) { delta = static_cast<Score>(5); alpha = static_cast<Score>(root_moves[0].previous_score) - delta; beta = static_cast<Score>(root_moves[0].previous_score) + delta; } else #endif { alpha = -SCORE_INFINITE; beta = SCORE_INFINITE; } // aspiration search のwindow幅をはじめは小さい値にして探索し、 // fail high/lowになったなら、今度はwindow幅を広げて再探索を行う。 while (true) { // 探索開始 score = search<ROOT>(alpha, beta, s, e, d, my_remain_time); // 先頭が最善手になるようにソート insertionSort(root_moves.begin(), root_moves.end()); // fail high / lowが起きなかった場合はループを抜ける。 if (alpha < score && score < beta) break; // fail low/highが起きた場合、aspiration窓を増加させ再探索し、 // さもなくばループを抜ける。 if (abs(score) >= Score(10000)) { // 勝ちか負けだと判定したら、最大の幅で探索を試してみる。 alpha = -SCORE_INFINITE; beta = SCORE_INFINITE; } else if (beta <= score) { beta += delta; delta += delta / 2; } else { alpha -= delta; delta += delta / 2; } if (stop) break; } best_move = stop ? best_move : best_[d]; MyOutputDebugString("score = %d, depth = %d, best = %s", score, depth_max_, best_move.toString(self, 0)); int s_field_ply = 0; int e_field_ply = 0; // pv表示 for (int size = 0; size < root_moves[0].pv.size() - 1; size++) { LightField* now_player = root_moves[0].player[size] == self.player() ? &self : &enemy; int now_field_ply; if (now_player == &self) now_field_ply = s_field_ply++; else now_field_ply = e_field_ply++; MyOutputDebugString("%s%s,", root_moves[0].player[size] == PLAYER1 ? "P1:" : "P2:", root_moves[0].pv[size].toString(*now_player, now_field_ply).c_str()); } MyOutputDebugString("\n"); } MyOutputDebugString("\n"); // 探索した結果得られた手を実際に配置できるかどうか。 assert(self.isEmpty(best_move.psq()) && self.isEmpty(best_move.csq())); // best_moveを操作に変換 operate_.generate(best_move, self); delete c1; delete c2; return score; }