Truth Tables: Your great-grandfather's computer If you remember back to your schooling years, you might remember learning about Truth Tables. They seemed boring, but they are basis for logic and (some would argue) all computing...



Problem

Your mission, should you choose to accept it is to write a program, function, or widget of code that can output a truth table given input.

Input

Input will be a string (like data structure) containing the logic statement to make the Truth Table into. For example:

p ∧ q


This means p and q(logical conjuction) and will output:

 p  q  p ∧ q
 T  T    T
 T  F    F
 F  T    F
 F  F    F            


Notice the spacing: The item of the column is in the center of the header

Characters

Score via characters, not bytes
The logic comparison characters are special and not always what they look like. Use these characters:

Logical Conjunction (AND): ∧ U+2227

Logical Disjunction (OR): ∨ U+2228

Logical Negation (NOT) ~ or ¬ U+7e and U+ac respectively 



Bonuses

All of these bonuses are optional, but will knock points off your score. Pick any.

Logical Negation

Logical Negation is a unary operator in truth tables. It is the equivalent of ! in most C-based languages. It makes false=>true and vise versa. It is notated with a ¬ or ~ (you must support both). Supporting this will knock off 10% of your score. You must, however, add an additional column to show its results:
For example:

~p ∧ q


will output:

p  ~p  q  ~p ∧ q
T  F   T     F
T  F   F     F
F  T   T     T
F  T   F     F


Pretty Print

The normal table notation is boring. Let's make it pretty! Pretty print format is as follows for p ∧ q is as follows:

+---+---+-------+
| p | q | p ∧ q |
+---+---+-------+
| T | T |   T   |
+---+---+-------+
| T | F |   F   |
+---+---+-------+
| F | T |   F   |
+---+---+-------+
| F | F |   F   |
+---+---+-------+


Special details for pretty printing:


There is a 1 space padding in each cell
Cell values are still centered


If you pretty print your tables, from your code and then multiply by 0.6. Use this function for this bonus:

score = 0.6 * code




Examples

p ∧ q:

p  q  p ∧ q
T  T    T
T  F    F
F  T    F
F  F    F


p ∨ q:

p  q  p ∨ q
T  T    T
T  F    T
F  T    T
F  F    F


~p ∧ q:

p  ~p  q  ~p ∧ q
T   F  T     F
T   F  F     F
F   T  T     T
F   T  F     F


~p ∨ q:

p  ~p  q  ~p ∧ q
T   F  T     T
T   F  F     F
F   T  T     T
F   T  F     T




Rules


Standard loopholes apply
No external resources
If you're going to break the rules, be clever ;)


Shortest Code (in characters) wins. Good Luck!
JavaScript (ES6), 141

Simple function, no bonus, 141 chars. (140 uft8, 1 unicode wide)

Complex function handling ~ or ¬, 254 chars (253 utf, 1 unicode wide), score 229

Could save 6 bytes using alert instead of console.log, but alert is particularly unfit to display tables.

Test running the snippet below in an EcmaScript 6 compliant browser (tested with Firefox. Won't work in Chrome as Chrome does not support .... Also, the bonus version use an extension of split that is Firefox specific).



/* TEST: redirect console.log into the snippet body */ console.log=x=&gt;O.innerHTML+=x+'\n'

// Simple
F=s=&gt;{[a,o,b]=[...s],z='  ',r=a+z+b+z+a+` ${o} ${b}
`;for(w='FT',n=4;n--;r+=w[c]+z+w[e]+z+z+w[o&lt;'∧'?c|e:c&amp;e]+`
`)c=n&amp;1,e=n&gt;&gt;1;console.log(r)}

// Simple, more readable
f=s=&gt;{
   [a,o,b]=[...s]
   r=a+'  '+b+'  '+a+` ${o} ${b}\n`
   for(w='FT',n=4; n--; )
   {
     c = n&amp;1, e = n&gt;&gt;1, x=o&lt;'∧' ? c|e : c&amp;e
     r += w[c]+'  '+w[e]+'    '+w[x]+'\n'
   }
   console.log(r)
}

// 10% Bonus
B=s=&gt;{[a,o,b]=s.split(/([∧∨])/),t=a&gt;'z',u=b&gt;'z',z='  ',r=(t?a[1]+z:'')+a+z+(u?b[1]+z:'')+b+z+a+` ${o} ${b}
`;for(s=v=&gt;'FT'[v]+z,n=4;n--;r+=s(c)+(t?s(d)+' ':'')+s(e)+(u?s(f)+' ':'')+(t?'   ':z)+s(o&lt;'∧'?d|f:d&amp;f)+`
`)c=n&amp;1,d=c^t,e=n&gt;&gt;1,f=e^u;console.log(r)}

Test1 = ['q∨p','q∧p']
Test2 = Test1.concat([
  '~q∨p','q∨~p','~q∨~p','~q∧p','q∧~p','~q∧~p',
  '¬q∨p','q∨¬p','¬q∨¬p','¬q∧p','q∧¬p','¬q∧¬p'
])


console.log('SIMPLE')
Test1.forEach(t=&gt;F(t));

console.log('BONUS')
Test2.forEach(t=&gt;B(t));
&lt;pre id=O&gt;&lt;/pre&gt;