Skip to content

Instantly share code, notes, and snippets.

@JadenGeller
Last active August 29, 2015 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JadenGeller/15a05124671f9130df48 to your computer and use it in GitHub Desktop.
Save JadenGeller/15a05124671f9130df48 to your computer and use it in GitHub Desktop.
Brainfuck in Swift
extension Dictionary {
init(_ elements: [Element]){
self.init()
for (k, v) in elements {
self[k] = v
}
}
func map<U>(transform: Value -> U) -> [Key : U] {
return Dictionary<Key, U>(Swift.map(self, { (key, value) in (key, transform(value)) }))
}
}
struct InfiniteArray<T : Equatable> : Printable, SequenceType {
private var backing = [Int : T]()
private let defaultValue: T
init(defaultValue: T){
self.defaultValue = defaultValue
}
private init(defaultValue: T, backing: [Int : T]){
self.defaultValue = defaultValue
self.backing = backing
}
mutating func removeAll(keepCapacity: Bool = false) {
backing.removeAll(keepCapacity: keepCapacity)
}
func map<U>(transform: T -> U) -> InfiniteArray<U> {
return InfiniteArray<U>(defaultValue: transform(defaultValue), backing: backing.map(transform))
}
subscript (index: Int) -> T {
get {
return backing[index] ?? defaultValue
}
set {
if newValue == defaultValue {
backing.removeValueForKey(index)
}
else {
backing[index] = newValue
}
}
}
subscript(subRange: Range<Int>) -> [T] {
var arr = [T]()
for i in subRange {
arr.append(self[i])
}
return arr
}
var isEmpty: Bool {
get {
return backing.isEmpty
}
}
var description: String {
get {
var str = "["
for (i, value) in backing {
str += "\(i): \(value), "
}
str += "deafult: \(defaultValue)]}"
return str
}
}
func generate() -> InfiniteArrayGenerator<T> {
return InfiniteArrayGenerator(array: self)
}
}
struct InfiniteArrayGenerator<T : Equatable> : GeneratorType {
private var array: InfiniteArray<T>
init(array: InfiniteArray<T>){
self.array = array
}
private var index: Int = 0
mutating func next() -> T? {
return array[index++]
}
}
typealias Byte = UInt8
class InfiniteMemory : Printable {
internal var backing = InfiniteArray<Byte>(defaultValue: 0)
var startPointer: Pointer {
get {
return Pointer(index: 0, memory: self)
}
}
var description: String {
get {
return backing.description
}
}
struct Pointer {
var index: Int
let memory: InfiniteMemory
init(index: Int, memory: InfiniteMemory) {
self.index = index
self.memory = memory
}
var value: Byte {
get {
return memory.backing[index]
}
set {
memory.backing[index] = newValue
}
}
var isZero : Bool {
get {
return value == 0
}
}
mutating func incrementPointer() {
index++
}
mutating func decrementPointer() {
index--
}
mutating func incrementValue() {
value = value &+ 1
}
mutating func decrementValue() {
value = value &- 1
}
func printValue(ascii: Bool = true) {
if ascii {
print(Character(UnicodeScalar(Int(value))))
}
else {
println(value)
}
}
mutating func readValue() {
let byte = malloc(sizeof(Byte))
let readLength = UnsafeMutablePointer<Int>.alloc(1)
readLength.initialize(0)
value = Byte(NSString(data:NSFileHandle.fileHandleWithStandardInput().availableData, encoding:NSUTF8StringEncoding)!.intValue)
byte.dealloc(sizeof(Byte))
readLength.dealloc(1)
}
}
}
extension Array {
func appended(value: T) -> [T] {
var copy = self
copy.append(value)
return copy
}
}
postfix operator ^ { }
postfix operator ~ { }
postfix operator + { }
postfix operator - { }
postfix operator % { }
postfix operator & { }
postfix operator / { }
postfix operator | { }
enum BrainfuckCommand : Printable {
case IncrementPointer // ^
case DecrementPointer // ~
case IncrementValue // +
case DecrementValue // -
case Print // %
case Read // &
case StartLoop // /
case EndLoop // |
var description: String {
get {
switch self {
case IncrementPointer: return "^"
case DecrementPointer: return "~"
case IncrementValue: return "+"
case DecrementValue: return "-"
case Print: return "%"
case Read: return "&"
case StartLoop: return "/"
case EndLoop: return "|"
}
}
}
}
class BrainfuckProgram {
// Set true to print all computation steps
let debug = false
private var complementaryBracket: [Int : Int]! = nil
private let commands: [BrainfuckCommand]
init?(commands: [BrainfuckCommand]){
self.commands = commands
if let found = findComplementaryBrackets(commands) {
self.complementaryBracket = found
}
else {
return nil
}
}
func run(ascii: Bool = true) -> InfiniteMemory {
var memory = InfiniteMemory()
var instructionIndex = 0
var pointer = memory.startPointer
while instructionIndex < commands.count {
let commandInstructionIndex = instructionIndex
let command = commands[instructionIndex++]
if debug { println("(index: \(instructionIndex), instruction: \(command)), (index: \(pointer.index), value: \(pointer.value))") }
switch command {
case .IncrementPointer: pointer.incrementPointer()
case .DecrementPointer: pointer.decrementPointer()
case .IncrementValue: pointer.incrementValue()
case .DecrementValue: pointer.decrementValue()
case .Print: pointer.printValue(ascii: ascii)
case .Read: pointer.readValue()
case .StartLoop:
if pointer.isZero {
instructionIndex = complementaryBracket[commandInstructionIndex]! + 1
}
case .EndLoop:
if !pointer.isZero {
instructionIndex = complementaryBracket[commandInstructionIndex]! + 1
}
}
}
return memory
}
func findComplementaryBrackets(allcommands: [BrainfuckCommand]) -> [Int : Int]? {
var found = [Int : Int]()
var stack = [Int]()
for (index, command) in enumerate(allcommands) {
switch command {
case .StartLoop:
stack.append(index)
case .EndLoop:
if stack.last != nil {
let openingIndex = stack.removeLast()
found[openingIndex] = index
found[index] = openingIndex
}
else {
return nil // Bad syntax, unopened close bracket
}
default: continue
}
}
if stack.count != 0 {
return nil // Bad syntax, unclosed open bracket
}
return found
}
}
postfix func ^(var lhs: [BrainfuckCommand]) -> [BrainfuckCommand] { return lhs.appended(.IncrementPointer) }
postfix func ~(var lhs: [BrainfuckCommand]) -> [BrainfuckCommand] { return lhs.appended(.DecrementPointer) }
postfix func +(var lhs: [BrainfuckCommand]) -> [BrainfuckCommand] { return lhs.appended(.IncrementValue) }
postfix func -(var lhs: [BrainfuckCommand]) -> [BrainfuckCommand] { return lhs.appended(.DecrementValue) }
postfix func %(var lhs: [BrainfuckCommand]) -> [BrainfuckCommand] { return lhs.appended(.Print) }
postfix func &(var lhs: [BrainfuckCommand]) -> [BrainfuckCommand] { return lhs.appended(.Read) }
postfix func /(var lhs: [BrainfuckCommand]) -> [BrainfuckCommand] { return lhs.appended(.StartLoop) }
postfix func |(var lhs: [BrainfuckCommand]) -> [BrainfuckCommand] { return lhs.appended(.EndLoop) }
let fuck = [BrainfuckCommand]()
let Brain = { x in BrainfuckProgram(commands: x) }
// Examples
// Count down from 3
Brain((((((((fuck+)+)+)+)/)-)%)|).run(ascii: false)
// -> 3 -> 2 -> 1 -> 0
// Multiply 6 and 7
Brain((((((((((((((((((((fuck+)+)+)+)+)+)/)^)+)+)+)+)+)+)+)~)-)|)^)%).run(ascii: false)
// -> 42
// Print uppercase 'A'
Brain((((((((((((((((((((((((((((fuck+)+)+)+)+)+)/)^)+)+)+)+)+)+)+)+)+)+)~)-)|)^)+)+)+)+)+)%).run(ascii: true)
// -> A
// Prints my bf's name
Brain(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((fuck+)+)+)+)+)+)/)^)+)+)+)+)+)/)^)+)+)^)+)+)+)+)^)+)+)+)^)+)+)+)+)^)+)+)+)^)+)+)+)+)^)+)+)+)+)^)+)+)^)+)+)^)~)~)~)~)~)~)~)~)~)~)-)|)^)+)^)-)^)+)^)-)-)^)+)^)-)-)^)-)-)^)^)-)-)^)+)+)~)~)~)~)~)~)~)~)~)~)~)-)|)^)^)%)^)%)^)+)%)^)+)+)%)^)+)+)+)+)%)^)+)+)+)%)^)+)+)%)^)%)^)+)+)+)%)^)-)-)%)?.run(ascii: true)
// -> Brandon<3
// Print the frist 10 fibonacci numbers
Brain(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((fuck+)+)+)+)+)+)+)+)+)+)^)+)^)+)~)~)/)^)^)/)-)^)+)^)+)~)~)|)~)/)-)^)^)^)+)~)~)~)|)^)^)^)/)-)~)~)+)^)^)|)~)/)-)~)~)+)^)^)|)~)~)%)~)-)|)?.run(ascii: false)
// 1 -> 2 -> 3 -> 5 -> 8 -> 13 -> 21 -> 34 -> 55 -> 89
// Encodes a string so you no longer have to deal with the weird prefix sytax
func unpack<T, S : SequenceType where S.Generator.Element == Optional<T>>(source: S) -> SequenceOf<T> {
return SequenceOf(lazy(source).filter{ x in x != nil }.map{ x in x! })
}
func encode(code: String) -> [BrainfuckCommand] {
return Array(unpack(lazy(code).map{ c in
switch c {
case ">": return .IncrementPointer
case "<": return .DecrementPointer
case "+": return .IncrementValue
case "-": return .DecrementValue
case ".": return .Print
case ",": return .Read
case "[": return .StartLoop
case "]": return .EndLoop
default: return nil
}
}))
}
if let x = BrainfuckProgram(commands: encode("++++++[>+++++[>++>++++>+++>++++>+++>++++>++++>++>++><<<<<<<<<<-]>+>->+>-->+>-->-->>-->++<<<<<<<<<<<-]>>.>.>+.>++.>++++.>+++.>++.>.>+++.>--.")) {
x.run(ascii: true) // -> Brandon<3
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment