DOCUMENT(); loadMacros( "PGstandard.pl", "PGML.pl", "contextBoolean.pl", "niceTables.pl", "parserPopUp.pl", "parserMultiAnswer.pl" ); ## PGMLTable helper functions sub wrapTeX { return '[`' . shift . '`]' } sub PGMLopts{ my $opts = shift; return '{' . join(', ', map { "$_ => $opts->{$_}" } keys %$opts) . '}' } sub wrapCell { my $cell = shift; my $opts; if (ref $cell eq 'ARRAY') { my $data = shift @$cell; $opts = {%$cell}; $cell = $data; } my $string = "[.$cell.]"; $string .= PGMLopts($opts) if $opts; return $string; } sub convertRow { my $row = shift; return join('', map { wrapCell($_) } @$row) . '* '; } sub PGMLTable { my $rows = shift; my %opts = @_; my $table = '[#' . join(' ', map { convertRow($_) } @$rows) . '#]'; if ($opts{layout}) { $table .= '*'; delete $opts{layout}; } $table .= PGMLopts(~~%opts) if %opts; return $table; } ## End PGMLTable helper functions ## Start problem ## Customize here Context("Boolean"); Context()->constants->set(T => { string => '1'}, F => { string => '0' }); Context()->variables->are(A => 'Boolean', B => 'Boolean', C => 'Boolean' ); Context()->operators->set( 'not' => { TeX => '\neg ' }, 'and' => {TeX => '\cdot '}, 'or' => {TeX => '+'} ); Context()->setPrecedence('oxan'); @f = ( Formula("(A+C)(B+C')"), Formula("(A'C')+(B'C)"), ); @dontcare = ( [0], [7], ); @fLabel = ( "O_1", "O_2" ); ## End customization @vars = Context()->variables->names; $T = Compute('T'); $F = Compute('F'); @ansOptions = ('T', 'F', 'X', 'I'); @dontcareHash; for my $i (0..$#dontcare) { my %dcHash = map { $_ => 1 } @{$dontcare[$i]}; push @dontcareHash, ~~%dcHash; } # custom checker is required for MultiAnswer # can be modified to return partial credit -- currently all or nothing $columnChecker = sub { my ($c, $s, $ma, $ansHash) = @_; my $incorrect = 0; my $size = @$c - 1; for (0..$size) { $incorrect++ unless ($c->[$_] == $s->[$_]); } Value->Error("You have $incorrect incorrect entr" . ($incorrect == 1 ? 'y' : 'ies') . " in this column") if $incorrect; return 1; }; # build tables @varheader = map { wrapTeX($_) } @vars; @fheader = map { wrapTeX($_) } @fLabel; $header = [ @varheader, @fheader ]; @table = ($header); @ans; @ansTable = ($header); $n = @vars-1; $numrows = 2**@vars-1; for (my $i=$numrows; $i >= 0; $i--) { my @coords = map { $i & 2**$_ ? 1 : 0 } (0..$n); my %point = map { $vars[$_]=>$coords[$n-$_] } (0..$n); my @row = map { $point{$vars[$_]} ? $T : $F } (0..$n); my @rowans = map { exists($dontcareHash[$_]->{$i}) ? 'X' : $f[$_]->eval(%point)->value } (0..$#f); push @ans, ~~@rowans; push @table, ~~@row; my @ansRow = (@row, @rowans); push @ansTable, ~~@ansRow; } # build one MA per expression to evaluate (in @f) @columnMA; @fLabelTable; for my $j (0..$#f) { $columnMA[$j] = MultiAnswer( map { DropDown( ~~@ansOptions, $ans[$_][$j] ) } (0..$numrows) )->with(singleResult=>1,allowBlankAnswers=>0,checker=>$columnChecker); # while we're at it, build a table for the expressions my @row = map { wrapTeX($_) } ($fLabel[$j], '=', $f[$j]->TeX); push @fLabelTable, ~~@row; } # push the MA answer blanks onto the end of each row for my $i (0..$numrows) { push @{$table[$i+1]}, map { "[__]{~~$columnMA[$_]}" } (0..$#f); } $PGMLLabelTable = PGMLTable(~~@fLabelTable); $PGMLTable = PGMLTable(~~@table); $PGMLAnsTable = PGMLTable(~~@ansTable); BEGIN_PGML [$PGMLLabelTable]** [$PGMLTable]** END_PGML BEGIN_PGML_SOLUTION [$PGMLAnsTable]** END_PGML_SOLUTION # position the correct answer labels at the top of each column my @answerLabels = keys %{ $PG->{PG_ANSWERS_HASH} }; for my $j (0 .. $#answerLabels) { $PG->{PG_ANSWERS_HASH}{ $answerLabels[$j] }{ans_eval}{rh_ans} {feedback_options} = sub { my ($ansHash, $options) = @_; $options->{insertMethod} = 'append_content'; my $headerRow = $options->{feedbackElements}->first->ancestors('table') ->first->find('tr')->first->children('td'); $options->{insertElement} = $headerRow->[ $j + 3 ]; }; } ENDDOCUMENT();