Mostrando entradas con la etiqueta java. Mostrar todas las entradas
Mostrando entradas con la etiqueta java. Mostrar todas las entradas

martes, 24 de septiembre de 2013

Método de cifrado inventado (en Android)

En este caso voy a publicar una pequeña aplicación muy parecida a la de la publicación anterior, al menos en apariencia. En este caso, la principal diferencia con respecto a la anterior radica en el algoritmo de cifrado que se aplica. Se trata de un método creado por mi mismo mezclando sustitución y transposición en el mismo algoritmo.
Este algoritmo consiste en dos pasos:

  •  Primero se sustituye cada carácter del mensaje por el correspondiente a su posición en el alfabeto con un desplazamiento 9 si se trata de una letra y 5 si es un dígito. En caso de ser otro carácter no se modificará.
  • En segundo lugar, divide el mensaje resultante de aplicar el proceso anterior en partes de 3 caracteres y se invierte el orden de los caracteres en cada grupo. Después se vuelven a agrupar y así se obtiene el mensaje final cifrado.
La implementación del algoritmo de cifrado/descifrado se hace en una clase independiente con lo que es muy fácil cambiar el algoritmo utilizado sin tener que modificar la interfaz de usuario, o haciendo cambios mínimos.
A continuación podéis ver el código y descargar un fichero para instalarla en un dispositivo Android.


package com.example.firstapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ");


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     
       
        Button btnConvertir = (Button)findViewById(R.id.btnConvertir);
        Button btnLimpiar = (Button)findViewById(R.id.btnLimpiar);
     
        final EditText etPlano = (EditText)findViewById(R.id.etPlano);
        final EditText etCifrado = (EditText)findViewById(R.id.etCifrado);
     
        btnLimpiar.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
etPlano.setText("");
etCifrado.setText("");
}
});
     
        btnConvertir.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
String textoPlano = etPlano.getText().toString();
String textoCifrado = etCifrado.getText().toString();
int txtLen = etPlano.length();
int cifrLen = etCifrado.length();

ECipherDecipher ecd = new ECipherDecipher();

if ((txtLen != 0) || (cifrLen !=0))
{
if (txtLen > 0)
{
String contenidoCifrado = ecd.cifrar(textoPlano);
etCifrado.setText(contenidoCifrado);
}
else
{
String contenidoPlano = ecd.descifrar(textoCifrado);
etPlano.setText(contenidoPlano);
}
}
}
});
    }

}

El código correspondiente a la implementación del algorirtmo se muestra en el código siguiente.

package com.example.firstapp;

public class ECipherDecipher {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ");
private final String abc2 = new String("0123456789");

//Definición del desplazamiento en la parte de cifrado por sustitución (César)
private int DESPLAZAMIENTO_CARACTERES = 9;
private int DESPLAZAMIENTO_DIGITOS = 5;

public ECipherDecipher()
{

}

public String cifrar(String cadena)
{
char caracterCifrado;
int posCaracterPlano;
int posCaracterCifrado;
int endPosSubCadena;
StringBuilder sbTextoIntermedio = new StringBuilder();
StringBuilder sbTextoCifrado = new StringBuilder();
StringBuilder subCadena3;

//Convertimos a mayúsculas
String texto = cadena.toUpperCase();

//Para cada caracter del texto
for (int i=0; i<texto.length(); i++)
{
char caracter = texto.charAt(i);
//Si es alfabético
if (Character.isLetter(caracter))
{
//Desplazamiento de cada carácter 9 posiciones
posCaracterPlano = abc.indexOf(caracter);
posCaracterCifrado = (posCaracterPlano + DESPLAZAMIENTO_CARACTERES) % abc.length();
caracterCifrado = abc.charAt(posCaracterCifrado);
sbTextoIntermedio.append(caracterCifrado);
}
else if (Character.isDigit(caracter))
{
//Si es numérico
//Desplazamiento de cada dígito 5 posiciones
posCaracterPlano = abc2.indexOf(caracter);
posCaracterCifrado = (posCaracterPlano + DESPLAZAMIENTO_DIGITOS) % abc2.length();
caracterCifrado = abc2.charAt(posCaracterCifrado);
sbTextoIntermedio.append(caracterCifrado);

}
else
{
//En otro caso no modificar el carácter
sbTextoIntermedio.append(caracter);
}
}

//Con el texto convertido anteriormente cogemos subcadenas de longitud 3
//y los invertimos.
while (sbTextoIntermedio.length()>0)
{
endPosSubCadena = 3;

if (sbTextoIntermedio.length()< 3)
{
endPosSubCadena = sbTextoIntermedio.length();
}
subCadena3 = new StringBuilder(sbTextoIntermedio.substring(0, endPosSubCadena));
sbTextoIntermedio = sbTextoIntermedio.delete(0, endPosSubCadena);
subCadena3 = subCadena3.reverse();
sbTextoCifrado.append(subCadena3);
}

return sbTextoCifrado.toString();
}

public String descifrar(String texto)
{
char caracterDescifrado;
int posCaracterCifrado;
int posCaracterDescifrado;
int endPosSubCadena;
StringBuilder sbTextoIntermedio = new StringBuilder();
StringBuilder sbTextoCifrado = new StringBuilder();
StringBuilder sbTextoPlano = new StringBuilder();
StringBuilder subCadena3;

sbTextoCifrado = new StringBuilder(texto.toUpperCase());

//Con el texto cogemos subcadenas de longitud 3 y los invertimos.
while (sbTextoCifrado.length()>0)
{
//Posición de fin de la subcadena
endPosSubCadena = 3;

if (sbTextoCifrado.length()< 3)
{
endPosSubCadena = sbTextoCifrado.length();
}
subCadena3 = new StringBuilder(sbTextoCifrado.substring(0, endPosSubCadena));
sbTextoCifrado = sbTextoCifrado.delete(0, endPosSubCadena);
subCadena3 = subCadena3.reverse();
sbTextoIntermedio.append(subCadena3);
}

//Para cada caracter del texto
texto = sbTextoIntermedio.toString();

for (int i=0; i<texto.length(); i++)
{

char caracter = texto.charAt(i);
//Si es alfabético
if (Character.isLetter(caracter))
{
//Desplazamiento de cada carácter -9 posiciones
posCaracterCifrado = abc.indexOf(caracter);
posCaracterDescifrado = (posCaracterCifrado - DESPLAZAMIENTO_CARACTERES +
(abc.length())) % abc.length();
caracterDescifrado = abc.charAt(posCaracterDescifrado);
sbTextoPlano.append(caracterDescifrado);
}
else if (Character.isDigit(caracter))
{
//Si es numérico
//Desplazamiento de cada dígito -5 posiciones
posCaracterCifrado = abc2.indexOf(caracter);
posCaracterDescifrado = (posCaracterCifrado - DESPLAZAMIENTO_DIGITOS +
(abc2.length())) % abc2.length();
caracterDescifrado = abc2.charAt(posCaracterDescifrado);
sbTextoPlano.append(caracterDescifrado);
}
else
{
//En otro caso no modificar el carácter
sbTextoPlano.append(caracter);
}
}

return sbTextoPlano.toString();
}
}

La apariencia de la aplicación es casi igual a la de la aplicación descrita en la entrada anterior del blog.


El fichero de instalación se puede descargar aquí.

Cifrado César (aplicación en Android)

En esta entrada voy a mostrar una pequeña aplicación que permite cifrar mensajes utilizando el método César. Del mismo modo, permite descifrar los mensajes cifrados utilizando el proceso inverso. En este caso la interfaz de usuario es muy sencilla, la parte un poco más compleja es el código que realiza las operaciones de cifrado/descifrado.
A continuación os muestro el código y alguna imagen de la aplicación en funcionamiento. En primer lugar se muestra el código correspondiente a la actividad principal.

package com.example.firstapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;

public class MainActivity extends Activity {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ");
private int desplazamiento = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     
        Spinner spin1 = (Spinner)findViewById(R.id.spin1);
     
        ArrayAdapter<CharSequence> adaptador = ArrayAdapter.createFromResource(this, R.array.desplazamientos,
        android.R.layout.simple_spinner_item);
        adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spin1.setAdapter(adaptador);
     
     
        Button btnConvertir = (Button)findViewById(R.id.btnConvertir);
        Button btnLimpiar = (Button)findViewById(R.id.btnLimpiar);
     
        final EditText etPlano = (EditText)findViewById(R.id.etPlano);
        final EditText etCifrado = (EditText)findViewById(R.id.etCifrado);
     
        btnLimpiar.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
etPlano.setText("");
etCifrado.setText("");
}
});
     
        etCifrado.setOnKeyListener(new EditText.OnKeyListener() {
@Override
public boolean onKey(View arg0, int arg1, KeyEvent arg2) {
if (etPlano.getText().toString().compareTo("") != 0)
{
etPlano.setText("");
}
return false;
}
        });
     
        spin1.setOnItemSelectedListener(new OnItemSelectedListener() {

@Override
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
desplazamiento = pos;
}

@Override
public void onNothingSelected(AdapterView<?> arg0) {
desplazamiento = 0;
}
       
        });
     
        btnConvertir.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
String textoPlano = etPlano.getText().toString();
String textoCifrado = etCifrado.getText().toString();
int txtLen = etPlano.length();
int cifrLen = etCifrado.length();
CifradorDescifradorSustitucion cifDecif = new CifradorDescifradorSustitucion(desplazamiento);

if ((txtLen != 0) || (cifrLen !=0))
{
if (txtLen > 0)
{
String contenidoCifrado = cifDecif.cifrar(textoPlano);
etCifrado.setText(contenidoCifrado);
}
else
{
String contenidoPlano = cifDecif.descifrar(textoCifrado);
etPlano.setText(contenidoPlano);
}
}
}
});
    }

}

En segundo lugar se muestra el código de la clase dónde se implementa el cifrado y descifrado mediante el método César.

package com.example.firstapp;

public class CifradorDescifradorSustitucion {
private final String abc = new String("ABCDEFGHIJKLMNÑOPQRSTUVWXYZ0123456789");

private int desplazamiento;
private String textoPlano;
private String textoCifrado;

public CifradorDescifradorSustitucion() {
desplazamiento = 0;
}

public CifradorDescifradorSustitucion(int desplazamiento) {
this.desplazamiento = desplazamiento;
}

public String descifrar(String textoCifrado) {
char caracterCifrado = ' ';
char caracterPlano = ' ';

textoCifrado = textoCifrado.toUpperCase();
StringBuilder textoPlano = new StringBuilder(textoCifrado.length());

for (int i = 0; i < textoCifrado.length(); i++) {
caracterCifrado = textoCifrado.charAt(i);
if (abc.contains(String.valueOf(caracterCifrado))) {
int posCaracterCifrado = abc.indexOf(caracterCifrado);
int posCaracterPlano = ((posCaracterCifrado - desplazamiento) + (abc
.length() + 1)) % (abc.length());
caracterPlano = abc.charAt(posCaracterPlano);
} else {
caracterPlano = caracterCifrado;
}
textoPlano.append(caracterPlano);
}

return textoPlano.toString();
}

public String cifrar(String textoPlano) {
char caracterCifrado = ' ';
char caracterPlano = ' ';

textoPlano = textoPlano.toUpperCase();
StringBuilder textoCifrado = new StringBuilder(textoPlano.length());

for (int i = 0; i < textoPlano.length(); i++) {
caracterPlano = textoPlano.charAt(i);
if (abc.contains(String.valueOf(caracterPlano))) {
int posCaracterPlano = abc.indexOf(caracterPlano);
int posCaracterCifrado = (posCaracterPlano + desplazamiento)
% (abc.length());
caracterCifrado = abc.charAt(posCaracterCifrado);
} else {
caracterCifrado = caracterPlano;
}
textoCifrado.append(caracterCifrado);
}
return textoCifrado.toString();
}

public int getDesplazamiento() {
return desplazamiento;
}

public void setDesplazamiento(int desplazamiento) {
this.desplazamiento = desplazamiento;
}

public String getTextoPlano() {
return textoPlano;
}

public void setTextoPlano(String textoPlano) {
this.textoPlano = textoPlano;
}

public String getTextoCifrado() {
return textoCifrado;
}

public void setTextoCifrado(String textoCifrado) {
this.textoCifrado = textoCifrado;
}

}

Por último se puede ver el código xml correspondiente al layout (muy sencillo como ya comenté anteriormente).

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Spinner
        android:id="@+id/spin1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/textView3"
        android:layout_below="@+id/textView1" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:text="@string/titulo_spin1" />

    <EditText
        android:id="@+id/etPlano"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/textView2"
        android:ems="10"
        android:hint="Texto plano aquí..."
        android:lines="4" >

        <requestFocus />
    </EditText>

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/etCifrado"
        android:layout_below="@+id/etPlano"
        android:layout_marginTop="45dp"
        android:text="@string/texto_cifrado" />

    <EditText
        android:id="@+id/etCifrado"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/etPlano"
        android:layout_below="@+id/textView3"
        android:ems="10"
        android:hint="Texto cifrado aquí..."
        android:lines="4" />

    <Button
        android:id="@+id/btnConvertir"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/etCifrado"
        android:layout_below="@+id/etCifrado"
        android:layout_marginTop="17dp"
        android:layout_toRightOf="@+id/textView3"
        android:text="@string/convertir" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/spin1"
        android:layout_below="@+id/spin1"
        android:text="@string/texto_plano" />

    <Button
        android:id="@+id/btnLimpiar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/btnConvertir"
        android:layout_alignBottom="@+id/btnConvertir"
        android:layout_alignLeft="@+id/etCifrado"
        android:text="Limpiar" />

</RelativeLayout>

El archivo de instalación podéis descargarlo aquí.

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);
    }
}