Cliente Servidor número secreto

CLIENTE

CLASE PRINCIPAL

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package socketcliente_multiples;

/**
 *
 * @author glop
 */
public class Socketcliente_multiples {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
       
        clientes cliente = new clientes(); // Instancia que representa un cliente
        cliente.start(); // Se inicia el hilo del cliente. Ya se encargará el servidor de asignarle un id
    }
}












CLASE HILO CLIENTES




/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package socketcliente_multiples;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 *
 * @author glop
 */
public class clientes extends Thread {
   
    public clientes() {
       
    }
   
   
    @Override
    public void run() {
        BufferedReader lector  = new BufferedReader(new InputStreamReader(System.in)); // Buffer que lee lo escrito por cliente
        try {
        Socket socket = new Socket("localhost",2000); // Se crea el socket del cliente con la conexión local y el puerto 2000
        System.out.println("Conectado");
       
        // Buffers de entrada y salida de datos. Necesarios para la comunicaciones entre el cliente y el servidor
        DataOutputStream salida = new DataOutputStream (socket.getOutputStream());
        DataInputStream entrada = new DataInputStream (socket.getInputStream());
       
        int numeroCliente=-1; // Variable que almacena el número introducido por el cliente. Al iniciarse el juego es -1
        int correcto = -1; // Variable que indica si se ha acertado el número. Al iniciarse es -1
        int intentos=0; // Variable que contabiliza los intentos
       
        System.out.println("Intenta averiguar el número secreto"); // Presentación del juego
       
        while(correcto!=1) { // Sigo pidiento datos al cliente hasta que el servidor envíe el 1 que es la clave
                             // de que ha acertado
            numeroCliente=-1; // Se resetea el valor del número del cliente
            while(numeroCliente==-1) { // Comprueba que es un número válido
            try {
                System.out.println("¿Número?"); // Pido el número
                numeroCliente = Integer.parseInt(lector.readLine()); // Lo guardo en una variable numérica
                   
            } catch (Exception ex) { // Si no es un número válido me lanza un error y vuelve a pedirlo
                System.out.println("No es un número válido");
            }
            }
            salida.writeInt(numeroCliente); // Envío lo que recibo por teclado
            correcto=entrada.readInt(); // Recibo la respuesta del servidor
            if (correcto==0) { // Si recibo un 0 es que el número es menor
                System.out.println("El número secreto es menor a " + numeroCliente);
            } else if (correcto==2) { // Si recibo un 2 es que el número es mayor
                System.out.println("El número secreto es mayor a " + numeroCliente);
            }
            intentos++; // Se contabiliza un nuevo intento
        }
       
        // Como ya he salido del while, he ganado y lo comunico al cliente
        System.out.println("Efectivamente, el número secreto es " + numeroCliente);
        System.out.println("¡¡EL JUEGO HA TERMINADO LO HAS CONSEGUIDO EN " + intentos +  " INTENTOS!!");
        System.out.println("Desconectando conexión ...");
       
        // Se cierra el socket y los flujos
        entrada.close();
        salida.close();
        socket.close();
      
        } catch (Exception ex) { // Si ocurriera alguna excepción, la capturo e informo
            System.out.println("Ocurrio un error en la comunicación con el servidor");
    }
    }
}

SERVIDOR

CLASE PRINCIPAL

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package socketservidor_multiples;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

/**
 *
 * @author glop
 */
public class servidor extends Thread {
   
    private Socket cliente;
    private int id;
    DataOutputStream salida;
    DataInputStream entrada;
   
    public servidor(Socket sock, int idd) {
        this.cliente = sock;
        this.id = idd;
       
       
        try {

       
       
        // Buffers de entrada y salida de datos. Necesarios para la comunicaciones entre el cliente y el servidor
        salida = new DataOutputStream (cliente.getOutputStream());
        entrada = new DataInputStream (cliente.getInputStream());
       
       
        } catch (Exception ex) {
       
        }
    }

        @Override
        public void run() {
        System.out.println("El cliente " + id + " está jugando");
        Random aleatorio = new Random(); // Generador de números aleatorios
        int n = aleatorio.nextInt(100); // Variable que almacena un número de 0 a 100
        int numeroCliente = -1; // Variable que almacena el número que me manda el cliente
        try {
         // Hasta que el número que me envíe el cliente no sea el número secreto, sigo comparándolos
        // y no dejo que la comunicación acabe
        while (n!=numeroCliente) {
            numeroCliente = entrada.readInt(); // Recibo el número de la parte del cliente
            if (numeroCliente>n) {
                salida.writeInt(0); // Le indico que es menor mediante el envío de un 0
               
            }
            if (numeroCliente<n) {
                salida.writeInt(2); // Le indico que es mayor mediante el envío de un 2
               
            }
           
        }
           
        salida.writeInt(1); // Le indico que el número es correcto mediante el envío de un 1
        // Como ya he salido del while, he ganado, se lo indico mandando un 1 que es la clave.
        System.out.println("¡¡EL CLIENTE " + id +  " HA ACERTADO!!");
        System.out.println("Desconectando conexión con el cliente " + id + " ...");
        cliente.close(); // Cierro cliente
    } catch (Exception ex) { // Si ocurriera algún error, lo capturo e informo
        System.out.println("Ocurrio un error en la comunicación con el cliente " + id);
   
}
    }
   
}

CLASE HILO SERVIDOR

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package socketservidor_multiples;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

/**
 *
 * @author glop
 */
public class servidor extends Thread {
   
    private Socket cliente;
    private int id;
    DataOutputStream salida;
    DataInputStream entrada;
   
    public servidor(Socket sock, int idd) {
        this.cliente = sock;
        this.id = idd;
       
       
        try {

       
       
        // Buffers de entrada y salida de datos. Necesarios para la comunicaciones entre el cliente y el servidor
        salida = new DataOutputStream (cliente.getOutputStream());
        entrada = new DataInputStream (cliente.getInputStream());
       
       
        } catch (Exception ex) {
       
        }
    }

        @Override
        public void run() {
        System.out.println("El cliente " + id + " está jugando");
        Random aleatorio = new Random(); // Generador de números aleatorios
        int n = aleatorio.nextInt(100); // Variable que almacena un número de 0 a 100
        int numeroCliente = -1; // Variable que almacena el número que me manda el cliente
        try {
         // Hasta que el número que me envíe el cliente no sea el número secreto, sigo comparándolos
        // y no dejo que la comunicación acabe
        while (n!=numeroCliente) {
            numeroCliente = entrada.readInt(); // Recibo el número de la parte del cliente
            if (numeroCliente>n) {
                salida.writeInt(0); // Le indico que es menor mediante el envío de un 0
               
            }
            if (numeroCliente<n) {
                salida.writeInt(2); // Le indico que es mayor mediante el envío de un 2
               
            }
           
        }
           
        salida.writeInt(1); // Le indico que el número es correcto mediante el envío de un 1
        // Como ya he salido del while, he ganado, se lo indico mandando un 1 que es la clave.
        System.out.println("¡¡EL CLIENTE " + id +  " HA ACERTADO!!");
        System.out.println("Desconectando conexión con el cliente " + id + " ...");
        cliente.close(); // Cierro cliente
    } catch (Exception ex) { // Si ocurriera algún error, lo capturo e informo
        System.out.println("Ocurrio un error en la comunicación con el cliente " + id);
   
}
    }
   
}

Tiro con arco

CLASE PRINCIPAL

package PaquetePrincipal;

import java.util.concurrent.Semaphore;

/******************************************************************************
 * Clase donde reside el método main() que inicia la aplicación
 *
 * @author IFU
 */


public class Main {

    /**************************************************************************
     * Define los parámetros necesarios para construir hilos tiradores (ver el
     * constructor de la clase Tirador). Se crean los 5 tiradores, y los inicia.
     *
     * @param args the command line arguments
     */
    public static void main(String[] args) {
       
        //número de tiradores. Cada tirador se identifica por un índice del 0 al 4
        //número de arcos de las que disponen los tiradores para disparar
        int tiradores = 5;
        int arcos = 2;

        //Aqui ira el código para declarar un semaforo con los permisos correspondientes
        //a los arcos de los que se disponen.
        Semaphore arco = new Semaphore(arcos,true);
       

       
        //Aqui ira el codigo para iniciar los hilos de los cinco tiradores.
        //Se debe tener en cuenta la forma del constructor tirador.
        for (int c=0;c<tiradores;c++) {
            Tirador tirador = new Tirador(c,arco);
            tirador.start();
        }
       
    }
}

CLASE HILO TIRADORES

package PaquetePrincipal;

import java.util.concurrent.Semaphore;

/*****************************************************************************
 * Hilo tirador. Su método run() realiza un bucle infinito que consite en
 * invocar a los métodos cogerArco, disparar, soltarArco...
 *
 * @author IFU
 */

public class Tirador extends Thread{
   
    //indice del Tirador actual
    private int miIndice;
   
    //referencia al semáforo externo
    private Semaphore semaforoArco;
   
     /****************************************************************************
     * constructor de dos parámetros, cada uno de los cuales se guardará en una
     * variable local para usarla cuando sea neceario
     *
     * @param miIndice índice que identifica al tirador (un entero del 0 al 4)
     * @param semaforoArco semáforo con número de permisos igual al de arcos
     */
    public Tirador(int miIndice, Semaphore semaforoArco){
        this.miIndice= miIndice;
        this.semaforoArco = semaforoArco;
    }
   
     /**************************************************************************
     * bucle infinito: llamada al método cogerArco(),
     * llamada al método disparar(),
     * llamada al método soltarArco()
     */
   
    @Override
    public void run() {

        //Aqui ira el codigo para que el hilo este en un bucle infinito en el que
        //el tirador coge el arco, dispara y suelta el arco.
        while(true) {
            cogerArco();
            disparar();
            soltarArco();
        }

    }
   
     /****************************************************************************
     * método cogerArco(): mostrará un mensaje en la Salida de que el
     * 'Tirador ' N ' quiere disparar', mientras trata de conseguir un
     * Arco para disparar. Una vez conseguida,
     * mostrará un mensaje de que el 'Tirador ' N ' coge un arco'.
     */
    public void cogerArco() {

        System.out.println("Tirador " + (miIndice+1) + " quiere disparar");

        //Aqui ira el codigo para que el hilo intente adquirir el recurso compartido
        //que en esta caso es un arco
        try {
            semaforoArco.acquire(1);
        } catch (InterruptedException iex) {
            System.out.println("Ocurrió un error cuando el tirador " + (miIndice + 1) + " intentaba coger el arco");
        }
       
      
       
        System.out.println("Tirador " + (miIndice+1) + " coge un arco");
    }
   
     /****************************************************************************
     * método disparar(): mostrará un mensaje en la Salida de que el
     * 'Tirador ' N ' disparando'
     * Para simular esta actividad, dormirá el hilo un tiempo aleatorio.
     */
    public void disparar(){
       
        //Aqui ira el codigo para mostrar un mensaje indicando
        //que el tirador número .... está disparando
       

        //Aqui ira el codigo para dormir el hilo un tiempo aleatorio para simular
        System.out.println("Tirador " + (miIndice+1) + " está disparando");
        try {
            sleep(5000);
        } catch (InterruptedException iex) {
            System.out.println("Ocurrió un error cuando el tirador " + (miIndice+1) + " estaba disparando");
        }
       
    
    }
   
     /****************************************************************************
     * método soltarArco(): mostrará un mensaje en la Salida de que el
     * 'Tirador ' N ' ha disparado y Suelta el Arco' y liberá la Arco.
     */
    public void soltarArco(){
        //termina de disparar
        System.out.println("Tirador " + (miIndice+1) + " ha disparado. Suelta un arco.");
       
        //Aqui ira el codigo para liberar el recurso compartido, es decir el arco
        semaforoArco.release(1);
       
    }
}  

Cena de los filósofos

CLASE PRINCIPAL

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cena_filosofos;

import java.util.concurrent.Semaphore;

/**
 *
 * @author glop
 */
public class Cena_filosofos {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Semaphore[] palillos = new Semaphore[5]; // Se crea el array de semáforos.
       
        // Mediante un bucle for, se recorre el array de semáforos y se le da a cada uno un permiso único de uso.
        for (int c = 0; c < 5; c++) {
            palillos[c] = new Semaphore(1,true);
        }
       
        // Se instancian los cinco filósofos aportando los datos: posiciones de los dos palillos, nombre, y los dos palillos
        // que le pertenecen y actúan como semáforos de uso compartido y excluyente
        filosofo f1 = new filosofo(5,1, "Filósofo 1",palillos[4],palillos[0]);
        filosofo f2 = new filosofo(1,2, "Filósofo 2",palillos[0],palillos[1]);
        filosofo f3 = new filosofo(2,3, "Filósofo 3",palillos[1],palillos[2]);
        filosofo f4 = new filosofo(3,4, "Filósofo 4",palillos[2],palillos[3]);
        filosofo f5 = new filosofo(4,5, "Filósofo 5",palillos[3],palillos[4]);
       
        // Se inician los cinco hilos.
        f1.start();
        f2.start();
        f3.start();
        f4.start();
        f5.start();
       
    }
}

CLASE HILO FILÓSOFO

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cena_filosofos;

// Importo las clases necesarias para trabajar
import java.util.Random;
import java.util.concurrent.Semaphore;

/**
 *
 * @author glop
 */
public class filosofo extends Thread{
  
    private static final Random aleatorio = new Random(); // Generador de números aleatorios
    private Semaphore palilloder; // Semáforo que representa el palillo derecho
    private Semaphore palilloizq; // Semñaforo que representa en palillo izquierdo
    int posder=-1; // Toma la posición del palillo correspondiente para informar al usuario
    int posizq=-1; // Toma la posición del palillo correspondiente para informar al usuario
    String nombre; // Nombre del filósofo
   
    // Construye el filósofo con los datos proporcionados. Éstos son; la posición de los dos palillos que le pertencen.
    // el nombre del filósofo y los dos palillos que utilizará que son semáforos de uso compartido y excluyente 
    public filosofo(int posd,int posiz,String nomb,Semaphore palder,Semaphore palizq) {
        this.posder = posd;
        this.posizq = posiz;
        this.nombre = nomb;
        this.palilloder = palder;
        this.palilloizq = palizq;
    }
   
    // Método que representa al filósofo pensando
    private void pensar() {
       
        try {
         System.out.println(this.nombre + " está pensando");
         sleep(aleatorio.nextInt(5000)) ;  // El tiempo que transcurre pensando se calcula aleatoriamente hasta 5 segundos
        } catch(InterruptedException ex) {
           
        }
    }
   
    // Método que representa al filósofo comiendo
    private void comer() {
      
        try { // Intenta tomar los palillos
           palilloder.acquire(); // Toma el palillo derecho, si este palillo estuviera en uso se entraría en una disputa,
                                 // el hilo se interrumpiría,
                                // y el proceso iría al finally donde lo suelta
          
           if (!palilloizq.tryAcquire()) { // Si el palillo izquierdo esta siendo usado el filósofo espera.
               System.out.println(this.nombre + " está hambriento"); // Se lanza un mensaje por pantalla indicando
                                                                     // que el filósofo está hambriento
              
               return; // Irá inmediatamente al finally donde soltará el palillo derecho que es quien primero tomó
           }
          
           // Si ha llegado hasta aquí es que el palillo izquierdo también ha sido tomado con éxito. ¡Ya puede empezar!
          
           // Se lanza el mensaje por pantalla de que el filósofo ha empezado a comer.
           // También se indica, a efectos informativos, los palillos que utiliza
           System.out.println(this.nombre + " está comiendo con los palillos : " + this.posder + " y " + this.posizq);
           sleep(aleatorio.nextInt(5000)); // Se calcula la demora en comer aleatoriamente hasta 5 segundos
          
           // Se lanza el mensaje por pantalla de que el filósofo ha terminado de comer.
           // También se indica, a efectos informativos, los palillos que ha utilizado y ahora libera       
           System.out.println(this.nombre + " ha terminado de comer y libera los palillos : "+ this.posder + " y " + this.posizq);
           palilloizq.release(); // Como ya ha terminado de comer, suelta el palillo izquierdo.
       } catch (InterruptedException ex) {
          
       } finally {
            // En cualquier caso, soltará el palillo derecho.
           palilloder.release();
       }
    }
   
    @Override
    public void run() {
        while(true) { // En un bucle infinito, piensa y come, piensa y come ...
        pensar();
        comer();
        }
    }
  
}

Productor consumidor

CLASE PRINCIPAL

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package productor_consumidor;

/**
 *
 * @author glop
 */
public class Productor_consumidor {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
       Buffer bu = new Buffer(); //Instalcia del objeto Buffer
       productor pro = new productor(bu); // Instancia del objeto productor
       consumidor con = new consumidor(bu); // Instancia del objeto consumidor
      
       // Se lanzan los hilos
       pro.start();
       con.start();
      
    }
}

CLASE BUFFER

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package productor_consumidor;


/**
 * Clase del objeto Buffer
 * @author glop
 */
public class Buffer {
   
    char conten[] = new char[6]; // Array de char con 6 posiciones
    public int capacidad=0; // Variable que almacena la capacidad del Buffer, se inicia con 0 y el máximo es 6
   
   
    // Se construye el objeto Buffer y se dan valores char vacío al array
    public Buffer() {
       conten[0] = ' ';
       conten[1] = ' ';
       conten[2] = ' ';
       conten[3] = ' ';
       conten[4] = ' ';
       conten[5] = ' ';
    }
   
    // Método sincronizado que deposita un caracter en el buffer
    public synchronized void deposita(char caract) {
       
        // La estructura while indica que el hilo debe esperar si no hay capacidad para más caracteres.
        while(capacidad==5) {
            try {
                wait();
            } catch(InterruptedException ex) {
           
            }
                }
       
         // Se recorre el array el búsqueda de elementos vacío en los que depositar el caracter
            for (int c=0;c<conten.length;c++) {
                if (conten[c]==' ') {
                    conten[c] = caract;
                    capacidad = capacidad + 1;
                    break; // En el momento que encuentre un caracter vacío, se puede salir del bucle
                }
            }
            notify(); // Se notifica a los demás hilo que acabó la operación
    }
   
   
    // Método sincronizado que recoge el caracter. Devuelve el caracter obtenido
    public synchronized char recoge() {
        char letra=' ';
       
        // Si no hay nada que recoger, el hilo espera
        while(capacidad==0) {
            try {
                wait();
            } catch(InterruptedException ex) {
           
            }
        }
       
        // Se recorre el array en búsqueda de elementos que tengan algún contenido.
        for (int c=0;c<conten.length;c++) {
            if (conten[c]!=' ') {
                letra = conten[c]; // Almacena en la variable letra lo contenido en el elemento.
                conten[c] = ' '; // Se borra el elemento ya que se ha extraído el caracter que tenía
                capacidad = capacidad - 1;
                break; // Cuando se ha extraído el elemento, se puede salir del bucle
            }
        }
       
        notify(); // Notifica a los demás hilos que acabó la acción
        return letra; // Devuelve el caracter obtenido
       
    }
}

CLASE HILO PRODUCTOR

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package productor_consumidor;


/**
 * Clase del objeto productor
 * @author glop
 */
public class productor extends Thread {
   
    private final String caracteres = "abcdefghijklmnñopqrstuvwxyz"; // String con las letras de abecedario
    private Buffer buffer; // Instancia del objeto buffer
   
    // Se construye el objeto productor pasando como parámetro un objeto Buffer
    public productor(Buffer buff) {
        this.buffer = buff;
    }
   
    public void run() {
       
        // Se realiza un bucle 15 veces según lo pedido en la tarea
        for (int c=0;c<15;c++) {
        char l=caracteres.charAt((int)(Math.random()*caracteres.length()));; // Se genera aleatoriomente un caracter
        buffer.deposita(l); // Se deposita en buffer
        System.out.println("Depositado el caracter " + l + " en el buffer"); // Salidad por pantalla
        try {
                sleep(100);
            } catch(InterruptedException ex) {
           
            }
        }
        }
       
    }

CLASE HILO CONSUMIDOR

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package productor_consumidor;


/**
 * Clase del objeto consumidor
 * @author glop
 */
public class consumidor extends Thread {
   
    private Buffer buffer; // Instancia del objeto Buffer
   
    // Se construye el objeto consumidor pasando por parámetro un objeto Buffer
    public consumidor(Buffer buff) {
        this.buffer = buff;
    }
   
    public void run() {
       
        // Se realiza un bucle 15 veces según lo pedido en la tarea
        for (int c=0;c<15;c++) {
        char l;
        l = buffer.recoge(); // Se almacena en una variable char el caracter obtenido de la recogida del buffer
        System.out.println("Recogido el caracter " + l + " en el buffer"); // Salida por pantalla
        try {
                sleep(100);
            } catch(InterruptedException ex) {
           
            }
        }
        }
       
    }

Robots 2d

CLASE PRINCIPAL

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package robots2D;

import java.io.File;
import org.lwjgl.LWJGLUtil;
import org.newdawn.slick.*;
import org.newdawn.slick.Input.*;
import org.newdawn.slick.font.effects.ColorEffect;
import org.newdawn.slick.tiled.*;

/**
 * JUEGO DE LOS ROBOTS - aplicación base para el desarrollo del examen de la segunda evaluación
 *
 *
 */
public class Robots2D extends BasicGame {

    // Tilemap
    private TiledMap mapa;
   
    // Estado del jugador
    private float jugadorX, jugadorY;
    private SpriteSheet cuadros;
    private SpriteSheet cuadrosRobot;
   
   
    // Posición del corazón
    private float corazonX, corazonY;
    private Image corazon;
   
    // NUEVO: Para almacenar la explosión
    private SpriteSheet explosion;
   
   
    private Animation jugador;
    private Animation jugadorArriba;
    private Animation jugadorDerecha;
    private Animation jugadorAbajo;
    private Animation jugadorIzquierda;
    private boolean jugadorVivo;
   
    // Estado de los robots
    private Animation[] robot;
    private Animation robotArriba;
    private Animation robotDerecha;
    private Animation robotAbajo;
    private Animation robotIzquierda;
    private float[] robotX, robotY;
    private boolean[] robotVivo;
    private boolean[] robotVisible;
    private float[] robotVelocidad;
    private int numeroRobotsVivos;
    private static final int TOTAL_ROBOTS = 30;
   
    // Escritura de cadenas
    private UnicodeFont fuente;
   
    // Contador de tiempo
    private long tiempo;
   
    // NUEVO: Música y sonidos
    private Music musica;
    private Sound sonido;

    public Robots2D(String name) {
        super(name);
    }

    public static void main(String[] args) {
        System.setProperty("org.lwjgl.librarypath", new File(new File(System.getProperty("user.dir"), "native"), LWJGLUtil.getPlatformName()).getAbsolutePath());
        System.setProperty("net.java.games.input.librarypath", System.getProperty("org.lwjgl.librarypath"));
        try {
            AppGameContainer container = new AppGameContainer(new Robots2D("PMDM06 - Tarea"));
            container.setDisplayMode(640, 480, false);
            container.setTargetFrameRate(60);
            container.setVSync(true);
            container.setShowFPS(false);
            container.setUpdateOnlyWhenVisible(false);
            container.start();
        } catch (SlickException e) {
        }
    }

    @Override
    public void init(GameContainer gc) throws SlickException {
       


        // cargar mapa
        mapa = new TiledMap("data/mapa.tmx", "data");
       
       
        corazon = new Image("data/corazon.png");

        // cargar spritesheets
        cuadros = new SpriteSheet("data/heroe.png", 24, 32);
        cuadrosRobot = new SpriteSheet("data/robot.png", 24, 32);
        explosion = new SpriteSheet("data/explosion.png", 32, 32); // NUEVO

        // cargar animaciones del jugador
        jugadorArriba = new Animation(cuadros, 0, 0, 2, 0, true, 150, false);
        jugadorDerecha = new Animation(cuadros, 0, 1, 2, 1, true, 150, false);
        jugadorAbajo = new Animation(cuadros, 0, 2, 2, 2, true, 150, false);
        jugadorIzquierda = new Animation(cuadros, 0, 3, 2, 3, true, 150, false);
        jugador = jugadorAbajo;

        // cargar animaciones del robot
        robotArriba = new Animation(cuadrosRobot, 0, 0, 2, 0, true, 150, true);
        robotDerecha = new Animation(cuadrosRobot, 0, 1, 2, 1, true, 150, true);
        robotAbajo = new Animation(cuadrosRobot, 0, 2, 2, 2, true, 150, true);
        robotIzquierda = new Animation(cuadrosRobot, 0, 3, 2, 3, true, 150, true);

        // estado inicial del jugador
        jugadorX = 320;
        jugadorY = 240;
        jugadorVivo = true;

        // estado inicial de los robots      
        robot = new Animation[TOTAL_ROBOTS];
        robotX = new float[TOTAL_ROBOTS];
        robotY = new float[TOTAL_ROBOTS];
        robotVivo = new boolean[TOTAL_ROBOTS];
        robotVelocidad = new float[TOTAL_ROBOTS];

        // NUEVO: Un robot puede estar muerto pero visible mientras explota
        robotVisible = new boolean[TOTAL_ROBOTS];

        numeroRobotsVivos = TOTAL_ROBOTS;

        // los colocamos repartidos al azar
        for (int i=0;i<TOTAL_ROBOTS;i++) {
           
            // Cogemos una coordenada X alejada del centro
            float X = (float)((Math.random()*(gc.getWidth()/2-100)));
            // ¿En la izquierda o en la derecha?
            if (Math.random()<0.5f) {
                robotX[i] = X;
                robot[i] = robotDerecha;     // mirar a la derecha
            }
            else {
                robotX[i] = gc.getWidth()-X;
                robot[i] = robotIzquierda;    // mirar a la izquierda
            }
                  
            // Cogemos una coordenada Y alejada del centro teniendo en cuenta
            // que los primeros 64 píxeles no se pueden usar porque está
            // el marcador
            float Y = 64 + (float)((Math.random()*(gc.getHeight()/2-132)));
            // ¿En la parte de arriba o de abajo?
            if (Math.random()<0.5f) {
                robotY[i] = Y;
            }
            else {
                robotY[i] = gc.getHeight()-Y;
            }
          
        }
       
        corazonX = (float)((Math.random()*(gc.getWidth()/2)));
        corazonY = 64 + (float)((Math.random()*(gc.getHeight()/2)));

        // indicamos que, de momento, los robots están vivos
        for (int i = 0; i < TOTAL_ROBOTS; i++) {
            robotVivo[i] = true;
            robotVisible[i] = true;
            // NUEVO: Que algunos empiecen más o menos rápidos
            robotVelocidad[i] = 0.25f + 0.5f * (float) Math.random();
        }

        // cargar tipo de letra de la carpeta data y todos los símboles
        // que podamos necesitar       
        fuente = new UnicodeFont("data/tuffy.ttf", 28, false, false);
        // añade las letras ASCII estándar
        fuente.addAsciiGlyphs();
        // y ahora añadimos los caracteres españoles
        fuente.addGlyphs("áéíóúÁÉÍÓÚñÑ¡¿");
        // en Slick es obligatorio añadir un efecto para poder dibujar
        // texto. Añadimos un efecto vacío.
        fuente.getEffects().add(new ColorEffect(java.awt.Color.WHITE));
        // cargamos los símbolos del tipo de letra
        fuente.loadGlyphs();

        // a partir de ahora, llamado a fuente.drawString(x, y, texto) ¡podremos
        // escribir en el contenedor!

        // NUEVO: Añadimos música de fondo y cargamos los efectos de sonido
        musica = new Music("data/tuturne land!.mod");
        sonido = new Sound("data/8bit_bomb_explosion.wav");
        musica.loop();

        // comenzar cuenta de tiempo. Apuntamos el número que contiene el
        // reloj del sistema en milisegundos. De esta forma, restando esta
        // cantidad a la cuenta actual nos dice el número de milisengudos
        // que han transcurrido.
        tiempo = System.currentTimeMillis();
       
       
               
       
       
    }

    @Override
    public void update(GameContainer gc, int delta) throws SlickException {
        Input entrada = gc.getInput();

        // si se pulsa Esc, salir
        if (entrada.isKeyDown(Input.KEY_ESCAPE)) {    // Tecla ESC
            gc.exit();
        }
       
        // si no quedan robots o ha muerto el jugador, no actualizar nada
        if ((jugadorVivo == false) || (numeroRobotsVivos == 0)) {
            return;
        }

        // movimiento del jugador
        if (entrada.isKeyDown(Input.KEY_DOWN)) {    // Tecla abajo
            jugadorY += delta * 0.1f;
            // evitar que nos salgamos por la parte inferior del contenedor
            if (jugadorY > (gc.getHeight() - jugador.getHeight())) {
                jugadorY = (gc.getHeight() - jugador.getHeight());
            }
            jugador = jugadorAbajo;
            jugador.update(delta);
        }
        if (entrada.isKeyDown(Input.KEY_UP)) {    // Tecla arriba
            jugadorY -= delta * 0.1f;
            // evitar que nos salgamos por la parte superior del contenedor
            if (jugadorY < 32) {
                jugadorY = 32;
            }
            jugador = jugadorArriba;
            jugador.update(delta);
        }
        if (entrada.isKeyDown(Input.KEY_RIGHT)) {    // Tecla derecha
            jugadorX += delta * 0.1f;
            // evitar que nos salgamos por la derecha del contenedor
            if (jugadorX > (gc.getWidth() - jugador.getWidth())) {
                jugadorX = (gc.getWidth() - jugador.getWidth());
            }
            jugador = jugadorDerecha;
            jugador.update(delta);
        }
        if (entrada.isKeyDown(Input.KEY_LEFT)) {    // Tecla izquierda
            jugadorX -= delta * 0.1f;
            // evitar que nos salgamos por la izquierda del contenedor
            if (jugadorX < 0) {
                jugadorX = 0;
            }
            jugador = jugadorIzquierda;
            jugador.update(delta);
        }
       
      

        // NUEVO: Movemos los robots hacia el jugador si están vivos
       
        // cada 50 segundos, el robot se moverá un 50% más rápido
        // respecto a la velocidad inicial
        float prisa = 1.0f + (System.currentTimeMillis() - tiempo) / 50000.0f; // cuanto mayor sea, más rápido irán
        for (int i = 0; i < TOTAL_ROBOTS; i++) {
            if (robotVivo[i]) {
                // calculamos la escala del movimiento, pero la acotaremos
                // para que no sean demasiado rápidos o el jugador nunca
                // podría escapar
                float escalaFinal = prisa * 0.1f * robotVelocidad[i];
                escalaFinal = escalaFinal > 1.15 ? 1.15f : escalaFinal;
                if (robotY[i] > jugadorY) {
                    robotY[i] -= delta * escalaFinal;
                    robot[i] = robotArriba;
                }
                if (robotY[i] < jugadorY) {
                    robotY[i] += delta * escalaFinal;
                    robot[i] = robotAbajo;
                }
                if (robotX[i] > jugadorX) {
                    robotX[i] -= delta * escalaFinal;
                    robot[i] = robotIzquierda;
                }
                if (robotX[i] < jugadorX) {
                    robotX[i] += delta * escalaFinal;
                    robot[i] = robotDerecha;
                }
            } else {
                // si el robot está visible pero su animación se ha parado
                // es que acaba de termina la animación de la explosión,
                // así que lo ocultamos
                if ((robotVisible[i]) && (robot[i].isStopped())) {
                    robotVisible[i] = false;
                }
            }
        }
        // NUEVO: Comprobar si han chocado entre sí o con el jugador
        for (int i = 0; i < TOTAL_ROBOTS; i++) {
            if (robotVivo[i]) {
               
                // ¿Ha chocado el robot 'i' con el jugador?
                // Para nosotros habrán colisionado cuando
                // la parte izquierda de sus bases estén a menos de 4
                // píxeles en vertical y en horizontal
                if ((Math.abs(robotX[i] - jugadorX) < 4.0f)
                        && (Math.abs(robotY[i] - jugadorY) < 4.0f)) {
                   
                    // Sí: robot muerto
                    robotVivo[i] = false;

                    // Hacerlo explotar una sola vez
                    robot[i] = new Animation(explosion, 0, 0, 3, 3, true, 100, true);
                    robot[i].setLooping(false);

                    // Aunque no sirve de mucho, ¡un robot menos!
                    numeroRobotsVivos -= 1;
                   
                    // Reproducir explosión
                    sonido.play();
                   
                    // El jugador ha muerto
                    jugadorVivo = false;
                }
               
                // ¿Ha chocado el robot 'i' con otro robot?
                for (int j = 0; j < TOTAL_ROBOTS; j++) {
                    // Cuidado, hay que evita comprobar si hemos chocado con
                    // nosotros o nada más empezar explotaremos
                    if (i != j && robotVivo[j]) {
                        // Para nosotros habrán colisionado los robots cuando
                        // la parte izquierda de sus bases estén a menos de 4
                        // píxeles en vertical y en horizontal
                        if ((Math.abs(robotX[i] - robotX[j]) < 4.0f)
                                && (Math.abs(robotY[i] - robotY[j]) < 4.0f)) {
                           
                            // Sí: robots muertos
                            robotVivo[i] = false;
                            robotVivo[j] = false;

                            // Crear una nueva explosión y asignársela a los
                            // dos robots ya que explotan simultáneamente
                            robot[i] = new Animation(explosion, 0, 0, 3, 3, true, 100, true);
                            // Que sólo exploten una vez
                            robot[i].setLooping(false);
                            robot[j] = robot[i];

                            // Dos robots menos
                            numeroRobotsVivos -= 2;
                           
                            // Reproducir explosión
                            sonido.play();
                           
                            // Si ya no quedan robots, ¡hemos ganado!
                            if (numeroRobotsVivos == 100) {
                                // Cambiar música
                                musica = new Music("data/bi-menu.xm");
                                musica.loop();
                            }
                            // Esto es para evitar que un robot ya
                            // muerto destruya a otro
                            break;
                        }
                    }
                }
            }
        }
       
       
        if ((Math.abs((jugadorX+jugador.getWidth()) - (corazonX + corazon.getWidth())) < 13.0f)
                                && (Math.abs((jugadorY+jugador.getHeight()) - (corazonY+corazon.getHeight())) < 10.0f)) {
            numeroRobotsVivos=0;
        }
       
    }

    @Override
    public void render(GameContainer gc, Graphics g) throws SlickException {

        // dibujar tilemap
        mapa.render(0, 0);
       
        corazon.draw(corazonX,corazonY);

        // dibujar jugador. NUEVO: sólo si está vivo
        if (jugadorVivo == true) {
            jugador.draw(jugadorX, jugadorY);
        }

        // dibujar robots si están visibles
        for (int i = 0; i < TOTAL_ROBOTS; i++) {
            if (robotVisible[i]) {
                robot[i].draw(robotX[i], robotY[i]);
            }
        }

        // dibujar robots restantes
        fuente.drawString(400, 10, "Quedan " + numeroRobotsVivos + " robots");

        if (jugadorVivo == false) {
            String gameOver = "Fin de juego";
            // dibujamos el texto centrado en el contenedor
            fuente.drawString((gc.getWidth() - fuente.getWidth(gameOver)) / 2, (gc.getHeight() - fuente.getHeight(gameOver)) / 2, gameOver, Color.red);
            return;
        } else {
            if (numeroRobotsVivos == 0) {
                String gameOver = "¡Has ganado!";
                // dibujamos el texto centrado en el contenedor
                fuente.drawString((gc.getWidth() - fuente.getWidth(gameOver)) / 2, (gc.getHeight() - fuente.getHeight(gameOver)) / 2, gameOver, Color.yellow);

                return;
            }
        }

        // dibujar tiempo transcurrido si no ha acabado el juego
        fuente.drawString(40, 10, "Tiempo: " + (System.currentTimeMillis() - tiempo) / 1000);

    }
}

Midlet mensajero

CLASE PRINCIPAL

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package midletMensajero;

// Importo las clases necesarias para trabajar.
import java.io.IOException;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.ImageItem;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.*;
import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;

/**
 * Midlet que permite la gestión de una agenda y el envío de sms's a la misma.
 * @author glop
 */
public class MidletMensajero extends MIDlet implements CommandListener {
   
    Display pantalla; // Pantalla del midlet.
    private Command seleccionar; // Comando con la opción seleccionar del menú principal.
    private Command Mver; // Comando con que lanza el formulario de ver cliente.
    private Command Mnuevo; // Comando con que lanza el formulario de guardar cliente.
    private Command Mmodificar; // Comando con que lanza el formulario de modificar cliente.
    private Command Meliminar; // Comando elimina el cliente seleccionado.
    private Command Mvolver; // Comando que regresa al menú principal.
    private Command cGuardar; // Comando que guarda el cliente.
    private Command cModificar; // Comando que modifica el cliente.
    private Command MmodificarPublicidad; // Modifica la plantilla del mensaje publicitario.
    private Command cVolver; // Comando que regresa al lista de clientes.
    private Command siguiente; // Comando utilizado en la pantalla de presentación que da paso a la pantalla de instrucciones.
    private Command probar; // Comando utilizado en la pantalla de instrucciones que da paso a la pantalla del menú principal.
    private Command adios; // Comando utilizado en la pantalla de créditos que cierra la aplicación.
    private RecordStore almacen; // Almacen de registros de clientes.
    listaClientes listado; // Instancia del objeto listaClientes que hereda de List.
    private List menu; // Lista que forma el menú principal.
    TextField tnombre; // TextField nombre. Utiliza tanto en la adición de clientes como en la modificación.
    TextField ttelefono; // TextField teléfono. Utiliza tanto en la adición de clientes como en la modificación.
    TextBox sms; // TextBox sms. Utilizado en la modificación del mensaje publicitario.
    private RecordEnumeration enumerador; // Enumerador que recorre los registros del RecordStore.
    private Form contenedor; // Formulario con el que se forman las pantallas según la necesidad.
    mensaje smsObj; // Instancia del objeto mensaje que representa un hilo de ejecución.
    String nombreCliente,telefonoCliente,smsTexto; // Variables que almacenan los datos necesarios para envío de mensajes

   
    public MidletMensajero() throws IOException {
       
        pantalla = Display.getDisplay(this); // Se indica que coja nuestra pantalla coja la pantalla principal del midlet.
        smsTexto = "Enhorabuena ***** ha sido agraciado con un premio de 1000 euros";
        presentacion(); // Se llama al método presentación que lanza la pantalla con el mismo nombre.
    }
   
    // Método que lanza la pantalla de presentación.
     public void presentacion() throws IOException {
        contenedor = new Form(""); // Formulario sin título
        contenedor.append("Tarea 3 -- Midlet Mensajero"); // Se añade texto
        Image imag = Image.createImage("imagenes/java.png"); // Se crea una imagen
        ImageItem elemento= new ImageItem ("",  imag, ImageItem.LAYOUT_CENTER, ""); // La imagen se pasa a un ImageItem para
                                                                                    // definir algunos detalles
        contenedor.append(elemento); // Se añade el ImageItem
        contenedor.append("Gabriel López Marcos"); // Se añade texto
        // Se añaden los comandos que tendrá la pantalla
        siguiente = new Command("Siguiente",Command.OK,0);
        contenedor.addCommand(siguiente);
        contenedor.setCommandListener(this); // Se asigna el oyente
        pantalla.setCurrent(contenedor); // La pantalla activa es ésta.
    }
    
     // Método que lanza la pantalla de instrucciones.
     public void instrucciones() {
        contenedor = new Form("Instrucciones");
        contenedor.append("La aplicación consiste en una pequeña agenda de clientes.\n"
                + "- Tienes control completo sobre los clientes, tanto su adición como su modificación\n"
                + "- Es posible enviar mensajes publicitarios a la lista de clientes, siendo posible editar el mensaje enviado");
        probar = new Command("Probar",Command.OK,0);
        contenedor.addCommand(probar);
        contenedor.setCommandListener(this);
        pantalla.setCurrent(contenedor);
    }

     // Lanza un menú principal con las opciones de la aplicación.
    public void menu() {
        menu = new List("Opciones",List.IMPLICIT);
        menu.append("Explorar lista de clientes", null);
        menu.append("Modificar mensaje publicitario", null);
        menu.append("Enviar publicidad a clientes", null);
        menu.append("Salir de la aplicación", null);
        seleccionar = new Command("Seleccionar",Command.OK,0);
        menu.addCommand(seleccionar);
        menu.setCommandListener(this);
        pantalla.setCurrent(menu);
    }
   
    // Se listan todos los clientes y se añaden las opciones que se pueden realizar sobre ellos.
   public void listarClientes() throws RecordStoreException {
      
       listado = new listaClientes("Clientes"); // Se instancia un nuevo objeto de listaClientes.
       listado.listar();
       Mver = new Command("Ver",Command.OK,0);
       Mnuevo = new Command("Nuevo cliente",Command.OK,1);
       Mmodificar = new Command("Editar cliente",Command.OK,1);
       Meliminar = new Command("Borrar cliente",Command.OK,1);
       Mvolver = new Command("Volver",Command.OK,1);
       listado.addCommand(Mnuevo);
       if (listado.size() != 0) {
       listado.addCommand(Mver);
       listado.addCommand(Mmodificar);
       listado.addCommand(Meliminar);
       }
       listado.addCommand(Mvolver);
       listado.setCommandListener(this);
       pantalla.setCurrent(listado);
      
   }
   
    // Método que lanza la pantalla de visualización de cliente. Para ello tenemos que obtener dicho cliente y lo hacemos
    // recurriendo a la tabla hash.
    public void verCliente() {
       // Se almacena el índice seleccionado de la lista. Recordemos que este índice está relacionado con la tabla hash
       // paralela de registros y que ésta contiene los clientes y podremos trabajar con sus datos.
       int idSeleccionado = listado.getSelectedIndex();
       // Se pasa el idSeleecionado al almacén paralelo de clientes para que nos devuelve el cliente asociado.
       // Guardamos lo obtenido en un objeto con el que trabajaremos.
       Object chash = listado.almacen_hash.get(String.valueOf(idSeleccionado));
       String cliente; // Variable donde se almacena la parte de los datos, sin el índice, del cliente almacenado en el objeto.
       String nombre; // Variable donde se almacena el nombre del cliente a editar.
       String telefono; // Variable donde se almacena el teléfono del cliente a editar.
       int separador = chash.toString().indexOf("|"); // Se almacena la posición del primer separador.
       // Se almacena en un string el cliente. Recordemos que en la tabla hash paralela al RecordStore, almacenamos los
       // clientes con su id para poder trabajar con este datos. Es por ello que tengo que acceder sin ese dato.
       // En la tabla hash se almacena así : id|nombre|teléfono
       cliente = chash.toString().substring(separador+1);
       separador = cliente.indexOf("|"); // Obtengo la posición del separador en la parte de los datos del cliente.
       // Almaceno el nombre. Lo obtengo con substring desde la posición 0 de la variable cliente, hasta el próximo separador.
       nombre = cliente.substring(0,separador);
       telefono = cliente.substring(separador+1); // El teléfono lo obtengo con substring desde el separador hasta el final.
      
       // Ahora puedo construir el formulario.
       contenedor = new Form("Detalle de cliente");
       contenedor.append("Nombre :");
       contenedor.append(nombre);
       contenedor.append("Teléfono : ");
       contenedor.append(telefono);
       cVolver = new Command("Volver",Command.BACK,0);
       contenedor.addCommand(cVolver);
       contenedor.setCommandListener(this);
       pantalla.setCurrent(contenedor);
   }
   
       // Método que lanza una pantalla con un formulario que contiene dos textfields para introducir un nuevo cliente.
   public void nuevoCliente() throws RecordStoreException {
       contenedor = new Form("Nuevo Cliente");
       // Se añade el TextField nombre con 25 caracteres de capacidad. Se pueden introducir todo tipo de caracteres.
       tnombre= new TextField ("Nombre: ", null, 25, TextField.ANY);
       // Se añade el TextField teléfono con 25 caracteres de capacidad. Se pueden introducir únicamente números.
       ttelefono= new TextField ("Teléfono: ", null, 25, TextField.PHONENUMBER);
       contenedor.append(tnombre);
       contenedor.append(ttelefono);
       cVolver = new Command("Volver",Command.BACK,0);
       cGuardar = new Command("Guardar",Command.BACK,1);
       contenedor.addCommand(cVolver);
       contenedor.addCommand(cGuardar);
       contenedor.setCommandListener(this);
       pantalla.setCurrent(contenedor);
   }
  
  
   // Método que lanza un formulario con los datos de clientes para editar. Es necesario rellenar dichos datos
   // accediendo a la tabla hash asociado e introducirlos en el formulario.
   public void modificarCliente() throws RecordStoreException {
      
       // Se almacena el índice seleccionado de la lista. Recordemos que este índice está relacionado con la tabla hash
       // paralela de registros y que ésta contiene los clientes y podremos trabajar con sus datos.
       int idSeleccionado = listado.getSelectedIndex();
       // Se pasa el idSeleecionado al almacén paralelo de clientes para que nos devuelve el cliente asociado.
       // Guardamos lo obtenido en un objeto con el que trabajaremos.
       Object chash = listado.almacen_hash.get(String.valueOf(idSeleccionado));
       String cliente; // Variable donde se almacena la parte de los datos, sin el índice, del cliente almacenado en el objeto.
       String nombre; // Variable donde se almacena el nombre del cliente a editar.
       String telefono; // Variable donde se almacena el teléfono del cliente a editar.
       int separador = chash.toString().indexOf("|"); // Se almacena la posición del primer separador.
       // Se almacena en un string el cliente. Recordemos que en la tabla hash paralela al RecordStore, almacenamos los
       // clientes con su id para poder trabajar con este datos. Es por ello que tengo que acceder sin ese dato.
       // En la tabla hash se almacena así : id|nombre|teléfono
       cliente = chash.toString().substring(separador+1);
       separador = cliente.indexOf("|"); // Obtengo la posición del separador en la parte de los datos del cliente.
       // Almaceno el nombre. Lo obtengo con substring desde la posición 0 de la variable cliente, hasta el próximo separador.
       nombre = cliente.substring(0,separador);
       telefono = cliente.substring(separador+1); // El teléfono lo obtengo con substring desde el separador hasta el final.
      
       // Ahora puedo construir el formulario.
       contenedor = new Form("Editar cliente");
       tnombre= new TextField ("Nombre: ", nombre, 25, TextField.ANY);
       ttelefono= new TextField ("Teléfono: ", telefono, 25, TextField.PHONENUMBER);
       contenedor.append(tnombre);
       contenedor.append(ttelefono);
       cVolver = new Command("Volver",Command.BACK,0);
       cModificar = new Command("Modificar",Command.BACK,1);
       contenedor.addCommand(cVolver);
       contenedor.addCommand(cModificar);
       contenedor.setCommandListener(this);
       pantalla.setCurrent(contenedor);
      
   }
  
   
    public void startApp() {
        pantalla.setCurrent(contenedor);
    }
   
    public void pauseApp() {
    }
   
    public void destroyApp(boolean unconditional) {
    }

    // Control de comandos.
    public void commandAction(Command c, Displayable d) {
       
        try {
           
            if (c == siguiente) {
            instrucciones();
            }
            if (c == probar) {
            menu();
            }
            if (c == Mnuevo) {
            nuevoCliente();
            }
           
        if (c == seleccionar) {
            int opcion = menu.getSelectedIndex();
            switch(opcion) {
                case 0:
                  listarClientes();
                    break;
                case 1:
                    editarMensaje();
                    break;
                case 2:
                    if (listado.almacen_hash.size()!=0) {
                    envioPublicidad();
                }
                       
                    break;
                case 3:
                    creditos();
            }
        }
        if (c == adios) {
        destroyApp (true);
        notifyDestroyed ();
                    }
       
        if (c == Mmodificar) {
            modificarCliente();
        }
        if (c == Mver) {
            verCliente();
        }
        if (c == cGuardar) {

            if (!"".equals(tnombre.getString()) && !"".equals(ttelefono.getString())) {
            listado.guardar(tnombre, ttelefono);
            listarClientes();
            }
           
        }
        if (c == cModificar) {
            if (!"".equals(tnombre.getString()) && !"".equals(ttelefono.getString())) {
            listado.modificar(tnombre, ttelefono);
            listarClientes();
            }
        }
        if (c == Meliminar) {
            listado.eliminar();
            listarClientes();
        }
        if (c == Mvolver) {
            pantalla.setCurrent(menu);
        }
        if (c == cVolver) {
            pantalla.setCurrent(listado);
        }
        if (c == MmodificarPublicidad) {
            smsTexto = sms.getString();
            pantalla.setCurrent(menu);
        }
       
       
        } catch (Exception ex) {
           
        }
    }
   
   
  // Método que lanza la pantalla de edición del mensaje publicitario.
   public void editarMensaje() {
       // La pantalla la forma un TextBox con el texto del mensaje listo para ser editado.
       sms = new TextBox("",smsTexto,255,TextField.ANY);
       MmodificarPublicidad = new Command("Modificar",Command.OK,0);
       Mvolver = new Command("Volver",Command.BACK,1);
       sms.addCommand(MmodificarPublicidad);
       sms.addCommand(Mvolver);
       sms.setCommandListener(this);
       pantalla.setCurrent(sms);
   }
  
   // Método que permite el envío de los mensajes a la lista.
   // En el RecordStore los datos se guardan así: nombre|teléfono
   public void envioPublicidad() throws RecordStoreException {
      
       try {
           almacen = RecordStore.openRecordStore("clientes", true); // Abrimos el almacén de registros.
           enumerador = almacen.enumerateRecords(null, null, true); // Se los pasamos al enumerador.
           while(enumerador.hasNextElement()) { // Mientras haya elementos ...
               byte[] b = enumerador.nextRecord(); // Pasamos el registros a un array de bytes para trabajar con los datos.
               String cliente = new String(b); // Convertimos el array a string.
               int separador = cliente.toString().indexOf("|"); // Obtenemos la posición del separador.
               nombreCliente = cliente.toString().substring(0,separador); // Obtenemos el nombre del cliente.
               telefonoCliente = cliente.toString().substring(separador+1); // Obtenemos el teléfono del cliente.
               // Nueva instancia de mensajes con los datos de los clientes y el texto publicitario.
               // Iniciaremos tantos hilos como clientes existan en el almacén. Los hilos trabajarán sincronizados.
               smsObj = new mensaje(nombreCliente,telefonoCliente,smsTexto);
               smsObj.start(); // Se inicia el hilo
           }
           resultadoEnvios(); // Al término de las operaciones, se lanza la pantalla de resultados para informar.
       } catch (Exception ex) {
          
       } finally { // Al finalizar ...
          if (enumerador!=null) {
              enumerador.destroy(); // Cerramos el enumerador.
          }
          if (almacen!=null) {
              almacen.closeRecordStore(); // Cerramos el RecordStore.
          }
       }
      
   }
  
   // Método que lanza una pantalla de resultados de operaciones.
   public void resultadoEnvios() {
       Alert alerta = new Alert("Resultado de los envíos");
       alerta.setString("El envío de mensajes ha finalizado ... \n"
               + "Se han enviado un total de : " + listado.size() + " mensajes");
       Mvolver = new Command("Volver",Command.BACK,0);
       alerta.addCommand(Mvolver);
       alerta.setCommandListener(this);
       pantalla.setCurrent(alerta);
   }
  
 
      // Método que lanza una pantalla de créditos.
       public void creditos() {
        contenedor = new Form ("Créditos");
        contenedor.append("Tarea realizada por:\n"
                + "Gabriel López Marcos\n"
                + "para DAM\n"
                + "10/Agosto/2013");
        adios = new Command("Adiós",Command.OK,0);
        contenedor.addCommand(adios);
        contenedor.setCommandListener(this);
        pantalla.setCurrent(contenedor);
    }
      
}

CLASE LISTA DE CLIENTES

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package midletMensajero;

// Importo las clases necesarias para trabajar.
import java.util.Hashtable;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.TextField;
import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;

/**
 * Clase donde se efectúan las acciones sobre la lista de clientes. Hereda de List.
 * @author glop
 */
public class listaClientes extends List {
   
    RecordStore almacen; // Almacén de registros.
    RecordEnumeration enumerador; // Enumerador de registros. Utilizado para recorrer el RecordStore.
    Hashtable almacen_hash; // Tabla hash que guarda una lista paralela de clientes.
   
    // Construímos el objeto listaClientes que hereda de List.
    public listaClientes(String nombre) {
        super(nombre,List.IMPLICIT); // Se construye una lista de tipo implícito.
        almacen_hash = new Hashtable(); // Se construye una tabla hash como almacen paralelo de clientes.
    }
   
    // Lista todos los clientes y los pasa a una tabla hash paralela para trabajar con los datos.
    public void listar() throws RecordStoreException {
        super.deleteAll(); // Cada vez que se llama a este método, se limpian los resultados de la lista.
        try {
        almacen = RecordStore.openRecordStore("clientes", true); // Se crea un almacén de registros o se abre si ya existía.
        enumerador = null;
        enumerador = almacen.enumerateRecords(null, null, true); // Se pasa al enumerador la lista de clientes.
       
        while(enumerador.hasNextElement()) { // Se recorre la lista de clientes.
            int indice = enumerador.nextRecordId(); // Se almacena el id de cliente.
            byte[] cl = almacen.getRecord(indice); // Se pasa el cliente a un array de bytes.
            String cliente = new String(cl); // El cliente se almacena en una variable String.
            int separador = cliente.indexOf("|"); // Posición del separador: nombre|teléfono.
            String nombre = cliente.substring(0,separador); // Se almacena el nombre del cliente.
            String telefono = cliente.substring(separador + 1); // Se almacena el teléfono del cliente.
            super.append(nombre + " " + telefono, null); // Se añade el cliente completo a la lista.
            // Se almacena el número de registros que tiene la tabla hash. Se almacena como String para poderlo utilizar
            // para añadir un nuevo registro a la tabla hash que solo admite objetos como keys.
            String nregistros = String.valueOf(almacen_hash.size());
            // Se añade un nuevo registros a la tabla hash. Se asocia la posición que ocupa en la lista como key, con
            // el cliente completo incluido el índice. Así es fácil de trabajar con sus datos.
            almacen_hash.put(nregistros, indice + "|" + nombre + "|" + telefono);
        }
        } catch (Exception ex) {
            System.out.println("Se ha producido un error al listar los clientes :" + ex);
        } finally {
            if (enumerador!=null) {
            enumerador.destroy();} // Se cierra el enumerador.
            if  (almacen!=null) {
            almacen.closeRecordStore();} // Se cierra el almacen.
        }
       
    }
   
    // Método que guarda un nuevo registro en el RecordStore. Cuando acabe, se actualizará la lista y se añadirá
    // el registro a la tabla hash.
    // Se le pasan por parámetros los textfields de la pantalla de añadir clientes.
    public void guardar(TextField nombre, TextField telefono) throws RecordStoreException {
       
        try {
            almacen = RecordStore.openRecordStore("clientes", true);
            // Se almacena el cliente en una variable String con el formato adecuado.
            String cliente = nombre.getString() + "|" + telefono.getString();
            byte[] cl = cliente.getBytes(); // Se pasa el cliente a un array de bytes.
            almacen.addRecord(cl, 0, cl.length); // Se guarda el cliente en el RecordStore.
        } catch (Exception ex) {
            System.out.println("Ha ocurrido un error al intentar guardar un registro : " + ex);
        } finally {
            almacen.closeRecordStore(); // Se cierra el RecordStore.
        }
    }
   
    // Se modifica un cliente con los valores de los textfields que se le pasan por parámetros.
    // Cuando acabe, se actualizará la tabla hash asociada.
    public void modificar(TextField nombre, TextField telefono) throws RecordStoreException {
       
        try {
            int idSeleccionado = super.getSelectedIndex(); // Se almacena el índice de la lista seleccionado.
            almacen = RecordStore.openRecordStore("clientes", true); // Se abre el RecordStore.
            // Se obtiene el cliente de tabla hash paralela pasándole por parámetro el índice seleccionado.
            // Lo almacenamos en un objeto
            Object chash = almacen_hash.get(String.valueOf(idSeleccionado));
            // Se obtiene la posición del separador. En el cliente se almacena así: nombre|teléfono
            // en la tabla hash, sin embargo, se almacena así: id|nombre|teléfono
            // Se almacena así para trabajar con los datos de cliente y poder acceder a sus índices dentro del RecordStore.
            int separador = chash.toString().indexOf("|");
            String indice = chash.toString().substring(0,separador); // Se obtiene el índice del cliente.
            int indiceCliente = Integer.parseInt(indice); // Valor númerico del índice de cliente.
            // Se almacena en un String el cliente modificado con los datos recogidos por parámetros.
            String clienteModificado = nombre.getString() + "|" + telefono.getString();
            // Se pasa el cliente modificado a un array de bytes. El único formato adecuado para guardar datos en RecordStore.
            byte[] cl = clienteModificado.getBytes();
            almacen.setRecord(indiceCliente, cl, 0, cl.length);
           
        } catch (Exception ex) {
            System.out.println("Ha ocurrido u error al intentar modificar el registro : " + ex);
        } finally {
            almacen.closeRecordStore(); // Se cierra el RecordStore.
        }
    }
   
    public void eliminar() throws RecordStoreException {
       
        try {
            int idSeleccionado = super.getSelectedIndex(); // Se almacena el índice de la lista seleccionado.
            almacen = RecordStore.openRecordStore("clientes", true); // Se abre el RecordStore.
            // Se obtiene el cliente de tabla hash paralela pasándole por parámetro el índice seleccionado.
            // Lo almacenamos en un objeto
            Object chash = almacen_hash.get(String.valueOf(idSeleccionado));
            // Se obtiene la posición del separador. En el cliente se almacena así: nombre|teléfono
            // en la tabla hash, sin embargo, se almacena así: id|nombre|teléfono
            // Se almacena así para trabajar con los datos de cliente y poder acceder a sus índices dentro del RecordStore.
            int separador = chash.toString().indexOf("|");
            String indice = chash.toString().substring(0,separador); // Se obtiene el índice del cliente.
            int indiceCliente = Integer.parseInt(indice); // Valor númerico del índice de cliente.
            almacen.deleteRecord(indiceCliente); // Se elimina por índice de cliente.
        } catch (Exception ex) {
            System.out.println("Se ha producido un error al intentar eliminar el cliente : " + ex);
        } finally {
            almacen.closeRecordStore(); // Se cierra el RecordStore.
        }
    }
  
}


CLASE HILO MENSAJES

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package midletMensajero;

// Importo las clases necesarias para trabajar.
import java.io.IOException;
import javax.microedition.io.Connector;
import javax.wireless.messaging.MessageConnection;
import javax.wireless.messaging.TextMessage;

/**
 * Clase que controla los envíos de sms. Hereda de Thread.
 * @author glop
 */
public class mensaje extends Thread {
   
    int ocupado=0; // Variable que indice si el hilo está ocupado. 0 libre, 1 ocupado.
    String nombre; // Variable que almacena el nombre del destinatarios.
    String telefono; // Variable que almacena el teléfono del destinatario.
    String texto; // Variable que almacena el texto del mensaje.
    MessageConnection conexion; // Variable que establece la conexión.
    TextMessage mensaje; // Variable que implementa el mensaje.
   
    public mensaje(String nomb,String tlf,String text) { // Se contruye el objeto con los datos
        this.nombre=nomb;
        this.telefono=tlf;
        this.texto = text;
    }
   
    // Método sincronizado que permite el envío de mensajes.
    public synchronized void enviar() throws IOException {
       
        try {
           
        // Si el hilo está ocupado, espera. De este modo nunca se produce un bloque en la aplicación.
        while(ocupado==1) {
                wait();
        }
       
        ocupado=1; // Indicamos que un hilo está ocupado enviando el mensaje.
        conexion= (MessageConnection) Connector.open("sms://+34"+this.telefono); // Establecemos la conexión.
        mensaje= (TextMessage) conexion.newMessage(MessageConnection.TEXT_MESSAGE); // Creamos el mensaje.
       
        String textoMensaje = this.texto; // Se almacena el mensaje en una variable para trabajar con su texto.
        // En esta estructura controlamos que el mensaje tenga asteriscos (caracteres que utilizamos para referirnos a
        // los clientes) si los hay, los cambiamos por el nombre del cliente; Si no los hay, el mensaje queda tal cual.
        if (textoMensaje.indexOf("*")!=-1) {
        char caracter='*'; // Caracter que buscamos.
        int primera=0;
        String aux1 = textoMensaje.substring(0,textoMensaje.lastIndexOf(caracter)); // Parte del mensaje hasta los asteriscos.
        primera = aux1.indexOf("*"); // Primera asterisco.
        aux1 = aux1.substring(0, primera); // Cogemos sólo la parte donde no hay asteriscos.
        String aux2 = textoMensaje.substring(textoMensaje.lastIndexOf(caracter)+1); // La segunda parte del mensaje.
        aux1 +=this.nombre; // Añadimos el nombre a la primera parte.
        textoMensaje = aux1 + aux2;  // Formamos el mensaje completo. 
        }
        mensaje.setPayloadText(textoMensaje); // Añadimos el texto del mensaje.
        conexion.send(mensaje); // Enviamos el mensaje
        } catch (Exception ex) {
  
        } finally { // Ejecutamos aquí las últimas acciones.
        ocupado=0; // Indicamos que hemos acabado.
        notify(); // Lo notificamos a los demás hilos.
        conexion.close(); // Cerramos la conexión.        
        }
       
    }
   
    // Método que se ejecuta en el hilo al iniciarlo.
    public void run() {
        try {
            enviar(); // Llamamos al método enviar.
        } catch (IOException ex) {
           
        }
    }
}