| Bytes | Lang | Time | Link |
|---|---|---|---|
| 128 | Mathematica | 170111T012021Z | user6198 |
| 048 | Dyalog APL | 160531T055505Z | Adá |
| 302 | C/C++ 302 Bytes | 170111T002505Z | user6428 |
| 119 | Python3 | 160531T005030Z | Karl Nap |
| 129 | Mathematica | 160531T131431Z | Xanderha |
| 2347 | MediaWiki template | 160530T103146Z | leo |
| 288 | Python | 150922T113508Z | SjoerdPe |
| 141 | JavaScript ES6 | 150918T091449Z | edc65 |
| 161 | Julia | 150918T033208Z | Alex 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.
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 {{#if:{{#pos:{{#sub:{{#replace:{{{1}}}|~|¬}}|0|1}}|¬}}| |}} {{#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 {{#if:{{#pos:{{#sub:{{#replace:{{{1}}}|~|¬}}|0|1}}|¬}}| |}} {{#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 {{#if:{{#pos:{{#sub:{{#replace:{{{1}}}|~|¬}}|0|1}}|¬}}| |}} {{#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 {{#if:{{#pos:{{#sub:{{#replace:{{{1}}}|~|¬}}|0|1}}|¬}}| |}} {{#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
