Source code for questioned.questions.logic_problem

"""
This module defines the logic problem question.
"""

import random

from .question import Question


[docs]class LogicProblem(Question): """ Defines a question that requires the student to solve a logical problem. The student is provided with a boolean logic expressions and a set of initial values. The student is then required to evaluate the expression and provide the resulting value in the form of a boolean (True or False) These logical problems are fully randomly generated and require no input through the exam_spec. """
[docs] def render_blackboard(self): """ Renders the question for blackboard. Uses the True/False type. """ out_question = self.question.replace('\n', '<br />') question_section = f"{out_question}" answer = str(self.answer).lower() out = f"TF\t{question_section}\t{answer}\n" return out
[docs] @classmethod def generate(cls, exam_spec, count: int = 5, section_data=None): """ Generates an amount of manually input questions. """ if section_data is None: section_data = {} out = [] for _ in range(count): variables = [ {"name": "a", "value": random.choice((True, False))}, {"name": "b", "value": random.choice((True, False))}, {"name": "c", "value": random.choice((True, False))}, ] tree = LogicTreeNode(variables) question_text = "Given the following expression:\n" question_text += f"q = {str(tree)}\n" question_text += "And the following starting values:\n" for var in variables: question_text += f"{var['name']} = {var['value']}\n" question_text += "\nWhat is the resulting value for q?\n" out.append(cls(exam_spec, question_text, str(tree.solution))) return out
[docs]class LogicTreeNode(): """ Node of a tree for a logical expression. """ def __init__(self, variables, depth=0): """ Generates a subtree. """ self.type = random.choice(["and", "or", "xor", "nand", "nor"]) # Generate Left if random.choice([True, False] + [False]*depth): self.left = LogicTreeNode(variables, depth=depth+1) else: self.left = random.choice(variables) if random.choice([True, False] + [False]*depth): self.right = LogicTreeNode(variables, depth=depth+1) else: self.right = random.choice(variables) self.variables = variables def __str__(self): """ Returns the string representation of the logical expression. """ if isinstance(self.left, LogicTreeNode): left = self.left else: left = self.left["name"] if isinstance(self.right, LogicTreeNode): right = self.right else: right = self.right["name"] return f"({str(left)} {self.type} {str(right)})" @property def solution(self) -> bool: """ Returns the solution of the logical expression. """ if isinstance(self.left, LogicTreeNode): left = self.left.solution else: left = self.left["value"] if isinstance(self.right, LogicTreeNode): right = self.right.solution else: right = self.right["value"] if self.type == "and": return left and right if self.type == "or": return left or right if self.type == "xor": return (left and not right) or (not left and right) if self.type == "nand": return not (left and right) if self.type == "nor": return not (left or right) raise Exception(f"Unknown operator in logic tree: {self.type}")