U : Mayan Calendar

21Dec12

I recently participated in the Advent Programming Contest organised by the IEEE Student Branch Klagenfurt (with support from Alpen-Adria-Universität Klagenfurt and Universität Passau), achieving a rank of 11th (out of 118 participants); as submissions of solutions to that contest are now closed, I’m posting here the solutions I submitted to that contest.

Problem (U; hard difficulty):

Mayan Calendar

The Mayan Calendar actually consists of three separate calendars which are used simultaneously: The Haab (civil calendar), the Tzolkin (divine calendar) and the Long Count. The Long Count was used to track long periods of time. All three calendars are cyclic, whereas the Long Count has the largest period of 1872000 days. Today we have Mayan Long Count date 13.0.0.0.0. The Long Count date is calculated by counting the number of days from the creation date corresponding to August 11, 3114 BC. The Long Count format is “Baktun.Katun.Tun.Uinal.Kin” where the numbers correspond to the following units:

  • Kin = 1 Day, numbered from 0 to 19
  • Uinal = 20 kin = 20 days, numbered from 0 to 17
  • Tun = 18 uinal = 360 days, numbered from 0 to 19
  • Katun = 20 tun = 360 uinal = 7,200 days, , numbered from 0 to 19
  • Baktun = 20 katun = 400 tun = 7,200 uinal = 144,000 days, numbered from 0 to 19

A common misunderstanding is that the mayan calender (and with it, the world) would cease to exist with the present day. However, there will be only a new Baktun starting with today.

Problem

Implement a date converter from a Gregorian Calendar date to a Mayan calendar date. The dates in the Gregorian calendar will be given in the format

day month year

for example “21 December 2012”. Your program should read a date from the standard input, convert it to the Mayan Calendar and print the corresponding Mayan date (followed by newline). The dates given will range between “15 October 1582” and “31 December 2050”. If you program reads a line with the string “end”, not the world, but your program should end.

Example

Input

22 December 2012
14 July 1789
end

Output

13.0.0.0.1
12.8.13.5.11

Solution (U.c):

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

typedef struct t_CharStackNode_struct
{
  struct t_CharStackNode_struct *m_down;
  char m_char;
}
t_CharStackNode;

typedef enum
{
  false = 0,
  true
}
bool;

static t_CharStackNode *g_charStack_top = NULL;
static int g_charStack_int = 0;
static bool g_charStack_errorOccurredConvertingContentToInt = true;
static size_t g_charStack_length = 0;

void p_CharStack_Reset( void );
void p_CharStack_Input( FILE *p_file, const char p_terminator, char *p_terminatedBy );
bool f_CharStack_Empty( void );
void p_CharStack_ConvertContentToInt( void );
bool f_CharStack_ErrorOccurredConvertingContentToInt( void );
int f_CharStack_Int( void );
char *f_CharStack_String( void );

bool f_IsLeapYear( int p )
{
  if(( p % 4 ) == 0 )
  {
    if(( p % 100 ) == 0 )
    {
      if(( p % 400 ) == 0 )
        return true;
      return false;
    }
    return true;
  }
  return false;
}

double f_GregorianToJulian( const int p_day, const int p_month, const int p_year )
{
  const double k_GREGORIAN_EPOCH = 1721425.5;
  double d = k_GREGORIAN_EPOCH - 1;
  d += ( 365 * ( p_year - 1 ));
  d += ( int )(( p_year - 1 ) / 4.0 );
  d -= ( int )(( p_year - 1 ) / 100.0 );
  d += ( int )(( p_year - 1 ) / 400.0 );
  d += ( int )((( 367 * p_month ) - 362 ) / 12.0 );
  if( p_month > 2 )
  {
    if( f_IsLeapYear( p_year ))
      d -= 1;
    else
      d -= 2;
  }
  d += p_day;
  return d;
}

#define M_STRING_TO_MONTH( p_string, p_int ) \
  if( strcmp( s, p_string ) == 0 )           \
    month = p_int;

int main( void )
{
  char c, *s;
  int day, month, year;
  double d;
  const double k_MAYAN_EPOCH = 584282.5;
  int i;
  l_LOOP:
    p_CharStack_Input( stdin, ' ', &c );
    if( c == '\n' )
    {
      s = f_CharStack_String();
      if( strcmp( s, "end" ) != 0 )
        return -1;
      return 0;
    }
    p_CharStack_ConvertContentToInt();
    if( f_CharStack_ErrorOccurredConvertingContentToInt())
      return -1;
    day = f_CharStack_Int();
    if( day < 1 )
      return -1;

    p_CharStack_Input( stdin, ' ', &c );
    if( c != ' ' )
      return -1;
    s = f_CharStack_String();
    month = -1;
    M_STRING_TO_MONTH( "January", 1 )
    M_STRING_TO_MONTH( "February", 2 )
    M_STRING_TO_MONTH( "March", 3 )
    M_STRING_TO_MONTH( "April", 4 )
    M_STRING_TO_MONTH( "May", 5 )
    M_STRING_TO_MONTH( "June", 6 )
    M_STRING_TO_MONTH( "July", 7 )
    M_STRING_TO_MONTH( "August", 8 )
    M_STRING_TO_MONTH( "September", 9 )
    M_STRING_TO_MONTH( "October", 10 )
    M_STRING_TO_MONTH( "November", 11 )
    M_STRING_TO_MONTH( "December", 12 )
    if( month == -1 )
      return -1;
    free( s );

    p_CharStack_Input( stdin, '\n', &c );
    p_CharStack_ConvertContentToInt();
    if( f_CharStack_ErrorOccurredConvertingContentToInt())
      return -1;
    year = f_CharStack_Int();

    {
      const int numberOfDaysInMonth[ 12 ] = { 31, ( !f_IsLeapYear( year ))?28:29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
      if( day > numberOfDaysInMonth[ month - 1 ] )
        return -1;
      if(( year < 1582 )
        || (( year == 1582 ) && ( month < 10 ))
        || (( year == 1582 ) && ( month == 10 ) && ( day < 15 )))
        return -1;
      if( year > 2050 )
        return -1;
    }

    d = f_GregorianToJulian( day, month, year );
    d -= k_MAYAN_EPOCH;
    i = d;
    int baktun = i / 144000;
    i -= ( baktun * 144000 );
    int katun = i / 7200;
    i -= ( katun * 7200 );
    int tun = i / 360;
    i -= ( tun * 360 );
    int uinal = i / 20;
    i -= ( uinal * 20 );
    int kin = i;
    printf( "%d.%d.%d.%d.%d\n", baktun, katun, tun, uinal, kin );
    goto l_LOOP;
}

static void p_CharStack_Delete( t_CharStackNode *p )
{
  if( p != NULL )
  {
    p_CharStack_Delete( p->m_down );
    free( p );
  }
}

void p_CharStack_Reset( void )
{
  p_CharStack_Delete( g_charStack_top );
  g_charStack_top = NULL;
  g_charStack_int = 0;
  g_charStack_errorOccurredConvertingContentToInt = true;
  g_charStack_length = 0;
}

void p_CharStack_Input( FILE *p_file, const char p_terminator, char *p_terminatedBy )
{
  char c;
  t_CharStackNode *n;
  p_CharStack_Reset();
  do
  {
    fscanf( p_file, "%c", &c );
    if(( c != p_terminator ) && ( c != '\n' ))
    {
      n = ( t_CharStackNode* )malloc( sizeof( t_CharStackNode ));
      n->m_down = g_charStack_top;
      g_charStack_top = n;
      n->m_char = c;
      if( g_charStack_length < ( size_t )-2 )
        g_charStack_length ++;
    }
  }
  while(( c != p_terminator ) && ( c != '\n' ));
  *p_terminatedBy = c;
}

bool f_CharStack_Empty( void )
{
  return ( g_charStack_top == NULL );
}

void p_CharStack_ConvertContentToInt( void )
{
  if( f_CharStack_Empty())
    g_charStack_errorOccurredConvertingContentToInt = true;
  else
  {
    t_CharStackNode *n = g_charStack_top;
    int multiplier = 1;
    g_charStack_int = 0;
    g_charStack_errorOccurredConvertingContentToInt = false;
    do
    {
      if(( n->m_char >= '0' ) && ( n->m_char <= '9' ))
      {
        g_charStack_int += (( n->m_char - '0' ) * multiplier );
        n = n->m_down;
        multiplier *= 10;
      }
      else
        g_charStack_errorOccurredConvertingContentToInt = true;
    }
    while(( n != NULL ) && ( !g_charStack_errorOccurredConvertingContentToInt ));
  }
}

bool f_CharStack_ErrorOccurredConvertingContentToInt( void )
{
  return g_charStack_errorOccurredConvertingContentToInt;
}

int f_CharStack_Int( void )
{
  return g_charStack_int;
}

char *f_CharStack_String( void )
{
  size_t i = 0, k = g_charStack_length - 1;
  t_CharStackNode *n = g_charStack_top;
  char *s = ( char* )malloc( sizeof( char ) * ( g_charStack_length + 1 ));
  for( ; i < g_charStack_length; i ++, k --, n = n->m_down )
    s[ k ] = n->m_char;
  s[ i ] = '\0';
  return s;
}

Testing:

gcc -std=c99 -Wall -lm U.c
mv a.out U
./U
22 December 2012
13.0.0.0.1
14 July 1789
12.8.13.5.11
end
Advertisements


No Responses Yet to “U : Mayan Calendar”

  1. Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: