Autor Tema: juego Mastermind java Swing programa código JFrame JButton JPanel #codigoJava  (Leído 1459 veces)

WATACHI_WA

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 6
    • Ver Perfil
Buenas a todos, recien llevo poco tiempo programando en java, me estan enseñando a usar javaSwing, y me han pedido este ejercicio, lo que pasa que no se por donde cogerlo, el juego es el mastermind, pero estaba haciendo botones uno a uno, pero leo por ahí hacerlo mejor con un array, alguien me podría ayudar e indicar como comenzar con esto?
Mando el enunciado para que se entienda mejor:
__________________________________________________________________
El mastermind es un juego de tablero que consiste en averiguar una combinación de cuatro colores. El jugador dispondrá de 10 oportunidades para averiguar la combinación, en caso de no averiguarla en estos intentos perderá la partida.

En cada turno el jugador indicará una combinación de cuatro colores y el juego le devolverá el número de MUERTOS y de HERIDOS. Muertos son los colores que ha acertado y que se encuentran en su posición y heridos los que ha acertado pero que no se encuentran en su posición.

Existen 6 posibles colores y pueden repetirse: ROJO, AZUL, VERDE, AMARILLO, NARANJA y BLANCO

Por ejemplo:

El ordenador obtiene la combinación aleatoria: ROJO - NARANJA - AMARILLO - AZUL

    ROJO - ROJO - AZUL - VERDE --> 1 Muerto 1 Herido
    NARANJA - ROJO - VERDE - VERDE --> 0 Muertos 2 Heridos
    ROJO - VERDE - NARANJA - AMARILLO --> 1 Muerto 2 Heridos
    AZUL - AMARILLO - ROJO - NARANJA --> 0 Muertos 4 Heridos
    ROJO - NARANJA - AMARILLO - AZUL --> 4 Muertos 0 Heridos

GANASTE
________________________________________________________________
Al comenzar la partida el ordenador deberá crear de forma aleatoria una combinación de cuatro colores. No importa que se repitan.

Deberás utilizar la función random de Math, para generar un número de 1 a 6. Asociando a cada uno de los números un color. Por ejemplo:

ROJO - 1

AZUL - 2

VERDE - 3

AMARILLO - 4

NARANJA - 5

BLANCO - 6

De esta forma la comprobación la realizarás comprobando cada uno de los números de la combinación.

La combinación no debe mostrarse nunca, a no ser que el jugador haya ganado o que haya agotado todas las posibilidades y por tanto haya perdido. En ese caso se mostrará la combinación oculta.
_____________________________________________________________________

No quiero que me hagan el ejercicio, pero estoy impotente por que no se como comenzar :(

« Última modificación: 02 de Abril 2021, 21:12 por Ogramar »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 725
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #1 en: 03 de Diciembre 2020, 01:06 »
Hola.
La verdad es que, ahora mismo, no se exactamente como resolverlo.

Pero estas cosas hay que empezar paso a paso, poco a poco. Nunca pensando en "el todo", porque "el todo" es mucho pensar... (parece una reflexión filosófica  ;D) y es entonces cuando nos venimos abajo  :-\

Hay que pensar en cosas pequeñas, en las partes que vamos a necesitar para conseguir "ese todo".

Por ejemplo, parece que vamos a necesitar unos botoncitos cuadrados, que alteren su color, según su valor entre 1 y 6.

Por la interfaz parece que el usuario al hacer click en esos botones decidirá su color (y por tanto su valor)

Pues comienza por eso.
Por crear una clase a partir de un JButton, que tenga un atributo int que admitirá valores entre 1 y 6.
Y según ese valor, se decidirá su color.

Así que tendrá que tener unos métodos para poder cambiar el valor del int, y cambiar el color del botón.

Y un ActionListener para que todo eso ocurra cuando el usuario lo clickee.

Intenta crear tú una clase que cumpla esto.

En cualquier caso, yo te propongo este código escrito por mí.

Clase Boton
Código: [Seleccionar]
public class Boton extends JButton implements ActionListener{

private int valor;

public Boton(int valor) {
this.valor = valor;
setPreferredSize(new Dimension(50, 50));
setFocusPainted(false);
cambiarColor();
addActionListener(this);
}

public int getValor() {
return valor;
}

public void ciclarValor() {
if (valor == 6)
valor = 1; //Comienza de nuevo en 1
else
valor++;
cambiarColor();
}

public void cambiarColor() {
switch (valor) {
case 1:
setBackground(Color.RED);
break;
case 2:
setBackground(Color.BLUE);
break;
case 3:
setBackground(Color.GREEN);
break;
case 4:
setBackground(Color.YELLOW);
break;
case 5:
setBackground(Color.ORANGE);
break;
case 6:
setBackground(Color.WHITE);
}
}

@Override
public void actionPerformed(ActionEvent e) {
ciclarValor();
}

}

Y esta es la clase JFrame donde ir creando el juego.
De momento, solo voy a poner el botón para comprobar si funciona, su aspecto, etc...

Código: [Seleccionar]
public class MasterMind extends JFrame{

public MasterMind() {

JPanel prueba = new JPanel();
prueba.add(new Boton(1));
add(prueba);


setTitle("MasterMind");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 300);
setLocationRelativeTo(null);
setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {

@Override
public void run() {
new MasterMind();
}
});
}
}

Y efectivamente, tengo un botón cuadrado que al hacerle click, va ciclando su valor y su color.


Pues ya tenemos un comienzo. Un primer ladrillo sobre el que seguir construyendo "el todo".

¿Siguiente paso?
Pues si volvemos a fijarnos en la interfaz... parece que podríamos usar varios paneles, apilados verticalmente, y cada uno compuesto de 4 botones de colores, un botón comprobar y un campo de texto que informe de los aciertos



Pues creo que este sería mi siguiente paso, modelar una clase JPanel con esos componentes.
De momento al principio no será capaz de informar de aciertos, porque aún no se ha implementado lo de generar la combinación aleatoria.
Pero para comprobar su funcionamiento, podemos hacer que cuando se pulse el botón "Comprobar", informe de los valores elegidos en los 4 botones.
Ya luego se le dará la funcionalidad correcta.

Yo seguiría por ese camino...
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 725
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #2 en: 03 de Diciembre 2020, 02:13 »
Yo voy a ir proponiendo mi código.
Tú puedes ir desarrollando el tuyo, basándote en el mío o como quieras.
Estaría genial que también lo compartieras por aquí.

Y ojalá más gente se animase a compartir también sus versiones para poder tener distintos puntos de vista y fórmulas de resolver un mismo ejercicio.

Como dije antes, para mi el siguiente paso lógico es crear un panel que tenga los 4 botones de colores, el botón "Comprobar" y un campo de texto para informar de resultados.

De momento, el resultado del que informará es de los valores seleccionados en los botones.
Por lo tanto, le pondré un ActionListener que al pulsar el botón "Comprobar", recupere los valores de cada botón, los junte en un array, y lo muestro en el campo de texto.
Este ActionListener es simplemente para "testeo", luego probablemente lo eliminaré.

Código: [Seleccionar]
public class PanelColores extends JPanel{

private Boton[] botones;
JButton btComprobar;
JTextField jtResultado;

public PanelColores() {

add(new PanelBotones());
add(new PanelComprobar());
add(new PanelResultado());
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(20, 10, 20, 10),
BorderFactory.createBevelBorder(BevelBorder.RAISED)));
}

private class PanelBotones extends JPanel {

public PanelBotones() {
//Inicializamos array de botones y añadimos
botones = new Boton[4];
for (int i = 0; i < botones.length; i++) {
botones[i] = new Boton(1);
add(botones[i]);
}
setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 15));
}
}

private class PanelComprobar extends JPanel {

public PanelComprobar() {
btComprobar = new JButton("Comprobar");
btComprobar.setFont(new Font("Verdana", Font.BOLD, 14));
btComprobar.addActionListener(new AccionComprobar());
add(btComprobar);
setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 15));
}
}

private class PanelResultado extends JPanel {

public PanelResultado() {
jtResultado = new JTextField(12);
jtResultado.setEditable(false);
jtResultado.setBackground(Color.WHITE);
jtResultado.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
jtResultado.setFont(new Font("Verdana", Font.BOLD, 14));
jtResultado.setFocusable(false);
jtResultado.setHorizontalAlignment(JTextField.CENTER);
add(jtResultado);
setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 15));
}
}

private class AccionComprobar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//Creamos array con los valores de los botones
int[] valores = new int[4];
for (int i = 0; i < 4; i++)
valores[i] = botones[i].getValor();
//Lo imprimo en el campo de texto
jtResultado.setText(Arrays.toString(valores));
}
}
}

Si ahora en el JFrame, muestro este panel:

Citar
public class MasterMind extends JFrame{
   
   public MasterMind() {
      
      JPanel prueba = new JPanel();
      prueba.add(new PanelColores());
      add(prueba);
      
      
      setTitle("MasterMind");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      pack();
      setLocationRelativeTo(null);
      setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {

         @Override
         public void run() {
            new MasterMind();   
         }
      });
   }
}

En pantalla veo modelado el concepto que tenía en mente:


A este panel le he puesto un borde compuesto, para que quede biselado y con unos píxeles de separación, ya que la idea es añadir diez de estos paneles a la interfaz, apilados unos sobre otros, y con esos bordes queda más elegante.

Citar
   public MasterMind() {
      
      JPanel panelesBotones = new JPanel();
      panelesBotones.setLayout(new BoxLayout(panelesBotones, BoxLayout.Y_AXIS));
      for (int i = 0; i < 10; i++)
         panelesBotones.add(new PanelColores());
      add(panelesBotones);

      
      
      setTitle("MasterMind");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      pack();
      setLocationRelativeTo(null);
      setVisible(true);
   }
Aunque lo he probado y me queda enorme xD, así que tengo que reducir píxeles de separación.

Pero bueno, al margen de eso, ya tengo una interfaz prácticamente completada:




Ahora ya habría que hacer lo de generar una combinación secreta y evaluar de verdad los aciertos del usuario.

A continuación mi código actual.

Clase Boton.java

Código: [Seleccionar]
package mastermind;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.border.BevelBorder;

@SuppressWarnings("serial")
public class Boton extends JButton implements ActionListener{

private int valor;

public Boton(int valor) {
this.valor = valor;
setPreferredSize(new Dimension(50, 50));
setFocusPainted(false);
cambiarColor();
addActionListener(this);
setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
}

public int getValor() {
return valor;
}

public void ciclarValor() {
if (valor == 6)
valor = 1; //Comienza de nuevo en 1
else
valor++;
cambiarColor();
}

public void cambiarColor() {
switch (valor) {
case 1:
setBackground(Color.RED);
break;
case 2:
setBackground(Color.BLUE);
break;
case 3:
setBackground(Color.GREEN);
break;
case 4:
setBackground(Color.YELLOW);
break;
case 5:
setBackground(Color.ORANGE);
break;
case 6:
setBackground(Color.WHITE);
}
}

@Override
public void actionPerformed(ActionEvent e) {
ciclarValor();
}

}


Clase MasterMind.java

Código: [Seleccionar]
package mastermind;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

@SuppressWarnings("serial")
public class MasterMind extends JFrame{

public MasterMind() {

JPanel panelesBotones = new JPanel();
panelesBotones.setLayout(new BoxLayout(panelesBotones, BoxLayout.Y_AXIS));
for (int i = 0; i < 10; i++)
panelesBotones.add(new PanelColores());
add(panelesBotones);


setTitle("MasterMind");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {

@Override
public void run() {
new MasterMind();
}
});
}
}


Clase PanelColores.java

Código: [Seleccionar]
package mastermind;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.BevelBorder;

@SuppressWarnings("serial")
public class PanelColores extends JPanel{

private Boton[] botones;
JButton btComprobar;
JTextField jtResultado;

public PanelColores() {

add(new PanelBotones());
add(new PanelComprobar());
add(new PanelResultado());
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEmptyBorder(5, 20, 5, 20),
BorderFactory.createBevelBorder(BevelBorder.RAISED)));
}

private class PanelBotones extends JPanel {

public PanelBotones() {
//Inicializamos array de botones y añadimos
botones = new Boton[4];
for (int i = 0; i < botones.length; i++) {
botones[i] = new Boton(1);
add(botones[i]);
}
setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));
}
}

private class PanelComprobar extends JPanel {

public PanelComprobar() {
btComprobar = new JButton("Comprobar");
btComprobar.setFont(new Font("Verdana", Font.BOLD, 14));
btComprobar.addActionListener(new AccionComprobar());
add(btComprobar);
setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));
}
}

private class PanelResultado extends JPanel {

public PanelResultado() {
jtResultado = new JTextField(12);
jtResultado.setEditable(false);
jtResultado.setBackground(Color.WHITE);
jtResultado.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
jtResultado.setFont(new Font("Verdana", Font.BOLD, 14));
jtResultado.setFocusable(false);
jtResultado.setHorizontalAlignment(JTextField.CENTER);
add(jtResultado);
setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));
}
}

private class AccionComprobar implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
//Creamos array con los valores de los botones
int[] valores = new int[4];
for (int i = 0; i < 4; i++)
valores[i] = botones[i].getValor();
//Lo imprimo en el campo de texto
jtResultado.setText(Arrays.toString(valores));
}
}
}
« Última modificación: 02 de Abril 2021, 20:55 por Ogramar »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 725
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #3 en: 04 de Diciembre 2020, 01:14 »
Generar combinación secreta y evaluar...

Para esto yo crearía una nueva clase.

Generar la combinación es sencillo, generar 4 int aleatorios entre 1 y 6, y guardarlos en un array.

Para evaluar si han habido "muertos" y/o "heridos" según las reglas de Mastermind..., no se cuál puede ser la forma más óptima.

Yo he decidido trabajar en este caso con arrays de clase Integer en lugar de tipo primitivo int, porque con Integer puedo dar valores null a los elementos del array.
¿Y para que quiero poder dar valores null?

Pues porque cuando vaya a comparar "colores", si al comparar dos posiciones de los dos arrays (el de la combinación y el de la selección del usuario) se produce un "muerto" o un "herido", dichas posiciones no deben volver a consultarse mientras sigo evaluando los arrays.
Necesito marcar esas posiciones de algún modo para que no se vuelvan a consultar mientras dura esta evaluación.
Y una forma puede ser darles valores null.

Esto implica que no puedo trabajar directamente sobre el array de combinación secreta, pues destruiría la combinación al evaluar.
Así que cada vez que evalúe, haré una copia de la combinación y trabajaré sobre esta copia.

Así el método que se encarga de evaluar, recibirá un array con la selección del usuario, comparará con la copia de la combinación secreta, contabilizará posibles "muertos" y "heridos".. y por último retornará un String con el resultado.

Para contabilizar "muertos" y "heridos"..., primero buscaré "muertos", es decir, recorreré ambos arrays a ver si en la misma posición, coinciden colores.

Luego buscaré "heridos" en las posiciones que no hayan sido nulleadas (que no hayan generado "muertos").
Los heridos son colores escogidos que sí constan en la combinación, pero no en la misma posición.



Esta clase, también puede ser interesante que contabilice los intentos (máximo 10) y con un boolean controlar si se ha resuelto o no la combinación, es decir, si en algún momento se contabilizan 4 "muertos".

Esta podría ser la clase:
Código: [Seleccionar]
public class Combinacion {

private int[] combi;
public int intentos;
public boolean resuelto;

public Combinacion() {
combi = new int[4];
generaCombi();
intentos = 0;
resuelto = false;
}

public void generaCombi() {
Random azar = new Random();
for (int i = 0; i < combi.length; i++)
combi[i] = azar.nextInt(6) + 1;
}

public String evaluar(Integer[] colores) {
int muertos = 0;
int heridos = 0;

Integer[] copia = new Integer[4];
for (int i = 0; i < 4; i++)
copia[i] = combi[i];

//Busco muertos
for (int i = 0; i < 4; i++)
if (colores[i] == copia[i]) {
//Mismo color y misma posicion
muertos++;
//Nuleo posiciones, ya no deben consultarse más.
colores[i] = null;
copia[i] = null;
}

//Si hay 4 muertos, el juego está resuelto
if (muertos == 4)
resuelto = true;
else {
//Busco heridos, habrá que obviar posibles valores null
for (int i = 0; i < 4; i++) {
if (colores[i] != null)//Posición consultable
for (int j = 0; j < 4; j++) {
if (copia[j] != null)//Posición consultable
if (colores[i] == copia[j]) {
heridos++;
//Posiciones nulleadas
colores[i] = null;
copia[j] = null;
}
}
}
}

//Contabilizo intento
intentos++;

//Retorno resultado
String resultado = muertos==1?"1 Muerto - ":muertos + " Muertos - ";
resultado += heridos==1?"1 Herido":heridos + " Heridos";

return resultado; 
}
}

Y para que cada "panel de colores" sea capaz de evaluarse por sí mismo de forma autosuficiente, voy a cambiar su constructor y añadir como atributo una referencia al objeto Combinación que será instanciado en la clase principal JFrame.

Y modificaré el ActionListener de su botón "Comprobar" para que muestre en el campo de texto el resultado que devuelve el objeto Combinación.
Además haré que deshabilite los botones de colores y el mismo botón "Comprobar".
Pues una vez el usuario elija comprobar un panel de colores, no puede tener ocasión de volver a cambiarlo y volver a comprobar.

Citar
public class PanelColores extends JPanel{
   
   private Boton[] botones;
   JButton btComprobar;
   JTextField jtResultado;
   private Combinacion combinacion;
   
   public PanelColores(Combinacion combi) {
      
      add(new PanelBotones());
      add(new PanelComprobar());
      add(new PanelResultado());
      setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createEmptyBorder(5, 20, 5, 20),
            BorderFactory.createBevelBorder(BevelBorder.RAISED)));
      combinacion = combi;
   }
   
   private class PanelBotones extends JPanel {
      
      public PanelBotones() {
         //Inicializamos array de botones y añadimos
         botones = new Boton[4];
         for (int i = 0; i < botones.length; i++) {
            botones = new Boton(1);
            add(botones);
         }
         setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));
      }
   }
   
   private class PanelComprobar extends JPanel {
      
      public PanelComprobar() {
         btComprobar = new JButton("Comprobar");
         btComprobar.setFont(new Font("Verdana", Font.BOLD, 14));
         btComprobar.addActionListener(new AccionComprobar());
         add(btComprobar);
         setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));
      }
   }
   
   private class PanelResultado extends JPanel {
      
      public PanelResultado() {
         jtResultado = new JTextField(14);
         jtResultado.setEditable(false);
         jtResultado.setBackground(Color.WHITE);
         jtResultado.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
         jtResultado.setFont(new Font("Verdana", Font.BOLD, 14));
         jtResultado.setFocusable(false);
         jtResultado.setHorizontalAlignment(JTextField.CENTER);
         add(jtResultado);
         setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));
      }
   }
   
   private class AccionComprobar implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         //Botones de este panel quedan inhabilitados
         botonesActivos(false);
         
         //Creamos array con los valores de los botones
         Integer[] valores = new Integer[4];
         for (int i = 0; i < 4; i++)
            valores = botones.getValor();
         
         //Evaluamos combinación y mostramos resultado en campo de texto
         jtResultado.setText(combinacion.evaluar(valores));

         
      }
   }
   
   public void botonesActivos(boolean activos) {
      btComprobar.setEnabled(activos);
      for (int i = 0; i < botones.length; i++)
         botones.setEnabled(activos);
   }

}

Y por último, en la clase JFrame instancio el objeto Combinación y lo paso al constructor de los paneles de colores.
Citar
public class MasterMind extends JFrame implements ActionListener{
   
   private Combinacion combinacion;
   
   public MasterMind() {
      
      combinacion = new Combinacion();
      
      JPanel panelesBotones = new JPanel();
      panelesBotones.setLayout(new BoxLayout(panelesBotones, BoxLayout.Y_AXIS));
      for (int i = 0; i < 10; i++)
         panelesBotones.add(new PanelColores(combinacion));
      add(panelesBotones);
      
      
      setTitle("MasterMind");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      pack();
      setLocationRelativeTo(null);
      setVisible(true);
   }

Si ahora lo ejecuto, tengo un juego funcional. He comenzado a evaluar desde abajo hacia arriba, y he acertado por los pelos en el último panel  ::)



Sin embargo, faltaría añadir más cositas, como mensajes de victoria/derrota o que el juego se reinicie para seguir jugando con una nueva combinación.
« Última modificación: 02 de Abril 2021, 21:00 por Ogramar »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

WATACHI_WA

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 6
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #4 en: 04 de Diciembre 2020, 11:02 »
Kabuto en primer lugar no se como agradecerte la ayuda que me estás brindando , de verdad, gracias a tu primer mensaje muy bien explicado y con un código muy bien escrito, me he animado a continuar con el tuyo, yo voy pasito a pasito como me dijiste, hay muchos conocimientos que todavía se me escapan , pero aún así, voy a compartir mi código para que veas el avance que he hecho, mi intención ahora sería poder replicar este frame que tengo 10 veces, pero antes de eso me gustaría ya poder conseguir que con el botón comprobar compruebe mis colores con el que se genera aleatoriamente

Código: [Seleccionar]
public class MasterMind extends JFrame{

    int muertos,heridos,n1,n2,n3,n4;
    private JButton botonC;
public MasterMind() {         
            FlowLayout flowLayout = new FlowLayout(FlowLayout.CENTER,20,20);
JPanel panelBotones = new JPanel();
                //panelBotones.setSize(220,600);
//panel.add(new Boton(0));
                //JPanel panelComprobar = new JPanel();
                //panelComprobar = new JPanel();;
                //panelComprobar.setSize(20, 20);
                panelBotones.setLayout(flowLayout);
                add(panelBotones);
                //CREACION DE BOTONES DE COLORES
                final Boton [] botones = new Boton[4];
                for (int i = 0; i < botones.length; i++) {
                    botones[i] = new Boton(0);
                    panelBotones.add(botones[i]);
                } 
                botonC = new JButton ("Comprobar");
                panelBotones.add(botonC);
               
               
               
               
                botonC.addActionListener( new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    n1=botones[0].getValor();
                    n2=botones[1].getValor();
                    n3=botones[2].getValor();
                    n4=botones[3].getValor();
                    String resultado = n1+","+n2+","+n3+","+n4+",";
                    JOptionPane.showMessageDialog(rootPane, resultado);
                }
                });
               
               
                JLabel jl_muertos = new JLabel("Muertos: " +muertos);
                panelBotones.add(jl_muertos);
               
                JLabel jl_heridos = new JLabel("Heridos: " +heridos);
                panelBotones.add(jl_heridos);
               
                //add(panelComprobar);


setTitle("MasterMind JB");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600, 800);
               
setLocationRelativeTo(null);
setVisible(true);
}

public static void main(String[] args) {
/*SwingUtilities.invokeLater(new Runnable() {
           
@Override
public void run() {
new MasterMind();
}
});*/
                    new MasterMind();
       
        }
}

Como puedes observar lo que he avanzado es el botón con los dos JLabel, y que al pulsar el boton me muestre por mensaje los valores de esos colores.
Voy a ponerme ahora a generar numeros en un vector de 4 posiciones, sería lo correcto?


PD: Gracias nuevamente por tu tiempo y por tu manera de explicarte, has conseguido por una parte que pueda tratar el ejercicio y por otra animarme a seguir indagando y avanzando, te estoy muy agradecido

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 725
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #5 en: 04 de Diciembre 2020, 11:49 »
Muy bien  ;)

Citar
Voy a ponerme ahora a generar numeros en un vector de 4 posiciones, sería lo correcto?

Sí, al usar vectores, luego es más cómodo recorrer con bucles esos números para hacer comparaciones.
Si cada número lo tenemos en una variable propia, no podremos usar bucles y el código para hacer comparaciones será más complejo.

Ánimo, y sigue intentando sacar tu propio código.

Puede que al leer mis mensajes, sea notable que exponga las ideas tan claras, y el código se vea sencillo y funcional.

Pero esto no es producto de un don divino, je je.., esto es después de mucho tiempo de indagar, probar, equivocarme, meterme en "laberintos" de lógica que no me llevaban a ninguna parte....
Yo he escrito códigos, que si existiera una policía de la programación, me habrían condenado a la silla eléctrica ja ja

Me he quedado atascado cientos de veces y dejado muchísimos programas sin completar porque ya no sabía como componer el desastre que estaba haciendo y era mejor dejarlo y empezar de nuevo.

Pero esos desastres siempre me han servido para aprender y sobre todo, para divertirme.

Sigue compartiendo lo que vayas logrando.
Un saludo.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

WATACHI_WA

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 6
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #6 en: 04 de Diciembre 2020, 18:35 »
Vale, he conseguido por una parte general los números en el vector, y por otra mostrarlos de forma puntual en mi JFrame, pero no se como comparar un vector con el otro, paso el código pero sigo indagando
Código: [Seleccionar]
public class MasterMind extends JFrame{

    public static int muertos,heridos,n1,n2,n3,n4;
    public static int solucion [] = new int [4];
    public static int valores [] = new int [4];
    public static String sol="";
    private static JButton botonC;

public MasterMind() {         
            FlowLayout flowLayout = new FlowLayout(FlowLayout.CENTER,20,20);
JPanel panelBotones = new JPanel();
               
               
                //panelBotones.setSize(220,600);
//panel.add(new Boton(0));
                //JPanel panelComprobar = new JPanel();
                //panelComprobar = new JPanel();;
                //panelComprobar.setSize(20, 20);
                panelBotones.setLayout(flowLayout);
                add(panelBotones);
                //CREACION DE BOTONES DE COLORES
                final Boton [] botones = new Boton[4];
                for (int i = 0; i < botones.length; i++) {
                    botones[i] = new Boton(0);
                    panelBotones.add(botones[i]);
                }
                botonC = new JButton ("Comprobar");
                panelBotones.add(botonC);
               
               
               
               
                botonC.addActionListener( new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {

                    for (int i = 0; i < 4; i++) {
                        valores[i]=botones[i].getValor();
                       
                    }
                    JOptionPane.showMessageDialog(rootPane, Arrays.toString(valores));
                   
                }
                });
               
                JLabel jl_muertos = new JLabel("Muertos: " +muertos);
                panelBotones.add(jl_muertos);
               
                JLabel jl_heridos = new JLabel("Heridos: " +heridos);
                panelBotones.add(jl_heridos);
               
                JLabel jl_sol = new JLabel("Solucion: " +sol);
                panelBotones.add(jl_sol);
                //add(panelComprobar);


setTitle("MasterMind JB");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600, 800);
               
setLocationRelativeTo(null);
setVisible(true);
}

public static void main(String[] args) {
/*SwingUtilities.invokeLater(new Runnable() {
           
@Override
public void run() {
new MasterMind();
}
});*/
           
           
            for (int i = 0; i<solucion.length; i++) {
                solucion[i]=(int)(Math.random()*6)+1;
                sol+=solucion[i]+" ";
               
            }
;
           
                    new MasterMind();
       
        }
}
« Última modificación: 04 de Diciembre 2020, 19:10 por WATACHI_WA »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 725
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #7 en: 05 de Diciembre 2020, 01:18 »
pero no se como comparar un vector con el otro, paso el código pero sigo indagando

En mis mensajes anteriores expliqué cómo lo hice yo.

Me pareció lógico buscar primero "muertos", es decir, comparar las mismas posiciones de ambos vectores. Si contienen el mismo valor, contabilizamos un "muerto".
Esto lo podemos hacer con un único bucle, y usar el mismo índice para ambos vectores.

Luego, tocaría buscar "heridos". Esta vez si necesitaríamos dos bucles anidados, pues cada elemento del vector de valores, se ha de comparar con todos los elementos del vector "solucion".

Para hacer las comparaciones correctamente, cuando unas posiciones que han sido comparados han dado lugar a un "muerto" o un "herido", ya no deben volver a consultarse en las siguientes iteraciones de los bucles.
Así que esas posiciones han de marcarse de alguna forma para saber si debemos consultarlas o no.

En mi caso, en lugar de usar el tipo int para los vectores, use la clase Integer, que a efectos prácticos es lo mismo, pero al ser una clase puedo dar valores "null" a esas posiciones que quiero ignorar.

Si usas int, no puedes darle valor null... pero hay alternativas, como por ejemplo darles como valor -1 para "marcar" esas posiciones que no queremos volver a consultar.

Esto plantea otro problema, si damos valores null, o -1, o lo que sea... a los elementos del vector, estaríamos alterando su contenido.
En el caso del vector de "valores" no tiene importancia, porque cada vez que el usuario pulse el botón "Comprobar" se volverá a generar con nuevos valores, así que no importa si los alteramos cuando queramos "marcar" posiciones.

Pero en el caso del vector "solucion" si que sería un desastre, este vector una vez generados sus valores, no deberían alterarse a lo largo del juego.
Por eso, en mi caso, cada vez que el usuario pulsa el botón "Comprobar", hago una copia de ese vector y trabajo con la copia. De este modo no importa si modifico sus valores, siempre tendré el vector original intacto para la próxima vez que el usuario quiera comprobar.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

WATACHI_WA

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 6
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #8 en: 05 de Diciembre 2020, 10:12 »
Perdona si es una pregunta tonta, pero estoy buscando el significado de una instrucción que tienes puesta, pack(), en tu linea 29 de la clase MasterMind y no entiendo qué hace, por que sin ella no muestra ningún JFrame.

Edit: Vale buceando por el manual me he encontrado que el pack() lo que hace realmente es encargarse del diseño del marco para adaptarse, en vez de que use setSize o setBounds, sería correcta esta definición?
Gracias de antemano por vuestro tiempo siempre
« Última modificación: 05 de Diciembre 2020, 10:16 por WATACHI_WA »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 725
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #9 en: 05 de Diciembre 2020, 11:38 »
Perdona si es una pregunta tonta, pero estoy buscando el significado de una instrucción que tienes puesta, pack(), en tu linea 29 de la clase MasterMind y no entiendo qué hace, por que sin ella no muestra ningún JFrame.

Edit: Vale buceando por el manual me he encontrado que el pack() lo que hace realmente es encargarse del diseño del marco para adaptarse, en vez de que use setSize o setBounds, sería correcta esta definición?
Gracias de antemano por vuestro tiempo siempre

Sí, pack() lo que hace es calcular el tamaño del JFrame, es decir, la ventana de la aplicación, basándose en el resto de componentes que este ha de contener: paneles, campos de texto, botones...
Lo hará de forma que todos esos componentes puedan cumplir su preferredSize.

A los componentes Swing podemos aplicarles un tamaño con setSize() y/o un tamaño preferido con setPreferredSize()


Por lo general es mejor usar pack() y preferredSize, porque aplica de forma excelente la maquetación de la interfaz, según los componentes, el layout escogido y también según el sistema operativo y configuración gráfica del ordenador donde se ejecuta.

La única desventaja es que al no imponer unos tamaños fijos, el tamaño de la interfaz a veces se nos puede ir de madre.

Yo por ejemplo, tengo un monitor QHD que me da una resolución de escritorio de 2560x1440 pixels.

Y claro, una interfaz que en mi pantalla se ve bien, que ni siquiera llega a los bordes del escritorio, si luego le paso mi aplicación otra persona con una pantalla de menor resolución como FullHD (que son más comunes), resulta que a esa persona se le ve enorme, incluso se sale de los bordes.

Pero bueno, eso son detalles que ahora no importan, lo importante ahora es aprender a programa y familiarizarse con Swing
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

WATACHI_WA

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 6
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #10 en: 06 de Diciembre 2020, 12:02 »
Bueno pues como me vi muy bloqueado, con su permiso continue en su propio proyecto, le he añadido 4 tonterías y lo comparto por aquí para q evalues que tal las tonterías que le he metido, gracias nuevamente por la ayuda q me has brindado por que sin ella no hubiese sido posible ya que has hecho tu TODO,

PD: Ahora me toca la documentación que jamás la he hecho asi que voy a indagar sobre como estructurarla, adjunto en zip el proyecto, un saludo gran compañero


Clase Boton

Código: [Seleccionar]
package mm_jb;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.border.BevelBorder;

public class Boton extends JButton implements ActionListener{

private int valor;

public Boton(int valor) {
this.valor = valor;
setPreferredSize(new Dimension(30, 30));
setFocusPainted(false);
cambiarColor();
addActionListener(this);
}

public int getValor() {return valor;
}

public void rotarValor() {if (valor == 6)
valor = 1; //Comienza de nuevo en 1
else
valor++;
cambiarColor();
}

public void cambiarColor() {
switch (valor) {
case 1:setBackground(Color.RED);break;
case 2:setBackground(Color.BLUE);break;
case 3:setBackground(Color.GREEN);break;
case 4:setBackground(Color.YELLOW);break;
case 5:setBackground(Color.ORANGE);break;
case 6:setBackground(Color.WHITE);
}
}

@Override
public void actionPerformed(ActionEvent e) { rotarValor(); }

}


Clase Combinacion

Código: [Seleccionar]
package mm_jb;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class Combinacion {
    public int [] combinacion;
    public int intentos;
    public int muertos;
    public int heridos;
    public int resp;
    public boolean resuelto;
    public String resultado;
    public final String msjTitulo = "MASTERMIND BY JB";
    public final String msjGanar = "Enhorabuena, ¡ GANASTE ! ";
    public String msjIntentos = "UPS!, HAS GASTADO LOS 10 INTENTOS";
    public String msjRepetir = "¿PROBAMOS DE NUEVO?";
   
    public Combinacion(){
        combinacion = new int[4];
        generaCombinacion();
        //Le meto al constructor el metodo
        intentos = 0;
        resuelto = false;
        //Con esto controlo los intentos;
    }
   
    public void generaCombinacion() {
        for (int i = 0; i < combinacion.length; i++) {
            combinacion[i] = (int) ((Math.random()*6)+1);
            System.out.print(combinacion[i] + " ,");
        }
        System.out.println();
    }
   
    public String evaluar (Integer [] colores){
        muertos = 0;
        heridos = 0;
        //Cada vez que evaluo, hago una copia
        Integer [] copia = new Integer [4] ;
        //Hago una copia con integer, por que así valores encontrados, sustituidos por -1
        for (int i = 0; i < 4; i++){
            copia[i] = combinacion [i];
        }
       
        //Busco muertos
        for (int i = 0; i < 4; i++){
            if (colores[i] == copia [i]){
                //Mismo color y misma posicion
                muertos++;
                //Pongo a null, por que no se deben consultar mas
                colores[i]=-1;
                copia[i]=-1;
            }
        }
        //Si encuentra 4 muertos, el juego está resuelto
        if (muertos == 4){
            resuelto = true;
            JOptionPane.showMessageDialog(null, msjGanar, msjTitulo, JOptionPane.INFORMATION_MESSAGE);
            Respuesta();
        }
        //Caso contrario, habrá que obviar los valores -1 si los hay
        else{
            for (int i=0; i<4;i++){
                if (colores[i]!=-1)//Busco quitando los encontrados{
                    for (int j = 0; j < 4; j++){
                        if (copia[j] != -1)//Busco quitando los encontrados{
                            if (colores[i] == copia[j]){
                                heridos++;
                                //Posiciones eliminadas
                                colores[i] = -1;
                                copia[j] = -1;
                            }
                        }
                    }
                }
            }
        }
        //Contabilizamos intentos
        intentos++;
                      //DEVUELVO RESULTADO
        resultado = muertos +  " Muertos - " + heridos + " Heridos";
        return resultado;
       }
   
    public void Resultado(){
        if (intentos == 10){
            msjRepetir = msjIntentos + "\n" + msjRepetir;
            Respuesta();           
        }
    }
   
    public void Respuesta(){
        resp =JOptionPane.showConfirmDialog(null, msjRepetir, msjTitulo, JOptionPane.YES_NO_OPTION);
            switch (resp) {
                case 0:
                    new MasterMind();
                    break;
                case 1:
                    System.exit(0);
                    break;
                default:
                    System.exit(0);
                    break;
            }
    }
   
}


Clase Mastermind

Código: [Seleccionar]
package mm_jb;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class MasterMind extends JFrame implements ActionListener
{
   
    Combinacion combinacion;

    public MasterMind() {
        combinacion = new Combinacion();
        JPanel panelesBotones = new JPanel();
        panelesBotones.setLayout(new BoxLayout(panelesBotones, BoxLayout.Y_AXIS));
        //Layout simple que me permite colocar los elementos en forma vertical ;)
        for (int i = 0; i < 10; i++)
        {//Con esto replico el panelColores que contiene los 3 paneles, 10 veces
            panelesBotones.add(new PanelColores(combinacion));
            add(panelesBotones);
        }

       
       
        setTitle("MasterMind by JB");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        //setSize(500, 600);
        setLocationRelativeTo(null);
        setVisible(true);
    }
   
    @Override
    public void actionPerformed(ActionEvent e) {
        //
    }
   
    public static void main(String[] args) {
new MasterMind();               
}

   
}


Clase PanelColores

Código: [Seleccionar]
package mm_jb;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class PanelColores extends JPanel
{
    private Boton [] botones;
    JButton btnComprobar;
    JTextField txtResultado;
   
    Combinacion combinacion;
    //PANEL PRINCIPAL
    public PanelColores(Combinacion c) {
        //Añado como referencia un objeto Combinacion
        //Cada panel se evalua por sí solo
        //Añadimos los 3 paneles
        add(new PanelBotones());
        add(new PanelComprobar());
        add(new PanelResultado());
        combinacion = c;
    }
   
    class PanelBotones extends JPanel {
        public PanelBotones() {
            //Inicializo array de botones y los añados
            botones = new Boton [4] ;
            for (int i = 0; i < botones.length; i++){
                botones[i] = new Boton(1);
                //Botones con el primer color
                add(botones[i]);
            }
        }
    }
   
    class PanelComprobar extends JPanel
    {
        public PanelComprobar(){
            btnComprobar = new JButton("Comprobar");
            btnComprobar.addActionListener(new AccionComprobar());
            add(btnComprobar);
        }
    }
   
    class PanelResultado extends JPanel{

        public PanelResultado(){
            txtResultado = new JTextField(14);
            txtResultado.setEditable(false);
            add(txtResultado);
        }
       
    }
   
    class AccionComprobar implements ActionListener{
        @Override
        public void actionPerformed(ActionEvent e) {
            //Deshabilito el boton una vez pulsado
            botonesActivos(false);
            //Creo array con los valores de los botones
            Integer [] valores = new Integer[4];
            for (int i = 0; i < 4; i++) {
                valores[i]= botones[i].getValor();
            }
           
            //Evaluo combinacion y muestro resultado
            txtResultado.setText(combinacion.evaluar(valores));
            combinacion.Resultado();
        }       
    }
    public void botonesActivos(boolean activos) {
btnComprobar.setEnabled(activos);
for (int i = 0; i < botones.length; i++)
botones[i].setEnabled(activos);
}
}

« Última modificación: 02 de Abril 2021, 21:09 por Ogramar »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 725
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #11 en: 06 de Diciembre 2020, 14:10 »
No te preocupes por usar mi código, pero sobre todo asegúrate de entender bien que hace cada línea.

Sobre tu programa, muy bien. Has añadido los mensajes tras finalizar partida.

Solo tiene una pega, cuando se elige volver a jugar lo que se hace es reinstanciar un nuevo juego completo, sin que se cierre el anterior.
Y como el anterior es quien hace la instancia, en realidad no se puede cerrar.
Esto implica que si elijo rejugar 20 veces.., tendré en memoria 20 juegos MasterMind.., y esto no es óptimo...

Una forma de solucionarlo sería, en lugar de abrir un nuevo juego, reiniciar el juego actual para que comience todo desde el principio, botones reactivados, seteados a valor 1, nueva   combinacion, contadores a 0, etc....

Esto va a implicar añadir métodos a las clases que hemos creado, para que cada una sepa como debe reiniciarse.

A la clase Boton habrá que darle un método para que recupere el valor inicial de 1 y adopte el color correspondiente:

Código: [Seleccionar]
public void reset() {
valor = 1;
cambiarColor();
}

A PanelColores un método que recorra los botones para dar orden de resetearlos, reactive todos los botones que habían sido desactivados durante el juego y limpie los campos de texto para que vuelvan a estar vacíos.

Código: [Seleccionar]
    public void resetPanel() {
    //Botones reinician valor
    for (int i = 0; i < botones.length; i++)
            botones[i].reset();
    //Botones se reactivan
    botonesActivos(true);
    //Limpiamos campo de text
    txtResultado.setText(null);
    }

A Combinación un método similar, que genere nueva combinación y reinicie contadores.
Código: [Seleccionar]
    public void resetCombinacion() {
    generaCombinacion();
    intentos = 0;
    muertos = 0;
        heridos = 0;
        resuelto = false;
    }

Hecho esto, ahora nos vamos a encontrar con unos problemas muy interesantes, que pueden servir para aprender cosas.

Ahora mismo los objetos de la clase PanelColores ya tienen un método para reiniciarse.
Pero resulta que no podemos pedirle que los usen  :o
¿Por qué?
Porque hemos creado objetos "desreferenciados", es decir, no les hemos dado una referencia que poder usar para acceder a ellos.
Simplemente dimos orden de crearlos con new PanelColores() y meterlos en la interfaz.
Pero no tienen un "nombre" de variable asignado para "hablarles" y pedirles que hagan cosas.
Existen, tenemos 10 objetos PanelColores, pero al no tener referencia, no podemos acudir a ellos

Citar
for (int i = 0; i < 10; i++)
        {//Con esto replico el panelColores que contiene los 3 paneles, 10 veces
            panelesBotones.add(new PanelColores(combinacion));
            add(panelesBotones);
        }

Si ahora queremos poder pedirles que se reinicien con el nuevo método que le hemos dado, necesitamos darles una referencia a la que poder acudir.
Como son muchos, lo mejor es referenciarlos usando un vector, así con un bucle podemos acceder a todos ellos con solo un par de líneas.

Así que a la clase MasterMind agregamos un vector como atributo para referenciar estos paneles.

Citar
public class MasterMind extends JFrame
{
   
    Combinacion combinacion;
    PanelColores[] pnColores;

    public MasterMind()
    {
        combinacion = new Combinacion(this);
        pnColores = new PanelColores[10];
       
        JPanel panelesBotones = new JPanel();
        panelesBotones.setLayout(new BoxLayout(panelesBotones, BoxLayout.Y_AXIS));
        //Layout simple que me permite colocar los elementos en forma vertical ;)
        for (int i = 0; i < 10; i++)
        {//Con esto replico el panelColores que contiene los 3 paneles, 10 veces
           pnColores[ i] = new PanelColores(combinacion);
            panelesBotones.add(pnColores[ i]);
            add(panelesBotones);
        }

¡Bien!
Ya podemos "hablar" con esos paneles, nos basta con un bucle, un simple FOR EACH dentro de un método para cuando queramos resetear los paneles.
Añadimos también este método a la clase MasterMind

Código: [Seleccionar]
    public void resetear() {
    for (PanelColores panel: pnColores)
    panel.resetPanel();
    }

Ahora, hay que decidir en qué momento les decimos a estos paneles que han de resetearse.
Lo lógico es hacerlo en el switch que hay dentro de la clase Combinación, ahí donde tu dabas orden de crear un nuevo MasterMind.

Citar
    public void Respuesta()
    {
        resp =JOptionPane.showConfirmDialog(null, msjRepetir, msjTitulo, JOptionPane.YES_NO_OPTION);
            switch (resp) {
                case 0:
                    new MasterMind();
                    break;
                case 1:
                    System.exit(0);
                    break;
                default:
                    System.exit(0);
                    break;
            }
    }
Como ya no vamos a crear un nuevo juego, sino resetear el juego actual, esa línea marcada en rojo la vamos a sustituir por otras dos líneas.
Una, para llamar al método que resetea a la clase Combinación
Y otra línea, para pedirle a la clase MasterMind, que resetee sus paneles de colores.

Pero, aquí surge un nuevo problema. Estamos dentro de la clase Combinación, y esta clase no tiene forma alguna de comunicarse con la clase MasterMind.

Las clases y los métodos/funciones tienen una cosa que se llama "ámbito"(scope), lo que viene a ser su área de influencia.
La clase Combinación puede influir en todo lo que está dentro de ella, pero no en lo que está "fuera".

De hecho, Combinación está dentro de MasterMind (es uno de sus atributos) así que MasterMind si puede influir en Combinación.
Pero no al revés, así que Combinación no puede pedirle a MasterMind que reinicie sus paneles.

A no ser que abramos un canal de comunicación.
Podemos hacer que Combinación también tenga un atributo MasterMind, y al construir un objeto Combinación, este reciba una referencia del objeto MasterMind.
Así ambas clases forman parte del ámbito de la otra, y pueden influirse mutuamente.

A Combinación le añadimos esa referencia a Mastermind como atributo, y la recibirá por su constructor

Citar
public class Combinacion {
   
    public int [] combinacion;
    public int intentos;
    public int muertos;
    public int heridos;
    public int resp;
    public boolean resuelto;
    public String resultado;
    public final String msjTitulo = "MASTERMIND BY JB";
    public final String msjGanar = "Enhorabuena, ¡ GANASTE ! ";
    public String msjIntentos = "UPS!, HAS GASTADO LOS 10 INTENTOS";
    public String msjRepetir = "¿PROBAMOS DE NUEVO?";
   
    MasterMind juegoMM; //Referencia a la clase principal
   
    public Combinacion(MasterMind mm)
    {
        combinacion = new int[4];
        generaCombinacion();
        //Le meto al constructor el metodo
        intentos = 0;
        resuelto = false;
        //Con esto controlo los intentos;
       
        juegoMM = mm;
    }

Y como ahora ya tenemos referencia a MasterMind, ya podemos "hablarle" y pedir que resetee sus paneles cuando el jugador quiera repetir partida.

Citar
    public void Respuesta()
    {
        resp =JOptionPane.showConfirmDialog(null, msjRepetir, msjTitulo, JOptionPane.YES_NO_OPTION);
            switch (resp) {
                case 0:
                   resetCombinacion();
                   juegoMM.resetear(); //Indicamos que hay que reiniciar los paneles

                    break;
                case 1:
                    System.exit(0);
                    break;
                default:
                    System.exit(0);
                    break;
            }
    }


Y con esto, ahora el juego se puede reiniciar tras cada partida, sin tener que crear nuevas instancias que se vayan acumulando en memoria.

Esto de la "comunicación entre clases" es algo que puede dar muchos quebraderos de cabeza, porque muchas veces necesitas que una única acción (pulsar el botón "SI") actúe sobre distintas clases y objetos.
Y aunque todas formen parte del mismo programa, no significa que estén comunicadas entre sí. De hecho, lo normal es que cada una tenga su ámbito propio, donde las otras clases no puedan meter mano.

Así que muchas veces habrá que abrir canales de comunicación mediante referencias entre unas y otras.

Por otra parte, esta comunicación se puede mejorar usando "patrones de diseño".
Es probable que hayas oído hablar del patrón "Modelo-Vista-Controlador", y si no tarde o temprano te hablarán de él.
Esto consiste en diseñar el programa de manera que unas clases se encarguen del Modelo del programa, es decir, los datos internos (contadores, evaluar resultados, etc,) y otras se encarguen de la Vista, lo que el usuario ve en pantalla (botones, diseño de interfaz, etc).

Entre estas, habría otra clase haciendo la función de Controlador. Esta clase tendría a todas las demás dentro de su ámbito y así puede encargarse de enviar los datos que una computa para que la otra los muestre, y actuar en todas ellas cuando sea necesario.

El programa que hemos hecho, en realidad, aplica este patrón pero no de la mejor forma.

La clase Combinación sería el Modelo.
Boton y PanelColores serían la Vista

Y la función del Controlador la llevan a medias entre MasterMind y Combinación, por eso hemos tenido que intercomunicarlas.

Lo ideal habría sido escribir el código de otro modo, para que solo MasterMind, o incluso otra clase creada específicamente para este propósito, fuera quien si encargase de "Controlar" si el juego ha terminado o no, de preguntar al usuario si quiere repetir o no, etc... dando y pidiendo datos a las clases del Modelo y de la Vista.


Pero bueno, todo esto lo comento para ampliar conocimientos.

Para ser nuestro primer MasterMind, yo creo que nos ha quedado muy bien je je..


EDITO:
Se me olvidó comentar un pequeño bug que surge tras todos estos cambios.
Al reiniciar partida, resulta que todos los campos se limpian pero luego en el campo de texto del útlimo panel donde hemos jugado, aparece el mensaje de "muertos y heridos".

Esto ocurre cuando se ha ganado, y es porque cuando ganamos, o sea cuando tenemos 4 muertos, el método evaluar() llama al JOptionPane para informar al usuario y si este quiere, se resetean los paneles para que siga jugando.

Pero el método evaluar()  no termina aquí, después de que todo se reinicie, el método continua con su algoritmo y retorna el String que contabiliza muertos y heridos.
Por eso tras el "reset" del juego, vuelve a aparecer esto en el campo de texto.

Para evitarlo, debemos poner fin al método evaluar() después de la llamada al JOptionPane, por ejemplo, pidiendo que retorne un valor null

Citar
        //Si encuentra 4 muertos, el juego está resuelto
        if (muertos == 4)
        {
            resuelto = true;
            JOptionPane.showMessageDialog(null, msjGanar, msjTitulo, JOptionPane.INFORMATION_MESSAGE);
            Respuesta();
            return null;
        }

Dejo el código completo en archivo adjunto (hay que estar logado en los foros para poder descargarlo).
« Última modificación: 02 de Abril 2021, 21:12 por Ogramar »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

WATACHI_WA

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 6
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #12 en: 07 de Diciembre 2020, 11:42 »
No se si esto sobrá aquí o no, ya que aquí solo se programa, pero incluyo aquí el manual del programador por si le quieres hechar un vistazo y darme tu opinion, lo tengo que entregar todo el miércoles, y te agradecería si me das una valoración por que así sé si entendí o no bien los atributos, clases, métodos, de tu proyecto

PD: no me deja incluir el manual, asiq comparto el enlace por si le quieres hechar un ojo, te lo agradecería
https://drive.google.com/file/d/1PoRSjIy3hFF_8yvtqlJy2PPEZLZPCk8T/view?usp=sharing

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 725
    • Ver Perfil
Re: MasterMind con JavaSwing
« Respuesta #13 en: 07 de Diciembre 2020, 13:13 »
Hay algunas cosas que no veo claras.

Citar
Clase Botón
Atributos
Int valor: Este atributo nos servirá para identificar el color que tiene como valor
ese momento el botón. Este valor esta codificado entre 1 y 6, que se corresponderá
con su posición en el Vector botones
, y según ese valor, se decidirá su color.

Ahí parece dar a entender que hay relación entre el valor del Boton y su posición en el vector, pero no es así.
Yo quitaría la parte marcada en negrita.



Citar
Public void rotarValor(): Este método nos permite darle un ciclo al valor, es
decir al llegar al máximo , comenzamos de nuevo desde el principio, en este caso sería
llegar al valor 6 , reseteamos al valor 1. Y le metemos el método cambiarColor para
que se resetee el valor al llegar a 6.

Esto tampoco queda claro, dicho así parece que sea cambiarColor quien resetea el valor.
Yo lo cambiaría por:
Citar
Public void rotarValor(): Este método nos permite darle un ciclo al valor, es
decir al llegar al máximo , comenzamos de nuevo desde el principio, en este caso sería
llegar al valor 6 , reseteamos al valor 1.
Cada vez que se altera el valor, se invoca al método cambiarColor para que actualice el color mostrado en pantalla y se corresponda con el nuevo valor.



Citar
Public void actionPerformed (Actionevent e): Para que todo esto ocurra le
metemos el método actionPerformed para que el usuario cuando clickee , dentro
escribimos el método rotarValor().

Esto no está mal, pero creo que se podría mejorar:
Citar
Public void actionPerformed (Actionevent e): Para que todo esto ocurra le
metemos el método actionPerformed para que el usuario cuando clickee , se llama al método rotarValor() para pasar al siguiente valor y color.



Citar
Clase combinación
Atributos
Public int [] combinacion: Es el vector generado aleatoriamente
Public int intentos: El número de veces que se puede jugar
Public int muertos: Contabiliza cuando el color y la posición en combinación[]
es la misma que la que el usuario elige y se guarda en vector botones [4].

Public int heridos: Contabiliza cuando el color es acertado, pero la posición en
botones [4] no es la misma que en combinación[4]

La explicación es mejorable:
Citar
Clase combinación
Atributos
Public int [] combinacion: Es el vector generado aleatoriamente
Public int intentos: El número de veces que se puede jugar
Public int muertos: Contabiliza los "muertos". Un "muerto" se produce cuando un elemento de botones[] coincide en valor y posición con un elemento de combinacion[].
Public int heridos: Contabiliza los "heridos". Un "herido" se produce cuando un elemento de botones[] coincide en valor, pero no en posición, con un elemento de combinacion[].



Citar
Public Combinacion(): Es el constructor, donde inicializo el vector, meto el
método generaCombinacion(), inicializo también los intentos a 0 y con el boolean
resuelto = false, controlo los intentos.
No es el boolean quien controla los intentos:
Citar
Public Combinacion(): Es el constructor, donde inicializo el vector, meto el
método generaCombinacion(), inicializo también los intentos a 0 y con el boolean
resuelto = false, controlo si la combinación secreta ha sido resuelta o no.



Esto que viene a continuación, es quizás lo más difícil de explicar, y lo has explicado muy bien.
Pero hay una cosita que llama la atención:

Citar
Public String evaluar (Integer [] colores): Con esto evaluamos si ha habido
muertos y/o heridos según las reglas del Mastermind. He usado un array de clase
Integer en lugar del tipo primitivo int, por que con Integer puedo dar valores null o -1 a
los elementos del array, porque cuando vaya a comparar los colores, si al comparar
dos posiciones de dos arrays ( combinación y el de selección de usuario) se producen
muertos o heridos, ya no se consultarán más esas posiciones mientras se sigue
evaluando, por eso las marco con valor null o -1. El problema que tiene esto es que no
puedo trabajar directamente con el array de combinación del usuario, puesto que
destruiría su combinación, para resolver este problema hago una copia de
combinación y trabajo sobre esa copia.
Así este método se encarga de evaluar recibiendo como parámetro un array con la
selección que ha hecho el usuario, comparo con la copia de la combinación generada
aleatoriamente, contabilizo si hay muertos y heridos y devuelvo un String con el
resultado.
Primero contabilizo muertos recorriendo ambos arrays a ver si en la misma posición,
coinciden los colores.
Segundo busco herido en las posiciones que no hagan sido puestas a null o -1 (las que
no hayan generado muertos), ya que los heridos son colores escogidos que sí constan
en la combinación, pero no en la misma posiciones.


Yo en mi código use Integer para poder poner valores null y "marcar" elementos que ya no deben ser consultados.
Tu en cambio, pusiste valores -1.

Ambas formas funcionan, eso no es problema.

Pero al explicarlo en la documentación, quizás mejor no mencionar lo de poner valores null, puesto que en realidad no lo estás haciendo en tu código.

Por eso en realidad, en tu código no necesitas usar vectores Integer, puedes usar todos como vectores int.

La diferencia entre int e Integer, es que int es un "dato primitivo", es decir, una variable a la "antigua usanza" que Java hereda del lenguaje C (Java es un derivado de C) y básicamente es un apuntador a una dirección de memoria.

Integer es una clase "moderna", ya pensada para la Programación Orientada a Objetos.
Es mucho más que un puntero de memoria, permite tener métodos, constructores, herencias, polimorfismo, valor null, etc...

En mi caso, me interesó usarlo únicamente por poder darles valor null.
Pero perfectamente podría haber usado el tipo primitivo int y haberles dado valor -1

Bueno, valor -1 , o cualquier otro valor que no estuviera entre 1 y 6.
Los elementos de los vectores que son "válidos", únicamente pueden tener valores entre 1 y 6.
Si quiero marcarlos como "no válidos", o "no consultables" mejor dicho, me basta con darle un valor cualquiera que este fuera del rango entre 1 y 6.
Le podría dar valor 0, -34, 7, 1000,....

La cuestión era idear una fórmula simple para "marcar" elementos de los vectores que ya no quiero seguir consultando, porque ya me habían dado un "muerto" o un "herido".



En clase PanelColores:
Citar
Public PanelColores (Combinacion c): Es el constructor de la clase, donde añado
como atributo una referencia al objeto combinación que será instanciado en la clase
principal JFrame Mastermind.
Añado la creación de los 3 paneles dentro del propio constructor y añado como
atributo una referencia al objeto combinación

Está bien, quizás yo añadiría una pequeña aclaración:

Citar
Public PanelColores (Combinacion c): Es el constructor de la clase, donde añado
como atributo una referencia al objeto combinación que será instanciado en la clase
principal JFrame Mastermind.
Teniendo una referencia al objeto combinacion, cada PanelColor es capaz por sí solo de evaluar la jugada del usuario con la combinación secreta.
Añado la creación de los 3 paneles dentro del propio constructor y añado como
atributo una referencia al objeto combinación
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".