-
-
Save jonasurbano/02bdeb5402e97f2f6045 to your computer and use it in GitHub Desktop.
Código para determinar si la respuesta del usuario introduciendo la definición de una palabra es correcta. Explicado en el blog: kcy.me/10eh2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.text.Normalizer; | |
import java.text.Normalizer.Form; | |
import java.util.ArrayList; | |
import java.util.List; | |
public class JuegoAdivinarDefinicion { | |
private static final String REGEX_SEPARAR_PALABRAS = "\\s\\W*|\\W\\s*"; | |
private static final double FACTOR_UMBRAL = 0.66; | |
private List<String> definiciones; | |
public JuegoAdivinarDefinicion() { | |
definiciones = new ArrayList<String>(); | |
} | |
public void anadirDefinicion(String definicion) { | |
definiciones.add(definicion); | |
} | |
/** | |
* Una definición es correcta si presenta más del 66% | |
* de palabras con una distancia hamming máxima de 1. | |
*/ | |
protected boolean esCorrecta(String respuesta) { | |
String[] palabrasRespuesta = removeDiacriticalMarks(respuesta) | |
.trim().split(REGEX_SEPARAR_PALABRAS); | |
String[] palabrasDefCandidata; | |
for (String definicion : definiciones) { | |
palabrasDefCandidata = removeDiacriticalMarks(definicion) | |
.trim().split(REGEX_SEPARAR_PALABRAS); | |
if (respuestaParecida(palabrasDefCandidata, palabrasRespuesta)) | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Determina si la respuesta del usuario es parecida a | |
* la definición candidata | |
*/ | |
private boolean respuestaParecida(String[] defCandidata,String[] respuesta) { | |
List<Integer> minimosPorPalabraDef = new ArrayList<Integer>(); | |
List<Integer> distancias; | |
for (String palabra : defCandidata) { | |
distancias = new ArrayList<Integer>(); | |
for (String palabraRespuesta : respuesta) { | |
distancias.add(distanciaHamming(palabra,palabraRespuesta)); | |
} | |
minimosPorPalabraDef.add(minimo(distancias)); | |
} | |
return evaluarMinimos(minimosPorPalabraDef); | |
} | |
private Integer minimo(List<Integer> distancias) { | |
if (distancias.isEmpty()) return Integer.valueOf(Integer.MAX_VALUE); | |
int minimo = distancias.get(0); | |
for (int i = 1; i < distancias.size(); i++) | |
if (distancias.get(i) < minimo) | |
minimo = distancias.get(i); | |
return Integer.valueOf(minimo); | |
} | |
/** | |
* Evalúa la lista de mínimos para determinar si | |
* la respuesta del usuario coincide con la definición. | |
* Criterios: | |
* - Si la definición candidata es de 1 sóla palabra, | |
* el usuario tiene que introducirla correctamente. | |
* - Si la def. candidata es de 2 palabras, el usuario | |
* puede cometer un fallo de d. Hamming 3 como máximo | |
* en una de las palabras. | |
* - Para definiciones de más de 2 palabras, el usuario | |
* tiene que cometer fallos como máximo de d. Hamming 1 | |
* en más del 66% del número de palabras. | |
* Ej. si la definición es de 10 palabras, el usuario | |
* puede cometer fallos como mucho de d. Hamming 1 en | |
* 7 palabras. | |
* @param minimos lista de las mínimas distancias | |
* Cada valor de minimos es el mínimo de la distancia | |
* entre una palabra de la definición y las palabras de | |
* la respuesta | |
*/ | |
private boolean evaluarMinimos(List<Integer> minimos) { | |
int numPalabrasRespuesta = minimos.size(); | |
if (numPalabrasRespuesta == 0) | |
return false; | |
else if (numPalabrasRespuesta == 1) { | |
return minimos.get(0) == 0; | |
} else if (numPalabrasRespuesta == 2) { | |
if (minimos.get(0) != 0 && minimos.get(1) != 0) return false; | |
int suma = minimos.get(0) + minimos.get(1); | |
return suma <= 3; | |
} else { | |
double umbral = minimos.size() * FACTOR_UMBRAL; | |
return minimosMenores2(minimos) > umbral; | |
} | |
} | |
/** | |
* Devuelve el número de mínimos menores | |
* que 2 en {@code minimos} | |
*/ | |
private double minimosMenores2(List<Integer> minimos) { | |
int numMenores2 = 0; | |
for (Integer minimo : minimos) | |
if (minimo < 2) numMenores2++; | |
return numMenores2; | |
} | |
public static int distanciaHamming(String palabra1, String palabra2) { | |
//Si la longitud de las cadenas es diferente, s1 contendrá la mayor | |
char[] s1, s2; | |
if (palabra2.length() > palabra1.length()) { | |
s1 = palabra2.toCharArray(); | |
s2 = palabra1.toCharArray(); | |
} else { | |
s1 = palabra1.toCharArray(); | |
s2 = palabra2.toCharArray(); | |
} | |
int result = 0, i = 0; | |
while (i < s2.length) { | |
if (s1[i] != s2[i]) { | |
if (s1.length > s2.length && i > 0 && s1[i-1] != s2[i-1]) { | |
s1 = eliminarCaracter(s1,i); | |
continue; | |
} | |
result++; | |
} | |
i++; | |
} | |
result += s1.length - s2.length; | |
System.out.println("Distancia hamming: " + result); | |
return result; | |
} | |
private static char[] eliminarCaracter(char[] palabra, int posicion) { | |
char[] nuevaPalabra = new char[palabra.length - 1]; | |
for (int i = 0; i < posicion; i++) nuevaPalabra[i] = palabra[i]; | |
for (int i = posicion; i < nuevaPalabra.length; i++) nuevaPalabra[i] = palabra[i+1]; | |
return nuevaPalabra; | |
} | |
private static String removeDiacriticalMarks(String string) { | |
return Normalizer.normalize(string,Form.NFD) | |
.replaceAll("\\p{InCombiningDiacriticalMarks}+", ""); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import static org.junit.Assert.assertFalse; | |
import static org.junit.Assert.assertTrue; | |
import org.junit.Test; | |
public class JuegoAdivinarDefinicionTest { | |
private JuegoAdivinarDefinicion j; | |
@Test | |
public void PalabraLongitud1() { | |
j = new JuegoAdivinarDefinicion(); | |
j.anadirDefinicion("house"); | |
assertTrue(j.esCorrecta("house")); | |
assertFalse(j.esCorrecta("housa")); | |
} | |
@Test | |
public void PalabraLongitud2() { | |
j = new JuegoAdivinarDefinicion(); | |
j.anadirDefinicion("starting point"); | |
assertTrue(j.esCorrecta("starting point")); | |
assertTrue(j.esCorrecta("start point")); | |
assertTrue(j.esCorrecta("start point")); | |
assertTrue(j.esCorrecta("stert point")); | |
assertFalse(j.esCorrecta("where you start")); | |
assertFalse(j.esCorrecta("start paint")); | |
} | |
@Test | |
public void Palabraslongitud3() { | |
j = new JuegoAdivinarDefinicion(); | |
j.anadirDefinicion("very good ending"); | |
assertTrue(j.esCorrecta("very good ending")); | |
assertTrue(j.esCorrecta("veri good end")); | |
assertTrue(j.esCorrecta("very good end")); | |
assertFalse(j.esCorrecta("success")); | |
assertFalse(j.esCorrecta("beri good end")); | |
j = new JuegoAdivinarDefinicion(); | |
j.anadirDefinicion("grab my attention"); | |
assertTrue(j.esCorrecta("grab my attention")); | |
assertTrue(j.esCorrecta("grab the attention")); | |
assertTrue(j.esCorrecta("grab the atention")); | |
j = new JuegoAdivinarDefinicion(); | |
j.anadirDefinicion("who after prep"); | |
assertTrue(j.esCorrecta("who after prep")); | |
assertTrue(j.esCorrecta("who after preposition")); | |
j = new JuegoAdivinarDefinicion(); | |
j.anadirDefinicion("estrecho, escaso, limitado"); | |
assertTrue(j.esCorrecta("estrecho escaso")); | |
assertFalse(j.esCorrecta("estrecho")); | |
j = new JuegoAdivinarDefinicion(); | |
j.anadirDefinicion("estrecho-escaso;limitado"); | |
assertTrue(j.esCorrecta("estrecho escaso")); | |
assertFalse(j.esCorrecta("estrecho")); | |
} | |
@Test | |
public void VariasDefiniciones() { | |
j = new JuegoAdivinarDefinicion(); | |
j.anadirDefinicion("captar mi atención"); | |
j.anadirDefinicion("distraerme"); | |
j.anadirDefinicion("grab my attention"); | |
assertTrue(j.esCorrecta("grab attention")); | |
assertTrue(j.esCorrecta("grab my attention")); | |
assertTrue(j.esCorrecta("grab the attention")); | |
assertTrue(j.esCorrecta("grab the atention")); | |
} | |
@Test | |
public void masTests() { | |
// Gist | |
j = new JuegoAdivinarDefinicion(); | |
j.anadirDefinicion("the main points (of an argument etc)"); | |
assertTrue(j.esCorrecta("the main points of an argument")); | |
assertTrue(j.esCorrecta("the main points of a argument")); | |
assertFalse(j.esCorrecta("da main points of a row")); | |
// Wildcard | |
j = new JuegoAdivinarDefinicion(); | |
j.anadirDefinicion("carácter (comodín)"); | |
assertTrue(j.esCorrecta("carácter ( comodín )")); | |
assertTrue(j.esCorrecta("carácter comodín")); | |
assertFalse(j.esCorrecta("carácter")); | |
// Fickle | |
j = new JuegoAdivinarDefinicion(); | |
j.anadirDefinicion("caprichoso"); | |
assertTrue(j.esCorrecta("caprichoso")); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment