2010-04-30 27 views
14

Estoy teniendo un gran problema tratando de entender "árboles" mientras hago un bot de Tic-Tac-Toe. Entiendo el concepto, pero no me puedo imaginar para implementarlos.Tic-Tac-Toe AI: ¿Cómo hacer el árbol?

¿Alguien me puede mostrar un ejemplo de cómo se debe generar un árbol para este caso? ¿O un buen tutorial sobre la generación de árboles? Supongo que la parte difícil es generar árboles parciales. Sé cómo implementar la generación de un árbol completo, pero no partes de él.

+0

¿Qué clase de árbol? Un árbol Minimax? –

+0

Cualquier árbol que almacena el estado para el próximo movimiento posible. Un árbol minimax funcionaría, solo estoy buscando ver cómo se llena/navega un "árbol"/etc. No tengo ninguna experiencia trabajando con árboles – cam

Respuesta

16

Imagine que en cualquier punto de un tablero de tres en raya, cada movimiento posible es una rama. El estado actual de la placa es la raíz. Un movimiento es una rama. Ahora pretenda (uno a la vez), que cada rama se convierta en el estado actual. Cada movimiento posible se convierte en una nueva rama. La hoja del árbol es cuando se realiza el último movimiento y el tablero está lleno.

La razón por la que necesita tener un árbol, es que una vez que está construido, necesita averiguar qué rama tiene la mayor cantidad de hojas que son escenarios 'GANAR'. Cree la rama de todos los resultados posibles, sume la cantidad total de WIN y luego haga la jugada que tenga la oportunidad de obtener la mayor cantidad de ganancias.

Hacer el árbol de algo como esto:

class Node { 
public: 
    std::list<Node> m_branches; 
    BoardState m_board; 
    int m_winCount; 
} 

std::list<Node> tree; 

Ahora, iterar a través de la lista de las ramas en el árbol, y para cada rama, iterar a través de sus ramas. Esto se puede hacer con una función recursiva:

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) 

Muy pseudocódigo.

+1

... Dicho esto, no es realmente AI en este momento, sino una determinación rigurosa de todos los resultados posibles, y tomando el riesgo exactamente apropiado. – Kieveli

+0

Bien, gracias a que la explicación ayudó, pero el principal problema que tengo es implementar esto. Entiendo el concepto por completo, pero generar el árbol y navegarlo me está abrumando. Estoy buscando algún código fuente que pueda ayudarme, o incluso un tutorial. Mi cerebro necesita ver un ejemplo antes de entender un concepto en el código. – cam

+0

Para que sea más AI como si se pudiera utilizar una profundidad máxima para limitar la mirada hacia adelante. O un temporizador para limitar la cantidad de tiempo que se gastaría en mirar hacia adelante, aunque en TTT el cálculo de un árbol completo se haría en nanosegundos. –

6

No creo que necesite mantener un árbol en la memoria. Sólo hay que poner en práctica una función recursiva que funciona algo así como:

Move getBestMove(Board state, boolean myTurn) 

Entonces sólo tiene que Recurse hasta que haya alcanzado una serie, perder o dibujar-estado.

La pila de llamadas con el tiempo se vería como un árbol si la dibujara en papel. Debería devolver el movimiento que conduce a un nodo en el cual el oponente (definitivamente/más probable) pierde (aunque también juega usando getBestMove)

Para un espacio de estado tan pequeño como tres en raya, sin embargo, ¡simplemente podría hacer una tabla de búsqueda completa con las mejores jugadas! :-)

+0

Supongo que esto es lo que no entendí. Pensé que se estaba creando una estructura de árbol real en la memoria. Así es como implementé el bot a partir de ahora, usando una función recursiva sin árboles. – cam

1

Si desea generar el árbol en la memoria (que no es necesario), tal vez un algoritmo como la siguiente podría ser utilizado (pseudo-código):

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) 

donde

Successors(s) // returns a list of successor states of s 
AddChild(p, n) // adds n to the list of p's children 
3

Es posible encontrar este artículo CodeProject interesante:

Solve Tic Tac Toe with the MiniMax algorithm

Está en C#, pero no será ningún problema adaptarlo en C++.

Este artículo fue también una buena lectura para mí cuando traté de poner en práctica mi primer juego de Tic-Tac-Toe en C++:

Minimax Explained