Tracks
/
Swift
Swift
/
Ejercicios
/
Agente secreto Double-Null0111
Agente secreto Double-Null0111

Agente secreto Double-Null0111

Ejercicio de aprendizaje

Introducción

Tipos de función

Si quitas todos los nombres y las etiquetas de la firma de una función de Swift, te queda el tipo de la función.

func shoppingList(item: String, quantity: Int) -> String {
  "You need to buy \(quantity) \(item)."
}
// shoppingList: (String, Int) -> String

func repeater(_ phrase: String, times: Int) -> String {
  var result = ""
  for _ in 1...times {
    result += phrase
  }
  return result
}
// repeater: (String, Int) -> String

func printString(line: String) {
  print(line)
}
// printString: (String) -> ()

Fíjate que los tipos de las dos primeras funciones son el mismo, (String, Int) -> String, aunque las firmas son diferentes y las dos funciones actúan de maneras muy distintas. Ambas reciben un String y un Int como argumentos y devuelven un String. Y, como se puede ver en el tipo de la tercera función, aunque el cuerpo de la función no parece devolver nada, en realidad devuelve () de forma implícita, el único valor del tipo Void.

Estos tipos de función se pueden usar de la misma manera que cualquier otro tipo de Swift; por ejemplo, se pueden usar en la declaración de variables o constantes. Y como las funciones son valores en Swift, puedes asignar funciones que ya existen a esas constantes o variables:

var stringAndIntToString: (String, Int) -> String

stringAndIntToString = shoppingList
stringAndIntToString("carrots", 3)
// => "You need to buy 3 carrots."

Igual que con otras variables o constantes, el valor que le asignas debe ser del tipo correcto:

stringAndIntToString = printShoppingList
// Error: Cannot assign value of type '(String) -> ()' to type '(String, Int) -> String'

Tipos de función como tipos de parámetro

Como los tipos de función se pueden usar en cualquier lugar donde se pueda usar otro tipo, se deduce que también se pueden usar como tipos de parámetro, pasar a otras funciones y llamar desde dentro de esas funciones.

func apply3(to str: String, function f: (String, Int) -> String) -> String {
  f(str,3)
}
// apply3: ([String], (String, Int) -> String) -> [String]

apply3(to: "eggs", function: shoppingList)
// => "You need to buy 3 eggs."

apply3(to: "eggs", function: repeater)
// => "eggseggseggs"

Tipos de función como tipos de retorno

De manera similar, los tipos de función se pueden usar como tipos de retorno de las funciones. En otras palabras, puedes escribir funciones que crean y devuelven otras funciones. Al crear estas funciones, la función que se devuelve puede usar los otros parámetros que se pasan a la función o las variables locales creadas dentro de la función padre.

func makeAdder(base: Int) -> (Int) -> Int {
  func adder(_ i: Int) -> Int {
    base + i
  }
  return adder
}
// makeAdder: (Int) -> (Int) -> Int

let add10 = makeAdder(base: 10)
// add10: (Int) -> Int

let subtract20 = makeAdder(base: -20)
// subtract10: (Int) -> Int

add10(5)
// => 15

subtract20(5)
// => -15

Instrucciones

Hola, Agente Double-Null0111.

Tu misión, si decides aceptarla, es escribir un par de herramientas que te ayuden a infiltrarte en el cuartel general de UMBRA (Secuaces Unidos Que Son Realmente Horribles) y recuperar los planos de su última y realmente espantosa maquinación. Necesitarás dos herramientas para llevar a cabo esta misión.

1. Protege los planos secretos recuperados con una contraseña

Una vez que tengas los planos secretos, tendrás que protegerlos para que solo quienes conocen la contraseña puedan recuperarlos.

Para lograrlo, tendrás que implementar la función protectSecret(_ secret: String, withPassword password: String) -> (String) -> String. Esta función devolverá otra función que recibe posibles strings de contraseña como argumentos. Si la contraseña que ingresas es correcta, la nueva función devuelve el secreto oculto; pero si la contraseña es incorrecta, la función devuelve «Sorry. No hidden secrets here.»

let secretFunction = protectSecret("Steal the world's supply of french fries!", withPassword: "5up3r53cr37")

secretFunction("Open sesame")
// Returns "Sorry. No hidden secrets here."

secretFunction("5up3r53cr37")
// Returns "Steal the world's supply of french fries!"

2. Genera una combinación para abrir su caja fuerte

Hemos descubierto que UMBRA basa todas las combinaciones de sus cajas fuertes en el número de la sala en la que se encuentran. Las combinaciones de las cajas fuertes se generan aplicando repetidamente una función especial al número de la sala. Así, el primer número de la combinación saldrá de aplicar la función al número de la sala, el segundo de aplicar la función al primer número y el tercero de aplicar la función al segundo número.

Sin embargo, UMBRA cambia con frecuencia la función que se usa para generar las combinaciones, así que tu herramienta tendrá que recibir tanto un número de sala como la función adecuada para generar la combinación.

Implementa la función generateCombination(forRoom room: Int, usingFunction f: (Int) -> Int) -> (Int, Int, Int) para generar la combinación que necesitarás.

func makeCombo(_ x: Int) -> Int {
  (x * 13) % 256
}

generateCombination(forRoom: 227, usingFunction: makeCombo)
// Returns (135, 219, 31)
Editar en GitHub El enlace se abre en una ventana o una pestaña nuevas
Swift Exercism

¿Todo listo para empezar Agente secreto Double-Null0111?

Regístrate en Exercism para aprender y dominar Swift con 35 conceptos116 ejercicios y mentoría humana real, todo gratis.