martes, 27 de noviembre de 2012

Hangman Android (II)

Esta es la continuación de la entrada anterior y en ella voy a completar el código de la aplicación Ahorcado. Se puede decir que aquí mostraré la parte fundamental del juego. En primer lugar, se puede ver el código que hay detrás de la actividad Game que es la que define y controla la evolución del juego.

package not.ebacelo.android;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

public class GameActivity extends Activity {
    private enum Estados {
        INICIAL, CABEZA, TRONCO, BRAZO_IZDO, BRAZO_DCHO, PIERNA_IZDA, PIERNA_DCHA, FINAL
    };

    LinearLayout llGame31, llGame2;
    Button btnNuevo;
    TextView tvMensaje, tvSolucion;
    CheckBox chkMostrarSolucion;
    Estados estado;
    String palabraGenerada = "";
    int errores, aciertos = 0, letrasCoinciden = 0;
    String idioma;
    int dificultad;
    int puntuacion;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Bundle infoExtra;

        super.onCreate(savedInstanceState);
        setContentView(R.layout.game);
       
        //Inicializamos el estado del juego
        estado = Estados.INICIAL;
        errores = 0;

        // Obtenemos los valores establecidos en la configuración (enviados
        // desde HangmanActivity)
        infoExtra = getIntent().getExtras();
        idioma = infoExtra.getString("IDIOMA");
        dificultad = infoExtra.getInt("DIFICULTAD");
       
        //Colocamos el botón con la bandera correspondiente al idioma seleccionado en la configuración
        ImageButton ibFlag = (ImageButton)findViewById(R.id.ibFlag);
        if (idioma.compareTo("ES") == 0)
            ibFlag.setBackgroundResource(R.drawable.spain);
        if (idioma.compareTo("EN") == 0)
            ibFlag.setBackgroundResource(R.drawable.uk);
           
        // Obtenemos referencias a los controles del layout
        llGame2 = (LinearLayout) findViewById(R.id.llGame2);
        llGame31 = (LinearLayout) findViewById(R.id.llGame31);

        // Creamos un control View personalizado dónde se dibujarán los gráficos
        Lienzo fondo = new Lienzo(this);

        // Añadimos el nuevo control a su localización
        llGame31.addView(fondo);
        tvMensaje = (TextView) findViewById(R.id.tvMensaje);
        tvSolucion = (TextView) findViewById(R.id.tvSolucion);
        chkMostrarSolucion = (CheckBox) findViewById(R.id.chkMostrarSolucion);
        chkMostrarSolucion
                .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

                    public void onCheckedChanged(CompoundButton buttonView,
                            boolean isChecked) {
                        // TODO Auto-generated method stub
                        if (isChecked) {
                            tvSolucion.setVisibility(View.VISIBLE);
                        } else {
                            tvSolucion.setVisibility(View.INVISIBLE);
                        }
                    }
                });

        // Botón "Nuevo" juego
        btnNuevo = (Button) findViewById(R.id.btnNuevo);
        btnNuevo.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
               
                Log.d("DEPURANDO .....  ", "Inicializando juego");
                inicializarGrafico(llGame31);
                mostrarMensaje("");
                limpiarSolucion();
                aciertos = 0;
                errores = 0;
                puntuacion = 0;
                inicializarBotonesLetras();
                palabraGenerada = generarPalabra();
                mostrarPalabra(palabraGenerada);
                Log.d("DEPURANDO .....", "Juego inicializado");
               
            }
        });

        // Inicializamos el juego
        Log.d("DEPURANDO ..... ", "Primera inicialización del juego");
        inicializarGrafico(llGame31); // también inicializa el estado
        mostrarMensaje("");
        limpiarSolucion();
        puntuacion = 0;
        palabraGenerada = generarPalabra();
        mostrarPalabra(palabraGenerada);
        Log.d("DEPURANDO ..... ", "Juego inicializado por primera vez");

        // Asignamos el manejador de eventos a los botones correspondientes a
        // cada una de las letras del abecedario
        TableLayout tlBotonesLetras = (TableLayout) findViewById(R.id.tlBotonesLetras);
        for (int i = 0; i < tlBotonesLetras.getChildCount(); i++) {
            TableRow tr = (TableRow) tlBotonesLetras.getChildAt(i);
           
            for (int j = 0; j < tr.getChildCount(); j++) {
                if (tr.getChildAt(j).getTag() == null) {
                    Button btn = (Button) tr.getChildAt(j);
                    btn.setOnClickListener(btnLetraListener);
                }
            }
        }
    }

    // Método que modifica la apariencia del botón que se le pasa como
    // parámetro. Se
    // utiliza cuando un botón correspondiente al abecedario se pulsa para
    // indicar que
    // ya ha sido pulsado
    private void modificarBotonLetra(Button btn) {
        if (btn.getBackground() == getResources().getDrawable(
                android.R.drawable.btn_default))
            btn.setBackgroundResource(R.color.buttons_error_bg_color);
        else
            btn.setBackgroundResource(android.R.drawable.btn_default);
    }

    // Manejador de eventos de de los botones correspondientes al abecedario
    private OnClickListener btnLetraListener = new OnClickListener() {
        public void onClick(View v) {
            Button btn = (Button) v;
            // Realizamos las tareas correspondientes a la pulsación de una
            // letra
            // Toast t = Toast.makeText(v.getContext(), "La letra pulsada es: "
            // + ((Button) v).getText().toString(), Toast.LENGTH_LONG);
            // t.show();

            if ((estado != Estados.FINAL)
                    && (aciertos != palabraGenerada.length())) {
                btn.setEnabled(false);
                modificarBotonLetra(btn);
                // Comprobar si la letra está contenida en la palabra generada
                if ((letrasCoinciden = comprobarLetra(btn.getText().toString())) > 0) {
                    modificarBotonLetra(btn);
                    aciertos = aciertos + letrasCoinciden;
                    //1 pto más por cada letra acertada
                    puntuacion += letrasCoinciden;
                    if (aciertos == palabraGenerada.length()) {
                        // El juego ha finalizado (El jugador ha ganado!)
                        mostrarMensaje("HA GANADO!");
                        //Calculamos la puntuación
                        //10 ptos por completar la palabra
                        puntuacion += 10;
                        //Si no hay fallos 10 ptos extra
                        if (errores == 0)
                            puntuacion += 10;
                        else if (errores <3)
                            puntuacion += 4;   //4ptos extra si hay 2 o menos fallos
                       
                        Toast t = Toast.makeText(v.getContext(),
                                "Juego finalizado. HA GANADO!!!  Puntuación: " + puntuacion + "errores: " + errores,
                                Toast.LENGTH_LONG);
                        t.show();
                    }
                } else {
                    incrementarEstado();
                    actualizarGrafico(llGame31);
                    if (estado == Estados.FINAL) {
                        // Se acabo el juego (El jugador perdió)
                        mostrarMensaje("HA PERDIDO!");
                        Toast t = Toast.makeText(v.getContext(),
                                "Juego finalizado. HA PERDIDO!  Puntuación: " + puntuacion,
                                Toast.LENGTH_SHORT);
                        t.show();
                    }

                }

            } else {
                // Se acabo el juego (Recordamos al jugador que ha perdido, si
                // es el caso)
                if (estado == Estados.FINAL) {
                    Toast t = Toast.makeText(v.getContext(),
                            "Juego ha finalizado. HA PERDIDO!",
                            Toast.LENGTH_SHORT);
                    t.show();
                }
            }
        }
    };

    protected Estados incrementarEstado() {
        switch (estado) {
        case INICIAL:
            return Estados.CABEZA;
        case CABEZA:
            return Estados.TRONCO;
        case TRONCO:
            return Estados.BRAZO_IZDO;
        case BRAZO_IZDO:
            return Estados.BRAZO_DCHO;
        case BRAZO_DCHO:
            return Estados.PIERNA_IZDA;
        case PIERNA_IZDA:
            return Estados.PIERNA_DCHA;
        case PIERNA_DCHA:
            return Estados.FINAL;
        default:
            return Estados.FINAL;
        }
    }

    // Este método se ocupa de comprobar si una letra es parte de la palabra
    // generada y, en caso
    // afirmativo, la muestra en la posición correspondiente.
    private int comprobarLetra(String letra) {
        TextView tvLetra;
        int coincidencias = 0;

        for (int i = 0; i < palabraGenerada.length(); i++) {
            if (letra.compareTo(String.valueOf(palabraGenerada.charAt(i))) == 0) {
                tvLetra = (TextView) llGame2.getChildAt(i);
                tvLetra.setTextColor(getResources().getColor(
                        R.color.tvLetras_color2));
                tvLetra.setText(letra);
                coincidencias++;
            }
        }
        if (coincidencias == 0) {
            errores++;
            estado = incrementarEstado();
        }

        return coincidencias;
    }

    // Creamos un control TextView por cada una de las letras de la palabra
    // generada, que el
    // jugador tendrá que adivinar y establecemos las propiedades que nos
    // interesan. Después se
    // añaden estos controles al layout que los contiene.
    private void mostrarPalabra(String palabra) {

        limpiarPalabra();
        // Por cada letra de la palabra añadimos un textView cuyo contenido
        // inicial será el carácter '_'.
        for (int i = 0; i < palabra.length(); i++) {
            TextView tvLetra = new TextView(this);
            tvLetra.setText("_"); // String.valueOf(palabra.charAt(i)));
            tvLetra.setId(i);
            tvLetra.setTextSize(28);
            tvLetra.setGravity(Gravity.CENTER);
            tvLetra.setPadding(3, 3, 3, 3);
            tvLetra.setWidth(28);
            // También la añadimos al TextView que contiene la solución (para
            // que se pueda
            // visualizar si así se desea.
            tvSolucion.setText(palabra);
            tvSolucion.setVisibility(View.INVISIBLE);

            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT);
            lp.setMargins(3, 0, 0, 0);
            llGame2.addView(tvLetra, lp);
        }
    }

    // Eliminamos los views dentro del layout correspondiente a la palabra a
    // adivinar
    private void limpiarPalabra() {
        llGame2.removeAllViews();
    }

    // Obtenemos aleatoriamente una palabra de la lista disponible (caso básico
    // de prueba:
    // array de palabras reducido)
    private String generarPalabra() {
        List<String> listaPalabras = new ArrayList<String>();
        // String[] listaPalabras = { "palabra", "elefante", "apadrinados" };

        if (idioma.compareTo("ES") == 0)
            listaPalabras = obtenerListaPalabras("listaPalabras.txt");
        if (idioma.compareTo("EN") == 0)
            listaPalabras = obtenerListaPalabras("wordList.txt");

        Random rnd = new Random();
        int indice = rnd.nextInt(listaPalabras.size());
        return listaPalabras.get(indice);
    }

    private List<String> obtenerListaPalabras(String fichero) {
        List<String> listaPalabras = new ArrayList<String>();
        InputStream in;
        BufferedReader reader;
        String linea;
        AssetManager assetManager = getAssets();

        try {
            in = assetManager.open(fichero);
            reader = new BufferedReader(new InputStreamReader(in));

            while ((linea = reader.readLine()) != null) {
                if ((linea.length() > 5) && (linea.length() < 11)) {
                    listaPalabras.add(linea);
                }
            }
        } catch (IOException e) {
            return null;
        }

        return listaPalabras;
    }

    // Inicializamos el estado del juego y repintamos el control View donde se
    // dibuja el ahorcado.
    // En el estado inicial sólo se dibuja la estructura de la horca.
    private void inicializarGrafico(View v) {
        estado = Estados.INICIAL;
        v.invalidate();
    }

    private void actualizarGrafico(View v) {
        v.invalidate();
    }

    private void inicializarBotonesLetras() {
        TableLayout tlBotonesLetras = (TableLayout) findViewById(R.id.tlBotonesLetras);
        for (int i = 0; i < tlBotonesLetras.getChildCount(); i++) {
            TableRow tr = (TableRow) tlBotonesLetras.getChildAt(i);
            for (int j = 0; j < tr.getChildCount(); j++) {
                if (tr.getChildAt(j).getTag() == null) {
                    Button btn = (Button) tr.getChildAt(j);
                    btn.setBackgroundResource(android.R.drawable.btn_default);
                    btn.setEnabled(true);
                }
            }
        }

    }

    private void mostrarMensaje(String mensaje) {
        tvMensaje.setText(mensaje);
    }

    // Deseleccionamos la casilla de activación de la visualización de la
    // respuesta correcta y ocultamos
    // la palabra generada
    private void limpiarSolucion() {
        chkMostrarSolucion.setChecked(false);
        tvSolucion.setText("");
    }

    // Clase interna que permite definir un control View en el que vamos a
    // contener los gráficos
    // correspondientes a la horca y al ahorcado
    class Lienzo extends View {

        public Lienzo(Context context) {
            super(context);
        }

        // Método que se ejecuta cada vez que se redibuja este control View.
        // Dependiendo del estado
        // en el que se encuentre el juego se dibujan distintas partes en el
        // objeto.
        protected void onDraw(Canvas canvas) {

            // Dibujamos sólo la estructura de la horca
            if (estado == Estados.INICIAL) {
                canvas.drawRGB(240, 240, 240);
                Paint pen = new Paint();
                pen.setStrokeWidth(8);
                pen.setARGB(255, 10, 10, 10);
                // Dibujamos la base de la horca
                canvas.drawLine(20, 220, 110, 220, pen);
                pen.setStrokeWidth(5);
                // Dibujamos la estructura de la horca
                canvas.drawLine(90, 220, 90, 60, pen);
                canvas.drawLine(90, 62, 50, 62, pen);
                canvas.drawLine(52, 62, 52, 82, pen);
            }

            // Dibujamos hasta la cabeza del ahorcado
            if (estado == Estados.CABEZA) {
                canvas.drawRGB(240, 240, 240);
                Paint pen = new Paint();
                pen.setStrokeWidth(8);
                pen.setARGB(255, 10, 10, 10);
                // Dibujamos la base de la horca
                canvas.drawLine(20, 220, 110, 220, pen);
                pen.setStrokeWidth(5);
                // Dibujamos la estructura de la horca
                canvas.drawLine(90, 220, 90, 60, pen);
                canvas.drawLine(90, 62, 50, 62, pen);
                canvas.drawLine(52, 62, 52, 82, pen);
                Paint pen2 = new Paint();
                pen2.setARGB(255, 85, 85, 85);
                pen2.setStrokeWidth(3);
                // Dibujamos la cabeza (con ojos, nariz y boca)
                canvas.drawCircle(52, 102, 20, pen2);
                canvas.drawCircle(43, 97, 2, pen); // ojo izdo
                canvas.drawCircle(61, 97, 2, pen); // ojo dcho
                Paint penB = new Paint();
                penB.setARGB(255, 10, 10, 10);
                penB.setStrokeWidth(3);
                canvas.drawLine(52, 100, 52, 105, penB);
                // Boca
                canvas.drawLine(45, 110, 59, 110, penB);
            }

            // Dibujamos el ahorcado hasta el tronco
            if (estado == Estados.TRONCO) {
                canvas.drawRGB(240, 240, 240);
                Paint pen = new Paint();
                pen.setStrokeWidth(8);
                pen.setARGB(255, 10, 10, 10);
                // Dibujamos la base de la horca
                canvas.drawLine(20, 220, 110, 220, pen);
                pen.setStrokeWidth(5);
                // Dibujamos la estructura de la horca
                canvas.drawLine(90, 220, 90, 60, pen);
                canvas.drawLine(90, 62, 50, 62, pen);
                canvas.drawLine(52, 62, 52, 82, pen);
                Paint pen2 = new Paint();
                pen2.setARGB(255, 85, 85, 85);
                pen2.setStrokeWidth(3);
                // Dibujamos la cabeza (con ojos, nariz y boca)
                canvas.drawCircle(52, 102, 20, pen2);
                canvas.drawCircle(43, 97, 2, pen); // ojo izdo
                canvas.drawCircle(61, 97, 2, pen); // ojo dcho
                Paint penB = new Paint();
                penB.setARGB(255, 10, 10, 10);
                penB.setStrokeWidth(3);
                canvas.drawLine(52, 100, 52, 105, penB);
                // Boca
                canvas.drawLine(45, 110, 59, 110, penB);
                // Dibujamos el tronco
                canvas.drawLine(52, 122, 52, 172, pen2);
            }

            // Dibujamos el ahorcado hasta el brazo izquierdo
            if (estado == Estados.BRAZO_IZDO) {
                canvas.drawRGB(240, 240, 240);
                Paint pen = new Paint();
                pen.setStrokeWidth(8);
                pen.setARGB(255, 10, 10, 10);
                // Dibujamos la base de la horca
                canvas.drawLine(20, 220, 110, 220, pen);
                pen.setStrokeWidth(5);
                // Dibujamos la estructura de la horca
                canvas.drawLine(90, 220, 90, 60, pen);
                canvas.drawLine(90, 62, 50, 62, pen);
                canvas.drawLine(52, 62, 52, 82, pen);
                Paint pen2 = new Paint();
                pen2.setARGB(255, 85, 85, 85);
                pen2.setStrokeWidth(3);
                // Dibujamos la cabeza (con ojos, nariz y boca)
                canvas.drawCircle(52, 102, 20, pen2);
                canvas.drawCircle(43, 97, 2, pen); // ojo izdo
                canvas.drawCircle(61, 97, 2, pen); // ojo dcho
                Paint penB = new Paint();
                penB.setARGB(255, 10, 10, 10);
                penB.setStrokeWidth(3);
                canvas.drawLine(52, 100, 52, 105, penB);
                // Boca
                canvas.drawLine(45, 110, 59, 110, penB);
                // Dibujamos el tronco
                canvas.drawLine(52, 122, 52, 172, pen2);
                // Dibujamos los brazos
                canvas.drawLine(52, 132, 37, 150, pen2); // izquierdo
            }

            // Dibujamos el ahorcado hasta el brazo derecho
            if (estado == Estados.BRAZO_DCHO) {
                canvas.drawRGB(240, 240, 240);
                Paint pen = new Paint();
                pen.setStrokeWidth(8);
                pen.setARGB(255, 10, 10, 10);
                // Dibujamos la base de la horca
                canvas.drawLine(20, 220, 110, 220, pen);
                pen.setStrokeWidth(5);
                // Dibujamos la estructura de la horca
                canvas.drawLine(90, 220, 90, 60, pen);
                canvas.drawLine(90, 62, 50, 62, pen);
                canvas.drawLine(52, 62, 52, 82, pen);
                Paint pen2 = new Paint();
                pen2.setARGB(255, 85, 85, 85);
                pen2.setStrokeWidth(3);
                // Dibujamos la cabeza (con ojos, nariz y boca)
                canvas.drawCircle(52, 102, 20, pen2);
                canvas.drawCircle(43, 97, 2, pen); // ojo izdo
                canvas.drawCircle(61, 97, 2, pen); // ojo dcho
                Paint penB = new Paint();
                penB.setARGB(255, 10, 10, 10);
                penB.setStrokeWidth(3);
                canvas.drawLine(52, 100, 52, 105, penB);
                // Boca
                canvas.drawLine(45, 110, 59, 110, penB);
                // Dibujamos el tronco
                canvas.drawLine(52, 122, 52, 172, pen2);
                // Dibujamos los brazos
                canvas.drawLine(52, 132, 37, 150, pen2); // izquierdo
                canvas.drawLine(52, 132, 67, 150, pen2); // derecho
            }

            // Dibujamos el ahorcado hasta la pierna izquierda
            if (estado == Estados.PIERNA_IZDA) {
                canvas.drawRGB(240, 240, 240);
                Paint pen = new Paint();
                pen.setStrokeWidth(8);
                pen.setARGB(255, 10, 10, 10);
                // Dibujamos la base de la horca
                canvas.drawLine(20, 220, 110, 220, pen);
                pen.setStrokeWidth(5);
                // Dibujamos la estructura de la horca
                canvas.drawLine(90, 220, 90, 60, pen);
                canvas.drawLine(90, 62, 50, 62, pen);
                canvas.drawLine(52, 62, 52, 82, pen);
                Paint pen2 = new Paint();
                pen2.setARGB(255, 85, 85, 85);
                pen2.setStrokeWidth(3);
                // Dibujamos la cabeza (con ojos, nariz y boca)
                canvas.drawCircle(52, 102, 20, pen2);
                canvas.drawCircle(43, 97, 2, pen); // ojo izdo
                canvas.drawCircle(61, 97, 2, pen); // ojo dcho
                Paint penB = new Paint();
                penB.setARGB(255, 10, 10, 10);
                penB.setStrokeWidth(3);
                canvas.drawLine(52, 100, 52, 105, penB);
                // Boca
                canvas.drawLine(45, 110, 59, 110, penB);
                // Dibujamos el tronco
                canvas.drawLine(52, 122, 52, 172, pen2);
                // Dibujamos los brazos
                canvas.drawLine(52, 132, 37, 150, pen2); // izquierdo
                canvas.drawLine(52, 132, 67, 150, pen2); // derecho
                // Dibujamos las piernas
                canvas.drawLine(52, 172, 37, 190, pen2); // izquerda
            }

            // Dibujamos el ahorcado completo
            if (estado == Estados.PIERNA_DCHA) {
                canvas.drawRGB(240, 240, 240);
                Paint pen = new Paint();
                pen.setStrokeWidth(8);
                pen.setARGB(255, 10, 10, 10);
                // Dibujamos la base de la horca
                canvas.drawLine(20, 220, 110, 220, pen);
                pen.setStrokeWidth(5);
                // Dibujamos la estructura de la horca
                canvas.drawLine(90, 220, 90, 60, pen);
                canvas.drawLine(90, 62, 50, 62, pen);
                canvas.drawLine(52, 62, 52, 82, pen);
                Paint pen2 = new Paint();
                pen2.setARGB(255, 85, 85, 85);
                pen2.setStrokeWidth(3);
                // Dibujamos la cabeza (con ojos, nariz y boca)
                canvas.drawCircle(52, 102, 20, pen2);
                canvas.drawCircle(43, 97, 2, pen); // ojo izdo
                canvas.drawCircle(61, 97, 2, pen); // ojo dcho
                Paint penB = new Paint();
                penB.setARGB(255, 10, 10, 10);
                penB.setStrokeWidth(3);
                canvas.drawLine(52, 100, 52, 105, penB);
                // Boca
                canvas.drawLine(45, 110, 59, 110, penB);
                // Dibujamos el tronco
                canvas.drawLine(52, 122, 52, 172, pen2);
                // Dibujamos los brazos
                canvas.drawLine(52, 132, 37, 150, pen2); // izquierdo
                canvas.drawLine(52, 132, 67, 150, pen2); // derecho
                // Dibujamos las piernas
                canvas.drawLine(52, 172, 37, 190, pen2); // izquerda
                canvas.drawLine(52, 172, 67, 190, pen2); // derecha
            }

            // Dibujamos el ahorcado completo
            if (estado == Estados.FINAL) {
                canvas.drawRGB(240, 240, 240);
                Paint pen = new Paint();
                pen.setStrokeWidth(8);
                pen.setARGB(255, 10, 10, 10);
                // Dibujamos la base de la horca
                canvas.drawLine(20, 220, 110, 220, pen);
                pen.setStrokeWidth(5);
                // Dibujamos la estructura de la horca
                canvas.drawLine(90, 220, 90, 60, pen);
                canvas.drawLine(90, 62, 50, 62, pen);
                canvas.drawLine(52, 62, 52, 82, pen);
                Paint pen2 = new Paint();
                pen2.setARGB(255, 85, 85, 85);
                pen2.setStrokeWidth(3);
                // Dibujamos la cabeza (con ojos, nariz y boca)
                canvas.drawCircle(52, 102, 20, pen2);
                canvas.drawCircle(43, 97, 2, pen); // ojo izdo
                canvas.drawCircle(61, 97, 2, pen); // ojo dcho
                Paint penB = new Paint();
                penB.setARGB(255, 10, 10, 10);
                penB.setStrokeWidth(3);
                canvas.drawLine(52, 100, 52, 105, penB);
                // Boca
                canvas.drawLine(45, 110, 59, 110, penB);
                // Dibujamos el tronco
                canvas.drawLine(52, 122, 52, 172, pen2);
                // Dibujamos los brazos
                canvas.drawLine(52, 132, 37, 150, pen2); // izquierdo
                canvas.drawLine(52, 132, 67, 150, pen2); // derecho
                // Dibujamos las piernas
                canvas.drawLine(52, 172, 37, 190, pen2); // izquerda
                canvas.drawLine(52, 172, 67, 190, pen2); // derecha

                // Dibujamos un aspa sobre el gráfico para indicar que el
                // jugador ha perdido.
                Paint penRed = new Paint();
                penRed.setARGB(100, 255, 10, 10);
                penRed.setStrokeWidth(8);
                canvas.drawLine(0, 0, this.getWidth(), this.getHeight(), penRed);
                canvas.drawLine(this.getWidth() - 1, 0, 0,
                        this.getHeight() - 1, penRed);
            }
        }
    }
}


Este es el código java detrás de la actividad que controla la pantalla inicial del juego. Esta actividad nos muestra una serie de botones que permiten iniciar un juego, salir, ver información sobre el juego o invocar un menú de configuración que nos permite modificar ciertas opciones como a que idioma pertenecerán las palabras generadas.

package not.ebacelo.android;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class HangmanActivity extends Activity implements OnClickListener {
    private int dificultad;
    private String idioma;

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // TODO Auto-generated method stub
        super.onOptionsItemSelected(item);
        switch(item.getItemId()) {
        case R.id.itemConfiguracion:
            Intent intentConf = new Intent(this, Preferencias.class);
            startActivity(intentConf);
            return true;
        }
        return false;
    }

    public void onClick(View v) {
        // TODO Auto-generated method stub
        switch (v.getId()) {
       
        case R.id.btnNuevo:
            Intent i = new Intent(this, GameActivity.class);
            //Obtenemos la información configurada en el menú Configuración
            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(HangmanActivity.this);
            dificultad = prefs.getInt("DIFICULTAD", 1);
            idioma = prefs.getString("IDIOMA", "ES");
           
            //Enviamos la información de la configuración a la actividad GameActivity
            i.putExtra("DIFICULTAD", dificultad);
            i.putExtra("IDIOMA", idioma);
            startActivity(i);
            break;
       
        case R.id.btnAcerca:
            AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(v.getContext());
            alertDialogBuilder.setTitle(v.getContext().getString(R.string.about_label));
            alertDialogBuilder.setMessage(v.getContext().getString(R.string.about_text))
            .setCancelable(false)
            .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
               
                public void onClick(DialogInterface dialog, int which) {
                    if (which == AlertDialog.BUTTON_POSITIVE)
                        dialog.cancel();                       
                }
            });
           
            AlertDialog alertDialog = alertDialogBuilder.create();
            alertDialog.show();
            break;
           
        case R.id.btnSalir:
            this.finish();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // TODO Auto-generated method stub
        super.onCreateOptionsMenu(menu);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return true;
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        Button btnContinuar = (Button)findViewById(R.id.btnContinuar);
        Button btnNuevo = (Button)findViewById(R.id.btnNuevo);
        Button btnAcerca = (Button)findViewById(R.id.btnAcerca);
        Button btnSalir = (Button)findViewById(R.id.btnSalir);
       
        btnContinuar.setOnClickListener(this);
        btnNuevo.setOnClickListener(this);
        btnAcerca.setOnClickListener(this);
        btnSalir.setOnClickListener(this);
    }
}

Hangman Android (I)

Como ya he comentado en una entrada anterior, he estado aprendiendo a programar aplicaciones en la plataforma Android. Todavía me queda mucho que aprender pero con lo que he aprendido hasta el momento ya he podido crear varias aplicaciones que se pueden enseñar al mundo. La que voy a describir en esta entrada no es la primera, pero si que es la que hasta la fecha me parece que está más completa.
La aplicación de la que estoy hablando es el juego del Ahorcado. Es la versión para Android de la aplicación que mostré en la última entrada de este blog. A continuación os muestro algunas imágenes del resultado final de la aplicación, así como el código correspondiente a dicha aplicación. En esta entrada podéis ver la parte de presentación de las distintas actividades que conforman la aplicación (los ficheros xml que definen la interfaz de usuario y como se visualizan). En la siguiente entrada añadiré el código que hay detrás de la actividad Game que es en la que se desarrolla realmente el juego.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/background1"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/linearLayout2"
         android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0.40"
        android:orientation="vertical" android:background="@drawable/fondo_ahorcado">

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/main_title"
            android:textSize="24dip" android:layout_gravity="center" android:textColor="@color/main_title_color" android:layout_marginTop="25dip"/>

        <Button
            android:id="@+id/btnContinuar"
            android:layout_width="200dip"
            android:layout_height="wrap_content"
            android:text="@string/continue_label"
            android:layout_gravity="center"
            android:padding="12dip" android:layout_marginBottom="15dip" android:layout_marginTop="40dip"/>

        <Button
            android:id="@+id/btnNuevo"
            android:layout_width="200dip"
            android:layout_height="wrap_content"
            android:text="@string/new_game_label"
            android:layout_gravity="center" 
            android:padding="12dip" android:layout_marginBottom="15dip"/>

        <Button
            android:id="@+id/btnAcerca"
            android:layout_width="200dip"
            android:layout_height="wrap_content"
            android:text="@string/about_label"
            android:layout_gravity="center" 
            android:padding="12dip" android:layout_marginBottom="15dip"/>

        <Button
            android:id="@+id/btnSalir"
            android:layout_width="200dip"
            android:layout_height="wrap_content"
            android:text="@string/exit_label"
            android:layout_gravity="center" 
            android:padding="12dip" android:fadingEdge="none"/>
    </LinearLayout>

</LinearLayout>


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llGame1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#ffee4444"
    android:orientation="vertical" >
   
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llGame2"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/fondo_gradienteh"
    android:orientation="horizontal"
    android:layout_weight="1" >
      <!-- lblLetras -->

        <TextView
            android:id="@+id/TextView06"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="3dip"
            android:padding="3dip"
            android:text="_"
            android:textColor="@color/tvLetras_color"
            android:textSize="36dip" android:layout_marginBottom="2dip"/>

        <TextView
            android:id="@+id/TextView04"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="3dip"
            android:padding="3dip"
            android:text="_"
            android:textColor="@color/tvLetras_color"
            android:textSize="36dip" android:layout_marginBottom="2dip"/>

        <TextView
            android:id="@+id/TextView03"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="3dip"
            android:padding="3dip"
            android:text="_"
            android:textColor="@color/tvLetras_color"
            android:textSize="36dip" android:layout_marginBottom="2dip"/>

        <TextView
            android:id="@+id/TextView02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="3dip"
            android:padding="3dip"
            android:text="_"
            android:textColor="@color/tvLetras_color"
            android:textSize="36dip" android:layout_marginBottom="2dip"/>

        <TextView
            android:id="@+id/TextView01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="3dip"
            android:padding="3dip"
            android:text="_"
            android:textColor="@color/tvLetras_color"
            android:textSize="36dip" android:layout_marginBottom="2dip"/>

        <TextView
            android:id="@+id/TextView05"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="3dip"
            android:text="_"
            android:textColor="@color/tvLetras_color"
            android:textSize="36dip" android:padding="3dip" android:layout_marginBottom="2dip"/>

    </LinearLayout>
   
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llGame3"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#4444ff44"
    android:layout_weight="0.42"
    android:orientation="horizontal" >
      <!-- btnLetras y canvas -->
      <TableLayout
          android:id="@+id/tlBotonesLetras"
          android:layout_width="wrap_content"
          android:layout_height="fill_parent"
          android:background="@drawable/fondo_gradiente">
          <TableRow android:id="@+id/trow1">
            <Button
            android:id="@+id/btnLetra1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="a" android:layout_marginTop="2dip"/>
            <Button
            android:id="@+id/btnLetra2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="b" android:layout_marginTop="2dip"/>
            <Button
            android:id="@+id/btnLetra3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="c" android:layout_marginTop="2dip"/>
            <Button
            android:id="@+id/btnLetra4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="d" android:layout_marginTop="2dip"/>
            <Button
            android:id="@+id/btnLetra5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="e" android:layout_marginTop="2dip"/>
            <Button
            android:id="@+id/btnLetra6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="f" android:layout_marginTop="2dip"/>
           
          </TableRow>
          <TableRow android:id="@+id/trow2">
            <Button
            android:id="@+id/btnLetra7"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="g" />
            <Button
            android:id="@+id/btnLetra8"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="h" />
            <Button
            android:id="@+id/btnLetra9"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="i" />
            <Button
            android:id="@+id/btnLetra10"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="j" />
            <Button
            android:id="@+id/btnLetra11"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="k" />
            <Button
            android:id="@+id/btnLetra12"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="l" />
             
          </TableRow>
          <TableRow android:id="@+id/trow3">
            <Button
            android:id="@+id/btnLetra13"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="m" />
            <Button
            android:id="@+id/btnLetra14"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="n" />
            <Button
            android:id="@+id/btnLetra15"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="ñ" />
            <Button
            android:id="@+id/btnLetra16"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="o" />
            <Button
            android:id="@+id/btnLetra17"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="p" />
            <Button
            android:id="@+id/btnLetra18"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="q" />
          </TableRow>
         
          <TableRow android:id="@+id/trow4">
            <Button
            android:id="@+id/btnLetra19"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="r" />
            <Button
            android:id="@+id/btnLetra20"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="s" />
            <Button
            android:id="@+id/btnLetra21"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="t" />
            <Button
            android:id="@+id/btnLetra22"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="u" />
            <Button
            android:id="@+id/btnLetra23"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="v" />
            <Button
            android:id="@+id/btnLetra24"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="w" />
           
          </TableRow>

          <TableRow android:id="@+id/trow5">
            <Button
            android:id="@+id/btnLetra25"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="x" android:layout_marginBottom="2dip"/>
            <Button
            android:id="@+id/btnLetra26"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="y" android:layout_marginBottom="2dip"/>
            <Button
            android:id="@+id/btnLetra27"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="z" android:layout_marginBottom="2dip"/>
            <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="invisible"
            android:text="" />
            <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="invisible"
            android:text="" />

            <ImageButton
                android:id="@+id/ibFlag"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:tag="invisible"/>

          
          </TableRow>
      </TableLayout>
     
      <LinearLayout
            android:id="@+id/llGame31"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@color/transparent"
        android:orientation="vertical" >
      </LinearLayout>
    </LinearLayout>
   
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llGame4"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal"
    android:layout_weight="1" android:background="@drawable/fondo_gradienteh">
        <!-- tvMensajes  y btnNuevo -->

        <TextView
            android:id="@+id/tvMensaje"
            android:layout_width="fill_parent"
            android:layout_height="40dip"
            android:text="TextView" android:layout_weight="0.6" android:layout_gravity="center" android:layout_marginRight="4dip" android:background="@drawable/fondo_gradienteh" android:textColor="@color/tvMensaje_textcolor" android:textSize="20dip"/>

        <Button
            android:id="@+id/btnNuevo"
            android:layout_width="fill_parent"
            android:layout_height="40dip"
            android:layout_weight="1"
            android:text="@string/btnNewGame" android:layout_gravity="center" android:layout_marginLeft="6dip" android:layout_marginRight="6dip"/>
       
    </LinearLayout>
   
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llGame5"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/fondo_gradienteh"
    android:orientation="horizontal"
    android:layout_weight="1" >
        <!-- chkVerSolucion  y  txtSolucion -->

        <CheckBox
            android:id="@+id/chkMostrarSolucion"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:text="@string/chkMostrarSolucion_label"/>

        <TextView
            android:id="@+id/tvSolucion"
            android:layout_width="120dip"
            android:layout_height="wrap_content"
            android:text="Solución" android:textSize="21dip" android:layout_marginLeft="20dip" android:textColor="@color/tvLetras_color"/>

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="30dip"
            android:layout_height="30dip"
            android:src="@drawable/logo32" android:layout_marginTop="20dip"/>
       
    </LinearLayout>
</LinearLayout>



// OPCIONES DEL MENÚ DE CONFIGURACIÓN
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    <ListPreference
        android:key="IDIOMA"
        android:title="Selección idioma"
        android:summary="Seleccionar idioma para jugar"
        android:dialogTitle="Indicar idioma"
        android:entries="@array/language"
        android:entryValues="@array/language_code"/>
    <ListPreference
        android:key="DIFICULTAD"
        android:title="Selección dificultad"
        android:summary="Seleccionar nivel de dificultad"
        android:dialogTitle="Indicar dificultad"
        android:entries="@array/difficulty_level"
        android:entryValues="@array/difficulty_code"/>
</PreferenceScreen>


// MENÚ CONFIGURACIÓN
<menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/itemConfiguracion" android:title="Configuración..."></item>
    </menu>

 //Actividad que genera las opciones de configuración
import android.os.Bundle;
import android.preference.PreferenceActivity;

public class Preferencias extends PreferenceActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.configuracion);
    }
}


lunes, 12 de noviembre de 2012

Hangman

Otro juego muy conocido por todos es  "El ahorcado". El juego consiste en tratar de averiguar una palabra desconocida escogiendo letras que se cree que forman parte de la misma hasta conseguir adivinarla, o hasta que se agota el número de errores que se pueden cometer. En este punto, el dibujo que se podrá ver será un muñeco completo colgando de la horca.
En esta entrada del blog voy a mostrar el código de una pequeña aplicación que he creado recreando este juego. Espero que sirva a alguién para aprender algo. A continuación os muestro el código y también un par de imágenes del resultado final.


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Collections;

namespace Hangman01
{
    public partial class Form1 : Form
    {
        enum HangmanParts { None, Head, Trunk, RightArm, LeftArm,
                            RightLeg, LeftLeg };
        //, RightEye, LeftEye, Nose, Mouth
        String palabraGenerada;
        String palabraIntroducida;
        HangmanParts estadoHangman = 0;
        int errores;
        int letrasAcertadas = 0;
        bool juegoFinalizado;

        public Form1()
        {
            InitializeComponent();
            palabraGenerada = "";
            juegoFinalizado = false;
            chkMostrarSolucion.Checked = false;
            txtSolucion.Visible = false;
        }


        //Este método nos permite saber si una determinada letra de la palabra
        //generada por el juego todavía no ha sido visualizada al menos en una
        //de las casillas.
        private bool letraPendienteAdivinar(String letra)
        {
            int pendientes = 0;

            for (int i = 0; i < palabraGenerada.Length; i++)
            {
                if ((((Label)pnlLetras.Controls["lblLetra" + i]).Text.CompareTo("_") == 0) &&
                    palabraGenerada[i].ToString().CompareTo(letra) == 0)
                {
                    pendientes++;
                }
            }
            if (pendientes > 0)
                return true;
            else
                return false;
        }

        //Este método se ejecuta cuando el jugador introduce una palabra para
        //comprobar directamente si es la palabra buscada. Cada letra que
        //no coincida con la palabra generada se considerará un fallo y se
        //actualizará el estado de acuerdo a ello.
        private void btnComprobar_Click(object sender, EventArgs e)
        {
            if (juegoFinalizado == false)
            {
                btnComprobar.Enabled = false;
                //Comparar la palabra generada aleatoriamente con la introducida
                //por el jugador. Para cada letra que coincida en la posición
                //correcta se asignará en el control label correspondiente en pnlLetras
                errores = 0;
                letrasAcertadas = 0;
                palabraIntroducida = txtPalabra.Text;

                if (palabraIntroducida.Length == palabraGenerada.Length)
                {
                    for (int i = 0; i < palabraIntroducida.Length; i++)
                    {
                        if (palabraIntroducida[i].ToString().ToUpper().CompareTo(palabraGenerada[i].ToString()) == 0)
                        {
                            letrasAcertadas++;
                            ((Label)pnlLetras.Controls["lblLetra" + i]).Text = palabraGenerada[i].ToString();
                           
                            //---->>>> <<<<----
                            //Si la letra actual no coincide con ninguna de la palabra generada
                            //que no se haya introducido correctamente
                            if (!letraPendienteAdivinar(palabraIntroducida[i].ToString().ToUpper()))
                                marcarBotonLetra(palabraGenerada[i].ToString(), true);
                        }
                        else
                        {
                            errores++;
                            //actualizar gráfico
                            dibujarHangman(++estadoHangman);
                            if (!letraPendienteAdivinar(palabraIntroducida[i].ToString().ToUpper()))
                                marcarBotonLetra(palabraIntroducida[i].ToString(), false);
                        }
                        //Si se agotan las oportunidades disponibles se mostrará un mensaje
                        //indicando que el juego ha finalizado y el jugador ha perdido
                        if (errores > (int)HangmanParts.LeftLeg)
                        {
                            lblMensaje.Text = "El juego ha finalizado. PALABRA INCORRECTA!";
                            juegoFinalizado = true;
                            break;
                        }
                    }
                }
                if (palabraIntroducida.Length > palabraGenerada.Length)
                {
                    for (int i = 0; i < palabraIntroducida.Length; i++)
                    {
                        if (i < palabraGenerada.Length)
                        {
                            if (palabraIntroducida[i].ToString().ToUpper().CompareTo(palabraGenerada[i].ToString()) == 0)
                            {
                                letrasAcertadas++;
                                ((Label)pnlLetras.Controls["lblLetra" + i]).Text = palabraGenerada[i].ToString();
                                if (!letraPendienteAdivinar(palabraIntroducida[i].ToString().ToUpper()))
                                    marcarBotonLetra(palabraIntroducida[i].ToString().ToUpper(), true);
                            }
                            else
                            {
                                errores++;
                                //actualizar gráfico
                                dibujarHangman(++estadoHangman);
                                if (!letraPendienteAdivinar(palabraIntroducida[i].ToString().ToUpper()))
                                    marcarBotonLetra(palabraIntroducida[i].ToString().ToUpper(), false);
                            }
                        }
                        else
                        {
                            errores++;
                            dibujarHangman(++estadoHangman);
                            if (!letraPendienteAdivinar(palabraIntroducida[i].ToString().ToUpper()))
                                marcarBotonLetra(palabraIntroducida[i].ToString(), false);
                        }
                        //Si se agotan las oportunidades disponibles se mostrará un
                        //mensaje indicando que el juego ha finalizado y el jugador ha perdido
                        if (errores > (int)HangmanParts.LeftLeg)
                        {
                            lblMensaje.Text = "El juego ha finalizado. PALABRA INCORRECTA!";
                            juegoFinalizado = true;
                            break;
                        }
                    }
                }

                if (palabraGenerada.Length > palabraIntroducida.Length)
                {
                    for (int i = 0; i < palabraGenerada.Length; i++)
                    {
                        if (i < palabraIntroducida.Length)
                        {
                            if (palabraIntroducida[i].ToString().ToUpper().CompareTo(palabraGenerada[i].ToString()) == 0)
                            {
                                letrasAcertadas++;
                                ((Label)pnlLetras.Controls["lblLetra" + i]).Text = palabraGenerada[i].ToString();
                                if (!letraPendienteAdivinar(palabraIntroducida[i].ToString().ToUpper()))
                                    marcarBotonLetra(palabraGenerada[i].ToString(), true);
                            }
                            else
                            {
                                errores++;
                                //actualizar gráfico
                                dibujarHangman(++estadoHangman);
                                if (!letraPendienteAdivinar(palabraIntroducida[i].ToString().ToUpper()))
                                    marcarBotonLetra(palabraGenerada[i].ToString(), false);
                            }
                        }
                        else
                        {
                            errores++;
                            dibujarHangman(++estadoHangman);
                            if (!letraPendienteAdivinar(palabraGenerada[i].ToString().ToUpper()))
                                marcarBotonLetra(palabraGenerada[i].ToString(), false);
                        }
                        //Si se agotan las oportunidades disponibles se mostrará un mensaje
                        //indicando que el juego ha finalizado y el jugador ha perdido
                        if (errores > (int)HangmanParts.LeftLeg)
                        {
                            lblMensaje.Text = "El juego ha finalizado. PALABRA INCORRECTA!";
                            juegoFinalizado = true;
                            break;
                        }

                    }
                }


                if ((juegoFinalizado == false) && (letrasAcertadas == palabraGenerada.Length))
                {
                    lblMensaje.Text = "PALABRA CORRECTA!!!";
                    juegoFinalizado = true;
                }
            }
            else
            {
                MessageBox.Show("El juego ha finalizado. Pulse Nuevo para empezar otra vez",
                           "Juego finalizado", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        //Este método se ocupa de deshabilitar los botones correspondientes a
        //las letras que ya han sido pulsadas diferenciando visualmente entre
        //las que corresponden a aciertos y las que corresponden a fallos.
        private void marcarBotonLetra(String letra, bool acertada)
        {
            foreach (Control ctrl in pnlBotones.Controls)
            {
                Button btn = (Button)ctrl;
                if (btn.Text.CompareTo(letra.ToUpper()) == 0)
                {
                    if (acertada == true)
                        btn.Enabled = false;
                    else
                    {
                        btn.Enabled = false;
                        btn.BackColor = Color.Orchid;
                        //dibujarFondoBoton(btn);
                    }
                }
            }
        }

        private void dibujarFondoBoton(Button btn)
        {
            Graphics g = btn.CreateGraphics();

            Pen p = new Pen(Color.Red, 2.5f);
            g.DrawLine(p, 0, 0, btn.Width, btn.Height);
            g.DrawLine(p, 0, btn.Height, btn.Width, 0);
        }

        //Habilita los botones correspondientes a las letras, para mostrarlos en
        //su estado inicial
        private void desmarcarBotonesLetras()
        {
            foreach (Control ctrl in pnlBotones.Controls)
            {
                Button btn = (Button)ctrl;
                btn.ForeColor = Color.FromKnownColor(KnownColor.ControlText);
                btn.BackColor = Color.FromKnownColor(KnownColor.Control);
                btn.Enabled = true;
            }
        }

        //Inicializa el contenido de las etiquetas correspondientes a cada una
        //de las letras de la palabra generada por el juego. El contenido inicial
        //de cada etiqueta es el carácter "_"
        private void limpiarEtiquetasLetras()
        {
            foreach (Control ctrl in pnlLetras.Controls)
            {
                Label lbl = (Label)ctrl;
                lbl.Text = "_";
                lbl.BackColor = Color.FromKnownColor(KnownColor.Control);
            }
        }

        //Acciones a realizar cuanod se pulsa alguno de los botones correspondientes
        //a las letras del alfabeto. Cada uno de estos botones permite que el jugador
        //seleccione cual es la letra que quiere seleccionar a continuación para
        //adivinar la palabra.
        private void btnLetra_Click(object sender, EventArgs e)
        {
            if (juegoFinalizado == false)
            {
                int coincidencias = 0;

                //Obtenemos la letra correspondiente al botón pulsado
                String letra = ((Button)sender).Text;
                String lblLetra = "lblLetra";
                //Comparar cada una de las letras de la palabra generada
                //con la letra pulsada. Para cada una que coincida, mostrar
                //la letra en cuestión como el texto del control label que
                //corresponde en pnlLetras
                for (int i = 0; i < palabraGenerada.Length; i++)
                {
                    if ((palabraGenerada[i].ToString().ToUpper().CompareTo(letra) == 0)
                       && (((Label)pnlLetras.Controls[lblLetra + i]).Text.CompareTo("_") == 0))
                    {
                        ((Label)pnlLetras.Controls[lblLetra + i]).Text = letra;
                        letrasAcertadas++;
                        coincidencias++;
                        marcarBotonLetra(letra, true);
                        if (letrasAcertadas == palabraGenerada.Length)
                        {
                            //Palabra acertada, juego terminado
                            lblMensaje.Text = "El juego ha finalizado. PALABRA CORRECTA!!!";
                            juegoFinalizado = true;
                            return;
                        }
                    }
                }
                if (coincidencias == 0)
                {
                    errores++;
                    dibujarHangman(++estadoHangman);
                    marcarBotonLetra(letra, false);
                    //Si se agotan las posibilidades, mostramos un mensaje
                    //indicando que el juego ha terminado.
                    if (errores >= (int)HangmanParts.LeftLeg)
                    {
                        lblMensaje.Text = "El juego ha finalizado. PALABRA INCORRECTA!";
                        juegoFinalizado = true;
                    }
                }
            }
            else
            {
                MessageBox.Show("El juego ha finalizado. Pulse Nuevo para empezar otra vez",
                    "Juego finalizado", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        //Inicialización del juego. Se inicializan la variables necesarias para
        //establecer el estado inicial del juego.
        private void btnNuevo_Click(object sender, EventArgs e)
        {
            letrasAcertadas = 0;
            errores = 0;
            estadoHangman = 0;
            juegoFinalizado = false;
            btnComprobar.Enabled = true;

            //Borramos limpiamos todos los controles label de pnlLetras
            limpiarEtiquetasLetras();
            //Inicializamos el estado de los botones correspondientes a las letras
            desmarcarBotonesLetras();
            //Limpiamos el contenido de pnlGrafico y dibujamos la parte inicial (la horca)
            dibujarHangman(HangmanParts.None);
            //Generamos aleatoriamente una nueva palabra
            palabraGenerada = generarPalabra().ToUpper();

            txtSolucion.Text = palabraGenerada;
            //Creamos y mostramos un control de tipo Label para cada letra
            //de la palabra generada
            crearEtiquetasPalabra(palabraGenerada.Length);
            //Eliminamos el mensaje anterior (si lo hay)
            limpiarMensaje();
        }
       
        //Este método permite dibujar el muñeco ahorcado que indica el número de
        //errores cometidos por el jugador y el número de errores que todavía puede
        //cometer antes de perder la partida. El método se ocupa de dibujar en el
        //un panel del formulario las partes del muñeco de acuerdo con el estado
        //del juego que recibe como parámetro.
        private void dibujarHangman(HangmanParts estado)
        {
            Graphics g = pnlGrafico.CreateGraphics();
            Pen pHorca = new Pen(Color.Black, 4.5f);
            Pen pCuerda = new Pen(Color.Black, 2.5f);
            Pen pMan = new Pen(Color.Brown, 2f);
            Pen pManFino = new Pen(Color.Brown, 1.5f);

            //Limpiamos el panel para redibujar el ahorcado
            g.Clear(Color.FromKnownColor(KnownColor.ScrollBar));
            //Dibujamos la horca
            g.DrawLine(pHorca, (pnlGrafico.Width / 2)-10, pnlGrafico.Height - 35,
                        (pnlGrafico.Width / 2) + 80, pnlGrafico.Height - 35);
            g.DrawLine(pHorca, (pnlGrafico.Width / 2) + 45, pnlGrafico.Height - 35,
                        (pnlGrafico.Width / 2) + 45, pnlGrafico.Height - 185);
            g.DrawLine(pHorca, (pnlGrafico.Width / 2) + 5, pnlGrafico.Height - 183,
                        (pnlGrafico.Width / 2) + 45, pnlGrafico.Height - 183);
            g.DrawLine(pCuerda, (pnlGrafico.Width / 2) + 6, pnlGrafico.Height - 183,
                        (pnlGrafico.Width / 2) + 5, pnlGrafico.Height - 160);

            if (estado >= HangmanParts.LeftLeg) {
                //Dibujamos la pierna izda
                g.DrawLine(pMan, (pnlGrafico.Width / 2) + 5, pnlGrafico.Height - 80,
                                  (pnlGrafico.Width / 2) - 8, pnlGrafico.Height - 70);
            }

            if (estado >= HangmanParts.RightLeg) {
                //Dibujamos la pierna derecha
                g.DrawLine(pMan, (pnlGrafico.Width / 2) + 5, pnlGrafico.Height - 80,
                           (pnlGrafico.Width / 2) + 18, pnlGrafico.Height - 70);
            }

            if (estado >= HangmanParts.LeftArm)
            {
                //Dibujamos el brazo izquierdo
                g.DrawLine(pMan, (pnlGrafico.Width / 2) + 5, pnlGrafico.Height - 120,
                           (pnlGrafico.Width / 2) - 8, pnlGrafico.Height - 105);
            }

            if (estado >= HangmanParts.RightArm)
            {
                //Dibujamos el brazo derecho
                g.DrawLine(pMan, (pnlGrafico.Width / 2) + 5, pnlGrafico.Height - 120,
                           (pnlGrafico.Width / 2) + 18, pnlGrafico.Height - 105);
            }

            if (estado >= HangmanParts.Trunk)
            {
                //Dibujamos el tronco
                g.DrawLine(pMan, (pnlGrafico.Width / 2) + 5, pnlGrafico.Height - 130,
                           (pnlGrafico.Width / 2) + 5, pnlGrafico.Height - 80);
            }

            //if (estado >= HangmanParts.Mouth)
            //{
            //    //Dibujamos la boca
            //    Point pto1 = new Point((pnlGrafico.Width / 2), pnlGrafico.Height - 137);
            //    Point pto2 = new Point((pnlGrafico.Width / 2) + 4, pnlGrafico.Height - 135);
            //    Point pto3 = new Point((pnlGrafico.Width / 2) + 8, pnlGrafico.Height - 137);
            //    Point[] ptosBoca = new Point[] { pto1, pto2, pto3 };
            //    g.DrawCurve(pManFino, ptosBoca);
            //}

            //if (estado >= HangmanParts.Nose)
            //{
            //    //Dibujamos la nariz
            //    g.DrawEllipse(pMan, (pnlGrafico.Width / 2) + 3, pnlGrafico.Height - 146, 2, 5);
            //}
            //if (estado >= HangmanParts.LeftEye)
            //{
            //    //Dibujamos el ojo izdo
            //    g.DrawEllipse(pMan, (pnlGrafico.Width / 2) + 7, pnlGrafico.Height - 152, 8, 4);
            //}

            //if (estado >= HangmanParts.RightEye)
            //{
            //    //Dibujamos el ojo derecho
            //    g.DrawEllipse(pMan, (pnlGrafico.Width / 2) - 6, pnlGrafico.Height - 152, 8, 4);
            //}

            if (estado >= HangmanParts.Head)
            {
                //Dibujamos la boca
                Point pto1 = new Point((pnlGrafico.Width / 2), pnlGrafico.Height - 137);
                Point pto2 = new Point((pnlGrafico.Width / 2) + 4, pnlGrafico.Height - 135);
                Point pto3 = new Point((pnlGrafico.Width / 2) + 8, pnlGrafico.Height - 137);
                Point[] ptosBoca = new Point[] { pto1, pto2, pto3 };
                g.DrawCurve(pManFino, ptosBoca);
                //Dibujamos la nariz
                g.DrawEllipse(pMan, (pnlGrafico.Width / 2) + 3, pnlGrafico.Height - 146, 2, 5);
                //Dibujamos el ojo izdo
                g.DrawEllipse(pMan, (pnlGrafico.Width / 2) + 7, pnlGrafico.Height - 152, 8, 4);
                //Dibujamos el ojo derecho
                g.DrawEllipse(pMan, (pnlGrafico.Width / 2) - 6, pnlGrafico.Height - 152, 8, 4);

                //Dibujamos la cabeza
                g.DrawEllipse(pMan, new Rectangle((pnlGrafico.Width / 2) - 10,
                              pnlGrafico.Height - 160, 30, 30));
            }      
        }

        //Acciones iniciales que se realizan cuando se inicia la aplicación. Poner
        //el juego en el estado inicial.
        private void Form1_Shown(object sender, EventArgs e)
        {
            //Generamos aleatoriamente una nueva palabra
            palabraGenerada = generarPalabra().ToUpper();
            txtSolucion.Text = palabraGenerada;

            //Creamos y mostramos un control de tipo Label para cada letra de la
            //palabra generada
            crearEtiquetasPalabra(palabraGenerada.Length);

            //Dibujamos la parte inicial del gráfico (la horca)
            dibujarHangman(HangmanParts.None);

        }

        //Este método se ocupa de generar las etiquetas que albergan cada una de
        //las letras que componen la palabra generada. Cuando se generan las
        //etiquetas su contenido será el carácter "_" y según avance el juego y según
        //vaya acertando letras el jugador, el contenido de dichas etiquetas irá
        //cambiando a las letras que se corresponden con las letras de la palabra
        //generada en cada momento.
        private void crearEtiquetasPalabra(int longitudPalabra)
        {
            pnlLetras.Controls.Clear();
            txtPalabra.Text = "";

            for (int i = 0; i < longitudPalabra; i++)
            {
                Label lbl = new Label();
                lbl.Name = "lblLetra" + i.ToString();
                lbl.Text = "_";
                //lbl.Text = palabra[i].ToString().ToUpper();
                lbl.Font = new Font(FontFamily.GenericSansSerif, 14f, FontStyle.Bold);
                lbl.Location = new Point(3 + (27 * i), 10);
                lbl.Size = new Size(21, 25);
                lbl.TextAlign = ContentAlignment.MiddleCenter;
                lbl.BackColor = Color.FromKnownColor(KnownColor.ActiveCaption);
                pnlLetras.Controls.Add(lbl);
            }
        }

        //Método que se encarga de obtener de forma aleatoria una palabra de una
        //conjunto de ellas (un fichero de texto es la opción más razonable). De
        //momento, se utiliza un array de cadenas con algunas palabras para realizar
        //las pruebas iniciales.
        private String generarPalabra()
        {
            ArrayList listaPalabras = new ArrayList();
            String linea;
            OpenFileDialog ofd = new OpenFileDialog();
            Random rnd = new Random();

            //String[] palabras = new String[] {"murciélago", "palabra", "elefante" };

            StreamReader sr = new StreamReader(File.OpenRead("listaPalabras.txt"));
            while ((linea = sr.ReadLine()) != null)
            {
                listaPalabras.Add(linea);
            }
            return listaPalabras[rnd.Next(listaPalabras.Count)].ToString();
            //return palabras[rnd.Next(palabras.Length)];
        }

        private void limpiarMensaje()
        {
            lblMensaje.Text = "";
        }

        private void chkMostrarSolucion_CheckedChanged(object sender, EventArgs e)
        {
            if (chkMostrarSolucion.Checked == true)
            {
                txtSolucion.Visible = true;
            }
            else
            {
                txtSolucion.Visible = false;
            }
        }
    }
}