Крестики - нолики AI: как сделать дерево?
У меня есть огромный блок, пытающийся понять "деревья", делая бот крестики-нолики. Я понимаю концепцию, но не могу понять, как их реализовать.
может ли кто-нибудь показать мне пример того, как дерево должно быть создано для такого случая? Или хороший учебник по генерации деревьев? Я думаю, что самая трудная часть-это создание частичных деревьев. Я знаю, как реализовать создание целого дерева, но не его частей.
4 ответов
представьте, что в любой точке доски крестики-нолики каждый возможный ход является ветвью. Текущее состояние платы-корень. Одно движение-это ветка. Теперь представьте (по одному), что каждая ветвь становится текущим состоянием. Каждый возможный ход становится новой веткой. Лист дерева-это когда сделан последний ход, и доска заполнена.
причина, по которой вам нужно иметь дерево, заключается в том, что как только он построен, вам нужно выяснить, какая ветка имеет больше всего листьев, что это сценарии "WIN". Вы создаете ветвь всех возможных исходов, складываете общее количество побед, а затем делаете ход, который имеет шанс в конечном итоге с наибольшим количеством побед.
сделайте дерево примерно так:
class Node {
public:
std::list< Node > m_branches;
BoardState m_board;
int m_winCount;
}
std::list< Node > tree;
теперь вы перебираете список ветвей дерева и для каждой ветви перебираете ее ветви. Это можно сделать с помощью рекурсивной функции:
int recursiveTreeWalk( std::list< Node >& partialTree)
{
for each branch in tree
if node has no branches
calculate win 1/0;
else
recursiveTreeWalk( branch );
partialTree.m_winCount = sum of branch wins;
}
// initial call
recursiveTreeWalk( tree )
очень псевдо-код.
Я не думаю, что вам нужно держать дерево в памяти. Вам просто нужно реализовать рекурсивную функцию, которая работает примерно так:
Move getBestMove(Board state, boolean myTurn)
тогда вы просто рекурсивно, пока вы не достигли выигрыш, проигрыш или ничья-государство.
стек вызовов со временем будет выглядеть как дерево, если вы нарисуете его на бумаге. Вы должны вернуть ход, который ведет к узлу, на котором противник (определенно / скорее всего) проигрывает (хотя он также играет, используя getBestMove)
для пространства состояний, как мало, как крестики - нолики, однако, вы можете просто сделать полный поиск таблицы с лучшими ходами! :-)
вы можете найти эту статью codeproject интересной:
решить крестики-нолики с алгоритмом минимакса
Это на C#, но это не будет проблемой, чтобы адаптировать его на C++.
эта статья также была хорошей для меня, когда я попытался реализовать свою первую игру в крестики - нолики на C++:
Если вы хотите сгенерировать дерево в памяти (что не обязательно), возможно, можно использовать следующий алгоритм (псевдо-код):
GenTree(State s):
T <- empty tree // T is a tree of States
SetRoot(T, s)
ForEach (s' in Successors(s)):
AddChild(T, GenTree(s'))
return T
// Call it
GenTree(currentMove)
здесь
Successors(s) // returns a list of successor states of s
AddChild(p, n) // adds n to the list of p's children