Skip to content

Commit

Permalink
Update Secret Agent exercise to use Swift 6.0 and improve documentati…
Browse files Browse the repository at this point in the history
…on clarity
  • Loading branch information
meatball133 committed Jan 26, 2025
1 parent 3c46168 commit ae1f583
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 52 deletions.
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
"higher-order-functions"
],
"prerequisites": [
"basics"
"optionals"
],
"status": "active"
},
Expand Down
18 changes: 10 additions & 8 deletions exercises/concept/secret-agent/.docs/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,35 @@ Your mission, should you choose to accept it, is to write a pair of tools to hel

Once you have the secret plans, you will need to protect it so that only those who know the password can recover them.

In order to do this, you will need to implement the function
`protectSecret(_ secret: String, withPassword password: String) -> (String) -> String`. This function will return another function that takes possible password strings as input. If the entered password is correct the new function returns the hidden secret, but if it is the incorrect password the function returns "Sorry. No hidden secrets here."
In order to do this, you will need to implement the function `protectSecret(_ secret: String, withPassword password: String) -> (String) -> String`.
This function will return another function that takes possible password strings as input.
If the entered password is correct the new function returns the hidden secret, but if it is the incorrect password the function returns "Sorry. No hidden secrets here."

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

secretFunction("Open sesame")
// => "Sorry. No hidden secrets here."
// returns "Sorry. No hidden secrets here."

secretFunction("5up3r53cr37")
// => "Steal the world's supply of french fries!"
// returns "Steal the world's supply of french fries!"
```

## 2. Generate a combination to open their safe

We have learned that UMBRA bases all of their safe combinations on the number of the room they are located in. The safe combinations are generated by repeatedly applying a special function to the room number. So the first number of the combination will come from applying the function to the room number, the second will come from applying the function to the first number, and the third from applying the function to the second number.
We have learned that UMBRA bases all of their safe combinations on the number of the room they are located in.
The safe combinations are generated by repeatedly applying a special function to the room number.
So the first number of the combination will come from applying the function to the room number, the second will come from applying the function to the first number, and the third from applying the function to the second number.

However, UMBRA regularly changes the function used to generate the combinations, so your tool will need to take both a room number and the appropriate function in order to generate the combination.

Implement the function
`generateCombination(forRoom room: Int, usingFunction f: (Int) -> Int) -> (Int, Int, Int)` to generate the combination you will need.
Implement the function `generateCombination(forRoom room: Int, usingFunction f: (Int) -> Int) -> (Int, Int, Int)` to generate the combination you will need.

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

generateCombination(forRoom: 227, usingFunction: makeCombo)
// => (135, 219, 31)
// returns (135, 219, 31)
```
44 changes: 22 additions & 22 deletions exercises/concept/secret-agent/Package.swift
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
// swift-tools-version:5.3
// swift-tools-version:6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "SecretAgent",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "SecretAgent",
targets: ["SecretAgent"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "SecretAgent",
dependencies: []),
.testTarget(
name: "SecretAgentTests",
dependencies: ["SecretAgent"]),
]
name: "SecretAgent",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "SecretAgent",
targets: ["SecretAgent"])
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "SecretAgent",
dependencies: []),
.testTarget(
name: "SecretAgentTests",
dependencies: ["SecretAgent"]),
]
)
Original file line number Diff line number Diff line change
@@ -1,37 +1,33 @@
import XCTest
import Foundation
import Testing

@testable import SecretAgent

final class SecretAgentTests: XCTestCase {
let runAll = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false
let RUNALL = Bool(ProcessInfo.processInfo.environment["RUNALL", default: "false"]) ?? false

@Suite struct SecretAgentTests {
let protected = protectSecret(
"UMBRA will fill everyone's sugar bowls with salt!", withPassword: "P455w0rd")

@Test("password success")
func testPasswordSuccess() {
XCTAssertEqual(protected("P455w0rd"), "UMBRA will fill everyone's sugar bowls with salt!")
#expect(protected("P455w0rd") == "UMBRA will fill everyone's sugar bowls with salt!")
}

func testPasswordFail() throws {
try XCTSkipIf(true && !runAll) // change true to false to run this test
XCTAssertEqual(protected("hunter2"), "Sorry. No hidden secrets here.")
@Test("password fail", .enabled(if: RUNALL))
func testPasswordFail() {
#expect(protected("hunter2") == "Sorry. No hidden secrets here.")
}

func testCombination1() throws {
try XCTSkipIf(true && !runAll) // change true to false to run this test
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
@Test("combination 1", .enabled(if: RUNALL))
func testCombination1() {
let combo = generateCombination(forRoom: 1, usingFunction: { ($0 * 127 + 19) % 256 })
XCTAssertTrue(combo == (146, 129, 18))
#expect(combo == (146, 129, 18))
}

func testCombination2() throws {
try XCTSkipIf(true && !runAll) // change true to false to run this test
let combo = generateCombination(
forRoom: 1,
usingFunction: {
($0 * 73 + 161) % 256
})
XCTAssertTrue(combo == (234, 91, 148))
@Test("combination 2", .enabled(if: RUNALL))
func testCombination2() {
let combo = generateCombination(forRoom: 1, usingFunction: { ($0 * 73 + 161) % 256 })
#expect(combo == (234, 91, 148))
}
}

0 comments on commit ae1f583

Please sign in to comment.