Monty Hall simulation only 44% - swift

I just created a simulation for the Monty Hall problem, but my result (even with 10,000,000 tests) is strange. For strategy 1 (keep) the hits are in 1/3, and strategy 2 (switch) in 44,44%. Is there a mistake in the code?
Thanks everybody!
var hits1 = 0
var hits2 = 0
let testsNumber = 1000
for i in 0..<testsNumber {
var doors: [Int] = []
for i in 0..<3 {
doors.append(0) // Append closed door
}
doors[Int(arc4random_uniform(UInt32(doors.count)))] = 1 // Here's the car...
var selection = Int(arc4random_uniform(UInt32(doors.count))) // Select door
if doors[selection] == 1 {
hits1 += 1
}
// Open first closed door
for i in 0..<doors.count {
if doors[i] != 1 {
doors[i] = -1 // Open door
break
}
}
// Switch to next closed door
repeat {
selection = (selection + 1) % doors.count
} while(doors[selection] == -1)
if doors[selection] == 1 {
hits2 += 1
}
}
print("Hits: \(hits1), quote: \((Double) (hits1) / (Double) (testsNumber))")
print("Hits: \(hits2), quote: \((Double) (hits2) / (Double) (testsNumber))")

The Monty Hall problem says "pick a door; before I open it, I'll show what's behind one of the other doors (one that doesn't have a car) and let you stay with your initial selection or switch to the other closed door".
But consider:
for i in 0 ..< doors.count {
if doors[i] != 1 {
doors[i] = -1 // Open door
break
}
}
That effectively says "show the contestant what's behind the first door that doesn't have a car".
But, you're not considering the possibility that this door might be the one that the contestant already picked. That's changing the parameters of the game.
You meant to say "open a door that does not have a car and is not the door the contestant picked."
for i in 0 ..< doors.count {
if doors[i] != 1 && i != selection {
doors[i] = -1 // Open door
break
}
}
When you do that, your odds by always changing your selection (having been shown one of the other two doors that didn't have a car) goes up to 2/3rds.

Related

Combine if statement and for loop such that loop only gets executed once per every execution of if statement in swift

I'm trying to understand swift and therefore try to come up with simple command line games: in this game a player has to guess a secret word within 6 attempts by typing something in the command line, but every time he gets it wrong, a statement prints the number of his wrong attempts:
let response = readLine()
if response != "secret word" {
for n in 1...6 {
print(n)
}
}
else {
print("you are right!")
}
Now I know that my code will print all lines once the condition is not true, but I'm looking for a way to only print one item out of the four loop for every if statement consecutively.
I think a while loop works pretty well. Maybe something like this:
print("Welcome to the input game!\n\n\n\n")
var remainingTries = 5
let dictionary = ["apple", "grape", "pear", "banana"]
let secretWord = dictionary.randomElement()
print("Please guess a fruit")
while remainingTries > 0 {
remainingTries -= 1
let response = readLine()
if response == secretWord {
print("You got it!")
remainingTries = 0
} else if remainingTries <= 0 {
print("Too bad, you lose!")
remainingTries = 0
} else {
print("Incorrect. Tries remaining: \(remainingTries)")
}
}

russian roulette odd way to count that confuses me

so i'm making this game about russian roullette
it starts wit 5 bullets out of 6 chamber
then whenever the person lives
one bullet is removed
is my way of doing it mathematicly accurate
the bullet count is based on the amount of characther on my button
heres my code
#objc func clickedTrigger(){
attempts += 1
if GKRandomDistribution.d6().nextInt() > gunTrigger.title.count{
if gunTrigger.title.count == 1{
gunTrigger.title = "⁍⁍⁍⁍⁍"
NSSound(named: NSSound.Name(rawValue: "Glass"))?.play()
attempts = 0
appWindow.title = "you won the game"
}
else{
gunTrigger.title = String(gunTrigger.title.dropLast())
appWindow.title = "the person dodged a bullet."
}
}
else{
gunTrigger.title = "⁍⁍⁍⁍⁍"
appWindow.title = "the person saddly died."
}
}

How to compare characters in Swift efficiently

I have a function in Swift that computes the hamming distance of two strings and then puts them into a connected graph if the result is 1.
For example, read to hear returns a hamming distance of 2 because read[0] != hear[0] and read[3] != hear[3].
At first, I thought my function was taking a long time because of the quantity of input (8,000+ word dictionary), but I knew that several minutes was too long. So, I rewrote my same algorithm in Java, and the computation took merely 0.3s.
I have tried writing this in Swift two different ways:
Way 1 - Substrings
extension String {
subscript (i: Int) -> String {
return self[Range(i ..< i + 1)]
}
}
private func getHammingDistance(w1: String, w2: String) -> Int {
if w1.length != w2.length { return -1 }
var counter = 0
for i in 0 ..< w1.length {
if w1[i] != w2[i] { counter += 1 }
}
return counter
}
Results: 434 seconds
Way 2 - Removing Characters
private func getHammingDistance(w1: String, w2: String) -> Int {
if w1.length != w2.length { return -1 }
var counter = 0
var c1 = w1, c2 = w2 // need to mutate
let length = w1.length
for i in 0 ..< length {
if c1.removeFirst() != c2.removeFirst() { counter += 1 }
}
return counter
}
Results: 156 seconds
Same Thing in Java
Results: 0.3 seconds
Where it's being called
var graph: Graph
func connectData() {
let verticies = graph.canvas // canvas is Array<Node>
// Node has key that holds the String
for vertex in 0 ..< verticies.count {
for compare in vertex + 1 ..< verticies.count {
if getHammingDistance(w1: verticies[vertex].key!, w2: verticies[compare].key!) == 1 {
graph.addEdge(source: verticies[vertex], neighbor: verticies[compare])
}
}
}
}
156 seconds is still far too inefficient for me. What is the absolute most efficient way of comparing characters in Swift? Is there a possible workaround for computing hamming distance that involves not comparing characters?
Edit
Edit 1: I am taking an entire dictionary of 4 and 5 letter words and creating a connected graph where the edges indicate a hamming distance of 1. Therefore, I am comparing 8,000+ words to each other to generate edges.
Edit 2: Added method call.
Unless you chose a fixed length character model for your strings, methods and properties such as .count and .characters will have a complexity of O(n) or at best O(n/2) (where n is the string length). If you were to store your data in an array of character (e.g. [Character] ), your functions would perform much better.
You can also combine the whole calculation in a single pass using the zip() function
let hammingDistance = zip(word1.characters,word2.characters)
.filter{$0 != $1}.count
but that still requires going through all characters of every word pair.
...
Given that you're only looking for Hamming distances of 1, there is a faster way to get to all the unique pairs of words:
The strategy is to group words by the 4 (or 5) patterns that correspond to one "missing" letter. Each of these pattern groups defines a smaller scope for word pairs because words in different groups would be at a distance other than 1.
Each word will belong to as many groups as its character count.
For example :
"hear" will be part of the pattern groups:
"*ear", "h*ar", "he*r" and "hea*".
Any other word that would correspond to one of these 4 pattern groups would be at a Hamming distance of 1 from "hear".
Here is how this can be implemented:
// Test data 8500 words of 4-5 characters ...
var seenWords = Set<String>()
var allWords = try! String(contentsOfFile: "/usr/share/dict/words")
.lowercased()
.components(separatedBy:"\n")
.filter{$0.characters.count == 4 || $0.characters.count == 5}
.filter{seenWords.insert($0).inserted}
.enumerated().filter{$0.0 < 8500}.map{$1}
// Compute patterns for a Hamming distance of 1
// Replace each letter position with "*" to create patterns of
// one "non-matching" letter
public func wordH1Patterns(_ aWord:String) -> [String]
{
var result : [String] = []
let fullWord : [Character] = aWord.characters.map{$0}
for index in 0..<fullWord.count
{
var pattern = fullWord
pattern[index] = "*"
result.append(String(pattern))
}
return result
}
// Group words around matching patterns
// and add unique pairs from each group
func addHamming1Edges()
{
// Prepare pattern groups ...
//
var patternIndex:[String:Int] = [:]
var hamming1Groups:[[String]] = []
for word in allWords
{
for pattern in wordH1Patterns(word)
{
if let index = patternIndex[pattern]
{
hamming1Groups[index].append(word)
}
else
{
let index = hamming1Groups.count
patternIndex[pattern] = index
hamming1Groups.append([word])
}
}
}
// add edge nodes ...
//
for h1Group in hamming1Groups
{
for (index,sourceWord) in h1Group.dropLast(1).enumerated()
{
for targetIndex in index+1..<h1Group.count
{ addEdge(source:sourceWord, neighbour:h1Group[targetIndex]) }
}
}
}
On my 2012 MacBook Pro, the 8500 words go through 22817 (unique) edge pairs in 0.12 sec.
[EDIT] to illustrate my first point, I made a "brute force" algorithm using arrays of characters instead of Strings :
let wordArrays = allWords.map{Array($0.unicodeScalars)}
for i in 0..<wordArrays.count-1
{
let word1 = wordArrays[i]
for j in i+1..<wordArrays.count
{
let word2 = wordArrays[j]
if word1.count != word2.count { continue }
var distance = 0
for c in 0..<word1.count
{
if word1[c] == word2[c] { continue }
distance += 1
if distance > 1 { break }
}
if distance == 1
{ addEdge(source:allWords[i], neighbour:allWords[j]) }
}
}
This goes through the unique pairs in 0.27 sec. The reason for the speed difference is the internal model of Swift Strings which is not actually an array of equal length elements (characters) but rather a chain of varying length encoded characters (similar to the UTF model where special bytes indicate that the following 2 or 3 bytes are part of a single character. There is no simple Base+Displacement indexing of such a structure which must always be iterated from the beginning to get to the Nth element.
Note that I used unicodeScalars instead of Character because they are 16 bit fixed length representations of characters that allow a direct binary comparison. The Character type isn't as straightforward and take longer to compare.
Try this:
extension String {
func hammingDistance(to other: String) -> Int? {
guard self.characters.count == other.characters.count else { return nil }
return zip(self.characters, other.characters).reduce(0) { distance, chars in
distance + (chars.0 == chars.1 ? 0 : 1)
}
}
}
print("read".hammingDistance(to: "hear")) // => 2
The following code executed in 0.07 secounds for 8500 characters:
func getHammingDistance(w1: String, w2: String) -> Int {
if w1.characters.count != w2.characters.count {
return -1
}
let arr1 = Array(w1.characters)
let arr2 = Array(w2.characters)
var counter = 0
for i in 0 ..< arr1.count {
if arr1[i] != arr2[i] { counter += 1 }
}
return counter
}
After some messing around, I found a faster solution to #Alexander's answer (and my previous broken answer)
extension String {
func hammingDistance(to other: String) -> Int? {
guard !self.isEmpty, !other.isEmpty, self.characters.count == other.characters.count else {
return nil
}
var w1Iterator = self.characters.makeIterator()
var w2Iterator = other.characters.makeIterator()
var distance = 0;
while let w1Char = w1Iterator.next(), let w2Char = w2Iterator.next() {
distance += (w1Char != w2Char) ? 1 : 0
}
return distance
}
}
For comparing strings with a million characters, on my machine it's 1.078 sec compared to 1.220 sec, so roughly a 10% improvement. My guess is this is due to avoiding .zip and the slight overhead of .reduce and tuples
As others have noted, calling .characters repeatedly takes time. If you convert all of the strings once, it should help.
func connectData() {
let verticies = graph.canvas // canvas is Array<Node>
// Node has key that holds the String
// Convert all of the keys to utf16, and keep them
let nodesAsUTF = verticies.map { $0.key!.utf16 }
for vertex in 0 ..< verticies.count {
for compare in vertex + 1 ..< verticies.count {
if getHammingDistance(w1: nodesAsUTF[vertex], w2: nodesAsUTF[compare]) == 1 {
graph.addEdge(source: verticies[vertex], neighbor: verticies[compare])
}
}
}
}
// Calculate the hamming distance of two UTF16 views
func getHammingDistance(w1: String.UTF16View, w2: String.UTF16View) -> Int {
if w1.count != w2.count {
return -1
}
var counter = 0
for i in w1.startIndex ..< w1.endIndex {
if w1[i] != w1[i] {
counter += 1
}
}
return counter
}
I used UTF16, but you might want to try UTF8 depending on the data. Since I don't have the dictionary you are using, please let me know the result!
*broken*, see new answer
My approach:
private func getHammingDistance(w1: String, w2: String) -> Int {
guard w1.characters.count == w2.characters.count else {
return -1
}
let countArray: Int = w1.characters.indices
.reduce(0, {$0 + (w1[$1] == w2[$1] ? 0 : 1)})
return countArray
}
comparing 2 strings of 10,000 random characters took 0.31 seconds
To expand a bit: it should only require one iteration through the strings, adding as it goes.
Also it's way more concise 🙂.

Swift readLine! is causing fatal error "execution was interrupted"

I have this piece of code
func sell() throws{
while(true)
{
var choice : String?
print("Please press a number from 1 to 3\n")
let product = readLine(stripNewline: true)!
switch product
{
case "1":
//
case "2":
//
case "3":
//
default:
choice = "Invalid"
try sell()
}
}
try sell()
And it gives me the error
execution was interrupted reason exc_bad_instruction
I realized that the ! is causing the error. If I remove it I have a problem with the comparisons inside switch.
Anyone knows what is the problem?
func foo()->Int {
print("Please press a number from 1 to 3")
while true {
if let l = readLine(),
let i = Int(l) {
if (1..<4).contains(i) {
return i
} else {
print("Number must be in range from 1 to 3")
}
} else {
print("Please press a number")
}
}
}
let r = foo()
print("You chose", r)
an example of ...
Please press a number from 1 to 3
u
Please press a number
7
Number must be in range from 1 to 3
45
Number must be in range from 1 to 3
h76
Please press a number
1
You chose 1
Program ended with exit code: 0
How about create one if let to check if this contains value or is it nil
let product = readLine(stripNewline: true)
if let productNo = product {
switch productNo {
//your same code in switch
}

Recursive Pathfinding in Swift - find longest path

(Sorry for the cross-post, but I put this up on GameDev.Stackexchange and it's not getting much traffic, so I thought I'd try here as well.)
I'm programming a simple tile-based puzzle game, and I've gotten stuck trying to work out a pathfinding algorithm.
Here's how the game is set out:
The game board is (arbitrarily) 8 tiles wide by 8 tiles tall.
Each tile can be one of four types (shown below as red, green, blue and yellow)
Additionally, a tile could be a reactor (the starting point of a path - this will become clear later on)
The board would look something like this:
(The reactors are the circles; the other tiles have no special properties.)
What I need to do is: starting from a reactor, trace the longest path along adjoining tiles of the same color as the reactor. Something like this:
The blue reactor is simple(ish) as its path doesn't branch. However, as you can see from the green reactor's start position, its path can branch two ways at the start (up or down), and take a detour midway through.
The path I'm looking for is the longest one, so that's the one that's highlighted in the screengrab (the first path only crosses two tiles, and the detour midway results in a sorter path).
When certain conditions have been fulfilled, the reactor will cause all the tiles in the longest path (where the arrows cross in the diagram) to disappear and be replaced with new ones. All other tiles will remain in place, including the extraneous green tiles adjacent to the green reactor's path.
The tiles are stored in an approximation of a 2D array (Swift doesn't have a robust native implementation of that yet, so I'm using the one described in this tutorial). They're retrieved using tile[column, row].
With some help from a friend, I've written a recursive function that should return the longest path. It's looping through correctly, but it's not pruning shorter branches from the longestPath array (for example, the longest path would include the 2-tile branch below the reactor, as well as the single-tile detour at the top of the arch).
Can anyone see where I'm going wrong in this code?
Here's the recursive function:
func pathfinder(startingTile: Tile, pathToThisPoint: Chain, var iteration: Int? = 1) -> Chain
{
var longestPath: Chain? = nil
var availableTiles = getNeighbouringTiles(startingTile)
for var nextTile = 0; nextTile < availableTiles.count; nextTile++
{
let column = availableTiles[nextTile].column
let row = availableTiles[nextTile].row
if tiles[column, row]!.tileType == startingTile.tileType && (tiles[column, row]!.isReactor == false || startingTile.isReactor)
{
// if we haven't been here before
if !pathToThisPoint.tiles.contains(tiles[column, row]!)
{
print(iteration)
iteration = iteration! + 1
// add this tile to the pathtothispoint
// go to the next unexplored tile (recurse this function)
pathToThisPointaddTile(tiles[column, row]!)
let tempPath = pathfinder(tiles[column, row]!, pathToThisPoint: pathToThisPoint)
// if the resulting path is longer...
if tempPath.length > longestPath.length
{
// then tempPath is now the longest path
for var i:Int = 0; i < tempPath.length; i++
{
let tile = Tile(column: pathToThisPoint.tiles[i].column, row: pathToThisPoint.tiles[i].row, tileType: pathToThisPoint.tiles[i].tileType)
longestPath?.addTile(tile)
}
}
}
}
if longestPath != nil
{
return longestPath!
}
else
{
return pathToThisPoint
}
}
It's dependent on the getNeighboringTiles function (shown below) that returns an array of valid tiles of the same type, excluding reactors:
func getNeighbouringTiles(tile: Tile, previousTile: Tile? = nil) -> Array<Tile>
{
var validNeighbouringTiles = Array<Tile>()
var neighbourTile: Tile
// check top, right, bottom, left
if tile.row < NumRows - 1
{
neighbourTile = tiles[tile.column, tile.row + 1]!
if neighbourTile.tileType == tile.tileType && !neighbourTile.isReactor && (previousTile == nil || previousTile != neighbourTile)
{
validNeighbouringTiles.append(neighbourTile)
}
}
if tile.column < NumColumns - 1
{
neighbourTile = tiles[tile.column + 1, tile.row]!
if neighbourTile.tileType == tile.tileType && !neighbourTile.isReactor && (previousTile == nil || previousTile != neighbourTile)
{
validNeighbouringTiles.append(neighbourTile)
}
}
if tile.row > 0
{
neighbourTile = tiles[tile.column, tile.row - 1]!
if neighbourTile.tileType == tile.tileType && !neighbourTile.isReactor && (previousTile == nil || previousTile != neighbourTile)
{
validNeighbouringTiles.append(neighbourTile)
}
}
if tile.column > 0
{
neighbourTile = tiles[tile.column - 1, tile.row]!
if neighbourTile.tileType == tile.tileType && !neighbourTile.isReactor && (previousTile == nil || previousTile != neighbourTile)
{
validNeighbouringTiles.append(neighbourTile)
}
}
// if we get this far, they have no neighbour
return validNeighbouringTiles
}
The Tile class looks like this (methods omitted for brevity):
class Tile: CustomStringConvertible, Hashable
{
var column:Int
var row:Int
var tileType: TileType // enum, 1 - 4, mapping to colors
var isReactor: Bool = false
// if the tile is a reactor, we can store is longest available path here
var reactorPath: Chain! = Chain()
}
And finally, the chain class looks like this (again, methods omitted for brevity):
class Chain {
// The tiles that are part of this chain.
var tiles = [Tile]()
func addTile(tile: Tile) {
tiles.append(tile)
}
func firstTile() -> Tile {
return tiles[0]
}
func lastTile() -> Tile {
return tiles[tiles.count - 1]
}
var length: Int {
return tiles.count
}
}
----------------------- EDIT : REPLACEMENT PATHFINDER ------------------------
I've attempted to convert User2464424's code to Swift. Here's what I've got:
func calculatePathsFromReactor(reactor: Tile) -> Chain?
{
func countDirections(neighbours: [Bool]) -> Int
{
var count: Int = 0
for var i:Int = 0; i < neighbours.count; i++
{
if neighbours[i] == true
{
count++
}
}
return count
}
var longestChain: Chain? = nil
longestChain = Chain()
var temp: Chain = Chain()
var lastBranch: Tile = reactor
var lastMove: Int? = reactor.neighbours.indexOf(true)
func looper(var currentTile: Tile)
{
if currentTile != reactor
{
if countDirections(currentTile.neighbours) > 2 //is branch
{
lastBranch = currentTile
}
if countDirections(currentTile.neighbours) == 1 //is endpoint
{
lastBranch.neighbours[lastMove!] = false // block move out of the last branch found
if longestChain.length < temp.length
{
longestChain = temp
}
currentTile = reactor // return to reactor and redo
lastVisitedTile = reactor
temp = Chain() //reset to empty array
lastBranch = reactor
lastMove = reactor.neighbours.indexOf(true)
looper(currentTile)
}
}
//let tempTile: Tile = Tile(column: currentTile.column, row: currentTile.row, tileType: currentTile.tileType, isReactor: currentTile.isReactor, movesRemaining: currentTile.movesRemaining)
//tempTile.neighbours = currentTile.neighbours
if currentTile.neighbours[0] == true
{
if !temp.tiles.contains(currentTile)
{
temp.addTile(currentTile)
}
if countDirections(currentTile.neighbours) > 2
{
lastMove = 0
}
lastVisitedTile = currentTile
currentTile = tiles[currentTile.column, currentTile.row + 1]! //must avoid going backwards
if !temp.tiles.contains(currentTile)
{
looper(currentTile)
}
}
if currentTile.neighbours[1] == true
{
if !temp.tiles.contains(currentTile)
{
temp.addTile(currentTile)
}
if countDirections(currentTile.neighbours) > 2
{
lastMove = 1
}
lastVisitedTile = currentTile
currentTile = tiles[currentTile.column + 1, currentTile.row]! //must avoid going backwards
if !temp.tiles.contains(currentTile)
{
looper(currentTile)
}
}
if currentTile.neighbours[2] == true
{
if !temp.tiles.contains(currentTile)
{
temp.addTile(currentTile)
}
if countDirections(currentTile.neighbours) > 2
{
lastMove = 2
}
lastVisitedTile = currentTile
currentTile = tiles[currentTile.column, currentTile.row - 1]! //must avoid going backwards
if !temp.tiles.contains(currentTile)
{
looper(currentTile)
}
}
if currentTile.neighbours[3] == true
{
if !temp.tiles.contains(currentTile)
{
temp.addTile(currentTile)
}
if countDirections(currentTile.neighbours) > 2
{
lastMove = 3
}
lastVisitedTile = currentTile
currentTile = tiles[currentTile.column - 1, currentTile.row]! //must avoid going backwards
if !temp.tiles.contains(currentTile)
{
looper(currentTile)
}
}
}
// trigger the function for the reactor tile
looper(reactor)
return longestChain
}
(The neighbours property is a struct containing four named variables: above, right, below and left, each initialised to false and then set to true by a function that runs immediately before the pathfinder.)
I'm finding a couple of issues now. The code loops as it should, but stops at the top of the arch, under the single-tile detour - the path that's returned is only 4 tiles long (including the reactor).
The other problem I'm having - which I'll worry about when the correct paths are being returned - is that I'm getting a memory access error when shifting the tiles in the third column down by one. I think it's getting confused when there's a block of tiles (2x2 or higher) rather than a path that's only ever a single tile wide.
I can't fix your code, but i have an idea for a system that doesn't require recursion.
You can try doing all possible paths from a reactor and block paths that you already traversed by being aware of the moves you have done when encountering a branch.
In the tile class, add another array of 4 integers initialized to 0 (called "dir" for example).
Pseudocode.
Do a preprocess loop first:
foreach tiles:
if tileHasNORTHNeighbor: tile.dir[0] = 1;
if tileHasEASTNeighbor: tile.dir[1] = 1;
if tileHasSOUTHNeighbor: tile.dir[2] = 1;
if tileHasWESTNeighbor: tile.dir[3] = 1;
Then do:
tile currentTile = reactor;
array longest;
array temp;
tile lastBranch = reactor;
int lastMove = any key of "reactor.dir" with "1" as value;
function int countOnes(array dir):
int count = 0;
int t;
for (t=0;t<4;t++):
if dir[t]==1:
count++;
return count;
:start
if currentTile != reactor:
if countOnes(currentTile.dir) > 2: //is branch
lastBranch = currentTile;
if countOnes(currentTile.dir) == 1: //is endpoint
lastBranch.dir[lastMove] = 0; // block move out of the last branch found
if longest.length < temp.length:
longest = temp;
currentTile = reactor; // return to reactor and redo
array temp = []; //reset to empty array
lastBranch = reactor;
lastMove = next "reactor.dir" key with "1" as value;
goto start;
if currentTile.dir[0] == 1:
temp.append(currentTile);
if countOnes(currentTile.dir) > 2:
lastMove = 0;
currentTile = getTileAtNORTH; //must avoid going backwards
goto start;
if currentTile.dir[1] == 1:
temp.append(currentTile);
if countOnes(currentTile.dir) > 2:
lastMove = 1;
currentTile = getTileAtEAST; //must avoid going backwards
goto start;
if currentTile.dir[2] == 1:
temp.append(currentTile);
if countOnes(currentTile.dir) > 2:
lastMove = 2;
currentTile = getTileAtSOUTH; //must avoid going backwards
goto start;
if currentTile.dir[3] == 1:
temp.append(currentTile);
if countOnes(currentTile.dir) > 2:
lastMove = 3;
currentTile = getTileAtWEST; //must avoid going backwards
goto start;
You could use the BFS Algorithm and easily modify it to give you the longest path.
You've got a implementation example here. Or you've got at least SwiftStructures and SwiftGraph github repositories with graph and search algorithms already implemented in swift.