Hoje é dia de resolvermos uns dos problemas mais graves do nosso atual jogo. Precisamos verificar se há peças em nosso caminho antes de realizarmos o movimento. Mas por que isso? Conforme dito no post anterior, todas as peças (com exceção do Cavalo), não podem passar por "cima" de outras em um movimento. Veja a figura abaixo que ilustra a situação:
Um movimento válido para a Torre seria uma casa antes do Peão branco. Assim como a Torre também não poderia fazer nenhum movimento horizontal neste momento, pois há um Cavalo na frente.
E como resolver isso de forma dinâmica em nosso código?
Bom, de alguma forma, nós temos que percorrer as casas do tabuleiro procurando por peças que podem interferir em nosso caminho. Mas nós temos que escrever isso, e para saber qual peça nos atrapalhará precisamos realizar algumas validações. Por exemplo, vejamos a primeira peça que encontramos no tabuleiro que não seja a Torre, que é o Cavalo. Poderíamos fazer a seguinte pergunta: o movimento da Torre é válido com relação ao Cavalo? A resposta é SIM, então essa é uma potencial peça que poderá atrapalhar nossos planos de movimento. Vejamos a segunda peça, que é o Peão branco que se encontra na primeira coluna. O movimento da Torre é válido com relação a essa peça? A resposta é SIM novamente, então esta é uma outra peça que poderia atrapalhar o movimento. Agora veja a última peça, que também é um Peão branco só que na segunda coluna. O movimento da Torre é válido com relação a essa peça? A resposta é NÃO, pois uma Torre nunca poderia chegar àquela posição considerando a posição atual dela. Então temos duas peças que podem atrapalhar o movimento. O próximo passo é verificar se cada peça que se encontra em nosso caminho está verdadeiramente no trajeto do destino. Começamos pela primeira peça, o Cavalo. Esta peça está no mesmo trajeto que o destino escolhido para a Torre? A resposta é NÃO, pois o destino da Torre é a mesma coluna só que anda várias linhas, enquanto o cavalo está na mesma linha. Agora a segunda peça, o Peão branco está no mesmo trajeto que o destino escolhido para a Torre? A resposta é SIM, porque a linha do Peão é uma linha antes do destino escolhido para a Torre. Desta forma o movimento é inválido. Se o destino da Torre fosse uma linha antes, o peão ainda estaria no trajeto, porém a linha do Peão seria uma DEPOIS do destino, então não teria problema.
Consegue entender a complexidade de traduzirmos isso para o código?
Então vamos lá. Primeiramente, criaremos um método na classe TabuleiroModel, chamado temPecaNaFrente. Este método responderá a todas as questões levantadas acima:
private boolean temPecaNaFrente(PecaModel p, int novaLinha, int novaColuna) {
boolean temPeca = false;
if (novaLinha > p.getLinha()) {
a1: for (int i = p.getLinha(); i <= novaLinha; i++) {
if (isColunaComOutraPeca(p, novaColuna, i, novaLinha)) {
temPeca = true;
break a1;
}
}
} else {
a2: for (int i = p.getLinha(); i >= novaLinha; i--) {
if (isColunaComOutraPeca(p, novaColuna, i, novaLinha)) {
temPeca = true;
break a2;
}
}
}
return temPeca;
}
boolean temPeca = false;
if (novaLinha > p.getLinha()) {
a1: for (int i = p.getLinha(); i <= novaLinha; i++) {
if (isColunaComOutraPeca(p, novaColuna, i, novaLinha)) {
temPeca = true;
break a1;
}
}
} else {
a2: for (int i = p.getLinha(); i >= novaLinha; i--) {
if (isColunaComOutraPeca(p, novaColuna, i, novaLinha)) {
temPeca = true;
break a2;
}
}
}
return temPeca;
}
O método acima verifica se a nova linha é maior do que a linha da peça selecionada. Caso seja, então vamos percorrer linha a linha, de forma crescente, para verificar se cada casa possui uma peça na frente. Repare que em cada iteração do laço for é invocado um método isColunaComOutraPeca, que será criado mais adiante. Se este método retornar verdadeiro, paramos a iteração do laço e atribuímos true a variável temPeca. Caso a nova linha seja MENOR do que a linha da peça selecionada, ou seja, está voltando, o método também faz a verificação linha a linha, porém de forma inversa.
Lembre-se, todo o nosso tabuleiro não passa de uma matriz (um array de arrays). O método isColunaComOutraPeca é criado abaixo:
private boolean isColunaComOutraPeca(PecaModel p, int novaColuna, int i, int novaLinha) {
if (novaColuna > p.getColuna()) {
for (int j = p.getColuna(); j <= novaColuna; j++) {
PecaModel pecaNaFrente = this.getPeca(i, j);
if (pecaNaFrente != null && !pecaNaFrente.equals(p)) {
if (pecaNaFrente.getColuna() == novaColuna && !pecaNaFrente.getCorOriginal().equals(p.getCorOriginal()) ) {
continue;
}
return true;
}
}
} else if (novaColuna < p.getColuna()) {
for (int j = p.getColuna(); j >= novaColuna; j--) {
PecaModel pecaNaFrente = this.getPeca(i, j);
if (pecaNaFrente != null && !pecaNaFrente.equals(p)) {
if (pecaNaFrente.getColuna() == novaColuna && !pecaNaFrente.getCorOriginal().equals(p.getCorOriginal()) ) {
continue;
}
return true;
}
}
} else {
PecaModel pecaNaFrente = this.getPeca(i, novaColuna);
if (pecaNaFrente != null && !pecaNaFrente.equals(p)) {
if (!(pecaNaFrente.getLinha() == novaLinha && !pecaNaFrente.getCorOriginal().equals(p.getCorOriginal()))) {
return true;
}
}
}
return false;
}
Este método executa a seguinte lógica. Ele verifica se a coluna de destino é maior do que a coluna da peça selecionada. No caso da Torre, isso só será verdade para movimentos lineares. Depois dessa verificação, fazemos um laço partindo da coluna da peça selecionada até a coluna de destino, e buscamos então qualquer peça que esteja naquela linha e coluna. Caso exista uma peça, e essa peça não for a própria peça selecionada, então já sabemos que há alguma peça atrapalhando o caminho. Mas ainda tem mais... se a coluna da peça que está atrapalhando o caminho for igual a coluna de destino e a cor NÃO for igual a peça selecionada, então temos aqui uma peça inimiga! E isso quer dizer que temos que eliminá-la! Então o movimento torna-se válido, caso contrário o movimento torna-se inválido. A lógica se repete caso a coluna de destino for menor do que a coluna da peça selecionada ou quando a coluna de destino é igual a coluna da peça selecionada.
UFA! Quanta coisa, não? Agora uma última coisa, precisamos chamar o método temPecaNaFrente no método realizaJogada:
public void realizaJogada(int linha, int coluna) {
if (pecaSelecionada == null) {
pecaSelecionada = this.getPeca(linha, coluna);
if (pecaSelecionada != null) {
pecaSelecionada.setSelecionada(true);
}
} else {
PecaModel outraPeca = this.getPeca(linha, coluna);
if (outraPeca != null && outraPeca.equals(pecaSelecionada)) {
pecaSelecionada.setSelecionada(false);
pecaSelecionada = null;
} else {
if (pecaSelecionada.validaMovimento(linha, coluna)
&& !this.temPecaNaFrente(pecaSelecionada, linha, coluna)) {
this.pecas[pecaSelecionada.getLinha()][pecaSelecionada
.getColuna()] = null;
this.pecas[linha][coluna] = pecaSelecionada;
pecaSelecionada.setSelecionada(false);
pecaSelecionada.setLinha(linha);
pecaSelecionada.setColuna(coluna);
pecaSelecionada = null;
}
}
}
this.notificaListener();
}
Definitivamente há outras formas de fazer, mas por enquanto essa é a maneira que encontrei.
Nos próximos POSTS continuaremos a validar os movimentos das outras peças, temos muito trabalho pela frente!
Um abraço e até logo.
if (novaColuna > p.getColuna()) {
for (int j = p.getColuna(); j <= novaColuna; j++) {
PecaModel pecaNaFrente = this.getPeca(i, j);
if (pecaNaFrente != null && !pecaNaFrente.equals(p)) {
if (pecaNaFrente.getColuna() == novaColuna && !pecaNaFrente.getCorOriginal().equals(p.getCorOriginal()) ) {
continue;
}
return true;
}
}
} else if (novaColuna < p.getColuna()) {
for (int j = p.getColuna(); j >= novaColuna; j--) {
PecaModel pecaNaFrente = this.getPeca(i, j);
if (pecaNaFrente != null && !pecaNaFrente.equals(p)) {
if (pecaNaFrente.getColuna() == novaColuna && !pecaNaFrente.getCorOriginal().equals(p.getCorOriginal()) ) {
continue;
}
return true;
}
}
} else {
PecaModel pecaNaFrente = this.getPeca(i, novaColuna);
if (pecaNaFrente != null && !pecaNaFrente.equals(p)) {
if (!(pecaNaFrente.getLinha() == novaLinha && !pecaNaFrente.getCorOriginal().equals(p.getCorOriginal()))) {
return true;
}
}
}
return false;
}
Este método executa a seguinte lógica. Ele verifica se a coluna de destino é maior do que a coluna da peça selecionada. No caso da Torre, isso só será verdade para movimentos lineares. Depois dessa verificação, fazemos um laço partindo da coluna da peça selecionada até a coluna de destino, e buscamos então qualquer peça que esteja naquela linha e coluna. Caso exista uma peça, e essa peça não for a própria peça selecionada, então já sabemos que há alguma peça atrapalhando o caminho. Mas ainda tem mais... se a coluna da peça que está atrapalhando o caminho for igual a coluna de destino e a cor NÃO for igual a peça selecionada, então temos aqui uma peça inimiga! E isso quer dizer que temos que eliminá-la! Então o movimento torna-se válido, caso contrário o movimento torna-se inválido. A lógica se repete caso a coluna de destino for menor do que a coluna da peça selecionada ou quando a coluna de destino é igual a coluna da peça selecionada.
UFA! Quanta coisa, não? Agora uma última coisa, precisamos chamar o método temPecaNaFrente no método realizaJogada:
public void realizaJogada(int linha, int coluna) {
if (pecaSelecionada == null) {
pecaSelecionada = this.getPeca(linha, coluna);
if (pecaSelecionada != null) {
pecaSelecionada.setSelecionada(true);
}
} else {
PecaModel outraPeca = this.getPeca(linha, coluna);
if (outraPeca != null && outraPeca.equals(pecaSelecionada)) {
pecaSelecionada.setSelecionada(false);
pecaSelecionada = null;
} else {
if (pecaSelecionada.validaMovimento(linha, coluna)
&& !this.temPecaNaFrente(pecaSelecionada, linha, coluna)) {
this.pecas[pecaSelecionada.getLinha()][pecaSelecionada
.getColuna()] = null;
this.pecas[linha][coluna] = pecaSelecionada;
pecaSelecionada.setSelecionada(false);
pecaSelecionada.setLinha(linha);
pecaSelecionada.setColuna(coluna);
pecaSelecionada = null;
}
}
}
this.notificaListener();
}
Definitivamente há outras formas de fazer, mas por enquanto essa é a maneira que encontrei.
Nos próximos POSTS continuaremos a validar os movimentos das outras peças, temos muito trabalho pela frente!
Um abraço e até logo.






