The first warmup in this class and the rasterizer and raytracer MPs are very open-ended. In theory by the time you take a 400-level class you should know enough to handle writing a program with no skeleton code, but some class has to be the first one to ask you to actually do that and for some of you that first class is this class. This is my effort at making that less daunting.

1 The cumulative effect of marginal improvements

Question
How do I write a N-line program?
Answer
By adding a few lines to an (N-\epsilon)-line program.

When faced with a big open-ended task like write an entire rasterizer, start by asking yourself what’s one thing the program has to do that can be done on its own? Maybe the answer is read a text file or create a PNG file or split lines of text into tokens. Write a program that does just that one thing, nothing else. Test it. Fix it. Test it again. Celebrate that you’ve got one thing working!

Then ask yourself what’s one additional thing it needs to do? Sometimes that’s something you can just add, either on its own or fitting nicely into what you’ve already done. Sometimes it’s something you can build out in its own little test program, then integrate later. Sometimes it’s something that requires you to first refactor your code, changing how it is doing what it is already doing so there’s a good place for what you’re adding.

And so on.

I have written programs of several hundred lines in one go, but that’s a very risky thing to do. Almost every program I’ve ever written was a small delta on a program I’d also written.

2 Data structures to match mental structures

Question
What data structures should I use to implement this algorithm?
Answer
The same ones you use to describe it.

If (a) an algorithm is described (either by me in the course material or by you when thinking about it) by referring to points or vectors or colors or pixels or rays or spheres or some other thing, and (b) you don’t have that thing as a data structure/object type in your code, then (c) you are doing things the hard way.

Perhaps even more importantly, if you have something you would refer to in describing the code that you store in several different data structures at the same time, you’ve set yourself up for confusing bugs. Should the thing we describe as a vector be a list or array or tuple or custom class? It may be one of those is better than another, but the worst of them is still better than some kind of chimera mix-and-match. One structure for one concept.

3 Don’t repeat yourself

In principle, any piece of code can be factored out into its own function. The following are all signs that a piece of code should be factored out as a function:

  • If what the code is doing has a name, put it in a function with that name.

  • If you wrote code by copy-paste-edit, you probably should have moved it into a function (or possibly a loop) instead.

  • If you ask yourself should this be its own function? the answer is generally yes.

4 I’ve never used X before

4.1 I’ve never used Makefiles before

We’re barely using them in this class: just enough to make code run regardless of the language you write in, and we give you example Makefiles you can use as-is.

If you don’t have make installed, odds are you are running Windows and need to download it using one of the following:

It’s easy to find people who don’t like make and there are many alternatives but as of 2023, make is still prevalent in open source and one of the few options that I have confidence will still be available and functioning 20 years from now.

4.2 I’ve never used command-line arguments before

Under the hood, most operating systems still invoke programs the way they did before the advent of graphical user interfaces: with a list of strings called command-line arguments. Traditionally the first such argument (at index 0) is the name of the program file itself and the first real argument is the second in the list (at index 1), though some programming languages violate that tradition.

You can access the command-line arguments (which is a list of strings) as

C/C++
The argv in int main(int argc, char *argv[])
C#
The args in static void Main(string[] args)
Dart
The arguments in void main(List<String> arguments)
Go
First, import os; then it’s os.Args
Haskell
First, import System.Environment; then it’s returned by getArgs
Java
The args in public static void main(String[] args)
Python
First, import sys; then it’s sys.argv
Rust
First, use std::env; then it’s returned by env::args().collect()
Typescript
First, import node:process; then it’s process.argv

The programs we have you write only take one argument, the name of a single input file (like mp1ex1.txt) that you should read.

4.3 I’ve never used code outside a Jupyter notebook before

This is a bit bigger than I can handle here; the ability to write code that works on its own is a prereq for this course (covered in CS 225 and its prereqs). That said, broadly speaking you need

  1. A file-editing development environment like an IDE or text editor. I use geany but VS Code, sublime, and atom are more popular among students.

  2. To adopt the code-and-execute patterns your editor or IDE assumes.