problematic
I have a program in which I do the N Queens algorithm graphically so that it is a game, the whole program works fine and when the queens are placed correctly everything runs perfect, but my problem starts as follows.
When I move the pieces I have an arrangement where it should represent the current position of the piece on the board (Everything I say is printed in the program) but from time to time when I get to move the pieces very fast it does not do the operations properly and sometimes the fix makes me wrong, this is not so noticeable from the computer that I have since it has good components but when I run the program on a common computer it starts to generate problems with it.
I think that the main problem is the methods of mouseReleased
and mousePressed
where I execute the operations that take care of the arrangement that I mention, I don't know how I could improve the performance of the program so that everything runs better, both those methods that I mention and e rest of the methods of the program, so if you could help me with that I would be very grateful.
The method of
posicion
this poorly optimized to a great extent and in many occasions generates errors when positioning elements.
ABSTRACT
The program fails sometimes even though all the queens are placed properly, the only way for the program not to fail at all is to move the pieces very slowly and Felicidades, completaste el juego de N reinas
instead gives the message with the error that happens in Sometimes the program simply launches a message mentioning the error even though this is not correct.
package otraprueba;
import java.awt.Color;
import java.awt.event.*;
import javax.swing.BorderFactory;
import javax.swing.*;
import javax.swing.border.Border;
public class OtraPrueba extends JFrame implements ActionListener {
static int reinas = 0;
String[][] algoritmo = new String[reinas][reinas];
String[][] comprobacion = new String[reinas][reinas];
int count = 0;
int anchoAlto = 50;
int margen = 25;
int espacio = 50;
JPanel jpanel = (JPanel) this.getContentPane();
JLabel ex = new JLabel();
JLabel label[] = new JLabel[reinas];
JLabel tablero[][] = new JLabel[reinas][reinas];
Border border = BorderFactory.createLineBorder(Color.black, 1);
String[] parts;
int x, y, cooX, cooY, newI, newJ;
JButton boton1;
public static void main(String[] args) {
reinas = Integer.parseInt(JOptionPane.showInputDialog(null, "Ingrese la cantidad de reinas"));
OtraPrueba op = new OtraPrueba();
op.setBounds(0, 0, (60 * reinas), (60 * reinas));
op.setVisible(true);
op.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public OtraPrueba() {
// Declaracion de reinas
for (int i = 0; i < label.length; i++) {
label[i] = new JLabel();
// r + r + r + r
label[i].setBounds(margen + (espacio * i), margen, anchoAlto, anchoAlto);
label[i].setText("Q" + (i + 1));
label[i].setForeground(Color.red);
label[i].setBorder(border);
label[i].setHorizontalAlignment(SwingConstants.CENTER);
label[i].addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent evt) {
arrastreReina(evt);
}
});
label[i].addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent evt) {
arregloTablero(evt);
}
@Override
public void mousePressed(MouseEvent evt) {
valoresIniciales(evt);
}
});
jpanel.add(label[i]);
for (int j = 0; j < algoritmo.length; j++) {
if (i == 0) {
algoritmo[i][j] = Integer.toString((margen + (espacio * j))) + "|" + Integer.toString(margen);
} else {
algoritmo[i][j] = "0|0";
}
}
}
// Declaracion del tablero
for (int i = 0; i < tablero.length; i++) {
for (int j = 0; j < tablero.length; j++) {
tablero[i][j] = new JLabel();
tablero[i][j].setBounds(margen + (espacio * i), margen + (espacio * j), anchoAlto, anchoAlto);
tablero[i][j].setBorder(border);
if ((i % 2 == 0) == (j % 2 == 0)) {
tablero[i][j].setBackground(Color.white);
} else {
tablero[i][j].setBackground(Color.black);
}
tablero[i][j].setOpaque(true);
tablero[i][j].setHorizontalAlignment(SwingConstants.CENTER);
jpanel.add(tablero[i][j]);
}
}
// Declaracion del boton
setLayout(null);
boton1 = new JButton("Finalizar");
boton1.setBounds(25, 3, 90, 20);
jpanel.add(boton1);
boton1.addActionListener(this);
ex.setBounds(margen, margen, anchoAlto, anchoAlto);
jpanel.add(ex);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == boton1) {
for (int i = 0; i < comprobacion.length; i++) {
for (int j = 0; j < comprobacion.length; j++) {
if (algoritmo[i][j].equals("0|0")) {
comprobacion[i][j] = "*";
} else {
comprobacion[i][j] = "+";
}
}
}
imprimirArreglo(comprobacion);
int contUno = 0;
int contDos = 0;
int contTres = 0;
int diagS, diagI;
for (int i = 0; i < comprobacion.length; i++) {
for (int j = 0; j < comprobacion.length; j++) {
// Comprobacion de filas
if (comprobacion[i][j].equals("+")) {
contUno++;
if (contUno == 2) {
JOptionPane.showMessageDialog(null, "Existe más de una reina en una fila");
break;
}
}
// Comprobacion de columnas
if (comprobacion[j][i].equals("+")) {
contDos++;
if (contDos == 2) {
JOptionPane.showMessageDialog(null, "Existe más de una reina en una columna");
break;
}
// Comprobacion de diagonales
diagS = j - 1;
diagI = j + 1;
if (diagS < 0) {
diagS = 0;
} else if (diagI >= comprobacion.length) {
diagI = (comprobacion.length - 1);
}
System.out.println("S/I: " + diagS + "/" + diagI);
if (i < comprobacion.length - 1) {
if (comprobacion[diagS][i + 1].equals("+") || comprobacion[diagI][i + 1].equals("+")) {
JOptionPane.showMessageDialog(null, "En alguna diagnoal de las reinas existe mas de una reina");
contTres = 2;
break;
}
}
}
}
if (contUno == 2 || contDos == 2 || contTres == 2) {
break;
}
contUno = 0;
contDos = 0;
contTres = 0;
}
if (contUno == 0 && contDos == 0 && contTres == 0) {
JOptionPane.showMessageDialog(null, "Felicidades, completaste el juego de N Reinas");
}
}
}
public void arrastreReina(MouseEvent evt) {
if (evt.getSource() instanceof JLabel) {
((JLabel) evt.getSource()).setLocation(posicion(evt)[0], posicion(evt)[1]);
}
}
public void valoresIniciales(MouseEvent evt) {
if (evt.getSource() instanceof JLabel) {
this.newI = (posicion(evt)[1] - 25) / 50;
this.newJ = (posicion(evt)[0] - 25) / 50;
x = posicion(evt)[0];
y = posicion(evt)[1];
System.out.println("INI X/Y: " + this.newI + "/" + this.newJ);
System.out.println("X/Y: " + x + "/" + y);
}
}
public void arregloTablero(MouseEvent evt) {
if (evt.getSource() instanceof JLabel) {
int newX = (posicion(evt)[0] - x) / 50;
int newY = (posicion(evt)[1] - y) / 50;
System.out.println("pos X/Y: " + posicion(evt)[0] + "/" + posicion(evt)[1]);
System.out.println("newX: " + newX + "\nnewY: " + newY);
algoritmo[newI][newJ] = "0|0";
System.out.println("newI/newJ: " + newI + "/" + newJ);
algoritmo[newI + newY][newJ + newX] = Integer.toString(posicion(evt)[0]) + "|" + Integer.toString(posicion(evt)[1]);
count++;
System.out.println("Movimientos: " + count);
imprimirArreglo(algoritmo);
}
}
public void imprimirArreglo(String[][] arreglo) {
for (String[] arreglo1 : arreglo) {
for (int j = 0; j < arreglo.length; j++) {
System.out.print(arreglo1[j] + " ");
}
System.out.println("");
}
}
public int[] posicion(MouseEvent evt) {
int newX, newY;
// Variables de entorno X
String conX = Integer.toString(evt.getXOnScreen());
String ultimoX = conX.substring(conX.length() - 2, conX.length());
int primerosMenosUltimosX = Integer.parseInt(ultimoX);
if (primerosMenosUltimosX < 25) {
newX = 25 + (evt.getXOnScreen() - espacio - primerosMenosUltimosX);
} else if (primerosMenosUltimosX < 75) {
newX = 75 + (evt.getXOnScreen() - espacio - primerosMenosUltimosX);
} else {
newX = 25 + ((evt.getXOnScreen() - espacio + 100) - primerosMenosUltimosX);
}
// Variables de entorno Y
String conY = Integer.toString(evt.getYOnScreen());
String ultimoY = conY.substring(conY.length() - 2, conY.length());
int primerosMenosUltimosY = Integer.parseInt(ultimoY);
if (primerosMenosUltimosY < 25) {
newY = 25 + (evt.getYOnScreen() - espacio - primerosMenosUltimosY);
} else if (primerosMenosUltimosY < 75) {
newY = 75 + (evt.getYOnScreen() - espacio - primerosMenosUltimosY);
} else {
newY = 25 + ((evt.getYOnScreen() - espacio + 100) - primerosMenosUltimosY);
}
int retorno[] = {newX, newY};
return retorno;
}
}
Actually there is a problem that is generated when releasing the mouse mouseReleased() > ArrayBoard() and it is:
which is generated when you release the mouse and try to modify a value in a non-existing position of the array:
Actually you should use the calculated
newI
y valuesnewJ
but from the methodposicion()
:The initial values "0|0" must be replaced inside the method
valoresIniciales()
:The problem is actually the calculation of the cells since sometimes incorrect or negative values are obtained which do not exist in the array!
Tienes algunos problemas en los método
arregloTablero()
,posicion()
, incluso en la impresión de los valores del arreglo se realiza incorrectamente porque deben insertarsealgoritmo[newJ][newI]
en lugar dealgoritmo[newI][newJ]
para que funcione correctamente el métodoimprimirArreglo()
:Estos son ejemplos del funcionamiento así como la impresión de los valores en el array y su comprobación:
El problema está en la función
posicion()
. Me es complicado entender el sentido de tu implementación donde haces tratamientos de Strings, cuando realmente sólo hay que hacer operaciones matemáticas.Ademas al usar los métodos getXOnScreen() la posicion que obtienes se ve afectada por la posición de la ventana.
Prueba con esta implementación:
Añado explicación
El motivo por el que no debes usar
evt.getXOnScreen()
para este caso es porque esa función devuelve la posición donde se hace click respecto a la pantalla. Es decir, devuelve la posición del cursor desde la esquina superior izquierda de la pantalla. Por lo tanto, la posición del JFrame en el escritorio afectará a este valor.Por otro lado, con
evt.getX()
la posición se obtiene relativa al componente que recibe el evento. En este caso, relativa al JLabel. Por ejemplo: Si evt.getX() devuelve 30, quiere decir que la pulsación se hizo a 30 píxeles desde el borde izquierdo del JLabel.Es por eso que en mi solución, obtengo
evt.getX()
y le sumo la posición del JLabellabelLocation.x
. Así sabrás de forma exacta en qué posición del tablero se hizo la pulsación.Te muestro gráficamente la distancia que devuelve cada funcion si pulsamos el cursor en una zona de Q2, por ejemplo:
Siguendo tu implementación, debes tener en cuenta el margen inicial que aplicas al tablero para obtener la posición de la casilla pulsada.
Dicho esto, al ejecutar el código, mediante estas líneas obtenemos qué casilla se pulsó:
Las siguientes 2 lineas comprueban que estos valores no sean inferior a 0 ni superior a reinas - 1 (por si el usuario arrastra la casilla por fuera del tablero)
Y finalmente convertimos la posición a la distancia para ubicar el JLabel en el tablero.
Como habrás comprobado, cambiando en tu código la implementación de
posicion()
por la que te he propuesto, funciona sin tener que realizar mas ajustes. Espero haberte ayudado.I open the app and indicate that I want three queens. Now I move them.
The reason for the failure is the method that calculates the square to which the queen moves
Call position(evt)
This method calculates the mouse position as follows:
This method, from a 1920x1080 screen, when I bring the form to the center of the screen, gives X values of 800-900px.
Since the value of the box is 17, in TableArray it will throw an exception:
Specifically in this line:
In this line, it would try to initialize the algorithm[17][11] when the array, in a 3 queens problem, does not exist.
The application crashes, it throws a java.lang.ArrayIndexOutOfBoundsException, but it doesn't close, so you get the feeling that it doesn't work right.
The solution is to fix the way you calculate the mouse position. You have the mouse position, you just need to know the position of the JFrame, and from there do the calculations.
This link tells you how to do it:
https://stackoverflow.com/questions/7950726/find-the-location-position-of-jframe-in-the-window
Hope this can help you.