The idea of this program was to challenge understanding of C, the objective of this program is to convert a Mayan Date to a Gregorian date (given the date is after Jan 2000). The way the code achieves this is by implementing a sort of division by repeated subtraction. We cannot do a division due to the subtraction not being constant due to edge cases such as leap years and non-constant month lengths. We also take advantage of 2 structs to use as data structures as it makes the most sense Problem from: Olympiad
/*
Mayan Calendar
Description: Conversion between the Mayan Calendar and Gregorian Calendar
Author: Kieran Grayshon
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// https://www.mayaarchaeologist.co.uk/public-resources/maya-calendar-converter-long-count/
struct Mayan{
int baktun;
int katun;
int tun;
int uinal;
int kin;
};
struct Date{
int year;
int month;
int day;
char* day_name;
};
/**
* mayan_to_gregorian:Converts Mayan date to Gregorian date
*
* @param: date as a pointer to a Mayan struct defined above
*
*/
struct Date mayan_to_gregorian(struct Mayan* date){
//Day names in this order due to offset as 1st Jan 2000 is a Saturday
const char day_names[7][3]={"sat", "sun", "mon", "tue", "wed", "thu", "fri"};
const char month_names[12][3]={"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
int month_lengths[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int jan_2000=1728000+136800+2160+300+2; //Number of kins in 1st Jan 2000
//Convert the Mayan date into days
int days=(date->baktun)*144000+(date->katun)*7200+(date->tun)*360+(date->uinal)*20+date->kin;
int difference=days-jan_2000; //Find number of days between the date and "anchor" date
//Get setup to store the result
struct Date result;
//Calculate the day by dividing my days in a week
result.day_name=malloc(3);
strncpy(result.day_name, day_names[difference%7], 3);
int year=0;
int month=0;
int day=0;
/*
Algorithm works by:
Take away from the number of days until a subtraction
makes the difference go negative
This is now the remainder and we move down to the next level
and repeat
*/
int days_per_year=365;
while(1){
days_per_year=(year%4==0)?366:365;
if(difference-days_per_year<0){
break;
}
difference-=days_per_year;
year++;
}
int days_per_month;
if(year%4==0){month_lengths[1]=29;}
while(1){
days_per_month=month_lengths[month];
if(difference-days_per_month<0){
break;
}
difference-=days_per_month;
month++;
}
month++;
day=difference+1;
result.year=year+2000;
result.month=month;
result.day=day;
return result;
}
int main(){
//Setup the test date and run the program
//Print out the result
struct Mayan* test=malloc(sizeof(struct Mayan));
//Wednesday 12th Oct 2022
test->baktun=13;
test->katun=0;
test->tun=9;
test->uinal=17;
test->kin=2;
struct Date result=mayan_to_gregorian(test);
free(test);
printf("%s %i %i %i\n", result.day_name, result.day, result.month, result.year);
return 0;
}