-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtruth_table_no_eval.py
More file actions
161 lines (143 loc) · 5.62 KB
/
truth_table_no_eval.py
File metadata and controls
161 lines (143 loc) · 5.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# -*- encoding: utf-8 -*-
# @Author: RZH
"""
A simple program to print the truth table of a given formula
*no `eval()` or `exec()` function version*
Guides:
- input variables as uppercase letter (A, B, C, ..., Z)
- input True or False as `1` or `0`
- input connectives as following:
- `~`: not
- `&`: and
- `|`: or
- `^`: xor
- `>`: implication
- `=`: double implication
- brackets (`(` and `)`) are supported
- spaces will be omitted
If the given formula is invalid, an exception will be raised
"""
from re import search, findall
class Statement(int):
"""
redefine `>` `~` `==` operators of `int`
"""
def __gt__(self, other): # `>` means `implication` now
return Statement(not self or other)
def __invert__(self):
return Statement(1 - self)
def __eq__(self, other):
return Statement(not (self - other))
class Formula(object):
def __init__(self, formula: str):
self.formula = formula.replace(' ', '') # the given formula
self.tmp_formula = self.formula
# changes while calculating the value under a given situation
self.variables = sorted(set(findall(r'[A-Z]', self.formula)))
# variables such as `A`, `B`, ...
def update(self):
"""
update `self.tmp_formula` to handle another situation
:return: self
"""
self.tmp_formula = self.formula
return self
def eval(self, statements: dict) -> str:
"""
calculate the truth value of `self.formula` under the given `statements`
:param statements: the given statements
:return: '0' or '1'
"""
statements['0'] = Statement(0)
statements['1'] = Statement(1)
sub_formula = set(findall(r'\([A-Z01~&|^>=]+\)', self.tmp_formula))
if sub_formula:
for each in sub_formula:
self.tmp_formula = self.tmp_formula.replace(
each, Formula(each.strip('()')).eval(statements)
)
return self.eval(statements)
else:
# calculate `~` first
while True:
# do loop until there is no `~` to handle `~~A` situation
not_: list = findall(r'~[A-Z01]', self.tmp_formula)
if not_:
for each in not_:
self.tmp_formula = self.tmp_formula.replace(
each, str(~statements[each[1]])
)
else:
break
# calculate `&` `|` `^` then
while True:
# do loop until there is no `&` to handle `A&B&C` situation
and_ = search(r'[A-Z01]&[A-Z01]', self.tmp_formula)
if and_:
and_ = str(and_.group())
self.tmp_formula = self.tmp_formula.replace(
and_, str(statements[and_[0]] & statements[and_[2]])
)
else:
break
while True:
# do loop until there is no `|` to handle `A|B|C` situation
or_ = search(r'[A-Z01]\|[A-Z01]', self.tmp_formula)
if or_:
or_ = str(or_.group())
self.tmp_formula = self.tmp_formula.replace(
or_, str(statements[or_[0]] | statements[or_[2]])
)
else:
break
while True:
# do loop until there is no `^` to handle `A^B^C` situation
xor_ = search(r'[A-Z01]\^[A-Z01]', self.tmp_formula)
if xor_:
xor_ = str(xor_.group())
self.tmp_formula = self.tmp_formula.replace(
xor_, str(statements[xor_[0]] ^ statements[xor_[2]])
)
else:
break
# calculate `>` `=` finally
while True:
# do loop until there is no `>` to handle `A>B>C` situation
imp_ = search(r'[A-Z01]>[A-Z01]', self.tmp_formula)
if imp_:
imp_ = str(imp_.group())
self.tmp_formula = self.tmp_formula.replace(
imp_, str(statements[imp_[0]] > statements[imp_[2]])
)
else:
break
while True:
# do loop until there is no `=` to handle `A=B=C` situation
eq_ = search(r'[A-Z01]=[A-Z01]', self.tmp_formula)
if eq_:
eq_ = str(eq_.group())
self.tmp_formula = self.tmp_formula.replace(
eq_, str(statements[eq_[0]] == statements[eq_[2]])
)
else:
break
return self.tmp_formula
def truth_table(self) -> None:
"""
print the truth table
:return: None
"""
print('%s Ans' % ' '.join(self.variables))
n = len(self.variables)
for i in range(2 ** n):
values: str = bin(i)[2:].rjust(n, '0')
statements: dict = dict(
zip(self.variables, map(Statement, map(int, values)))
)
# the values of statements will be stored in the dict `statements`
result: str = self.update().eval(statements)
print('%s %s' % (values.replace('', ' ').strip(), result))
return
if __name__ == '__main__':
f = Formula(input())
f.truth_table()