La programación de motores de ajedrez es un territorio muy complicado, así que desde el principio te dirijo a la Wiki de programación de ajedrez , que tiene mucha información excelente sobre este tema.
Antecedentes
Los cálculos de ajedrez (y muchas cosas similares) generalmente se modelan y se consideran "árboles de juego" o " árboles de decisión ". En términos generales, este árbol es un gráfico dirigido, con un nodo en la parte superior (la posición actual), que conduce a un nodo para cada posible movimiento, cada uno de los cuales conduce a más nodos para cada posible próximo movimiento, y así sucesivamente.
En su forma más simple y de fuerza bruta, los motores de ajedrez generan todas las posiciones en este árbol hasta cierto límite de profundidad ("capa"), evaluando cada posición resultante en función de algunos criterios complejos 1 . Luego juega el movimiento que parece conducir al mejor resultado. Hoy en día, se han desarrollado muchas técnicas realmente complicadas para limitar el número de posiciones que el motor tiene que mirar, pero voy a ignorarlas a los efectos de esta respuesta, porque no cambian el problema real en mano.
Tangente Matemática
La razón básica por la que los motores generalmente tardan aproximadamente la misma cantidad de tiempo en considerar cada movimiento es que el tamaño del árbol de decisión aumenta exponencialmente con la profundidad ( k
).
Considere la posición inicial. La parte superior del árbol ( k=0
) es un nodo. Hay veinte primeros movimientos posibles para las blancas, por lo que hay veinte nodos en profundidad k=1
. Luego, las negras también tienen veinte movimientos disponibles para cada una de las opciones de las blancas: así que k=2
, ¡hay 20 * 20 = 400
posibles posiciones! ¡Y solo empeora a medida que los jugadores desarrollan sus piezas!
Por ejemplo, supongamos que siempre hay veinte movimientos posibles para cada jugador en un momento dado 2 . Le indica a la computadora que mire hacia adelante cinco movimientos para cada jugador (diez capas). Veamos el tamaño del árbol de fuerza bruta en cada nivel. Por diversión, también veremos el número total de posiciones en el árbol (desde la parte superior hasta el nivel dado).
Ply | Positions | Total Tree Size
----------------------------------------
0 | 1 | 1
1 | 20 | 21
2 | 400 | 421
3 | 8000 | 8421
4 | 160000 | 168421
5 | 3200000 | 3368421
6 | 64000000 | 67368421
7 | 1280000000 | 1347368421
8 | 25600000000 | 26947368421
9 | 512000000000 | 538947368421
10 | 10240000000000 | 10778947368421
El resultado de que cada nivel sea exponencialmente mayor que el nivel anterior es que el tamaño de todo el árbol está dominado por el nivel inferior . Considere el ejemplo anterior: el último nivel solo contiene diez billones de nodos. Todo el resto del árbol solo contiene quinientos mil millones. La décima capa contiene aproximadamente el 95% de los nodos en todo el árbol (esto es realmente cierto en cada nivel). En la práctica, lo que esto significa es que se pasa todo el tiempo de búsqueda evaluando el "último" movimiento.
Responder
Entonces, ¿cómo se relaciona esto con su pregunta? Bueno, digamos que la computadora está configurada en diez capas, como se indicó anteriormente, y además "recuerda" los resultados de sus evaluaciones. Calcula un movimiento, lo juega y luego haces un movimiento. Ahora se han realizado dos movimientos, por lo que elimina todas las posiciones de la memoria relacionadas con los movimientos que no ocurrieron, y queda con un árbol que baja los ocho movimientos restantes que ya calculó: ¡26,947,368,421 posiciones!
¡Todo bien! ¡Entonces solo tenemos que calcular las dos últimas capas! Usando nuestra estimación de 20 movimientos en cada profundidad, el número total de movimientos que necesitamos calcular aquí todavía supera los diez billones. ¡Las posiciones que ya calculamos solo representan el 2.5% de las posibilidades! Entonces, incluso al almacenar en caché los resultados del último movimiento, ¡lo mejor que podemos esperar es un aumento del 2.5% en la velocidad! En el fondo, esta es la razón por la cual, incluso si su programa almacena en caché resultados anteriores, generalmente no ve una aceleración significativa entre movimientos (¡excepto en los casos en que la computadora encuentra un compañero forzado o algo así, por supuesto!).
Descargo de responsabilidad de simplificación
Hay mucha complejidad involucrada en esta pregunta, por eso me vinculé a la wiki de programación en la parte superior y solo intenté explicar la respuesta en términos matemáticos generales. En realidad, los programas hacen generalmente partes de caché del árbol de movimiento para mover y hay otras razones por las que es insuficiente por sí solo - algunas razones simples (por ejemplo, una determinada línea puede ser bueno a ocho movimientos, pero termina con una parte posterior - ¡Mate compañero en el movimiento nueve!) y muchos muy complicados (generalmente relacionados con varios métodos de poda inteligentes). Por lo tanto, la computadora debe seguir mirando más adelante en un intento de evitar hacer suposiciones erróneas basadas en la profundidad de corte del movimiento anterior.
1 No voy a entrar en funciones heurísticas aquí, porque esa es su área increíblemente compleja, pero a menudo también se pueden lograr algunas ganancias a través de esquemas de almacenamiento en caché de posición.
2 Un factor de ramificación promedio de 20 es probablemente demasiado bajo .