CSC230 Homework 6: Turtle Graphics
This homework is to be done individually.
Only use ANSI C99 standard library functions (excluding system()
). Other libraries, like GNU libraries, etc., are not allowed.
- Minor: Added a separate header for the
LD_LIBRARY_PATH
stuff so it doesn't get lost in the boilerplate github directions that people skip.
- Updated the Makefile diagram to (a) correct it by adding dependencies between the executables and libCTurtle.so and (b) clarifying that the compiler flags are applied in building the target, not on an individual dependency edge.
- Essential update to starter kit (sorry!): I failed to include an improvement in the student version of CTurtle.py. The latest starter kit includes this fix. No other files have changed.
- Instructor test details added.
- Added small clarification of the behavior of
do_pixel
for coordinates outside of the image dimensions: skip such pixels and don't segfault. - Update to starter kit (optional!): Minor bugfix to the reference implementation in the starter kit. No upgrade is necessary unless you want a healthy reference library to compare against.
Learning Outcomes
- Write small to medium C programs having several separately-compiled modules.
- Explain what happens to a program during preprocessing, lexical analysis, parsing, code generation, code optimization, linking, and execution, and identify errors that occur during each phase. In particular, they will be able to describe the differences in this process between C and Java.
- Correctly identify error messages and warnings from the preprocessor, compiler, and linker, and avoid them.
- Find and eliminate runtime errors using a combination of logic, language understanding, trace printout, and gdb or a similar command-line debugger.
- Interpret and explain data types, conversions between data types, and the possibility of overflow and underflow.
- Explain, inspect, and implement programs using structures such as enumerated types, unions, and constants and arithmetic, logical, relational, assignment, and bitwise operators.
- Trace and reason about variables and their scope in a single function, across multiple functions, and across multiple modules.
- Allocate and deallocate memory in C programs while avoiding memory leaks and dangling pointers. In particular, they will be able to implement dynamic arrays and singly-linked lists using allocated memory.
- Use the C preprocessor to control tracing of programs, compilation for different systems, and write simple macros.
- Write, debug, and modify programs using library utilities, including, but not limited to assert, the math library, the string library, random number generation, variable number of parameters, standard I/O, and file I/O.
- Use simple command-line tools to design, document, debug, and maintain their programs.
- Use an automatic packaging tool, such as make or ant, to distribute and maintain software that has multiple compilation units.
- Use a version control tools, such as subversion (svn) or git, to track changes and do parallel development of software.
- Distinguish key elements of the syntax (what’s legal), semantics (what does it do), and pragmatics (how is it used) of a programming language.
Introduction
Turtle graphics were developed in the 1960's to study robotics, and later adapted to educate students in computer programming in concert with the LOGO programming language.
They are capable of rendering complex, interesting images with relatively simple algorithms.
The concept is that there is a cursor called the "turtle" on a 2D plane representing an image.
This cursor has a position and a direction, and can be told to go "forward" (drawing a line behind it) or to turn "left" or "right" (changing the angle that will be traversed when it goes forward).
It can also do things like lift its virtual drawing "pen" up and down, change color, etc.
An simple example of turtle graphics is shown to the right, where an interactive turtle is used to draw four boxes.
In this assignment, you're going to implement a shared library (.so file) that implements turtle graphics, and it's going to be many times faster than the animation shown, rendering complex images in a few milliseconds. Features of this library will include:
- Basic turtle graphics.
- Read/write support for Targa (.tga) and Portable Pixmap (.ppm) image files.
- A few basic image manipulation algorithms.
- A front-end allowing use of the library seamlessly from Python.
As image processing is not the focus of this course, this document will provide you algorithms for the non-trivial graphics algorithms.
Program Requirements
API

You are provided with the header file for the library, CTurtle.h. This file constitutes your contract with the user of the library; you may not modify content it in any way except to optionally add entirely new functions. The file is documented with the behavior of each supported function to be implemented in CTurtle.c. This API can be used to create all sorts of fancy graphics, such as the Hilbert curve fractal shown to the right.
Images structs will be created by the program in one of three ways:
Function | Purpose |
---|---|
create_image() | Create a new image of the given dimensions, all pixels defaulting to black. |
read_tga() | Reads the given file and returns a new Image struct representing it -- only certain kinds of .tga files are supported (see below). |
read_ppm() | Reads the given file and returns a new Image struct representing it -- only certain kinds of .ppm files are supported (see below). |
If an error occurs during file IO, users can get a string representing this error by calling get_last_error()
.
In order to free these objects, users of the API will call destroy_image()
.
Users can write direct graphics onto the canvas using the following functions -- these have no effect on the turtle.
Function | Purpose |
---|---|
do_pixel() | Set the given pixel to the given color. If the pixel lies outside of the image dimensions, ignore the request. |
do_line() | Draw a line from (x0,y0) to (x1,y1) using the given color. If any pixel of the line lies outside of the image dimensions, ignore that pixel. |
do_clear() | Blank the entire canvas with the given color. |
do_invert() | Invert all pixels of the image, giving the "negative" image. |
do_reverse_rgb() | Switch red and blue channels in the image. |
For turtle graphics, the supported functions are:
Function | Purpose |
---|---|
turtle_set_xy() | Move the turtle to the given position without drawing anything. |
turtle_move() | Move the turtle to the given position, drawing a line as it goes if the pen is down. |
turtle_forward() | Move the turtle in the current direction by d pixels, drawing as it goes if the pen is down. |
turtle_face_north() | Reset the angle of the turtle to north. |
turtle_left() | Turn left by the number of degrees given. |
turtle_right() | Turn right by the number of degrees given. |
turtle_pen_up() | Lift the "pen", causing turtle move and forward to not draw anything. |
turtle_pen_down() | Put the "pen" down, causing turtle move and forward to draw lines. |
turtle_set_color() | Change the current turtle color. |
Error handling: There are a number of error cases whose precise result is not specified in this document.
For IO related errors, the correct response is to return NULL
or false
and place an appropriate message to be returned by get_last_error()
.
If the IO error was from a system call (such as fopen
), the error message should be the system-provided one, i.e. strerror(errno)
.
If the IO error was format or parsing related, provide the error message given in the tables below, or if a specific message isn't given in this document, provide a descriptive error message of your choosing.
For non-IO errors, simply return NULL or false as appropriate.
You will not be tested on specific error conditions not described in this document except to verify that your program does not crash (e.g. segfault).
Library behavior:
- Good libraries don't print to
stdout
orstderr
-- you don't know what the user is trying to do with the console, so don't interfere. It's okay to print stuff while you're developing, though -- just take it all out before you're done. - Your library shouldn't care about command line arguments -- you don't know if you're part of a program that even uses command line arguments.
- In addition, good libraries don't
exit()
when there's an error -- you give that error back to the user of the library to decide what to do about it.
TGA support
Truevision TGA is an old but fairly well supported graphic format that has its origins in the TARGA video card of early IBM PC, which was the first graphics card to support true photorealistic color. It has several modes and options that will not be supported by your library, specifically:
Feature | Description | Support | Read behavior | Write behavior |
---|---|---|---|---|
Image ID field | Files could store extra metadata in the image id field. | Unsupported | If the image reports an image ID field of non-zero length, fail with error "TGA id field not supported" | Emit files without an image ID field (so image id field length is zero) |
Color map | Files could have a "palette" of fixed colors. | Unsupported | If the image has a non-zero value for color map type, color map length, or color map first entry, then fail with error "TGA color map not supported" | Emit files with no color map (color map fields are zero) |
Multiple image types | TGA supports a variety of image formats and compression levels | RGB uncompressed only | If the image has an image type of any value other than 2 (RGB uncompressed), fail with error "Unsupported image type, only uncompressed RGB is supported" | Emit files with image type 2 (uncompressed RGB) |
Origin | Files can specify where (0,0) is on their canvas | Ignore | Simply ignore these fields | Set these fields to zero |
Pixel depth | How many bits per pixel? | 24-bit RGB | The bpp (bits per pixel) must be 24; if it isn't, fail with the message "Unsupported image type, bit depth must be 24" | Emit files with bpp of 24. |
Image descriptor | TGA has a field to indicate the nubmer of bits of transparency as well as if the image is written top-to-bottom or bottom-to-top. | No transparency, top-to-bottom only | The image descriptor must be 0x20 (zero transparency bits, bit 5 indicating that the image is read top-to-bottom). If it isn't, fail with the message "Unsupported image format, TGA image descriptor must be 0x20". | Emit files with image descriptor set to 0x20. |
Tips on supporting this file format are given in the Implementation section later in this document.
PPM support
The Portable Pixmap (PPM) format was developed to be easy to read and write on a variety of platforms. There are six formats in this family, two of which will be supported by your library.
Format | Description | Supported? |
---|---|---|
P1 | Portable bitmap (.pbm), 1 bit per pixel monochrome, ASCII format | No |
P2 | Portable greymap (.pgm), 8 bit per pixel greyscale, ASCII format | No |
P3 | Portable pixmap (.ppm), 24 bit per pixel true color, ASCII format | Yes |
P4 | Portable bitmap (.pbm), 1 bit per pixel monochrome, binary format | No |
P5 | Portable greymap (.pgm), 8 bit per pixel greyscale, binary format | No |
P6 | Portable pixmap (.ppm), 24 bit per pixel true color, binary format | Yes |
Error handling: If a file is provided which does not start with 'P', fail with the error message "Improperly formatted PPM file". If the character following the 'P' is something other than '3' or '6', fail with the error message "Only P3 and P6 formats are supported".
Tips on supporting this file format are given in the Implementation section later in this document.
Python bindings
Your library will be usable by C programs directly, but it will be able to be called from programs written in the Python programming language. As this is not a course on Python, almost all of the bindings have been written for you:CTurtle.py
.
However, you will need to add the bindings for face_north()
, left()
, and right()
.
Artistic self-expression
Once you have completed the library, in either C or Python, you will write a client program that links this library, and use it to produce an image which you deem to be aesthetically pleasing and/or cool looking.Requirements:
- No smaller than 1280x720 (standard 720p resolution)
- No larger than 3840x2160 (standard 4k resolution)
- You may base it on an input image as opposed to a blank canvas, but your program must make substantive changes to this image.
- You may add functions beyond those presented in CTurtle.h and take advantage of them to generate your image. You may not alter any of the provided function prototypes, however.
- You may not post-process the image in any way.
If you're looking for inspiration, note that turtle graphics are often used for linear fractals. See A Very Patient Turtle Who Draws Lines, L-Systems, and chapter 5 of Mathematical Problem Solving with Computers by Simanca & Sutherland.
Design
The starter kit includes the following files:
File | Description | Changes needed? |
---|---|---|
CTurtle.h | Interface of the CTurtle library | None, unless you want to add optional functionality |
CTurtle.c | Implementation of the CTurtle library | Write from scratch |
CTurtle.py | Python binding for the CTurtle library | Need to add a few function bindings |
cturtle_test.c | Student test suite written in C | None (you may add to this file at your discretion) |
pyturtle_test.py | Student test suite written in Python | None (you may add to this file at your discretion) |
Makefile | Used to build the project | Write from scratch |
test.sh | Student test script -- runs both C and Python tests | None (you may add to this file at your discretion) |
test-in/* | Test input files | None (you may add test inputs at your discretion) |
test-out/ | Test output directory | None (the test script will deposit results here) |
test-out/expected* | Test expected outputs | None (the test script will compare results against these files) |
In addition, you must create the following files:
File | Description |
---|---|
cturtle_make_art.c OR cturtle_make_art.py | Creates the artistic expression required. If written in C, compiles to cturtle_make_art .
|
fantastic_art.tga OR fantastic_art.ppm | The artistic expression, in TGA format or binary PPM format. Do NOT submit in ASCII PPM format (it's too big). |
The Makefile
: Your Makefile should implement the following dependency graph:

The arrows are labeled with important gcc options that will be needed. Blue nodes represent source files, yellow are binaries, and pink are dummy targets.
Note: your dependency graph may differ slightly depending on if you make your art in Python versus C, and if your art is in PPM rather than TGA format.
Implementation
Workflow
Get your environment set up
Note: If you successfully cloned your GitHub repo for HW2, you can skip to the section "Get the starter files". Make sure that you're developing in the 6_homework
directory!
Start by cloning the provided CSC230 GitHub repo in your local AFS (or development space) using the following commands:
$
This will create a directory with your repo's name. If you cd
into the directory, you should see directories for each of the homeworks for the class. You'll want to do all of your development in 6_homework
. If you do NOT see the 6_homework
directory, enter the following command to make the directory:
Setting LD_LIBRARY_PATH
so your library can be linked at runtime
Because we are building a library, we'll need to include our development area in the LD_LIBRARY_PATH
environment variable. You can do this by executing the following in your development directory:
If you get sick of typing that every time, put the command above into a file called prep
(or whatever) and have your shell read it in with the source
command:
Note that the source
command is so frequently used that it can be appreviated to a single dot:
Get the starter files
Next, you will need to copy the hw6_starter.tgz
from the course locker into your 6_homework
directory. Use the following command:
Untar using the command:
Set up your Makefile
In addition, the Makefile
is empty -- you will also need to write this. Requirements:
- The Makefile must be written such that when
make
is executed, it buildscturtle_test
andlibCTurtle.so
. - The "clean" target must also be specified, such that it removes all compilation results (any executables and object files).
- Compiling to an intermediate object file (*.o) is required.
See the Design section above for tips on building your Makefile
.
Write your code: CTurtle.c
Your code library code should be implemented in CTurtle.c
. You must use the appropriate name for automated grading.
Complete the Python bindings: CTurtle.py
You will add the missing bindings for face_north()
, left()
, and right()
. If you do not do this, then some of the Python test cases will not pass, even if your C code is complete.
Create art: cturtle_make_art.c
or cturtle_make_art.py
; fantastic_art.tga
or fantastic_art.ppm
Use your library to create a C or Python program which generates a cool looking image.
Structs and typedefs
The color of individual pixels will be represented by a Color struct:
Therefore, to represent an image, you simply need an array of Color
structs.
The typedef is present so that Color
is a top-level name that is an alais for struct Color
.
The #pragma
directives ensure that no padding is added to this struct by the compiler -- see the Implementing TGA section for details on how this works.
Images will be represented by a heap-allocated Image struct:
Note the typedef of struct Image* to Image. This will make Image function somewhat similar to a traditional OO object -- it's allocated at creation time and freed at destruction time. In addition, there's also a heap-allocated region for the pixels themselves. This is comprised of Color structs, each containing one byte for red, green, and blue. Therefore, each image actually consists of two heap-allocated regions -- a fixed-size Image struct and a variably sized array of Color structs pointed to by the Image member pixels.
Introduction to graphics
Images are two-dimensional matrices of colored dots called pixels.
On a modern true-color system, each pixel is represented by three unsigned bytes: red, green, and blue.
These colors correspond to the light receptors in your eyes.
We refer to this as 24-bit RGB.
These colors combine additively, as shown in the diagram on the right.
For example, {0,0,0} represents black, {255,0,0} represents red, and {0,255,0} represents green. If you add red and green:
{255,0,0} + {0,255,0} = {255,255,0}You get {255,255,0}, which is yellow. From this, we conclude that {255,255,255} is white.
Individual pixels are located on an XY plane. Different applications orient the coordinates differently. In this program, we're going to use a common format: the origin (0,0) is at the upper left of the image. This means that positive X values are to the right, and positive Y values are to the bottom.
To change a pixel's color, you simply change its value. Because we're using calloc
to allocate the pixels
array, you're going to end up with a one-dimensional array of Color
structs which you can index with the expression:
From there, you can access the r
, g
, and b
members.
A line drawing algorithm for do_line()
It's actually surprisingly hard to draw a line out of pixels (see this article for an explanation why).
Because this isn't a graphics course, we will simply provide a straightforward algorithm for line drawing, Bresenham's line algorithm:
Above, plot
means set pixel to the desired color.
Implementing turtle_forward()
The turtle_forward()
walks the turtle forward a given number of pixels along the current compass heading, the angle
.
To do this requires a bit of trigonometry that you might be rusty on.
If you're at position (x,y)
with an angle
specified in integer degrees and you walk d
units, then you can compute your new position with these formulas:
Note the difference in sign. In traditional math, the increasing Y dimension points up. However, in most graphics applications, the increasing Y dimension points down, because the graphical origin is the upper-left corner. We negate the adjustment to Y to accomodate this difference.
Once you have this, you can draw the line by relying on the do_line()
function.
Implementing TGA support
TGA is a fully binary file format. TGA files start with a fixed-header, some optional fields your library won't support, then a dump of the raw pixel data.
Packed structs: It is recommended that you model the TGA header as a struct.
However, you will need to tell the compiler not to insert any "padding" space in the struct's layout.
On gcc, you can do this by using the #pragma
directive, which sets compiler-specific settings. For example:
The first #pragma
says "pack this struct to the nearest 1 byte (i.e. no padding), and push this setting onto a setting stack.
The setting stack is used so you can append the following right after the struct to undo this change with the second #pragma
directive,
which pops the original pack setting from the setting stack.
Header layout: To determine the content of this struct, you can refer to the original 80's-era specification, the Wikipedia article for it, or this detailed discussion of the format. (Note that historical documentation may refer to 16-bit values as a "word", because this was the dominant word size at the time.)
Channel order: One important thing to note is the order of colors in a pixel -- TGA files store their pixels in BGR order rather than RGB.
This means that you will need to swap the red and blue channels before writing the TGA pixel data, then swap them back the image remains stored properly in memory.
This is an ideal place to use the do_reverse_rgb()
function.
File IO: Use the C standard IO methods for binary file IO (fopen
, fread
, fwrite
, etc.).
When loading, read in the struct, parse it, allocate space for width*height
the pixels, then read in the appropriate number of pixels into this space.
You can read the whole TGA file in two fread
calls.
Similarly, you can write a whole TGA file with two fwrite
calls.
Also, because we're doing binary IO, be sure to include the "b
" flag in your fopen
call.
Implementing PPM support
This standard includes six formats: P1 through P6. We'll focus on just the P3 and P6 formats, which are the only two you will support.
Header format: Both of these formats share a single header, which is ASCII (even if the pixel data is in binary, as in format P6). This format is:
WIDTH
and HEIGHT
, predictably, refer to the dimensions of the image, in pixels.
MAX_VALUE
indicates what numeric value corresponds to full intensity. It is usually 255, the max unsigned byte value.
However, if it isn't when reading a file in, you will need to scale all pixels by 255.0/MAX_VALUE
.
After the newline following the MAX_VALUE
, the actual pixel data is emitted.
For P3 format, this is as a series of whitespace-delimited human-readable numbers suitable for reading with scanf.
For P6 format, this is a binary dump of the image pixel data, suitable for slurping up with a single call to fread
.
However, when reading P6 format, make sure you explicitly read all the way to the newline following MAX_VALUE
before reading binary data.
If you read in the newline as part of the pixel data, your whole image will be off by one byte!
Channel order: Unlike TGA, PPM stores colors in RGB, meaning you can simply read the channel values in the order they appear.
In fact, for P6 format, you can fread
all the pixels at once.
For more information, see the detailed spec or Wikipedia's Netpbm article.
Testing
When you are ready to run the full suite of tests, execute the test script test.sh
.
We'll prepare to do this by ensuring that the script (as well as the Python front-end) are marked as being executable:
This sets the permissions of test.sh
to allow for execution.
It also enables execution of pyturtle_test.py
, which is a Python script that can be executed directly on the command line.
You only have to run this command once.
Pushing changes
When you are ready to commit to your local repository, execute:
$
When you are ready to submit to the remote repository for automated grading or teaching staff feedback, execute:
Testing
Two test suite utilities are provided: cturtle_test.c
and pyturtle_test.py
.
These are functionally identical in their outputs, but the Python version relies on the bindings in CPython.py
in addition to your library.
The script test.sh
uses these to launch a series of tests. Each test produces image file outputs in all three formats (TGA, ASCII PPM, and binary PPM) using both the C and Python test tools.
Your library must emit nothing to stdout or stderr, and it must produce output files which match the expected results exactly for automated grading.
The syntax of both tools is:
The
Testing is divided into "test groups", where each group is seeking to produce a specific image.
Each test group has test variants for the C and Python front-ends, and each of the three output formats (TGA, ASCII PPM, and binary PPM).
The script will produce files with filenames of the following format:
Further, when run by test.sh
, the stdout and stderr of the program will be logged to "test-out/
".
Because the test program writes errors from get_last_error() to stdout, this is how we will check error message output.
The test.sh
will compare all these outputs to the appropriate file of the form "test-out/expected-*
".
Some of the test modes (5,6,7) take a parameter test-out/
directory to be verified by the test.sh
.
Grading will test additional inputs and outputs, so you should test your program with inputs and outputs beyond the provided examples.
The test cases and testing script (e.g., test.sh
) are provided for you in hw6_starter.tgz.
See the Implementation section for details about setting up your work environment and how to use hw6_starter.tgz.
If your program does NOT pass the tests in test.sh
then it will not be able to pass the teaching staff test cases.
Use test.sh
as a method to verify that at least the minimum requirements have been met for this assignment.
The details of the provided tests are:
Test IDs | Outputs | Description | Image |
---|---|---|---|
Test group 'T01' Test 'T01-c.tga' Test 'T01-c.a.ppm' Test 'T01-c.b.ppm' Test 'T01-py.tga' Test 'T01-py.a.ppm' Test 'T01-py.b.ppm' |
Image outputs: T01-c.tga T01-c.a.ppm T01-c.b.ppm T01-py.tga T01-py.a.ppm T01-py.b.ppm Console logs: T01-c.tga.log T01-c.a.ppm.log T01-c.b.ppm.log T01-py.tga.log T01-py.a.ppm.log T01-py.b.ppm.log | Simple 3x5 image, reg/green/blue dots going down the middle, white dots in the corners | ![]() Enlarged 10x |
Test group 'T02' Test 'T02-c.tga' Test 'T02-c.a.ppm' Test 'T02-c.b.ppm' Test 'T02-py.tga' Test 'T02-py.a.ppm' Test 'T02-py.b.ppm' |
Image outputs: T02-c.tga T02-c.a.ppm T02-c.b.ppm T02-py.tga T02-py.a.ppm T02-py.b.ppm Console logs: T02-c.tga.log T02-c.a.ppm.log T02-c.b.ppm.log T02-py.tga.log T02-py.a.ppm.log T02-py.b.ppm.log | Same as test 1, but invert at the end | ![]() Enlarged 10x |
Test group 'T03' Test 'T03-c.tga' Test 'T03-c.a.ppm' Test 'T03-c.b.ppm' Test 'T03-py.tga' Test 'T03-py.a.ppm' Test 'T03-py.b.ppm' |
Image outputs: T03-c.tga T03-c.a.ppm T03-c.b.ppm T03-py.tga T03-py.a.ppm T03-py.b.ppm Console logs: T03-c.tga.log T03-c.a.ppm.log T03-c.b.ppm.log T03-py.tga.log T03-py.a.ppm.log T03-py.b.ppm.log | Same as test 1, but reverse rgb at the end | ![]() Enlarged 10x |
Test group 'T04' Test 'T04-c.tga' Test 'T04-c.a.ppm' Test 'T04-c.b.ppm' Test 'T04-py.tga' Test 'T04-py.a.ppm' Test 'T04-py.b.ppm' |
Image outputs: T04-c.tga T04-c.a.ppm T04-c.b.ppm T04-py.tga T04-py.a.ppm T04-py.b.ppm Console logs: T04-c.tga.log T04-c.a.ppm.log T04-c.b.ppm.log T04-py.tga.log T04-py.a.ppm.log T04-py.b.ppm.log | A colored triforce pattern on the left of a 150x60 dark blue background | ![]() |
Test group 'T05-toucan.tga' Test 'T05-toucan.tga-c.tga' Test 'T05-toucan.tga-c.a.ppm' Test 'T05-toucan.tga-c.b.ppm' Test 'T05-toucan.tga-py.tga' Test 'T05-toucan.tga-py.a.ppm' Test 'T05-toucan.tga-py.b.ppm' |
Image outputs: T05-toucan.tga-c.tga T05-toucan.tga-c.a.ppm T05-toucan.tga-c.b.ppm T05-toucan.tga-py.tga T05-toucan.tga-py.a.ppm T05-toucan.tga-py.b.ppm Console logs: T05-toucan.tga-c.tga.log T05-toucan.tga-c.a.ppm.log T05-toucan.tga-c.b.ppm.log T05-toucan.tga-py.tga.log T05-toucan.tga-py.a.ppm.log T05-toucan.tga-py.b.ppm.log | Read toucan.tga and output it (no changes) | ![]() |
Test group 'T05-toucan.a.ppm' Test 'T05-toucan.a.ppm-c.tga' Test 'T05-toucan.a.ppm-c.a.ppm' Test 'T05-toucan.a.ppm-c.b.ppm' Test 'T05-toucan.a.ppm-py.tga' Test 'T05-toucan.a.ppm-py.a.ppm' Test 'T05-toucan.a.ppm-py.b.ppm' |
Image outputs: T05-toucan.a.ppm-c.tga T05-toucan.a.ppm-c.a.ppm T05-toucan.a.ppm-c.b.ppm T05-toucan.a.ppm-py.tga T05-toucan.a.ppm-py.a.ppm T05-toucan.a.ppm-py.b.ppm Console logs: T05-toucan.a.ppm-c.tga.log T05-toucan.a.ppm-c.a.ppm.log T05-toucan.a.ppm-c.b.ppm.log T05-toucan.a.ppm-py.tga.log T05-toucan.a.ppm-py.a.ppm.log T05-toucan.a.ppm-py.b.ppm.log | Read toucan.a.ppm (ASCII PPM) and output it (no changes) | ![]() |
Test group 'T05-toucan.b.ppm' Test 'T05-toucan.b.ppm-c.tga' Test 'T05-toucan.b.ppm-c.a.ppm' Test 'T05-toucan.b.ppm-c.b.ppm' Test 'T05-toucan.b.ppm-py.tga' Test 'T05-toucan.b.ppm-py.a.ppm' Test 'T05-toucan.b.ppm-py.b.ppm' |
Image outputs: T05-toucan.b.ppm-c.tga T05-toucan.b.ppm-c.a.ppm T05-toucan.b.ppm-c.b.ppm T05-toucan.b.ppm-py.tga T05-toucan.b.ppm-py.a.ppm T05-toucan.b.ppm-py.b.ppm Console logs: T05-toucan.b.ppm-c.tga.log T05-toucan.b.ppm-c.a.ppm.log T05-toucan.b.ppm-c.b.ppm.log T05-toucan.b.ppm-py.tga.log T05-toucan.b.ppm-py.a.ppm.log T05-toucan.b.ppm-py.b.ppm.log | Read toucan.b.ppm (binary PPM) and output it (no changes) | ![]() |
Test group 'T05-scaled.a.ppm' Test 'T05-scaled.a.ppm-c.tga' Test 'T05-scaled.a.ppm-c.a.ppm' Test 'T05-scaled.a.ppm-c.b.ppm' Test 'T05-scaled.a.ppm-py.tga' Test 'T05-scaled.a.ppm-py.a.ppm' Test 'T05-scaled.a.ppm-py.b.ppm' |
Image outputs: T05-scaled.a.ppm-c.tga T05-scaled.a.ppm-c.a.ppm T05-scaled.a.ppm-c.b.ppm T05-scaled.a.ppm-py.tga T05-scaled.a.ppm-py.a.ppm T05-scaled.a.ppm-py.b.ppm Console logs: T05-scaled.a.ppm-c.tga.log T05-scaled.a.ppm-c.a.ppm.log T05-scaled.a.ppm-c.b.ppm.log T05-scaled.a.ppm-py.tga.log T05-scaled.a.ppm-py.a.ppm.log T05-scaled.a.ppm-py.b.ppm.log | Read scaled.a.ppm (an ASCII PPM with a non-255 max value) and output it as the test output files (no changes) | ![]() Enlarged 10x |
Test group 'T05-pgm_unsupp_grey.ppm' Test 'T05-pgm_unsupp_grey.ppm-c.tga' Test 'T05-pgm_unsupp_grey.ppm-py.tga' |
Image outputs: (none) Console logs: T05-pgm_unsupp_grey.ppm-c.tga.log T05-pgm_unsupp_grey.ppm-py.tga.log | Attempt to read pgm_unsupp_grey.ppm, failing because it is an unsupported type | n/a |
Test group 'T05-tga_unsupp_colormap.tga' Test 'T05-tga_unsupp_colormap.tga-c.tga' Test 'T05-tga_unsupp_colormap.tga-py.tga' |
Image outputs: (none) Console logs: T05-tga_unsupp_colormap.tga-c.tga.log T05-tga_unsupp_colormap.tga-py.tga.log | Attempt to read tga_unsupp_colormap.tga, failing because it has a color map, which is unsupported | n/a |
Test group 'T05-tga_unsupp_compression.tga' Test 'T05-tga_unsupp_compression.tga-c.tga' Test 'T05-tga_unsupp_compression.tga-py.tga' |
Image outputs: (none) Console logs: T05-tga_unsupp_compression.tga-c.tga.log T05-tga_unsupp_compression.tga-py.tga.log | Attempt to read tga_unsupp_compression.tga, failing because it is compressed, which is unsupported | n/a |
Test group 'T05-tga_unsupp_image_desc.tga' Test 'T05-tga_unsupp_image_desc.tga-c.tga' Test 'T05-tga_unsupp_image_desc.tga-py.tga' |
Image outputs: (none) Console logs: T05-tga_unsupp_image_desc.tga-c.tga.log T05-tga_unsupp_image_desc.tga-py.tga.log | Attempt to read tga_unsupp_image_desc.tga, failing because it has an unsupported image descriptor value | n/a |
Test group 'T06-toucan.a.ppm' Test 'T06-toucan.a.ppm-c.tga' Test 'T06-toucan.a.ppm-c.a.ppm' Test 'T06-toucan.a.ppm-c.b.ppm' Test 'T06-toucan.a.ppm-py.tga' Test 'T06-toucan.a.ppm-py.a.ppm' Test 'T06-toucan.a.ppm-py.b.ppm' |
Image outputs: T06-toucan.a.ppm-c.tga T06-toucan.a.ppm-c.a.ppm T06-toucan.a.ppm-c.b.ppm T06-toucan.a.ppm-py.tga T06-toucan.a.ppm-py.a.ppm T06-toucan.a.ppm-py.b.ppm Console logs: T06-toucan.a.ppm-c.tga.log T06-toucan.a.ppm-c.a.ppm.log T06-toucan.a.ppm-c.b.ppm.log T06-toucan.a.ppm-py.tga.log T06-toucan.a.ppm-py.a.ppm.log T06-toucan.a.ppm-py.b.ppm.log | Read toucan.a.ppm (ASCII PPM) and output it with rgb reversed | ![]() |
Test group 'T07-toucan.a.ppm' Test 'T07-toucan.a.ppm-c.tga' Test 'T07-toucan.a.ppm-c.a.ppm' Test 'T07-toucan.a.ppm-c.b.ppm' Test 'T07-toucan.a.ppm-py.tga' Test 'T07-toucan.a.ppm-py.a.ppm' Test 'T07-toucan.a.ppm-py.b.ppm' |
Image outputs: T07-toucan.a.ppm-c.tga T07-toucan.a.ppm-c.a.ppm T07-toucan.a.ppm-c.b.ppm T07-toucan.a.ppm-py.tga T07-toucan.a.ppm-py.a.ppm T07-toucan.a.ppm-py.b.ppm Console logs: T07-toucan.a.ppm-c.tga.log T07-toucan.a.ppm-c.a.ppm.log T07-toucan.a.ppm-c.b.ppm.log T07-toucan.a.ppm-py.tga.log T07-toucan.a.ppm-py.a.ppm.log T07-toucan.a.ppm-py.b.ppm.log | Read toucan.a.ppm (ASCII PPM) and invert it, then draw most of test 2 on top of it | ![]() |
Test group 'T08' Test 'T08-c.tga' Test 'T08-c.a.ppm' Test 'T08-c.b.ppm' Test 'T08-py.tga' Test 'T08-py.a.ppm' Test 'T08-py.b.ppm' |
Image outputs: T08-c.tga T08-c.a.ppm T08-c.b.ppm T08-py.tga T08-py.a.ppm T08-py.b.ppm Console logs: T08-c.tga.log T08-c.a.ppm.log T08-c.b.ppm.log T08-py.tga.log T08-py.a.ppm.log T08-py.b.ppm.log | The "hello world" of turtle graphics -- drawing one line with the default settings in the default direction | ![]() |
Test group 'T09' Test 'T09-c.tga' Test 'T09-c.a.ppm' Test 'T09-c.b.ppm' Test 'T09-py.tga' Test 'T09-py.a.ppm' Test 'T09-py.b.ppm' |
Image outputs: T09-c.tga T09-c.a.ppm T09-c.b.ppm T09-py.tga T09-py.a.ppm T09-py.b.ppm Console logs: T09-c.tga.log T09-c.a.ppm.log T09-c.b.ppm.log T09-py.tga.log T09-py.a.ppm.log T09-py.b.ppm.log | Same as 8, but turn a bit first | ![]() |
Test group 'T10' Test 'T10-c.tga' Test 'T10-c.a.ppm' Test 'T10-c.b.ppm' Test 'T10-py.tga' Test 'T10-py.a.ppm' Test 'T10-py.b.ppm' |
Image outputs: T10-c.tga T10-c.a.ppm T10-c.b.ppm T10-py.tga T10-py.a.ppm T10-py.b.ppm Console logs: T10-c.tga.log T10-c.a.ppm.log T10-c.b.ppm.log T10-py.tga.log T10-py.a.ppm.log T10-py.b.ppm.log | Simple triangle with different colors on each edge (red/orange/yellow) | ![]() |
Test group 'T11' Test 'T11-c.tga' Test 'T11-c.a.ppm' Test 'T11-c.b.ppm' Test 'T11-py.tga' Test 'T11-py.a.ppm' Test 'T11-py.b.ppm' |
Image outputs: T11-c.tga T11-c.a.ppm T11-c.b.ppm T11-py.tga T11-py.a.ppm T11-py.b.ppm Console logs: T11-c.tga.log T11-c.a.ppm.log T11-c.b.ppm.log T11-py.tga.log T11-py.a.ppm.log T11-py.b.ppm.log | Draw a magenta box with a cyan X on it a bit off center | ![]() |
Test group 'T12' Test 'T12-c.tga' Test 'T12-c.a.ppm' Test 'T12-c.b.ppm' Test 'T12-py.tga' Test 'T12-py.a.ppm' Test 'T12-py.b.ppm' |
Image outputs: T12-c.tga T12-c.a.ppm T12-c.b.ppm T12-py.tga T12-py.a.ppm T12-py.b.ppm Console logs: T12-c.tga.log T12-c.a.ppm.log T12-c.b.ppm.log T12-py.tga.log T12-py.a.ppm.log T12-py.b.ppm.log | Draw a "zipper" type shape going from blue to cyan | ![]() |
Test group 'T13' Test 'T13-c.tga' Test 'T13-c.a.ppm' Test 'T13-c.b.ppm' Test 'T13-py.tga' Test 'T13-py.a.ppm' Test 'T13-py.b.ppm' |
Image outputs: T13-c.tga T13-c.a.ppm T13-c.b.ppm T13-py.tga T13-py.a.ppm T13-py.b.ppm Console logs: T13-c.tga.log T13-c.a.ppm.log T13-c.b.ppm.log T13-py.tga.log T13-py.a.ppm.log T13-py.b.ppm.log | Draw a dashed hexagon | ![]() |
Test group 'T14' Test 'T14-c.tga' Test 'T14-c.a.ppm' Test 'T14-c.b.ppm' Test 'T14-py.tga' Test 'T14-py.a.ppm' Test 'T14-py.b.ppm' |
Image outputs: T14-c.tga T14-c.a.ppm T14-c.b.ppm T14-py.tga T14-py.a.ppm T14-py.b.ppm Console logs: T14-c.tga.log T14-c.a.ppm.log T14-c.b.ppm.log T14-py.tga.log T14-py.a.ppm.log T14-py.b.ppm.log | Draw a totally sweet hilbert curve fractal | ![]() |
Test group 'T15' Test 'T15-c.tga' Test 'T15-c.a.ppm' Test 'T15-c.b.ppm' Test 'T15-py.tga' Test 'T15-py.a.ppm' Test 'T15-py.b.ppm' |
Image outputs: T15-1-c.tga T15-1-c.a.ppm T15-1-c.b.ppm T15-1-py.tga T15-1-py.a.ppm T15-1-py.b.ppm T15-2-c.tga T15-2-c.a.ppm T15-2-c.b.ppm T15-2-py.tga T15-2-py.a.ppm T15-2-py.b.ppm Console logs: T15-c.tga.log T15-c.a.ppm.log T15-c.b.ppm.log T15-py.tga.log T15-py.a.ppm.log T15-py.b.ppm.log | Make two images at once | ![]() ![]() |
Instructor tests
In this assignment, you will have limited access to the instructor tests. Jenkins will be configured to provide "workspace" access, but the only evidence of the instructor tests will be the outputs. Consider these to be submitted materials coming from your "users", along with the brief information below.
Test IDs | Outputs | Description | Image |
---|---|---|---|
Test group 'I01' Test 'I01-py.tga' Test 'I01-py.a.ppm' Test 'I01-py.b.ppm' |
Image outputs: I01-py.tga I01-py.a.ppm I01-py.b.ppm Console logs: I01-py.tga.log I01-py.a.ppm.log I01-py.b.ppm.log | Color map with do_pixel | ![]() |
Test group 'I02' Test 'I02-py.tga' Test 'I02-py.a.ppm' Test 'I02-py.b.ppm' |
Image outputs: I02-1-py.tga I02-1-py.a.ppm I02-1-py.b.ppm I02-2-py.tga I02-2-py.a.ppm I02-2-py.b.ppm I02-3-py.tga I02-3-py.a.ppm I02-3-py.b.ppm Console logs: I02-py.tga.log I02-py.a.ppm.log I02-py.b.ppm.log | 3 images at once | ![]() ![]() ![]() |
Test group 'I03' Test 'I03-py.tga' Test 'I03-py.a.ppm' Test 'I03-py.b.ppm' |
Image outputs: I03-1-py.tga I03-1-py.a.ppm I03-1-py.b.ppm I03-2-py.tga I03-2-py.a.ppm I03-2-py.b.ppm I03-3-py.tga I03-3-py.a.ppm I03-3-py.b.ppm Console logs: I03-py.tga.log I03-py.a.ppm.log I03-py.b.ppm.log | Simple image test written 3 times | ![]() Enlarged 10x |
Test group 'I04' Test 'I04-py.tga' Test 'I04-py.a.ppm' Test 'I04-py.b.ppm' |
Image outputs: I04-py.tga I04-py.a.ppm I04-py.b.ppm Console logs: I04-py.tga.log I04-py.a.ppm.log I04-py.b.ppm.log | A blue/cyan spiral with some pen up/down | ![]() |
Test group 'I05' Test 'I05-py.tga' Test 'I05-py.a.ppm' Test 'I05-py.b.ppm' |
Image outputs: I05-py.tga I05-py.a.ppm I05-py.b.ppm Console logs: I05-py.tga.log I05-py.a.ppm.log I05-py.b.ppm.log | A more complex spiral | ![]() |
Test group 'I06' Test 'I06-py.tga' Test 'I06-py.a.ppm' Test 'I06-py.b.ppm' |
Image outputs: I06-py.tga I06-py.a.ppm I06-py.b.ppm Console logs: I06-py.tga.log I06-py.a.ppm.log I06-py.b.ppm.log | Draw a multi-colored border exactly on the edge of the image using do_line | ![]() |
Test group 'I07' Test 'I07-py.tga' Test 'I07-py.a.ppm' Test 'I07-py.b.ppm' |
Image outputs: I07-py.tga I07-py.a.ppm I07-py.b.ppm Console logs: I07-py.tga.log I07-py.a.ppm.log I07-py.b.ppm.log | Draw a multi-colored border exactly on the edge of the image using turtle graphics | ![]() |
Test group 'I08' Test 'I08-py.tga' Test 'I08-py.a.ppm' Test 'I08-py.b.ppm' |
Image outputs: I08-py.tga I08-py.a.ppm I08-py.b.ppm Console logs: I08-py.tga.log I08-py.a.ppm.log I08-py.b.ppm.log | Go out of bounds with the turtle | ![]() |
Test group 'I09-bad1.a.ppm' Test 'I09-bad1.a.ppm-py.tga' |
Image outputs: (none) Console logs: I09-bad1.a.ppm-py.tga.log | Try to read an awfully bad ppm file | n/a |
Test group 'I10' Test 'I10-py.tga' Test 'I10-py.a.ppm' Test 'I10-py.b.ppm' |
Image outputs: I10-py.tga I10-py.a.ppm I10-py.b.ppm Console logs: I10-py.tga.log I10-py.a.ppm.log I10-py.b.ppm.log | Test of drawing pixels off each edge with do_pixel (only the brightest lines try to go off the edge) | ![]() |
Test group 'IVxx' Test 'IVxx-c.tga' Test 'IVxx-c.a.ppm' Test 'IVxx-c.b.ppm' |
Image outputs: IVxx-c.tga IVxx-c.a.ppm IVxx-c.b.ppm Console logs: IVxx-c.tga.log IVxx-c.a.ppm.log IVxx-c.b.ppm.log | Similar to the given Txx tests, but with a valgrind check | n/a |
Checking Jenkins Feedback
We have created a Jenkins build job for you. Jenkins is a continuous integration server that is used in industry to compile, build, and test applications under development. We will be using Jenkins to compile, build, and test your homework submissions to GitHub, which will provide early feedback on the completeness (does your implementation meet the requirements) and quality (does your implementation correctly implement the requirements).
Your Jenkins job is associated with your GitHub repository and will poll or query GitHub every two minutes for changes. After you have pushed code to GitHub, Jenkins will notice the change and automatically start a build process on your code. The following actions will occur:
- Code will be pulled from your GitHub repository
- The style checker vera++ will run on your code and report notifications that you should fix.
- A magic number checker will run on your code and report notifications that you should fix.
- A check for the required files
test.sh
will execute the following items using your Makefile (so make sure you pushtest.sh
to GitHub!)- Run
make clean
- Compile your library
libCTurtle.so
and the C test toolcturtle_test
, usingmake
- Run the provided test cases using both C and Python
- Run
Jenkins will record the results of each execution. To obtain your Jenkins feedback, do the following tasks:
- Go to Jenkins for CSC230
- Click the project named HW6-<unityid>
- There will be a table called Build History in the lower left, click the link for the latest build
- Click the Console Output link in the left menu (4th item)
- The console output provides the feedback from static analysis (style and magic number checks), compiling your program, and executing the test cases
NOTE: Jenkins will NOT execute test.sh
without evidence that you have run the tests locally. We require that at least one file matching the regular expression test-out/actual-*
is pushed to GitHub for automated testing to run.
Instructions for Submission
The following files MUST be pushed to your assigned CSC230 GitHub repository:
CTurtle.h
CTurtle.c
CTurtle.py
cturtle_test.c
pyturtle_test.py
Makefile
test.sh
cturtle_make_art.c
orcturtle_make_art.py
fantastic_art.tga
orfantastic_art.ppm
- All test files, including actual results of execution in
test-out/
By submitting the actual results from the tests, you will prove that you have tested your program with the minimum set of the provided acceptance tests. Automated grading will not run on your program without at least one generated actual result file (it doesn't mean your tests have to pass, just that you've attempted the tests locally before pushing to your repo).
Additional Considerations
Follow the CSC 230 Style Guidelines. Make sure your program compiles on the common platform and Jenkins cleanly (no errors or warnings), with the required compile options.
There are certain learning outcomes and basic software engineering skills that this assignment is assessing. See the rubric below for deductions may be applied to your submission as enforcement of good software engineering practices and assignment intentions.
Make sure that you push your code to the GitHub repository provided for you! Pushing your code to GitHub is your submission!
There is a 24 hour window for late submissions. After the main deadline, continue to submit to GitHub. We will use the last commit to GitHub before the late deadline for grading and the timestamp of that commit will determine a deduction, if any.
Rubric
+20 for compiling on the common platform with gcc –Wall –std=c99
options
+60 for passing teaching staff test cases (all tests will be done using a diff
of output files), which demonstrates a correct implementation.
+10 for artistic expression (all or nothing)
+20 for comments, style, and constants
-5 for meaningless or missing comments
-5 for inconsistent formatting
-5 for magic numbers
-5 for no name in comments
Total: 110 points
Global deductions FROM the score you earn above:
-15 points for any compilation warnings. Your program must compile cleanly! (if it doesn't compile, you will not receive any credit for test cases or compilation)
-60 points for using library functions outside of ANSI C99 or for using
system()
-- This means that you may have circumvented the intention of the assignment and receive no points for a correct implementation.-10 points for files that are named incorrectly or missing.
-20 points for late work, even if you submit part of the assignment on time.
You can not receive less than a 0 for this assignment unless an academic integrity violation occurs.