Percursos
/
Swift
Swift
/
Exercícios
/
Agente secreto Double-Null0111
Agente secreto Double-Null0111

Agente secreto Double-Null0111

Exercício de aprendizagem

Introdução

Tipos de função

Se retirares todos os nomes e etiquetas de uma assinatura de função em Swift, ficas apenas com o tipo da função.

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) -> ()

Repara que os tipos das duas primeiras funções são iguais, (String, Int) -> String, ainda que as assinaturas sejam diferentes e as duas funções façam coisas muito diferentes. Ambas recebem uma String e um Int como parâmetros de entrada e devolvem uma String. E, como se vê pelo tipo da terceira função, embora o corpo da função não pareça devolver nada, na verdade devolve implicitamente (), o único valor do tipo Void.

Estes tipos de função podem ser usados da mesma forma que qualquer outro tipo em Swift; por exemplo, podem ser usados na declaração de variáveis ou constantes. E, como em Swift as funções são valores, podes atribuir funções já existentes a essas constantes ou variáveis:

var stringAndIntToString: (String, Int) -> String

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

Tal como acontece com outras variáveis ou constantes, o valor que lhe atribuis tem de ser do tipo correto:

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

Tipos de função como tipos de parâmetros

Como os tipos de função podem ser usados em qualquer sítio onde se usem outros tipos, também podem ser usados como tipos de parâmetros, passados para outras funções e chamados a partir do interior dessas funções.

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 função como tipos devolvidos

Da mesma forma, os tipos de função podem ser usados como tipos devolvidos por funções. Por outras palavras, podes escrever funções que criam e devolvem outras funções. Ao criar estas funções, a função devolvida pode usar os outros parâmetros passados para a função ou as variáveis locais criadas dentro da função principal.

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

Instruções

Olá, Agente Double-Null0111.

A tua missão, se decidires aceitá-la, é escrever um par de ferramentas que te ajudem a infiltrar-te no quartel-general da UMBRA (Lacaios Unidos Realmente Horríveis) e a recuperar os planos do seu mais recente esquema verdadeiramente horrível. Vais precisar de duas ferramentas para levar a cabo esta missão.

1. Protege os planos secretos recuperados com uma palavra-passe

Depois de teres os planos secretos, vais precisar de os proteger para que só quem souber a palavra-passe os possa recuperar.

Para isso, vais precisar de implementar a função protectSecret(_ secret: String, withPassword password: String) -> (String) -> String. Esta função devolve outra função que recebe possíveis palavras-passe como parâmetros de entrada. Se a palavra-passe introduzida estiver correta, a nova função devolve o segredo escondido; mas se a palavra-passe estiver errada, a função devolve "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. Gera uma combinação para abrir o cofre

Descobrimos que a UMBRA baseia todas as combinações dos seus cofres no número da sala onde se encontram. As combinações dos cofres são geradas aplicando repetidamente uma função especial ao número da sala. Assim, o primeiro número da combinação vem de aplicar a função ao número da sala, o segundo vem de aplicar a função ao primeiro número e o terceiro vem de aplicar a função ao segundo número.

No entanto, a UMBRA muda regularmente a função usada para gerar as combinações, por isso a tua ferramenta vai precisar de receber tanto um número de sala como a função adequada para gerar a combinação.

Implementa a função generateCombination(forRoom room: Int, usingFunction f: (Int) -> Int) -> (Int, Int, Int) para gerar a combinação de que vais precisar.

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

generateCombination(forRoom: 227, usingFunction: makeCombo)
// Returns (135, 219, 31)
Editar via GitHub A ligação abre numa nova janela ou separador
Swift Exercism

Estás pronto para começar Agente secreto Double-Null0111?

Inscreve-te no Exercism para aprenderes e dominares Swift com 35 conceitos116 exercícios, e mentoria humana real, tudo grátis.