terça-feira, 10 de março de 2009

Instalando o Eclipse 3.4 no Ubuntu

Sofri muito com o Eclipse no Ubuntu ontem. A versão do repositório é só a 3.2; no site do Eclipse já existe a 3.4. Tentando instalar o subclipse para a versão 3.2, só consegui arrumar mais e mais problemas.

Hoje consegui instalar (muito facilmente, por sinal) o Eclipse 3.4 + CDT + subclipse.

Pra começar, a máquina virtual. Estou usando a openJDK:
sudo apt-get install openjdk-6-jdk

Aí, vamos selecionar essa máquina virtual como a default usada pelo sistema:
update-java-alternatives -s java-6-openjdk

(Claro, se você já tiver uma máquina virtual instalada, pode pular esses passos)

Aí instalar o Eclipse 3.4 propriamente dito:
cd ~
wget http://ftp.osuosl.org/pub/eclipse/technology/epp/downloads/release/ganymede/R/eclipse-java-ganymede-linux-gtk.tar.gz
tar xzvf eclipse-java-ganymede-linux-gtk.tar.gz
mv eclipse eclipse3.4


(Estou assumindo a versão de 32 bits. Para 64 bits, o .tar.gz é outro)

Aí criamos um laucher para facilitar as coisas. Como eu deixei as duas versões do Eclipse instaladas (a do repositório e essa), criei um launcher que usava o mesmo ícone:

sudo gedit /usr/share/applications/eclipse34.desktop

E dentro do arquivo, cole:
[Desktop Entry]
Name=Eclipse34
Comment=Develop applications in a variety of different programming languages
Exec=/home/(nome do usuário)/eclipse3.4/eclipse
Icon=eclipse48.png
Terminal=false
Type=Application
Categories=Development;
StartupNotify=true


Pronto. Eclipse 3.4 funcionando.

Consegui também instalar o subclipse adicionando o site da versão 1.4 nos plugins:
http://subclipse.tigris.org/update_1.4.x

Pra instalar o plugin de desenvolvimento em C/C++, foi só selecioná-lo nos sites que já vem com as atualizações do próprio Eclipse.

Fonte: esse site.

segunda-feira, 9 de março de 2009

Novidades

O final de semana foi produtivo para o Hal. Depois de muita briga, consegui usar o SVN para controlar a versão do código. Implementei novas funcionalidades de iterative deepening, controle de tempo, promoções e sub-promoções, além de várias correções de bugs.

Agora o Hal já consegue resolver problemas de "Mate em n movimentos".
Próximos passos: tabela de transposição, busca quiescente, melhorias na função de avaliação, protocolo xboard.

O código continua aparentemente bem organizado - nenhuma vez tive que pensar 'em que lugar essa função deve ficar??', mas a tendência é que as coisas se compliquem um pouco mais com essa lista de coisas pra fazer. Vamos ver.

sexta-feira, 6 de março de 2009

Bitboards

Bitboard é uma representação de tabuleiro peça-cêntrica, ou seja, voltada às peças e não às posições. Isso quer dizer que é rápido olhar para a peça e descobrir onde ela está no tabuleiro, mas é custoso olhar para a posição e descobrir qual peça se encontra nela.

Os bitboards são muito bons para representar tabuleiros de xadrez porque os inteiros de 64 bits tem exatamente 64 posições, exatamente como um tabuleiro convencional de 8x8. Cada um dos bits do inteiro representa uma posição, e cada peça tem um ou mais bits setados.

Traduzindo... vamos imaginar um tabuleiro hipotético de 2x2, com quatro posições possíveis. Nesse tabuleiro, as posições seriam representadas da seguinte forma:



0b0000 -> nenhuma posição, peça não se encontra no tabuleiro
0b0001 -> posição A1
0b0010 -> posição B1
0b0100 -> posição A2
0b1000 -> posição B2


Por exemplo, se as brancas só tem um peão, e ele estiver na posição A1, vamos ter um inteiro chamado iPeaoBrancas com o valor 0b0001 (ou, simplesmente, 1). Se as brancas tiverem um peão em A1 e um peão em A2, então iPeaoBrancas vai ter o valor 0b0011 (ou 3 em decimal). Uma observação interessante sobre os bitboards é que cada posição corresponde a uma potência de 2 (2 elevado a 0, 2 elevado a 1, 2 elevado a 2, etc). Se você numerar as casas do tabuleiro de 0 a 3, no nosso caso, ou de 0 a 63 no tabuleiro real, vai notar que o bitboard correspondente a cada casa vai ser 2 elevado ao número da casa.

Qual é a vantagem disso? Simples. Imagine que você queira testar se o peão branco pode capturar alguma peça. Imagine que, estando na posição A1, o peão branco pode capturar uma peça na posição B2 e, estando na posição B1, ele pode capturar peças na posição A2. No caso de estar na linha 2, o peão não poderá fazer nenhuma captura.

No nosso exemplo pra lá de simples, você poderia testar se existe um peão em A1 e uma peça inimiga em B2; depois testaria se existe um peão em B1 e uma peça inimiga em A2. Mas, no caso de um tabuleiro 8x8, os testes ficariam muito mais complicados. Então vamos definir uma forma genérica de dar a mesma resposta, e que seja muito mais rápida.

Para fazer isso, em primeiro lugar temos que definir algumas constantes que irão nos ajudar mais para frente. No nosso tabuleiro imaginário, temos apenas duas linhas e duas colunas; devemos definir constantes para as quatro possibilidades.

Começando com a linha 1: em quais posições uma peça pode estar para estar na linha 1? Resposta óbvia: A1 e B1. Então, a constante da coluna 1 vai ser A1 e B1 ao mesmo tempo, ou seja, 0b0011. Para a linha 2, seria A2 e B2 ao mesmo tempo, ou 0b1100. Para as colunas, o raciocínio é parecido. No final, ficaríamos com:

LINHA_1 0b0011
LINHA_2 0b1100
COLUN_A 0b0101
COLUN_B 0b1010


Agora conseguimos mostrar o verdadeiro valor dos bitboards. Podemos fazer operações lógicas bit-a-bit e os inteiros irão responder as nossas perguntas. Por exemplo, se você quiser saber quais são os peões brancos que estão na linha 1, é só fazer:

iPeoesLinhaA = iPeoesBrancos & LINHA_1

Aí começa a mágica. O operador usado na linha do exemplo é o & bit-a-bit, ou seja, ele faz uma 'E' de cada um dos bits entre as duas variáveis. Para exemplificar, vamos pegar uma situação em que existam dois peões brancos; um em A1 e um em B2. Aí, vamos querer saber quais peões estão na linha 1. Nesse caso, o bitboard iPeoesBrancos será:

iPeoesBrancos = 0b1001

Ou, no tabuleiro:



E a operação & bit-a-bit irá realizar o seguinte:


iPeoesBrancos -> 0b1001
LINHA_1 ->       0b0011
& bit-a-bit -----------
Resultado ->     0b0001


Como pode ser visto, o resultado está correto; Só o peão localizado em A1 está na linha 1.

O & bit-a-bit funciona como uma máscara sobre o tabuleiro que só mostra a posição que queremos olhar. Imagine que o tabuleiro está coberto com um pano preto. Em algumas posições, o pano está cortado e você consegue observar aquela parte do tabuleiro. No nosso caso, a parte 'recortada' do pano é a linha 1, conforme a figura:



No próximo post, vou colocar mais operações bit-a-bit e como elas se juntam para dar as respostas certas para a engine de xadrez.

Refactoring

Acho que a minha primeira tentativa de criar uma engine de xadrez foi no meio do ano retrasado. Estava usando o C++ Builder, da Borland, e tinha noções (a maioria muito incorretas) de como o processo devia funcionar.

As coisas acabaram ficando paradas até o início do ano passado, quando consegui ter uma versão que funcionasse razoavelmente bem. Agora o Hal era realmente uma engine, e não um jogo completo (ou seja, era um motor de jogo, sem se preocupar com interface) compatível com xboard. Eu tinha recomeçado o programa do zero, e consegui implementar nele bitboards, busca quiescente, static exchange evaluation, algumas reduções, etc, etc.

Depois de algum tempo, as coisas chegaram em um ponto em que eu não conseguia mais manter o meu próprio código. O design ficou cada vez cheio de penduricalhos, cada vez mais confuso. A idéia de ter começado em C++ se revelou não muito boa.

Mas o que motivou mesmo recomeçar o código do zero foi a total impossibilidade de adicionar algumas reduções no mecanismo de busca. O null move não funcionava nem com reza brava.

Recomecei há mais ou menos um mês atrás. Estou usando o Eclipse e fazendo tudo em C. Ontem estava debugando para conseguir fazer funcionar o básico do alpha-beta; quando a engine estiver funcionando pelo menos como um 'resolvedor' de problemas de xadrez (mate em 3, mate em 5) vou ter mais tranquilidade para continuar a partir de uma base estável.