Coursework: Week 3, Triangle

Before starting the coursework, check your feedback for the grade assignment, by looking in the folder where you submitted the work. The feedback doesn't yet include extra work done. If you didn't get 50%, try to make sure you don't make the same mistakes this week.

The coursework this week counts for 25% of your credit for the unit. The main purpose is to continue to practice writing simple programs, and particularly to understand how to achieve precision. The first half of the assignment is to write a triangle classifier, and the second half is open ended. You may need information from the lecture notes up to the statements chapter.

understand the triangle problem

You are asked to write a program which reads in three integers representing the lengths of the sides of a triangle, and then prints out the type of triangle.

The program should take its input from the command line, and print its output on the standard output, e.g.

./triangle 3 4 6
Scalene

The possible responses are:

Equilateral     (all sides equal)
Isosceles       (two sides equal)
Right           (has a right angle)
Scalene         (sides unequal, but no right angle)
Flat            (lengths add up exactly, so no area)
Impossible      (lengths don't add up)
Illegal         (lengths are invalid)

study the skeleton program

You are given this skeleton as a starting point:

triangle.c (old triangle.c)
Makefile

Here are some notes about its design:

It uses a custom assert function

Last week, some people, though not all, had problems with the terminal window freezing after a call to assert. We have failed to find out why that is. So, this week, the skeleton has been changed to use a custom version of the assert function. The original version is still available, and can be used or studied if you want. The changes are that the inclusion of assert.h has been deleted, a definition of assert has been written, and each call to assert has had an extra argument added to pass in the line number of the test.

It can be compiled and run

Try compiling it and running it like this:

$ clang -std=c11 -Wall triangle.c -o triangle
$ ./triangle 5 5 5
Equilateral
$ ./triangle
... assertion fails on line ...

or preferably like this:

$ make
$ ./triangle 5 5 5
Equilateral
$ ./triangle
... assertion fails on line ...

At the moment, if you run it with three integer arguments, the program prints out Equilateral all the time. If you run the program without arguments, it carries out the tests. That is what you should be doing most of the time while you are developing. At the moment, only the first couple of tests pass. it.

There are lots of tests

The skeleton seems long, because of all the tests. There are lots of them, because there are surprisingly many quirky details, and because they are designed to catch every mistake that any student is ever likely to make. In a 'real' project, there would probably not be so many.

You are unlikely to need to write more than about 20 or 30 lines of code.

It is in two parts

The first part of the program is the part you are supposed to work on. That's the convert and triangle functions, and any supporting functions you choose to add. The rest is the tests and user interface, which you should not change.

triangle returns an integer

The triangle function returns an integer constant representing the type of triangle. Named constants are used rather than strings because (a) the compiler will tell you if you miss-spell them (b) it separates the symbolic issue of classification from the textual issue of printing, e.g. making it easy to change to a language other than English (c) it makes testing marginally easier and (d) it avoids pointer notation, which would be needed if a string was returned.

Note that C doesn't allow you to define a 'safe' enumerated type for constants. Any type name you use (e.g. enum type) is just a synonym for int

Supporting functions are encouraged

The skeleton provides two functions convert and triangle which will be tested. If either of those expands beyond a very few lines, it is strongly recommended that you define one or two support functions, e.g. a valid function for checking if a string length is valid, or a separate function to handle each type of triangle. That isn't necessary if you have a compact programming style, because each of the types can be checked in one line of code, but it may be a good idea if your style is more verbose. Either way, your aim should be to keep each of your functions very short.

develop the program

Your initial aim should be to make at least one more test pass. When that works, tackle the next test that fails until you can get it to pass, and so on. As it says in Alice in Wonderland: "Begin at the beginning, go on till you come to the end: then stop." Here are some notes on development:

Read the tests

The tests form the specification of the program, filling in the gaps in the quick description above, and illustrating all the nitty gritty details of what your program is supposed to do. So you should study them carefully, especially the one that currently fails.

Do only a small amount at once

The first thing to do is, for example, add a couple of lines to triangle to test for the isosceles case.

There's a good chance the program won't compile immediately, but you must work at it, solving any problems, until it compiles and runs again, before trying to achieve more.

The program should now pass at least one more test.

The tests are used for marking

The number of tests your program passes before failing is a rough measure of progress. Your program will be compiled and run for marking (using a clean copy of the tests) and the number of tests passed out of the 50 before it fails will be your mark for the first half of the assignment.

You are now an agile developer

The general approach to software deveopment we are trying to promote is agile development. There is more to it than you've experienced so far, so you are an apprentice-level agile developer. The specific technique for this assignment is test driven development, and is a very powerful technique for confident development of robust programs. Of course, you would normally have to design the program yourself so that it supports testing, and create your own tests.

Design notes

The triangle function needs to do various checks on the three integer lengths. These have to work no matter what order the lengths are in. You can either do several checks, or you can sort the lengths into order first (just by doing a couple of swaps, not necessarily using a full sorting algorithm). The two approaches are about equally good. If you are careful about the order of the checks for the different types, that can make the checks much simpler.

The convert function needs to check if a string is valid, and in range, and convert it into an integer.

There are at least three approaches to validity chacking. One is to do it yourself, with a loop, before conversion. A second is to use a conversion function which provides enough extra information, beyond just the result, to help with validity checking. The third is to use a clever trick: convert the string to an integer using a simple conversion function, and then convert back to a string, and compare with the original string, catching all validity issues in one go.

To check if the integer is in range, you could either do suitable checks on the string before conversion, or convert to an integer type bigger than int and check the range before putting it into an int variable.

Implementation notes

To find the length of a string (if you need it) use strlen. To convert a string to an integer, you can either use a simple function like atoi or atol, or a more complex function like strtol if you want to get validity information from it.

To convert an integer back to a string, use sprintf, and to compare two strings, use strcmp. Type C atoi into Google, for example, to find the documentation for a function.

To avoid a 'magic number' for the maximum allowable length, you can use INT_MAX, which is defined in limits.h.

Overflow

The last few tests are designed to catch overflow problems. This is when integers exceed the limit of the int type. You might consider switching to the long type in parts of the program where you think overflow might occur. It is OK for this assignment to assume that ints have 32 bits and longs have 64 bits.

write something extra

If you have time, and if you are interested or you want more than 50% for the assignment, you can do some extra open-ended work. Write any program you want in C (of the same sort of scope as the triangle program) which involves simple classification or calculation.

Submit the source file, and a file readme.txt (or a pdf file) which describes your aims for the program and how far you got with it. There are no marks for report writing, but the report may be necessary for us to make sense of the program.

A mark out of 50 for the extra work will be awarded by swiftly reading the report, checking whether your program matches what you claim, judging the sophistication of what has been done, and checking whether the program follows the conventions and advice in the lectures. In particular, writing tests as part of the program, in the same way as the skeletons, is very much recommended (though you only need enough tests to make you confident). Also recommended is working in very small steps, one test at a time, keeping your program in a working state.

The mark will aim to make your total for the assignment meet the university scale. So assuming you get full marks for the triangle program, 10/50 means "this raises your total result from average to good", 20/50 means "overall first class", 30/50 means "overall above and beyond what was expected" and 40/50 means "publishable in a research journal".

submit

Submit your program triangle.c (not Triangle.c or any other name, unless you want to lose marks, and not the compiled program). Make sure your program compiles without warnings, runs, and doesn't still contain debugging print statements. Feel free to resubmit it if you improve it before the deadline (using the same filename).

Submit your extra program, if any, and a readme.txt file with any comments you might want to make.