Codingame『Mayan Calculation』クリア

Image from page 128 of Image from page 128 of "Biologia Centrali-Americana, or, Contributions to the knowledge of the fauna and flora of Mexico and Central America" (1889) / Internet Archive Book Images


 マヤ文明では数は20進法だったらしい。
掛け算を憶える小学生は苦労したに違いない。いないけど。
www.codingame.com

進数変換のやりかた

 例えば、いつも使ってる10進数の数字145。
これを4進数で表現したいとする。


 まずは、心を無にして145を4で割って割って割りまくる。
ただし、0になったら人間性を取り戻して計算をやめる。


145÷4 = 36 余り1
36÷4 = 9 余り 0
9÷4 = 2 余り 1
2÷4 = 0 余り 2


 この結果から、余りを列挙して
145(10進数) = 2101(4進数)となる。

検算

 合ってるかどうかは検算してみればわかる。
2×43 + 1×42 + 0×41 + 1×40
= 2×64 + 1×16 + 0×4 + 1×1
=128 + 16 + 0 + 1
=145
よかった合ってた。
あ、そうそう、この検算方法は4進数を10進数に変える方法でもある。

10進数をマヤ数字(20進数)にする

 4進数が20進数に変わっただけなので、やることは変わらない。
4で割るところを20で割るだけ。

Source code
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;

/**
 * Auto-generated code below aims at helping you parse
 * the standard input according to the problem statement.
 **/
class Solution
{
    static void Main(string[] args)
    {
        MNP mnp = new MNP();
        mnp.main();

        // Write an action using Console.WriteLine()
        // To debug: Console.Error.WriteLine("Debug messages...");
    }

    /// <summary>
    /// マヤ計算問題
    /// </summary>
    class MNP
    {
        //マヤ数字横幅
        private int width;
        //マヤ数字縦幅
        private int height;
        //値とマヤ数字の辞書
        private Dictionary<int, string[]> numbers;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MNP()
        {
            this.numbers = new Dictionary<int, string[]>();

            //マヤ数字のサイズを得る
            this.ReadMayanSize();
            //マヤ数字を読み込んで辞書を作る
            this.ReadMayanNumber();
        }

        /// <summary>
        /// 処理の流れ
        /// </summary>
        public void main()
        {
            //2つの数字を読み込む
            Int64 e1 = this.ReadNumber();
            Int64 e2 = this.ReadNumber();
            //計算する
            Int64 r = this.Operation(e1, e2);
            //結果を出力する
            this.NumberToMayan(r);
        }

        /// <summary>
        /// マヤ数字のサイズを読み込む
        /// </summary>
        private void ReadMayanSize()
        {
            string[] inputs = Console.ReadLine().Split(' ');
            this.width = int.Parse(inputs[0]);
            this.height = int.Parse(inputs[1]);
        }

        /// <summary>
        /// 全マヤ数字を読み込んで辞書を作る
        /// </summary>
        private void ReadMayanNumber()
        {
            //全マヤ数字データを読み込む
            string[] line = new string[this.height];
            for (int i = 0; i < this.height; i++)
            {
                line[i] = Console.ReadLine();
            }

            //0 - 19の数字とマヤ数字を辞書化
            for (int n = 0; n < 20; n++)
            {
                //マヤ数字一つ分を切り出す
                string[] mayanNumber = new string[height];
                for (int i = 0; i < this.height; i++)
                {
                    mayanNumber[i] = line[i].Substring(n * width, width);
                }
                //辞書に加える
                this.numbers[n] = mayanNumber;
            }
        }

        /// <summary>
        /// マヤ数字を読み込む
        /// </summary>
        /// <returns></returns>
        public Int64 ReadNumber()
        {
            //マヤ数字の行数を得る
            int lines = int.Parse(Console.ReadLine());

            //10進数の値
            Int64 num = 0;
            //マヤ数字一つ分
            string[] mayanStrings = new string[this.height];
            //桁
            int digit = lines / this.height;

            //最大桁から始まる
            for (int d = digit - 1; d >= 0; d--)
            {
                //マヤ数字一つ分を読み込む
                for (int i = 0; i < this.height; i++)
                {
                    mayanStrings[i] = Console.ReadLine();
                }

                //マヤ数字の値を調べる
                foreach (var p in numbers)
                {
                    if (p.Value.SequenceEqual(mayanStrings) == true)    //辞書のマヤ数字と同じものがあれば
                    {
                        //20進数なので、20^桁*値 を求める
                        num += p.Key * (int)Math.Pow(20, d);
                        break;
                    }
                }
            }

            return num;
        }

        /// <summary>
        /// 演算子を読み込んで計算する
        /// </summary>
        /// <param name="e1">一項目</param>
        /// <param name="e2">二項目</param>
        /// <returns>計算結果</returns>
        public Int64 Operation(Int64 e1, Int64 e2)
        {
            //演算子を読み込む
            string symbol = Console.ReadLine();

            //処理を選ぶ
            switch (symbol)
            {
                case "+":
                    return e1 + e2;
                case "-":
                    return e1 - e2;
                case "*":
                    return e1 * e2;
                case "/":
                    return e1 / e2;
                default:
                    //どれにも当てはまらなければ-1(一応)
                    return -1;
            }
        }

        /// <summary>
        /// 値をマヤ数字に変換する
        /// </summary>
        /// <param name="n"></param>
        public void NumberToMayan(Int64 n)
        {
            //値が0の場合、0を出力して終了
            if (n == 0)
            {
                foreach (string s in numbers[0])
                {
                    Console.WriteLine(s);
                }
                return;
            }

            //それぞれの桁の値
            List<int> num = new List<int>();

            //余り
            int q;
            //値のコピー
            Int64 p = n;

            //各桁の値を得る
            for (int i = 0; p != 0; i++)
            {
                q = (int)(p % 20);
                p = p / 20;
                num.Add(q);
            }

            //マヤ数字を出力する
            for (int i = num.Count - 1; i >= 0; i--)
            {
                foreach (string s in numbers[num[i]])
                {
                    Console.WriteLine(s);
                }
            }
        }
    }

}


古代マヤ・アステカ不可思議大全

古代マヤ・アステカ不可思議大全