Programming Fundamentals

Objectives

  • using complex if statements to control program execution
  • using while loops for repetition
  • building up combinations of loops
  • defining and using enums and structs

Feedback Week!

In this week's lab, your tutors will go around the class and give you one on one feedback on some code you have written in a previous week.

Take this as an opportunity to ask any questions you might have about the course content so far!

So, if you would like, have a think about if there is any particular exercise you would like to receive feedback for, or any particular content you would like to ask about.

1511 Cheatsheet

When you are finished with the exercises for this week, take a look at the 1511 Cheatsheet. This page has useful linux commands and VSCode keyboard shortcuts that you may find helpful when programming!

Reminder: Help sessions

Help sessions are running this week!

These are one of the best ways for you to get one on one help with a tutor for any course content (including Lab Exercises and Assignments).

For the dates and times of the help sessions, see the Help Session Timetable.

To join a help session, or for more information, see the COMP(1511|1911) Help Session Microsoft Teams.

For face-to-face help sessions, the lab map can be found here. If help sessions are running in other buildings you can use Lost on Campus to help you find them.

Revision Videos!

Need a quick recap or revision on a topic we have looked at?

Head over to our Revision Videos Playlist! Here, you can watch some short youtube videos to help you understand and revise topics we have learnt so far!

If you watched one of the revision videos, please take a minute or two to fill out the survey here. Please note that this survey is completely optional and anonymous but aims to give feedback and provide suggestions fore more videos!

Activities To Be Completed

The following is a list of all the activities available to complete this week...

Worth 1 mark(s) in total:

  • count_up_down
  • vector_sum
  • debug_factorial
  • print_grid

Worth 1 mark(s) in total:

  • custom_cake
  • letters_between
  • street_fighter

Worth 0.5 mark(s) in total:

  • xtreme
  • perfect_number

For your interest, but not for marks:

  • spiral
  • decimal_spiral

Problem sets are capped at 15 marks (there are 4 possible bonus marks from the three-dot exercises that can bring you up to a total of 15 if you missed out on any other marks in the one- or two-dot exercises).

Completing just the one and two-dot exercises every week can give you the full 15 marks needed in this component.

For more details, see the course outline.

Preparation

Before the lab you should re-read the relevant lecture slides and their accompanying examples.

When attempting the following exercises, make sure to read the whole exercise, including any hints and assumptions that may make the exercise easier.

Exercise
(●◌◌)
:

Count Up/Down

Write a C program count_up_down.c that reads one integer n and prints all integers from 0 to n inclusive one per line.

Note that if n is positive, we are counting up and if n is negative, we are counting down.

Examples

dcc count_up_down.c -o count_up_down
./count_up_down
Enter number: 5
0
1
2
3
4
5
./count_up_down
Enter number: -3
0
-1
-2
-3

Assumptions/Restrictions/Clarifications

  • You may assume 0 will never be given as input.
  • You are not permitted to use arrays.
  • You do not have to do any error checking.
  • You do not have to check the return value from scanf.
You can run an automated code style checker using the following command:
1511 style count_up_down.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest count_up_down

When you are finished working on this exercise, you must submit your work by running give:

give cs1511 lab03_count_up_down count_up_down.c

You must run give before Tuesday 07 October 18:00 to obtain the marks for this lab exercise. Note that this is an individual exercise, the work you submit with give must be entirely your own.

Sample solution for count_up_down.c
// 
// Written 23rd September 2021
// By Clarissa Tatang
//
// Program which takes in a number n and
// counts up from 0 till n if n is greater than 0 or
// counts down from 0 till n if n is less than 0.
// 

#include <stdio.h>

int main(void) {
    int n;
    printf("Enter number: ");
    scanf("%d", &n);

    int i = 0;
    if (n > 0) {
        while (i <= n) {
            printf("%d\n", i);
            i++;
        } 
    } 

    if (n < 0) {
        while (i >= n) {
            printf("%d\n", i);
            i--;
        }
    }

}

Exercise
(●◌◌)
:

Vector Sum

Download vector_sum.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity vector_sum

Complete the C program vector_sum.c which reads in two vectors with 3 integer components each and stores the sum of these components in a new vector to be printed.

Your job for this exercise is to complete the middle section (bolded above). There is a given struct vector called sum_vector, which needs to store the sum of the two scanned-in vectors, everything else has already been completed.

Complete the C program vector_sum.c which takes in two 3D vectors, each with an x, y and z integer component as input, and then calculates the sum to be printed.

Your job for this exercise is to use the values stored in first_vector and second_vector which have already been scanned in for you to calculate the sum of the vectors and store the result in the given struct vector called sum_vector.

Examples

dcc vector_sum.c -o vector_sum
./vector_sum
Please enter the values of the first vector (x, y, z): 1 2 3
Please enter the values of the second vector (x, y, z): 4 5 6
The resulting sum vector is:
x: 5
y: 7
z: 9
./vector_sum
Please enter the values of the first vector (x, y, z): 1 2 3
Please enter the values of the second vector (x, y, z): 1 2 3
The resulting sum vector is:
x: 2
y: 4
z: 6
./vector_sum
Please enter the values of the first vector (x, y, z): -5 30 -12
Please enter the values of the second vector (x, y, z): 15 -31 -30
The resulting sum vector is:
x: 10
y: -1
z: -42

Assumptions/Restrictions/Clarifications

  • You may assume that you will be given only integers as input.
  • You may assume that all input is valid.
  • You may notice that the starter code does not pass 1511 style. Defining a vector with x, y and z is perfectly fine in this case, even though they are 1 letter variables. Context is important here! Since x, y and z are common for dimensions in math, it is okay here. However, a vector with h, v, q would not be good style.
You can run an automated code style checker using the following command:
1511 style vector_sum.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest vector_sum

When you are finished working on this exercise, you must submit your work by running give:

give cs1511 lab03_vector_sum vector_sum.c

You must run give before Tuesday 07 October 18:00 to obtain the marks for this lab exercise. Note that this is an individual exercise, the work you submit with give must be entirely your own.

Sample solution for vector_sum.c
#include <stdio.h>

struct vector {
    int x;
    int y;
    int z;
};

int main(void) {

    //////////////// DO NOT CHANGE ANY OF THE CODE BELOW HERE //////////////////
    struct vector first_vector;
    struct vector second_vector;

    // Scans in vector values from user
    // Carefully read how these scanf's work ~ Try to understand it
    printf("Please enter the values of the first vector (x, y, z): ");
    scanf("%d %d %d", &first_vector.x, &first_vector.y, &first_vector.z);

    printf("Please enter the values of the second vector (x, y, z): ");
    scanf("%d %d %d", &second_vector.x, &second_vector.y, &second_vector.z);

    struct vector sum_vector;
    //////////////// DO NOT CHANGE ANY OF THE CODE ABOVE HERE //////////////////


    ///////////////////// ONLY WRITE CODE BELOW HERE ///////////////////////////
    // TODO: Fill in `sum_vector` by adding each component of `first_vector`
    // and `second_vector`
    sum_vector.x = first_vector.x + second_vector.x;
    sum_vector.y = first_vector.y + second_vector.y;
    sum_vector.z = first_vector.z + second_vector.z;

    ///////////////////// ONLY WRITE CODE ABOVE HERE ///////////////////////////


    printf("The resulting sum vector is:\n");
    printf("x: %d\n", sum_vector.x);
    printf("y: %d\n", sum_vector.y);
    printf("z: %d\n", sum_vector.z);
    return 0;
}

Exercise
(●◌◌)
:

Debugging - Factorial

Download debug_factorial.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity debug_factorial

Debugging Tips!

Some debugging tips for you:

  • dcc output - as you run into issues, dcc will point you to where the errors are. Remember that dcc gives you the line number the issue is on, and will give some sort of explanation. Make sure you read everything dcc gives you. Sometimes we get “errors carried forward”, so find your first error, fix that, then recompile.
  • print statements - sometimes it can be handy to see if the flow of your code puts you in the spot you expect it to be (ie. inside the right if statement, or going through a loop the correct amount of times). A quick way you can check this is by putting print statements in your code for testing purposes, like "the value of x is %d and y is %d". This lets you check that you got against what you expected.
  • COMP1511 debugging guide

The Task

This exercise takes in a positive integer as input, calculates the factorial of that number and prints it out. Currently it has some issues - it is your job to figure them out and fix the code.

Examples

dcc debug_factorial.c -o debug_factorial
./debug_factorial
Enter a number: 3
The factorial of 3 is 6
./debug_factorial
Enter a number: 7
The factorial of 7 is 5040
./debug_factorial
Enter a number: 1
The factorial of 1 is 1

Assumptions/Restrictions/Clarifications

  • You can assume you will not be given negative numbers
You can run an automated code style checker using the following command:
1511 style debug_factorial.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest debug_factorial

When you are finished working on this exercise, you must submit your work by running give:

give cs1511 lab03_debug_factorial debug_factorial.c

You must run give before Tuesday 07 October 18:00 to obtain the marks for this lab exercise. Note that this is an individual exercise, the work you submit with give must be entirely your own.

Sample solution for debug_factorial.c
// debug_factorial.c
//
// Write a C program that takes a positive integer as input, calculates the
// factorial of that number and prints it out.
//
// Sofia De Bellis, 2023

#include <stdio.h>

int main (void) {
    int num = 0;
    int factorial = 1;

    printf("Enter a number: ");
    scanf("%d", &num);

    int counter = num;

    while (counter > 0) {
        factorial *= counter;
        counter--;
    }    

    printf("The factorial of %d is %d\n", num, factorial);

    return 0;
}

Exercise
(●◌◌)
:

Print a Coordinate Grid

Write a program called print_grid.c that reads an integer n from standard input. and prints an n x n grid with all the coordinates of the grid shown.

Each of the points of the grid should be printed out in the form (row, col). This is different to your typical (x,y) coordinate grid and you should see if you can figure out why this is more convenient for us!

Examples

dcc print_grid.c -o print_grid
./print_grid 
Enter size: 4
(0, 0) (0, 1) (0, 2) (0, 3)
(1, 0) (1, 1) (1, 2) (1, 3)
(2, 0) (2, 1) (2, 2) (2, 3)
(3, 0) (3, 1) (3, 2) (3, 3)
./print_grid 
Enter size: 5
(0, 0) (0, 1) (0, 2) (0, 3) (0, 4)
(1, 0) (1, 1) (1, 2) (1, 3) (1, 4)
(2, 0) (2, 1) (2, 2) (2, 3) (2, 4)
(3, 0) (3, 1) (3, 2) (3, 3) (3, 4)
(4, 0) (4, 1) (4, 2) (4, 3) (4, 4)
./print_grid
Enter size: 8
(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7)
(1, 0) (1, 1) (1, 2) (1, 3) (1, 4) (1, 5) (1, 6) (1, 7)
(2, 0) (2, 1) (2, 2) (2, 3) (2, 4) (2, 5) (2, 6) (2, 7)
(3, 0) (3, 1) (3, 2) (3, 3) (3, 4) (3, 5) (3, 6) (3, 7)
(4, 0) (4, 1) (4, 2) (4, 3) (4, 4) (4, 5) (4, 6) (4, 7)
(5, 0) (5, 1) (5, 2) (5, 3) (5, 4) (5, 5) (5, 6) (5, 7)
(6, 0) (6, 1) (6, 2) (6, 3) (6, 4) (6, 5) (6, 6) (6, 7)
(7, 0) (7, 1) (7, 2) (7, 3) (7, 4) (7, 5) (7, 6) (7, 7)

Assumptions/Restrictions/Clarifications

  • You may assume that your program will only scan in integers
  • Your program only has to handle sizes in the range 0 to 10 inclusive
  • Your program is not required to do any error checking
  • Your program is not permitted to use arrays
You can run an automated code style checker using the following command:
1511 style print_grid.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest print_grid

When you are finished working on this exercise, you and your lab partner must both submit your work by running give:

give cs1511 lab03_print_grid print_grid.c

Note, even though this is a pair exercise, you both must run give from your own account before Tuesday 07 October 18:00 to obtain the marks for this lab exercise.

Sample solution for print_grid.c
// Written ...

// Print a grid of coordinates

#include <stdio.h>

int main(void) {

    int size;
    printf("Enter size: ");
    scanf("%d", &size);

    int row = 0;
    while (row < size) {
        int col = 0;
        while (col < size) {
            printf("(%d, %d) ", row, col);
            col = col + 1;
        }
        printf("\n");
        row = row + 1;
    }

    return 0;
}

Exercise
(●●◌)
:

Custom Cake

In this activity you will create a program called custom_cake.c.

The program will first ask for the number of layers (rows) of a cake. It will then scan in an ASCII character for each layer. Finally, the program will print out a row for each layer (ASCII character), equal in width to the number of layers.

For example, if the number of layers was 3, it should print out a cake that is 3x3 characters large. If the number of layers was 5, it should print out a cake that is 5x5 characters large.

Examples

dcc custom_cake.c -o custom_cake
./custom_cake
How many layers: 5
Please enter layers: *|=~=
*****
|||||
=====
~~~~~
=====
./custom_cake
How many layers: 3
Please enter layers: =&=
===
&&&
===

Assumptions/Restrictions/Clarifications

  • The number of layers will always be a non-zero positive integer.
  • The number of characters input will always match the number of layers.
  • The width of each layer will always be the same as the total number of layers.
  • You may assume that a whitesapce ' ', will never be the character for a layer.
You can run an automated code style checker using the following command:
1511 style custom_cake.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest custom_cake

When you are finished working on this exercise, you must submit your work by running give:

give cs1511 lab03_custom_cake custom_cake.c

You must run give before Tuesday 07 October 18:00 to obtain the marks for this lab exercise. Note that this is an individual exercise, the work you submit with give must be entirely your own.

Sample solution for custom_cake.c
// Custom Cake
// custom_cake.c
//
// This program was written by Morgan Swaak (z5476300)
// on 15/01/24
//
// A program which prints out a layered cake.

#include <stdio.h>

int main(void) {
    printf("How many layers: ");
    int num_layers;
    scanf("%d", &num_layers);

    printf("Please enter layers: ");

    int i = 0;
    char layer;
    while (i < num_layers) {
        scanf(" %c", &layer);
        int j = 0;
        while (j < num_layers) {
            printf("%c", layer);
            j++;
        }
        printf("\n");
        i++;
    }
    return 0;
}

Exercise
(●●◌)
:

Letters Between

Design a program named letters_between.c that accepts a starting letter and target letter as input. The program should calculate the shortest path between the two given letters by either moving forwards or backwards through the alphabet. The program then prints out all the letters from the starting letter to the target letter along the shortest path.

For example, if 'c' and 'k' were entered as the starting and target letters respectively, the program would calculate the path moving forwards through the alphabet to be cdefghijk, which takes 9 letters and the
the path moving backwards through the alphabet to be cbazyxwvutsrqponmlk, which takes 19 letters.

Hence the program will print cdefghijk as 9 letters is less than 19.

Note In the case where the number of letters are equal, the program will print the letters moving forwards through the alphabet.

Examples

dcc letters_between.c -o letters_between
./letters_between
Please enter starting letter: H
Please enter target letter: K
HIJK
./letters_between
Please enter starting letter: b
Please enter target letter: w
bazyxw
./letters_between
Please enter starting letter: Q
Please enter target letter: D
QRSTUVWXYZABCD
./letters_between
Please enter starting letter: m
Please enter target letter: m
m

Assumptions/Restrictions/Clarifications

  • The starting and target letters will either be both uppercase or both lowercase.
  • The result should be printed in the same case as the input.
  • Letters will be from the english alphabet (a,b,c ... x,y,z).
  • If the starting letter and target letter are the same the program should only print one character.
  • If the number of letters are the same moving forwards and backwards, choose forwards.
You can run an automated code style checker using the following command:
1511 style letters_between.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest letters_between

When you are finished working on this exercise, you and your lab partner must both submit your work by running give:

give cs1511 lab03_letters_between letters_between.c

Note, even though this is a pair exercise, you both must run give from your own account before Tuesday 07 October 18:00 to obtain the marks for this lab exercise.

Sample solution for letters_between.c
// Letters Between
// letters_between.c
//
// This program was written by Morgan Swaak (z5476300)
// on 31/01/24
//
// A program that prints the shortest length of characters 
// between two letters.

#include <stdio.h>

#define NUM_LETTERS 26
#define REVERSE 25
#define SEQUENTIAL 1

int main(void) {
    // get input
    printf("Please enter starting letter: ");
    char start_letter;
    scanf(" %c", &start_letter);
    printf("Please enter target letter: ");
    char target_letter;
    scanf(" %c", &target_letter);

    int distance_sequential = target_letter - start_letter;

    int distance_reverse = start_letter - target_letter;

    // make sure numbers are positive
    if (distance_sequential < 0) {
        distance_sequential += NUM_LETTERS;
    } else {
        distance_reverse += NUM_LETTERS;
    }

    // we also check capitalisation
    int offset;
    if ('a' <= start_letter && start_letter <= 'z') {
        offset = 'a';
    } else {
        offset = 'A';
    }

    int direction;
    if (distance_sequential <= distance_reverse) {
        direction = SEQUENTIAL;
    } else {
        direction = REVERSE;
    }

    // generalising so printing works for upper and lower case.
    int start = start_letter - offset;
    int target = target_letter - offset;

    // print out result
    int current = start;
    while (current != target) {
        printf("%c", current + offset);
        current = (current + direction) % NUM_LETTERS;
    }
    printf("%c\n", target + offset);
    return 0;
}

Exercise
(●●◌)
:

Street Fighter

Download street_fighter.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity street_fighter
Write a C program street_fighter.c which allows the user to play a game of Street Fighter. The user should be able to customise the attack power and attack key-binding (the assignment of a key on a keyboard to a command) for each fighter.

Each round, the program should prompt each fighter to attack.

When a fighter attacks, their opponent's health should immediately be reduced by the attacking fighter's attack power. A fighter that is below 50% of their maximum health deals 50% more damage. If during a round a fighter is brought below 50% of their maximum health, they should immediately start dealing 50% more damage to their opponent from that point onwards.

If fighter 2 has no health remaining after fighter 1 attacks, fighter 2 still has the opportunity to attack before the fight is over.

At the end of each round, the program should print out the current health of each fighter. If either fighter has no health remaining at the end of a round, the fight is over and the program should print which fighter won.

If both fighters have no health remaining at the end of the fight your program should print It's a draw! instead.

Finally the program should then print GAME OVER and exit.

You are required to define a struct fighter which should store the following information:

  1. The attack power of the fighter. A fighter's attack power which will be scanned in, and is an integer between 1 and 10 inclusive.
  2. The current health of the fighter. Fighters begin with a maximum health of 50.0.
  3. The key-binding for the attack command of the fighter, which is a character that is scanned in.

Examples

dcc street_fighter.c -o street_fighter
./street_fighter
Welcome to Street Fighter!

Enter Fighter 1's attack power (1-10): 7
Enter an ascii character for Fighter 1's attack command: a

Enter Fighter 2's attack power (1-10): 10
Enter an ascii character for Fighter 2's attack command: b

FIGHT!

Fighter 1, press a to attack: a
Fighter 1 attacks!
Fighter 2, press b to attack: b
Fighter 2 attacks!

Fighter 1's health: 40.0
Fighter 2's health: 43.0
Fighter 1, press a to attack: a
Fighter 1 attacks!
Fighter 2, press b to attack: b
Fighter 2 attacks!

Fighter 1's health: 30.0
Fighter 2's health: 36.0
Fighter 1, press a to attack: a
Fighter 1 attacks!
Fighter 2, press b to attack: b
Fighter 2 attacks!

Fighter 1's health: 20.0
Fighter 2's health: 29.0
Fighter 1, press a to attack: a
Fighter 1 attacks!
Fighter 2, press b to attack: b
Fighter 2 attacks!

Fighter 1's health: 5.0
Fighter 2's health: 18.5
Fighter 1, press a to attack: a
Fighter 1 attacks!
Fighter 2, press b to attack: b
Fighter 2 attacks!

Fighter 1's health: -10.0
Fighter 2's health: 8.0

Fighter 2 wins!
GAME OVER
./street_fighter
Welcome to Street Fighter!

Enter Fighter 1's attack power (1-10): 10
Enter an ascii character for Fighter 1's attack command: a

Enter Fighter 2's attack power (1-10): 9
Enter an ascii character for Fighter 2's attack command: s

FIGHT!

Fighter 1, press a to attack: a
Fighter 1 attacks!
Fighter 2, press s to attack: s
Fighter 2 attacks!

Fighter 1's health: 41.0
Fighter 2's health: 40.0
Fighter 1, press a to attack: a
Fighter 1 attacks!
Fighter 2, press s to attack: s
Fighter 2 attacks!

Fighter 1's health: 32.0
Fighter 2's health: 30.0
Fighter 1, press a to attack: a
Fighter 1 attacks!
Fighter 2, press s to attack: s
Fighter 2 attacks!

Fighter 1's health: 18.5
Fighter 2's health: 20.0
Fighter 1, press a to attack: a
Fighter 1 attacks!
Fighter 2, press s to attack: s
Fighter 2 attacks!

Fighter 1's health: 5.0
Fighter 2's health: 5.0
Fighter 1, press a to attack: a
Fighter 1 attacks!
Fighter 2, press s to attack: s
Fighter 2 attacks!

Fighter 1's health: -8.5
Fighter 2's health: -10.0

It's a draw!
GAME OVER

Assumptions/Restrictions/Clarifications

  • You may find %0.1lf useful for formatting the health of each fighter.
  • Assume you will only be given valid inputs for the attack power and attack command.
You can run an automated code style checker using the following command:
1511 style street_fighter.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest street_fighter

When you are finished working on this exercise, you must submit your work by running give:

give cs1511 lab03_street_fighter street_fighter.c

You must run give before Tuesday 07 October 18:00 to obtain the marks for this lab exercise. Note that this is an individual exercise, the work you submit with give must be entirely your own.

Sample solution for street_fighter.c
// Street Fighter
// street_fighter.c
//
// This program was written by Ibrahim Ghoneim (z5470570)
// on 14/01/2024
//
// Let's play Street Fighter!
// 3..2..1.. FIGHT!

#include <stdio.h>

#define MAX_HEALTH 50.0
#define MAX_ATTACK 10

// Provided fighter struct
struct fighter {
    int attack;
    double health;
    char attack_command;
};

int main(void) {
    printf("Welcome to Street Fighter!\n");
    ////////////////////////////////////////////////////////////////////////////
    ///////////////////////// Fighter 1 Creation ///////////////////////////////
    ////////////////////////////////////////////////////////////////////////////
    struct fighter fighter1;

    printf("\nEnter Fighter 1's attack power (1-10): ");
    scanf("%d", &fighter1.attack);

    fighter1.health = MAX_HEALTH;

    printf("Enter an ascii character for Fighter 1's attack command: ");
    scanf(" %c", &fighter1.attack_command);
    ////////////////////////////////////////////////////////////////////////////
    /////////////////////////// REPEAT FOR FIGHTER 2 ///////////////////////////
    ////////////////////////////////////////////////////////////////////////////
    struct fighter fighter2;

    printf("\nEnter Fighter 2's attack power (1-10): ");
    scanf("%d", &fighter2.attack);

    fighter2.health = MAX_HEALTH;

    printf("Enter an ascii character for Fighter 2's attack command: ");
    scanf(" %c", &fighter2.attack_command);
    ////////////////////////////////////////////////////////////////////////////
    //////////////////////////////// Fight Loop ////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////
    printf("\nFIGHT!\n\n");
    char action;
    while (fighter1.health > 0 && fighter2.health > 0) {
        printf("Fighter 1, press %c to attack: ", fighter1.attack_command);
        scanf(" %c", &action);
        if (action == fighter1.attack_command) {
            printf("Fighter 1 attacks!\n");
            if (fighter1.health < MAX_HEALTH/2) {
                fighter2.health -= fighter1.attack * 1.5;
            } else {
                fighter2.health -= fighter1.attack;
            }
        }
    ////////////////////////////////////////////////////////////////////////////
    /////////////////////////// REPEAT FOR FIGHTER 2 ///////////////////////////
    ////////////////////////////////////////////////////////////////////////////
        printf("Fighter 2, press %c to attack: ", fighter2.attack_command);
        scanf(" %c", &action);
        if (action == fighter2.attack_command) {
            if (fighter2.health < MAX_HEALTH/2) {
                fighter1.health -= fighter2.attack * 1.5;
            } else {
                fighter1.health -= fighter2.attack;
            }
            printf("Fighter 2 attacks!\n");
        }
        printf("\n");
        printf("Fighter 1's health: %.01lf\n", fighter1.health);
        printf("Fighter 2's health: %.01lf\n", fighter2.health);
    }

    ////////////////////////////////////////////////////////////////////////////
    ////////////////////////////// Fight Results ///////////////////////////////
    ////////////////////////////////////////////////////////////////////////////
    printf("\n");
    if (fighter1.health <= 0 && fighter2.health <= 0) {
        printf("It's a draw!\n");
    } else if (fighter1.health > 0) {
        printf("Fighter 1 wins!\n");
    } else {
        printf("Fighter 2 wins!\n");
    }
    
    printf("GAME OVER\n");
    return 0;
}

Exercise
(●●●)
:

Draw a fancy pattern

Write a program called xtreme.c that reads an (odd) integer n from standard input, and prints an n x n a square of asterisks and dashes in the following pattern:

Enter size: 9
*---*---*
-*-----*-
--*---*--
---*-*---
*---*---*
---*-*---
--*---*--
-*-----*-
*---*---*
Enter size: 15
*---*-----*---*
-*---*---*---*-
--*---*-*---*--
---*---*---*---
*---*-----*---*
-*---*---*---*-
--*---*-*---*--
---*---*---*---
--*---*-*---*--
-*---*---*---*-
*---*-----*---*
---*---*---*---
--*---*-*---*--
-*---*---*---*-
*---*-----*---*
Enter size: 25
*---*---*---*---*---*---*
-*---*---*-----*---*---*-
--*---*---*---*---*---*--
---*---*---*-*---*---*---
*---*---*---*---*---*---*
-*---*---*-----*---*---*-
--*---*---*---*---*---*--
---*---*---*-*---*---*---
*---*---*---*---*---*---*
-*---*---*-----*---*---*-
--*---*---*---*---*---*--
---*---*---*-*---*---*---
*---*---*---*---*---*---*
---*---*---*-*---*---*---
--*---*---*---*---*---*--
-*---*---*-----*---*---*-
*---*---*---*---*---*---*
---*---*---*-*---*---*---
--*---*---*---*---*---*--
-*---*---*-----*---*---*-
*---*---*---*---*---*---*
---*---*---*-*---*---*---
--*---*---*---*---*---*--
-*---*---*-----*---*---*-
*---*---*---*---*---*---*

For more examples of this pattern, see the example program output at the end of this question

This exercise is designed to give you practice with while loops, if statements and some mathematical operators.

As the course has not taught arrays yet, you are not permitted to use an array in this exercise.

Examples

dcc xtreme.c -o xtreme
./xtreme
Enter size: 5
*---*
-*-*-
--*--
-*-*-
*---*
./xtreme
Enter size: 7
*-----*
-*---*-
--*-*--
---*---
--*-*--
-*---*-
*-----*
./xtreme
Enter size: 11
*---*-*---*
-*---*---*-
--*-----*--
---*---*---
*---*-*---*
-*---*---*-
*---*-*---*
---*---*---
--*-----*--
-*---*---*-
*---*-*---*
./xtreme
Enter size: 13
*---*---*---*
-*---*-*---*-
--*---*---*--
---*-----*---
*---*---*---*
-*---*-*---*-
--*---*---*--
-*---*-*---*-
*---*---*---*
---*-----*---
--*---*---*--
-*---*-*---*-
*---*---*---*
./xtreme
Enter size: 17
*---*---*---*---*
-*---*-----*---*-
--*---*---*---*--
---*---*-*---*---
*---*---*---*---*
-*---*-----*---*-
--*---*---*---*--
---*---*-*---*---
*---*---*---*---*
---*---*-*---*---
--*---*---*---*--
-*---*-----*---*-
*---*---*---*---*
---*---*-*---*---
--*---*---*---*--
-*---*-----*---*-
*---*---*---*---*

Assumptions/Restrictions/Hints

  • You can assume n is odd and n >= 5.
  • You may assume that you will be given only integers as input
  • You may assume that all input is valid
You can run an automated code style checker using the following command:
1511 style xtreme.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest xtreme

When you are finished working on this exercise, you must submit your work by running give:

give cs1511 lab03_xtreme xtreme.c

You must run give before Tuesday 07 October 18:00 to obtain the marks for this lab exercise. Note that this is an individual exercise, the work you submit with give must be entirely your own.

Sample solution for xtreme.c
#include <stdio.h>

#define GAP 4


int main(void) {

    printf("Enter size: ");
    int size;
    scanf("%d", &size);

    int half_size = size/2;

    int row = 0;
    while (row < size) {
        int column = 0;
        while (column < size) {
            // Top left/bottom right quadrant
            if ((row <= half_size) == (column < half_size)) {
                if (row % GAP == column % GAP) {
                    printf("*");
                } else {
                    printf("-");
                }

            // bottom right/ top left quadrant
            } else {
                if (row % GAP == (size - 1 - column) % GAP) {
                    printf("*");
                } else {
                    printf("-");
                }
            }
            column = column + 1;
        }
        printf("\n");
        row = row + 1;
    }

    return 0;
}
Alternative solution for xtreme.c
// A program that prints an n x n square of dashes in a certain pattern
// By Nathan Colyer on the 28/02/2023

#include <stdio.h>

int abs(int x);

int main(void) {
    int len;
    // Note that 'size' (len) is odd and greater than 5
    printf("Enter size: ");
    scanf(" %d", &len);

    for (int row = 0; row < len; row++) {
        for (int col = 0; col < len; col++) {
            int col_mirror = abs(col - len / 2);
            int row_mirror = abs(row - len / 2);
            if ((row_mirror - col_mirror) % 4 == 0) {
                putchar('*');
            } else {
                putchar('-');
            }
        }
        putchar('\n');
    }
    return 0;
}

// Takes the absolute value of a number
int abs(int x) {
    if (x < 0) x = -x;
    return x;
};

Exercise
(●●●)
:

Perfect Number

Write a program called perfect_number.c that continuously reads numbers until the end of input and determines whether each number is a perfect number.

A perfect number is a positive integer that is equal to the sum of it's factors (excluding the number itself). A factor is a number that divides the given number exactly, leaving no remainder.

For example, 6 is a perfect number (1 + 2 + 3 = 6) but 4 is not (1 + 2 != 4).

Examples

dcc perfect_number.c -o perfect_number
./perfect_number
Enter a number: 3
No, 3 is not a perfect number!
Enter a number: 6
Yes, 6 is a perfect number!
Enter a number: 10
No, 10 is not a perfect number!
Enter a number: 
./perfect_number
Enter a number: 

Assumptions/Restrictions/Clarifications

  • You can assume that the number will always be a whole number (i.e. an integer).
  • You can assume that the number will always be positive (i.e. greater than zero).
  • You may assume that the user has finish typing in input when Ctrl-D is pressed.
  • You may assume that the maximum value required to be checked is 2147483647 (max value an int can store!).
  • Given 1 has no divisors other than the number itself, 1 is not counted as a perfect number.
  • Note, the autotests expects a new line character (\n) to be printed after Ctrl-D is pressed.
You can run an automated code style checker using the following command:
1511 style perfect_number.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest perfect_number

When you are finished working on this exercise, you must submit your work by running give:

give cs1511 lab03_perfect_number perfect_number.c

You must run give before Tuesday 07 October 18:00 to obtain the marks for this lab exercise. Note that this is an individual exercise, the work you submit with give must be entirely your own.

Sample solution for perfect_number.c
// Perfect Number
// perfect_number.c
//
// This program was written on 09/02/2025
// by Grace Murray (z5363191)
//
// A program which determines if given numbers are perfect numbers.

#include <stdio.h>

int main(void) {

    int number = 0;
    printf("Enter a number: ");

    while (scanf("%d", &number) == 1) {

        int current = 1;
        int sum = 0;

        while (current < number) {
            if (number % current == 0) {
                sum += current;
            }
            current++;
        }

        if (number == sum) {
            printf("Yes, %d is a perfect number!\n", number);
        } else {
            printf("No, %d is not a perfect number!\n", number);
        }

        printf("Enter a number:");

    }

    printf("\n");

    return 0;
}

Exercise
(☠)
:

Spiral

Write a program called spiral.c that reads an integer n from standard input. and prints an n x n pattern of asterisks and dashes in the shape of a spiral.

Examples

dcc spiral.c -o spiral
./spiral
Enter size: 5
*****
----*
***-*
*---*
*****
./spiral
Enter size: 7
*******
------*
*****-*
*---*-*
*-***-*
*-----*
*******
./spiral
Enter size: 9
*********
--------*
*******-*
*-----*-*
*-***-*-*
*-*---*-*
*-*****-*
*-------*
*********
./spiral
Enter size: 17
*****************
----------------*
***************-*
*-------------*-*
*-***********-*-*
*-*---------*-*-*
*-*-*******-*-*-*
*-*-*-----*-*-*-*
*-*-*-***-*-*-*-*
*-*-*-*---*-*-*-*
*-*-*-*****-*-*-*
*-*-*-------*-*-*
*-*-*********-*-*
*-*-----------*-*
*-*************-*
*---------------*
*****************

Assumptions/Restrictions/Clarifications

  • You can assume n is odd and n >= 5.
You can run an automated code style checker using the following command:
1511 style spiral.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest spiral
Sample solution for spiral.c
//spiral.c
//By Alex Rowell z5116848
//Written 20th/21st March 2017
//A program to print a spiral of stars

#include <stdio.h>
#include <stdlib.h>


//A key part of this implementation is splitting the numbers into lines
//These are the straight lines of numbers, with the first number coming from the line before
//There are 4 cases to deal with each line based on which direction it would go when spiraling inwards
//(For the example below 'r' is for lines going right, 'd' for lines going down, 'u' for lines going up and 'l' for lines going left)
//eg.
// rrrrr
// ----d
// urr-d
// u---d
// lllld

int main(void) {
    int num;

    printf("Enter size: ");
    if (!scanf("%d", &num) || num % 2 == 0) {
        //Did not get a number or the number is even, exit
        return 1;
    }

    int row = 0;
    int col = 0;

    while (row < num) {
        col = 0;

        while (col < num) {
            if (row <= num/2 && row % 2 == 0 && col >= row - 1 && col <= num-row - 1) { //Line going to the right

                printf("*");

            } else if (row > num/2 && row % 2 == 0 && col <= row && col >= num - row - 1) { //Line going to the left

                printf("*");

            } else if (col <= num/2 && col % 2 == 0 && row >= col + 2 && row < num - col - 1) { //Line going upwards

                printf("*");

            } else if (col > num/2 && col % 2 == 0 && row <= col && row >= num - col) { //Line going downwards

                printf("*");

            } else { // Not part of any line

                printf("-");

            }

            col = col + 1;
        }
        printf("\n");
        row = row + 1;
    }

    return 0;
}

Exercise
(☠)
:

Decimal Spiral (extra-hard)

Write a program called decimal_spiral.c that reads an integer n from standard input. and prints an n x n pattern of decimal digits and dashes in the shape of a spiral.

Examples

dcc decimal_spiral.c -o decimal_spiral
./decimal_spiral
Enter size: 5
65432
----1
210-0
3---9
45678
./decimal_spiral
Enter size: 7
0987654
------3
87654-2
9---3-1
0-012-0
1-----9
2345678
./decimal_spiral
Enter size: 9
876543210
--------9
8765432-8
9-----1-7
0-210-0-6
1-3---9-5
2-45678-4
3-------3
456789012
./decimal_spiral
Enter size: 15
654321098765432
--------------1
2109876543210-0
3-----------9-9
4-210987654-8-8
5-3-------3-7-7
6-4-87654-2-6-6
7-5-9---3-1-5-5
8-6-0-012-0-4-4
9-7-1-----9-3-3
0-8-2345678-2-2
1-9---------1-1
2-01234567890-0
3-------------9
456789012345678

Assumptions/Restrictions/Clarifications

  • You can assume n is odd and n >= 5.
You can run an automated code style checker using the following command:
1511 style decimal_spiral.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest decimal_spiral
Sample solution for decimal_spiral.c
//decimal_spiral.c
//By Alex Rowell z5116848
//Written 20th March 2017
//A program to print a spiral of numbers, with the numbers increasing as it spirals outwards

#include <stdio.h>
#include <stdlib.h>


//These are for the direction of the current line being printed (to be explained below)
#define DIR_NONE 0
#define DIR_LEFT 1
#define DIR_RIGHT 2
#define DIR_UP 3
#define DIR_DOWN 4


//A key part of this implementation is splitting the numbers into lines
//These are the straight lines of numbers, with the first number coming from the line before
//There are 4 cases to deal with each line based on which direction it would go when spiraling inwards
//(For the example below 'r' is for lines going right, 'd' for lines going down, 'u' for lines going up and 'l' for lines going left)
//eg.
// rrrrr
// ----d
// urr-d
// u---d
// lllld

int main(void) {
    int num;

    printf("Enter size: ");
    if (!scanf("%d", &num) || num % 2 == 0) {
        //Did not get a number or the number is even, exit
        return 1;
    }


    // These are the sizes of the original lines, the right line starts
    // longer than the others since it doesn't have another direction that takes its first number
    // The up line starts shorter than the others since every time it gets to the upwards line the line
    // gets smaller
    int original_up_size = num - 3;
    int original_down_size = num - 1;
    int original_right_size = num + 1;
    int original_left_size = num - 1;



    //Determine the total number of numbers to write (so that it can count down)
    //This is done by simulating each side
    int total_stars = 0;

    int up_size = original_up_size;
    int down_size = original_down_size;
    int right_size = original_right_size;
    int left_size = original_left_size;

    while (up_size > 0) {
        total_stars = total_stars + up_size;
        up_size = up_size - 4; //Every go of the spiral, each side shrinks by 4
    }
    while (down_size > 0) {
        total_stars = total_stars + down_size;
        down_size = down_size - 4;
    }
    while (right_size > 0) {
        total_stars = total_stars + right_size;
        right_size = right_size - 4;
    }
    while (left_size > 0) {
        total_stars = total_stars + left_size;
        left_size = left_size - 4;
    }


    int row = 0;
    int col = 0;

    while (row < num) {
        col = 0;

        while (col < num) {

            int line_num = 0; // The number of line changes in the spiral before this line

            int offset = 0; // The number along the line this position is

            int line_dir = DIR_NONE; //The direction the line's going (or none if a dash should be printed)


            if (row <= num/2 && row % 2 == 0 && col >= row - 1 && col <= num-row - 1) { //Line going to the right
                line_dir = DIR_RIGHT;
                line_num = (row / 2 * 4);

                offset = col - row + 2;

            } else if (row > num/2 && row % 2 == 0 && col <= row && col >= num - row - 1) { //Line going to the left
                line_dir = DIR_LEFT;
                line_num = ((num-row-1)/2 * 4) + 2;

                offset = row - col;

            } else if (col <= num/2 && col % 2 == 0 && row >= col + 2 && row < num - col - 1) { //Line going upwards
                line_dir = DIR_UP;
                line_num = (col / 2 * 4) + 3;

                offset = num - col - 1 - row;
            } else if (col > num/2 && col % 2 == 0 && row <= col && row >= num - col) { //Line going downwards
                line_dir = DIR_DOWN;
                line_num = ((num-col-1)/2 * 4) + 1;

                offset = row - num + col + 1;
            }

            if (line_dir != DIR_NONE) {
                // Reset the number of stars in the first line of each type
                // For calculating the number to print out
                up_size = original_up_size;
                down_size = original_down_size;
                right_size = original_right_size;
                left_size = original_left_size;

                int num_so_far = 0; //The total numbers that have been printed so far in the spiral
                int i = 0;

                while (i < line_num) {
                    // Similar to calculating total number of numbers printed in the whole spiral
                    // but in this case only go up to the current line
                    if (i % 4 == 0) { // rightwards line
                        num_so_far = num_so_far + right_size;
                        right_size = right_size - 4;
                    } else if (i % 4 == 1) { // downwards line
                        num_so_far = num_so_far + down_size;
                        down_size = down_size - 4;
                    } else if (i % 4 == 2) { // leftwards line
                        num_so_far = num_so_far + left_size;
                        left_size = left_size - 4;
                    } else { // i % 4 == 3, upwards line
                        num_so_far = num_so_far + up_size;
                        up_size = up_size - 4;
                    }

                    i = i + 1;
                }

                num_so_far = num_so_far + offset; // Include the amount printed in the current line

                int to_print = total_stars - num_so_far; // Subtract num_so_far from total_stars as
                // the spiral should be counting down as it goes inwards
                printf("%d", to_print % 10); // Only take last digit of what to print

            } else {
                printf("-"); // Not part of spiral, just print a dash
            }
            col = col + 1;
        }
        printf("\n");
        row = row + 1;
    }

    return 0;
}
Alternative solution for decimal_spiral.c
// Draws a decimal spiral of size defined by the user. O(n^2)
// By Sabine Lim z5242579
// For COMP1511 Lab04

// The implementation consists of 2 parts:
// 1. Loop left to right, up to down, calling an isDigit function to
// know whether to print a digit or a dash for each coordinate
// 2. If a digit should be printed, call a getDigit function to
// calculate the digit to be printed

// The isDigit function is the same the code for the regular spiral, but
// instead of printing an asterisk it returns 1 to whatever code called it

// getDigit works by splitting the spiral into triangular quadrants
//
//   *******
// *  *****  *
// **  ***  **
// ***  *  ***
// **  ***  **
// *  *****  *
//   *******
//
// For the top quadrant, observe the following digits
//
// 6**************
// --------------*
// **0**********-*
// *-----------*-*
// *-**0******-*-*
// *-*-------*-*-*
// *-*-**6**-*-*-*
// *-*-*---*-*-*-*
// *-*-*-***-*-*-*
// *-*-*-----*-*-*
// *-*-*******-*-*
// *-*---------*-*
// *-***********-*
// *-------------*
// ***************
//
// The actual numbers at the location of these digits form a quadratic sequence
// 6  30  70  126
//  24  40  56
//    16  16
// Where the differences between the differences is 16.
// Using this, you can make a quadratic sequence for the top left corners
// of each box, and subtract the current column to find the digits for
// coordinates to the right
//
// You'll need to come up with a different quadratic equation for each quadrant
// Since there are 2 types of spiral (last digit in the centre, last digit
// off-centre, that's a total of 8 different quadratic equations
// Use the current column or current row accordingly to determine how much
// to add or subtract from the corner values

#include <stdio.h>

int abs(int i);
// Returns 0 if current coordinate is a dash, 1 for a digit
int isDigit(int size, int row, int col);
// Returns the integer at a specific coordinate on a box for a given size
int getDigit(int size, int row, int col);

int main() {
    int size = 0;
    printf("Enter size: ");
    scanf("%d", &size);
    int row = 0;
    while (row < size) {
        int col = 0;
        while (col < size) {
            if (isDigit(size, row, col) == 1) {
                if (row <= size / 2 && col < size / 2 && row == col + 1) {
                    // Special handling for box segments modified to be spirals
                    printf("%d", getDigit(size, row - 1, col - 1) % 10);
                } else {
                    printf("%d", getDigit(size, row, col) % 10);
                }
            } else {
                printf("-");
            }
            ++col;
        }
        printf("\n");
        ++row;
    }
    return 0;
}

int abs(int i) {
    if (i < 0) {
        i = -i;
    }
    return i;
}

int isDigit(int size, int row, int col) {
    // Absolute row distance from midpoint
    int rowDist = abs(row - size / 2);
    // Absolute column distance from midpoint
    int colDist = abs(col - size / 2);
    int isDigit = 0;
    if (size % 4 == 1) {
        // Type 1 spiral (digit in centre)
        if (row <= size / 2 && col < size / 2 && row == col + 1) {
            // Special handling to turn boxes into spirals
            if (rowDist % 2 == 0) {
                isDigit = 1;
            }
        } else if (colDist >= rowDist && colDist % 2 == 0) {
            isDigit = 1;
        } else if (colDist < rowDist && rowDist % 2 == 0) {
            isDigit = 1;
        }
    } else {
        // Type 2 spiral (no digit in centre)
        if (row <= size / 2 && col < size / 2 && row == col + 1) {
            // Special handling to turn boxes into spirals
            if (rowDist % 2 == 1) {
                isDigit = 1;
            }
        } else if (colDist >= rowDist && colDist % 2 == 1) {
            isDigit = 1;
        } else if (colDist < rowDist && rowDist % 2 == 1) {
            isDigit = 1;
        }
    }
    return isDigit;
}

int getDigit(int size, int row, int col) {
    // Row displacement from midpoint
    int rowDist = row - size / 2;
    // Absolute row distance from midpoint
    int absRowDist = abs(rowDist);
    // Column displacement from midpoint
    int colDist = col - size / 2;
    // Absolute column distance from midpoint
    int absColDist = abs(colDist);
    // Size of box current coordinate is on
    int subSize = 0;
    if (absRowDist >= absColDist) {
        subSize = 2 * absRowDist + 1;
    } else {
        subSize = 2 * absColDist + 1;
    }
    row = row - (size - subSize) / 2;
    col = col - (size - subSize) / 2;
    // Layer of current box. 0 is centre
    int layer = (subSize + 1) / 4;
    if (rowDist <= 0 && absRowDist >= absColDist) {
        // Top quadrant
        if (subSize % 4 == 1) {
            // Type 1 boxes
            return 8 * layer * layer + 8 * layer - col;
        } else {
            // Type 2 boxes
            return 8 * layer * layer - 2 - col;
        }
    } else if (colDist > 0 && absColDist > absRowDist) {
        // Right quadrant
        if (subSize % 4 == 1) {
            // Type 1 boxes
            return 8 * layer * layer + 4 * layer - row;
        } else {
            // Type 2 boxes
            return 8 * layer * layer - 4 * layer - row;
        }
    } else if (rowDist > 0 && absRowDist >= absColDist) {
        // Bottom quadrant
        if (subSize % 4 == 1) {
            // Type 1 boxes
            return 8 * layer * layer - 4 * layer + col;
        } else {
            // Type 2 boxes
            return 8 * layer * layer - 12 * layer + 4 + col;
        }
    } else {
        // Left quadrant
        if (subSize % 4 == 1) {
            // Type 1 boxes
            return 8 * layer * layer - 8 * layer + row;
        } else {
            // Type 2 boxes
            return 8 * layer * layer - 16 * layer + 6 + row;
        }
    }
}

Exercise — individual:
(Not For Marks) Debugging - Square

Download debug_square.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity debug_square

Note that this exercise is not marked or worth marks!

Debugging Tips!

Some debugging tips for you:

  • dcc output - as you run into issues, dcc will point you to where the errors are. Remember that dcc gives you the line number the issue is on, and will give some sort of explanation. Make sure you read everything dcc gives you. Sometimes we get “errors carried forward”, so find your first error, fix that, then recompile.
  • print statements - sometimes it can be handy to see if the flow of your code puts you in the spot you expect it to be (ie. inside the right if statement, or going through a loop the correct amount of times). A quick way you can check this is by putting print statements in your code for testing purposes, like "the value of x is %d and y is %d". This lets you check that you got against what you expected.
  • COMP1511 debugging guide

The Task

This exercise takes in a positive integer 'n' as input, and prints the outline of a square of size 'n' by 'n' in asterisks ('x'). Currently it has some issues - it is your job to figure them out and fix the code.

Examples

dcc debug_square.c -o debug_square
./debug_square
Enter the size of the pattern: 2
**
**
./debug_square
Enter the size of the pattern: 5
*****
*   *
*   *
*   *
*****
./debug_square
Enter the size of the pattern: 1
*

Walkthrough

Below is a video walkthrough of this exercise! Make sure to attempt it before watching this video

You can run an automated code style checker using the following command:
1511 style debug_square.c

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest debug_square
Sample solution for debug_square.c
// debug_square.c
//
// Write a C program that prints the outline of a square in asterisks ('*').
// The program should take a positive integer 'n' as input and print the 
// outline of a square of size 'n' by 'n'.
//
// Sofia De Bellis, 2023

#include <stdio.h>

int main (void) {
    int size = 0;
    int rows = 0;
    int cols = 0;

    printf("Enter the size of the pattern: ");
    scanf("%d", &size);

    while (rows < size) {
        cols = 0;
        while (cols < size) {
            if (rows == 0 || cols == 0 || rows == size - 1 || cols == size - 1) {
                printf("*");
            } else {
                printf(" ");
            }
            cols++;
        }
        printf("\n");
        rows++;
    }
    return 0;
}

Exercise — individual:
(Not For Marks) Splashkit

Splashkit logo

Welcome to our SplashKit activity page! Designed to ignite your creativity, these walkthroughs will guide you into the world of Graphical User Interfaces (GUIs) with ease.

With SplashKit, a toolkit tailored for beginners, you'll find GUI development both accessible and enjoyable. It simplifies the process of creating windows, drawing graphics, and managing user input, allowing you to focus on bringing your ideas to life.

Through the activities on this page, you'll gain hands-on experience with SplashKit, mastering the basics while building confidence in your programming skills.

Dive in, explore, and let your imagination guide you as you discover the exciting possibilities of GUI programming!

SplashKit.io (2017) Let’s Build A Game In One Minute - SplashKit.

 

Are you ready to bring your C programs to life with colour, graphics, and interactivity?

This activity is the first in a series that will take your programs beyond printf() and the terminal.

SplashKit

Graphical User Interfaces (GUIs) allow programs to display graphics, text, buttons, and other dynamic elements in dedicated application windows.

SplashKit is a beginner-friendly toolkit that simplifies GUI development, making it easy to write programs that create windows, draw graphics, and handle user input with minimal setup.

Getting Started

Let's get everything set up so you can start coding with SplashKit:

  1. Create a Project Directory.
  2. Install SplashKit.
  3. Compile an Example File.
  4. Run the Example Program.
  5. Set up the VS Code Project.

1. Create a Project Directory

As you progress through these activities, you will be working with many files. Creating a folder for each activity is essential and will help to keep your files organised.

First, create a new directory to store all of your SplashKit projects and cd into it.

mkdir splashkit
cd splashkit

Similarly, create another new directory for your first project and cd into it.

mkdir getting_started
cd getting_started

2. Install SplashKit

From your getting_started directory, install SplashKit to your CSE account using:

1511 setup-splashkit splashkit_getting_started

SplashKit should now be installed.

Use the ls command to confirm that splashkit_examples.c has been copied to your getting_started directory.

3. Compile an Example File

Until now, we’ve used dcc to compile C code.

SplashKit projects require a different compiler called skm clang++.

Compile the splashkit_examples.c file using:

skm clang++ splashkit_example.c -o splashkit_example

If SplashKit was installed correctly, you will see this message:

🎉  clang++ command run successfully 🎉

Use the ls command to confirm that a file named splashkit_example exists in your getting_started directory

4. Run the Example Program

We run SplashKit programs the same way that we run our C programs.

Run the example program with the following command.

./splashkit_example

A window opens, displaying "Hello, SplashKit!", then closes after 5 seconds.

5. Set Up the VS Code Project

Use pwd to ensure that you're in the getting_started directory, then open it with code ..

VS Code lists your project files on the left (press Ctrl+B if it's missing).

Click on splashkit_example.c to open it:

VS Code highlighting errors in splashkit_example.c

Notice anything strange? VS Code is highlighting errors on nearly every line!

This is because VS Code doesn't know about SplashKit.

Close VS Code and run the following command from inside your project directory:

1511 setup-splashkit-directory

Reopen the project with code . and the errors should be gone!

You will learn more about how the example code works in the upcoming SplashKit activities. For now, note the line #include <splashkit.h> at the top of the file. This is similar to #include <stdio> and it allows us to use the SplashKit toolkit in our code.

SplashKit Summary

We've covered a lot of material to get started. Here's what to remember:

  • SplashKit is installed once with 1511 setup-splashkit splashkit_getting_started.
  • Create a separate directory for each SplashKit project.
  • Set up each SplashKit directory with 1511 setup-splashkit-directory.
  • SplashKit projects are opened with code ..
  • Compile SplashKit code with skm clang++ instead of dcc.
  • Run SplashKit programs normally e.g. ./program_name.

In this activity, you will learn how to manage windows with SplashKit.

A window is a rectangular area on the screen where graphical programs display visual elements and interact with the user. Windows are everywhere. If you're viewing this in a browser (such as Firefox, Chrome, or Safari) then the browser is open in a window. Familiar applications such as VS Code, the terminal, and file managers (Finder on macOS, File Explorer on Windows) all open in their own windows.

Setting Up

Step 1. Navigate to your SplashKit directory (the one created during SplashKit #1 - Getting Started).

cd splashkit

Step 2. Create a new directory for this activity and cd into it.

mkdir windows
cd windows

Step 3. Set up the windows directory.

1511 setup-splashkit-directory

Step 4.

Download splashkit_windows.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity splashkit_windows

Step 5. Open the SplashKit project directory in VS Code.

code .

SplashKit Windows

SplashKit includes a windows library that allows programs to open and close windows. Opening a window gives your program a dedicated space to display graphics and receive user input, while closing it is crucial for freeing up resources and providing a clear way for users to exit.

To use SplashKit's libraries add #include <splashkit.h> near the top of a .c file. Once you do this, you have a starting point for all of your SplashKit programs:

#include <splashkit.h>

int main(void) {
    // we will be adding more code here

    return 0;
}

Opening Windows

SplashKit's open_window() function creates a new window and displays it on the screen.

window open_window(string caption, int width, int height);

The following statement opens a window titled "My Window" with a width and height of 800 and 600 pixels respectively.

open_window("My Window", 800, 600);

Delay/Wait

Imagine you want to show a quick welcome message or instructions on the screen, but you don't want the program to instantly jump to the next step. By pausing for a couple of seconds you give the user time to understand what's being shown before continuing.

SplashKit provides a delay() function. Calling this will pause our program for a specified amount of time.

void delay(int milliseconds);

For example:

delay(7000);

This pauses program execution for 7 seconds (7000 milliseconds) before continuing.

Closing Windows

When you're finished with the window, you can close it with close_all_windows().

void close_all_windows(void);

We call this function with no arguments:

close_all_windows();

Putting It All Together

Combining these operations yields a short program:

#include <splashkit.h>

int main(void) {
    open_window("My Window", 800, 600);
    delay(7000);
    close_all_windows();

    return 0;
}

This program:

  1. Opens a window titled "My Window" width and height of 800 and 600 pixels respectively.
  2. Pauses program execution for 7 seconds, keeping the window open.
  3. Closes the window before exiting.

Code Demo

#include <splashkit.h>

#define WIDTH 400
#define HEIGHT 240
#define DELAY_DURATION 4000

int main(void) {
    // window open_window(string caption, int width, int height);
    // Open a window of width 640 pixels and height 480 pixels
    open_window("My First Window", 640, 480);

    // void delay(int milliseconds);
    // Wait two seconds (2000 milliseconds)
    delay(2000);

    // void close_all_windows(void);
    // Close the window
    close_all_windows();

    // Open a second window, this time using #defined constants
    open_window("My Second Window", WIDTH, HEIGHT);
    delay(DELAY_DURATION);
    close_all_windows();

    // Open a third window, this time using variables as arguments
    int width = 960;
    int height = 360;
    int duration = 3000;
    open_window("My Third Window", width, height);
    delay(duration);
    close_all_windows();

    return 0;
}

Activity

Now you have a chance to practice what you've learned!

Create a program splashkit_windows.c. It should:

  • Prompt the user for a width.
  • Prompt the user for a height.
  • Prompt the user for a duration.
  • Open a window of the given size.
  • Wait for the specified duration, keeping the window open.
  • Close the window.

Examples

Example 1: Opening a 400×300 Window for 5 Seconds

skm clang++ splashkit_master.c -o splashkit_master
./splashkit_master
Enter a window width (pixels): 400
Enter a window height (pixels): 300
Enter a duration (seconds): 5

After the user enters these values, a window should appear as shown below and automatically close after 5 seconds.

Screenshot of a SplashKit window (width=400px, height=300px)

Example 2: Opening a 600×200 Window for 12 Seconds

skm clang++ splashkit_master.c -o splashkit_master
./splashkit_master
Enter a window width (pixels): 600
Enter a window height (pixels): 200
Enter a duration (seconds): 12

After the user enters these values, a window should appear as shown below and automatically close after 12 seconds.

Screenshot of a SplashKit window (width=400px, height=300px)

Assumptions/Restrictions/Clarifications

  • There are no autotests for this activity.

Summary

In this activity, you learned how to work with three functions to manage windows:

  1. open_window(caption, width, height) - Opens a new window on the screen.
  2. delay(milliseconds) - Pauses program execution.
  3. close_all_windows() - Closes all windows.

List of New Functions

At the end of each activity, you'll find a list of all new function prototypes.

Keeping a list of these functions as you progress will be useful for whenever you need a quick refresher.

// Window Management
window open_window(string caption, int width, int height);
void close_all_windows(void);

// Program Control
void delay(int milliseconds);

Welcome to the  c o l o u r f u l  world of SplashKit!

In this activity, you'll discover how colours are used in SplashKit to make your programs bright and visually appealing.

With an understanding of colours, you will be able to control how shapes and text appear when displayed by your program. You'll learn:

  • How colours are represented in SplashKit.
  • How to use some fun, built-in colours.
  • How to create your very own custom colours using RGB values.

Setting Up

Step 1. Navigate to your SplashKit directory (the one created during SplashKit #1 - Getting Started).

cd splashkit

Step 2. Create a new directory for this activity and cd into it.

mkdir colours
cd colours

Step 3. Set up the colours directory.

1511 setup-splashkit-directory

Step 4.

Download splashkit_colours.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity splashkit_colours

Step 5. Open the SplashKit project directory in VS Code.

code .

SplashKit Colours

SplashKit provides a color library that includes:

  • 144 built-in preset colours.
  • Functions to define over 16 million custom colours.
  • A color data type to store our colours as variables.

Our starter code is a familiar program from SplashKit #2 - Windows.

Copy this into a file named playground.c. Then, you can use this "playground" to experiment with colours as you progress through this activity.

#include <splashkit.h>

int main(void) {
    open_window("My Window", 800, 600);

    // TODO: we will add code here

    delay(2000);

    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Pauses for 2 seconds.
  • Closes the window and exits.

Compile and run it with:

skm clang++ playground.c -o playground
./playground


Clear and Refresh

To explore SplashKit's colours, we'll be changing the background colour of our window.

When you call clear_screen(), SplashKit changes the window's background to the colour you specify.

For example, the following statement clears our window and paints the background black:

clear_screen(COLOR_BLACK);

Note that calling clear_screen() alone won't display the new colour right away. SplashKit waits until you call refresh_screen() before showing any changes. So to make the update visible, follow the clear_screen() call with:

refresh_screen();

Calling refresh_screen() applies all pending updates to the window, allowing you to see your changes.

In later activities, you will be drawing shapes, text, and images on the window. Whether you're clearing the background or adding new elements, changes will not appear on the window until you call refresh_screen(). This function applies all pending updates since the last refresh, making your changes visible on the window.

To see how clear_screen() and refresh_screen() work together, try this program in your playground.c file. What does the program do if refresh_screen() isn't called? Try it and see!

#include <splashkit.h>

int main(void) {
    open_window("Clear and Refresh", 800, 600);
    delay(2000);

    // Clear the window and colour it black.
    clear_screen(COLOR_BLACK);
    // Refresh the screen to display our changes.
    refresh_screen();
    // Pause the program for 2 seconds.
    delay(2000);

    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Pauses for 2 seconds.
  • Calls clear_screen(COLOR_BLACK) to paint the window black.
  • Calls refresh_screen() to update the window with the changes from clear_screen().
  • Pauses for 2 seconds.
  • Closes the window and exits.


Preset Colours

We're not limited to COLOR_BLACK. SplashKit provides 144 built-in presets!

Here are a few to choose from:

  • COLOR_ORANGE_RED
  • COLOR_DEEP_SKY_BLUE
  • COLOR_PURPLE
  • COLOR_DARK_TURQUOISE

These values are like #defined constants, but for colours. Whenever a SplashKit function expects a colour parameter, we can use these as arguments. For example, we could call clear_screen() with:

  • clear_screen(COLOR_ORANGE_RED);
  • clear_screen(COLOR_PURPLE);
  • clear_screen(COLOR_DARK_TURQUOISE);

To see how different colour presets can be used, run this program in your playground.c file.

#include <splashkit.h>

#define DELAY_DURATION 2000

int main(void) {
    open_window("Using Preset Colours", 640, 480);

    // Black
    clear_screen(COLOR_BLACK);
    refresh_screen();
    delay(DELAY_DURATION);

    // Orange Red
    clear_screen(COLOR_ORANGE_RED);
    refresh_screen();
    delay(DELAY_DURATION);

    // Sky Blue
    clear_screen(COLOR_DEEP_SKY_BLUE);
    refresh_screen();
    delay(DELAY_DURATION);

    // Purple
    clear_screen(COLOR_PURPLE);
    refresh_screen();
    delay(DELAY_DURATION);

    // Dark Turquoise
    clear_screen(COLOR_DARK_TURQUOISE);
    refresh_screen();
    delay(DELAY_DURATION);

    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Pauses for 2 seconds.
  • Colours the window BLACK
  • Pauses for 2 seconds.
  • Colours the window ORANGE_RED
  • Pauses for 2 seconds.
  • Colours the window DEEP_SKY_BLUE
  • Pauses for 2 seconds.
  • Colours the window PURPLE
  • Pauses for 2 seconds.
  • Colours the window DARK_TURQUOISE
  • Pauses for 2 seconds.
  • Closes the window and exits.

For more preset colours:

  • Visit SplashKit's Colour Generator.
  • Scroll down to the Colour Palette.
  • Click on a colour.
  • The name will appear below.
Choosing from the SplashKit colour pallette

In the example above, the selected colour is COLOR_MEDIUM_BLUE.


The color Data Type

SplashKit provides a custom data type called color. Just like an int holds a number, a color holds a colour.

For example, you can assign a preset colour to a variable and pass it around your program:

color my_colour = COLOR_BLACK;
clear_screen(my_colour);
refresh_screen();

This code snippet:

  • Declares a color variable named my_colour.
  • Assigns it the value COLOR_BLACK.
  • Uses my_colour to paint the window black.
  • Calls refresh_screen() to display the change of colour.

Custom Colours

If the preset colours aren't enough, SplashKit gives you full control to construct over 16 million unique colours with an RGB colour model.

You can create colours by specifying how much of each colour component (red, green, and blue) to mix together. By mixing different amounts, you can produce just about any colour you can think of.

Each component can be assigned a value from 0 to 255 where:

  • 0 means "none of that colour".
  • 255 means "as much of that colour as possible".

These components are mixed with the rgb_color() function

color rgb_color(int red, int green, int blue);

which takes in three int values, one for each colour component, and returns a variable of type color.

Primary RGB Colours: Red, Green, Blue

These examples demonstrate how setting one component to its maximum value (255) while keeping the others at 0 results in the primary colours of the RGB colour model.

color red = rgb_color(255, 0, 0);

color green = rgb_color(0, 255, 0);

color blue = rgb_color(0, 0, 255);

Any Colour You Like

Experiment with different values in rgb_color() to invent your own unique shades!

Here are four extra colours to spark your creativity.

color sea_green = rgb_color(102, 194, 165);

color apricot_orange = rgb_color(252, 141, 98);

color wisteria_blue = rgb_color(141, 160, 203);

color orchid_purple = rgb_color(231, 138, 195);

Colours For All

Approximately 4-5% of the population lives with a Colour Vision Deficiency that affects how they perceive and distinguish colours. Although no single colour palette ensures universal accessibility, using a palette such as Okabe-Ito (below) can help make colours more enjoyable for all users.

color black = rgb_color(0, 0, 0);

color orange = rgb_color(230, 159, 0);

color sky_blue = rgb_color(86, 180, 233);

color bluish_green = rgb_color(0, 158, 115);

color yellow = rgb_color(240, 228, 66);

color blue = rgb_color(0, 114, 178);

color vermillion = rgb_color(213, 94, 0);

color reddish_purple = rgb_color(204, 121, 167);

Black, White, and Grey

A colour appears as a shade of grey when all three RGB components have the same value.

color black = rgb_color(0, 0, 0);

color darkgrey = rgb_color(63, 63, 63);

color grey = rgb_color(127, 127, 127);

color lightgrey = rgb_color(181, 181, 181);

color white = rgb_color(255, 255, 255);

To see how custom colours can be used, test this program in playground.c.

#include <splashkit.h>

#define DELAY_DURATION 2000

int main(void) {
    open_window("RGB Colours", 640, 480);

    color deep_blue  = rgb_color(  0, 114, 178);
    color vermillion = rgb_color(213,  94,   0); 
    color blue_green = rgb_color(  0, 158, 115); 
    color yellow     = rgb_color(240, 228,  66); 

    // Deep Blue
    clear_screen(deep_blue);
    refresh_screen();
    delay(DELAY_DURATION);

    // Vermillion
    clear_screen(vermillion);
    refresh_screen();
    delay(DELAY_DURATION);

    // Blue Green
    clear_screen(blue_green);
    refresh_screen();
    delay(DELAY_DURATION);

    // Yellow
    clear_screen(yellow);
    refresh_screen();
    delay(DELAY_DURATION);

    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Defines five custom colours with rgb_color() and assigns them to the variables deep_blue, vermillion, blue_green, and yellow.
  • Displays each colour on the screen for 2 seconds.
  • Closes the window and exits.

For more custom colours:

  • Visit SplashKit's Colour Generator.
  • Scroll down to the Colour Generator.
  • Set values for red, green, and blue.
  • Preview the RGB colour.
Screenshot of a SplashKit window (width=960px, height=360px)

In the example above, the warm orange colour can be assigned to a variable with:

color warm_orange = rgb_color(255, 183, 77);


Activity

Create a program splashkit_colours.c. It should:

  • Prompt the user for a red value from 0 to 255.
  • Prompt the user for a green value 0 to 255.
  • Prompt the user for a blue value 0 to 255.
  • Open a window 960 pixels wide and 360 pixels in height.
  • Display the corresponding RGB colour for 5 seconds.
  • Close the window.

Examples

skm clang++ splashkit_master.c -o splashkit_master
./splashkit_master
Enter a RED value (from 0 to 255): 0
Enter a GREEN value (from 0 to 255): 191
Enter a BLUE value (from 0 to 255): 255

After the user enters these values, a window should appear as shown below, displaying a deep sky blue colour for 5 seconds before closing.

Screenshot of a SplashKit window (width=960px, height=360px)
skm clang++ splashkit_master.c -o splashkit_master
./splashkit_master
Enter a RED value (from 0 to 255): 255
Enter a GREEN value (from 0 to 255): 69
Enter a BLUE value (from 0 to 255): 0

Similarly, a window should appear as shown below, displaying an orange red colour for 5 seconds before closing.

Screenshot of a SplashKit window (width=960px, height=360px)

Assumptions/Restrictions/Clarifications

  • There are no autotests for this activity.

Summary

In this activity, you learned how to work with three functions to manage colours:

  1. clear_screen(color) - Clears the window and changes the background colour.
  2. refresh_screen() - Applies changes to display them on the window.
  3. rgb_color(red, green, blue) - Creates a colour from RGB components.

Types and Functions

// Screen Management
void clear_screen(color clr);
void refresh_screen(void);

// Colours
color rgb_color(int red, int green, int blue);

// Okabe-Ito Accessible Colour Palette
color black          = rgb_color(  0,   0,   0);
color orange         = rgb_color(230, 159,   0);
color sky_blue       = rgb_color( 86, 180, 233);
color bluish_green   = rgb_color(  0, 158, 115);
color yellow         = rgb_color(240, 228,  66);
color blue           = rgb_color(  0, 114, 178);
color vermillion     = rgb_color(213,  94,   0);
color reddish_purple = rgb_color(204, 121, 167);

// Window Management
window open_window(string caption, int width, int height);
void close_all_windows(void);

// Program Control
void delay(int milliseconds);

// Screen Management
void clear_screen(color clr);
void refresh_screen(void);

// Colours
color rgb_color(int red, int green, int blue);

// Okabe-Ito Accessible Colour Palette
color black          = rgb_color(  0,   0,   0);
color orange         = rgb_color(230, 159,   0);
color sky_blue       = rgb_color( 86, 180, 233);
color bluish_green   = rgb_color(  0, 158, 115);
color yellow         = rgb_color(240, 228,  66);
color blue           = rgb_color(  0, 114, 178);
color vermillion     = rgb_color(213,  94,   0);
color reddish_purple = rgb_color(204, 121, 167);

In previous activities you learned how to:

  • Open a window.
  • Define and use colours.
  • Clear and refresh the screen.

In this activity, we'll explore how to draw various shapes onto our window. This includes: pixels, lines, rectangles, circles, ellipses, and triangles. We'll also extend our knowledge of colours with semi-transparent colours.

Setting Up

Step 1. Navigate to your SplashKit directory (the one created during SplashKit #1 - Getting Started).

cd splashkit

Step 2. Create a new directory for this activity and cd into it.

mkdir drawing
cd drawing

Step 3. Set up the drawing directory.

1511 setup-splashkit-directory

Step 4.

Download splashkit_master.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity splashkit_master

Step 5. Open the SplashKit project directory in VS Code.

code .

SplashKit Drawing

SplashKit provides a graphics library that includes functions to draw shapes such as:

  • Pixels.
  • Lines.
  • Rectangles.
  • Circles.
  • Ellipses.
  • Triangles.

Our starter code is a familiar program from SplashKit #2 - Windows and includes an accessible palette of colours from SplashKit #3 - Colours.

Copy this into a file named playground.c. You can then use this "playground" to experiment with sample programs as you progress through this activity.

#include <splashkit.h>

int main(void) {
    open_window("My Window", 800, 600);

    color black = rgb_color(0, 0, 0);
    color orange = rgb_color(230, 159, 0);
    color sky_blue = rgb_color(86, 180, 233);
    color bluish_green = rgb_color(0, 158, 115);
    color yellow = rgb_color(240, 228, 66);
    color blue = rgb_color(0, 114, 178);
    color vermillion = rgb_color(213, 94, 0);
    color reddish_purple = rgb_color(204, 121, 167);

    // TODO: we will add code here

    delay(2000);

    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Declares and initialises colours from the Okabe-Ito palette.
  • Pauses for 2 seconds.
  • Closes the window and exits.

Compile and run it with:

skm clang++ playground.c -o playground
./playground

Pixels

A pixel is the smallest visible element displayed on a screen.

When you create a SplashKit window that's 800 pixels wide by 600 pixels in height, imagine it as a grid with 800 columns and 600 rows. Each square (pixel) in this grid can be individually set to display its own colour. By changing the colours of enough pixels, you can form images, shapes, or even patterns on the screen.

The simplest drawing function is:

void draw_pixel(color clr, double x, double y);

This changes the colour of a single pixel at coordinates (x, y).

  • The coordinates (0, 0) represent the pixel at the top-left corner of the window.
  • The x coordinate increases as you move to the right.
  • The y coordinate increases as you move down.

For example, the following snippet demonstrates how you can colour individual pixels using the draw_pixel() function:

draw_pixel(orange, 2, 1);
draw_pixel(sky_blue, 5, 3);
draw_pixel(bluish_green, 0, 5);
refresh_screen();

This snippet colours the pixels at position (2, 1), (5, 3), and (0, 5) orange, sky blue, and blueish-green respectively before calling refresh_screen() to ensure that these changes are displayed on the window.

The image below shows how these pixel changes would appear on a grid representing an 8-by-6 window.

Image of pixels drawn on an 8-by-6 grid

To see how draw_pixel() works, try this program in your playground.c file.

What does the program do if refresh_screen() isn't called? Try it and see!

#include <splashkit.h>

int main(void) {
    open_window("Your Turn: Draw Pixels", 800, 600);

    // draw a pixel at point (x, y) = (583, 168)
    // x = 583 means the pixel is drawn 583 pixels from the left edge
    // y = 168 means the pixel is drawn 168 pixels from the top edge
    draw_pixel(COLOR_BLACK, 583, 168);

    // draw a pixel at point (x, y) = (474, 102)
    // x = 474 means the pixel is drawn 474 pixels from the left edge
    // y = 102 means the pixel is drawn 168 pixels from the top edge
    draw_pixel(COLOR_BLACK, 474, 102);

    // draw two more pixels at (237, 481) and (203, 492)
    draw_pixel(COLOR_BLACK, 237, 481);
    draw_pixel(COLOR_BLACK, 203, 492);

    // draw a pixel at the top-left corner
    draw_pixel(COLOR_BLACK, 0, 0);

    // draw a pixel at the top-right corner
    draw_pixel(COLOR_BLACK, 799, 0);

    // draw a pixel at the bottom-left corner
    draw_pixel(COLOR_BLACK, 0, 599);

    // draw a pixel at the bottom-right corner
    draw_pixel(COLOR_BLACK, 799, 599);

    refresh_screen();

    delay(60000);
    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Draws four pixels at randomly-chosen locations in the window
  • Draws pixels in each corner of the window
  • Pauses for 60 seconds.
  • Closes the window and exits.


Lines

You can draw lines by manually colouring individual pixels one-at-a-time, but this becomes tedious, especially for longer lines. To simplify this process, SplashKit provides a convenient draw_line() function:

void draw_line(color clr, double x1, double y1, double x2, double y2);

This draws a line between two points. The coordinates

  • (x1, y1) represent the pixel where the line begins, and
  • (x2, y2) represent the pixel where the line ends.

To see this in action, here is an example code snippet that draws three lines:

draw_line(yellow, 3, 1, 7, 1);
draw_line(vermillion, 1, 0, 1, 4);
draw_line(reddish_purple, 4, 3, 6, 5);
refresh_screen();

This snippet:

  • Draws a horizontal yellow line from (3, 1) to (7, 1).
  • Draws a vertical vermillion line from (1, 0), to (1, 4).
  • Draws a diagonal reddish-purple line from (4, 3) to (6, 5).

Calling refresh_screen() applies visual changes and displays them on the screen.

The image below illustrates how these three lines appear on a grid representing a small 8-by-6 window.

Image of lines drawn on an 8-by-6 grid

Sometimes you may want to draw lines thicker than the default size. SplashKit provides an additional function to help you do this:

drawing_options option_line_width(int width);

This functions take an integer argument width, representing how many pixels thick you want your lines to be. It returns a new data type called drawing_options which you can then use with an extended version of the draw_line() function:

void draw_line(color clr, double x1, double y1, double x2, double y2, drawing_options opts);

This extended function behaves the same as the original version, but it accepts an additional drawing_options argument.

Here's how you can use these functions together:

drawing_options thick_line = option_line_width(3);
draw_line(blueish_green, 1, 2, 5, 2, thick_line);
refresh_screen();

This snippet:

  • Creates a new drawing_options variable called thick_line which stores a line width of 3 pixels.
  • Passes the thick_line option as an extra argument to draw_line() to draw a line that's 3 pixels thick.
  • Updates the window with refresh_screen() to display the result.

To see how draw_line() and option_line_width() can be used together, run this program in your playground.c file.

What does the program do if the width argument of option_line_width() is set to 0? Try it and see!

#include <splashkit.h>

#define DELAY 2000

int main(void) {
    open_window("Lines", 800, 600);

    color black        = rgb_color(  0,   0,   0);
    color sky_blue     = rgb_color( 86, 180, 233);
    color bluish_green = rgb_color(  0, 158, 115);
    color blue         = rgb_color(  0, 114, 178);
    color vermillion   = rgb_color(213,  94,   0);

    // draw a black diagonal  line from top-left (50, 50) to bottom-right (750, 550)
    draw_line(black, 50,  50, 750, 550);
    refresh_screen();
    delay(DELAY);

    // draw a thick sky_blue horizontal line from (50, 100) to (750, 100)
    // use the extra `option_line_width()` argument to give this line a width of 20 pixels
    draw_line(sky_blue, 50, 100, 750, 100, option_line_width(20));
    refresh_screen();
    delay(DELAY);

    // store line width drawing options in a variable
    // any line drawn with a `medium_width` option will have a width of 6 pixels
    drawing_options medium_width = option_line_width(6);

    // draw three `medium_width` lines
    draw_line(bluish_green, 400, 150, 400, 550, medium_width);
    draw_line(vermillion, 50, 550, 750, 50, medium_width);
    draw_line(blue, 50, 550, 750, 550, medium_width);
    refresh_screen();
    delay(DELAY);

    delay(60000);
    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Declares and initialises colours from the Okabe-Ito palette.
  • Draws a thin black diagonal line.
  • Draws a thick sky blue horizontal line, using option_line_width() to give this line a width of 20 pixels.
  • Stores line drawing options (a line width of 6 pixels) in a variable named medium_width.
  • Draws three more medium-width overlapping lines.
  • Pauses for 60 seconds.
  • Closes the window and exits.
Screenshot of a SplashKit window displaying lines of different widths


Rectangles

SplashKit provides two functions to draw rectangles:

void draw_rectangle(color clr, double x, double y, double width, double height);
void fill_rectangle(color clr, double x, double y, double width, double height);

These functions work as follows:

  • Both functions take (x, y) coordinates to specify the rectangle's top-left corner.
  • The width parameter determines how many pixels wide the rectangle is.
  • The height parameter determines how many pixels tall the rectangle is.
  • The difference between the two functions is:
    • draw_rectangle() draws only the border of the rectangle.
    • fill_rectangle() colours the entire rectangle, filling all pixels in the specified area.

Here's an example code snippet demonstrating these functions:

fill_rectangle(sky_blue, 0, 0, 5, 4);
draw_rectangle(orange, 2, 1, 6, 5);
refresh_screen();

In this snippet:

  • A solid (filled) sky-blue rectangle with its top-left corner at (0, 0) is drawn with a width of 5 pixels and height of 4 pixels.
  • The outline (border) of an orange rectangle with its top-left corner at (2, 1) is drawn with a width of 6 pixels and height of 5 pixels.

Calling refresh_screen() ensures these rectangles become visible.

The image below illustrates how these rectangles would appear if drawn on a 8-by-6 pixel grid.

Image of rectangles drawn on an 8-by-6 grid

To see how draw_rectangle() and fill_rectangle() can be used, run this program in your playground.c file.

What happens if part of a rectangle falls outside of the window? Will it still be drawn? Give it a go and see for yourself!

#include <splashkit.h>

#define DELAY 2000

int main(void) {
    open_window("Rectangles", 800, 600);

    color black        = rgb_color(  0,   0,   0);
    color bluish_green = rgb_color(  0, 158, 115);
    color sky_blue     = rgb_color( 86, 180, 233);
    color orange       = rgb_color(230, 159,   0);
    color yellow       = rgb_color(240, 228,  66);

    // draw the outline of a rectangle at the top-left
    // (x,y) position of top-left corner: (100, 100)
    // width: 250 pixels
    // height: 150 pixels
    draw_rectangle(bluish_green, 100, 100, 250, 150);
    refresh_screen();
    delay(DELAY);

    // fill a rectangle at the top-right
    // (x,y) position of top-left corner: (450, 100)
    // width: 200 pixels
    // height: 200 pixels
    fill_rectangle(sky_blue, 450, 100, 200, 200);
    refresh_screen();
    delay(DELAY);

    // draw a rectangle at the bottom-left
    fill_rectangle(orange, 100, 350, 300, 150);
    // add a border to the previous rectangle
    draw_rectangle(black, 100, 350, 300, 150);
    refresh_screen();
    delay(DELAY);

    // fill two overlapping rectangles at the bottom-right
    fill_rectangle(yellow, 450, 350, 200, 150);
    fill_rectangle(bluish_green, 550, 400, 200, 100);
    refresh_screen();
    delay(DELAY);

    delay(60000);
    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Declares and initialises colours from the Okabe-Ito palette.
  • Draws the outline of a rectangle at the top‑left with draw_rectangle().
  • Fills a rectangle at the top‑right with fill_rectangle().
  • Draws a rectangle (with a black border) at the bottom‑left.
  • Fills two overlapping rectangles at the bottom‑right.
  • Pauses for 60 seconds.
  • Closes the window and exits.
Screenshot of a SplashKit window displaying a series of rectangles


Circles

As with rectangles, SplashKit also provides functions to draw circles:

void draw_circle(color clr, double x, double y, double radius);
void fill_circle(color clr, double x, double y, double radius);

These two functions work as follows:

  • Both functions take (x, y) coordinates to specify the centre (origin) of the circle.
  • The radius parameter controls the size of the circle.
  • The difference between them is:
    • draw_circle() draws only the border/outline of the circle.
    • fill_circle() draws the entire circle, completely filled with colour.

As an example, here's how you could use these functions:

fill_circle(reddish_purple, 4, 4, 4);
draw_circle(blueish_green, 10, 6, 5);
refresh_screen();

In this snippet:

  • A filled reddish-purple circle is drawn with its centre at (4, 4) and a radius of 4 pixels.
  • The outline of a blueish-green circle is drawn with its centre at (10, 6) and a radius of 5 pixels.

To see how draw_circle() and fill_circle() are used, run this program in your playground.c file.

What happens if you change the radius argument of fill_circle()? try it!

#include <splashkit.h>

#define DELAY 2000

int main(void) {
    open_window("Circles", 800, 600);

    color black        = rgb_color(  0,   0,   0);
    color bluish_green = rgb_color(  0, 158, 115);
    color sky_blue     = rgb_color( 86, 180, 233);
    color vermillion   = rgb_color(213,  94,   0);
    color yellow       = rgb_color(240, 228,  66);

    // draw the outline of a circle at the top-left
    // (x, y) position of centre: (250, 150)
    // radius: 80 pixels
    draw_circle(bluish_green, 200, 150,  80);
    refresh_screen();
    delay(DELAY);

    // fill a circle at the top right
    // (x, y) position of centre: (600, 150)
    // radius: 80 pixels
    fill_circle(sky_blue, 600, 150,  80);
    refresh_screen();
    delay(DELAY);

    // draw a circle at the bottom-left
    fill_circle(vermillion, 200, 400, 100);
    // draw a border around the previous circle
    draw_circle(black, 200, 400, 100);
    refresh_screen();
    delay(DELAY);

    // fill two overlapping circles at the bottom-right
    fill_circle(yellow, 600, 400,  80);
    fill_circle(sky_blue, 650, 450,  50);
    refresh_screen();
    delay(DELAY);

    delay(60000);
    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Declares and initialises colours from the Okabe-Ito palette.
  • Draws the outline of a circle at the top‑left with draw_circle().
  • Fills a circle at the top‑right with fill_circle().
  • Draws a circle (with a border) at the bottom‑left.
  • Fills two overlapping circles at the bottom‑right.
  • Pauses for 60 seconds.
  • Closes the window and exits.
Screenshot of a SplashKit window displaying a series of circles


Ellipses

If you need to draw an ellipse (an oval), SplashKit includes:

void draw_ellipse(color clr, double x, double y, double width, double height);
void fill_ellipse(color clr, double x, double y, double width, double height);

Both ellipse functions use the following parameters:

  • (x, y) specifies the centre of the ellipse.
  • width and height define how wide and tall the ellipse is.
  • The difference between the two functions is:
    • draw_ellipse() will only draw the ellipse's outline/border.
    • fill_ellipse() fills the entire ellipse, including its border.

Here's how you can use these functions:

fill_ellipse(sky_blue, 5, 6, 8, 6);
draw_ellipse(orange, 11, 5, 6, 8);
refresh_screen();

In this snippet:

  • A solid (filled) sky-blue ellipse is drawn, centred at (5, 6) with a width and height of 8 and 6 pixels respectively.
  • An orange outline of an ellipse is drawn, centred at (11, 5) with a width and height of 6 and 8 pixels respectively.

To see how draw_ellipse() and fill_ellipse() are used, run this program in your playground.c file.

What happens if the width of an ellipse is negative number? Try it out!

#include <splashkit.h>

#define DELAY 2000

int main(void) {
    open_window("Ellipse", 800, 600);

    color black        = rgb_color(  0,   0,   0);
    color bluish_green = rgb_color(  0, 158, 115);
    color sky_blue     = rgb_color( 86, 180, 233);
    color orange       = rgb_color(230, 159,   0);
    color yellow       = rgb_color(240, 228,  66);

    // draw the outline of an ellipse at the top-left
    // (x,y) position of top-left corner: (100, 100)
    // width: 300 pixels
    // height: 150 pixels
    draw_ellipse(bluish_green, 100, 100, 300, 150);
    refresh_screen();
    delay(DELAY);

    // fill an ellipse at the top-right
    // (x,y) position of top-left corner: (500, 100)
    // width: 200 pixels
    // height: 100 pixels
    fill_ellipse(sky_blue, 500, 100, 200, 100);
    refresh_screen();
    delay(DELAY);

    // draw an ellipse at the bottom-left
    fill_ellipse(orange, 100, 350, 300, 150);
    // add a border around the previous rectangle
    draw_ellipse(black, 100, 350, 300, 150);
    refresh_screen();
    delay(DELAY);

    // fill two overlapping ellipses at the bottom-right
    fill_ellipse(yellow, 450, 300, 250, 120);
    fill_ellipse(sky_blue, 550, 400, 200,  80);
    refresh_screen();
    delay(DELAY);

    delay(60000);
    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Declares and initialises colours from the Okabe-Ito palette.
  • Draws the outline of an ellipse at the top‑left with draw_ellipse().
  • Fills an ellipse at the top‑right with fill_ellipse().
  • Draws an ellipse (with a border) at the bottom‑left.
  • Fills two overlapping ellipses at the bottom‑right.
  • Pauses for 60 seconds.
  • Closes the window and exits.
Screenshot of a SplashKit window displaying a series of ellipses


Triangles

And in case you need to draw triangles, SplashKit offers two functions to do this:

void draw_triangle(color clr, double x1, double y1, double x2, double y2, double x3, double y3);
void fill_triangle(color clr, double x1, double y1, double x2, double y2, double x3, double y3);

Both triangle-drawing functions require coordinates for the three corners of the triangle:

  • (x1, y1), (x2, y2), and (x3, y3) are the coordinates for the triangle's three vertices (corners).
  • The difference between the two functions is, as before:
    • draw_triangle() draws only the outline/border of a triangle.
    • fill_triangle() fills-in the entire area within a triangle.

The following example shows how these functions can be used:

fill_triangle(sky_blue, 2, 2, 2, 9, 7, 6);
draw_triangle(orange, 9, 2, 14, 4, 12, 9);
refresh_screen();

In this snippet:

  • A filled sky-blue triangle is drawn with vertices (2, 2), (2, 9), and (7, 6).
  • The outline of an orange triangle is drawn with vertices (9, 2), (14, 4), and (12, 9).

To see how draw_triangle() and fill_triangle() are used, run this program in your playground.c file.

#include <splashkit.h>

#define DELAY 2000

int main(void) {
    open_window("Triangles", 800, 600);

    color black          = rgb_color(  0,   0,   0);
    color bluish_green   = rgb_color(  0, 158, 115);
    color sky_blue       = rgb_color( 86, 180, 233);
    color orange         = rgb_color(230, 159,   0);
    color reddish_purple = rgb_color(204, 121, 167);

    // draw the outline of an equilateral triangle at the top-left
    draw_triangle(bluish_green,
                  100, 150,
                  175,  50,
                  250, 150);
    refresh_screen();
    delay(DELAY);

    // fill a right-angled triangle at the upper-right
    fill_triangle(sky_blue,
                  500, 150,
                  700, 150,
                  500, 350);
    refresh_screen();
    delay(DELAY);

    // draw an obtuse triangle (with a border) at the bottom left
    fill_triangle(orange,
                  100, 400,
                  350, 350,
                  400, 500);
    draw_triangle(black,
                  100, 400,
                  350, 350,
                  400, 500);
    refresh_screen();
    delay(DELAY);

    // fill two overlapping triangles at the bottom-right
    fill_triangle(reddish_purple,
                  500, 400,
                  600, 550,
                  650, 420);
    fill_triangle(sky_blue,
                  600, 380,
                  750, 400,
                  650, 550);
    refresh_screen();
    delay(DELAY);

    delay(60000);
    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Declares and initialises colours from the Okabe-Ito palette.
  • Draws the outline of an equilateral triangle at the top‑left with draw_triangle().
  • Fills a right‑angled triangle at the upper‑right with fill_triangle().
  • Draws an obtuse triangle (with a border) at the bottom‑left (using fill_triangle() then draw_triangle()).
  • Fill two overlapping triangles at the bottom‑right with fill_triangle() and fill_triangle().
  • Pauses for 60 seconds.
  • Closes the window and exits.
Screenshot of a SplashKit window displaying a series of triangles


Transparent Shapes

Up until now, we've used rgb_color() to define colours by mixing red, green, and blue. These colours are "opaque", meaning that shapes drawn on top will completely hide anything beneath them.

SplashKit provides another function that allows you to define colours with transparency:

color rgba_color(int red, int green, int blue, int alpha);

  • The parameters red, green, and blue behave the same as with rgb_color(), ranging from 0 (no colour) to 255 (maximum intensity).
  • The alpha parameter controls transparency:
    • 0 means "fully transparent". Shapes drawn with this colour will be completely invisible.
    • 255 means "fully opaque". Shapes drawn with this colour will be solid and not see-through at all.
    • Values between 0 and 255 represent varying degrees of transparency.

This example demonstrates how transparent colours are used to draw overlapping shapes:

fill_rectangle(sky_blue, 2, 2, 8, 6);
color transparent_orange = rgba_color(230, 159, 0, 128);
fill_rectangle(transparent_orange, 6, 4, 8, 6);
refresh_screen();

In this snippet:

  • A sky-blue rectangle is drawn.
  • A transparent orange colour is defined with an alpha value of 128. This alpha value is halfway between 0 and 255, representing a transparency of 50%.
  • A second rectangle using this transparent orange colour is drawn, partially overlapping the first rectangle. Due to the transparency of the second rectangle, the overlapped section of the first rectangle remains partially visible.

To see how rgba_color() can create transparent shapes, test this program in your playground.c file.

What does the program do if the alpha values in rgba_color() are changed from 180 to 255? Try it and see!

#include <splashkit.h>

#define DELAY 2000

int main(void) {
    open_window("Transparency", 800, 600);

    // declare semi‑transparent colours
    // each of these colours has an "alpha" opacity value of 180/255
    color transparent_orange       = rgba_color(230, 159,   0, 180);
    color transparent_sky_blue     = rgba_color( 86, 180, 233, 180);
    color transparent_bluish_green = rgba_color(  0, 158, 115, 180);
    color transparent_vermilion    = rgba_color(213,  94,   0, 180);

    // fill a rectangle
    fill_rectangle(transparent_orange, 100, 100, 400, 300);
    refresh_screen();
    delay(DELAY);

    // fill a transparent circle overlapping the rectangle
    fill_circle(transparent_sky_blue, 500, 200, 180);
    refresh_screen();
    delay(DELAY);

    // fill a transparent ellipse overlapping the rectangle and circle
    fill_ellipse(transparent_bluish_green, 350, 350, 350, 200);
    refresh_screen();
    delay(DELAY);

    // fill a transparent triangle overlapping all shapes
    fill_triangle(transparent_vermilion, 200, 450, 450, 150, 700, 450);
    refresh_screen();
    delay(DELAY);

    delay(60000);
    close_all_windows();
    return 0;
}

This program:

  • Opens a window with a default (white) background.
  • Declare semi‑transparent colours using rgba_color().
  • Fills a transparent rectangle.
  • Fills a transparent circle overlapping the rectangle.
  • Fills a transparent ellipse overlapping the rectangle and the circle.
  • Fills a transparent triangle overlapping all shapes.
  • Pauses for 60 seconds.
  • Closes the window and exits.
Screenshot of a SplashKit window displaying a series of transparent overlapping shapes


Activity 1 of 2

Create a program splashkit_drawing_part1.c. It should:

  • Open a window 800 pixels wide and 600 pixels in height.
  • Draw a simple house from basic shapes similar to the image below.
  • Keep the window open for 10 seconds.
  • Close the window and exit.
Screenshot of a basic house

Examples

skm clang++ splashkit_drawing_part1.c -o splashkit_drawing_part1
./splashkit_drawing_part1

When the program runs, a window should appear, displaying a simple house for 10 seconds before closing.

Screenshot of a SplashKit window (width=960px, height=360px) with a basic house

Assumptions/Restrictions/Clarifications

  • There are no autotests for this activity.

Activity 2 of 2:

Create a program splashkit_drawing_part2.c. It should:

  • Open a window 800 pixels wide and 600 pixels in height.
  • Draw the impossible object as shown below.
  • Keep the window open for 10 seconds.
  • Close the window and exit.
Screenshot of an impossible shape

Examples

skm clang++ splashkit_drawing_part2.c -o splashkit_drawing_part2
./splashkit_drawing_part2

When the program runs, a window should appear, displaying the impossible object for 10 seconds before closing.

Screenshot of a SplashKit window (width=960px, height=360px) with an impossible shape

Assumptions/Restrictions/Clarifications

  • There are no autotests for this activity.

Summary

In this activity, you learned how to work with functions to draw and fill shapes such as:

  • Pixels.
  • Lines.
  • Rectangles.
  • Circles.
  • Ellipses.
  • Triangles.

You also learned how to define transparent colours to draw see-through shapes.

Types and Functions

// Colours
color rgba_color(int red, int green, int blue, int alpha);

// Drawing
void draw_pixel(color clr, double x, double y);
void draw_line(color clr, double x1, double y1, double x2, double y2);
drawing_options option_line_width(int width);
void draw_line(color clr, double x1, double y1, double x2, double y2, drawing_options opts);
void draw_rectangle(color clr, double x, double y, double width, double height);
void fill_rectangle(color clr, double x, double y, double width, double height);
void draw_circle(color clr, double x, double y, double radius);
void fill_circle(color clr, double x, double y, double radius);
void draw_ellipse(color clr, double x, double y, double width, double height);
void fill_ellipse(color clr, double x, double y, double width, double height);
void draw_triangle(color clr, double x1, double y1, double x2, double y2, double x3, double y3);
void fill_triangle(color clr, double x1, double y1, double x2, double y2, double x3, double y3);

// Window Management
window open_window(string caption, int width, int height);
void close_all_windows(void);

// Program Control
void delay(int milliseconds);

// Screen Management
void clear_screen(color clr);
void refresh_screen(void);

// Colours
color rgb_color(int red, int green, int blue);
color rgba_color(int red, int green, int blue, int alpha);

// Okabe-Ito Accessible Colour Palette
color black          = rgb_color(  0,   0,   0);
color orange         = rgb_color(230, 159,   0);
color sky_blue       = rgb_color( 86, 180, 233);
color bluish_green   = rgb_color(  0, 158, 115);
color yellow         = rgb_color(240, 228,  66);
color blue           = rgb_color(  0, 114, 178);
color vermillion     = rgb_color(213,  94,   0);
color reddish_purple = rgb_color(204, 121, 167);

// Drawing
void draw_pixel(color clr, double x, double y);
void draw_line(color clr, double x1, double y1, double x2, double y2);
drawing_options option_line_width(int width);
void draw_line(color clr, double x1, double y1, double x2, double y2, drawing_options opts);
void draw_rectangle(color clr, double x, double y, double width, double height);
void fill_rectangle(color clr, double x, double y, double width, double height);
void draw_circle(color clr, double x, double y, double radius);
void fill_circle(color clr, double x, double y, double radius);
void draw_ellipse(color clr, double x, double y, double width, double height);
void fill_ellipse(color clr, double x, double y, double width, double height);
void draw_triangle(color clr, double x1, double y1, double x2, double y2, double x3, double y3);
void fill_triangle(color clr, double x1, double y1, double x2, double y2, double x3, double y3);




Submission

When you are finished each exercises make sure you submit your work by running give.

You can run give multiple times. Only your last submission will be marked.

Don't submit any exercises you haven't attempted.

If you are working at home, you may find it more convenient to upload your work via give's web interface.

Remember you have until Week 4 Tuesday 18:00 to submit your work.

You cannot obtain marks by e-mailing your code to tutors or lecturers.

You check the files you have submitted here.

Automarking will be run by the lecturer several days after the submission deadline, using test cases different to those autotest runs for you. (Hint: do your own testing as well as running autotest.)

After automarking is run by the lecturer you can view your results here. The resulting mark will also be available via give's web interface.