Problem:
マヤの大予言

真也君はテレビで「マヤの大予言！2012年で世界が終る？」という番組を見ました。結局、世界が終るかどうかはよくわかりませんでしたが、番組で紹介されていたマヤの「長期暦」という暦に興味を持ちました。その番組では以下のような説明をしていました。

マヤ長期暦は、右の表のような単位からなる、全部で13バクトゥン(187万2000日)で構成される非常に長い暦である。ある計算法では、この暦は紀元前3114年8月11日に始まり2012年12月21日に終わると考えられていて、このため今年の12月21日で世界が終るという説が唱えられている。しかし、13バクトゥンで１サイクルとなり、今の暦が終わったら新しいサイクルに入るだけという考えもある。

１キン＝１日

１ウィナル＝２０キン

１トゥン＝１８ウィナル

１カトゥン＝２０トゥン

１バクトゥン＝２０カトゥン

 

「ぼくの二十歳の誕生日はマヤ暦だと何日になるのかな？」真也君はいろいろな日をマヤ長期暦で表してみたくなりました。

では、真也君の代わりに、西暦とマヤ長期暦とを相互変換するプログラムを作成してください。

入力

入力は複数のデータセットからなる。入力の終わりは#１つの行で示される。各データセットは以下の形式で与えられる。

b.ka.t.w.ki

または

y.m.d

データセットは１つの文字列を含む１行からなる。b.ka.t.w.ki はマヤ長期暦の日付、y.m.d は西暦の日付である。与えられる単位は以下の通りである。

マヤ長期暦

b

バクトゥン

(0 ≤ b< 13)

ka

カトゥン

(0 ≤ ka < 20)

t

トゥン

(0 ≤ t< 20)

w

ウィナル

(0 ≤ w < 18)

ki

キン

(0 ≤ ki < 20)

西暦

y

年

(2012 ≤ y ≤ 10,000,000)

m

月

(1 ≤ m ≤ 12)

d

日

(1 ≤ d ≤ 31)

西暦の日の最大値は、大の月、小の月、うるう年かどうかで変わる(うるう年は 4 の倍数の年のうち、100 で割り切れない年か、400 で割り切れる年である)。マヤ長期暦の日付の範囲は 0.0.0.0.0 から 12.19.19.17.19 までとする。ただし、マヤ長期暦の 0.0.0.0.0 は西暦の 2012.12.21 に対応する。また、西暦の日付の範囲は 2012.12.21から 10000000.12.31 までとする。

データセットの数は 500 を超えない。

出力

入力が西暦のときはマヤ長期暦を、マヤ長期暦のときは西暦を、それぞれ入力と同じ形式で出力する。
入力された西暦を換算した結果、マヤ長期暦の次のサイクルに入った場合でも b.ka.t.w.ki の形式で出力してよい。

入力例

2012.12.31
2.12.16.14.14
7138.5.13
10.5.2.1.5
10000000.12.31
#

出力例

0.0.0.0.10
3054.8.15
0.0.0.0.10
6056.2.29
8.19.3.13.2

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace _0261
{
    class Program
    {

        static readonly int[] DaysToMonth365 = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
        static readonly int[] DaysToMonth366 = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };

        static readonly DateTime BaseDate = new DateTime(2012, 12, 21);
        static readonly long[] MayaUnit = new long[] { 20, 20, 18, 20, 1 };
        static readonly int MayaCycle = 13;

        static void Main(string[] args)
        {

            while (true)
            {
                string s = RSt();
                if (s == "#") break;

                long[] vs = Array.ConvertAll(s.Split('.'), e => long.Parse(e));
                Console.WriteLine(vs.Length == 5 ? CalcAd(vs) : CalcMaya(vs));
            }

        }

        private static string CalcAd(long[] vs)
        {
            long days = 0;
            for (int i = 0; i < vs.Length; i++) days = (days + vs[i]) * MayaUnit[i];
            DateTime newDate = BaseDate.AddDays(days);
            return newDate.ToString("yyyy.M.d");
        }

        private static string CalcMaya(long[] vs)
        {
            long days = GetDays(vs[0], vs[1], vs[2]) - GetDays(2012, 12, 21);

            long[] mayaDate = new long[MayaUnit.Length];
            for (int i = MayaUnit.Length - 1; i > 0; i--)
            {
                mayaDate[i] = days % MayaUnit[i - 1];
                days /= MayaUnit[i - 1];
            }
            mayaDate[0] = days % MayaCycle;
            return WAr(mayaDate, ".");
        }

        private static long GetDays(long year, long month, long day)
        {
            int[] days = IsLeapYear(year) ? DaysToMonth366 : DaysToMonth365;
            long y = year - 1;
            long n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day;
            return n;
        }

        private static bool IsLeapYear(long year)
        {
            return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
        }

        static string RSt() { return Console.ReadLine(); }
        static int RInt() { return int.Parse(Console.ReadLine().Trim()); }
        static long RLong() { return long.Parse(Console.ReadLine().Trim()); }
        static double RDouble() { return double.Parse(Console.ReadLine()); }
        static string[] RArSt(char sep = ' ') { return Console.ReadLine().Trim().Split(sep); }
        static int[] RArInt(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Trim().Split(sep), e => int.Parse(e)); }
        static long[] RArLong(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Trim().Split(sep), e => long.Parse(e)); }
        static double[] RArDouble(char sep = ' ') { return Array.ConvertAll(Console.ReadLine().Trim().Split(sep), e => double.Parse(e)); }
        static string WAr<T>(IEnumerable<T> array, string sep = " ") { return string.Join(sep, array.Select(x => x.ToString()).ToArray()); }
    }
}