#include <stdio.h>
#include <math.h>
#include <time.h>

/* 数字と曜日の対応 */
char week[][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

/* 関数のプロトタイプ宣言 */
void weekcount(int, int, int);
int zeller(int, int, int);
int doomsday(int, int, int);
int max(int*);
int thisyear(void);

int main(){

  /* 今年の取得 */
  int now = thisyear();

  /* Zellerで */
  printf("Zeller:\n");
  weekcount(now - 400 + 1, now, 1);
  weekcount(1, 2015, 1);
  weekcount(now - 10000 + 1, now, 1);
  weekcount(now - 100000 + 1, now, 1);

  /* Doomsdayで */
  printf("\nDoomsday:\n");
  weekcount(now - 400 + 1, now, 0);
  weekcount(1, 2015, 0);
  weekcount(now - 10000 + 1, now, 0);
  weekcount(now - 100000 + 1, now, 0);

  return 0;
}

/* start年からend年までの13日の曜日をカウントして表示する */
/* is_zeller が1ならzellerで，0ならdoomsdayで曜日を求める */
void weekcount(int start, int end, int is_zeller){
  int i,y,m;
  int cnt[7]={0}; /* 各曜日の回数 */

  /* 曜日のカウント */
  for(y=start; y<=end; y++){
    for(m=1; m<=12; m++){
      if(is_zeller){
        cnt[zeller(y, m, 13)]++;
      }else{
        cnt[doomsday(y, m, 13)]++;
      }
    }
  }

  /* 最も多い曜日を調べる */
  int m_cnt = max(cnt);

  /* 結果の表示 */
  printf("From %d To %d,\n", start, end);
  for(i=0; i<7; i++){
    if(cnt[i] == m_cnt){
      printf(" %s : %d (Most) \n", week[i], cnt[i]);
    }else{
      printf(" %s : %d \n", week[i], cnt[i]);
    }
  }

}

/* cnt[0]〜cnt[6]で最も大きい数を返す */
int max(int* cnt){
  int i;
  int m = cnt[0];

  for(i=1; i<7; i++){
    if(cnt[i] > m){
      m = cnt[i];
    }
  }
  return m;
}

/* Zellerの公式でy年m月d日の曜日を返す */
int zeller(int y, int m, int d){
  if(m<=2){
    /* 1,2月は昨年の13,14月と考える */
    y--;
    m+=12;
  }
  /* Zellerの公式 */
  int C = (int)floor(y/100.0);
  int Y = y - 100*C;
  int Gamma = -2*C + (int)floor(C/4.0);
  int h = (d + (int)floor(26.0*(m+1)/10) + Y 
             + (int)floor(Y/4.0) + Gamma) % 7;
  h = (h+6)%7;  //0が日曜日になるよう修正
  return h;
}

/* Doomsdayでy年m月d日の曜日を返す */
int doomsday(int y, int m, int d){
  /* Doomsdayの定義 */
  int doomsday[12] = {3, 28, 0, 4, 9, 6, 11, 8, 5, 10, 7, 12};

  /* うるう年は，1，2月のdoomsdayが一日ずれる */
  if(y%4 == 0 && (y%100 != 0 || y%400 == 0)){
    doomsday[0]++;
    doomsday[1]++;
  }

  /* Doomsdayの曜日を調べる */
  int day_of_the_doomsday = 2 + y + (int)floor(y/4.0) 
                    - (int)floor(y/100.0) + (int)floor(y/400.0);

  /* 最寄のDoomsdayとの差から曜日を求める */
  int h = (day_of_the_doomsday + d - doomsday[m-1]) % 7;
  h = (h+7)%7;  //負のmodについての修正
  return h;
}

/* 今年の取得 */
int thisyear(){
  time_t timer = time(NULL);
  return 1900 + localtime(&timer) -> tm_year;
}
