This page does not represent the most current semester of this course; it is present merely as an archive.
This programming assignment’s goal is to making sure you are ready for the non-real-time MPs that follow. It is dramatically easier than other MPs.
We also have some tips if this is your first open-ended project
This assignment, like all other assignments, is governed by the common components of MPs.
Unlike other programming assignments
Submit
A Makefile
with (at least) two targets:
build
, which accepts no arguments, and run
,
which accepts a single input file
argument.
Running
make build
make run file=inputfilename.txt
should execute your code on inputfilename.txt
.
Your code, in whatever language you prefer, including any
necessary support libraries that make build
cannot
obtain
A file named implemented.txt
that contains the names
of the reference input files you believe your code handles, one per
line
If all of your files are in the same directory, you can submit them as-is (but must submit all of them in one go; piecemeal uploads will not work).
If you need a specific directory structure, upload a
.zip
or .tar
that contains those files. The
logic for handling submissions is
Makefile
directly, we use thatMakefile
, we use thatMakefile
in that directory, we use
thatThe input files your code will read are ASCII text files; after processing an input file, your code will produce one or more RGBA PNG files.
Each run, your program will be given one command-line argument, which is the path to an input file.
Each input file will have a number of lines; each line will have a
keyword first, followed by zero or more extra pieces of information
separated by whitespace (some mix of ' '
and
'\t'
). Lines should be read in order, first to last,
because some lines refer to the lines above them.
Ignore blank lines and lines starting with anything other than a keyword you know. Always strip leading and trailing space from a line before parsing it.
In this assignment input files might look like
png 200 300 outfilename.png
xy 10 20
xyrgb 50 50 255 127 0
ignore this line since "ignore" is not a keyword you know
likewise ignore this line, which also starts with an unknown keyword
xyc 150 250 #ff00ee
You do not need to have error checking code. For example, if a
png
keyword is not followed by exactly two positive
integers and one string ending .png
, your code is welcome to
break in any way you wish.
Each homework will define its own set of keywords. For this warmup MP, these are:
Every file will begin with png
png
will be followed by two positive integers,
width and height, and a filename. You should
write a RGBA png image of the specified width and height (see [Image
file creation]). You should write the file in the default directory. The
initial color of every pixel in the image should be transparent black
(0, 0, 0, 0).
You may assume the filename contains only non-whitespace ASCII
characters and already has the appropriate .png
ending.
Fill the pixel noted by the x and y coordinate to have the specified color (r, g, b, 255).
You may assume r, g, and b are integers
between 0 and 255, inclusive. See the discussion of xy
for
comments on x and y.
Fill the pixel noted by the x and y coordinate to
have the specified color. The color is given in a web-standard 3-byte
hex code: #rrggbb
, where rr
is a two-digit
hexidecimal value for red, gg
for green, and
bb
for blue. Set the alpha to 255 (0xff)
You may assume hexColorString is always a seven-character
string of the appropriate format. See the discussion of xy
for comments on x and y.
You should be able to pass both of the following. To get credit for
them, make sure you put their names in your implemented.txt
file, like
mp0ex1.txt
mp0ex2.txt
This file’s contents are
png 5 8 mp0ex1.png
xyrgb 0 1 255 255 255
xyrgb 1 2 127 255 255
xyc 2 3 #aaaaff
xyc 3 4 #ffffff
xyrgb 4 5 200 120 3
xyrgb 3 3 0 0 0
xyrgb 2 4 0 0 0
and it should produces this image file:
.
That’s so small it’s almost impossible to see, so let’s zoom in and put a striped background behind the image so you can tell the difference between transparent and white:
This file’s contents are
png 5 8 mp0ex2.png
xyrgb 1 2 127 255 255
xyc 2 3 #aaaaff
nothing here 23425 56
xyrgb 4 5 200 120 3
xyrgb 2 4 0 0 0
and it should produces this image file:
This warmup MP is not graded by a human. Rather, each time you submit your code to submission site it will run automated tests and add information about their outcomes to that site. There will be a delay of up to an hours before that information is visible.
Feel free to re-submit until you get positive status results. Please refer questions to the campus forum or office hours.
You will create an 8-bit RGBA PNG image with a specified width and height. The way to do this will vary by language. You must use a technique that supports setting individual pixels to specific colors, not one with higher-level shape drawing functions (we’ll write those functions ourselves).
Some optional parts of homeworks 2 and 3 will include reading image files too. If you want to do those then, it might make sense to learn how now.
The following is example code to write PNGs taken from past semester’s student submissions. I don’t claim they are optimal, but they did work.
Past students have used miniz.c and LodePNG. Miniz can only write images (not read them) so it won’t let you do the texture-based optional parts of assignments. Lodepng does not have this limitation.
#include "lodepng.h"
int main(int argc, char *argv[]){
/* ... */
unsigned char *image = calloc(width * height * 4, sizeof(unsigned char));
/* ... */
[((y * width) + x)*4 + 0] = red;
image[((y * width) + x)*4 + 1] = green;
image[((y * width) + x)*4 + 2] = blue;
image[((y * width) + x)*4 + 3] = alpha;
image/* ... */
(filename, image, width, height);
lodepng_encode32_file(image);
free}
#include "miniz.h"
int main(int argc, char *argv[]){
/* ... */
unsigned char *image = calloc(width * height * 4, sizeof(unsigned char));
/* ... */
[((y * width) + x)*4 + 0] = red;
image[((y * width) + x)*4 + 1] = green;
image[((y * width) + x)*4 + 2] = blue;
image[((y * width) + x)*4 + 3] = alpha;
image/* ... */
size_t size;
void* data = tdefl_write_image_to_png_file_in_memory((void*) image, width, height, 4, &size);
FILE* out_file = fopen(filename, "wb");
(data, 1, size, out_file);
fwrite(out_file);
fclose(data);
free(image);
free}
All methods that work for C also work for C++, and most students used one of those. An OO interface is also available through CImg. CImg depends on libpng, which some students have difficulty installing; the two C libraries do not depend on libpng and have worked for every student that has tried it so far.
#define cimg_use_png
#define cimg_display 0
#include "CImg.h"
int main(int argc, char *argv[]){
/* ... */
::CImg<unsigned char> image(width, height, 1, 4);
cimg_library/* ... */
(x,y,0,0) = red;
image(x,y,0,1) = green;
image(x,y,0,2) = blue;
image(x,y,0,3) = alpha;
image/* ... */
.save_png(filename.c_str());
image}
The testing server is running mono on Linux, not Microsoft’s C# implementation. If you chose to use C#, you are responsible for ensuring it runs on Linux with mono.
The relevant class is System.Drawing.Bitmap
.
using System.Drawing;
class ClassName {
static void Main(string[] args) {
// ...
= new Bitmap(width, height, PixelFormat.Format32bppArgb);
Bitmap img // ...
.SetPixel(x,y, Color.FromARGB(red,green,blue,alpha));
img// ...
.save(filename);
img}
}
The relevant package is image/image.dart
.
import 'package:image/image.dart';
import 'dart:io';
void main(List<String> args) {
// ...
= Image(width, height);
image // ...
.setPixelRgba(x, y, red, green, blue);
image// ...
.writeBytesAsSync(encodePng(image));
File(filename) }
The relevant package is image
.
import (
"image/png"
"image/color"
"io"
)
func main() {
// ...
:= image.NewRGBA(image.Rect(0, 0, width, height))
img // ...
.Set(x, y, color.RGBA{red, green, blue, alpha})
img// ...
, err := os.Create(img.filename)
w.Encode(w, img)
png}
Students have reported success using Phll
import qualified Data.ByteString.Lazy as B
import Phll
= flip map [0..width] $
pixels -> flip map [0..height] $
\x -> (red, green, blue, alpha)
\y
= B.writeFile filename $ B.pack $ Phll.png_rgba pixels main
The relevant libraries are Color
from
java.awt
, BufferedImage
and
WritableRaster
from java.awt.image
and ImageIO
from
javax.imageio
package. Do not use java.awt.Graphics
.
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.WriteableRaster;
import javax.imageio.ImageIO;
class ClassName {
public static void main(String[] args) {
// ...
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
WritableRaster raster = b.getRaster();
// ...
.SetPixel(x,y, new Color(red,green,blue,alpha));
raster// ...
ImageIO.write(image, "png", new File(filename));
}
}
The relevant library is pillow. To install, do pip install pillow
or pip3 install pillow
from the command line on your machine (not in your Makefile because
we’ve pre-installed pillow, but not pip, on the testing server). Do not
use the ImageDraw
module.
from PIL import Image
# ...
= Image.new("RGBA", (width, height), (0,0,0,0))
image # ...
image.im.putpixel((x,y), (red, green, blue, alpha))# ...
image.save(filename)
The relevant library is std::io::RgbaImage
and
std::io:Rgba
.
use std::io::{BufRead, BufReader};
fn main() {
// ...
let mut image = RgbaImage::from_pixel(width, height, Rgba([0, 0, 0, 0]));
// ...
.put_pixel(x, y, Rgba([red, green, blue, alpha]));
image// ...
.save(filename).unwrap();
image}
The relevant library is jimp
.
import Jimp from 'jimp';
const run = async () => {
const image = new Jimp(width, height);
// ...
// make rgba a 32-bit integer of the form 0xRRGGBBAA
.setPixelColor(rgba, x, y);
image// ...
await image.writeAsync(filename);
;
}run().catch(console.error);
In earlier semesters we’ve also had students use D, Kotlin, and Scala. In principle I am open to any language I can get to work on the testing server; just let me know what you’d like.
You will submit your code and a Makefile
. We will run
your Makefile
on a Linux server. It is your responsibility
to see that the Makefile
and your code work in a Linux
environment. Following are minimal Makefiles you might use as a
baseline. We recommend using make’s more advanced operations (separate
.o
targets, pattern rules, variables, etc) if you
understand them.
Note that Makefile
indentation must be in tabs,
not spaces and that the file name must be exactly
Makefile
with no filename extension.
.PHONEY: build, run
build: program
run: program
$(file)
./program
program: main.c lodepng.c
clang -O3 -I. main.c lodepng.c -o program
.PHONEY: build, run
build: program
run: program
$(file)
./program
program: main.cpp
clang++ -O3 -I. main.cpp -o program
Note: some libraries may require more flags. For example,
CImg.h
requires -lpng
and
-lm
.
.PHONEY: build, run
build: program.exe
run: program.exe
$(file)
mono program.exe
program.exe: program.cs
mcs -r:System.Drawing -pkg:gtk-sharp-2.0 program.cs
.PHONEY: build, run
build:
pub get
run:
$(file) dart program.dart
.PHONEY: build, run
build:
go build -o bin/main main.go
run:
$(file) ./bin/main
.PHONEY: build, run
build:
run:
$(file) runghc program.hs
.PHONEY: build, run
build: Program.class
run: Program.class
$(file)
java Program
Program.class: Program.java
javac Program.java
If your code is in a package (as many IDEs will make it), you’ll need a slightly more involved Makefile.
If the .java
files contain
package some.name;
then they will be in some path
path/prefix/some/name
. Put the Makefile
(and
implemented.txt
) in path/prefix/
as
follows:
SRC = $(wildcard some/name/*.java)
CLS = $(SRC:.java=.class)
.PHONEY: build, run
build: $(CLS)
$(SRC)
javac
run: $(CLS)
$(file) java some.name.ClassWithMain
the SRC
uses the
wildcard
function to find all Java files in that one
package; if you use several packages, you will need to add additional
wildcards there.
.PHONEY: build, run
build:
run:
$(file) python program.py
.PHONEY: build, run
build:
cargo build
run:
$(file) cargo run
.PHONEY: build, run
build:
npm install && npm run build
run:
$(file) npm start
Think your output looks like the reference output? Maybe so, but
like
is a fuzzy idea and sometimes we’ll hold you to a higher
standard of similarity than your eye is trained to see.
Enter ImageMagick (or its less popular but faster clone, GraphicsMagick). ImageMagick is a collection of versatile command-line tools for manipulating images, including many forms of image comparison.
During grading, we use ImageMagick to create comparison images containing
student.png
ref.png
ae.png
rawdiff.png
diff.png
We create those images and stick them together into one large image to look at during grading using the following commands:
compare -fuzz 2% student.png ref.png ae.png
composite student.png ref.png -alpha off -compose difference rawdiff.png
convert rawdiff.png -level 0%,8% diff.png
convert +append ref.png student.png ae.png rawdiff.png diff.png look_at_this.png
Note that some tasks are permissive of some differences while others will be more strict. For example, consider this image:
It is similar to its reference image, but the outline is not the same (a few missing pixels along the left edge, touching in the middle) and there’s visible horizontal banding in the color error. If this input was meant to test shading and overlap, those would result in lost points. It it were meant to measure positioning and perspective, they’d not be a concern.