Curso Kotlin | #19. Pair
Tags: spanish, kotlin, beginners, programming
Published: 2022-12-15 14:21:28

Bienvenido/a a otro capítulo del Curso de Kotlin! Podés consultar el curso completo desde [este link](https://github.com/maxwellnewage/kotlin-course) que te dejo acá. Podés seguirme por [LinkedIn](https://www.linkedin.com/in/maximilianoburgos/) o [Twitter](https://twitter.com/maxwellnewage) si querés estar al tanto de las próximas publicaciones.

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:

```kotlin
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.

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

Para accederlo, existen dos atributos llamados first y second:

```kotlin
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:

```kotlin
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:

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

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

```kotlin
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:

```kotlin
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:

```kotlin
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:

```kotlin
val input = readLine()?.toInt()
```

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

```kotlin
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:

```kotlin
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.

```kotlin
} 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!