@@ -0,0 +1,159 @@
1+//
2+// Truther.swift
3+// Truther
4+//
5+// Created by Ilya Kos on 10/6/17.
6+// Copyright © 2017 Ilya Kos. All rights reserved.
7+//
8+
9+import Foundation
10+
11+struct Truther {
12+ var formula: Formula
13+ func run() -> [(inp: [Bool], result: Bool)] {
14+ var out: [(inp: [Bool], result: Bool)] = []
15+ for i in 0..<Int(pow(2, Double(formula.variables.count))) {
16+ var t = 0
17+ var inp: [Bool] = []
18+ for _ in formula.variables {
19+ inp.append((UInt(i)>>t) & 1 == 1)
20+ t += 1
21+ }
22+ inp = inp.reversed()
23+ out.append((inp, formula.run(with: inp)))
24+ }
25+ return out
26+ }
27+}
28+
29+struct Formula {
30+ fileprivate func run(with inputs: [Bool]) -> Bool {
31+ var ins: [Variable: Bool] = [:]
32+ for (v, va) in zip(variables, inputs) {
33+ ins[v] = va
34+ }
35+ return value.evaluate(with: ins)
36+ }
37+ init(_ f: String) {
38+ var vars: Set<String> = Set()
39+ func process(_ s: Substring, startingLeft: FormulaElement? = nil) -> FormulaElement {
40+ if s.isEmpty {
41+ guard let startingLeft = startingLeft else {
42+ print("Internal error: Empty input")
43+ exit(1)
44+ }
45+ return startingLeft
46+ }
47+ var ns = s.trimmingCharacters(in: .whitespaces)
48+ if ns == "0" {
49+ return .constant(false)
50+ }
51+ if ns == "1" {
52+ return .constant(true)
53+ }
54+ if ns.trimmingCharacters(in: .whitespaces).reduce(true, {$0 && CharacterSet.letters.contains($1.unicodeScalars.first!)}) {
55+ vars.insert(String(s))
56+ return .variable(String(s))
57+ }
58+ func extractVar() -> Substring {
59+ if ns.first == "(" {
60+ let parts = extractBrackets(from: ns)
61+ ns = parts.after.trimmingCharacters(in: .whitespaces)
62+ return Substring(parts.wasInside.trimmingCharacters(in: .whitespaces))
63+ } else {
64+ if CharacterSet.whitespaces.contains((ns.first?.unicodeScalars.first)!) {
65+ print("Internal error: weird variable name first charecter \(ns.first!)")
66+ exit(1)
67+ }
68+ switch ns.first! {
69+ case "0":
70+ ns = ns.dropFirst().trimmingCharacters(in: .whitespaces)
71+ return "0"
72+ case "1":
73+ ns = ns.dropFirst().trimmingCharacters(in: .whitespaces)
74+ return "1"
75+ default:
76+ break
77+ }
78+ var i = ns.startIndex
79+ while i < ns.endIndex {
80+ if !CharacterSet.letters.contains(ns[i].unicodeScalars.first!) {
81+ break
82+ }
83+ i = ns.index(after: i)
84+ }
85+ let out = ns[..<i]
86+ ns = ns[i...].trimmingCharacters(in: .whitespaces)
87+ return out
88+ }
89+ }
90+ let left = startingLeft ?? process(extractVar())
91+ ns = ns.trimmingCharacters(in: .whitespaces)
92+ let isLetterOrNot = CharacterSet.letters.contains((ns.first?.unicodeScalars.first)!)
93+ var i = ns.startIndex
94+ while i < ns.endIndex {
95+ if CharacterSet.letters.contains(ns[i].unicodeScalars.first!) != isLetterOrNot || ns[i] == " " {
96+ break
97+ }
98+ i = ns.index(after: i)
99+ }
100+ guard let op = Operator.process(ns[..<i]) else {
101+ print("No such operator \(ns[..<i])")
102+ exit(1)
103+ }
104+ ns = ns[i...].trimmingCharacters(in: .whitespaces)
105+ let right = process(extractVar())
106+ return process(Substring(ns), startingLeft: .operation(left, op, right))
107+ }
108+ self.value = process(Substring(f))
109+ self.variables = vars.sorted()
110+ }
111+ let variables: [String]
112+ private let value: FormulaElement
113+}
114+
115+private func extractBrackets(from s: String) -> (wasInside: Substring, after: Substring) {
116+ var i = s.startIndex
117+ var brackets = 0
118+ while i < s.endIndex {
119+ switch s[i] {
120+ case "(":
121+ brackets += 1
122+ case ")":
123+ brackets -= 1
124+ default:
125+ break
126+ }
127+ if brackets == 0 {
128+ break
129+ }
130+ i = s.index(after: i)
131+ }
132+ if brackets != 0 {
133+ print("Mismatched brackets")
134+ exit(1)
135+ }
136+ return (s[s.index(after: s.startIndex)..<i], s[s.index(after: i)...])
137+}
138+
139+private typealias Variable = String
140+private indirect enum FormulaElement {
141+ case variable(Variable)
142+ case constant(Bool)
143+ case operation(FormulaElement, Operator, FormulaElement)
144+ func evaluate(with variables: [Variable: Bool]) -> Bool {
145+ switch self {
146+ case .variable(let v):
147+ if let va = variables[v] {
148+ return va
149+ } else {
150+ print("Internal error: didn't initialize all variables")
151+ exit(1)
152+ }
153+ case .operation(let l, let op, let r):
154+ return op.value(l.evaluate(with: variables), r.evaluate(with: variables))
155+ case .constant(let b):
156+ return b
157+ }
158+ }
159+}