Curso Kotlin | #19. Pair

A veces necesitamos relacionar dos valores y almacenarlos en una variable única, y para ello tenemos a Pair.

La estructura de Pair es muy sencilla. Imaginemos que necesitamos almacenar el nombre y apellido de una persona. Esto implica dos valores de tipo String. Por lo cual, lo podemos hacer de la siguiente manera:

val person = Pair<String, String>("Maxwell", "Tompson")

En principio, Pair nos pide que especifiquemos los tipos de datos que se van a almacenar en la variable; algo similar a la vez que estudiamos arrays. Luego, por parametro inicializamos el mismo, pasándole nuestros dos elementos. Podemos quitar “<String, String>” porque Kotlin, al leer los parámetros que introducimos, infiere el tipo necesario.

val person = Pair("Maxwell", "Tompson")

Para accederlo, existen dos atributos llamados first y second:

println("Hola ${person.first} ${person.second}")
output: Hola Maxwell Tompson

Como ven, la utilización de Pair es extremadamente sencilla, pero útil. Podemos utilizarla en el contexto de una lista de variables, por ejemplo:

val persons = arrayOf(
    Pair("Maxwell", "Tompson"),
    Pair("Tomas", "Voltor"),
)

println("Hola ${persons[0].first} ${persons[0].second}")

¡Termina el corte publicitario!

Ahora que les he demostrado (y promocionado) el poder de Pair, volvamos a nuestro juego para darle la forma final a la funcionalidad del diálogo. En principio cambiaremos cada array de respuesta por un Pair, de la siguiente manera:

Pair(1, "1. Si, soy nuev@")

Habrá que hacerlo con cada uno, pero les voy a dejar el trabajo final:

val conversation = arrayOf(
    arrayOf(
        "Bienvenido a Pueblo Ceniza! Eres nuev@ por aqui?",
        arrayOf(
            Pair(1, "1. Si, soy nuev@"),
            Pair(2, "2. No es mi primer visita!")
        )
    ),
    arrayOf(
        "Espero que puedas hacer nuevos amigos!",
        arrayOf(
            Pair(0, "0. Gracias!")
        )
    ),
    arrayOf(
        "Ya me parecía que tu nombre me resultara conocido!",
        arrayOf(
            Pair(0, "0. Gracias!")
        )
    ),
)

Cada first de nuestros Pair va a llevar la referencia de la posición a la que saltará cuando se seleccione esa respuesta; y cada second contendrá el String de la respuesta en si misma. Esto es, en efecto, un Pair<Int, String>(). Una vez terminada de modificar nuestra variable de conversaciones, vamos al método letsTalk. Primero modificaremos la variable responses, porque ya no es un array de arrays:

val responses = conversation[line][1] as Array<Pair<Int, String>>

Ahora es un arreglo de Pair, y esto nos resultará sencillo de tratar en nuestra iteración de respuestas:

for(res in responses) {
    println(res.second)
}

El problema radica en que nosotros no tenemos una referencia a cada res.first para llevarnos la posición de la pregunta siguiente, pero esto lo solucionaremos pronto. En principio, dentro de nuestro try vamos a solicitar el input y convertirlo a un entero:

val input = readLine()?.toInt()

Luego utilizaremos una lambda function para buscar si el número que utilizamos existe dentro de nuestro array de pares:

val isFound = responses.any { term -> term.first == input }

Profundizaremos en el concepto de este tipo de funciones más adelante. Ahora tenemos una variable booleana isFound, la cual nos da la información de si se encontró o no la respuesta, y por ello vamos a armar su debido condicional:

if(isFound) {
    letsTalk(input!!)
} else {
    throw Exception()
}

Si la encuentra, enviará la respuesta por parámetro de nuestra llamada recursiva. Necesitamos el bang bang operator porque readLine() devuelve un String Nullable, pero sabemos que no fallará porque se encontró el valor entero en la lista, gracias a la función any. En caso contrario, lanzamos una excepción para evitar código repetido (principio DRY), lo cual nos llevará al catch.

} catch (e: Exception) {
    println("No has respondido mi pregunta...")
    letsTalk(line)
}

Aquí devolvemos un mensaje y llamamos recursivamente a nuestra función con el mismo parámetro para repetir la pregunta.

Conclusiones

¡Felicidades! Ahora tenemos un sistema de diálogos funcionando dinámicamente. Podés agregarle todas las preguntas y respuestas que quieras para ir navegando y testeando cada proceso de la misma. Lo siguiente será generar ciertos eventos entre los diálogos, como por ejemplo gastar dinero, puntos de vida, u otros atributos del heroe. ¡Se vienen tópicos muy interesantes!

¡Deja un comentario!

Artículos relacionados

Curso Kotlin | #17. Proyecto: The Hero Legacy

Si empezaste esta serie desde cero y ya leíste 16 capítulos, ¡Felicidades! Empezaste a dominar los primeros conceptos fundamentales en Kotlin. Este es el primer paso de tu senda como desarrollador/a. Estamos en una instancia en donde podemos poner en práctica todo lo que aprendiste hasta ahora. Bienvenido/a al primer proyecto de la serie.

Curso Kotlin | #16. Funciones

Las funciones son procedimientos que se pueden reutilizar y nos permiten encapsular comportamientos y mejorar la lectura del código.

Curso Kotlin | #15. Excepciones

Las excepciones en Kotlin nos permiten evitar comportamientos no deseados ante problemas que se presentan en tiempo de ejecución. Por ejemplo cuando se intenta dividir por cero, castear un tipo por otro no válido, intentar agregar un valor a una lista nula, entre otros casos. Hoy vamos a ver su implementación en el código.

Curso Kotlin | #14. Rangos

Cuando hablamos de rangos, nos referimos a un intervalo de números en el sentido matemático. Podemos generar, por ejemplo, un rango que comprenda los números del 1 al 10. Hoy veremos como aplicarlo a los conceptos anteriormente aprendidos.

Curso Kotlin | #13. Bucle For

El bucle For es uno de los más utilizados por todos los lenguajes de programación. Nos permite recorrer arrays y listas, como también generar iteraciones con un límite contabilizado. Vamos a verlo en detalle.