The Teaching Machine

Jed Rembold & Fred Agbo

April 10, 2024

Announcements

  • Personal Project is due on Monday night next week!
    • Try not to ask for extension becuase the next week project is a bit extensive
  • 10% grade curving for midterm #2 was applied
  • Adventure Project may be introduced on Friday
  • Polling: https://www.polleverywhere.com/agbofred203

Review Question

Suppose I had created the data structure to the right in order to keep track of class sizes over the years. How would I access the size of my Spring 2018 Mechanics (Phys 339) class?

  1. data[2018]['classes']['Phys339']
  2. data[1]['Phys339']
  3. data[1]['classes']['Phys339']
  4. data[2018]['Phys339']
data = [
    {   'year': 2017,
        'semester': 'Fall',
        'classes': {
            'Phys221': 38,
            'Phys110': 49
        }
    },
    {   'year': 2018,
        'semester': 'Spring',
        'classes': {
            'Phys339': 16,
            'Phys222': 35
        }
    },
    {   'year': 2018,
        'semester': 'Fall',
        'classes': {
            'CS151': 26,
            'Phys110': 45
        }
    }
]

Data-Driven Programs

  • In most programming languages, data structures are easier to manipulate than the code itself
  • Often useful then to push as much of the program behavior as possible into data structures rather than methods and functions
    • Programs working in this fashion are said to be data driven
  • In a data-driven model, the actual program (commonly called the driver) is generally very small and simple simple managing:
    • Reading in data from a file into a suitable internal structure
    • Using the data structure to control the flow of the program

The Teaching Machine

  • Suppose you wanted to write a program that would give an “intelligent” quiz
    • Correct answers would move the client on to other, more difficult questions
    • Incorrect answers might give some explanation and then ask some follow up questions
  • Having the questions and answers in some sort of data structure would make sense
  • The teacher would generally be who comes up with the questions and progression though, and most teachers are not experts at writing code
    • Need a format that is more not code based where teachers could construct the questions and progression
    • Need to translate that format into more common data structures that the computer can then understand and act on

The Course Data File

  • One common method of achieving this is to have configuration or data files
  • The general format of a file is shown to the left, and an example question to the right
Identifying name for first question
Text of first question
------
responseA: name of next question
responseB: name of next question
responseC: name of next question
responseD: name of next question

...more questions/answers...
RemQ1
What is the value of 17 % 4?
    a. 0
    b. 1
    c. 3
    d. 4
------
a: RemQ2
b: PrecQ1
c: RemQ2
d: RemQ2

An Internal Representation

image/svg+xml course questions TMCourse name : question TMQuestion name text answers array of strings string : name
 

Data file to Internal Rep

DivQ1 What is the value of 3 / 2? ----- 1: DivQ2 1.5: DivQ4 *: DivQ3
DivQ2 The / operator produces floats. What is the value of 9 / 3? ----- 3: DivQ2 3.0: DivQ4 *: DivQ3
DivQ3 What is the value of 5 / 4? ----- 1.25: DivQ4 *: DivQ2
DivQ4 What is the value of 9 // 4? ----- 2: EXIT *: DivQ1
image/svg+xml DivQ1 DivQ2 DivQ3 DivQ4 questions START name text answers DivQ1 1 DivQ2 1.5 DivQ4 * DivQ3 What is the value of 3 / 2? name text answers 3 DivQ2 3.0 DivQ4 * DivQ3 DivQ2 The / operator produces floats. What is the value of 9 / 3? name text answers DivQ3 1.25 DivQ4 * DivQ2 What is the value of 5 / 4? name text answers 2 EXIT * DivQ1 DivQ4 What is the value of 9 // 4?
 

The TeachingMachine Program

from TMCourse import read_course

def teaching_machine():
    course = choose_course()
    course.run()

def choose_course():
    """
    Returns a course chosen by the user.
    """
    while True:
        try:
            filename = input("Enter course name: ")
            with open(filename + ".txt") as f:
                return read_course(f)
        except IOError:
            print("Please enter a valid course name.")


# Startup code

if __name__ == "__main__":
    teaching_machine()

The TMCourse Class

from TMQuestion import TMQuestion, read_question

class TMCourse:

    def __init__(self, questions):
        """Creates a new TMCourse object with the specified questions."""
        self._questions = questions

    def get_question(self, name):
        """Returns the question with the specified name."""
        return self._questions[name]

    def run(self):
        """Steps through the questions in this course."""
        current = "START"
        while current != "EXIT":
            question = self.get_question(current)
            for line in question.get_text():
                print(line)
            answer = input("> ").strip().upper()
            next = question.lookup_answer(answer)
            if next is None:
                print("I don't understand that response.")
            else:
                current = next

def read_course(fh):
    """Reads the entire course from the data file handle fh."""
    questions = { }
    finished = False
    while not finished:
        question = read_question(fh)
        if question is None:
            finished = True
        else:
            name = question.get_name()
            if len(questions) == 0:
                questions["START"] = question
            questions[name] = question
    return TMCourse(questions)

The TMQuestion Class


MARKER = "-----"

class TMQuestion:

    def __init__(self, name, text, answers):
        """Creates a new TMQuestion object with these attributes."""
        self._name = name
        self._text = text
        self._answers = answers

    def get_name(self):
        """Returns the name of this question."""
        return self._name

    def get_text(self):
        """Returns the list containing the text of this question."""
        return self._text

    def lookup_answer(self, response):
        """Looks up the response to find the next question."""
        next_question = self._answers.get(response, None)
        if next_question is None:
            next_question = self._answers.get("*", None)
        return next_question

def read_question(fh):
    """Reads one question from the data file handle fh."""
    name = fh.readline().rstrip()
    if name == "":
        return None
    text = [ ]
    finished = False
    while not finished:
        line = fh.readline().rstrip()
        if line == MARKER:
            finished = True
        else:
            text.append(line)
    answers = { }
    finished = False
    while not finished:
        line = fh.readline().rstrip()
        if line == "":
            finished = True
        else:
            colon = line.find(":")
            if colon == -1:
                raise ValueError("Missing colon in " + line)
            response = line[:colon].strip().upper()
            next_question = line[colon + 1:].strip()
            answers[response] = next_question
    return TMQuestion(name, text, answers)

Teaching the Adventure

  • The TeachingMachine program can process and run any data file that has the correct format
    • Does not need to technically be a series of educational questions
    • This is part of the strength of the data driven model: data is easy to change, programs less so
  • Could make a sort of “Choose your own adventure” game out of it!
// reveal.js plugins