Anexos diversos.

Compartición de código entre proyectos Gradle de Netbeans

El proceso es sencillo:

  1. Localiza el archivo JAR que contiene las clases que quieres importar y aprovechar en tu proyecto. Probablemente la ruta sea algo como «c:userspepeNetbeansProjectProyectobuildslibsarchivo.jar».

  2. Ve a tu proyecto Gradle de Netbeans y localiza el archivo build.gradle.

  3. Dentro de build.gradle encuentra la sección dependencies y añade dentro esta línea ``implementation files(c:\users\pepe\NetbeansProject\Proyecto\builds\libs\archivo.jar)

Observa que en el último paso hemos duplicado la barra diagonal.

Compartición de código entre proyectos Maven en Netbeans

La clase UtilidadesFicheros

A continuación se muestra el código completo de la clase UtilidadesFicheros:

public class UtilidadesFicheros {

    public static BufferedReader getBufferedReader(
        String nombreFichero) throws
    FileNotFoundException {
        FileReader lector;
        lector = new FileReader(nombreFichero);
        BufferedReader bufferedReader;
        bufferedReader = new BufferedReader(lector);
        return bufferedReader;
    }

    public static PrintWriter getPrintWriter(
        String nombreFichero) throws IOException {
        PrintWriter printWriter;
        FileWriter fileWriter;
        fileWriter = new FileWriter(nombreFichero);
        printWriter = new PrintWriter(fileWriter);
        return printWriter;
        //Fin de getPrintWriter
    }

    public static ArrayList<String> getLineasFichero(
        String nombreFichero) throws IOException {
        ArrayList<String> lineas = new ArrayList<String>();
        BufferedReader bfr = getBufferedReader(nombreFichero);
        //Leemos líneas del fichero...
        String linea = bfr.readLine();
        while (linea != null) {
            //Y las añadimos al array
            lineas.add(linea);
            linea = bfr.readLine();
        }
        //Fin del bucle que lee líneas
        return lineas;
    }

    //Fin de getLineasFichero
    public static long getSuma(String[]
                               listaNombresFichero) {
        long suma = 0;
        ArrayList<String> lineas;
        String lineaCantidad;
        long cantidad;
        for (String nombreFichero : listaNombresFichero) {
            try {
                //Recuperamos todas las lineas
                lineas = getLineasFichero(nombreFichero);
                //Pero solo nos interesa la primera
                lineaCantidad = lineas.get(0);
                //Convertimos la linea a número
                cantidad = Long.parseLong(lineaCantidad);
                //Y se incrementa la suma total
                suma = suma + cantidad;
            } catch (IOException e) {
                System.err.println("Fallo al procesar el fichero "
                                   + nombreFichero);
                //Fin del catch
            }
            //Fin del for que recorre los nombres de fichero
        }
        return suma;
    }
}

Solución al problema del simulador de Casino

Se ha optado por un diseño muy simple y con un acoplamiento muy alto. En pocas palabras hay solo dos clases:

  1. La clase Banca: ejecuta toda la simulación y acepta apuestas de jugadores. La banca crea los Jugadores (que serán hilos), y luego pasará a ejecutar la simulación, que puede pasar por diversos estados. Algunos métodos de la banca deben ser synchronized, ya que todos los hilos Jugador tienen una referencia a la clase Banca y por lo tanto puede haber varios hilos intentando entrar en un cierto método.

  2. La clase Jugador: no necesita métodos synchronized, ya que cada Jugador accede solo a su propia información. Sin embargo, si hubiese más de una banca (quizá porque un Jugador jugase a varias ruletas a la vez) la situación sería muy distinta.

  3. En realidad, la clase Jugador es solo una base para poder crear distintos tipos de Jugador que siguen distintas estrategias.

En las secciones siguientes se ilustra el código de las distintas clases.

La clase Banca

public class Banca {

    protected long saldo;

    protected boolean enBancarrota;

    protected Random generador;

    protected boolean sePuedenHacerApuestas;

    protected int numeroGanador;

    public enum Estado {

        INICIO, ACEPTANDO_APUESTAS, RULETA_GIRANDO, PAGANDO_APUESTAS, EN_BANCARROTA
    }

    ;

    private Estado estadoRuleta;

    private ArrayList<Jugador> apostadores;

    public Banca(long saldoInicial) {
        saldo = saldoInicial;
        enBancarrota = false;
        estadoRuleta = Estado.INICIO;
        generador = new Random();
        apostadores = new ArrayList<Jugador>();
    }

    public synchronized boolean enBancarrota() {
        return enBancarrota;
    }

    public synchronized void sumarSaldo(
        long cantidad) {
        saldo = saldo + cantidad;
    }

    public synchronized void restarSaldo(
        long cantidad) {
        if (saldo - cantidad <= 0) {
            saldo = 0;
            estadoRuleta = Estado.EN_BANCARROTA;
            return;
        }
        saldo = saldo - cantidad;
    }

    public synchronized void aceptarApuesta(
        Jugador jugador) {
        if (estadoRuleta == Estado.ACEPTANDO_APUESTAS) {
            apostadores.add(jugador);
        }
    }

    public synchronized boolean aceptaApuestas() {
        if (estadoRuleta == Estado.ACEPTANDO_APUESTAS) {
            return true;
        }
        return false;
    }

    public void comunicarNumeroGanador(int numero) {
        /* Al pasar el número a los jugadores, ellos nos
         * irán restando el saldo que les corresponda por haber ganado */
        int numApostadores = apostadores.size();
        for (Jugador apostador : apostadores) {
            apostador.comunicarNumero(numeroGanador);
        }
        /* Una vez comunicadas todas las apuestas, borramos
         * el vector. La partida va a volver a empezar */
        apostadores.clear();
    }

    public void girarRuleta() throws
    InterruptedException {
        int segundosAzar;
        System.out.println("Empieza el juego!");
        while (estadoRuleta != Estado.EN_BANCARROTA) {
            estadoRuleta = Estado.ACEPTANDO_APUESTAS;
            /* Se eligen unos milisegundos al azar para que los jugadores
             * elijan, aunque quizá no todos puedan llegar a apostar
             */
            segundosAzar = 1 + generador.nextInt(3);
            System.out.println("Hagan juego, tienen Vds " +
                               segundosAzar + " segundos");
            Thread.sleep(1000 * segundosAzar);
            System.out.println("Ya no va más, señores. ¡Girando!");
            estadoRuleta = Estado.RULETA_GIRANDO;
            Thread.sleep(3000);
            numeroGanador = generador.nextInt(37);
            System.out.println("El número ganador es el :" +
                               numeroGanador);
            estadoRuleta = Estado.PAGANDO_APUESTAS;
            this.comunicarNumeroGanador(numeroGanador);
            System.out.println("El saldo de la banca es ahora:"
                               + saldo);
        }
    }

    public void simular(int jugadoresPar,
                        int jugadoresMartingala,
                        int jugadoresClasicos) throws
    InterruptedException {
        Thread[] hilosJugadoresPares = new Thread[jugadoresPar];
        for (int i = 0; i < jugadoresPar; i++) {
            JugadorParImpar jugador = new JugadorParImpar(
                1000, this);
            hilosJugadoresPares[i] = new Thread(jugador);
            hilosJugadoresPares[i].setName("Apostador par/impar "
                                           + i);
            hilosJugadoresPares[i].start();
        }
        Thread[] hilosJugadoresMartingala = new Thread[jugadoresMartingala];
        for (int i = 0; i < jugadoresMartingala; i++) {
            JugadorMartingala jugador = new JugadorMartingala(
                1000, this);
            hilosJugadoresMartingala[i] = new Thread(jugador);
            hilosJugadoresMartingala[i].setName("Apostador martingala "
                                                + i);
            hilosJugadoresMartingala[i].start();
        }
        Thread[] hilosJugadoresClasico = new Thread[jugadoresClasicos];
        for (int i = 0; i < jugadoresClasicos; i++) {
            JugadorClasico jugador = new JugadorClasico(1000,
                    this);
            hilosJugadoresClasico[i] = new Thread(jugador);
            hilosJugadoresClasico[i].setName("Apostador clasico "
                                             + i);
            hilosJugadoresClasico[i].start();
        }
        this.girarRuleta();
    }

    public static void main(String[] args) throws
    InterruptedException {
        Banca b = new Banca(50000);
        b.simular(5, 5, 5);
    }
}

La clase Jugador

public abstract class Jugador implements
    Runnable {

    protected long saldo;

    protected boolean enBancarrota;

    protected long cantidadApostada;

    protected boolean apuestaRealizada;

    protected Banca banca;

    protected String nombreHilo;

    protected Random generador;

    public Jugador(long saldoInicial, Banca b) {
        saldo = saldoInicial;
        banca = b;
        apuestaRealizada = false;
        generador = new Random();
    }

    public void sumarSaldo(long cantidad) {
        saldo = saldo + cantidad;
    }

    public void restarSaldo(long cantidad) {
        if (saldo - cantidad <= 0) {
            saldo = 0;
            enBancarrota = true;
            return;
        }
        saldo = saldo - cantidad;
    }

    public boolean enBancarrota() {
        return enBancarrota;
    }

    /* Lo usa la banca para comunicarnos el número*/
    public abstract void comunicarNumero(int numero);

    public abstract void hacerApuesta();

    /* Todos los jugadores hacen lo mismo:
     * Mientras no estemos en bancarrota ni la
     * banca tampoco, hacemos apuestas. La banca
     * nos dirá el número que haya salido y en
     * ese momento (y si procede) incrementaremos
     * nuestro saldo
     */
    @Override
    public void run() {
        nombreHilo = Thread.currentThread().getName();
        while ((!enBancarrota)
                && (!banca.enBancarrota())) {
            int msAzar;
            /* Mientras la ruleta no acepte apuestas, dormimos un
             * periodo al azar */
            while (!banca.aceptaApuestas()) {
                msAzar = this.generador.nextInt(500);
                try {
                    //System.out.println(nombreHilo+":banca ocupada, durmiendo...");
                    Thread.sleep(msAzar);
                } catch (InterruptedException e) {
                    return;
                }
                if (banca.enBancarrota()) {
                    return;
                }
            }
            hacerApuesta();
        }
        String nombre = Thread.currentThread().getName();
        if (enBancarrota) {
            System.out.println(nombre +
                               ": ¡¡Me arruiné!!");
            return;
        }
        if (banca.enBancarrota()) {
            System.out.println(nombre +
                               " hizo saltar la banca");
        }
    }
}

La clase JugadorClasico

public class JugadorClasico extends Jugador {

    int numeroElegido;

    public JugadorClasico(long saldoInicial,
                          Banca b) {
        super(saldoInicial, b);
    }

    @Override
    public void comunicarNumero(int numero) {
        /* No hace falta comprobar si el numero es
         * 0, ya que este jugador no lo elige nunca */
        if (numero == numeroElegido) {
            System.out.println(nombreHilo +
                               ": ¡Gana 36 veces lo jugado, 360 euros");
            banca.restarSaldo(360);
            sumarSaldo(360);
        }
        System.out.println(nombreHilo +
                           " queda con un saldo de " + saldo);
        apuestaRealizada = false;
    }

    @Override
    public void hacerApuesta() {
        if (!banca.aceptaApuestas())
            return;
        if (apuestaRealizada)
            return;
        /* Elegimos del 1 al 36 (no se puede elegir el 0*/
        numeroElegido = 1 + generador.nextInt(36);
        banca.sumarSaldo(10);
        restarSaldo(10);
        apuestaRealizada = true;
        banca.aceptarApuesta(this);
    }
}

La clase JugadorParImpar

public class JugadorParImpar extends Jugador {

    public JugadorParImpar(long saldoInicial,
                           Banca b) {
        super(saldoInicial, b);
    }

    protected boolean jugamosAPares;

    @Override
    public void hacerApuesta() {
        if (!banca.aceptaApuestas())
            return;
        if (apuestaRealizada)
            return;
        /* Elegimos una apuesta...*/
        if (generador.nextBoolean() == true) {
            //System.out.println(nombreHilo+" elige apostar a par");
            jugamosAPares = true;
        } else {
            //System.out.println(nombreHilo+" elige apostar a impar");
            jugamosAPares = false;
        }
        banca.sumarSaldo(10);
        restarSaldo(10);
        apuestaRealizada = true;
        /* Y pedimos a la banca que nos la acepte*/
        banca.aceptarApuesta(this);
    }

    public boolean esGanador(int num) {
        /* Este jugador necesita comprobar si ha salido el 0,
         * aunque no lo elige nunca, ya que si hemos apostado
         * Par podríamos pensar que hemos ganado cuando no es así */
        if (num == 0) {
            return false;
        } else {
            if ((num % 2 == 0) && (jugamosAPares)) {
                return true;
            }
            if ((num % 2 != 0) && (!jugamosAPares)) {
                return true;
            }
        }
        //Fin del else externo
        return false;
        //Fin de esGanador
    }

    @Override
    public void comunicarNumero(int numero) {
        if (esGanador(numero)) {
            /*Ganamos y cogemos a la banca 20 euros*/
            System.out.println(nombreHilo +
                               " gana 20 euros por acertar impar");
            banca.restarSaldo(20);
            this.sumarSaldo(20);
        }
        System.out.println(nombreHilo +
                           " se queda con un saldo de " + saldo);
        /* Sea como sea, al terminar indicamos que ya no tenemos
         * una apuesta realizada. Es decir, permitirmos al
         * jugador volver a apostar	 */
        apuestaRealizada = false;
    }
}

La clase JugadorMartingala

public class JugadorMartingala extends Jugador {

    private int cantidadAApostar;

    private int numeroElegido;

    public JugadorMartingala(long saldoInicial,
                             Banca b) {
        super(saldoInicial, b);
        cantidadAApostar = 1;
    }

    @Override
    public void comunicarNumero(int numero) {
        if (numero == 0) {
            System.out.println(nombreHilo + " pierde " +
                               cantidadAApostar);
            cantidadAApostar = cantidadAApostar * 2;
            return;
        }
        if (numeroElegido == numero) {
            int beneficios = cantidadAApostar * 36;
            banca.restarSaldo(beneficios);
            sumarSaldo(beneficios);
            cantidadAApostar = 1;
        }
        if (numeroElegido != numero) {
            //System.out.println(nombreHilo + " pierde "+cantidadAApostar);
            cantidadAApostar = cantidadAApostar * 2;
        }
        System.out.println(nombreHilo +
                           " queda con un saldo de " + saldo);
        apuestaRealizada = false;
    }

    @Override
    public void hacerApuesta() {
        if (!banca.aceptaApuestas())
            return;
        if (apuestaRealizada)
            return;
        /* Elegimos del 1 al 36 (no se puede elegir el 0*/
        numeroElegido = 1 + generador.nextInt(36);
        banca.sumarSaldo(cantidadAApostar);
        restarSaldo(cantidadAApostar);
        apuestaRealizada = true;
        banca.aceptarApuesta(this);
    }
}