/// <summary> /// Avalia a Dama. /// </summary> /// <remarks> /// Mobilidade e ataques a casas perto ao rei pode ser addicionada. /// </remarks> /// <param name="pontuacao">Pontuação do lado branco ou preto</param> /// <param name="indice">Índice da casa da dama</param> private void AvaliaDama(Pontuacao pontuacao, int indice) { Fase -= Pontuacao.Fase.DAMA; pontuacao.Inicial += Pontuacao.Material.DAMA_INICIO; pontuacao.Final += Pontuacao.Material.DAMA_FINAL; pontuacao.Final += Pontuacao.Tabela.CENTRALIZACAO[Defs.Converte12x12Para8x8(indice)] / 2; }
/// <summary> /// Avalia o bispo. /// </summary> /// <remarks> /// Vai tentar centralizar o bispo. /// Outro item que pode ser adicionado é uma relação com os próprios peões, /// não estando no quadrado da mesma cor do bispo. /// </remarks> /// <param name="pontuacao">Pontuação do lado branco ou preto</param> /// <param name="indice">Índice da casa do bispo</param> private void AvaliaBispo(Pontuacao pontuacao, int indice) { Fase -= Pontuacao.Fase.BISPO; pontuacao.Inicial += Pontuacao.Material.BISPO_INICIO; pontuacao.Inicial += Pontuacao.Tabela.CENTRALIZACAO[Defs.Converte12x12Para8x8(indice)]; pontuacao.Final += Pontuacao.Material.BISPO_FINAL; pontuacao.Final += Pontuacao.Tabela.CENTRALIZACAO[Defs.Converte12x12Para8x8(indice)]; }
/// <summary> /// Avalia o Rei. /// </summary> /// <remarks> /// Apenas dá um bônus para peões na frente do rei, ou seja, escudo de peão (pawn shield). /// O que pode ser adicionado é uma penalidade para muitos peões inimigos perto do rei, o que /// significa que um ataque de peão está se formando. /// Especialmente em termos de segurança do rei, se as peças inimigas estão atacando a área próxima ao rei, /// pode ser um grande valor a este item. Em geral a segurança do rei é difícil de calibrar corretamente e /// requer muitos testes. /// Além disso, algo a considerar é a presença da dama inimiga ao avaliar a segurança do rei. Sem a dama o /// valor da segurança do rei reduz drasticamente. /// </remarks> /// <param name="pontuacao">Pontuação do lado branco ou preto</param> /// <param name="indice">Índice da casa do rei</param> /// <param name="dados_rei">Informação relativa à cor a ser avaliada.</param> private void AvaliaRei(Pontuacao pontuacao, int indice, DadosRei dados_rei) { for (int i = 0; i < dados_rei.DirecaoEmFrente.Length; i++) { if (Tabuleiro.ObtemPeca(indice + i) == dados_rei.PeaoAmigo) { pontuacao.Inicial += Pontuacao.Rei.PEAO_ESCUDO; } } pontuacao.Inicial += dados_rei.TabelaInicio[Defs.Converte12x12Para8x8(indice)]; }
/// <summary> /// Avalia peões pretos. /// </summary> /// <see cref="AvaliaPeaoBranco(int)"/> /// <param name="indice">Índice da casa do peão</param> private void AvaliaPeaoPreto(int indice) { Fase -= Pontuacao.Fase.PEAO; Preto.Inicial += Pontuacao.Material.PEAO_INICIO; Preto.Inicial += Pontuacao.Tabela.PEAO_PRETO[Defs.Converte12x12Para8x8(indice)]; if (indice == (int)Defs.INDICE.D5 || indice == (int)Defs.INDICE.E5) { Preto.Inicial += Pontuacao.Peao.PEAO_CENTRAL_1; } if (indice == (int)Defs.INDICE.D6 || indice == (int)Defs.INDICE.E6) { Preto.Inicial += Pontuacao.Peao.PEAO_CENTRAL_2; } Preto.Final += Pontuacao.Material.PEAO_FINAL; Preto.Final += Pontuacao.Tabela.PEAO_PRETO[Defs.Converte12x12Para8x8(indice)]; }
/// <summary> /// Avalia peões brancos. /// </summary> /// <remarks> /// Valor material, valor na casa de acordo com uma tabela e bônus de centralização. /// Outros termos que podems ser adicionados: /// Peões passados: bônus para peões que não podem ser capturados por peões inimigos. /// Peões isolados: penalidade para peões sem peões amigos em colunas vizinhas. /// Peões conectados: bônus para peões que se apoiam. /// Peões duplicados: penalidade para peões na mesma coluna. /// Peões para trás: penalidade para peões que não podem avançar sem encontrar os peões inimigos. /// Peões candidatos: bônus para peões que podem se tornar passados. /// Outra idéia é armazenar o valor da estrutura de peões em uma tabela, e quando encontramos /// a mesma estrutura de peões mais tarde, podemos usar o valor calculado dessa tabela. Isso ajuda /// o desempenho, pois a estrutura do peão pode repetir muito em uma pesquisa. /// Neste caso, podemos usar uma chave zobrist para a estrutura do peão. Normalmente, isso é /// chamado de "pawn hash table". /// </remarks> /// <param name="indice">Índice da casa do peão</param> private void AvaliaPeaoBranco(int indice) { Fase -= Pontuacao.Fase.PEAO; Branco.Inicial += Pontuacao.Material.PEAO_INICIO; Branco.Inicial += Pontuacao.Tabela.PEAO_BRANCO[Defs.Converte12x12Para8x8(indice)]; if (indice == (int)Defs.INDICE.D4 || indice == (int)Defs.INDICE.E4) { Branco.Inicial += Pontuacao.Peao.PEAO_CENTRAL_1; } if (indice == (int)Defs.INDICE.D3 || indice == (int)Defs.INDICE.E3) { Branco.Inicial += Pontuacao.Peao.PEAO_CENTRAL_2; } Branco.Final += Pontuacao.Material.PEAO_FINAL; Branco.Final += Pontuacao.Tabela.PEAO_BRANCO[Defs.Converte12x12Para8x8(indice)]; }
/// <summary> /// Retorna a lista ordenada de movimentos. /// </summary> /// <remarks> /// Ordem de classificação: /// 1. Movimento melhor vindo da tabela de transposição. /// 2. Capturas /// 3. Movimentos simples classificados pela tabela de valores. /// /// Falta aqui os movimentos matadores (killer moves). Quase todos os programas de xadrez /// usam esta técnica. Eu me pergunto se alguém poderia fazer isso e se faria o Enxadrista /// um pouco melhor. /// </remarks> /// <param name="cor">Cor do lado com movimentos a ordenar.</param> /// <param name="lista">List de movimentos.</param> /// <param name="melhor">Melhor movimento que será ordenado primeiro, normalmente da tabela de transposição</param> /// <returns>Lista ordenada de movimentos.</returns> public List <Movimento> Orderna(Cor cor, List <Movimento> lista, Movimento melhor) { foreach (var movimento in lista) { if (movimento.Equals(melhor)) { movimento.ValorOrdenacao = 100000000; continue; } if (movimento.Captura()) { movimento.ValorOrdenacao = ValorCaptura(movimento) * 10000; continue; } int indice_peca = IndicePeca(movimento.Peca); int indice_casa = Defs.Converte12x12Para8x8(movimento.IndiceDestino); movimento.ValorOrdenacao = Tabela[indice_peca][indice_casa]; } return(lista.OrderByDescending(m => m.ValorOrdenacao).ToList()); }
/// <summary> /// Atualiza informação sempre que um bom movimento é encontrada. /// </summary> /// <remarks> /// Note que consideramos somente os movimentos simples. Captura já possui /// um valor maior do que movimentos simples. /// </remarks> /// <param name="cor">Cor do lado fazendo o movimento.</param> /// <param name="movimento">Movimento considerado bom.</param> /// <param name="profundidade">Profundidade que o movimento foi pesquisado.</param> public void AtualizaHistoria(Cor cor, Movimento movimento, int profundidade) { if (movimento.Tatico()) { return; } int indice_peca = IndicePeca(movimento.Peca); int indice_casa = Defs.Converte12x12Para8x8(movimento.IndiceDestino); Tabela[indice_peca][indice_casa] += profundidade; // Se o valor na tabela estiver muito alto, é feito um ajuste a todos valores. if (Tabela[indice_peca][indice_casa] > 9000) { for (int peca = 0; peca < NUMERO_PECAS; peca++) { for (int casa = 0; casa < NUMERO_CASAS; casa++) { Tabela[peca][casa] /= 8; } } } }