C# で扱える最大値は ulong の「18,446,744,073,709,551,615」(1,844京)ですが
基本的にはそんな値いかないと思うので int で実装することが多い
※理想は int よりも uint だが uint を使うと int を使うとキャストする必要があるため面倒
int の場合は最大値が「2,147,483,647」(21億)となり
初期のゲームでは小さい値だったがインフレして 21億超えるなんて簡単に起こり得る
また最近遊んでたペンギンの島では 1000毎にアルファベットのAから単位をつけて、Zまで行くとAAからまた加算されている
ペンギンの島で登場するペンギンは現在9種ですね。小さくて可愛いOOOペンギンとか大きな身長のXXXXペンギン等も登場します🎵各ペンギンは種によって少し違う行動パターンがあるとか?!お楽しみに🐧 pic.twitter.com/W8XO1NirEF
— ペンギンの島 (@Penguin_Isle) August 14, 2019
今回はこの手法を参考に作成してみる
クラス設計
入れ込む値を4桁区切りにして、Listに格納していく 例えば 123456789 の場合
var list = new List<int> { 1, 2345, 6789 }
と格納しておく
加算
下の桁から順に加算していき、上振れたした分を次に繰り越す
減算
下の桁から順に減算していき、結果がマイナスになった場合は一つ上の桁から 10000を借りてくる
コード
上記を踏まえたコードが下記になる
using System; using System.Collections.Generic; using UnityEngine; [Serializable] public class MultiDigit { [SerializeField] private List<ushort> _values; public int this[int digit] => _values[digit]; /// <summary> /// 桁数 /// </summary> public int Digit => _values.Count; /// <summary> /// 最大桁の値 /// </summary> public int MaxDigitValue => Digit <= 0 ? 0 : _values[Digit - 1]; public MultiDigit() { _values = new List<ushort> {0}; } public MultiDigit(List<ushort> values) { _values = new List<ushort>(values); _values.Reverse(); } public MultiDigit(ushort value, int digit = 0) { _values = new List<ushort>(digit + 1); for (int i = 0; i < digit + 1; i++) _values.Add(0); _values[digit] = (ushort) Mathf.Clamp(value, 0, 9999); } public static MultiDigit operator +(MultiDigit a, MultiDigit b) { var n = new MultiDigit { _values = new List<ushort>(a._values) }; if (n.Digit < b.Digit) for (int i = n.Digit; i < b.Digit; i++) n._values.Add(0); ushort over = 0; for (var i = 0; i < b._values.Count; i++) { n._values[i] += (ushort)(b._values[i] + over); if (n._values[i] >= 10000) { over = (ushort) (n._values[i] / 10000); n._values[i] %= 10000; } else { over = 0; } } while (over > 0) { var temp = (ushort)(over % 10000); n._values.Add(temp); over /= 10000; } return n; } public static MultiDigit operator -(MultiDigit a, MultiDigit b) { var n = new MultiDigit { _values = new List<ushort>(a._values) }; if (n.Digit < b.Digit || (n.MaxDigitValue < b.MaxDigitValue && n.Digit == b.Digit)) { Debug.LogError("負の値にはできません"); return n; } short over = 0; ushort bVal = 0; for (var i = 0; i < n.Digit; i++) { bVal = (ushort) (i < b.Digit ? b._values[i] : 0); over = (short) (n._values[i] - bVal + over); if (over > 0) { n._values[i] = (ushort) over; over = 0; } else if (over < 0) { n._values[i] = (ushort) (10000 + over); over = -1; } else { n._values[i] = 0; } } // 先頭0は消す for (var i = n.Digit - 1; i >= 0; i--) if (n[i] <= 0) n._values.RemoveAt(i); return n; } public static bool operator ==(MultiDigit a, MultiDigit b) { if (a._values.Count != b._values.Count) return false; var count = a._values.Count; for (var i = 0; i < count; i++) { if (a._values[i] != b._values[i]) return false; } return true; } public static bool operator !=(MultiDigit a, MultiDigit b) { return !(a == b); } public override bool Equals(object o) { if(o == null) return false; var a = o as MultiDigit; if (a._values.Count != _values.Count) return false; var count = a._values.Count; for (var i = 0; i < count; i++) { if (a._values[i] != _values[i]) return false; } return true; } public override int GetHashCode() { return _values[0] ^ _values.Count; } }
サンプル
ulong の最大値に加算できているので、ulong の最大値を超えていても問題無く動作するようにできた