Programming Fundamentals

Objectives

  • using arrays
  • using struct arrays
  • creating functions
  • using while loops for repetition

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:

  • devowel
  • print_pi_style
  • scanning_into_array_style
  • points

Worth 1 mark(s) in total:

  • savings_analysis
  • cs_calculator

Worth 0.5 mark(s) in total:

  • detective
  • rewrite_letters

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
(●◌◌)
:

Devowelling Text

Write a C program devowel.c which reads characters from its input and writes the same characters to its output, except it does not write lower case vowels ('a', 'e', 'i', 'o', 'u').

Your program should stop only at the end of input.

Examples

dcc devowel.c -o devowel
./devowel
Are you saying 'Boo' or 'Boo-Urns'?
Ar y syng 'B' r 'B-Urns'?
In this house, we obey the laws of thermodynamics!
In ths hs, w by th lws f thrmdynmcs!

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

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

1511 autotest devowel

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

give cs1511 lab04_devowel devowel.c

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

Sample solution for devowel.c
//  Written 3/3/2018 by Andrew Taylor (andrewt@unsw.edu.au)
//  read characters from stdin and write to stdout
//  except lower case vowels ('a', 'e','i', 'o', 'u') are not written

#include <stdio.h>

int is_vowel(char character);

int main(void) {

    char character;
    while (scanf("%c", &character) == 1) {

        if (!is_vowel(character)) {
            printf("%c", character);
        }
    }

    return 0;
}

// return 1 if character is a lower case vowel
// 0 otherwise
int is_vowel(char character) {
    return character == 'a' ||
           character == 'e' ||
           character == 'i' ||
           character == 'o' ||
           character == 'u';
}

Exercise
(●◌◌)
:

Print out pi to a certain number of digits

Good code style is required for this exercise.

To get full marks in this exercise, you MUST pass the automatic style checker (1511 style).

If 1511 style finds any issues in your code, the maximum mark you can achieve for this exercise is capped at 75%.

To run the automatic style checker on your code, use the following command:

1511 style print_pi_style.c

Download print_pi_style.c here

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

1511 fetch-activity print_pi_style

Your task is to add code to these functions in print_pi_style.c:

void print_pi_style(int num_digits) {
    // DO NOT CHANGE THIS LINE
    int pi[MAX_DIGITS] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
    // TODO: Finish this function below

}

Write a C program, print_pi_style.c, which prints out the first n digits of pi, where n is specified by the user.

The main function has already been written for you. There's an empty function that has been provided for you called print_pi_style that takes in one integer as an argument.

Place your code (only the printing code) inside this function. You can NOT put all of your code in main for this exercise, main must remain unmodified.

Examples

dcc print_pi_style.c -o print_pi_style
./print_pi_style
How many digits of pi would you like to print? 3
3.14
./print_pi_style
How many digits of pi would you like to print? 5
3.1415
./print_pi_style
How many digits of pi would you like to print? 10
3.141592653

Assumptions/Restrictions/Clarifications

  • You can assume that n >= 2 AND n <= 10, however, do not use this as a reason to avoid while loops.
You can run an automated code style checker using the following command:
1511 style print_pi_style.c

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

1511 autotest print_pi_style

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

give cs1511 lab04_print_pi_style print_pi_style.c

You must run give before Monday 17 March 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 print_pi_style.c
//Prints the first n digits of pi, where n is specified
// by the user
// Liz Willer
// (fake zID: z5255555)
// 2020-03-07

#include <stdio.h>

#define MAX_DIGITS 10

void print_pi_style(int num_digits);

int main(void) {
    printf("How many digits of pi would you like to print? ");
    // TODO: Insert your code here to read in digits
    int digits;
    scanf("%d", &digits);
    // TODO: Call the print_pi_style function you finished
    print_pi_style(digits);

    return 0;
}

void print_pi_style(int num_digits) {
    // DO NOT CHANGE THIS LINE
    int pi[MAX_DIGITS] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
    // TODO: Finish this function below
    int i = 0;
    while (i < num_digits) {
        if (i == 1) {
            printf(".");
        }
        printf("%d", pi[i]);
        i++;
    }
    printf("\n");
}

Exercise
(●◌◌)
:

Scanning numbers into an array

Good code style is required for this exercise.

To get full marks in this exercise, you MUST pass the automatic style checker (1511 style).

If 1511 style finds any issues in your code, the maximum mark you can achieve for this exercise is capped at 75%.

To run the automatic style checker on your code, use the following command:

1511 style scanning_into_array_style.c

Download scanning_into_array_style.c here

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

1511 fetch-activity scanning_into_array_style

Write a C program scanning_into_array_style.c which scans in a certain amount of numbers from the user and fills an array with them.

  • First, it scans in the quantity of numbers from the user.
  • Then, it scans in that many numbers from the user.

Once the array is filled with the numbers the user input, call a pre-written function that prints the minimum and maximum values in that array

Examples

dcc scanning_into_array_style.c -o scanning_into_array_style
./scanning_into_array_style
How many numbers: 5
Please enter numbers: 1
2
3
4
5
Minimum: 1
Maximum: 5
./scanning_into_array_style
How many numbers: 4
Please enter numbers: 3
-2
7
1
Minimum: -2
Maximum: 7

Assumptions/Restrictions/Clarifications

  • The given inputs will always be integers.
  • The given list of numbers will never be more than 100 numbers.
You can run an automated code style checker using the following command:
1511 style scanning_into_array_style.c

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

1511 autotest scanning_into_array_style

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

give cs1511 lab04_scanning_into_array_style scanning_into_array_style.c

You must run give before Monday 17 March 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 scanning_into_array_style.c
// 
// Written 5th March 2022
// By William Setiawan
// (fake zID: z5255555)
// Program which scans a certain number of integers into an array, then prints
// the minimum and maximum values in the array.
//

#include <stdio.h>

#define MAX_SIZE 100

// Given an integer array, iterate over the array and print the minimum and
// maximum values in the array.
void print_array_minmax(int length, int arr[MAX_SIZE]);

int main(void) {
    int scanned_length;
    int length_count = 0;
    int scanned_value;
    int scanned_num[MAX_SIZE];

    // Prompts user for the specific number of integers to be taken from input
    printf("How many numbers: ");
    scanf("%d", &scanned_length);

    // Only takes in scanned_length number of integers
    printf("Please enter numbers: ");
    while (length_count < scanned_length) {
        scanf("%d", &scanned_value);
        scanned_num[length_count] = scanned_value;

        length_count++;
    }
    
    // Print the minimum and maximum values
    print_array_minmax(scanned_length, scanned_num);

    return 0;
}

//////////////////////// DO NOT CHANGE THE CODE BELOW! ////////////////////////

// Given an integer array, iterate over the array and print the minimum and
// maximum values in the array.
//
// Takes in:
// - `length` -- The length of the array.
// - `arr[MAX_SIZE]` -- The integer array to iterate over.
//
// Returns: nothing.
void print_array_minmax(int length, int arr[MAX_SIZE]) {
    int index = 0;
    if (length > 0) {
        int minimum = arr[index];
        int maximum = arr[index];

        while (index < length) {
            if (arr[index] < minimum) {
                minimum = arr[index];
            } else if (arr[index] > maximum) {
                maximum = arr[index];
            }
            
            index++;
        }

        printf("Minimum: %d\nMaximum: %d\n", minimum, maximum);
    }
    
    return;
}

Exercise
(●◌◌)
:

Using struct arrays to store points of a shape

Download points.c here

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

1511 fetch-activity points

Complete the C program points.c, so that it scans in all the points of a shape into an array of structs. It should then print out the points that were given.

First, it scans in the number of points that the shape has. Then, it scans in the coordinates of each point. Afterwards, it prints out the points in order.

Examples

dcc points.c -o points
./points
How many points in the shape? 2
Enter points:
1.231 4.560
7.892 0.12

Shape Points:
 1: x = 1.231, y = 4.560
 2: x = 7.892, y = 0.120
./points
How many points in the shape? 4
Enter points:
6.340 2.781
5.675 2.453
4.893 0.123
0.232 3.349

Shape Points:
 1: x = 6.340, y = 2.781
 2: x = 5.675, y = 2.453
 3: x = 4.893, y = 0.123
 4: x = 0.232, y = 3.349

Assumptions/Restrictions/Clarifications

  • When asked for the number of points, you will be given a non-zero positive integer.
  • All inputs will be the correct type and non-zero positive numbers.
  • The number of points will not exceed 10.
You can run an automated code style checker using the following command:
1511 style points.c

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

1511 autotest points

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

give cs1511 lab04_points points.c

You must run give before Monday 17 March 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 points.c
// points.c SOLUTION
// Written 17 June 2023
// By Gab Steiner
//
// This is a c program that scans in points belonging to a shape in a random
// order, then prints them out in the correct order.

#include <stdio.h>

#define MAX_POINTS 10

struct point {
    double x_coord;
    double y_coord;
};


// Prints a point out.
void print_point(int point_no, double x, double y);

int main(void) {

    // Declare an array of points of size MAX_POINTS
    struct point shape[MAX_POINTS];

    printf("How many points in the shape? ");
    // scan in number of points in the shape
    int no_points;
    scanf("%d", &no_points);

    printf("Enter points:\n");
    // scan in the details of each point into the array
    int index = 0;
    while (index < no_points) {
        
        scanf("%lf", &shape[index].x_coord);        // scan the x_coord
        scanf("%lf", &shape[index].y_coord);        // scan the y_coord
        
        index = index + 1;
    }

    printf("\nShape Points:\n");
    // print all the points

    // Go through all the points and print them
    for (int count = 0; count < no_points; count++) {
        print_point(count + 1, shape[count].x_coord, shape[count].y_coord);
    }

    return 0;
}


//  Prints a single point in the correct format.
//
// Parameters:
// - `point_no` -- The point number
// - `x`        -- The x-coordinate of the point
// - `y`        -- The y-coordinate of the point
//
// Returns: nothing.
void print_point(int point_no, double x, double y) {
    
    printf("%2d: x = %.3lf, y = %.3lf\n", point_no, x, y);
}

Exercise
(●●◌)
:

Savings Analysis

Download savings_analysis.c here

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

1511 fetch-activity savings_analysis

You have been provided with some starter code savings_analysis.c with functions for you to complete: calc_yearly_deposits, calc_yearly_spending, calc_ending_balance and calc_months_saving_goal_met. It is your job to implement the functions and complete the program.

The program reads in the user's starting balance and monthly saving goal for the year. This is followed by 12 months of deposits and 12 months of spending. The program then runs a series of functions to analyse the account over the year. It is your job to complete these functions.

Examples

dcc savings_analysis.c -o savings_analysis
./savings_analysis
Please enter starting balance: 1320 
Please enter monthly saving goal: 60      
Please enter monthly deposits: 208 234 182 182 208 156 156 182 208 208 234 260
Please enter monthly spending: 120 103 150 122 130 372 106 115 127 124 104 200

Yearly deposits = $2418
Yearly spending = $1773
Ending balance  = $1965
You met the monthly saving goal 9 times!
./savings_analysis
Please enter starting balance: 500
Please enter monthly saving goal: 220
Please enter monthly deposits: 800 850 900 870 820 880 890 830 910 850 860 840
Please enter monthly spending: 600 620 610 630 640 615 610 625 600 630 635 670

Yearly deposits = $10300
Yearly spending = $7485
Ending balance  = $3315
You met the monthly saving goal 8 times!

Assumptions/Restrictions/Clarifications

  • The function names in your solution should be the same as the provided starter code.
  • Numbers entered will always be positive integers.
  • The correct amount of input will always be provided. That is, the number of monthly deposits and monthly spending will always be 12.
  • You must implement the functions specified to pass the autotests and receive marks for this activity.
You can run an automated code style checker using the following command:
1511 style savings_analysis.c

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

1511 autotest savings_analysis

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

give cs1511 lab04_savings_analysis savings_analysis.c

You must run give before Monday 17 March 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 savings_analysis.c
// Savings Analysis
// savings_analysis.c
//
// This program was written by Morgan Swaak (z5476300)
// on 03/02/24
//
// A program to do analysis on a savings account.

#include <stdio.h>

#define NUM_MONTHS 12

struct transaction {
    int deposits;
    int spending;
};

int calc_yearly_deposits(struct transaction transactions[NUM_MONTHS]);
int calc_yearly_spending(struct transaction transactions[NUM_MONTHS]);
int calc_ending_balance(int starting_balance, struct transaction transactions[NUM_MONTHS]);
int calc_months_saving_goal_met(int saving_goal, struct transaction transactions[NUM_MONTHS]);

// main funciton initalises transactions array and prints results
int main(void) {
    // array initalisation
    int starting_balance;
    int saving_goal;
    struct transaction transactions[NUM_MONTHS]; 
    printf("Please enter starting balance: ");
    scanf("%d", &starting_balance);
    printf("Please enter monthly saving goal: ");
    scanf("%d", &saving_goal);
    printf("Please enter monthly deposits: ");
    int i = 0;
    while (i < NUM_MONTHS) {
        scanf("%d", &transactions[i].deposits);
        i++;
    }
    printf("Please enter monthly spending: ");
    i = 0;
    while (i < NUM_MONTHS) {
        scanf("%d", &transactions[i].spending);
        i++;
    }

    // print out analysis
    int yearly_deposits = calc_yearly_deposits(transactions);
    int yearly_spending = calc_yearly_spending(transactions);
    int ending_balance = calc_ending_balance(starting_balance, transactions);
    int num_months = calc_months_saving_goal_met(saving_goal, transactions);

    printf("\n");
    printf("Yearly deposits = $%d\n", yearly_deposits);
    printf("Yearly spending = $%d\n", yearly_spending);
    printf("Ending balance  = $%d\n", ending_balance);
    printf("You met the monthly saving goal %d times!\n", num_months);
    return 0;
}

// calculates and returns the total amount of money deposited
int calc_yearly_deposits(struct transaction transactions[NUM_MONTHS]) {
    int yearly_deposits = 0;
    int i = 0;
    while (i < NUM_MONTHS) {
        yearly_deposits += transactions[i].deposits;
        i++;
    }
    return yearly_deposits;
}

// calculates and returns the total amount of money spent
int calc_yearly_spending(struct transaction transactions[NUM_MONTHS]) {
    int yearly_spending = 0;
    int i = 0;
    while (i < NUM_MONTHS) {
        yearly_spending += transactions[i].spending;
        i++;
    }
    return yearly_spending;
}

// calculates and returns the ending balance of an account
int calc_ending_balance(
    int starting_balance, 
    struct transaction transactions[NUM_MONTHS]
) {
    return starting_balance + calc_yearly_deposits(transactions) - calc_yearly_spending(transactions);
}

// returns the the number of months the saving goal was met
int calc_months_saving_goal_met(
    int saving_goal, 
    struct transaction transactions[NUM_MONTHS]
) {
    int num_months = 0;
    int i = 0;
    while (i < NUM_MONTHS) {
        if (transactions[i].deposits - transactions[i].spending >= saving_goal) {
            num_months += 1;
        }
        i++;
    }
    return num_months;
}

Exercise
(●●◌)
:

Create a simple calculator, reading different numbers of integers

For this exercise, make a program called cs_calculator.c which will scan in instructions until End-Of-Input (which we enter to our terminal with the keyboard shortcut CTRL-D) and prints the output as specified below. An instruction is a character, followed by one or two positive integers.

The first character identifies what type the instruction is.

  • If the first character in the instruction is 's', then your program should print out the square of the next number in the instruction.
  • If the first character in the instruction is 'p', then your program should print out the value of the next number raised to the power of the number after next.

Examples

dcc cs_calculator.c -o cs_calculator
./cs_calculator
Enter instruction: s 2
4
Enter instruction: p 5 3
125
Enter instruction: s 4
16
Enter instruction: p 3 4
81
Enter instruction: 
./cs_calculator
Enter instruction: p 3 3
27
Enter instruction: s 10
100
Enter instruction: 

One major challenge of this exercise is figuring out how to use scanf effectively. The lessons you learn in this exercise regarding scanf will be useful in assignment 1!

Assumptions/Restrictions/Clarifications

  • You can assume that the first character in the instruction is only either 's' or 'p'
  • You can assume that for each instruction, the correct number of successive positive integers will be given.
  • The autotest for this exercise expects your program to end WITHOUT a new line character when the user presses Ctrl-D. This means that the command prompt for the next command should be on the same line as the end of your program.
You can run an automated code style checker using the following command:
1511 style cs_calculator.c

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

1511 autotest cs_calculator

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

give cs1511 lab04_cs_calculator cs_calculator.c

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

Sample solution for cs_calculator.c
// Author: Dean Wunder
// d.wunder@unsw.edu.au
// 2020-05-04
// A arbitrary calculator app designed to help students
// understand variable length input scanning before assignment 1.

#include <stdio.h>

#define SQUARE_COMMAND 's'
#define POWER_COMMAND  'p'

int main (void) {

    char command;
    printf("Enter instruction: ");
    while (scanf(" %c", &command) == 1) {
        if (command == SQUARE_COMMAND) {
            int num;
            scanf("%d", &num);
            printf("%d\n", num * num);
        } else if (command == POWER_COMMAND) {
            int base, power;
            scanf("%d %d", &base, &power);
            int i = 0;
            int result = 1;
            while (i < power) {
                result *= base;
                i++;
            }
            printf("%d\n", result);
        }
        printf("Enter instruction: ");
    }

    return 0;
}

Exercise
(●●●)
:

Detective

Download detective.c here

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

1511 fetch-activity detective

Your mission (if you choose to accept it) is to complete the program detective.c to decipher encoded messages.

Over the past few months UNSW Security Society has found seemingly normal messages paired with random numbers. To help you solve this challenge we have created the program detective.c that reads in the message and numbers, storing them in a struct array.

We have been lucky enough to find one decoded message:

Encoded Message: muahahaha_we're_so_evil#_GNTY

Secret Numbers: 7-23-3-6-13-22-24-2-16-4-14-18-20-11-9-28-21-1-27-8-0-26-12-5-10-15-25-19-17

Deciphered Message: haha_we_are_TeasiNG_You

Our observations from this are:

  • Messages seem to end with a #.
  • There are always the same number of letters as there are numbers.
  • Letters maintain their case between their encoded and deciphered message.
  • Each number is unique counting from 0 to n - 1 (where n is the number of letters).

We wish you luck detective!

Examples

dcc detective.c -o detective
./detective
Please enter Encrypted Message: muahahaha_we're_so_evil#_GNTY
Please enter Secret Numbers: 7-23-3-6-13-22-24-2-16-4-14-18-20-11-9-28-21-1-27-8-0-26-12-5-10-15-25-19-17
Secret Message is: haha_we_are_TeasiNG_You
./detective
Please enter Encrypted Message: STUDENTS_L0VE_COMP1511_#new_students_aww_:)
Please enter Secret Numbers: 28-12-24-38-6-33-36-27-16-7-19-17-39-2-11-14-32-31-41-23-18-15-0-21-35-9-40-20-1-30-5-42-4-25-13-26-37-34-22-8-29-10-3
Secret Message is: sTEw_MeET_at_Unsw_tuNneLS_11:05

Assumptions/Restrictions/Clarifications

  • The maximum number of characters is 100.
  • The number of characters in the encrypted message and the amount of secret numbers are the same.
  • The case of each letter is preserved in translation.
  • Messages will end with a #.
You can run an automated code style checker using the following command:
1511 style detective.c

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

1511 autotest detective

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

give cs1511 lab04_detective detective.c

You must run give before Monday 17 March 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 detective.c
// Detective
// detective.c
//
// This program was written by Morgan Swaak (z5476300)
// on 02/02/24
//
// A program to decipher hidden messages in enemy codes.

#include <stdio.h>

#define MAX_SIZE 100

struct code {
    char letter;
    int number;
};

int main(void) {
    //////////////// DO NOT CHANGE ANY OF THE CODE BELOW HERE //////////////////
    struct code message[MAX_SIZE];

    // read in message
    printf("Please enter Encrypted Message: ");
    int i = 0;
    char letter;
    scanf("%c", &letter);
    while(letter != '\n') {
        message[i].letter = letter;
        scanf("%c", &letter);
        i++;
    }

    // read in numbers
    printf("Please enter Secret Numbers: ");
    int j = 0;
    int number;
    scanf("%d", &number);
    message[j].number = number;
    j++;
    while (j != i) {
        scanf("-%d", &number);
        message[j].number = number;
        j++;
    }
    //////////////// DO NOT CHANGE ANY OF THE CODE ABOVE HERE //////////////////

    ////////////////////////////////////////////////////////////////////////////
    ///////////////////// ONLY WRITE CODE BELOW HERE ///////////////////////////
    ////////////////////////////////////////////////////////////////////////////

    printf("Secret Message is: ");

    int index = message[0].number;
    while (message[index].letter != '#') {
        printf("%c", message[index].letter);
        index = message[index].number;
    }
    printf("\n");

    ////////////////////////////////////////////////////////////////////////////
    ///////////////////// ONLY WRITE CODE ABOVE HERE ///////////////////////////
    ////////////////////////////////////////////////////////////////////////////
    return 0;
}

Exercise
(●●●)
:

Rewrite Letters

Download rewrite_letters.c here

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

1511 fetch-activity rewrite_letters

A sequence of characters can be rewritten by replacing a chosen character with a rewriting rule. For example, the sequence of characters "This is X" can be rewritten by replacing character 'X' with rewriting rule "COMP1511" to yield "This is COMP1511".

Rewriting can also be done with more than one character at a time. For example, the sequence of characters "All X are Y" can be rewritten by replacing X with "squares" and Y with "rectangles" to yield "All squares are rectangles".

Task

Write a C program rewrite_letters.c that rewrites an initial sequence of letters by replacing specified characters based on user-defined rules.

The program should:

  1. Prompt for an initial sequence of characters.
  2. Read the first character to replace.
  3. Read the rewriting rule to replace the first character.
  4. Read the second character to replace.
  5. Read the rewriting rule to replace the second character.
  6. Apply the rewriting rules to the initial sequence, replacing all instances of the letters to be rewritten with their replacement rule.
  7. Output the rewritten result.

Examples

dcc rewrite_letters.c -o rewrite_letters
./rewrite_letters
Initial letters: All @ must gather at the # immediately.
1st letter to be rewritten: @
1st rewriting rule: ninjas
2nd letter to be rewritten: #
2nd rewriting rule: chocolate fountain
All ninjas must gather at the chocolate fountain immediately.
./rewrite_letters
Initial letters: aba
1st letter to be rewritten: a
1st rewriting rule: xx
2nd letter to be rewritten: b
2nd rewriting rule: yyy
xxyyyxx
./rewrite_letters
Initial letters: How much X would a XY Y if a XY could Y X?
1st letter to be rewritten: X
1st rewriting rule: wood
2nd letter to be rewritten: Y
2nd rewriting rule: chuck
How much wood would a woodchuck chuck if a woodchuck could chuck wood?
./rewrite_letters
Initial letters: 143 = (m + n) * (m - n)
1st letter to be rewritten: m
1st rewriting rule: 12
2nd letter to be rewritten: n
2nd rewriting rule: 1
143 = (12 + 1) * (12 - 1)

Assumptions/Restrictions/Clarifications

  • The following will contain 1024 characters or less:
    • The sequence of initial letters.
    • The rewriting rules.
    • The final rewritten result.
  • The letters to be rewritten will always be input by the user.
  • The letters to be rewritten will be unique. For example:
    • If the first letter to be rewritten is an 'a' then the second letter to be rewritten will be a letter other than 'a'.
  • The rewriting rules will always be input by the user.
  • Your program must be able to handle all printable ASCII characters (decimal codes 32 to 126). This excludes any control characters (from 0 to 31) and the delete character (127).
You can run an automated code style checker using the following command:
1511 style rewrite_letters.c

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

1511 autotest rewrite_letters

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

give cs1511 lab04_rewrite_letters rewrite_letters.c

You must run give before Monday 17 March 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 rewrite_letters.c
// Rewrite Letters
// rewrite_letters.c
//
// This program was written by Andrew Polak (fake zid z9999999)
// on 12-Jan-2025.
//
// A program which reads in an array of initial letters, then rewrites each
// occurrence of two chosen letters with corresponding sequences of letters.
//
// Example:
// 
// $ ./rewrite_letters
// Initial letters: All X are Y, but not all Y are X.
// 1st letter to be rewritten: X
// 1st rewriting rule: cats
// 2nd letter to be rewritten: Y
// 2nd rewriting rule: gravity-testers who push things off tables
// All cats are gravity-testers who push things off tables, but not all
//   gravity-testers who push things off tables are cats.
//


#include <stdio.h>

#define MAX_LENGTH 1024

////////////////////////////////////////////////////////////////////////////////
// Function Prototypes
////////////////////////////////////////////////////////////////////////////////

int scan_char_array(char array[MAX_LENGTH]);

////////////////////////////////////////////////////////////////////////////////
// Main Function
////////////////////////////////////////////////////////////////////////////////

int main(void) {
    // scan the initial letters into an array & keep track of how many there are
    printf("Initial letters: ");
    char initial_letters[MAX_LENGTH];
    int num_of_initial_chars = scan_char_array(initial_letters);

    // get the first letter to be replaced/rewritten
    printf("1st letter to be rewritten: ");
    char letter_1;
    scanf("%c", &letter_1);

    // scan the first rewriting rule into an array & keep track of its length
    printf("1st rewriting rule: ");
    char rule_1[MAX_LENGTH];
    int rule_1_length = scan_char_array(rule_1);

    // get the second letter to be replaced/rewritten
    printf("2nd letter to be rewritten: ");
    char letter_2;
    scanf("%c", &letter_2);

    // scan the second rewriting rule into an array & keep track of its length
    printf("2nd rewriting rule: ");
    char rule_2[MAX_LENGTH];
    int rule_2_length = scan_char_array(rule_2);

    // print out the initial letters, but with every 'letter_to_be_written'
    // replaced by the letters in the rewriting rule
    int i = 0;
    while (i < num_of_initial_chars) {
        if (initial_letters[i] == letter_1) {
            // write rule_1 instead of letter_1
            for (int rule_index = 0; rule_index < rule_1_length; rule_index++) {
                printf("%c", rule_1[rule_index]);
            }
        } else if (initial_letters[i] == letter_2) {
            // write rule_2 instead of letter_2
            for (int rule_index = 0; rule_index < rule_2_length; rule_index++) {
                printf("%c", rule_2[rule_index]);
            }
        } else {
            // write letter without replacement
            printf("%c", initial_letters[i]);
        }
        i++;
    }
    printf("\n");

    return 0;
}


////////////////////////////////////////////////////////////////////////////////
// Fuction Definitions
////////////////////////////////////////////////////////////////////////////////

// Reads up to MAX_LENGTH characters from stdin and stores them in 'array'.
// Returns the number of characters that were stored.
int scan_char_array(char array[MAX_LENGTH]) {
    int array_length = 0;

    int i = 0;
    char c;
    scanf(" %c", &c);
    while (c != '\n' && i < MAX_LENGTH) {
        array[i] = c;
        i++;
        scanf("%c", &c);
    }
    array_length = i;

    return array_length;
}

Exercise — individual:
(Not for Marks) Refactoring - Class Details

Download class_details.c here

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

1511 fetch-activity class_details

For this activity, you've been provided with a fully working program: class_details.c.

While this code produces the correct output, it's code style is not very good.

In particular, class_detail.c is full of magic numbers and repeating code, and it's main function is more than 200 lines long!

Try running 1511 style class_details.c to see even more of it's style issues.

For this activity your job is to go through and improve the readability of the code by

  • Replacing magic numbers with enums and #defines,
  • Breaking it up into small functions (less than 40 lines),
  • Using those functions to remove unnecessary repetition,
  • Writing some function comments to document the code.

You shouldn't change any of the actual functionality of the program i.e. none of the changes you make should change any of the program's output.

Program description

Below is a description of the program. Keep in mind that this has all already been implemented for you.

The provided program scans in and stores the details of students in a class. It first scans in the size of the class, and then scans in the details of each of the students including:

  • zID
  • Degree type (Undergraduate/Postgraduate)
  • Major (if an Undergraduate)
  • Assignments mark (Collated mark of assignments and labs)
  • Exam mark
  • Course grade

Once all student details have been scanned in, the program then loops and scans in commands. It doesn't stop looping until the QUIT command is entered. The program performs one of the following tasks:

  • Command 0 Help: Display program instructions
  • Command 1 (Display Student): Print the details of a specific student
  • Command 2 (Display Class): Print the details of all students in a class
  • Command 3 (Quit): Exit the program

Examples

dcc class_details.c -o class_details
./class_details
Enter Class Size: 1
Student 1: 
Enter zID: 5111111
Select Degree Type: 
0: Undergraduate
1: Postgraduate
0
Select Major: 
0: Computer Science
1: Database Systems
2: eCommerce Systems
3: Artificial Intelligence
4: Programming Languages
5: Computer Networks
6: Embedded Systems
7: Security Engineering
8: None
2
Enter Assignments mark (out of 60): 35.5
Enter exam mark (out of 40): 30
Enter Command Number (0 for Help): 0
Enter a number corresponding to one of the following commands: 
0 (Help): Display program instructions
1 (Display Student): Print the details of a specific student
2 (Display Class): Print the details of all students in a class
3 (Quit): Exit the program
Enter Command Number (0 for Help): 1
Enter Student zID: 5222222 
No student with that zID exists
Enter Command Number (0 for Help): 1
Enter Student zID: 5111111 
z5111111: {
        Degree Type: Undergraduate
        Major: eCommerce Systems
        Assignments Mark: 35.50/60
        Exam Mark: 30.00/40
        Course Grade: 65.50/100
}
Enter Command Number (0 for Help): 100
Invalid Command
Enter Command Number (0 for Help): 3
Exiting Program
./class_details
Enter Class Size: 2
Student 1: 
Enter zID: 5111111
Select Degree Type: 
0: Undergraduate
1: Postgraduate
0
Select Major: 
0: Computer Science
1: Database Systems
2: eCommerce Systems
3: Artificial Intelligence
4: Programming Languages
5: Computer Networks
6: Embedded Systems
7: Security Engineering
8: None
6
Enter Assignments mark (out of 60): 35.5
Enter exam mark (out of 40): 30
Student 2: 
Enter zID: 5222222
Select Degree Type: 
0: Undergraduate
1: Postgraduate
1
Enter Assignments mark (out of 60): 40.5
Enter exam mark (out of 40): 25.9
Enter Command Number (0 for Help): 2
Students: 
z5111111: {
        Degree Type: Undergraduate
        Major: Embedded Systems
        Assignments Mark: 35.50/60
        Exam Mark: 30.00/40
        Course Grade: 65.50/100
}
z5222222: {
        Degree Type: Postgraduate
        Assignments Mark: 40.50/60
        Exam Mark: 25.90/40
        Course Grade: 66.40/100
}
Enter Command Number (0 for Help): 1
Enter Student zID: 5222222
z5222222: {
        Degree Type: Postgraduate
        Assignments Mark: 40.50/60
        Exam Mark: 25.90/40
        Course Grade: 66.40/100
}
Enter Command Number (0 for Help): 3
Exiting Program

Assumptions/Restrictions/Hints

  • You should not change the functionality of the program in any way
  • If there are any edge cases not handled by the original code (e.g. students sharing zids), you do not need to modify the code to handle them
  • All inputs will positive, and be the correct type
You can run an automated code style checker using the following command:
1511 style class_details.c

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

1511 autotest class_details
Sample solution for class_details.c
// Written June 2022
// By Enzo Lee Solano (z5258621)
//
// Interactive program to scan in and display the details of students in a 
// class.

#include <stdio.h>

#define MAX_CLASS_SIZE 20
#define MAX_EXAM_MARK 40
#define MAX_ASSIGMENTS_MARK 60
#define NOT_FOUND -1

enum loop_sentinal { STOP_LOOPING, KEEP_LOOPING };
enum command {HELP, PRINT_STUDENT, PRINT_CLASS, QUIT, INVALID_COMMAND };
enum degree_type {UGRD, PGRD, INVALID_DEGREE};
enum major {
    COMPA1,
    COMPD1,
    COMPE1,
    COMPI1,
    COMPJ1,
    COMPN1,
    COMPS1,
    COMPY1,
    NONE
};

struct student {
    int z_id;
    enum major major;
    enum degree_type degree_type;
    double assignments_mark;
    double exam_mark;
    double course_grade;
};

//Additional Helper Functions:
void print_degree_prompt(void);
void print_major_prompt(void);
double clamp_double(double n, double lower, double higher);
void print_class(int class_size, struct student class[MAX_CLASS_SIZE]);
int find_student_index(int z_id, int class_size, 
                       struct student class[MAX_CLASS_SIZE]);
void print_help_prompt(void);
void find_and_print_student(int class_size, 
                            struct student class[MAX_CLASS_SIZE]);


// Required Functions:
void print_degree_type(enum degree_type degree_type);
enum degree_type scan_degree(void);
void print_major(enum major major);
enum major scan_major(void);
struct student scan_student_details(void);
void print_student(struct student student);
enum command scan_command(void);


int main(void) {
    int class_size;
    printf("Enter Class Size: ");
    scanf("%d", &class_size);

    if (class_size <= 0 || class_size > MAX_CLASS_SIZE) {
        printf("Class Size must be between 1 and %d\n", MAX_CLASS_SIZE);
        // Exit the program early
        return 0;
    }

    struct student class[MAX_CLASS_SIZE];

    int i = 0;
    while (i < class_size) {
        printf("Student %d: \n", i + 1);
        class[i] = scan_student_details();
        i++;
    }

    enum loop_sentinal is_looping = KEEP_LOOPING;
    while (is_looping) {
        printf("Enter Command Number (0 for Help): ");

        enum command command = scan_command();
        if (command == HELP) {
            print_help_prompt();
        } else if (command == PRINT_STUDENT) {
            find_and_print_student(class_size, class);
        } else if (command == PRINT_CLASS) {
            print_class(class_size, class);
        } else if (command == QUIT) {
            is_looping = STOP_LOOPING;
        } else {
            printf("Invalid Command\n");
        }
    }

    printf("Exiting Program\n");

    return 0;
}


// Given a `enum degree_type`, prints out the corresponding string.
void print_degree_type(enum degree_type degree_type) {
    if (degree_type == UGRD) {
        printf("Undergraduate\n");
    } else if (degree_type == PGRD) {
        printf("Postgraduate\n");
    } else {
        printf("INVALID\n");
    }
}

// Prints the prompt which explains to the user how to input a degree_type.
void print_degree_prompt(void) {
    printf("Select Degree Type: \n");
    enum degree_type degree_type = UGRD;
    while (degree_type <= PGRD) {
        printf("%d: ", degree_type);
        print_degree_type(degree_type);
        degree_type++;
    }
}

// Scans in a degree as an integer and maps it to the corresponding 
// `enum degree_type`
// returns : INVALID_DEGREE, if the scanned integer does not correspond to a
//           degree type,
//         : else, the corresponding degree_type
enum degree_type scan_degree(void) {

    int scanned_degree_type;
    scanf("%d", &scanned_degree_type);
    enum degree_type degree_type = INVALID_DEGREE;
    if (scanned_degree_type == UGRD || scanned_degree_type == PGRD) {
        degree_type = scanned_degree_type;
    }

    return degree_type;
}



// Given a `enum major`, prints out the corresponding string.
void print_major(enum major major) {
    if (major == COMPA1) {
        printf("Computer Science\n");
    } else if (major == COMPD1) {
        printf("Database Systems\n");
    } else if (major == COMPE1) {
        printf("eCommerce Systems\n");
    } else if (major == COMPI1) {
        printf("Artificial Intelligence\n");
    } else if (major == COMPJ1) {
        printf("Programming Languages\n");
    } else if (major == COMPN1) {
        printf("Computer Networks\n");
    } else if (major == COMPS1) {
        printf("Embedded Systems\n");
    } else if (major == COMPY1) {
        printf("Security Engineering\n");
    } else {
        printf("None\n");
    }
}

// Prints the prompt which explains to the user how to input a major.
void print_major_prompt(void) {
    printf("Select Major: \n");
    enum major major = COMPA1;
    while (major <= NONE) {
        printf("%d: ", major);
        print_major(major);
        major++;
    }
}

// Scans in a COMP/SCI major as an integer and maps it to the corresponding 
// `enum major`
// returns : NONE, if the scanned integer does not correspond to a
//           MAJOR,
//         : else, the corresponding major
enum major scan_major(void) {
    int scanned_major;
    scanf("%d", &scanned_major);
    enum major major = NONE;
    if (scanned_major >= COMPA1 && scanned_major < NONE) {
        major = scanned_major;
    }

    return major;
}

// Clamps n in the range lower <= n <= higher
// Parameters
//      n     : the number to clamp
//      lower : the lower bound
//      higher: the upper bound
//
// returns : the clamped value.
double clamp_double(double n, double lower, double higher) {
    double clamped_n = n;
    if (n > higher) {
        clamped_n = higher;
    } else if (n < lower) {
        clamped_n = lower;
    }

    return clamped_n;
}

// Scans in all the details for a single student, and returns the details as a
// `struct student`.
//
// returns : the new struct student.
struct student scan_student_details(void) {
    struct student new_student;
    printf("Enter zID: ");
    scanf("%d", &new_student.z_id);

    print_degree_prompt();
    new_student.degree_type = scan_degree();

    new_student.major = NONE;
    if (new_student.degree_type == UGRD) {
        print_major_prompt();
        new_student.major = scan_major();
    }

    printf("Enter Assignments mark (out of %d): ", MAX_ASSIGMENTS_MARK);
    double assignments_mark;
    scanf("%lf", &assignments_mark);
    assignments_mark = clamp_double(assignments_mark, 0, MAX_ASSIGMENTS_MARK);

    printf("Enter exam mark (out of %d): ", MAX_EXAM_MARK);
    double exam_mark;
    scanf("%lf", &exam_mark);
    exam_mark = clamp_double(exam_mark, 0, MAX_EXAM_MARK);

    new_student.assignments_mark = assignments_mark;
    new_student.exam_mark = exam_mark;
    new_student.course_grade = exam_mark + assignments_mark;

    return new_student;
}

// Given a `struct student`, prints out the formatted details of the student.
void print_student(struct student student) {
    printf("z%07d: {\n", student.z_id);
    printf("\tDegree Type: ");
    print_degree_type(student.degree_type);

    if (student.degree_type == UGRD) {
        printf("\tMajor: ");
        print_major(student.major);
    }

    printf("\tAssignments Mark: %3.02lf/%d\n", student.assignments_mark, 
           MAX_ASSIGMENTS_MARK);
    printf("\tExam Mark: %3.02lf/%d\n", student.exam_mark, MAX_EXAM_MARK);
    printf("\tCourse Grade: %3.02lf/%d\n", student.course_grade, 
           MAX_ASSIGMENTS_MARK + MAX_EXAM_MARK);
    printf("}\n");
}

// Given an array of `struct student`s, prints out the formatted details 
// all students in the array.
void print_class(int class_size, struct student class[MAX_CLASS_SIZE]) {
    printf("Students: \n");
    int i = 0;
    while (i < class_size) {
        print_student(class[i]);
        i++;
    }
}

// Given a specific zID, finds and returns the index of the corresponding 
// student.
// Parameters
//      z_id       : the zID of the student to find
//      class_size : the number of students in the class
//      class      : an array of students
//
// returns : NOT_FOUND, if `z_id` does not correspond to a student in the array.
//         : the index of the first occurance of a student with zID: `z_id`,
//           otherwise.
int find_student_index(int z_id, int class_size, 
                       struct student class[MAX_CLASS_SIZE]) {
    int i = 0;
    int student_index = NOT_FOUND;
    while (i < class_size) {
        if (class[i].z_id == z_id) {
            student_index = i;
        }
        i++;
    }

    return student_index;
}


// Prints the prompt which explains to the user how to input different commands
void print_help_prompt(void) {
    printf("Enter a number corresponding to one of the following commands: \n");
    printf("0 (Help): Display program instructions\n");
    printf("1 (Display Student): Print the details of a specific student\n");
    printf("2 (Display Class): Print the details of all students in a class\n");
    printf("3 (Quit): Exit the program\n");
}


// Scans in a command as an integer and maps it to the corresponding 
// `enum command`
// returns : INVALID_COMMAND, if the scanned integer does not correspond to a
//           command,
//         : else, the corresponding command
enum command scan_command(void) {

    int scanned_command;
    scanf("%d", &scanned_command);
    enum command command = INVALID_COMMAND;
    if (scanned_command >= HELP && scanned_command <= QUIT) {
        command = scanned_command;
    }

    return command;
}

// Scans in a zID and displays the details of the corresponding student in a 
// given class.
//
// Parameters
//      class_size : the number of students in the class
//      class      : an array of students
void find_and_print_student(int class_size, struct student class[MAX_CLASS_SIZE]) {
    printf("Enter Student zID: ");
    int z_id;
    scanf("%d", &z_id);
    int student_index = find_student_index(z_id, class_size, class);

    if (student_index == NOT_FOUND) {
        printf("No student with that zID exists\n");
    } else {
        print_student(class[student_index]);
    }
}

Exercise — individual:
(Not For Marks) Debugging - Letter Search

Download debug_letter_search.c here

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

1511 fetch-activity debug_letter_search

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 reads in a letter from the user, and then searches more input given by the user for that letter, or until CTRL+D is entered. It then tells the user if the search was sucessful or not.

Examples

dcc debug_letter_search.c -o debug_letter_search
./debug_letter_search
Which letter are we searching for?: g
COMP1511 is awesome!
hmmm, how about this?
what about now?
hm. How about frog?
We found g!!!
./debug_letter_search
Which letter are we searching for?: ?
No questions here.
Only sentences.
I could have a question.
Nah

The mission was not successful :(

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_letter_search.c

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

1511 autotest debug_letter_search
Sample solution for debug_letter_search.c
// debug_letter_search.c SOLUTION
//
// Write a C program that takes in a letter from the user, and then searches 
// more input given by the user for that letter, or until CTRL+D is entered.
//
// Gab Steiner, June 2023

#include <stdio.h>

#define TRUE 1
#define FALSE 0

int main(void) {
    // Get the letter we are trying to find
    printf("Which letter are we searching for?: ");
    char target;
    scanf("%c", &target);

    // Loop through input until we get the target, or ctrl+d
    char letter;
    int found = FALSE;
    while (found == FALSE && scanf("%c", &letter) == 1) {
        // Check if we found the letter
        if (letter == target) {
            found = TRUE;
        }
    }

    // Tell the user if we found it or not
    if (found == TRUE) {
        printf("We found %c!!!\n", target);
    } else {
        printf("The mission was not successful :(\n");
    }

    return 0;
}

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

Download debug_cloud.c here

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

1511 fetch-activity debug_cloud

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 reads in some cloud heights from a user and works out what type of clouds they are. The program then prints out the total count for all the types.

Note that fog clouds are the lowest, then cumulo, then alto, then cirro clouds occur at the highest heights.

Examples

dcc debug_cloud.c -o debug_cloud
./debug_cloud
Enter some clouds:
200
550
880
2500
100000

CLOUDS
There are 1 fog clouds
There are 2 cumulo clouds
There are 1 alto clouds
There are 1 cirro clouds
./debug_cloud
Enter some clouds:
65000
80000
3000
4000
4690.23
12.54
24.57
8

CLOUDS
There are 3 fog clouds
There are 0 cumulo clouds
There are 3 alto clouds
There are 2 cirro clouds

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_cloud.c

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

1511 autotest debug_cloud
Sample solution for debug_cloud.c
// debug_cloud.c SOLUTION
// This is a C program that reads in some clouds and tallies the types.
// Gab Steiner, June 2023

#include <stdio.h>

enum levels {
    LOW = 500,
    MID = 2000,
    HIGH = 6000
};

enum cloud_type {
    FOG,
    CUMULO,
    ALTO,
    CIRRO
};

struct cloud {
    double height;
    enum cloud_type type;
};

int cloud_type_count(enum cloud_type type, struct cloud clouds[10], 
                            int count);

int main(void) {
    struct cloud sky[10];    

    printf("Enter some clouds:\n");
    // Scan in some clouds
    int index = 0;
    while (scanf("%lf", &sky[index].height) == 1) {

        // Determine the type of cloud based on it's height
        if (sky[index].height > HIGH) {
            sky[index].type = CIRRO;
        } else if (sky[index].height > MID) {
            sky[index].type = ALTO;
        } else if (sky[index].height > LOW) {
            sky[index].type = CUMULO;
        } else {
            sky[index].type = FOG;
        }

        index++;
    }

    // Print out the total for each cloud
    printf("\nCLOUDS\n");
    printf("There are %d fog clouds\n", cloud_type_count(FOG, sky, index));
    printf("There are %d cumulo clouds\n", cloud_type_count(CUMULO, sky, index));
    printf("There are %d alto clouds\n", cloud_type_count(ALTO, sky, index));
    printf("There are %d cirro clouds\n", cloud_type_count(CIRRO, sky, index));

    return 0;
}

// This function counts the number of times a specific type of cloud was seen.
//
// ARGS:
// - type is the type of cloud being looked for.
// - clouds is an array of cloud structs.
// - count is the number of clouds filled in the array.
//
// RETURN:
// - total is the number of clouds of the specific type that were found.
//
int cloud_type_count(enum cloud_type type, struct cloud clouds[10], 
                            int count) {
    
    int total = 0;

    // Find all the clouds with that type
    for (int i = 0; i < count; i++) {
        if (clouds[i].type == type) {
            total++;
        }
    }

    return total;
}

Exercise — individual:
(Not for Marks) Fractal Turtle 🐢 (extra-hard)

Download fractal_turtle.c here

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

1511 fetch-activity fractal_turtle

The goal of this activity is to display fractals on the terminal. To do this, three topics are combined:

  • Turtle Graphics - to draw images based on sequences of characters.
  • L-Systems - to generate sequences of characters.
  • Fractals - the types of images we are interested in.

These topics will be introduced, followed by instructions for the activity.

Turtle Graphics

Turtle Graphics is a simplified drawing system where an imaginary turtle moves around the screen according to commands.

Initially, the turtle faces up towards the top of the screen. It then follows commands to draw on the canvas:

  • F moves the turtle forwards 2 steps while painting a line.
  • f moves the turtle forwards 2 steps, without painting a line.
  • + turns the turtle left by 90 degrees.
  • - turns the turtle right by 90 degrees.

Using these commands, we can create images by instructing the turtle where to move and when to draw.

For example, if we wanted to paint the blue shapes in Figure 1, we could use the instructions FFF-FffF-F-fff+f+F-FF. Our turtle would interpret this sequence of characters according to the annotations in Figure 2.

Tile A is not shadowed

Figure 1. Example turtle graphic.

Tile A is not shadowed

Figure 2. Turtle interpretation of FFF-FffF-F-fff+f+F-FF.

But how can we represent these graphics in the terminal?

We could choose to represent each blue painted tile by a hash '#', and each unpainted tile by a space ' '. But due to the unequal heights and widths of characters printed to the terminal, this results in the skewed image shown by Figure 3.

###   ###
#       #
#       #
#        
# ###    
#   #    
#   #    
    #    
    #    

Figure 3. Sad turtle graphics ☹.

Luckily, this can be fixed! We represent each tile as two characters on the terminal:

  • For each painted tile, we use two characters: a space ' ' followed by a hash '#' i.e. " #".
  • For each unpainted tile, we use two spaces i.e. "  ".

This results in the terminal output shown in Figure 4. Compare this to Figure 1.

 # # #       # # #
 #               #
 #               #
 #                
 #   # # #        
 #       #        
 #       #        
         #        
         #        

Figure 4. Happy turtle graphics 🐢.

Figures 5-8 show some examples of other shapes drawn with turtle graphics:
 # # #
 #   #
 # # #

Figure 5. The turtle interpretation of F-F-F-F draws a square.

     #    
     #    
 # # #    
 #        
 # # # # #
         #
     # # #
     #    
     #    

Figure 6. The turtle interpretation of F-F+F+FF-F-F+F draws a squiggle.

     #    
     #    
     #    
     #    
 # # # # #
 #       #
 # # # # #
     #    
     #    
     #    
     #    

Figure 7. The turtle interpretation of FF+F-F-FF-F-F-fFF draws a circuit element.

         #        
         #        
         #   # # #
         #   #   #
         #   #   #
         #   #   #
 # # #   #   # # #
 #   #   #        
 #   #   #        
 #   #   #        
 # # #   #        
         #        
         #        

Figure 8. The turtle interpretation of F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF draws a birds-eye view of a road with two cars.

L-Systems

Writing out long sequences (such as F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF) can be tedious and error-prone. Instead, we use a find-and-replace method known as an L-System to generate these sequences automatically. We begin with a short sequence and apply simple rules to expand it into larger sequences.

An L-system is a set of rules used to generate complex sequences of characters.

Given a sequence of characters, we can rewrite it by replacing chosen characters according to designated rules.

For example, starting with an initial sequence of characters "abc" we could rewrite it by replacing:

  • every a with rule "ba", and
  • every b with rule "baab".

Initially, we have:

"abc"

After one rewrite:

"babaabc"

After the second rewrite:

"baabbabaabbababaabc"

And so on...

Each rewrite replaces every occurrence of a character with the sequence of characters from its corresponding rule.

By employing L-systems, we can use simple rules to systematically produce long and complex sequences of characters.

Fractals

For this activity: a fractal is a shape that repeats a pattern at difference scales.

For example, suppose we begin with the single vertical line in Figure 9 resulting from the turtle interpretation of F.

 #
 #
 #

Figure 9. A single vertical line: F.

If we replace F with F-F+F+FF-F-F+F (i.e. replace it with the squiggle from Figure 6) the rewritten sequence of characters is F-F+F+FF-F-F+F, and is shown by Figure 10. We've replaced every line by a squiggle, and since we started with one line, the result is one squiggle.

     #    
     #    
 # # #    
 #        
 # # # # #
         #
     # # #
     #    
     #    

Figure 10. The turtle interpretation of F-F+F+FF-F-F+F is a squiggle.

Now we're at the main point of this exercise: what if we do it again? Let's replace every line (every F character) in the squiggle F-F+F+FF-F-F+F with another squiggle F-F+F+FF-F-F+F.

The rewritten result is the long sequence of characters F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F+F-F+F+FF-F-F+FF-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F. The turtle interpretation of these commands is illustrated in Figure 11 to be a squiggle of squiggles!

At this point it's worth pausing to observe that this shape is a large squiggle, where every edge has been replaced by a smaller squiggle. This is an example of what we're calling a fractal: a shape that repeats a pattern at different scales.

                     #                    
                     #                    
                 # # #                    
                 #                        
                 # # # # #                
                         #                
             # # #   # # #                
             #   #   #                    
     # # #   #   # # #                    
     #   #   #                            
 # # #   # # #                            
 #                                        
 # # # # #                                
         #                                
     # # #   # # #           # # #        
     #       #   #           #   #        
     # # #   #   # # # # #   #   # # #    
         #   #           #   #       #    
         # # #           # # #   # # #    
                                 #        
                                 # # # # #
                                         #
                             # # #   # # #
                             #   #   #    
                     # # #   #   # # #    
                     #   #   #            
                 # # #   # # #            
                 #                        
                 # # # # #                
                         #                
                     # # #                
                     #                    
                     #                    

Figure 11. A squiggly-squiggle resulting from replacing F by F-F+F+FF-F-F+F two times.

Task

Write a C program fractal_turtle.c that repeatedly rewrites an initial sequence of characters by replacing characters 'F' and 'f' with user-defined rules, and then prints a turtle interpretation of the resulting sequence to the terminal.

The program should:

  1. Read an initial sequence of characters consisting of any combination of 'F', 'f', '+', or '-'.
  2. Prompt the user to enter a rewriting rule for 'F'.
  3. Prompt the user to enter a rewriting rule for 'f'.
  4. Ask for the number of times to apply the rewriting rules.
  5. Apply the rewriting rules, replacing each instance of 'F' and 'f' with the corresponding rewriting rule. Revisiting the section on L-Systems may be helpful here.
  6. Print each intermediate rewrite (e.g. the initial string, the 1st rewrite, the 2nd rewrite, etc) to the terminal.
  7. Output the turtle interpretation of the final sequence of rewritten characters to the terminal.

Examples

dcc fractal_turtle.c -o fractal_turtle
./fractal_turtle
Initial characters (F, f, -, +): F
Rewriting rule for 'F': F-F+F+FF-F-F+F
Rewriting rule for 'f': f
Number of times to apply the rewriting rules: 1
Rewrite 0: F
Rewrite 1: F-F+F+FF-F-F+F
     #    
     #    
 # # #    
 #        
 # # # # #
         #
     # # #
     #    
     #    
./fractal_turtle
Initial characters (F, f, -, +): F
Rewriting rule for 'F': F-F+F+FF-F-F+F
Rewriting rule for 'f': f
Number of times to apply the rewriting rules: 2
Rewrite 0: F
Rewrite 1: F-F+F+FF-F-F+F
Rewrite 2: F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F+F-F+F+FF-F-F+FF-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F
                     #                    
                     #                    
                 # # #                    
                 #                        
                 # # # # #                
                         #                
             # # #   # # #                
             #   #   #                    
     # # #   #   # # #                    
     #   #   #                            
 # # #   # # #                            
 #                                        
 # # # # #                                
         #                                
     # # #   # # #           # # #        
     #       #   #           #   #        
     # # #   #   # # # # #   #   # # #    
         #   #           #   #       #    
         # # #           # # #   # # #    
                                 #        
                                 # # # # #
                                         #
                             # # #   # # #
                             #   #   #    
                     # # #   #   # # #    
                     #   #   #            
                 # # #   # # #            
                 #                        
                 # # # # #                
                         #                
                     # # #                
                     #                    
                     #                    
./fractal_turtle
Initial characters (F, f, -, +): F-F-F-F
Rewriting rule for 'F': F-F+F+FF-F-F+F
Rewriting rule for 'f': f
Number of times to apply the rewriting rules: 1
Rewrite 0: F-F-F-F
Rewrite 1: F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F
             # # #        
             #   #        
     # # #   #   # # #    
     #   #   #       #    
 # # #   # # #   # # #    
 #               #        
 # # # # #       # # # # #
         #               #
     # # #   # # #   # # #
     #       #   #   #    
     # # #   #   # # #    
         #   #            
         # # #            

dcc fractal_turtle.c -o fractal_turtle
./fractal_turtle
Initial characters (F, f, -, +): F
Rewriting rule for 'F': FF+F-F-FF-F-F-fFF
Rewriting rule for 'f': f
Number of times to apply the rewriting rules: 1
Rewrite 0: F
Rewrite 1: FF+F-F-FF-F-F-fFF
     #    
     #    
     #    
     #    
 # # # # #
 #       #
 # # # # #
     #    
     #    
     #    
     #    
./fractal_turtle
Initial characters (F, f, -, +): F
Rewriting rule for 'F': FF+F-F-FF-F-F-fFF
Rewriting rule for 'f': fffff
Number of times to apply the rewriting rules: 2
Rewrite 0: F
Rewrite 1: FF+F-F-FF-F-F-fFF
Rewrite 2: FF+F-F-FF-F-F-fFFFF+F-F-FF-F-F-fFF+FF+F-F-FF-F-F-fFF-FF+F-F-FF-F-F-fFF-FF+F-F-FF-F-F-fFFFF+F-F-FF-F-F-fFF-FF+F-F-FF-F-F-fFF-FF+F-F-FF-F-F-fFF-fffffFF+F-F-FF-F-F-fFFFF+F-F-FF-F-F-fFF
                         #                        
                         #                        
                         #                        
                         #                        
                     # # # # #                    
                     #       #                    
                     # # # # #                    
                         #                        
                         #                        
                         #                        
                         #                        
                         #                        
                         #                        
                         #                        
                     # # # # #                    
                     #       #                    
                     # # # # #                    
                         #                        
             # # #       #       # # #            
             #   #       #       #   #            
     # # # # #   # # # # # # # # #   # # # # #    
     #       #   #               #   #       #    
     #       # # #               # # #       #    
     #                                       #    
 # # # # #                               # # # # #
 #       #                               #       #
 # # # # #                               # # # # #
     #                                       #    
     #       # # #               # # #       #    
     #       #   #               #   #       #    
     # # # # #   # # # # # # # # #   # # # # #    
             #   #       #       #   #            
             # # #       #       # # #            
                         #                        
                     # # # # #                    
                     #       #                    
                     # # # # #                    
                         #                        
                         #                        
                         #                        
                         #                        
                         #                        
                         #                        
                         #                        
                     # # # # #                    
                     #       #                    
                     # # # # #                    
                         #                        
                         #                        
                         #                        
                         #    
./fractal_turtle
Initial characters (F, f, -, +): F-F-F-F
Rewriting rule for 'F': FF+F-F-FF-F-F-fFF
Rewriting rule for 'f': f
Number of times to apply the rewriting rules: 1
Rewrite 0: F-F-F-F
Rewrite 1: FF+F-F-FF-F-F-fFF-FF+F-F-FF-F-F-fFF-FF+F-F-FF-F-F-fFF-FF+F-F-FF-F-F-fFF
             # # #            
             #   #            
     # # # # #   # # # # #    
     #       #   #       #    
     #       # # #       #    
     #                   #    
 # # # # #           # # # # #
 #       #           #       #
 # # # # #           # # # # #
     #                   #    
     #       # # #       #    
     #       #   #       #    
     # # # # #   # # # # #    
             #   #            
             # # #            

dcc fractal_turtle.c -o fractal_turtle
./fractal_turtle
Initial characters (F, f, -, +): F
Rewriting rule for 'F': F+F-F-F+F
Rewriting rule for 'f': f
Number of times to apply the rewriting rules: 1
Rewrite 0: F
Rewrite 1: F+F-F-F+F
     #
     #
 # # #
 #    
 # # #
     #
     #
./fractal_turtle
Initial characters (F, f, -, +): F
Rewriting rule for 'F': F+F-F-F+F
Rewriting rule for 'f': f
Number of times to apply the rewriting rules: 2
Rewrite 0: F
Rewrite 1: F+F-F-F+F
Rewrite 2: F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F
                 #
                 #
             # # #
             #    
         # # # # #
         #   #   #
     # # #   # # #
     #            
 # # #            
 #                
 # # #            
     #            
     # # #   # # #
         #   #   #
         # # # # #
             #    
             # # #
                 #
                 #
./fractal_turtle
Initial characters (F, f, -, +): F
Rewriting rule for 'F': F+F-F-F+F
Rewriting rule for 'f': f
Number of times to apply the rewriting rules: 3
Rewrite 0: F
Rewrite 1: F+F-F-F+F
Rewrite 2: F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F
Rewrite 3: F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F+F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F-F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F-F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F+F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F
                                                     #
                                                     #
                                                 # # #
                                                 #    
                                             # # # # #
                                             #   #   #
                                         # # #   # # #
                                         #            
                                     # # #            
                                     #                
                                 # # # # #            
                                 #   #   #            
                             # # #   # # # # #   # # #
                             #           #   #   #   #
                         # # #           # # # # # # #
                         #                   #   #    
                     # # # # #           # # # # # # #
                     #   #   #           #   #   #   #
                 # # #   # # #           # # #   # # #
                 #                                    
             # # #                                    
             #                                        
         # # # # #                                    
         #   #   #                                    
     # # #   # # #                                    
     #                                                
 # # #                                                
 #                                                    
 # # #                                                
     #                                                
     # # #   # # #                                    
         #   #   #                                    
         # # # # #                                    
             #                                        
             # # #                                    
                 #                                    
                 # # #   # # #           # # #   # # #
                     #   #   #           #   #   #   #
                     # # # # #           # # # # # # #
                         #                   #   #    
                         # # #           # # # # # # #
                             #           #   #   #   #
                             # # #   # # # # #   # # #
                                 #   #   #            
                                 # # # # #            
                                     #                
                                     # # #            
                                         #            
                                         # # #   # # #
                                             #   #   #
                                             # # # # #
                                                 #    
                                                 # # #
                                                     #
                                                     #

dcc fractal_turtle.c -o fractal_turtle
./fractal_turtle
Initial characters (F, f, -, +): F-F-F-F
Rewriting rule for 'F': FF-F-F-F-FF
Rewriting rule for 'f': f
Number of times to apply the rewriting rules: 2
Rewrite 0: F-F-F-F
Rewrite 1: FF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FF
Rewrite 2: FF-F-F-F-FFFF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FFFF-F-F-F-FF-FF-F-F-F-FFFF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FFFF-F-F-F-FF-FF-F-F-F-FFFF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FFFF-F-F-F-FF-FF-F-F-F-FFFF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FF-FF-F-F-F-FFFF-F-F-F-FF
 # # # # # # # # # # # # # # # # # # #
 #   #   #   #   #   #   #   #   #   #
 # # # # #   # # # # # # #   # # # # #
 #   #       #   #   #   #       #   #
 # # #       # # # # # # #       # # #
 #           #   #   #   #           #
 # # # # # # # # # # # # # # # # # # #
 #   #   #   #           #   #   #   #
 # # # # # # #           # # # # # # #
 #   #   #   #           #   #   #   #
 # # # # # # #           # # # # # # #
 #   #   #   #           #   #   #   #
 # # # # # # # # # # # # # # # # # # #
 #           #   #   #   #           #
 # # #       # # # # # # #       # # #
 #   #       #   #   #   #       #   #
 # # # # #   # # # # # # #   # # # # #
 #   #   #   #   #   #   #   #   #   #
 # # # # # # # # # # # # # # # # # # #
./fractal_turtle
Initial characters (F, f, -, +): F-F-F-F
Rewriting rule for 'F': FF-F--F-F
Rewriting rule for 'f': f
Number of times to apply the rewriting rules: 2
Rewrite 0: F-F-F-F
Rewrite 1: FF-F--F-F-FF-F--F-F-FF-F--F-F-FF-F--F-F
Rewrite 2: FF-F--F-FFF-F--F-F-FF-F--F-F--FF-F--F-F-FF-F--F-F-FF-F--F-FFF-F--F-F-FF-F--F-F--FF-F--F-F-FF-F--F-F-FF-F--F-FFF-F--F-F-FF-F--F-F--FF-F--F-F-FF-F--F-F-FF-F--F-FFF-F--F-F-FF-F--F-F--FF-F--F-F-FF-F--F-F
 # # # # # # # # # # # # # # # # # # #
 #       #           #   #       #   #
 # # #   #           #   # # #   #   #
 #                       #           #
 #   #               # # #       # # #
 #   #                   #           #
 # # # # # # #           #           #
 #       #                           #
 # # #   #                           #
 #                                   #
 #                           #   # # #
 #                           #       #
 #           #           # # # # # # #
 #           #                   #   #
 # # #       # # #               #   #
 #           #                       #
 #   #   # # #   #           #   # # #
 #   #       #   #           #       #
 # # # # # # # # # # # # # # # # # # #
./fractal_turtle
Initial characters (F, f, -, +): F
Rewriting rule for 'F': FF-F--F-F
Rewriting rule for 'f': f
Number of times to apply the rewriting rules: 3
Rewrite 0: F
Rewrite 1: FF-F--F-F
Rewrite 2: FF-F--F-FFF-F--F-F-FF-F--F-F--FF-F--F-F-FF-F--F-F
Rewrite 3: FF-F--F-FFF-F--F-F-FF-F--F-F--FF-F--F-F-FF-F--F-FFF-F--F-FFF-F--F-F-FF-F--F-F--FF-F--F-F-FF-F--F-F-FF-F--F-FFF-F--F-F-FF-F--F-F--FF-F--F-F-FF-F--F-F--FF-F--F-FFF-F--F-F-FF-F--F-F--FF-F--F-F-FF-F--F-F-FF-F--F-FFF-F--F-F-FF-F--F-F--FF-F--F-F-FF-F--F-F
 #                                    
 #                                    
 # # #                                
 #                                    
 #   #                                
 #   #                                
 # # # # # # #                        
 #       #                            
 # # #   #                            
 #                                    
 #                                    
 #                                    
 #           #                        
 #           #                        
 # # #       # # #                    
 #           #                        
 #   #   # # #   #           #        
 #   #       #   #           #        
 # # # # # # # # # # # # # # # # # # #
 #       #           #   #       #    
 # # #   #           #   # # #   #    
 #                       #            
 #   #               # # #            
 #   #                   #            
 # # # # # # #           #            
 #       #                            
 # # #   #                            
 #                                    
 #                                    
 #                                    
 #                                    
 #                                    
 # # #                                
 #                                    
 #                                    
 #                                    
 #                                    
 #                                    
 # # #                                
 #                                    
 #   #                                
 #   #                                
 # # # # # # #                        
 #       #                            
 # # #   #                            
 #                                    
 #                                    
 #                                    
 #                                    
 #                                    
 # # #                                
 #                                    
 #                                    
 #                                    
 #   
./fractal_turtle
Initial characters (F, f, -, +): F+F+F+F
Rewriting rule for 'F': F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF
Rewriting rule for 'f': ffffff
Number of times to apply the rewriting rules: 1
Rewrite 0: F+F+F+F
Rewrite 1: F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF+F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF+F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF+F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF
             # # # # #                    
             #       #                    
             # # # # #                    
                                          
         # # # # # # # # # # # # #        
         #                       #        
         #   # # #   # # # # #   #   # # #
         #   #   #   #       #   #   #   #
         #   #   #   # # # # #   #   #   #
         #   #   #               #   #   #
 # # #   #   # # #       # # #   #   # # #
 #   #   #               #   #   #        
 #   #   #   # # # # #   #   #   #        
 #   #   #   #       #   #   #   #        
 # # #   #   # # # # #   # # #   #        
         #                       #        
         # # # # # # # # # # # # #        
                                          
                     # # # # #            
                     #       #            
                     # # # # #  

Assumptions/Restrictions/Clarifications

  • Use of the following C language features is not permitted for this activity:

    • Two-dimensional arrays.
    • Variable-length arrays.
    • Dynamically allocated memory e.g. any use of malloc().
  • There is no predefined limit or maximum size (number of rows or columns) required to output the turtle interpretation. Your program should be able to handle arbitrarily large output sizes.

  • Every '#' character is printed with a space ' ' before it. In particular: note from the examples that a '#' character is never printed in the first column of output as it is always preceded by a space ' '.

  • The following inputs will contain 16384 characters or less:

    • The sequence of initial letters.
    • The rewriting rules.
    • All rewritten sequences of characters.
  • The initial sequence of characters will never be empty.

  • It is possible for a rewriting rule to be empty e.g. to replace an 'f' with no characters at all.

  • Your program must be able to handle all printable ASCII characters (decimal codes 32 to 126). This excludes any control characters (from 0 to 31) and the delete character (127).

  • The number of times to apply the rewriting rules will be a non-negative integer (zero is a valid input).

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

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

1511 autotest fractal_turtle
Sample solution for fractal_turtle.c
// Fractal Turtle
// fractal_turtle.c
//
// This program was written by Andrew Polak (fake zid z9999999)
// on 12-Jan-2025.
//
// NOTES:
//  - This activity is an extension of the "rewrite_letters" activity.
//  - This solution uses string functions (e.g. fgets(), strncpy()) as a matter
//    of convenience, but they are not required. See the solution to
//    "rewrite_letters" for how to handle arrays of chars without strings.
//
// A program which generates strings with Lindenmayer Systems (L-Systems) and
// paints their turtle interpretation to the terminal.
//
// The principles implemented by this program are inspired by
// "The Algorithmic Beauty of Plants" by Prusinkiewicz and Lindenmayer.
//

// Lindenmayer Systems:
//
// A Lindenmayer system consists of:
//  - An initial string e.g. 
//      "a"
//  - Rewriting rules in the form of predecessor:"successor" e.g.
//      a:"acb"
//      b:"baab"
// Every occurrence of a predecessor in the initial string is replaced with the
// corresponding successor in parallel (at the same time). This can be repeated
// multiple times to generate increasingly longer (or shorter) strings:
//  - Initial String: "a"
//  - 1st rewrite: "acb"
//  - 2nd rewrite: "acbcbaab"
//  - 3rd rewrite: "acbcbaabcbaabacbacbbaab"
//

// Turtle Interpretations:
//
// A Turtle interpretation of a string is named as though there is a turtle
// located on a drawing canvas (i.e. the terminal). It initially faces up 
// towards the top of the screen, then reads characters from the string an
// moves according to a set of rules:
//   "F" means "move forward two steps, painting a line"
//   "f" means "move forward two steps, without painting a line"
//   "-" means "turn right"
//   "+" means "turn left"
// In this way, and string consisting of characters {F, f, -, +} can be drawn on
// the terminal. When the turtle paints a line, it writes characters to the
// terminal. When the turtle moves without painting a line, it writes spaces.
// 
// For example, the sequence of characters "F-F-F-F" draws a square:
//   Initially, the turtle faces up
//   'F' means "draw a line up"
//   '-' means "turn to the right"
//   'F' means "draw a line right"
//   '-' means "turn downwards"
//   'F' means" draw a line down"
//   '-' means "turn to the left"
//   'F' means "draw a line to the left"

// Combining L-Systems with Turtle Interpretations:
//
// If an L-System produces a sequence of characters {F, f, -, +}, then it can be
// drawn on the terminal with a turtle interpretation. That's what this
// program does.
//
// Examples:

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F           
// Rewriting rule for 'F': F
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F
// Rewrite 1: F
//  #
//  #
//  #

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F-F
// Rewriting rule for 'F': F
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F-F
// Rewrite 1: F-F
//  # # #
//  #    
//  #  

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F
// Rewriting rule for 'F': FF
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F
// Rewrite 1: FF
//  #
//  #
//  #
//  #
//  #

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F-FfF-F
// Rewriting rule for 'F': F
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F-FfF-F
// Rewrite 1: F-FfF-F
//  # # #   # # #
//  #           #
//  #           #

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F-FfF-F
// Rewriting rule for 'F': FF
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F-FfF-F
// Rewrite 1: FF-FFfFF-FF
//  # # # # #   # # # # #
//  #                   #
//  #                   #
//  #                   #
//  #                   #

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F-FfF-F
// Rewriting rule for 'F': FF
// Rewriting rule for 'f': ffff
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F-FfF-F
// Rewrite 1: FF-FFffffFF-FF
//  # # # # #               # # # # #
//  #                               #
//  #                               #
//  #                               #
//  #                               #

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F-F-F-F
// Rewriting rule for 'F': F
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F-F-F-F
// Rewrite 1: F-F-F-F
//  # # #
//  #   #
//  # # #

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F-F-F-F
// Rewriting rule for 'F': FF
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F-F-F-F
// Rewrite 1: FF-FF-FF-FF
//  # # # # #
//  #       #
//  #       #
//  #       #
//  # # # # #

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F
// Rewriting rule for 'F': F-F+F+FF-F-F+F
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F
// Rewrite 1: F-F+F+FF-F-F+F
//      #    
//      #    
//  # # #    
//  #        
//  # # # # #
//          #
//      # # #
//      #    
//      #    

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F
// Rewriting rule for 'F': F-F+F+FF-F-F+F
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 2
// Rewrite 0: F
// Rewrite 1: F-F+F+FF-F-F+F
// Rewrite 2: F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F+F-F+F+FF-F-F+FF-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F
//                      #                    
//                      #                    
//                  # # #                    
//                  #                        
//                  # # # # #                
//                          #                
//              # # #   # # #                
//              #   #   #                    
//      # # #   #   # # #                    
//      #   #   #                            
//  # # #   # # #                            
//  #                                        
//  # # # # #                                
//          #                                
//      # # #   # # #           # # #        
//      #       #   #           #   #        
//      # # #   #   # # # # #   #   # # #    
//          #   #           #   #       #    
//          # # #           # # #   # # #    
//                                  #        
//                                  # # # # #
//                                          #
//                              # # #   # # #
//                              #   #   #    
//                      # # #   #   # # #    
//                      #   #   #            
//                  # # #   # # #            
//                  #                        
//                  # # # # #                
//                          #                
//                      # # #                
//                      #                    
//                      #          

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F-F-F-F
// Rewriting rule for 'F': F-F+F+FF-F-F+F
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F-F-F-F
// Rewrite 1: F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F
//              # # #        
//              #   #        
//      # # #   #   # # #    
//      #   #   #       #    
//  # # #   # # #   # # #    
//  #               #        
//  # # # # #       # # # # #
//          #               #
//      # # #   # # #   # # #
//      #       #   #   #    
//      # # #   #   # # #    
//          #   #            
//          # # #   

// 
// This is the same as above, but applying the rewriting rule TWICE
//
// $ ./fractal_turtle
// Initial characters (F, f, -, +): F-F-F-F
// Rewriting rule for 'F': F-F+F+FF-F-F+F
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 2
// Rewrite 0: F-F-F-F
// Rewrite 1: F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F
// Rewrite 2: F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F+F-F+F+FF-F-F+FF-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F+F-F+F+FF-F-F+FF-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F+F-F+F+FF-F-F+FF-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F+F-F+F+FF-F-F+FF-F+F+FF-F-F+F-F-F+F+FF-F-F+F-F-F+F+FF-F-F+F+F-F+F+FF-F-F+F
//                                                              # # #                                        
//                                                              #   #                                        
//                                                      # # #   #   # # #                                    
//                                                      #   #   #       #                                    
//                                                  # # #   # # #   # # #                                    
//                                                  #               #                                        
//                                                  # # # # #       # # # # #                                
//                                                          #               #                                
//                              # # #                   # # #           # # #   # # #                        
//                              #   #                   #               #       #   #                        
//                      # # #   #   # # #               #               # # #   #   # # #                    
//                      #   #   #       #               #                   #   #       #                    
//                  # # #   # # #   # # #           # # #                   # # #   # # #                    
//                  #               #               #                               #                        
//                  # # # # #       # # # # #       # # # # #                       # # # # #                
//                          #               #               #                               #                
//              # # #   # # #           # # #   # # #   # # #                   # # #   # # #                
//              #   #   #               #       #   #   #                       #   #   #                    
//      # # #   #   # # #               # # #   #   # # #               # # #   #   # # #                    
//      #   #   #                           #   #                       #   #   #                            
//  # # #   # # #                           # # #                   # # #   # # #                            
//  #                                                               #                                        
//  # # # # #                                                       # # # # #                                
//          #                                                               #                                
//      # # #   # # #           # # #                                   # # #   # # #           # # #        
//      #       #   #           #   #                                   #       #   #           #   #        
//      # # #   #   # # # # #   #   # # #                               # # #   #   # # # # #   #   # # #    
//          #   #           #   #       #                                   #   #           #   #       #    
//          # # #           # # #   # # #                                   # # #           # # #   # # #    
//                                  #                                                               #        
//                                  # # # # #                                                       # # # # #
//                                          #                                                               #
//                              # # #   # # #                   # # #                           # # #   # # #
//                              #   #   #                       #   #                           #   #   #    
//                      # # #   #   # # #               # # #   #   # # #               # # #   #   # # #    
//                      #   #   #                       #   #   #       #               #   #   #            
//                  # # #   # # #                   # # #   # # #   # # #           # # #   # # #            
//                  #                               #               #               #                        
//                  # # # # #                       # # # # #       # # # # #       # # # # #                
//                          #                               #               #               #                
//                      # # #   # # #                   # # #           # # #   # # #   # # #                
//                      #       #   #                   #               #       #   #   #                    
//                      # # #   #   # # #               #               # # #   #   # # #                    
//                          #   #       #               #                   #   #                            
//                          # # #   # # #           # # #                   # # #                            
//                                  #               #                                                        
//                                  # # # # #       # # # # #                                                
//                                          #               #                                                
//                                      # # #   # # #   # # #                                                
//                                      #       #   #   #                                                    
//                                      # # #   #   # # #                                                    
//                                          #   #                                                            
//                                          # # #  

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F
// Rewriting rule for 'F': FF+F-F-FF-F-F-fFF
// Rewriting rule for 'f': f
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F
// Rewrite 1: FF+F-F-FF-F-F-fFF
//      #    
//      #    
//      #    
//      #    
//  # # # # #
//  #       #
//  # # # # #
//      #    
//      #    
//      #    
//      #    

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F
// Rewriting rule for 'F': FF+F-F-FF-F-F-fFF
// Rewriting rule for 'f': fffff
// Number of times to apply the rewriting rules: 2
// Rewrite 0: F
// Rewrite 1: FF+F-F-FF-F-F-fFF
// Rewrite 2: FF+F-F-FF-F-F-fFFFF+F-F-FF-F-F-fFF+FF+F-F-FF-F-F-fFF-FF+F-F-FF-F-F-fFF-FF+F-F-FF-F-F-fFFFF+F-F-FF-F-F-fFF-FF+F-F-FF-F-F-fFF-FF+F-F-FF-F-F-fFF-fffffFF+F-F-FF-F-F-fFFFF+F-F-FF-F-F-fFF
//                          #                        
//                          #                        
//                          #                        
//                          #                        
//                      # # # # #                    
//                      #       #                    
//                      # # # # #                    
//                          #                        
//                          #                        
//                          #                        
//                          #                        
//                          #                        
//                          #                        
//                          #                        
//                      # # # # #                    
//                      #       #                    
//                      # # # # #                    
//                          #                        
//              # # #       #       # # #            
//              #   #       #       #   #            
//      # # # # #   # # # # # # # # #   # # # # #    
//      #       #   #               #   #       #    
//      #       # # #               # # #       #    
//      #                                       #    
//  # # # # #                               # # # # #
//  #       #                               #       #
//  # # # # #                               # # # # #
//      #                                       #    
//      #       # # #               # # #       #    
//      #       #   #               #   #       #    
//      # # # # #   # # # # # # # # #   # # # # #    
//              #   #       #       #   #            
//              # # #       #       # # #            
//                          #                        
//                      # # # # #                    
//                      #       #                    
//                      # # # # #                    
//                          #                        
//                          #                        
//                          #                        
//                          #                        
//                          #                        
//                          #                        
//                          #                        
//                      # # # # #                    
//                      #       #                    
//                      # # # # #                    
//                          #                        
//                          #                        
//                          #                        
//                          #    

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F
// Rewriting rule for 'F': F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF
// Rewriting rule for 'f': f    
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F
// Rewrite 1: F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF
//          #        
//          #        
//          #   # # #
//          #   #   #
//          #   #   #
//          #   #   #
//  # # #   #   # # #
//  #   #   #        
//  #   #   #        
//  #   #   #        
//  # # #   #        
//          #        
//          #      

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F
// Rewriting rule for 'F': F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF
// Rewriting rule for 'f': ffffff
// Number of times to apply the rewriting rules: 2
// Rewrite 0: F
// Rewrite 1: F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF
// Rewrite 2: F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF+ffffff-F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFFF+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF+F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF+F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFFF+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF+F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFFffffff+F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFFF+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF-ffffff+F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFFF+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF-F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF-F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFFF+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF-F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFFffffff-F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFFF+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFFF+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF
//                                                          #                                                        
//                                                          #                                                        
//                                                          #   # # #                                                
//                                                          #   #   #                                                
//                                                          #   #   #                                                
//                                                          #   #   #                                                
//                                                  # # #   #   # # #                                                
//                                                  #   #   #                                                        
//                                                  #   #   #                           # # # # #                    
//                                                  #   #   #                           #       #                    
//                                                  # # #   #                           # # # # #                    
//                                                          #                                                        
//                                                          #                       # # # # # # # # # # # # #        
//                                                          #                       #                       #        
//                                                          #   # # #               #   # # #   # # # # #   #   # # #
//                                                          #   #   #               #   #   #   #       #   #   #   #
//                                                          #   #   #               #   #   #   # # # # #   #   #   #
//                                                          #   #   #               #   #   #               #   #   #
//                                                  # # #   #   # # #       # # #   #   # # #       # # #   #   # # #
//                                                  #   #   #               #   #   #               #   #   #        
//                                                  #   #   #               #   #   #               #   #   #        
//                                                  #   #   #               #   #   #               #   #   #        
//                                                  # # #   #               # # #   #               # # #   #        
//                                                          #                       #                       #        
//                                                          #                       #                       #        
//                                                          #                       #                       #        
//                                                          #   # # #               #   # # #               #   # # #
//                                                          #   #   #               #   #   #               #   #   #
//                                                          #   #   #               #   #   #               #   #   #
//                                                          #   #   #               #   #   #               #   #   #
//                                                  # # #   #   # # #       # # #   #   # # #       # # #   #   # # #
//                                                  #   #   #               #   #   #               #   #   #        
//              # # # # #                           #   #   #               #   #   #   # # # # #   #   #   #        
//              #       #                           #   #   #               #   #   #   #       #   #   #   #        
//              # # # # #                           # # #   #               # # #   #   # # # # #   # # #   #        
//                                                          #                       #                       #        
//          # # # # # # # # # # # # #                       #                       # # # # # # # # # # # # #        
//          #                       #                       #                                                        
//          #   # # #   # # # # #   #   # # #               #   # # #                           # # # # #            
//          #   #   #   #       #   #   #   #               #   #   #                           #       #            
//          #   #   #   # # # # #   #   #   #               #   #   #                           # # # # #            
//          #   #   #               #   #   #               #   #   #                                                
//  # # #   #   # # #       # # #   #   # # #       # # #   #   # # #                                                
//  #   #   #               #   #   #               #   #   #                                                        
//  #   #   #               #   #   #               #   #   #                                                        
//  #   #   #               #   #   #               #   #   #                                                        
//  # # #   #               # # #   #               # # #   #                                                        
//          #                       #                       #                                                        
//          #                       #                       #                                                        
//          #                       #                       #                                                        
//          #   # # #               #   # # #               #   # # #                                                
//          #   #   #               #   #   #               #   #   #                                                
//          #   #   #               #   #   #               #   #   #                                                
//          #   #   #               #   #   #               #   #   #                                                
//  # # #   #   # # #       # # #   #   # # #       # # #   #   # # #                                                
//  #   #   #               #   #   #               #   #   #                                                        
//  #   #   #   # # # # #   #   #   #               #   #   #                                                        
//  #   #   #   #       #   #   #   #               #   #   #                                                        
//  # # #   #   # # # # #   # # #   #               # # #   #                                                        
//          #                       #                       #                                                        
//          # # # # # # # # # # # # #                       #                                                        
//                                                          #                                                        
//                      # # # # #                           #   # # #                                                
//                      #       #                           #   #   #                                                
//                      # # # # #                           #   #   #                                                
//                                                          #   #   #                                                
//                                                  # # #   #   # # #                                                
//                                                  #   #   #                                                        
//                                                  #   #   #                                                        
//                                                  #   #   #                                                        
//                                                  # # #   #                                                        
//                                                          #                                                        
//                                                          #                                                        

// $ ./fractal_turtle
// Initial characters (F, f, -, +): F-F-F-F
// Rewriting rule for 'F': F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF
// Rewriting rule for 'f': ffffff
// Number of times to apply the rewriting rules: 1
// Rewrite 0: F-F-F-F
// Rewrite 1: F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF-F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF-F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF-F+f-FF+F+FF+Ff+FF-f+FF-F-FF-Ff-FFF
//              # # # # #                    
//              #       #                    
//              # # # # #                    
//                                           
//          # # # # # # # # # # # # #        
//          #                       #        
//          #   # # #   # # # # #   #   # # #
//          #   #   #   #       #   #   #   #
//          #   #   #   # # # # #   #   #   #
//          #   #   #               #   #   #
//  # # #   #   # # #       # # #   #   # # #
//  #   #   #               #   #   #        
//  #   #   #   # # # # #   #   #   #        
//  #   #   #   #       #   #   #   #        
//  # # #   #   # # # # #   # # #   #        
//          #                       #        
//          # # # # # # # # # # # # #        
//                                           
//                      # # # # #            
//                      #       #            
//                      # # # # #            

#include <stdio.h>
#include <string.h>

#define FALSE 0
#define TRUE 1

#define MAX_LENGTH 16384

#define CHAR_MOVE_FORWARD_PAINT 'F'
#define CHAR_MOVE_FORWARD_NOPAINT 'f'
#define CHAR_TURN_LEFT '+'
#define CHAR_TURN_RIGHT '-'

#define TILE_PAINTED " #"
#define TILE_BLANK "  "

#define DOES_NOT_PAINT -1

////////////////////////////////////////////////////////////////////////////////
// Structs
////////////////////////////////////////////////////////////////////////////////

// Stores a position (row, col) pair. Used for location.
struct position {
    int row;
    int col;
};

// Stores a vector (x, y) pair. Used for direction.
struct vector {
    int x;
    int y;
};

// Object to represent a turtle by their position and direction
struct turtle {
    struct position position;
    struct vector direction;
};

// Object to represent a canvas over which a turtle walks/paints 
struct canvas {
    int is_minmax_initialised;
    struct position min;
    struct position max;
    int height;
    int width;
};


////////////////////////////////////////////////////////////////////////////////
// Function Prototypes
////////////////////////////////////////////////////////////////////////////////

void rewrite_string_n_times(
    char source[MAX_LENGTH],
    char dest[MAX_LENGTH],
    char letter_1, char rule_1[MAX_LENGTH],
    char letter_2, char rule_2[MAX_LENGTH],
    int n
);
void rewrite_string(
    char source[MAX_LENGTH],
    char dest[MAX_LENGTH],
    char letter_1, char rule_1[MAX_LENGTH],
    char letter_2, char rule_2[MAX_LENGTH]
);
void draw_turtle_interpretation_of_string(char string[MAX_LENGTH]);
struct turtle new_turtle(void);
struct canvas update_canvas_minmax(struct canvas canvas, struct turtle turtle);
struct turtle move_turtle_n_steps(struct turtle turtle, int n);
struct turtle turn_turtle_left(struct turtle turtle);
struct turtle turn_turtle_right(struct turtle turtle);
int turtle_paints_point(char string[MAX_LENGTH], int row, int col);


////////////////////////////////////////////////////////////////////////////////
// Main Function
////////////////////////////////////////////////////////////////////////////////

// Reads inputs, rewrites a string, then draws its turtle interpretation.
int main(void) {
    printf("Initial characters (F, f, -, +): ");
    char initial_string[MAX_LENGTH];
    fgets(initial_string, MAX_LENGTH, stdin);
    initial_string[strlen(initial_string) - 1] = '\0';

    printf("Rewriting rule for '%c': ", CHAR_MOVE_FORWARD_PAINT);
    char rule_1[MAX_LENGTH];
    fgets(rule_1, MAX_LENGTH, stdin);
    rule_1[strlen(rule_1) - 1] = '\0';

    printf("Rewriting rule for '%c': ", CHAR_MOVE_FORWARD_NOPAINT);
    char rule_2[MAX_LENGTH];
    fgets(rule_2, MAX_LENGTH, stdin);
    rule_2[strlen(rule_2) - 1] = '\0';

    printf("Number of times to apply the rewriting rules: ");
    int n = 0;
    scanf("%d", &n);

    char final_string[MAX_LENGTH];
    rewrite_string_n_times(
        initial_string,
        final_string,
        CHAR_MOVE_FORWARD_PAINT, rule_1,
        CHAR_MOVE_FORWARD_NOPAINT, rule_2,
        n
    );

    draw_turtle_interpretation_of_string(final_string);

    return 0;
}


////////////////////////////////////////////////////////////////////////////////
// Fuction Definitions
////////////////////////////////////////////////////////////////////////////////

// Rewrites the 'source' string 'n' times by repeatedly replacing each instance
// of char 'letter_X' with string 'rule_X', leaving the result in 'dest'.
//
// Note: this function overwrites the original 'source' string.
void rewrite_string_n_times(
    char source[MAX_LENGTH],
    char dest[MAX_LENGTH],
    char letter_1, char rule_1[MAX_LENGTH],
    char letter_2, char rule_2[MAX_LENGTH],
    int n
) {
    printf("Rewrite 0: %s\n", source);

    int count = 0;
    while (count < n) {
        if (count % 2 == 0) {
            rewrite_string(source, dest, letter_1, rule_1, letter_2, rule_2);
            printf("Rewrite %d: %s\n", count + 1, dest);
        } else {
            rewrite_string(dest, source, letter_1, rule_1, letter_2, rule_2);
            printf("Rewrite %d: %s\n", count + 1, source);
        }
        count++;
    }

    if (n % 2 == 0) {
        strncpy(dest, source, MAX_LENGTH);
    }
}


// Rewrites a string once by copying every character of 'source' into 'dest',
// replacing each occurrence of character 'letter_X' with string 'rule_X'.
void rewrite_string(
    char source[MAX_LENGTH],
    char dest[MAX_LENGTH],
    char letter_1, char rule_1[MAX_LENGTH],
    char letter_2, char rule_2[MAX_LENGTH]
) {
    int rule_1_length = strlen(rule_1);
    int rule_2_length = strlen(rule_2);

    int j = 0;
    char c;
    for (int i = 0; (c = source[i]) != '\0'; i++) {
        if (c == letter_1) {
            if (j + rule_1_length >= MAX_LENGTH) {
                printf("Warning: string exceeds maximum allowable length\n");
                return;
            }
            strcpy(dest + j, rule_1);
            j += rule_1_length;
        } else if (c == letter_2) {
            if (j + rule_2_length >= MAX_LENGTH) {
                printf("Warning: string exceeds maximum allowable length\n");
                return;
            }
            strcpy(dest + j, rule_2);
            j += rule_2_length;
        } else {
            dest[j] = c;
            j++;
        } 
    }

    dest[j] = '\0';
}


// Given a 'string', draw the turtle interpretation.
//
// The turtle interpretation is as follows:
//  - Initially, the turtle faces up towards the top of screen
//  - An 'F' means "move forwards 2 tiles, painting a line segment"
//  - An 'f' means "move forwards 2 tiles, without painting anything"
//  - A '+' means "turn left 90 degrees"
//  - A '-' means "turn right 90 degrees"
//  - Any other character in the 'string' is simply ignored/skipped
void draw_turtle_interpretation_of_string(char string[MAX_LENGTH]) {
    // initialise turtle and canvas
    struct turtle turtle = new_turtle();
    struct canvas canvas;
    canvas.is_minmax_initialised = FALSE;

    // walk through the turtle's path to find the required canvas size
    int i = 0;
    char c;
    while ((c = string[i]) != '\0') {
        if (c == CHAR_MOVE_FORWARD_PAINT) {
            canvas = update_canvas_minmax(canvas, turtle);
            turtle = move_turtle_n_steps(turtle, 1);
            canvas = update_canvas_minmax(canvas, turtle);
            turtle = move_turtle_n_steps(turtle, 1);
            canvas = update_canvas_minmax(canvas, turtle);
        } else if (c == CHAR_MOVE_FORWARD_NOPAINT) {
            turtle = move_turtle_n_steps(turtle, 2);
        } else if (c == CHAR_TURN_LEFT) {
            turtle = turn_turtle_left(turtle);
        } else if (c == CHAR_TURN_RIGHT) {
            turtle = turn_turtle_right(turtle);
        }

        i++;
    }

    // calculate values required to paint turtle path on the terminal
    canvas.height = canvas.max.row - canvas.min.row + 1;
    canvas.width = canvas.max.col - canvas.min.col + 1;
    int row_offset = canvas.min.row;
    int col_offset = canvas.min.col;

    // draw turtle interpretation of 'string' to the terminal, row-by-row
    for (int row = 0; row < canvas.height; row++) {
        for (int col = 0; col < canvas.width; col++) {
            // check if turtle paints the point
            int turtle_paint = turtle_paints_point(
                string,
                row + row_offset,
                col + col_offset
            );
            if (turtle_paint == DOES_NOT_PAINT) {
                printf(TILE_BLANK);
            } else {
                printf(TILE_PAINTED);
            }
        }
        printf("\n");
    }
}


// Returns a new turtle:
//  - positioned at row/col (0, 0), and
//  - initially, the turtle faces up towards the top of the terminal/screen.
struct turtle new_turtle(void) {
    struct turtle turtle;
    turtle.position.row = 0;
    turtle.position.col = 0;
    turtle.direction.x = 0;
    turtle.direction.y = -1;
    return turtle;
};


// Returns a canvas with its minimum and maximum bounds expanded to enclose the
// painted path of the turtle. In other words: if the turtle paints a tile
// outside of the current bounds of the canvas, the canvas size is expanded to
// contain the turtle's path.
//
// If the bounds of the canvas have not yet been initialised, this will be done
// on the first time that this function is called.
struct canvas update_canvas_minmax(struct canvas canvas, struct turtle turtle) {
    if (canvas.is_minmax_initialised == FALSE) {
        canvas.min.row = turtle.position.row;
        canvas.min.col = turtle.position.col;
        canvas.max.row = turtle.position.row;
        canvas.max.col = turtle.position.col;
        canvas.is_minmax_initialised = TRUE;
    } else {
        if (turtle.position.row < canvas.min.row) {
            canvas.min.row = turtle.position.row;
        }
        if (turtle.position.col < canvas.min.col) {
            canvas.min.col = turtle.position.col;
        }
        if (turtle.position.row > canvas.max.row) {
            canvas.max.row = turtle.position.row;
        }
        if (turtle.position.col > canvas.max.col) {
            canvas.max.col = turtle.position.col;
        }
    }

    return canvas;
}


// Returns a turtle, moved by a number_of_steps in its current direction
struct turtle move_turtle_n_steps(struct turtle turtle, int number_of_steps) {
    turtle.position.row += (turtle.direction.y * number_of_steps);
    turtle.position.col += (turtle.direction.x * number_of_steps);
    return turtle;
}


// Returns a turtle, turned left from its original direction
struct turtle turn_turtle_left(struct turtle turtle) {
    struct vector old_direction = turtle.direction;
    turtle.direction.x = old_direction.y;
    turtle.direction.y = -old_direction.x;
    return turtle;
}


// Returns a turtle, turned right from its original direction
struct turtle turn_turtle_right(struct turtle turtle) {
    struct vector old_direction = turtle.direction;
    turtle.direction.x = -old_direction.y;
    turtle.direction.y = old_direction.x;
    return turtle;
}


// Given a string, returns TRUE if a turtle interpretation would paint the tile
// located at (row, col), otherwise DOES_NOT_PAINT (i.e. normally -1).
int turtle_paints_point(char string[MAX_LENGTH], int row, int col) {
    struct turtle turtle = new_turtle();

    int i = 0;
    char c;
    while ((c = string[i]) != '\0') {
        if (c == CHAR_MOVE_FORWARD_PAINT) {
            if (turtle.position.row == row && turtle.position.col == col) {
                return TRUE;
            }
            turtle = move_turtle_n_steps(turtle, 1);
            if (turtle.position.row == row && turtle.position.col == col) {
                return TRUE;
            }
            turtle = move_turtle_n_steps(turtle, 1);
            if (turtle.position.row == row && turtle.position.col == col) {
                return TRUE;
            }
        } else if (c == CHAR_MOVE_FORWARD_NOPAINT) {
            turtle = move_turtle_n_steps(turtle, 2);
        } else if (c == CHAR_TURN_LEFT) {
            turtle = turn_turtle_left(turtle);
        } else if (c == CHAR_TURN_RIGHT) {
            turtle = turn_turtle_right(turtle);
        }

        i++;
    }

    return DOES_NOT_PAINT;
}

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 5 Monday 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.