@@ -0,0 +1,140 @@
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.trimmingCharacters(in: .whitespaces).reduce(true, {$0 && CharacterSet.letters.contains($1.unicodeScalars.first!)}) {
49+ vars.insert(String(s))
50+ return .variable(String(s))
51+ }
52+ func extractVar() -> Substring {
53+ if ns.first == "(" {
54+ let parts = extractBrackets(from: ns)
55+ ns = parts.after.trimmingCharacters(in: .whitespaces)
56+ return Substring(parts.wasInside.trimmingCharacters(in: .whitespaces))
57+ } else {
58+ if CharacterSet.whitespaces.contains((ns.first?.unicodeScalars.first)!) {
59+ print("Internal error: weird variable name first charecter \(ns.first!)")
60+ exit(1)
61+ }
62+ var i = ns.startIndex
63+ while i < ns.endIndex {
64+ if !CharacterSet.letters.contains(ns[i].unicodeScalars.first!) {
65+ break
66+ }
67+ i = ns.index(after: i)
68+ }
69+ let out = ns[..<i]
70+ ns = ns[i...].trimmingCharacters(in: .whitespaces)
71+ return out
72+ }
73+ }
74+ let left = startingLeft ?? process(extractVar())
75+ ns = ns.trimmingCharacters(in: .whitespaces)
76+ let isLetterOrNot = CharacterSet.letters.contains((ns.first?.unicodeScalars.first)!)
77+ var i = ns.startIndex
78+ while i < ns.endIndex {
79+ if CharacterSet.letters.contains(ns[i].unicodeScalars.first!) != isLetterOrNot || ns[i] == " " {
80+ break
81+ }
82+ i = ns.index(after: i)
83+ }
84+ guard let op = Operator.process(ns[..<i]) else {
85+ print("No such operator \(ns[..<i])")
86+ exit(1)
87+ }
88+ ns = ns[i...].trimmingCharacters(in: .whitespaces)
89+ let right = process(extractVar())
90+ return process(Substring(ns), startingLeft: .operation(left, op, right))
91+ }
92+ self.value = process(Substring(f))
93+ self.variables = vars.sorted()
94+ }
95+ let variables: [String]
96+ private let value: FormulaElement
97+}
98+
99+private func extractBrackets(from s: String) -> (wasInside: Substring, after: Substring) {
100+ var i = s.startIndex
101+ var brackets = 0
102+ while i < s.endIndex {
103+ switch s[i] {
104+ case "(":
105+ brackets += 1
106+ case ")":
107+ brackets -= 1
108+ default:
109+ break
110+ }
111+ if brackets == 0 {
112+ break
113+ }
114+ i = s.index(after: i)
115+ }
116+ if brackets != 0 {
117+ print("Mismatched brackets")
118+ exit(1)
119+ }
120+ return (s[s.index(after: s.startIndex)..<i], s[s.index(after: i)...])
121+}
122+
123+private typealias Variable = String
124+private indirect enum FormulaElement {
125+ case variable(Variable)
126+ case operation(FormulaElement, Operator, FormulaElement)
127+ func evaluate(with variables: [Variable: Bool]) -> Bool {
128+ switch self {
129+ case .variable(let v):
130+ if let va = variables[v] {
131+ return va
132+ } else {
133+ print("Internal error: didn't initialize all variables")
134+ exit(1)
135+ }
136+ case .operation(let l, let op, let r):
137+ return op.value(l.evaluate(with: variables), r.evaluate(with: variables))
138+ }
139+ }
140+}