Supongo que ya conoce el concepto de Min-Max, árboles y podas, heurística y otros conceptos básicos, y lo que escribo aquí son solo algunos detalles que podrían haberse subestimado.
Yo, junto con un amigo, escribí nuestro propio motor de ajedrez a veces. Comparto algunos problemas e ideas que tuvimos y espero que les sean útiles.
Como ambos éramos programadores de Java, nuestro lenguaje se convirtió en Java y comenzamos con un enfoque orientado a objetos. Las piezas eran objetos, el tablero era objeto, los archivos y las filas (filas y columnas en la literatura de ajedrez) eran objetos. Y esto estaba mal. La sobrecarga era masiva y el programa estaba luchando para ir más allá de 2 movimientos (4 capas) en el árbol de búsqueda.
Entonces, con un poco de búsqueda, terminamos con una idea brillante (¡aunque no la nuestra!): Representar las piezas y el tablero como enteros largos (64 bits). Esto tiene sentido porque un tablero de ajedrez tiene 64 casillas. El resto fueron operaciones poco sabias (ejecutando muy cerca de cpu = extremadamente rápido). Por ejemplo, considere un entero binario de 64 bits en el que los que están presentando los cuadrados en el tablero que su pieza puede atacar. Ahora, si ejecuta un "Y" lógico entre dos números como este, un resultado distinto de cero indica que tiene un cuadrado con atacantes. Hay varias formas de presentar el tablero de ajedrez y las piezas, así que:
1 - Decide sobre la presentación de tu junta
Entonces necesitas y abrir la base de datos. La apertura del ajedrez está resuelta de alguna manera y es muy recomendable tener un libro de apertura. En este caso, tienes mucho tiempo extra en los juegos de blitz.
2 - Búscate un libro de apertura.
Hicimos esto, pero aún estábamos lejos de ser buenos:
3 - Un buen motor de ajedrez debería poder ver 6 movimientos (12 capas) por delante.
Entonces, lo que hicimos entonces fue usar el tiempo muerto (si se trata de un motor humano frente a un ordenador).
4 - Usa el tiempo cuando el oponente está pensando en crear algunos niveles de tu árbol.
Y aún así estábamos muy lejos de 12 capas. ¡Por más estudio, descubrimos algunos trucos! Por ejemplo, se sugirió omitir una capa del árbol y comenzar desde la siguiente capa (como si no hubiera oponente). La idea es que si un movimiento es extremadamente idiota, ¿por qué perder el tiempo y ver cuáles son las respuestas de los oponentes a ese movimiento? Sin embargo, un buen motor debería ser capaz de distinguir entre un movimiento idiota y un sacrificio de reina genio.
5 - Aprende los trucos de programación para este problema específico (ajedrez).
Mi amigo y yo, en este estado, todavía éramos malos: / Lo que pudimos hacer, y lo hicimos parcialmente, fue salvar las posiciones calculadas. Si calcula una posición, ¡guárdela para el futuro! Lo mismo ocurre con los bucles en el árbol de búsqueda. El punto era guardar / recuperar eficientemente:
6 - Guarde los datos que genera ... ¡de manera eficiente!
y finalmente:
7 - Código con la máxima optimización.
Este problema es extremadamente costoso tanto en tiempo de CPU como en memoria. Es muy importante escribir su código de manera muy eficiente. Recuerde que estamos hablando del factor de ramificación de 35. Esto significa que un "si" inútil en algún lugar de su heurística puede convertirse en un 3.3792205e+18
"si" inútil en algún lugar de su árbol de búsqueda.
La programación de ajedrez es un desafío muy interesante y es el momento en que puedes poner tus capacidades de programación en una prueba seria. Hay algunos puntos más que puedo sugerir, pero estoy seguro de que los descubrirá usted mismo. ¡Hay muchos más puntos que no sé, pero puedes encontrarlos en Internet!
¡Buena suerte y diviertete!
ps No conozco muy bien javascript, pero algo me dice en base a la dificultad del problema, tal vez, teniendo en cuenta todo lo que C ++ puede ofrecer, sería mejor soltar javascript y hacerlo en C ++.