[英]Optimizing C++ Tree Generation
我正在生成一個Tic-Tac-Toe游戲樹(第一次移動后9秒鍾),並且被告知只需要幾毫秒的時間。 因此,我正在嘗試對其進行優化,並通過CodeAnalyst進行了測試,這是進行的前5個調用(我使用位集表示Tic-Tac-Toe板):
std::_Iterator_base::_Orphan_me
std::bitset<9>::test
std::_Iterator_base::_Adopt
std::bitset<9>::reference::operator bool
std::_Iterator_base::~_Iterator_base
void BuildTreeToDepth(Node &nNode, const int& nextPlayer, int depth)
{
if (depth > 0)
{
//Calculate gameboard states
int evalBoard = nNode.m_board.CalculateBoardState();
bool isFinished = nNode.m_board.isFinished();
if (isFinished || (nNode.m_board.isWinner() > 0))
{
nNode.m_winCount = evalBoard;
}
else
{
Ticboard tBoard = nNode.m_board;
do
{
int validMove = tBoard.FirstValidMove();
if (validMove != -1)
{
Node f;
Ticboard tempBoard = nNode.m_board;
tempBoard.Move(validMove, nextPlayer);
tBoard.Move(validMove, nextPlayer);
f.m_board = tempBoard;
f.m_winCount = 0;
f.m_Move = validMove;
int currPlay = (nextPlayer == 1 ? 2 : 1);
BuildTreeToDepth(f,currPlay, depth - 1);
nNode.m_winCount += f.m_board.CalculateBoardState();
nNode.m_branches.push_back(f);
}
else
{
break;
}
}while(true);
}
}
}
我應該在哪里進行優化? 我應該如何優化這5個調用(我無法識別它們=。
井字游戲樹非常多余。 消除旋轉的和鏡像的板將使游戲樹的最終層數減少3或4個數量級。 沒有任何數量的優化可以使Bubblesort像introsort一樣快。
struct Game_board;
struct Node
{
Game_board game_board;
Node* parent;
std::vector<Node*> children;
enum { X_Win, Y_Win, Draw, Playing } outcome;
};
// returns the same hash value for all "identical" boards.
// ie boards that can be rotated or mirrored to look the
// same will have the same hash value
int hash( const Game_board& game_board );
// uses hash() function to generate hashes from Node*
struct Hash_functor;
// nodes yet to be explored.
std::hash_set<Node*,Hash_functor> open;
//nodes already explored.
std::hash_set<Node*,Hash_functor> closed;
while( ! open.empty() )
{
Node* node_to_expore = get_a_node( open );
assert( node_to_expore not in close or open sets )
if( node_to_expore is win lose or draw )
{
Mark node as win lose or draw
add node to closed set
}
loop through all children of node_to_expore
{
if( child in close )
{
add node from closed set to children list of node_to_expore
}
else if( child in open )
{
add node from open set to children list of node_to_explore
}
else
{
add child to open set
add child to children list of node_to_expore
}
}
}
這些功能通常是微不足道的。 這意味着優化(“發行”)版本通常會將它們內聯。 但是,在調試版本中不是。 結果是調試構建的速度較慢,但允許您在這些函數上設置斷點。 因此,“毫秒注釋”應該應用於發布版本,在該版本中您將不再擁有這些功能。
您將全部包裹在數據結構中。 不建樹,只走它。 僅擁有一份董事會副本。 在搜索樹的每個節點上,只需修改電路板,然后在退回時取消對其進行修改。
而且,如果您想知道它在做什么,只需隨機點擊暫停按鈕即可。 它會向您顯示為什么在所有您不認識的例程中總是花時間。
坦白地說,這並不是要對您構成抨擊,您是在要求我們檢查文檔記錄不良的一段代碼,而該代碼段是較大代碼庫的一小部分。 我們沒有提供太多信息的上下文。 當其他人似乎還沒有完成他們自己可以做的所有事情來檢查自己的代碼時,我個人也被關閉(我並不是說我對您或其他任何事情感到惱火,只是我的眼睛在注視着您的代碼)。
我建議您通過探查器運行代碼,然后確定花費了很多時間的確切時間。 像調試一樣對待此配置文件。 當您發現一個需要很長時間的模塊時,請分小節檢查該模塊(就像您正在尋找錯誤一樣)以了解原因。
如果您仍然需要問一些問題,這將使您提出一個更加明智的問題。
讓我補充一下,如果您的系統花費9秒鍾來完成工作,那么這意味着被稱為數十億倍的東西。 如果您沒有發布級別的分析功能,則在代碼中放置一些全局計數器,並在每次調用它們所在的代碼時對其進行遞增。 這將為您提供一個窮人的檔案,該檔案可用於發行版本。 如果您在意想不到的地方看到數十億電話,那么您現在可以放心看看。
實際上,如果需要速度,井字游戲的整個移動樹應該很容易存儲為散列。 9! 動作不再是一個大領域(不再)。 36.2萬的舉動不應該破壞資金,這是蠻力分析。 當您考慮所有各種數據形式時,可以將該域削減。
ah,這是我編寫代碼的方式,因為人們已經將我鎖定在信封數學的背面:
我什至不會走樹路線,只需遵守一些規則即可。
轉1.進入中心。
轉2。如果中心沒空,去那兒,否則去角落
轉3。如果對手在一個角上填充,則在對面的角走,否則在角上-您贏了。
轉動4.如果需要,阻止。 如果X占據對角,則填充邊緣。 如果X占據中心和對角,則填充角。 如果X占據相反的邊緣,則填充角並獲勝。 如果X填充相鄰的邊,請在它們之間填充角。
如果可能,轉5贏。 如果需要,阻止。 否則,在相鄰邊緣的對角移動並獲勝。
如果可能,轉6-9贏。 如果需要,阻止。 否則,隨機抽獎。
您發布的代碼太少了。
您正在詢問如何優化代碼,但是您也應該詢問如何優化算法。
我立即看到兩件事。
正如“邁克爾·多根(Michael Dorgan)”所說的那樣,產生一次動作樹。
您在樹中生成了多少個廣泛對象? 362880? 您的代碼似乎正在生成冗余條目。 例如,對於一個空板,實際上有3個動作而不是9個動作。 所有其他組合都是旋轉的板(相等)。 您可以減少所需生成的板數,並加快生成樹的速度。
這是前三個動作(旋轉最后兩個板以生成其他板)
| | |X| | | |X| | | | | X| | | | | |
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.