(please scroll within the code cite to see full input):
var gathered = 0
func setGather(initialOrient: String) {
var targetPortal = greenPortal
if initialOrient == "left" {
targetPortal = greenPortal
} else {
targetPortal = orangePortal
}
func orientationTurn() {
if initialOrient == "left" {
turnLeft()
} else {
turnRight()
}
}
func gather(target: Int) {
gathered = 0
moveForward()
while target > gathered {
if isOnGem {
collectGem()
gathered += 1
} else if isOnClosedSwitch {
toggleSwitch()
gathered += 1
} else { // core gather loop
orientationTurn()
orientationTurn()
moveForward()
orientationTurn()
moveForward()
}
}
orientationTurn()
orientationTurn()
}
orientationTurn()
moveForward()
moveForward()
targetPortal.isActive.toggle() // off for "X" gather
gather(target: 4) // “X” gather
targetPortal.isActive.toggle() // on to leave
moveForward()
targetPortal.isActive.toggle() // off for "L" gather
orientationTurn()
orientationTurn()
gather(target: 2) // “L” gather
moveForward()
moveForward()
moveForward()
orientationTurn()
}
setGather(initialOrient: "left")
setGather(initialOrient: "right")
Swift’s built-in Bool function toggle()—once I discovered it exists—allowed me to construct an effectively posable expression, although I’d still prefer to use Key-Path because that would eliminate the need to define targetPortal and disambiguate its case via an if.
The reason I couldn’t use Key-Path is because I am starved of the class hierarchy the portal objects are made from by the fact that Swift Playgrounds displays the contents only of .swift files among the resources accessed via the “…” menu’s > Advanced > View Anciliary Source Files option (I have only my iPad, no Mac to fall back on into XCode to view them; I’m also not currently in a position to afford even the relatively modest Apple Developer membership fee to access any documentation that may be exclusive thereto which might have let me scaffold/hazard a guess as to what names would hit upon the portals’ valid path). The compiler disclosing via an error message one time that it couldn’t pass a Bool to object of type Portal was as close as I got, and a Key-Path of \Root.Portal.greenPortal.isActive gave an error that I had to “fill in this placeholder” (I’d include a screenshot but as a new user it says I can only include 1 media item per post
).
Compounding this are the facts that the Learn to Code 2 playground doesn’t seem to support alert() (I also tried show(), which apparently was what older version of Swift Playgrounds used instead), and that it effectively hides/covers-over console output (I really don’t feel it’s worthwhile to tackle grafting-in a separate view just for that), preventing me from discovering the portal’s path via String(describing: self).
I would still love to try a Key-Path solution, so if anyone’s willing to supply the full valid hierarchy of this lesson’s Portal type that should let me give it a whirl
Although, if I’m not mistaken, even optimally deployed, they are brokered by inheritance, which was something I hoped to avoid because it prevents granularity finer than whole names (I do note that the original proposal for Key-Path in its More Features section mentions, “creating a KeyPath from a String at runtime”, tantalizingly close to evaluating a path statement in the way I wish, e.g. [colorOf]Portal.isActive where [colorOf] is—perhaps similarly to the “\” initiating a Key-Path—dropped into the expression by the “[…]” square brackets (no idea what use Swift may have claimed of those or therewith which would this conflict, just a hypothetical/provisional delimiter proposed for the sake of discussion, though one of some kind be requisite), passed in as a String argument yet part of an expression evaluating to a Bool (not 100% sure on all my terminology, here: part of a statement…?).
The reason I find acceptable my present solution is because I was able to exactly match the mirrored structure of the puzzle scenario with no hard-coded handling. The superiority to a Dict-based approach, though I never implemented it, seems to be several fold: greater clarity in settling disambiguation into the same, rather than casting out to separate, variables; no need for object index manipulation, such as by map(); and no complications introduced by having to pass in an argument purposely for portals per-se, versus my having just the 1 for all aspects of each iteration, encompassing also orientation management. True, I save, by my count, only 2 significant lines and 4 items over my original shoe-leather kludge, but the cleanliness of logic flows and function-to-code consummation are far higher and therefore, I find, much more satisfactory. I’m still open to ideas to improve it 
Please do let me try for a Key-Path solution by supplying this lesson’s portal objects’ full inheritance lineage!