マヤ文明の数字(マヤ数字)を生成する

#はじめに
今回は**マヤ数字**についてお話していきます。

#マヤ数字とは
(マヤ文字って美しいですよね)
**マヤ数字**とは**マヤ文明**で使われていた数字です。

私たちが一般に使っているのは、
10個の記号を使って数字を表す**"十進法"**ですが
(10個の記号: 0123456789)

**マヤ数字**は
20個の記号を使って数字を表す**"二十進法"**なんです！
(20個の記号: 𝋠𝋡𝋢𝋤𝋥𝋦𝋧𝋨𝋩𝋪𝋪𝋫𝋬𝋭𝋮𝋯𝋰𝋱𝋲𝋳)
※比較的最新の環境でないと上記のマヤ数字がみられません。

もっと詳細にいうと
**"十進法"**は**10** を底とし、底およびその冪を基準にして数を表す方法
**"二十進法"**は**20** を底とし、底およびその冪を基準にして数を表す方法
です。

**マヤ数字**のすごいところは**"0"**を表す記号があることですね。
古代から数字を発明し、暦の計算に使っていた**マヤ人**はすごいです。


###マヤ数字の0
![0](https://qiita-image-store.s3.amazonaws.com/0/213065/8f21fc05-dc5e-0580-4626-1cd9c5c1512a.png)

###マヤ数字
[![MayaNumber](https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Maya.svg/248px-Maya.svg.png)](https://en.wikipedia.org/wiki/Maya_numerals)

横棒は5ずつ増えます。

[![MayaNumber](https://upload.wikimedia.org/wikipedia/commons/thumb/c/c2/Maya_add.png/210px-Maya_add.png)](https://en.wikipedia.org/wiki/Maya_numerals)
[![MayaNumber](https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Mayan_subtract.png/210px-Mayan_subtract.png)](https://en.wikipedia.org/wiki/Maya_numerals)

#数値からマヤ数字へ変換

```cpp:MayaGlyph.hpp
#pragma once
#include <iostream>
#include <vector>

namespace maya {

	//通常の数字をマヤ数字に変換する
	template <typename NormalNum, typename MayaNum>
	void mayaNumber(NormalNum num_, std::vector<MayaNum>& maya_num_) {
		//各位の上限値
		constexpr NormalNum num_20 = (NormalNum)20;
		constexpr NormalNum num_18 = (NormalNum)18;
		constexpr NormalNum num_0 = (NormalNum)0;
		//要素を消去
		maya_num_.clear();
		//元の数字が0以下の場合
		if (num_ <= num_0) {
			maya_num_.emplace_back((MayaNum)0);
			return;
		}
		//1桁目を選定 (0~19)
		maya_num_.emplace_back((MayaNum)(num_ % num_20));
		if ((num_ /= num_20) == 0) return;
		//2桁目を選定 (0~17)
		maya_num_.emplace_back((MayaNum)(num_ % num_18));
		if ((num_ /= num_18) == 0) return;
		//3桁目以降を選定 (0~19)
		while (true) {
			maya_num_.emplace_back((MayaNum)(num_ % num_20));
			if ((num_ /= num_20) == 0) return;
		}
	}
	template <typename MayaNum>
	void mayaNumber(const float num_, std::vector<MayaNum>& maya_num_) {
		mayaNumber((unsigned long long)num_, maya_num_);
	}
	template <typename MayaNum>
	void mayaNumber(const double num_, std::vector<MayaNum>& maya_num_) {
		mayaNumber((unsigned long long)num_, maya_num_);
	}
	template <typename MayaNum>
	void mayaNumber(const long double num_, std::vector<MayaNum>& maya_num_) {
		mayaNumber((unsigned long long)num_, maya_num_);
	}
	//マヤ数字を出力する
	template <typename MayaNum>
	void mayaNumberOutput(const std::vector<MayaNum>& maya_num_) {
		for (size_t i = 0; i < maya_num_.size(); ++i)
			std::cout << maya_num_[i] << ',';
	}
	template <>
	void mayaNumberOutput(const std::vector<unsigned char>& maya_num_) {
		for (size_t i = 0; i < maya_num_.size(); ++i)
			std::cout << (int)maya_num_[i] << ',';
	}
	template <>
	void mayaNumberOutput(const std::vector<signed char>& maya_num_) {
		for (size_t i = 0; i < maya_num_.size(); ++i)
			std::cout << (int)maya_num_[i] << ',';
	}
	//通常の数字をマヤ数字に変換して出力する
	template <typename NormalNum, typename MayaNum>
	void mayaNumberOutput(const NormalNum& num_, std::vector<MayaNum>& maya_num_) {
		mayaNumber(num_, maya_num_);
		mayaNumberOutput(maya_num_);
	}
	//通常の数字をマヤ数字に変換して出力する
	template <typename NormalNum>
	void mayaNumberOutput(const NormalNum& num_) {
		std::vector<unsigned char> maya_num_;
		mayaNumber(num_, maya_num_);
		mayaNumberOutput(maya_num_);
	}

}
```

まずは手始めにプログラミングしてみました。

###原理

**マヤ数字**は20進法なので**"mayaNumber()"**で20進法へ変換します。
ただし、ここで注意点があります。

**マヤ数字**の下から2桁目は**17**までしかありません。
つまり下から2桁目が最上位になる正の数は**20~359**です。(**20~399**ではありません)
おそらくこの仕様は暦の計算がしやすくなるよう1年の長さ(365日)に近くなるように
考えられたからではないかと思います。

###出力

```cpp:Source.cpp
#include <MayaGlyph.hpp>

int main() {
	maya::mayaNumberOutput(100);
	return 0;
}
```

```:出力結果(元の数字が100の時)
0,5,
```


```:出力結果(元の数字が65536の時)
16,0,2,9,
```

これでデータ上ではマヤ数字の生成ができました！

#マヤ数字を画像として出力する

楽に画像を出力するため、DxLibを使用してコードを書いていきます。

```cpp:Source.cpp
#include <cstdint>
#include <string>
#include <MayaGlyph.hpp>
#include <DxLib.h>

int main()
{
	//マヤ数字を生成
	std::uint64_t num{};
	std::cin >> num;
	std::vector<size_t> maya_num;
	maya::mayaNumber(num, maya_num);
	if (maya_num.size() < 2) return 0;

	DxLib::SetOutApplicationLogValidFlag(0);
	DxLib::ChangeWindowMode(1);
	DxLib::SetGraphMode(1, 1, 32);
	if (DxLib::DxLib_Init() == -1) return -1;

	//数字の画像を読み込む
	constexpr size_t array_num = 20;
	int num_texture[array_num];
	for (size_t i = 0; i < array_num; ++i)
		num_texture[i] = DxLib::LoadGraph(std::string(std::to_string(i) + ".png").c_str(), 1);
	//画像サイズを元に作成する画像のサイズを決める
	int size_x, size_y;
	if (DxLib::GetGraphSize(num_texture[0], &size_x, &size_y) == -1) return -1;
	const int window_size_y = size_y * (int)maya_num.size();
	int screen = DxLib::MakeScreen(size_x, window_size_y, 1);

	DxLib::SetDrawScreen(screen);
	DxLib::ClearDrawScreen();
	for (size_t i = 0; i < maya_num.size(); ++i)
		DxLib::DrawExtendGraph(0, window_size_y - (size_y*(int)i + size_y), size_x, window_size_y - size_y * (int)i, num_texture[maya_num[i]], 1);
	//PNG形式で画像保存
	DxLib::SaveDrawScreenToPNG(0, 0, size_x, size_y*(int)maya_num.size(), std::string(std::to_string(num) + ".png").c_str(), 0);
	//終了処理
	DxLib::DxLib_End();
	return 0;
}
```

##使用例

###"100"のマヤ数字
![100.png](https://qiita-image-store.s3.amazonaws.com/0/213065/8032441a-8fee-dd0d-579c-87fd98cd0563.png)

###"360"のマヤ数字

![360.png](https://qiita-image-store.s3.amazonaws.com/0/213065/7d86edb1-c986-8e7b-874c-8b7971057d05.png)

###"65536"のマヤ数字

![65536.png](https://qiita-image-store.s3.amazonaws.com/0/213065/fa72282c-9814-357b-90b8-5fc43c477182.png)

###"1000000000000"(1兆)のマヤ数字

![1000000000000.png](https://qiita-image-store.s3.amazonaws.com/0/213065/c0648d09-bb34-6039-9a3c-783cc0cf40ee.png)

###"10000000000000000"(1京)のマヤ数字

手書きの**マヤ数字**を出力してみました。

![10000000000000000.png](https://qiita-image-store.s3.amazonaws.com/0/213065/21c9744f-6ce3-dfd9-c3bd-affe2f23b275.png)



#結論

**マヤ数字**っておもしろい！

##ソースコードのライセンス

These codes are licensed under CC0.
[![CC0](https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg "CC0")](http://creativecommons.org/publicdomain/zero/1.0/deed.ja)