Archive for November, 2010

Course Explorer Released, Bugs Known

Nov 14 2010 Published by under CourseTree

Coursetree 1.0



  • All of the courses in the course calendar, categorized by department
  • Displays course title and description
  • Color codes for the time of the year a course is offered
  • Less clicks to look up information on a course
  • Draws prerequisite diagram
  • Nodes can be toggled to show an alternative list of prerequisites


  • Some courses were rejected by the scraper
  • Some courses are missing prerequisites, possibly a parsing issue
  • Due to the above two bugs, some prerequisites won’t show
  • Some nodes at the bottom of the prerequisite tree appear to be transparent

Recommended browsers for Waterloo Course Planner: Firefox, Chrome, and Opera.

No responses yet

Generating Possible Courses to Fulfill Prerequisites

Nov 06 2010 Published by under CourseTree

For this part of the project, the goal is to generate a list of courses that meets the requirements for a course from a string stored in the database in a specific format. The entire project was designed so that each component is modular. This way, each component could be written and tested independently, and the complexity of the task is greatly reduced. Likewise, the project consists of so many high level components it appears, at first glance, to be incapable of being one piece. To my surprise, I put together Scrapy + PLY + Django, and it all works beautifully.

Part of the reason these separate components can all come together is that the specifications were set in stone before design, and the design itself (choosing the web framework, scraper, compiler) is tailored with the whole in mind. So for this part, these are the requirements:

From a string of prerequisites separated by commas, with alternatives separated by slashes, generate a list of lists that represents all possible course combinations, without more than one course selected out of each group of alternatives.

"CS 241, STAT 206/STAT 230/STAT 240" -> [['CS 241'], [' STAT 206', 'STAT 230', 'STAT 240']]
[['CS 241'], [' STAT 206', 'STAT 230', 'STAT 240']] -> [('CS 241', 'STAT 206'), ('CS 241', 'STAT 230'), ('CS 241', 'STAT 240')]

Basically, it’s a combination of a list of lists of strings.

Once the goal was set, the coding phase was straightforward. Simply understand the meaning of the input, and use a python function to turn it into the specified output.

def calc_comb(t):
    l = t.split(', ')
    group = []
    for s in l:
    return list(itertools.product(*group))


No responses yet

Coding Horror and the Illumination

Nov 03 2010 Published by under CourseTree

Can you imagine anything useful coming out of this line of code?

prereqPattern='''([A-Z]{2,5} \d{3}/[A-Z]{2,5} \d{3}\s*and\s*[A-Z]{2,5} \d{3}/[A-Z]{2,5} \d{3})|([A-Z]{2,5} \d{3}\s*and\s*\(*[A-Z]{2,5} \d{3}\)*)|(\)\s*and\s*\()|(One of [A-Z]{2,5} \d{3}\s*[, or\d{3}]*;|[A-Z]{2,5} \d{3}[, \d{3}]*;|.*,\s*[A-Z]{2,5} \d{3}.*;|[A-Z]{2,5} \d{3} or [A-Z]{2,5} \d{3}|[A-Z]{2,5} \d{3} or \d{3}|[A-Z]{2,5} \d{3})'''

I can, because I’ve seen it. Here’s a small slice:

MATH 137 or 147
 ACTSC 231, STAT 230 or 240
MATH 136 or 146
AFM 272;ACTSC 291
STAT 330, 333
STAT 330, 333
 ACTSC 331, STAT 330
AFM 372;ACTSC 391;ACTSC 231;ACTSC 231 and BUS 393;STAT 330;STAT 334
AFM 372;ACTSC 391;ACTSC 231;ACTSC 231 and BUS 393;STAT 333 or 334
AFM 101 or BUS 227
AFM 101

A master piece at its time, and quite decent to maintain with the documentation:

'CS 134 or 145 or a mark of 60% or higher in 136 or 138; Honours Mathematics or Software Engineering students only.'
'([A-Z]{2,5} \d{3}) or (\d{3})*'
('CS 134', '145')

'One of CS 134, 136, 138, 145; Computer Science students only.'
'([A-Z]{2,5} \d{3})([, \d{3}]*;)'
('CS 134', ', 136, 138, 145;')

'Computer Science students only.'
'(\D* students only)'
'Computer Science students only'

'CS 350 or ECE 354'
'([A-Z]{2,5} \d{3}) or ([A-Z]{2,5} \d{3})*'
('CS 350', 'ECE 354')

'CM 339/CS 341 or CS 350'
'([A-Z]{2,5} \d{3})/([A-Z]{2,5} \d{3})( or [A-Z]{2,5} \d{3})*'
('CM 339', 'CS 341', ' or CS 350')

'DAC 201/ENGL 203 and DAC 202/ENGL 204'
 '([A-Z]{2,5} \d{3})/([A-Z]{2,5} \d{3}).*([A-Z]{2,5} \d{3})/([A-Z]{2,5} \d{3})*'
('DAC 201', 'ENGL 203', 'AC 202', 'ENGL 204')

And a light comes through. There is a better way, better than I ever imagined. In fact, the ugly phase of evolution comes before the flowering. A metaphor for this would be the pollution during industrialization and a bloom of clean industries following it due to the emphasis on knowledge rather than machine labor.
Simply pass on the parenthesis in the lexer and rewrite the grammar so that it can see more of the input before having to make a decision for shift/reduce conflicts. This is similar to using a parser with more lookahead, an oracle that sees infinitely many steps ahead.

Yet, no matter how sweet the code,

it is time to part ways.

What comes next,

no one knows.

This age is past,

and the ground is laid for the next one.

No responses yet