7

I ran across this truth table generator site, and tried to mimic it in PHP (i realize the source code is available, but i know 0 perl).

Now my question is not about evaluating the expression, but how to output the table so that every combination of T and F for the variables is shown

For example, with 3 variables, the table would look like such:

a | b | c 
-----------
T | T | T  
T | T | F 
T | F | T 
T | F | F 
F | T | T 
F | T | F 
F | F | T 
F | F | F 

and with 4 variables..

a | b | c | d
-------------
T | T | T | T
T | T | T | F
T | T | F | T
T | T | F | F
T | F | T | T
T | F | T | F
T | F | F | T
T | F | F | F
F | T | T | T
F | T | T | F
F | T | F | T
F | T | F | F
F | F | T | T
F | F | T | F
F | F | F | T
F | F | F | F

What is the logic/pattern to create it?

sqram
  • 7,069
  • 8
  • 48
  • 66
  • You could just use nested for loops, one for each variable? But these 'truthtables' don't really mean anything; they're just a list of all possible combinations of T's and F's? – user254875486 Feb 15 '12 at 10:56
  • Yes. Getting the combination is what stomped me. – sqram Feb 15 '12 at 10:57

7 Answers7

4

How about this recursive function? It returns a 2-dimensional array where each 'row' has $count elements. You can use this to generate your table.

function getTruthValues($count) {
    if (1 === $count) {
        // true and false for the first variable
        return array(array('T'), array('F'));
    }   

    // get 2 copies of the output for 1 less variable
    $trues = $falses = getTruthValues(--$count);
    for ($i = 0, $total = count($trues); $i < $total; $i++) {
        // the true copy gets a T added to each row
        array_unshift($trues[$i], 'T');
        // and the false copy gets an F
        array_unshift($falses[$i], 'F');
    }   

    // combine the T and F copies to give this variable's output
    return array_merge($trues, $falses);
}

function toTable(array $rows) {
    $return = "<table>\n";
    $headers = range('A', chr(64 + count($rows[0])));
    $return .= '<tr><th>' . implode('</th><th>', $headers) . "</th></tr>\n";

    foreach ($rows as $row) {
        $return .= '<tr><td>' . implode('</td><td>', $row) . "</td></tr>\n";
    }

    return $return . '</table>';
}

echo toTable(getTruthValues(3));

EDIT: Codepad, with an added function to convert the array to a table.

cmbuckley
  • 40,217
  • 9
  • 77
  • 91
  • 1
    A more sensible order is created using array_unshift instead of array_push: http://codepad.org/lMlWJfRl – cmbuckley Feb 15 '12 at 11:48
  • Hi. I spent the last couple of hours(about 7) studying this code as I have always struggled with recursive functions. Although I now understand the logic and process of how the code works, my question is, in your head, what is the pattern you had in your had that you wanted the code to follow? (sorry if the question isn't too clear) – sqram Feb 17 '12 at 21:17
  • 1
    I saw it as starting off with T and F for one variable, and then the second variable would grab 2 copies of the first's output, one to combine with its T value and one with its F value. This continues for each variable. It's not terribly efficient but it works OK. I'll add some comments to the code. – cmbuckley Feb 18 '12 at 14:18
3
$nbBooleans = 5; // change to whatever you want

// show header

for($i = 0; $i < $nbBooleans ; $i++) {
  if ($i > 0) {
    echo " | ";
  }
  echo chr($i + 65); // 1 => A, 2 => B etc.
}

// separator line (dynamic size)

echo "\n".str_repeat("-", ($nbBooleans - 1) * 3 + $nbBooleans)."\n";

// show combinations

$nbInterations = pow(2, $nbBooleans);

for($i = 0; $i < $nbInterations; $i++) {
  for ($iBit = 0; $iBit < $nbBooleans; {
    if ($iBit > 0) {
      echo " | ";
    }
    echo (($i & pow(2, $iBit)) != 0 ? 'Y' : 'N');
  }
  echo "\n";
}
Maxime Pacary
  • 22,336
  • 11
  • 85
  • 113
1

You can do something like this:

echo "<table>";
for($a=0; $a<=1; $a++){
    for($b=0; $b<=1; $b++){
        for($c=0; $c<=1; $c++){
            for($d=0; $d<=1; $d++){
                echo "<tr><td>$a</td><td>$b</td><td>$c</td><td>$d</td></tr>";
            }
        }
    }
}
echo "</table>";

maybe a bit overkill, but it works...

user254875486
  • 11,190
  • 7
  • 36
  • 65
1

You should first compute the number of combinations, for example if you have 4 variables then you will have 16 combinations. For every variable take its index, call it i. In that variable's column you will have (n / (2^i)) times of toggling T and F groups where n is the total combinations of possible values of the variables.

   <?php
        $numberOfVariables = 5;
        $totalCombinations = pow(2, $numberOfVariables);

        for ($i = 0; $i < $numberOfVariables; $i++) 
        {
            $subGroupCount = $totalCombinations / pow(2, $i); 
            $lettersPerGroup = $totalCombinations / $subGroupCount;

            $toggler = true;
            for($j=0; $j<$subGroupCount; $j++)
            {
                for($k=0; $k < $lettersPerGroup; $k++)
                    $array[$i][$j*$lettersPerGroup + $k] =  ($toggler ? "T" : "F");
                $toggler = !$toggler;
            }
        }

        echo("<table border='1' bgcolor='yellow'>");
        for ($k=0;$k<$totalCombinations;$k++) 
        {
            echo("<tr>");
            for ($j=$numberOfVariables-1;$j>=0;$j--) 
                    echo("<td>".$array[$j][$k]."</td>");
            echo("</tr>");
        }
        echo("</table>");
 ?>
Juvanis
  • 25,802
  • 5
  • 69
  • 87
  • I can convert this to PHP. But I am trying to understand your explanation though...it's a good one but i'm not fully getting it. Hold on – sqram Feb 15 '12 at 11:26
  • 1
    Now I guess it's working in the way you wanted. Can you check it? Hoping it helps. – Juvanis Feb 15 '12 at 12:31
1

Made a little function for that:

function printTruth($vars) {
 $rows = array();
 $max = pow(2, $vars);

 // Lines and Letters
 $arr = array();
 for($i=97;$i<(97+$vars);$i++) { $arr[] = chr($i); }

 $rows[] = implode(' | ', $arr);
 $rows[] = str_repeat('-', $vars*3);

 // Variables 
 for($i=0;$i<$max;$i++) {
    $oneRow = '';
  for ($j=0;$j<$vars;$j++) {
    if($j>0) 
            $oneRow .= " | ";
    $oneRow .= (($i & pow(2,$j)) != 0 ? 'T' : 'F');
  }
  $rows[] = strrev($oneRow);
 } 

 return implode("<br>", $rows); 
}

echo printTruth(3);
Keenora Fluffball
  • 1,647
  • 2
  • 18
  • 34
  • Narfs, seems like I should hit F5 before posting. Was a bit too slow :) At least you've got a function for this now. – Keenora Fluffball Feb 15 '12 at 11:29
  • The more the better. Although I am not trying to merely copy & paste, i am also trying to get a deep understanding of the logic/concept, and the more code, the better :) – sqram Feb 15 '12 at 11:57
1

Try this code. generate($numberOfVariables) returns an array with the truth table. Each element is a string that you can iterate over

<?
function generate($var=3){
$number= pow(2,$var)-1;

$array=array();
while($number>=0){
$str=decbin($number);

$number--;

while(strlen($str)<$var)
{

$str="0".$str;
}
array_push($array,$str);
}

return $array;
}?>
<pre>
<?print_r(array_reverse(generate(3)));
?>
</pre>
SoWhat
  • 5,564
  • 2
  • 28
  • 59
1

this approach may be ugly, but it seems to be universal :)

$length = 3;


for($i=0;$i<pow(2,$length);$i++){
        $bin = decbin($i);
        _add($bin, $length);
        _out($bin, $length);
}


function _out($str, $length){
        for ($i=0; $i<$length; $i++)
                echo ($str[$i] == 0 ? 'F' : 'T')."\t";

        echo "\n";
}

function _add(&$bin, $length){
        $add = '';
        if (strlen($bin) < $length){
                for($j=0;$j<($length - strlen($bin));$j++){
                        $add.='0';
                }
                $bin = $add.$bin;
        }
}

the output is as follows

F   F   F   
F   F   T   
F   T   F   
F   T   T   
T   F   F   
T   F   T   
T   T   F   
T   T   T
k102
  • 7,861
  • 7
  • 49
  • 69