g | x | w | all
Bytes Lang Time Link
128Mathematica170111T012021Zuser6198
048Dyalog APL160531T055505ZAdá
302C/C++ 302 Bytes170111T002505Zuser6428
119Python3160531T005030ZKarl Nap
129Mathematica160531T131431ZXanderha
2347MediaWiki template160530T103146Zleo
288Python150922T113508ZSjoerdPe
141JavaScript ES6150918T091449Zedc65
161Julia150918T033208ZAlex A.

Mathematica, 128 characters

TraditionalForm@Grid[({#}~Join~BooleanTable[#,Cases[b,_Symbol,{0,∞}]]&/@Cases[b=ToExpression@#,_,{0,∞}]/.{0<1->"T",0>1->"F"})]&

is the private use character U+F3C7 representing \[Transpose].

Luckily for us Mathematica golfers, and already represent And and Or, so all we have to do is convert the input string into a Mathematica expression and we can do symbolic logical operations on it.

Note that this solution will also handle Not (¬), Implies (), Equivalent (), Xor (), Nand (), Xor (), and Nor (), but it doesn't get the bonus because ~p is a syntax error in Mathematica. Meh.

enter image description here

Explanation

b=ToExpression@#

Converts the input string into a Mathematica expression and stores it in b.

Cases[b=ToExpression@#,_,{0,∞}]

This is a list every possible subexpression of the input. Each will receive its own column.

Cases[b,_Symbol,{0,∞}]

This is a list of all of the variables that appear in the input.

BooleanTable[#,Cases[b,_Symbol,{0,∞}]]&

Pure function which takes an input expression # and returns a list of truth values for all possible combinations of truth values for the variables.

{#}~Join~BooleanTable[...]

Prepends the expression itself to this list.

.../@Cases[b=ToExpression@#,_,{0,∞}]

Applies this function to each subexpression of the input.

.../.{0<1->"T",0>1->"F"}

Then replace true (0<1) with "T" and false (0>1) with "F".

(...)

Interchange rows and columns.

Grid[...]

Display the result as a Grid.

TraditionalForm@Grid[...]

Convert the Grid to traditional form so that it uses the fancy symbols.

Dyalog APL, 58 48 characters

Requires ⎕IO←0, which is default on many systems. Takes string as argument.

{('p q ',⍵)⍪'FT '[p,q,⍪⍎⍵]\⍨324⊤⍨9⍴≢p q←↓2 2⊤⌽⍳4}

No bonuses, but on the plus side, any operator works.

⍳4 first four indices (0 1 2 3)

 reverse (3 2 1 0)

2 2⊤ two-bit Boolean table

 split into two-element list of lists (high-bits, low-bits)

p q← store as p and q

 tally them (2)*

9⍴ cyclically reshape that to length 9 (2 2 2 2 2 2 2 2 2)

324⊤⍨ encode 324 thusly, i.e. as 12-bit binary (1 0 1 0 0 0 1 0 0)

\⍨ use that to expand (insert a space for each 0)...

'FT '[...] the string "FT ", indexed by

⍎⍵ the executed argument (valid since p and q now have values)

make that into a column matrix

q, prepend a column consisting of q (1 1 0 0)

q, prepend a column consisting of p (1 0 1 0)

(...)⍪ insert a row above, consisting of

 the argument

'p q ', prepended with the string "p q "


* Please star this issue if you see as ≢ and not as ̸≡.

C/C++ 302 Bytes

335 characters less 10% for handling negation. Formatting incomplete but submitting before I see what the impact of completion is.

Marked as C/C++ because my gcc and g++ accepts it with -fpermissive and it looks far more C like than C++ to me.

#include <stdio.h>
void T(char*S) { int (*P)(char*,...)=printf;char*v[2]={"F","T"};for(int m=4;m--;){P("|");char*s=S;int x=m&1;X:P(" %s |",v[x]);if(*++s!=' '){x=x^1;goto X;}char*o=++s;s+=3;int y=(m>>1)&1;Y:P(" %s |",v[y]);if(*++s){y=y^1;goto Y;}int g;for(g=o-S+1;g--;)P(" ");P(*++o==39?v[x&y]:v[x|y]);for(g=s-o;g--;)P(" ");P("|\n");}}

I'm sure there's probably a few tweaks that could be applied. In fact handling the nots adds more than the 10% bonus removes.

This does assume the input format is as stated, i.e. 2 input values (p and q), with or without the not prefix and nothing else, and all tokens delimited by a single space.

Ungolfed:

void ungolfed(char* S)
{
   int (*P)(char*,...) = printf;         // useful lookup stuff
   char* v[2] = {"F","T"};

   for(int m = 4; m--;) {                // loop over all 2 bit bit patterns (truth table inputs)

      P("|");                            // start of line format
      char* s=S;                         // iterator to start of equation for each bit pattern

      int x = m&1;                       // input 1 (aka. p which I called x here to be awkward)
X:    P(" %s |",v[x]);                   // input 1 output and format

      if(*++s!=' ') {                    // if next character is not a space then input must be prefixed with the not character
         x=x^1;                          // so negate the input
         goto X;                         // and redo input 1 output
      }

      char* o = ++s;                     // remember where the operator is
      s+=3;                              // and skip it and following space

      int y = (m>>1)&1;                  // input 2 (aka. q which I called y obviously) processing as for input 1
Y:    P(" %s |",v[y]);

      if(*++s) {
         y=y^1;
         goto Y;
      }

      int g;

      for(g=o-S+1;g--;) P(" ");         // pre-result value padding

      P(*++o==39?v[x&y]:v[x|y]);      // result

      for(g=s-o;g--;) P(" ");           // post-result value padding and format
      P("|\n");
   }
}

and the tests:

int main()
{
   T("p \x22\x27 q");  // p & q
   puts("");

   T("p \x22\x28 q");  // p | q
   puts("");

   T("\x7ep \x22\x27 q");  // ~p & q
   puts("");

   T("\xacp \x22\x28 q");  // ~p | q
   puts("");

   T("p \x22\x28 \xacq");  // p | ~q
   puts("");

   return 0;
}

Python3, 145 139 120 119 Bytes

No bonus (with bonus at the end)

 def f(s):
 a,m,b=s.split(" ");print(a,b,s);F,T,c=0,1,"FT"
 for p in c:
  for q in c:print(p,q," ",c[eval(p+"+*"[m=="∧"]+q)>0])

Needing Python3 for Unicode support out of the box.

Based on DJgamer98 Python code, figuring out his table is not right.

Edit1: Splitting into distinct variables and ommiting the operator string variable

Edit2: (ab)using F and T as both variables and string characters

Edit3: Saving one space thanks to NoOneIsHere

With Bonus, 215 * 0.6 = 129

def f(s):
 r="+---"*3+"----+"
 a,m,b=s.split(" ");F,T,c=0,1,"FT"
 print("%s\n| %s | %s | %s |\n%s"%(r,a,b,s,r));
 for p in c:
  for q in c: print("| %s | %s |   %s   |\n%s"%(p,q,c[eval(p+"+*"[m=="∧"]+q)>0],r));

Mathematica, 129 Bytes

Golfed:

t=InputString[];s=Append[StringCases[t,LetterCharacter],t];Grid[Prepend[Map[If[#,"T","F"]&,BooleanTable[ToExpression[s]],{2}],s]]

Ungolfed:

(*Take input*)
t=InputString[];
(* Find all occurrences of letters and append the final statement.*)
s=Append[StringCases[t,LetterCharacter],t];
(* Evaluate the list as expressions and create a boolean table of True/False values, then display as a table. *)
(* To satisfy the output conditions, we must convert each True/False to T/F *)
Grid[Prepend[Map[If[#,"T","F"]&,BooleanTable[ToExpression[s]],{2}],s]]

Not a Mathematica expert, but I found this rather elegant compared to having to do direct character comparison.

I had a solution that worked for negation, but it was longer than the score reduction would take off.

Depending on what qualifies for pretty printing, I might try for that bonus. I feel like outputting in ASCII in Mathematica would be far too expensive for the score reduction to compensate, but if the two main features are a dotted border and specified padding inside the cells, that's only a couple options in Grid.

With pretty printing, 171 * 0.6 = 102.6 Bytes

t=InputString[];s=Append[StringCases[t,LetterCharacter],t];Grid[Prepend[Map[If[#,"T","F"]&,BooleanTable[ToExpression[s]],{2}],s],Spacings->1,Frame->All,FrameStyle->Dashed]

MediaWiki template - 2347 characters

MediaWiki has a built template function called {{#expr}} that can handle logical expressions. This must be the perfect challenge for MediaWiki templates! Features such as variables, loops and a readable syntax would have helped a bit, though. Also, the fact that there is no NOT operator for the expr function made it a bit more complex.

{{#sub:{{#replace:{{#replace:{{{1}}}|~|}}|¬|}}|0|1}} {{#sub:{{{1}}}|{{#expr:{{#len:{{{1}}}}}-1}}|{{#len:{{{1}}}}}}} {{{1}}}<br>T T &nbsp;{{#if:{{#pos:{{#sub:{{#replace:{{{1}}}|~|¬}}|0|1}}|¬}}|&nbsp;|}} {{#replace:{{#replace:{{#expr:{{#replace:{{#replace:{{#replace:{{#replace:{{#replace:{{#replace:{{{1}}}|~|¬}}|{{#sub:{{#replace:{{#replace:{{{1}}}|~|}}|¬|}}|0|1}}|{{#if:{{#pos:{{#replace:{{{1}}}|~|¬}}|¬{{#sub:{{#replace:{{#replace:{{{1}}}|~|}}|¬|}}|0|1}}}}|0|1}}}}|{{#sub:{{{1}}}|{{#expr:{{#len:{{{1}}}}}-1}}|{{#len:{{{1}}}}}}}|{{#if:{{#pos:{{#replace:{{{1}}}|~|¬}}|¬{{#sub:{{{1}}}|{{#expr:{{#len:{{{1}}}}}-1}}|{{#len:{{{1}}}}}}}}}|0|1}}|0|1}}|¬|}}|∧|and}}|∨|or}}}}|1|T}}|0|F}}<br>T F &nbsp;{{#if:{{#pos:{{#sub:{{#replace:{{{1}}}|~|¬}}|0|1}}|¬}}|&nbsp;|}} {{#replace:{{#replace:{{#expr:{{#replace:{{#replace:{{#replace:{{#replace:{{#replace:{{#replace:{{{1}}}|~|¬}}|{{#sub:{{#replace:{{#replace:{{{1}}}|~|}}|¬|}}|0|1}}|{{#if:{{#pos:{{#replace:{{{1}}}|~|¬}}|¬{{#sub:{{#replace:{{#replace:{{{1}}}|~|}}|¬|}}|0|1}}}}|0|1}}}}|{{#sub:{{{1}}}|{{#expr:{{#len:{{{1}}}}}-1}}|{{#len:{{{1}}}}}}}|{{#if:{{#pos:{{#replace:{{{1}}}|~|¬}}|¬{{#sub:{{{1}}}|{{#expr:{{#len:{{{1}}}}}-1}}|{{#len:{{{1}}}}}}}}}|1|0}}|1|0}}|¬|}}|∧|and}}|∨|or}}}}|1|T}}|0|F}}<br>F T &nbsp;{{#if:{{#pos:{{#sub:{{#replace:{{{1}}}|~|¬}}|0|1}}|¬}}|&nbsp;|}} {{#replace:{{#replace:{{#expr:{{#replace:{{#replace:{{#replace:{{#replace:{{#replace:{{#replace:{{{1}}}|~|¬}}|{{#sub:{{#replace:{{#replace:{{{1}}}|~|}}|¬|}}|0|1}}|{{#if:{{#pos:{{#replace:{{{1}}}|~|¬}}|¬{{#sub:{{#replace:{{#replace:{{{1}}}|~|}}|¬|}}|0|1}}}}|1|0}}}}|{{#sub:{{{1}}}|{{#expr:{{#len:{{{1}}}}}-1}}|{{#len:{{{1}}}}}}}|{{#if:{{#pos:{{#replace:{{{1}}}|~|¬}}|¬{{#sub:{{{1}}}|{{#expr:{{#len:{{{1}}}}}-1}}|{{#len:{{{1}}}}}}}}}|0|1}}|0|1}}|¬|}}|∧|and}}|∨|or}}}}|1|T}}|0|F}}<br>F F &nbsp;{{#if:{{#pos:{{#sub:{{#replace:{{{1}}}|~|¬}}|0|1}}|¬}}|&nbsp;|}} {{#replace:{{#replace:{{#expr:{{#replace:{{#replace:{{#replace:{{#replace:{{#replace:{{#replace:{{{1}}}|~|¬}}|{{#sub:{{#replace:{{#replace:{{{1}}}|~|}}|¬|}}|0|1}}|{{#if:{{#pos:{{#replace:{{{1}}}|~|¬}}|¬{{#sub:{{#replace:{{#replace:{{{1}}}|~|}}|¬|}}|0|1}}}}|1|0}}}}|{{#sub:{{{1}}}|{{#expr:{{#len:{{{1}}}}}-1}}|{{#len:{{{1}}}}}}}|{{#if:{{#pos:{{#replace:{{{1}}}|~|¬}}|¬{{#sub:{{{1}}}|{{#expr:{{#len:{{{1}}}}}-1}}|{{#len:{{{1}}}}}}}}}|1|0}}|1|0}}|¬|}}|∧|and}}|∨|or}}}}|1|T}}|0|F}}

Test:

{{TemplateName|¬X ∧ ~Y}}

{{TemplateName|p ∨ q}}

Result:

X Y ¬X ∧ ~Y
T T    F
T F    F
F T    F
F F    T

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

I'm assuming MediaWiki >= 1.18, where the ParserFunctions extensions comes bundled with the software.

Python - 288 characters (+10 penalty cause I couldn't get unicode to work :c)

No bonuses. This is my very first codegolf answer.

def f(i):
    i=i.split(" ")
    print i[0],i[2],
    for f in i[0:3]: print f,
    print ""
    for t in["TT","TF","FT","FF"]:
        p,q=t[0],t[1]
        y = t[0]+" "+t[1]
        if i[1]=="^": r=(False,True)[p==q]
        if i[1]=="v": r=(False,True)[p!=q]
        if r: y+="   T"
        else: y+="   F"
        print y

i is the input.

EDIT: Removed a few spaces and it now uses function args as input.

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=>O.innerHTML+=x+'\n'

// Simple
F=s=>{[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<'∧'?c|e:c&e]+`
`)c=n&1,e=n>>1;console.log(r)}

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

// 10% Bonus
B=s=>{[a,o,b]=s.split(/([∧∨])/),t=a>'z',u=b>'z',z='  ',r=(t?a[1]+z:'')+a+z+(u?b[1]+z:'')+b+z+a+` ${o} ${b}
`;for(s=v=>'FT'[v]+z,n=4;n--;r+=s(c)+(t?s(d)+' ':'')+s(e)+(u?s(f)+' ':'')+(t?'   ':z)+s(o<'∧'?d|f:d&f)+`
`)c=n&1,d=c^t,e=n>>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=>F(t));

console.log('BONUS')
Test2.forEach(t=>B(t));
<pre id=O></pre>

Julia, 161 bytes

No bonuses.

s->(S=split(s);P=println;p=S[1];q=S[3];a=[&,|][(S[2]=="∨")+1];c="  ";P(p,c,q,c,s);for t=["TT","TF","FT","FF"] P(t[1],c,t[2],c^2,"FT"[a(t[1]>'F',t[2]>'F')+1])end)

Ungolfed:

function f(s::String)
    # Split the input on spaces
    S = split(s)

    # Separate out the pieces of the statement
    p = S[1]
    q = S[3]
    a = [&, |][(S[2] == "∨") + 1]

    # Print the header
    println(p, "  ", q, "  ", s)

    # Create the table entries in a loop
    for t = ["TT", "TF", "FT", "FF"]
        println(t[1], "  ", t[2], "    ", "FT"[a(t[1] > 'F', t[2] > 'F') + 1])
    end
end