sábado, 24 de agosto de 2013

O livre arbítrio das peças não é tão livre assim

Bom dia.
Nosso jogo de Xadrez está evoluindo. Precisamos agora implementar as regras do jogo. E é aí que começa a ficar um pouco mais complicado.
No POST anterior, implementamos o movimento das peças, fazendo-as circular livremente por todo o tabuleiro. Mas eu e você sabemos que em um jogo verdadeiro de Xadrez, existem regras, e que essas regras impedem um determinado tipo de movimento para uma peça específica. Além disso, nenhuma peça pode "passar por cima" de outra peça, com exceção do poderoso Cavalo (minha peça preferida, diga-se de passagem).
O que precisamos agora é implementar, de alguma forma, a regra do movimento de cada peça. Por exemplo, a Torre não pode mover-se diagonalmente, enquanto que o Bispo não pode realizar movimentos horizontais/verticais, somente diagonais. O Cavalo, por sua vez, faz o movimento em "L", enquanto a Rainha herda a capacidade de movimento do Bispo + Torre.
São essas regras que vamos começar a implementar a partir de agora, e começaremos pelo mais fácil: a Torre.
Vamos fazer algumas modificações em nossas classes. Primeiramente, vamos tornar a nossa classe "PecaModel" uma classe abstrata. Por que isso? Veremos mais adiante que teremos um método em comum para todas as peças, que serão implementados de formas diferentes, e precisamos do Polimorfismo para fazer a "coisa" funcionar:

public abstract class PecaModel {...}

Não se assuste com os erros de compilação que você receberá a partir do momento que fizer isso. 
Na sequência, vamos criar um método abstrato que deverá ser implementado por todas as classes filhas e que será responsável por validar o movimento daquela determinada peça:

public abstract boolean validaMovimento(int novaLinha, int novaColuna); 

Basicamente vamos verificar se a peça pode se mover para a nova linha e a nova coluna desejada.
O próximo passo é começarmos a criar as classes de cada peça e implementarmos o método validaMovimento de acordo com a regra daquela peça. Vamos começar pela Torre, conforme dito no início:

public class Torre extends PecaModel {

    @Override
    public boolean validaMovimento(int novaLinha, int novaColuna) {
        if (this.getColuna() != novaColuna && this.getLinha() == novaLinha) {
            return true;
        } else if (this.getLinha() != novaLinha && this.getColuna() == novaColuna) {
            return true;
        }
        return false;
    }
   
    public Torre(String cor, int linha, int coluna, String corOriginal) {
        super(cor,linha,coluna,corOriginal);
    }
} 


Vamos entender o que isso faz? Primeiramente, observe a anotação @Override que indica que estamos sobrescrevendo nosso método validaMovimento. Bom, sabemos que a Torre não pode realizar movimentos diagonais, então a lógica do método validaMovimento é verificar se isso é verdade ou não. Perceba que a lógica é muito boba. O primeiro if verifica se a coluna da peça que eu cliquei é diferente da coluna de destino. Se isso for verdade, a linha de destino tem que ser IGUAL a linha da peça selecionada. Ou seja, este primeiro if valida o movimento horizontal, já que a linha é a mesma. Já o else trata o inverso. Se a linha da peça que eu cliquei for diferente da linha de destino, a coluna de destino tem que ser IGUAL a coluna da peça que eu selecionei, ou seja, estamos validando o movimento vertical, já que a coluna é a mesma. Consegue entender a complexidade de movimento de outras peças, como por exemplo o poderoso Cavalo? Bom, eu ainda não quero pensar nisso. Continuando na classe Torre, vemos que temos um construtor que chama a versão da super classe. Isso é porque cada peça tem que instanciar os atributos padrão que todas as peças tem (linha, coluna, etc). Crie o atributo "corOriginal" na classe PecaModel para que possamos ter um valor somente com PRETA ou BRANCA, mais adiante veremos o motivo disso. 
Feito isso, precisamos alterar a classe TabuleiroModel pois ela está instanciando objetos abstratos, o que está incorreto e nem compila. Precisamos alterar o método montaTabuleiro() para criar classes concretas, desta forma:

public void montaTabuleiro() {
        pecas[0][0] = new Torre("TORREPRETO.gif", 0, 0, "PRETA");
        pecas[0][1] = new Cavalo("CAVALOPRETO.gif", 0, 1, "PRETA");
        pecas[5][0] = new Peao("PEAOBRANCO.gif", 5, 0, "BRANCA");
        pecas[6][1] = new Peao("PEAOBRANCO.gif", 6, 1, "BRANCA");
    }


OBS: Ainda não criamos a validação de movimento para as outras peças, mas coloque-as no tabuleiro para que você possa verificar se o movimento da Torre está correto.
Veja que o atributo que criamos "corOriginal" é somente para dizermos se a peça é PRETA ou BRANCA.
O último passo agora é passar a responsabilidade para o Tabuleiro, para que, ao tentar realizar o movimento, este pergunte à peça se ela pode se movimentar para o destino selecionado. Precisamos alterar o método realizaJogada() para que fique desta forma:

public void realizaJogada(int linha, int coluna) {
        ...
            } else {
                if (pecaSelecionada.validaMovimento(linha, coluna)) {
                    ...
                }
            }
        }
 }

Não colocarei o método inteiro pois já temos no POST anterior, veja somente que a parte alterada foi no else, onde adicionamos a chamada do validaMovimento para a peça em questão. Todo o código do else só poderá ser executado se o movimento for válido!

Ah... temos ainda muito o que fazer. Esta foi a validação apenas da Torre, mas temos todas as outras ainda para fazer. Além do mais, você não se esqueceu de que a única peça que passa por "cima" de outra é o Cavalo, certo? Então prepare-se para isso, que no próximo POST vamos trabalhar nesta funcionalidade:

Um abraço e até a próxima!

quinta-feira, 15 de agosto de 2013

Dança das peças

Boa noite galera!
É hora de dar vida as nossas peças. O nosso tabuleiro de Xadrez precisa nos proporcionar movimentos, para que você possa usar aquela sua jogada bem trabalhada e causar arrepios em seu adversário.
Chega de conversa, vamos trabalhar porque temos muito o que fazer.
Para começar, vou partir do princípio de que você já esteja um pouco familiarizado com os eventos do Java (ActionListener, MouseListener, etc). Caso não faça ideia do que eu estou falando, é melhor dar uma lida aqui. Caso contrário, saberá que alguma de nossas classes terá que responder aos eventos de mouse (clique). Como saber qual peça está selecionada e qual casa eu cliquei? Usaremos um MouseListener que "escutará" os eventos de clique no tabuleiro para nos ajudar a responder essas perguntas.

Não postarei o código todo novamente, e sim as partes que formos alterando, ok?
Bom, então a primeira coisa a fazer é com que a nossa classe Tabuleiro implemente a interface MouseListener para escutar os eventos de clique:

public class Tabuleiro extends JPanel implements MouseListener{...}

Ao fazer isso, nós temos que fornecer implementações "válidas" para todos os métodos abstratos declarados nessa interface. Por "válidas" entenda que o método tem que ter um corpo (par de chaves). De todos os métodos, o único que realmente precisaremos escrever alguma lógica é o mouseClicked que é efetivamente o clique do mouse.
Vamos para a implementação?

@Override
    public void mouseClicked(MouseEvent arg0) {
        Celula c = (Celula)arg0.getSource();
        this.tabuleiroModel.realizaJogada(c.getLinha(), c.getColuna());
    }

Hey! Que método é esse de "realizaJogada"? Calma, já vamos chegar lá. Primeiro vamos entender esse método. Na primeira linha, usamos o método getSource() do argumento MouseEvent para descobrirmos e pegarmos que tipo de objeto veio como resposta ao clique. Como nosso tabuleiro é preenchido somente com células, o downcast é extremamente seguro, não sendo necessário fazer a verificação com instanceof. Na segunda linha, passamos a linha e a coluna da célula selecionada para um método realizaJogada do objeto TabuleiroModel, que será explicado e criado a seguir.

Como estamos aplicando boas práticas MVC no nosso projeto, a "lógica" do negócio não pode estar na camada de apresentação. E é por isso que o método realizaJogada será criado no TabuleiroModel. Mas, o que esse método precisa fazer? Como você deve lembrar, na classe TabuleiroModel possuímos uma matriz de peças. A lógica é basicamente tirar a peça selecionada da posição antiga e colocá-la na nova posição. Exemplo:
Figura 01: Preparando movimento da Torre

Observe que selecionamos a peça TORRE e queremos andar uma "casa" para frente. Vamos implementar essa lógica. Primeiramente, vamos criar uma variável na classe TabuleiroModel para representar a peca que está sendo selecionada no momento:

private PecaModel pecaSelecionada = null;

A seguir, veja a lógica do método:
public void realizaJogada(int linha, int coluna) {
        // se não há peça selecionada, pegue a peça da linha e coluna e marque-a como selecionada = true
        if (pecaSelecionada == null) {
            pecaSelecionada = this.getPeca(linha, coluna);
            if (pecaSelecionada != null) {
                pecaSelecionada.setSelecionada(true);
            }
        } else {
            // caso haja uma peça selecionada, quer dizer que falta definir o destino da peça selecionada.
            PecaModel outraPeca = this.getPeca(linha, coluna);
            // aqui verificamos se o usuário clicou na mesma peça. Caso tenha clicado, só setar a propriedade "selecionada" para false.
            if (outraPeca != null && outraPeca.equals(pecaSelecionada)) {
                pecaSelecionada.setSelecionada(false);
                pecaSelecionada = null;
            } else {
                // caso o destino selecionado não seja a própria peça selecionada, então "atualizamos" a posição da peça.
                this.pecas[pecaSelecionada.getLinha()][pecaSelecionada.getColuna()] = null;
               
                this.pecas[linha][coluna] = pecaSelecionada;
                pecaSelecionada.setSelecionada(false);
                pecaSelecionada.setLinha(linha);
                pecaSelecionada.setColuna(coluna);
                pecaSelecionada = null;
            }
        }
    }

Observe que o método "realizaJogada" será chamado a cada vez que o usuário clicar o mouse.
Se compilarmos e executarmos este código, não vamos notar diferença nenhuma na nossa tela. Isso porque nós não atualizamos o nosso tabuleiro visual! E agora, quem poderá nos salvar?
Precisamos criar uma forma de "avisar" a camada de visão (o nosso tabuleiro visual) que o modelo foi alterado. Se você já ouviu falar no padrão "Observer", sabe do que estou falando. Vamos criar uma simples interface "ouvidora" de tabuleiros:

public interface TabuleiroListener {
    public void tabuleiroChanged();
}

Esta interface define apenas um método que será responsável por atualizar o nosso tabuleiro visual. E quem deve implementar essa interface? O "provedor" dos eventos, ou seja, aquela classe que irá disparar os eventos. Você já sabe. É claro que é a classe Tabuleiro quem deve implementar esta interface, visto que os cliques (ações) ocorrem lá. Vamos ao código?

public class Tabuleiro extends JPanel implements TabuleiroListener, MouseListener {
...
 @Override
    public void tabuleiroChanged() {
        this.montaTabuleiro();
    }
}

Se você olhar nos posts anteriores, saberá que o método montaTabuleiro coloca as peças no lugar e reorganiza o layout. Então a ideia é simples, mas quem que vai chamar esse método tabuleiroChanged()? Beleza, ele está aí declarado, implementado, mas não vejo ninguém o chamando. Bom, se o modelo foi alterado, quem é responsável por avisar a visão de que houve alguma mudança? É claro que é o próprio modelo quem deverá invocar esse método!
Vamos fazer isso funcionar de vez.
Crie uma variável do tipo TabuleiroListener na classe TabuleiroModela:

private TabuleiroListener listener;

Em seguida, crie um método configurador na mesma classe, para atribuirmos um valor a essa variável:
public void setTabuleiroListener(TabuleiroListener listener) {
        this.listener = listener;
}

Agora, no construtor da classe Tabuleiro, registre-o como "ouvinte" do modelo:
tabuleiroModel.setTabuleiroListener(this);

Esta linha está dizendo: "hey, quero ficar sabendo de todas as alterações aí no seu modelo!".
Pois bem, agora só falta dizer para o modelo avisar a visão de que ele mesmo se alterou.
Lembra do método realizaJogada()? Pois bem, ao final dele, basta fazer esse aviso a visão:

listener.tabuleiroChanged();

Ou seja, a cada jogada realizada, esse método será invocado. E adivinha... ? O método tabuleiroChanged remonta todo o tabuleiro, pegando as alterações que foram feitas!
Veja o resultado abaixo:

Imagem 02: Torre prestes a ser movida
Imagem 03: Torre em sua nova posição

Ufa! Quanta coisa! Mas não se iluda, falta muuuuita coisa a ser feita. Por exemplo, ainda não estamos validando o movimento das peças... a torre pode se movimentar em todos os sentidos, o que em um jogo de Xadrez isso não é permitido. Então, mãos a obra e aguardem o próximo POST para fazermos o movimento válido das peças, verificando se existem peças "inimigas"e todas as particularidades do jogo.
É agora que começa a ficar divertido, então, não percam!

Um abraço e até a próxima :)

terça-feira, 30 de julho de 2013

Colocando as peças no lugar

Olá.
Depois de alguns dias de molho e outros ocupado demais, cá estou para continuarmos nosso jogo de Xadrez.
No último POST, prometi que iria mostrar como colocar as peças no tabuleiro.
Pois bem. As peças na realidade nada mais são do que uma coleção de PecaModelS na matriz Pecas, localizada na classe TabuleiroModel. Você se lembra disso?
Caso não lembre, declaramos ele da seguinte forma:

private PecaModel pecas[][];

Nós vamos colocar as nossas peças no método montaTabuleiro() da classe TabuleiroModel, que havíamos deixado em branco antes. Observe que para construir uma Peca, precisamos informar a cor, a linha e a coluna:

public void montaTabuleiro() {
        pecas[0][0] = new PecaModel("TORREPRETO.gif", 0, 0);
        pecas[0][1] = new PecaModel("CAVALOPRETO.gif", 0, 1);
        ...
    }

Repare que só fiz para as duas primeiras peças, mas você deve terminar até completar todas as peças. Agora, porque eu coloquei aquele nome "TORREPRETO.gif", sendo que ali teoricamente deveria ser a cor da peça? Bem, vou explicar isso daqui a pouco, mas vou adiantar um pouco. Nós precisamos representar as nossas peças graficamente, ou seja, precisamos ter um cavalo ou uma torre em forma de figura para que seja um jogo de Xadrez de verdade, e o que eu informei ali é um nome de um arquivo. 

Continuando, vamos para a classe Peca, aquela que extends JLabel, lembra? Vamos relembrar o construtor desta classe:

public Peca(PecaModel peca) {
        this.pecaModel = peca;
}

Aqui nada de estranho, associamos um PecaModel a nossa classe Peca. Mas é agora que vem o segredo. Lembra que no construtor de PecaModel eu passei um nome de arquivo? Pois é aqui que vamos usá-lo, para que, ao associarmos um PecaModel a uma Peca, possamos buscar uma imagem para associação!
Vamos mudar o nosso construtor de Peca para o seguinte código:

public Peca(PecaModel peca) {
        this.pecaModel = peca;
        this.setIcon(new ImageIcon(getClass().getResource(
                "/imagens/" + pecaModel.getCor())));

}

Observe o método setIcon (sim, é this porque Peca É-UM JLabel, e JLabel possui um método setIcon!).
E que diretório é esse /imagens? Crie um subdiretório no src com o nome imagens. É aqui que suas peças deverão ser adicionadas. Observe que o nome do arquivo deve coincidir com o nome que você passou no construtor de PecaModel.

Chegando na última parte do nosso POST de hoje, precisamos mostrar essas peças no tabuleiro. No artigo anterior, conseguimos mostrar o tabuleiro, através do método montaTabuleiro da classe Tabuleiro. Vamos modificá-lo para adicionar as peças? Destacarei as partes que foram adicionadas em vermelho para facilitar o entendimento:

private TabuleiroModel tabuleiroModel = new TabuleiroModel();

public void montaTabuleiro() {
        this.setLayout(new GridLayout(8, 8));
        tabuleiroModel.montaTabuleiro();

        this.removeAll();
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                PecaModel pecaModel = tabuleiroModel.getPeca(i, j);
                Celula celula;
                if (pecaModel != null) {
                    Peca peca = new Peca(pecaModel);
                    celula = new Celula(peca);
                } else {
                    celula = new Celula(i, j);
                }

                if ((i + j) % 2 == 0) {
                    celula.setBackground(Color.WHITE);
                } else {
                    celula.setBackground(Color.BLACK);
                }
                this.add(celula);
            }
        }
        this.revalidate();
    }

Vamos a lógica dos elementos novos adicionados no código. Primeiramente, instanciamos um TabuleiroModel fora do método montaTabuleiro para que possamos ter uma referência ao modelo do tabuleiro (ou seja, acessar suas peças, etc). Na sequência, pedimos para o tabuleiro se organizar (para o modelo se ajustar, colocando as devidas peças em seus devidos lugares). Para cada linha/coluna, nós criamos um PecaModel e verificamos se naquela linha e coluna há uma peça. Caso haja (pecaModel != null), então construímos uma Celula passando quem? Exatamente a peca que está naquela posição! A célula já saberá em qual linha e coluna deverá ser colocada, pois a própria Peca tem essa informação. Caso não haja nenhuma peça na respectiva linha e coluna, construímos uma célula em branco. Muito bacana, não é?
O resultado deverá ficar assim:



Imagem 01: Tabuleiro com peças

Mas ainda temos muito trabalho pela frente. Neste momento, não conseguimos mover sequer uma peça e nem fazer nenhum tipo de interação, ou seja, JOGAR. No próximo POST, aprenderemos a criar VIDA para as nossas queridas peças! Um abraço e até logo!                                                  






sexta-feira, 19 de julho de 2013

Erro ao liberar conexão no DB2

Para liberar uma conexão (chamar close() em um objeto Connection) utilizando DB2, verifique o autoCommit da sua conexão. Caso esteja como FALSE, você precisará fazer um commit() ou um rollback() explícito na conexão antes de liberá-la, se não o fizer, você receberá um belo SQLException dizendo que o estado da transação é inválido. Caso o seu autoCommit estiver como TRUE, então não é necessário fazer os comandos acima.
Demorei uns 40 minutos entre debug e pesquisa no Google para achar uma referência.
Estou utilizando o driver db2java.jar e não procurei um driver mais recente, então pode ser que já tenham corrigido essa detalhe em versões mais recentes.
Enfim, se enfrentou esse mesmo problema, aí está a solução.

Até a próxima dica rápida! :)

quinta-feira, 18 de julho de 2013

Criando forma ao nosso tabuleiro

Boa noite!
No post anterior, demos início ao nosso jogo de Xadrez.
Hoje vamos dar forma ao nosso tabuleiro. Mas, para isso, precisamos modificar e incluir novas coisas em nosso projeto.
Nós precisamos de uma maneira de representar o modelo de nosso tabuleiro. Aqui não estamos falando do tabuleiro em si, aquele que você vê na tabela, mas estamos falando do que um tabuleiro contém. Então, vamos criar o código que representará isso:
public class TabuleiroModel {
 private PecaModel pecas[][];

 public TabuleiroModel() {
  pecas = new PecaModel[8][8];
 }

 public void montaTabuleiro() {
 }

 public PecaModel[][] getPecas() {
  return pecas;
 }

 public void setPecas(PecaModel[][] pecas) {
  this.pecas = pecas;
 }
 
 public PecaModel getPeca(int linha, int coluna) {
  return pecas[linha][coluna];
 }
}

Veja que aqui não temos nenhum elemento de interface gráfica. Esta classe apenas representa o modelo do tabuleiro. Mas e o que é aquele PecaModel? Bom, precisamos de Peças em nosso jogo, correto? Então, assim como o tabuleiro, precisamos de uma classe que representa cada peça do jogo. Vamos ao código, para que a classe TabuleiroModel faça mais sentido:
public abstract class PecaModel {
 private boolean selecionada;
 private String cor;
 private int linha;
 private int coluna;

 public int getLinha() {
  return linha;
 }

 public void setLinha(int linha) {
  this.linha = linha;
 }

 public int getColuna() {
  return coluna;
 }

 public void setColuna(int coluna) {
  this.coluna = coluna;
 }

 public PecaModel(String cor, int linha, int coluna) {
  this.cor = cor;
  this.linha = linha;
  this.coluna = coluna;
 }

 public boolean isSelecionada() {
  return selecionada;
 }

 public void setSelecionada(boolean selecionada) {
  this.selecionada = selecionada;
 }

 public String getCor() {
  return cor;
 }

 public void setCor(String cor) {
  this.cor = cor;
 }
}

Bom, a classe acima representa uma peça. Não sabemos que tipo de peça é (torre, cavalo, etc), por isso ela é uma classe abstrata. Não faz sentido fazer Peca p = new Peca(). Que cor? Que tipo de peça? Por esse motivo ela é abstrata. Se observamos a classe TabuleiroModel, vamos encontrar uma matriz de PecaModel, representado pelo atributo pecas. Ele representa uma matriz de 8x8, onde cada posição dessa armazenará um PecaModel. E faz muito sentido isso, porque dizemos "um tabuleiro tem várias peças". O método que nos auxiliará a "pegar" determinada peça de nosso tabuleiro é o getPeca, onde o mesmo retorna um PecaModel, recebendo a linha e a coluna que a suposta peça se encontra (mais para frente vamos entender o porque de "suposta").

A princípio, nosso modelo está pronto. Temos nosso tabuleiro e nossa peça representados corretamente. Agora é hora de partirmos para a interface gráfica do nosso tabuleiro! Precisamos fazer alguns ajustes antes de termos nosso tabuleiro na tela.No post anterior, nós já criamos a classe que representa o tabuleiro graficamente. O que precisamos fazer agora é representar a Peca graficamente. Vamos escrever isso?
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Peca extends JLabel {
 private PecaModel pecaModel;

 public PecaModel getPecaModel() {
  return pecaModel;
 }

 public void setPecaModel(PecaModel pecaModel) {
  this.pecaModel = pecaModel;
 }

 public Peca(PecaModel peca) {
  this.pecaModel = peca;
 }
}

A classe Peca faz um extends em JLabel, para que possamos plotá-lo no tabuleiro. É um label normal, não há nada de diferente aqui. Além disso, observe que temos um atributo do tipo PecaModel (que é o modelo). O que é interessante é que não estamos colocando nossa regra de negócio na tela, o que é um bom começo, visto que, se lá na frente formos precisar usar uma interface Web, não teríamos problemas.

Calma, já estamos quase lá...

Lembra da classe Celula do post anterior? Vamos melhorá-la para se adequar a nossa nova realidade:
import javax.swing.JPanel;

public class Celula extends JPanel {
 private int linha;
 private int coluna;
 private Peca peca;
 
 public Celula(Peca peca) {
  this(peca.getPecaModel().getLinha(),peca.getPecaModel().getColuna());
  this.peca = peca;
  this.add(peca);
 }
 
 public Celula(int linha, int coluna) {
  this.linha = linha;
  this.coluna = coluna;
 }

 public int getLinha() {
  return linha;
 }

 public void setLinha(int linha) {
  this.linha = linha;
 }

 public int getColuna() {
  return coluna;
 }

 public void setColuna(int coluna) {
  this.coluna = coluna;
 }

 public Peca getPeca() {
  return peca;
 }

 public void setPeca(Peca peca) {
  this.peca = peca;
 }

}
Vamos com calma. Fiz questão de destacar as partes mais importantes dessa classe. Primeiramente, vemos um atributo do tipo Peca. Mas dessa vez NÃO é nosso modelo, é a Peca representada graficamente... pois quem tem o modelo da peca (PecaModel) é a própria classe Peca! Observe também os dois construtores da classe Celula, um recebendo uma Peca e outro recebendo uma linha e uma coluna... mas agora não é hora de explicar o porque disso. Apenas atente-se ao fato de que quando o construtor que recebe uma Peca é invocado, a célula adiciona a Peca a ela mesma, como se estivéssemos dizendo "Ok, coloque uma peça nessa célula aqui".
Bom, chegou a hora de montar o nosso tabuleiro (pelo menos fazer ele aparecer na tela!).
import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class Tabuleiro extends JPanel {
 public void montaTabuleiro() {
  this.setLayout(new GridLayout(8, 8));
  this.removeAll();
  for (int i = 0; i < 8; i++) {
   for (int j = 0; j < 8; j++) {
    Celula celula;
    celula = new Celula(i, j);
    if ((i + j) % 2 == 0) {
     celula.setBackground(Color.WHITE);
    } else {
     celula.setBackground(Color.BLACK);
    }
    this.add(celula);
   }
  }
  this.revalidate();
 }
}
Ué, e cade todos aquelas classes que sofremos para codificar?
Calma... estamos fazendo a base para o próximo POST, se não ia perder toda a graça, não é mesmo? :)
Bom, vamos explicar esse código:
A classe Tabuleiro continua sendo um JPanel, como no post anterior. Observe que fizemos um duplo laço (para simular a varredura em uma matriz mesmo), sendo o "i" a linha e o "j" a coluna. Dentro do laço mais interno, veja que instanciamos um objeto Celula, passando como parâmetros quem? A linha e a coluna! Ou seja, agora sabemos exatamente qual posição a célula ocupará no tabuleiro. Para saber se ela deve ser preta ou branca, fazemos a seguinte lógica: se o resto da divisão da soma entre i e j for igual a 0, então pintamos de branco, se não pintamos de preto. Após termos pintado a célula, precisamos adicioná-la no painel, através do método add(celula).
O final deverá se parecer com isso:

Ufa! Quanto trabalho por hoje! No próximo POST, vamos utilizar toda a estrutura que criamos anteriormente, para começarmos a colocar as nossas peças no tabuleiro! Uma prévia do que vem pela frente:
  Nosso tabuleiro conterá peças! :) Então, até a próxima!

PS: Achei esse link para formatar códigos muito bom! Parabéns ao criador.





segunda-feira, 15 de julho de 2013

Todos podem aprender brincando

Boa noite!
Estive revirando alguns materiais da faculdade/pós graduação neste fim de semana e acabei achando um projeto muito bacana, na época em que o professor tentava de uma maneira divertida nos ensinar a programação orientada a objetos. Este projeto consistia em fazermos um jogo de Xadrez, onde precisaríamos basicamente montar a lógica do movimento das peças, como em um jogo real mesmo. E como na época eu não havia terminado todo ele, resolvi ressuscitá-lo e compartilhar com vocês, para que possamos aprender juntos! E melhor, começando do ZERO! Ou seja, vamos aprender desde a criação do tabuleiro até as peças do jogo, então pegue sua cadeira e vamos em frente!

1) Início
Para darmos início ao nosso jogo de Xadrez, precisamos saber os componentes que precisamos para montá-lo:
a) Um tabuleiro com 64 posições, sendo intercaladas em cores de preto/branco, ou seja, uma matriz de 8,8, onde teremos os eixos X e Y, começando na posição 0 e terminando na posição 7.
b) Peças do Xadrez: precisamos de todas as peças do nosso jogo (peões, reis, rainhas, etc) e que possam ser peças pretas ou brancas, pois no mínimo são dois jogadores.
c) Figuras: precisamos de figuras para representar as peças no tabuleiro

2) Implementação - Tabuleiro
Tendo em mente o que precisamos, é hora de partir para o trabalho duro. Vamos começar com o tabuleiro e depois, gradativamente, iremos programando os demais componentes. Bom, como dito anteriormente, um tabuleiro é composto por uma matriz de 64 posições (8 x 8), em que cada posição do tabuleiro corresponde a uma posição na matriz. Por exemplo, a primeira "casa" do tabuleiro corresponde a posição 0,0 da matriz, bem como a segunda casa (na primeira linha) representa a posição 0,1 da matriz. A imagem a seguir ajuda a interpretar isso:
Imagem 01: Parte de um tabuleiro de Xadrez

Ou seja, o eixo Y é representado pelo primeiro número e o eixo X pelo segundo. 

Mas, não basta termos vários quadrados pintados de preto ou branco se eles não tiverem nenhuma ação, certo? As células precisam ser representadas por algo... algo que tenha as coordenadas X e Y e ao mesmo tempo possam ser configuradas com cor. Bom, isso pode ser um botão, um Panel... optaremos aqui pelo Panel (JPanel). Não há nenhum motivo particular nisso, apenas escolhemos JPanel para representar as células. 

Vamos então implementar a dificílima classe que representará isso?

public class Celula extends JPanel {
    private int linha;
    private int coluna;
}

Só isso? Sim, por enquanto sim.  Nossa classe Celula ainda não faz nada de útil. O que ela sabe atualmente é em que posição do tabuleiro ela se encontra - e só.

O tabuleiro
Bom, sabemos que um tabuleiro possui VÁRIAS células, e elas precisam ser representadas por uma matriz. 
Já que temos a classe Celula, precisamos dizer ao tabuleiro que ele terá várias instâncias dela. O tabuleiro também é um componente gráfico, então mais uma vez escolheremos um JPanel para representá-lo.
Vamos ao código:

public class Tabuleiro extends JPanel {
    private Celula[][] celulas = new Celula[8][8];
}

Veja o que fizemos, declaramos que um tabuleiro conterá uma matriz de células (em Java isso se chama array multidimensional, mas não entraremos em detalhes muito técnicos aqui). Este código está dizendo o seguinte, "declare em meu tabuleiro uma matriz de 8,8 que totalizará 64 posições". 

E então você quer dizer que rodando tudo isso já vai funcionar? De maneira nenhuma. Isso é apenas o COMEÇO. Precisamos ir com calma para que a gente não se perca :)

No próximo POST faremos a construção dinâmica do tabuleiro. Ele se parecerá com o seguinte:

Imagem 02: Tabuleiro de Xadrez completo

Então não percam o próximo POST! Até breve!

domingo, 7 de julho de 2013

Não reinvente a roda - alguém já fez isso por você!

Boa noite!
O assunto de hoje é algo muito interessante e que eu descobri há pouco tempo, e que se eu tivesse descoberto antes, teria poupado muitas e muitas noites de sono.
Mas que solução mágica é essa?
Bom, quem nunca pensou em como seria bom se os criadores da linguagem Java tivessem pensado em TUDO, como por exemplo, criar um método na classe String que fosse segura com relação a irritante exceção NullPointerException. Bem, nós sabemos que não dá para se pensar em tudo - nós é que precisamos cuidar do que estamos fazendo. Mas eu sempre fiquei com uma pulga atrás da orelha e me perguntava porque ninguém havia feito métodos para evitar esse tipo de coisa, afinal é relativamente simples, não é mesmo?
Até que um dia, olhando um extenso código de outra pessoa eu vi um tal de StringUtils.isEmpty. WTF? Pensei comigo, "bom, a pessoa deve ter feito essa classe pois com certeza sempre teve a mesma preocupação que eu, fazer as coisas de forma mais elegante e segura" (sim, o elegante está destacado aqui pois programar em Java qualquer um programa, mas programar com elegância são poucos). Ao abrir a classe, vi um import bem peculiar: org.apache.commons.lang3.StringUtils. Fiz uma pesquisa básica no Google e... voilá! Descobri que a Apache tem um excelente projeto com várias coisas úteis desse tipo! E o nome não poderia ser mais claro - Apache Commons. E fica ainda melhor: lá você poderá encontrar não só classes utilitárias do pacote java.lang, mas de várias outras, como Collections, e-mail, EL... 
As duas que mais me chamaram a atenção, até o momento, foram as classes StringUtils e ObjectUtils. Vamos ver alguns métodos?

StringUtils:

  • isEmpty(CharSequence cs) - Verifica se o CharSequence é nulo OU vazio. Exemplo:

 StringUtils.isEmpty(null)      = true
 StringUtils.isEmpty("")        = true
 StringUtils.isEmpty(" ")       = false
 StringUtils.isEmpty("bob")     = false
 StringUtils.isEmpty("  bob  ") = false
  • difference(String str1, String str2) - Retorna a diferença das duas Strings. Exemplo:
StringUtils.difference(null, null) = null StringUtils.difference("", "") = "" StringUtils.difference("", "abc") = "abc" StringUtils.difference("abc", "") = "" StringUtils.difference("abc", "abc") = "" StringUtils.difference("ab", "abxyz") = "xyz" StringUtils.difference("abcde", "abxyz") = "xyz" StringUtils.difference("abcde", "xyz") = "xyz"

ObjectUtils:

  • defaultIfNull(T object, T defaultValue) - Atribui o valor default caso o objeto passado seja nulo. Exemplo:
 ObjectUtils.defaultIfNull(null, null)      = null
 ObjectUtils.defaultIfNull(null, "")        = ""
 ObjectUtils.defaultIfNull(null, "zz")      = "zz"
 ObjectUtils.defaultIfNull("abc", *)        = "abc"
 ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE

OBS: Exemplos tirados da própria documentação!

Isso não é mágico? Eu pelo menos achei sensacional, e com certeza usarei emmeus projetos. Além de serem métodos muito eficientes, deixam o seu códigoextremamente limpo e elegante.
Para mais informações, visite o site da Apache Commons! Os exemplos acima estão no componente Lang, e você pode ir direto no link clicando aqui.

Por hoje é só minha gente, um abraço e até a próxima!