Os mecanismos de xadrez armazenam todas as posições analisadas anteriormente entre os movimentos


17

Estou começando a jogar com máquinas de xadrez. Percebo que os melhores mecanismos de xadrez podem levar alguns minutos para serem movidos. Eu estou querendo saber o porquê. Antes de cada movimento, o mecanismo examina todos os movimentos futuros legais com mais profundidade. No entanto, parece repetir esse exercício para o próximo passo. Dado que o movimento anterior já foi incluído na árvore de movimentos examinados, isso não é ineficiente? Ou eu entendi mal?

[Edit: Estou assumindo que a razão pela qual as análises de movimentação não são armazenadas em cache é devido a algumas limitações de memória do computador que apenas tornam mais rápido o reinício da análise]

Respostas:


20

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 = 400posiçõ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

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 .


Muito interessante, isso explica por que minha RAM quase entra em colapso quando eu estou analisando profundamente com meu mecanismo (um mistério que me surpreendeu há algum tempo).
Pablo S. Ocal

Obrigado! Muito interessante. Achei a discussão no wiki do mecanismo de xadrez fascinante.
Dom

3

Um mecanismo de xadrez típico armazena algumas das posições e suas pontuações alfa-beta entre bracketing em uma tabela de transposição que pode ser consultada durante pesquisas subsequentes. Esta tabela não é consultada diretamente para escolher a próxima jogada, mas torna a pesquisa por essa jogada mais eficiente de duas maneiras.

  1. Uma posição provavelmente será encontrada várias vezes em uma árvore de pesquisa, sendo alcançada por uma transposição ou permutação de uma sequência de movimentos. Como a tabela pode ser consultada, essa posição pode precisar ser avaliada apenas algumas vezes (para diferentes profundidades de pesquisa fixas) em vez de dezenas de vezes quando a posição é visitada e revisitada.

  2. Uma técnica padrão para pesquisas alfa-beta é usar o aprofundamento iterativo , sondando repetidamente a árvore em uma profundidade de pesquisa maior até que a profundidade terminal seja atingida. As pontuações de avaliação calculadas nas iterações anteriores são usadas para ordenar as movimentações pesquisadas nas iterações posteriores. Sabe-se que o alfa-beta tem melhor desempenho (ou seja, apaga mais da árvore de pesquisa) se boas jogadas são pesquisadas antes de más jogadas.


3

Exemplo evidenciando a memória do mecanismo:

Considere posições em que profundas novidades teóricas são descobertas, em particular o jogo Caruana vs Topalov disputado este ano. Quando você deixa o mecanismo analisar a posição após o movimento 12 por um período mais ou menos curto (digamos 10 a 15 minutos), você pode verificar os movimentos sugeridos e ver se o TN ( 13.Re2!) não aparece entre eles. Faça você mesmo o movimento, volte um passo e deixe o mecanismo analisar novamente a mesma posição por mais ou menos ao mesmo tempo. Surpreendentemente, depois de pensar um pouco, agora o mecanismo considera o TN entre os melhores movimentos e o aprova.

EDIT: A resposta original (mantida abaixo) está errada, no entanto, fornece um exemplo útil da memória do mecanismo, citada na parte superior.

Até onde eu sei, eles não iniciam a pesquisa na árvore quase do zero a cada movimento.

No entanto, eles devem ter algum tipo de função que atualize os valores para cada movimento, e essa função certamente possui alguma memória de curto prazo. Alguns exemplos são posições em que profundas novidades teóricas são descobertas, em particular o jogo Caruana vs Topalov disputado este ano. Quando você deixa o mecanismo analisar a posição após o movimento 12 por um período mais ou menos curto (digamos 10 a 15 minutos), você pode verificar os movimentos sugeridos e ver se o TN ( 13.Re2!) não aparece entre eles. Faça você mesmo o movimento, volte um passo e deixe o mecanismo analisar novamente a mesma posição por mais ou menos ao mesmo tempo. Surpreendentemente, depois de pensar um pouco, agora o mecanismo considera o TN entre os melhores movimentos e o aprova.

Não sou especialista em software de xadrez, mas isso acontece. Isso pode ser explicado pelo menos parcialmente se (como dito) a função que avalia os movimentos da posição tiver alguma memória.


2
Não. Os motores não iniciam a pesquisa em árvore do zero. Consulte a minha resposta.
SmallChess

Desculpe, mas acho que sua resposta é um pouco enganadora #
BlueTrin 7/14

1
Eu tentei deixar mais claro. Como já foi dito, a resposta está errada, no entanto, o exemplo é válido e é bom verificar (para nós, românticos, isso nos dá algumas esperanças de que, apesar dos computadores serem muito mais fortes que os humanos, às vezes a intuição, a experiência e o trabalho duro podem "superar" os original).
Pablo S. Ocal

@ pablo, seu exemplo é bom. Há memória porque, na primeira vez em que você executa a pesquisa, o mecanismo armazena as avaliações de posição em uma tabela. Quando você pesquisa a mesma posição novamente, o mecanismo poderá pesquisar muito mais rapidamente. Portanto, isso lhe dará um resultado diferente.
SmallChess

Essa última edição foi para @BlueTrin, que achou enganosa.
Pablo S. Ocal

2

Henry Keiter já lhe deu uma resposta geral, eu darei uma resposta mais técnica. É tudo sobre tabela de transposição, profundidade de pesquisa e ponto de corte. A discussão aqui é MUITO mais técnica que outras respostas, mas será benéfica para quem quiser aprender programação de xadrez.

É um mal-entendido comum que, se uma posição tiver sido avaliada antes, a pontuação da avaliação possa ser reutilizada desde que haja memória suficiente para armazenar os movimentos. A programação de xadrez é mais complicada do que isso. Mesmo com memória infinita, você ainda teria que procurar as posições novamente. Para cada jogada, uma pontuação de avaliação é anexada com sua profundidade e seu limite. Por exemplo, se o mecanismo armazena uma movimentação por falha alta, a entrada da tabela terá um limite inferior. Isso significa que, se você estiver procurando uma posição, ainda terá que verificar os limites se pode usar a pontuação da avaliação anterior.

Além disso, cada avaliação tem uma profundidade associada. Em uma estrutura de aprofundamento da iteração, à medida que você aumenta a profundidade de cada iteração, você ainda precisa procurar as posições que já pesquisou na iteração anterior.

A resposta curta para sua pergunta é que um mecanismo armazena todas as posições analisadas anteriormente (contanto que haja memória suficiente), mas esses resultados armazenados não podem ser reutilizados tão facilmente quanto você poderia imaginar . Em uma fase de abertura em que há menos repetições, esses resultados armazenados são mais úteis para a ordenação de movimentos e uma dúzia de heurísticas de redução de movimentos. Por exemplo, supõe-se que a melhor jogada da última profundidade seja a melhor na profundidade atual, portanto, ordenamos as listas de movimentos e pesquisamos o melhor antes de qualquer outro movimento. Felizmente, teríamos um ponto de interrupção precoce alto.

Não temos memória infinita para armazenar as posições. Precisamos definir um algoritmo de hash. O algoritmo de hash Zobrist nos fornece uma distribuição pseudo-aleatória, mas mais cedo ou mais tarde ainda precisaríamos substituir algumas entradas existentes.


0

Cada mecanismo possui seu próprio esquema de gerenciamento de tempo. Alguns mecanismos e GUIs permitem definir o ritmo em que o mecanismo será executado. Os mecanismos sempre calculam / avaliam / minimax o máximo que podem, dadas as restrições impostas pelas sub-rotinas de gerenciamento de tempo ou pelas configurações do usuário. Se um mecanismo pensa por um longo tempo, é provável que o controle do tempo do jogo seja lento ou o usuário o tenha configurado para jogar lentamente.

As posições e avaliações que o mecanismo calculou são armazenadas em uma tabela de hash. O usuário pode definir o tamanho do hash disponível nas configurações da maioria dos mecanismos UCI. O mecanismo em si usa uma certa quantidade de RAM e, se você definir o tamanho da tabela de hash muito alto, o computador começará a armazenar o hash no disco rígido na forma de RAM virtual. A memória do disco rígido é acessada mais lentamente que a RAM, e você geralmente poderá ouvir o disco rígido se agitando. Muitos usuários definem o tamanho da tabela de hash para que ele caiba na RAM disponível.

Uma grande proporção de qualquer tabela de hash se torna inútil após o mecanismo e seu oponente terem feito seus movimentos, pois as outras posições consideradas não são mais relevantes. O mecanismo reutilizará as avaliações armazenadas em hash, mas algumas das avaliações são incorretas devido aos efeitos do horizonte, uma vez que o mecanismo se afunda mais na mesma linha, portanto, é necessário reordenar os movimentos de candidatos.

Como a quantidade de hash é finita, um mecanismo também precisa tomar decisões sobre quais informações excluir do hash à medida que adiciona novas informações. O mecanismo não sabe com antecedência quais movimentos serão executados, portanto, pode excluir inadvertidamente informações que seriam úteis à medida que adiciona novos dados.

Os motores em geral não examinam todos os movimentos legais a uma certa profundidade. Eles eliminam certos ramos da árvore da consideração com base na poda para a frente e para trás. Além disso, se uma posição do nó folha ainda capturar ou verificar, o mecanismo continuará nessa linha até alcançar uma posição quieta (quieta). A árvore real provavelmente é bastante profunda em alguns lugares, enquanto outras linhas podem ter sido truncadas após um pequeno número de movimentos.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.