-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtruth.js
103 lines (101 loc) · 3.62 KB
/
truth.js
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
/*
A function that returns an ASCII truth table. Dots represent true, nothing represents false.
EXAMPLES
truthTable(['Q->R','P->Q','PvT','T->S','~R'],'S');
truthTable(['T->Q','~TvR','~R'],'~Q');
truthTable(['~(PvQ)','PvR','T->R'],'T');
*/
function truthTable(premises,conclusion) {
function makePerfect(molecular) {
return molecular.replace(/[\s]/g,'').replace(/<-*>/g,'↔').replace(/-*>/g,'→').replace(/&/g,'^').replace(/~/g,'¬');
}
premises=premises.map(a=>makePerfect(a));
conclusion=makePerfect(conclusion);
var atomics='';
for (var atomic of (premises.join('')+conclusion).replace(/[^A-Z]/g,'')) if (!~atomics.indexOf(atomic)) atomics+=atomic;
function isTrue(molecular,atomics) {
function addTruth(op,dep,val) {
if (operations.length&&op.depth===dep) {
var t=op.negateNext?!val:!!val;
op.negateNext=false;
if (op.arg1!==undefined) op.arg2=t;
else op.arg1=t;
} else operations.splice(0,0,{
depth:dep,
arg1:!!val
});
}
molecular=`(${molecular})`;
var depth=0,operations=[];
for (var i=0;i<molecular.length;i++) {
if (molecular[i]==='(') depth++;
else if (molecular[i]===')') {
if (operations.length&&operations[0].depth===depth) {
var result;
switch (operations[0].type) {
case "DISJUNCTION":result=operations[0].arg1||operations[0].arg2;break;
case "CONJUNCTION":result=operations[0].arg1&&operations[0].arg2;break;
case "CONDITIONAL":result=!operations[0].arg1||operations[0].arg2;break;
case "BICONDITIONAL":result=operations[0].arg1===operations[0].arg2;break;
default:result=operations[0].arg1;
}
operations.splice(0,1);
addTruth(operations[0],depth-1,result);
}
depth--;
} else if (/[A-Z]/.test(molecular[i])) {
addTruth(operations[0],depth,atomics[molecular[i]]);
} else switch (molecular[i]) {
case "v":operations[0].type="DISJUNCTION";break;
case "^":operations[0].type="CONJUNCTION";break;
case "→":operations[0].type="CONDITIONAL";break;
case "↔":operations[0].type="BICONDITIONAL";break;
case "¬":
if (operations.length&&operations[0].depth===depth) operations[0].negateNext=true;
else operations.splice(0,0,{
depth:depth,
negateNext:true
});
break;
}
}
return operations[0].arg1;
}
var table='',tablelengths=[],div='';
var i=0;
for (var col of [...atomics.split(''),...premises,conclusion]) {
tablelengths+=col.length;
if (i===atomics.length+premises.length) table+='║',div+='╫';
else if (i!==0) table+='┃',div+='╋';
table+=col,div+='━'.repeat(col.length);
i++;
}
table+='\n'+div;
var combos=Math.pow(2,atomics.length),trues=[];
for (var i=0;i<combos;i++) trues.push({});
for (var i=0;i<atomics.length;i++) {
var t=combos/Math.pow(2,i+1);
for (var j=0,mode=false;j<combos;j++) {
if (j%t===0) mode=!mode;
trues[j][atomics[i]]=mode;
}
}
for (var i=0;i<combos;i++) {
var col=0,row='\n',results=[],conclu;
for (var atomic of atomics) {
row+=(trues[i][atomic]?'·':' ')+'┃';
col++;
}
for (var premise of premises) {
results.splice(0,0,isTrue(premise,trues[i]));
row+=(results[0]?'•':' ')+' '.repeat(tablelengths[col]-1)+'┃';
col++;
}
conclu=isTrue(conclusion,trues[i]);
row=row.slice(0,-1)+'║'+(conclu?'·':'');
if (~results.indexOf(false)) row=row.replace(/•/g,'·');
else row+=(conclu?' ✔':' ✖');
table+=row;
}
return table;
}