|
func fromBrainfuck(brainfuck: String) -> String { |
|
let commands = brainfuck.map { Command(rawValue: String($0)) }.flatMap { $0 } |
|
|
|
guard let firstCommand = commands.first else { |
|
return "" |
|
} |
|
var path = initialPath(to: firstCommand) |
|
var last = firstCommand |
|
|
|
for command in commands.dropFirst() { |
|
let shortest = shortestPath(from: last, to: command) |
|
path.append(contentsOf: shortest) |
|
last = command |
|
} |
|
|
|
let program = path.map { $0.rawValue }.reduce("", +) |
|
|
|
return program |
|
} |
|
|
|
func initialPath(to: Command) -> [Direction] { |
|
switch to { |
|
case .rightCell: return [.right, .right] |
|
case .leftCell: return [.left, .left] |
|
case .increment: return [.up, .up] |
|
case .decrement: return [.down, .down] |
|
case .output: return [.right, .down, .right, .down] |
|
case .input: return [.left, .down, .left, .down] |
|
case .loopStart: return [.left, .up, .left, .up] |
|
case .loopEnd: return [.right, .up, .right, .up] |
|
} |
|
} |
|
|
|
func shortestPath(from: Command, to: Command) -> [Direction] { |
|
switch from { |
|
case .rightCell: |
|
switch to { |
|
case .rightCell: return [.left, .right] |
|
case .leftCell: return [.left, .left, .left, .left] |
|
case .increment: return [.left, .up, .left, .up] |
|
case .decrement: return [.left, .down, .left, .down] |
|
case .output: return [.down, .down] |
|
case .input: return [.left, .down, .left, .left, .down, .left] |
|
case .loopStart: return [.left, .up, .left, .left, .up, .left] |
|
case .loopEnd: return [.up, .up] |
|
} |
|
case .leftCell: |
|
switch to { |
|
case .rightCell: return [.right, .right, .right, .right] |
|
case .leftCell: return [.right, .left] |
|
case .increment: return [.right, .up, .right, .up] |
|
case .decrement: return [.right, .down, .right, .down] |
|
case .output: return [.right, .down, .right, .right, .down, .right] |
|
case .input: return [.down, .down] |
|
case .loopStart: return [.up, .up] |
|
case .loopEnd: return [.right, .up, .right, .right, .up, .right] |
|
} |
|
case .increment: |
|
switch to { |
|
case .rightCell: return [.right, .down, .right, .down] |
|
case .leftCell: return [.left, .down, .left, .down] |
|
case .increment: return [.down, .up] |
|
case .decrement: return [.down, .down, .down, .down] |
|
case .output: return [.down, .right, .down, .down, .right, .down] |
|
case .input: return [.down, .left, .down, .down, .left, .down] |
|
case .loopStart: return [.left, .left] |
|
case .loopEnd: return [.right, .right] |
|
} |
|
case .decrement: |
|
switch to { |
|
case .rightCell: return [.up, .right, .up, .right] |
|
case .leftCell: return [.up, .left, .up, .left] |
|
case .increment: return [.up, .up, .up, .up] |
|
case .decrement: return [.up, .down] |
|
case .output: return [.right, .right] |
|
case .input: return [.left, .left] |
|
case .loopStart: return [.up, .left, .up, .up, .left, .up] |
|
case .loopEnd: return [.up, .right, .up, .up, .right, .up] |
|
} |
|
case .output: |
|
switch to { |
|
case .rightCell: return [.up, .up] |
|
case .leftCell: return [.up, .left, .left, .up, .left] |
|
case .increment: return [.up, .left, .up, .up, .left, .up] |
|
case .decrement: return [.left, .left] |
|
case .output: return [.left, .right] |
|
case .input: return [.up, .left, .left, .left, .left, .down] |
|
case .loopStart: return [.up, .left, .up, .up, .left, .left, .up, .left] |
|
case .loopEnd: return [.up, .left, .up, .up, .right, .up] |
|
} |
|
case .input: |
|
switch to { |
|
case .rightCell: return [.up, .right, .right, .up, .right] |
|
case .leftCell: return [.up, .up] |
|
case .increment: return [.up, .right, .up, .up, .right, .up] |
|
case .decrement: return [.right, .right] |
|
case .output: return [.up, .right, .right, .right, .right, .down] |
|
case .input: return [.right, .left] |
|
case .loopStart: return [.up, .right, .up, .up, .left, .up] |
|
case .loopEnd: return [.up, .right, .up, .up, .right, .right, .up, .right] |
|
} |
|
case .loopStart: |
|
switch to { |
|
case .rightCell: return [.down, .right, .right, .right, .down, .right] |
|
case .leftCell: return [.down, .down] |
|
case .increment: return [.right, .right] |
|
case .decrement: return [.down, .right, .down, .down, .right, .down] |
|
case .output: return [.down, .right, .down, .down, .right, .right, .down, .right] |
|
case .input: return [.right, .down, .down, .down, .down, .left] |
|
case .loopStart: return [.right, .left] |
|
case .loopEnd: return [.down, .right, .right, .right, .right, .up] |
|
} |
|
case .loopEnd: |
|
switch to { |
|
case .rightCell: return [.down, .down] |
|
case .leftCell: return [.down, .left, .left, .left, .down, .left] |
|
case .increment: return [.left, .left] |
|
case .decrement: return [.down, .left, .down, .down, .left, .down] |
|
case .output: return [.left, .down, .down, .down, .down, .right] |
|
case .input: return [.down, .left, .down, .down, .left, .left, .down, .left] |
|
case .loopStart: return [.down, .left, .left, .left, .left, .up] |
|
case .loopEnd: return [.left, .right] |
|
} |
|
} |
|
} |