NivaarExam PrepOfficial exam papers ↗

25-Comp-A4 Program Design and Data Structures · December 2019

Question 1 of 9: Programming — Horoscope Sign and Compatibility

Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)

Notes on this paper

Paper format. 17-Comp-A4 Program Design and Data Structures, December 2019 — 3 hours, closed book, no calculator permitted. Nine questions, each of equal weight (Questions 1, 2, 7 and 8 are split 10+10; Questions 3–6 and 9 are 20 marks each), so 180 marks are printed in total. The cover page directs candidates to answer any six of the nine, and only the first six as they appear in the answer book are marked — so a complete paper is $6\times 20 = 120$ marks, which is the "total mark is out of 120" the paper's Note 6 states. Pseudocode or any high-level language (e.g. C or C++) is accepted, and the examiner's note states explicitly that marking emphasises the operation of the program, not syntactic details. All nine questions are answered below, because the whole set is the more useful revision resource. Answers are given in C or C++ as the question dictates; each is compilable as written, but a clear, correctly reasoned pseudocode answer would earn the same marks.

Reference texts for this subject.

  • Cormen, Leiserson, Rivest & Stein, Introduction to Algorithms, 4th ed. — tree walks (ch. 12), sorting and its complexity (ch. 2, 7), asymptotic analysis (ch. 3).
  • Weiss, Data Structures and Algorithm Analysis in C, 2nd ed. — arrays (ch. 1), linked lists (ch. 3), binary trees (ch. 4), searching and hashing (ch. 5).
  • Deitel & Deitel, C++ How to Program, 10th ed. — class design and operator overloading (ch. 9–11), file streams (ch. 14).
  • Kernighan & Ritchie, The C Programming Language, 2nd ed. — character/file I/O idioms (ch. 1, 7), pointers and structures (ch. 5–6).
  • Stroustrup, The C++ Programming Language, 4th ed. — value semantics, const-correctness and operator overloading (ch. 3, 11).

The Computer Engineering citation list is built around architecture and networking texts (Patterson & Hennessy, Tanenbaum, Mano); this subject is programming and data structures, so the works above are cited instead.

Question 1: Programming — Horoscope Sign and Compatibility (20 marks: (a) 10, (b) 10)

Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.

Given. A birthdate as (month, day); twelve (start, end) date ranges, one per sign, with Capricorn's range wrapping the year boundary (Dec 22 → Jan 19); a fixed grouping of the twelve signs into four 3-sign Elements.

Find. (a) The sign name for a valid birthdate, or an "Invalid birthdate" message. (b) The other two signs sharing that sign's Element.

Approach. Validate the month and day first (day must lie between 1 and that month's length), then scan a table of twelve (sign, start, end) entries with a single "does (month,day) fall in this range" test that treats Capricorn's wraparound as an OR of two conditions instead of a plain interval compare. Part (b) is a second table lookup, sign → Element, followed by printing the other two members of that Element.

(a) Sign lookup with validation (10 marks)

  1. Write the validity check and the range table. A day is valid only against its own month's length; the exam does not ask for leap-year handling, so February is fixed at 29 days here (30/31/29 day-lengths only bound which invalid dates are rejected, and every worked example below falls well inside real dates, so the choice does not affect any sign lookup).

    Check: assumes February has 29 days for the purpose of range-checking day validity (no leap-year test is requested); a stricter 28-day bound would only reject a few extra dates (Feb 29) and does not change any traced example.

    #include <stdio.h>
    #include <string.h>   /* strcmp(), used by part (b) below */
    
    typedef struct {
        const char *name;
        int start_m, start_d, end_m, end_d;
    } SignRange;
    
    static const SignRange SIGNS[12] = {
        {"Capricorn",   12, 22,  1, 19},   /* wraps the year boundary */
        {"Aquarius",     1, 20,  2, 18},
        {"Pisces",       2, 19,  3, 20},
        {"Aries",        3, 21,  4, 19},
        {"Taurus",       4, 20,  5, 20},
        {"Gemini",       5, 21,  6, 21},
        {"Cancer",       6, 22,  7, 22},
        {"Leo",          7, 23,  8, 22},
        {"Virgo",        8, 23,  9, 22},
        {"Libra",        9, 23, 10, 22},
        {"Scorpio",     10, 23, 11, 21},
        {"Sagittarius", 11, 22, 12, 21}
    };
    
    static const int DAYS_IN_MONTH[13] =
        {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    
    int is_valid_date(int month, int day)
    {
        if (month < 1 || month > 12) return 0;
        if (day < 1 || day > DAYS_IN_MONTH[month]) return 0;
        return 1;
    }
    
    /* true if (month,day) falls within [start,end], handling year wraparound */
    int in_range(int month, int day, int sm, int sd, int em, int ed)
    {
        if (sm <= em) {
            if (month < sm || month > em) return 0;
            if (month == sm && day < sd) return 0;
            if (month == em && day > ed) return 0;
            return 1;
        }
        /* wraps December -> January, e.g. Capricorn */
        if (month > sm || month < em) return 1;
        if (month == sm && day >= sd) return 1;
        if (month == em && day <= ed) return 1;
        return 0;
    }
    
    const SignRange *find_sign(int month, int day)
    {
        int i;
        for (i = 0; i < 12; i++)
            if (in_range(month, day, SIGNS[i].start_m, SIGNS[i].start_d,
                                      SIGNS[i].end_m, SIGNS[i].end_d))
                return &SIGNS[i];
        return NULL;   /* unreachable once month/day are validated */
    }
    
    int main(void)
    {
        int month, day;
        printf("Enter birthdate: ");
        if (scanf("%d %d", &month, &day) != 2 || !is_valid_date(month, day)) {
            printf("Invalid birthdate\n");
            return 0;
        }
        printf("Sign is: %s\n", find_sign(month, day)->name);
        return 0;
    }
  2. Trace the paper's own examples. $(10,18)$ is valid (October has 31 days) and falls in Libra's Sep 23–Oct 22 window. $(1,12)$ is valid and falls in Capricorn's wraparound window (month $1 < \text{start month } 12$, so the wraparound branch fires, and day $12 \le 19$ puts it inside the January tail). $(2,30)$ fails validation outright, since February's length is at most 29. $$\boxed{(10,18)\to\text{Libra},\quad (1,12)\to\text{Capricorn},\quad (2,30)\to\text{Invalid birthdate}}$$

(b) Most-compatible signs (10 marks)

  1. Add the Element lookup and print the other two members.
    typedef struct { const char *name; const char *members[3]; } ElementGroup;
    
    static const ElementGroup ELEMENTS[4] = {
        {"FIRE",  {"Aries", "Leo", "Sagittarius"}},
        {"EARTH", {"Taurus", "Virgo", "Capricorn"}},
        {"AIR",   {"Gemini", "Libra", "Aquarius"}},
        {"WATER", {"Cancer", "Scorpio", "Pisces"}}
    };
    
    void print_compatible(const char *sign)
    {
        int g, k;
        for (g = 0; g < 4; g++)
            for (k = 0; k < 3; k++)
                if (strcmp(ELEMENTS[g].members[k], sign) == 0) {
                    printf("Most compatible with: ");
                    int printed = 0, j;
                    for (j = 0; j < 3; j++)
                        if (strcmp(ELEMENTS[g].members[j], sign) != 0) {
                            printf("%s%s", printed ? " and " : "", ELEMENTS[g].members[j]);
                            printed = 1;
                        }
                    printf("\n");
                    return;
                }
    }
    The main program calls print_compatible() right after printing the sign found in part (a).
  2. Trace it on the paper's examples. Libra ($10,18$) is in AIR, so the other two AIR signs are Gemini and Aquarius. Capricorn ($1,12$) is in EARTH, so the other two are Taurus and Virgo. $$\boxed{\text{Libra}\to\{\text{Gemini, Aquarius}\},\quad \text{Capricorn}\to\{\text{Taurus, Virgo}\}}$$
Question 1 — results
Input (month, day)SignMost compatible with
10, 18LibraGemini, Aquarius
1, 12CapricornTaurus, Virgo
2, 30Invalid birthdate—
← Paper overview