A5P1

 

For thoses who don’t know what a5p1 means, it means Assignment 5, Problem 1.

Yesterday, my professor Jim added a new assignment for us to do. I am going to talk about the first in this article.

I am not a good coder and I just started learning C this term. Still, I am trying to solve the puzzle as best I can. I know it is not a good style to put everything under main(), but since it’s a simple and straightforward problem, please accept my messy style of coding.

You can view the question here. I started writing the first problem this morning and I think I have finished this problem at the noon. (Just before the time I was writing this article.)

If you get a 404 error, that means this term has finished, you can get the problem sets by emailing me.

Things need attention:

1. I need to justify what format the input/output is:

input:
N
Year(%d) Month(%s) Day(%d)
....

output:
Year(%d) Month(%d) Day(%s)

I happened to mixed the order up during programming, but it wasn’t a big deal.

2. It’s important to know that the Highwings calendar count from 0 in day section but Lowwings calendar count start from 1 in month section.

3. Those calendar systems have different days per year. Highwings has 12\times30+20 = 380 days per year and Lowwings has 20\times12=240 days per year, we can write a macro for further use.

#define TOTAL_DAYS_PERYR_HIGHWING (12 * 30 + 20)
#define TOTAL_DAYS_PERYR_LOWWING (20 * 12)

The structure is simple, parse every line until N is reached using a for loop. Using getchar and scanf to read the values from stdin, assign it to corresponding values. Professor has already talked about this in a3p1, we can extract his ideas and implement them into our code.

Why we don’t just parse the whole line all-together using

 scanf("%d %s %D\n", &h_yr, &h_m, &h_d)

You’ll never know what the user is going to type in, therefore the stdin might not be what you expected. This is for error checking which I’ll talk about it later.

When you have all the correct values assigned to correct variables, then how to convert it to Lowwings Calendar system?

What I did was to find the total days, it should be the only thing in common between these 2 systems of calendar, I call the variable unify_day.

Now things are getting clearer.

In this case,

1 charlie 17

charlie is the 3^{rd} month in Year 1, but the 3^{rd} month has not passed, so we only need to count the first 2 months into unify_day, then calculate the day/month/year in Lowwings system.

Finally you need to reset unify_day to 0 at the end of loop.

When you try to divide a number with 12, and if the remainder is 0, it doesn’t mean that it’s the start of next month, it’s the end of the previous month. So I have put zulu first in my string array.

*lowwing_day_names[] = {"zulu", "november", "oscar", "papa", "quebec",
        "romeo", "sierra", "tango", "uniform", "victor", "whiskey", "xray"};

The error detect part, which types of error have I considered?

(a). When N = 0.
(b). When N < next few lines. (When N > next few lines I just ignore the rest)
(c). Invalid data:
   i. When !isdigit(N)
   ii. !isdigit(h_day)
   iii. !isdigit(h_yr)
(d). spaces/tabs as seperator.

Programme ends whenever an error occurs.

/*
 * File:    lightplane.c
 * Author:  Luxing Huang
 * Version: 1.0
 *
 * Purpose:
 * When we have 2 different calendar systems, we need to translate the old one
 * to the new one. 
 *
 * Here we have an old system called Highwings: A year with 13 month, 30 days 
 * for the 1-12th month, and 20 days for the 13th month. We will have 30x12+20
 * = 380 days a year. Every month has its own name.
 *
 * And the second system is 240 days a year. We have 20 months with 12 days in
 * each month. Every day in each month has its own name. This system is called
 * Lowwings.
 *
 * The input format is:
 * N
 * Year(%d) Month(%s) Day(%d)
 *
 * The output format is:
 * Year(%d) Month(%d) Day(%s)
 */
#include 
#include 
#include 
#include 

#define CHAR_LENGTH 128
#define TOTAL_DAYS_PERYR_HIGHWING (12 * 30 + 20)
#define TOTAL_DAYS_PERYR_LOWWING (20 * 12)

int
main(int argc, char *argv[])
{
    /*
     * Structure:
     * 1. scan the input, preferrably using getchar then scanf
     * 2. Convert Highwing days to unify_day.
     * 3. Error detect:
     *  a. N < next a few lines. If > I just ignore the rest.
     *  b. Invalid data:
     *      (a) when it should be a number, it's a char.
     *      (b) after year we have more char rather than \n.
     * 4. Calculate the unify day to Lowwing system.
     */
    unsigned int i, unify_day = 0, highwing_year = 0, highwing_day = 0, 
                 lowwing_year = 0, lowwing_month = 0, lowwing_day = 0;
    int highwing_month = -1, entries = 0, c = 0;
    char highwing_month_name[CHAR_LENGTH] = "";
    char *highwing_compare[] = {"alpha", "bravo", "charlie", "delta", "echo", 
        "foxtrot", "golf", "hotel", "india", "juliet", "kilo", "lima", "mike"},
         *lowwing_day_names[] = {"zulu", "november", "oscar", "papa", "quebec", 
        "romeo", "sierra", "tango", "uniform", "victor", "whiskey", "xray"};
    
    /* Ignoring spaces if have any */
    scanf("%*[ \t]");

    /* check if is a digit */
    c = getchar();
    if (!isdigit(c))
    {
        fprintf(stderr, "You need to put a positive integer in the first " 
                "line!\n");
        return EXIT_FAILURE;
    }
    else
        ungetc(c, stdin);

    scanf("%d", &entries);
    if (entries <= 0)
    {
        fprintf(stdout, "Nothing to calculate!\n");
        return EXIT_SUCCESS;
    }
    else
    {
        /* 
         * Error detect for:
         * N more_char_here
         */
        scanf("%*[ \t]");
        c = getchar();
        if (c == EOF)
        {
            fprintf(stderr, "Where are your next lines?\n");
            return EXIT_FAILURE;
        }
        else if (c != '\n')
        {
            fprintf(stderr, "You should not input anything "
                            "behind %d!\n", entries);
            return EXIT_FAILURE;
        }

        /* We need to have a loop for entries time */
        for (i = 0; i < entries; i++)
        {
            /* We get year first, ignoring spaces */
            scanf("%*[ \t]");
            c = getchar();
            if (c == EOF)
            {
                fprintf(stderr, "Where's the %d(th) set of data?\n", i+1);
                return EXIT_FAILURE;
            }
            else if (!isdigit(c))
            {
                fprintf(stderr, "This is not a valid day!\n");
                return EXIT_FAILURE;
            }
            ungetc(c, stdin);
            scanf("%d", &highwing_year);

            /* Now the name (string) for highwing month */
            int m;
            c = getchar();
            if (c != ' ' && c != '\t')
                fprintf(stderr, "Your input format is wrong but we'll " 
                        "proceed anyway.\n");
            scanf("%*[ \t]");

            scanf("%s", highwing_month_name);
            for (m = 0; m <= 13; m++)
            {
                if (strcmp(highwing_month_name, highwing_compare[m]) == 0)
                {
                    /* Array of strings position start from 0 */
                    highwing_month = m;
                    break;
                }
            }
            if (highwing_month == -1)
            {
                fprintf(stderr, "Invalid month name.\n");
                return EXIT_FAILURE;
            }

            /* 
             * Let's now scan the day
             * First we need to make sure that the first character is a digit.
             */
            c = getchar();
            if (c != ' ' && c != '\t')
                fprintf(stderr, "Your input format is wrong but we'll "
                        "proceed anyway.\n");

            scanf("%*[ \t]");
            c = getchar();
            if (!isdigit(c))
            {
                fprintf(stderr, "Invalid input!\n");
                return EXIT_FAILURE;
            }
            else
                ungetc(c, stdin);

            scanf("%d", &highwing_day);

            if (highwing_day > 29)
            {
                fprintf(stderr, "You shouldn't input more than 30 days!\n");
                return EXIT_FAILURE;
            }
            highwing_day++;

            /* 
             * We need to make sure about the boundary values, 
             * In this case, the last day of mike is 20th
             */
            if (highwing_month == 12 && highwing_day > 20)
            {
                fprintf(stderr, "You cannot input 20 or more in day in " 
                        "Mike!\n");
                return EXIT_FAILURE;
            }

            /* ignoreing the spaces afterwards */
            scanf("%*[ \t]");

            /* Make sure that we have a nextline in the end */
            c = getchar();
            if (!(c == '\n'))
            {
                fprintf(stderr, "Nothing behind %d please!", highwing_day);
                return EXIT_FAILURE;
            }
            /* 
             * Once it is all done, we add the current inputs to unify_day.
             * Every Highwing month has 30 days except the last one.
             */
            unify_day = highwing_year * TOTAL_DAYS_PERYR_HIGHWING + highwing_month * 30
                        + highwing_day;

            /* 
             * From unify_day we need to calculate the year for Lowwing calendar
             */
            lowwing_year = unify_day / TOTAL_DAYS_PERYR_LOWWING;
            unify_day -= lowwing_year * TOTAL_DAYS_PERYR_LOWWING;

            /* We need to have lowwing_month at this point. */
            lowwing_month = unify_day / 12;
            unify_day -= lowwing_month * 12;

            if ((unify_day % 12) == 0)
                lowwing_month--;

            /* Now the day */
            lowwing_day = unify_day;

            printf("Highwings %d %s %d\t is\t Lowwings %d %d %s\n", 
                    highwing_year, highwing_month_name, highwing_day - 1,
                    lowwing_year, lowwing_month + 1, 
                    lowwing_day_names[lowwing_day]);
            
            /* Reset all the values which won't be re-assigned from stdin. */
            unify_day = 0;
        }
    }

    return EXIT_SUCCESS;
}

Leave a comment

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.