A programação de mecanismos de xadrez é um território muito complicado, portanto, logo no início, vou apontar para o Wiki de programação de xadrez , que contém muitas informações excelentes sobre esse tópico.
fundo
Os cálculos do xadrez (e muitas outras coisas semelhantes) são geralmente modelados e pensados como "árvores de jogo" ou " árvores de decisão ". Em termos gerais, essa árvore é um gráfico direcionado, com um nó na parte superior (a posição atual), levando a um nó para cada movimento possível, cada um dos quais leva a mais nós para cada próximo movimento possível , e assim por diante.
Em sua forma mais simplista, de força bruta, os motores de xadrez geram todas as posições nesta árvore até algum limite de profundidade ("dobra"), avaliando cada posição resultante com base em alguns critérios complexos 1 . Em seguida, ele executa a jogada que parece levar ao melhor resultado. Atualmente, muitas técnicas realmente complicadas foram desenvolvidas para limitar o número de posições que o mecanismo precisa examinar, mas vou ignorá-las para os fins desta resposta, porque elas não mudam o problema real em mão.
Math Tangent
O motivo básico pelo qual os mecanismos normalmente levam a mesma quantidade de tempo para considerar cada movimento é que o tamanho da árvore de decisão aumenta exponencialmente com a profundidade ( k
).
Considere a posição inicial. A parte superior da árvore ( k=0
) é um nó. Existem vinte primeiros movimentos possíveis para as brancas, então há vinte nós em profundidade k=1
. Então, as pretas também têm vinte jogadas disponíveis para cada uma das opções das brancas: portanto k=2
, existem 20 * 20 = 400
posições possíveis! E só piora à medida que os jogadores desenvolvem suas peças!
Por exemplo, vamos fingir que sempre há vinte movimentos possíveis para cada jogador a qualquer momento 2 . Você instrui o computador a analisar cinco movimentos para cada jogador (dez dobras). Vejamos o tamanho da árvore de força bruta em cada nível. Por diversão, também veremos o número total de posições na árvore (do topo ao nível especificado).
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
O resultado de cada nível ser exponencialmente maior que o nível anterior é que o tamanho de toda a árvore é dominado pelo nível inferior . Considere o exemplo acima: o último nível sozinho contém dez trilhões de nós. O restante da árvore contém apenas quinhentos bilhões. A décima dobra contém cerca de 95% dos nós em toda a árvore (isso é verdade em cada nível). Na prática, isso significa que todo o tempo de pesquisa é gasto avaliando o "último" movimento.
Responda
Então, como isso se relaciona com a sua pergunta? Bem, digamos que o computador esteja configurado para dez camadas, como acima, e além disso "se lembra" dos resultados de suas avaliações. Ele calcula uma jogada, a executa e você faz uma jogada. Agora, foram feitos dois movimentos, portanto, remove todas as posições da memória relacionadas aos movimentos que não aconteceram e fica com uma árvore que desce os oito movimentos restantes que já foram calculados: 26.947.368.421 posições!
Tudo certo! Então, só precisamos calcular as duas últimas dobras! Usando nossa estimativa de 20 movimentos a cada profundidade, o número total de movimentos que precisamos calcular aqui ainda é superior a dez trilhões. As posições que já calculamos representam apenas 2,5% das possibilidades! Assim, mesmo armazenando em cache os resultados da última jogada, o melhor que podemos esperar é um aumento de 2,5% na velocidade! No fundo, é por isso que, mesmo que seu programa armazene em cache os resultados anteriores, você normalmente não vê uma aceleração significativa entre as jogadas (exceto casos em que o computador encontra um posicionamento forçado ou algo assim, é claro!).
Isenção de responsabilidade de simplificação
Há muita complexidade envolvida nessa questão, e é por isso que eu liguei ao wiki de programação no topo e tentei explicar a resposta em termos matemáticos amplos. Na realidade, os programas fazem geralmente peças de cache da árvore de movimento para movimento, e há outras razões pelas quais isso é insuficiente por si próprio - algumas razões simples (por exemplo, uma determinada linha pode parecer boa para oito movimentos, mas termina com uma volta -conquiste o companheiro na jogada nove!) e muitos altamente complicados (geralmente relacionados a vários métodos de poda inteligentes). Portanto, o computador deve continuar olhando mais à frente, na tentativa de evitar suposições ruins com base na profundidade de corte da jogada anterior.
1 Não vou entrar em funções heurísticas aqui, porque essa é a sua própria área incrivelmente complexa, mas frequentemente existem alguns ganhos que podem ser alcançados por meio de esquemas de cache de posição aqui.
2 Um fator de ramificação médio de 20 é provavelmente muito baixo .