zakuro 0.1.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/lib/zakuro/calculation/base/multi_gengou.rb +101 -0
  3. data/lib/zakuro/calculation/base/multi_gengou_roller.rb +218 -0
  4. data/lib/zakuro/calculation/base/year.rb +107 -0
  5. data/lib/zakuro/calculation/cycle/abstract_remainder.rb +484 -0
  6. data/lib/zakuro/calculation/cycle/abstract_solar_term.rb +173 -0
  7. data/lib/zakuro/calculation/cycle/zodiac.rb +106 -0
  8. data/lib/zakuro/calculation/monthly/abstract_lunar_phase.rb +169 -0
  9. data/lib/zakuro/calculation/monthly/first_day.rb +45 -0
  10. data/lib/zakuro/calculation/monthly/initialized_month.rb +125 -0
  11. data/lib/zakuro/calculation/monthly/month.rb +187 -0
  12. data/lib/zakuro/calculation/monthly/month_label.rb +88 -0
  13. data/lib/zakuro/calculation/monthly/operated_month.rb +209 -0
  14. data/lib/zakuro/calculation/range/full_range.rb +210 -0
  15. data/lib/zakuro/calculation/range/medieval_annual_range.rb +105 -0
  16. data/lib/zakuro/calculation/range/operated_range.rb +144 -0
  17. data/lib/zakuro/calculation/range/operated_solar_terms.rb +201 -0
  18. data/lib/zakuro/calculation/range/transfer/western_date_allocation.rb +82 -0
  19. data/lib/zakuro/calculation/range/transfer/year_boundary.rb +146 -0
  20. data/lib/zakuro/calculation/specifier/single_day.rb +109 -0
  21. data/lib/zakuro/calculation/stella/lunar/abstract_location.rb +78 -0
  22. data/lib/zakuro/calculation/stella/lunar/choukei_value.rb +71 -0
  23. data/lib/zakuro/calculation/stella/solar/abstract_average.rb +117 -0
  24. data/lib/zakuro/calculation/stella/solar/abstract_location.rb +187 -0
  25. data/lib/zakuro/calculation/stella/solar/choukei_value.rb +136 -0
  26. data/lib/zakuro/calculation/summary/single.rb +129 -0
  27. data/lib/zakuro/calculation/type/old_float.rb +69 -0
  28. data/lib/zakuro/era/japan/reki.rb +1 -1
  29. data/lib/zakuro/merchant.rb +2 -2
  30. data/lib/zakuro/output/error.rb +7 -6
  31. data/lib/zakuro/output/logger.rb +50 -49
  32. data/lib/zakuro/output/response.rb +145 -144
  33. data/lib/zakuro/tools/typeof.rb +2 -2
  34. data/lib/zakuro/version.rb +1 -1
  35. data/lib/zakuro/version/abstract_version.rb +1 -1
  36. data/lib/zakuro/version/context.rb +23 -0
  37. data/lib/zakuro/version/daien/const/number.rb +55 -0
  38. data/lib/zakuro/version/daien/const/remainder.rb +53 -0
  39. data/lib/zakuro/version/daien/cycle/remainder.rb +59 -0
  40. data/lib/zakuro/version/daien/cycle/solar_term.rb +34 -0
  41. data/lib/zakuro/version/daien/daien.rb +36 -0
  42. data/lib/zakuro/version/daien/monthly/lunar_phase.rb +106 -0
  43. data/lib/zakuro/version/daien/range/annual_range.rb +39 -0
  44. data/lib/zakuro/version/daien/stella/lunar/adjustment.rb +240 -0
  45. data/lib/zakuro/version/daien/stella/lunar/localization.rb +44 -0
  46. data/lib/zakuro/version/daien/stella/lunar/location.rb +80 -0
  47. data/lib/zakuro/version/daien/stella/lunar/value.rb +75 -0
  48. data/lib/zakuro/version/daien/stella/origin/average_november.rb +34 -0
  49. data/lib/zakuro/version/daien/stella/origin/lunar_age.rb +62 -0
  50. data/lib/zakuro/version/daien/stella/origin/winter_solstice.rb +55 -0
  51. data/lib/zakuro/version/daien/stella/solar/adjustment.rb +93 -0
  52. data/lib/zakuro/version/daien/stella/solar/average.rb +98 -0
  53. data/lib/zakuro/version/daien/stella/solar/interval.rb +108 -0
  54. data/lib/zakuro/version/daien/stella/solar/location.rb +61 -0
  55. data/lib/zakuro/version/daien/stella/solar/value.rb +36 -0
  56. data/lib/zakuro/version/gihou/const/number.rb +55 -0
  57. data/lib/zakuro/version/gihou/const/remainder.rb +54 -0
  58. data/lib/zakuro/version/gihou/cycle/remainder.rb +56 -0
  59. data/lib/zakuro/version/gihou/cycle/solar_term.rb +34 -0
  60. data/lib/zakuro/version/gihou/gihou.rb +23 -2
  61. data/lib/zakuro/version/gihou/monthly/lunar_phase.rb +106 -0
  62. data/lib/zakuro/version/gihou/range/annual_range.rb +39 -0
  63. data/lib/zakuro/version/gihou/stella/lunar/adjustment.rb +250 -0
  64. data/lib/zakuro/version/gihou/stella/lunar/localization.rb +44 -0
  65. data/lib/zakuro/version/gihou/stella/lunar/location.rb +80 -0
  66. data/lib/zakuro/version/gihou/stella/lunar/value.rb +75 -0
  67. data/lib/zakuro/version/gihou/stella/origin/average_november.rb +34 -0
  68. data/lib/zakuro/version/gihou/stella/origin/lunar_age.rb +62 -0
  69. data/lib/zakuro/version/gihou/stella/origin/winter_solstice.rb +55 -0
  70. data/lib/zakuro/version/gihou/stella/solar/adjustment.rb +93 -0
  71. data/lib/zakuro/version/gihou/stella/solar/average.rb +97 -0
  72. data/lib/zakuro/version/gihou/stella/solar/interval.rb +108 -0
  73. data/lib/zakuro/version/gihou/stella/solar/location.rb +61 -0
  74. data/lib/zakuro/version/gihou/stella/solar/value.rb +36 -0
  75. data/lib/zakuro/version/senmyou/const/number.rb +51 -0
  76. data/lib/zakuro/version/senmyou/const/remainder.rb +47 -0
  77. data/lib/zakuro/version/senmyou/cycle/remainder.rb +56 -0
  78. data/lib/zakuro/version/senmyou/cycle/solar_term.rb +34 -0
  79. data/lib/zakuro/version/senmyou/monthly/lunar_phase.rb +80 -195
  80. data/lib/zakuro/version/senmyou/range/annual_range.rb +25 -145
  81. data/lib/zakuro/version/senmyou/senmyou.rb +10 -4
  82. data/lib/zakuro/version/senmyou/stella/lunar/adjustment.rb +237 -0
  83. data/lib/zakuro/version/senmyou/stella/lunar/localization.rb +44 -0
  84. data/lib/zakuro/version/senmyou/stella/lunar/location.rb +87 -0
  85. data/lib/zakuro/version/senmyou/stella/lunar/value.rb +67 -0
  86. data/lib/zakuro/version/senmyou/stella/origin/average_november.rb +34 -0
  87. data/lib/zakuro/version/senmyou/stella/origin/lunar_age.rb +62 -0
  88. data/lib/zakuro/version/senmyou/stella/origin/winter_solstice.rb +55 -0
  89. data/lib/zakuro/version/senmyou/stella/solar/adjustment.rb +93 -0
  90. data/lib/zakuro/version/senmyou/stella/solar/average.rb +97 -0
  91. data/lib/zakuro/version/senmyou/stella/solar/interval.rb +103 -0
  92. data/lib/zakuro/version/senmyou/stella/solar/location.rb +61 -0
  93. data/lib/zakuro/version/senmyou/stella/solar/value.rb +39 -0
  94. data/lib/zakuro/version/version_class_resolver.rb +70 -0
  95. data/lib/zakuro/version_factory.rb +3 -3
  96. metadata +83 -28
  97. data/lib/zakuro/cycle/abstract_remainder.rb +0 -456
  98. data/lib/zakuro/cycle/zodiac.rb +0 -103
  99. data/lib/zakuro/version/senmyou/base/era.rb +0 -83
  100. data/lib/zakuro/version/senmyou/base/multi_gengou.rb +0 -98
  101. data/lib/zakuro/version/senmyou/base/multi_gengou_roller.rb +0 -217
  102. data/lib/zakuro/version/senmyou/base/remainder.rb +0 -60
  103. data/lib/zakuro/version/senmyou/base/solar_term.rb +0 -148
  104. data/lib/zakuro/version/senmyou/base/year.rb +0 -104
  105. data/lib/zakuro/version/senmyou/monthly/first_day.rb +0 -44
  106. data/lib/zakuro/version/senmyou/monthly/initialized_month.rb +0 -119
  107. data/lib/zakuro/version/senmyou/monthly/month.rb +0 -181
  108. data/lib/zakuro/version/senmyou/monthly/month_label.rb +0 -87
  109. data/lib/zakuro/version/senmyou/monthly/operated_month.rb +0 -196
  110. data/lib/zakuro/version/senmyou/range/full_range.rb +0 -194
  111. data/lib/zakuro/version/senmyou/range/operated_range.rb +0 -126
  112. data/lib/zakuro/version/senmyou/range/operated_solar_terms.rb +0 -181
  113. data/lib/zakuro/version/senmyou/range/western_date_allocation.rb +0 -68
  114. data/lib/zakuro/version/senmyou/range/year_boundary.rb +0 -138
  115. data/lib/zakuro/version/senmyou/specifier/single_day_specifier.rb +0 -102
  116. data/lib/zakuro/version/senmyou/stella/lunar_orbit.rb +0 -332
  117. data/lib/zakuro/version/senmyou/stella/solar_average.rb +0 -169
  118. data/lib/zakuro/version/senmyou/stella/solar_location.rb +0 -213
  119. data/lib/zakuro/version/senmyou/stella/solar_orbit.rb +0 -213
  120. data/lib/zakuro/version/senmyou/stella/winter_solstice.rb +0 -106
  121. data/lib/zakuro/version/senmyou/summary/single.rb +0 -125
  122. data/lib/zakuro/version/taien/taien.rb +0 -19
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base/multi_gengou_roller'
4
+ require_relative '../base/year'
5
+
6
+ require_relative '../../era/western'
7
+ require_relative '../../output/response'
8
+ require_relative '../../output/logger'
9
+
10
+ # :nodoc:
11
+ module Zakuro
12
+ # :nodoc:
13
+ module Calculation
14
+ # :nodoc:
15
+ module Specifier
16
+ #
17
+ # SingleDay 一日検索
18
+ #
19
+ module SingleDay
20
+ # @return [Output::Logger] ロガー
21
+ LOGGER = Output::Logger.new(location: 'specifier')
22
+
23
+ #
24
+ # 取得する
25
+ #
26
+ # @param [Array<Year>] yeas 範囲
27
+ # @param [Western::Calendar] date 西暦日
28
+ #
29
+ # @return [Result::Data::SingleDay] 和暦日
30
+ #
31
+ def self.get(years: [], date: Western::Calendar.new)
32
+ year = specify_year(years: years, date: date)
33
+
34
+ year = transfer(year: year, date: date)
35
+
36
+ month = specify_month(year: year, date: date)
37
+ first_date = month.western_date
38
+
39
+ Output::Response::SingleDay.save_single_day(
40
+ param: Output::Response::SingleDay::Param.new(
41
+ year: year, month: month,
42
+ date: date, days: date - first_date
43
+ )
44
+ )
45
+ end
46
+
47
+ #
48
+ # 年を特定する
49
+ #
50
+ # @param [Array<Year>] years 範囲
51
+ # @param [Western::Calendar] date 西暦日
52
+ #
53
+ # @return [Year] 対象年
54
+ #
55
+ def self.specify_year(years:, date:)
56
+ years.reverse_each do |year|
57
+ return year if date >= year.new_year_date
58
+ end
59
+
60
+ raise ArgumentError, "invalid year range. date: #{date.format}"
61
+ end
62
+ private_class_method :specify_year
63
+
64
+ #
65
+ # 改元する
66
+ #
67
+ # @param [Year] year 年
68
+ # @param [Western::Calendar] date 西暦日
69
+ #
70
+ # @return [Year] 改元後の年
71
+ #
72
+ def self.transfer(year:, date:)
73
+ multi_gengou = Calculation::Base::MultiGengouRoller.transfer(
74
+ multi_gengou: year.multi_gengou, date: date
75
+ )
76
+ Calculation::Base::Year.new(
77
+ multi_gengou: multi_gengou, new_year_date: year.new_year_date,
78
+ months: year.months, total_days: year.total_days
79
+ )
80
+ end
81
+ private_class_method :transfer
82
+
83
+ # :reek:TooManyStatements { max_statements: 7 }
84
+
85
+ #
86
+ # 月を特定する
87
+ #
88
+ # @param [Year] year 年
89
+ # @param [Western::Calendar] date 西暦日
90
+ #
91
+ # @return [Month] 対象月
92
+ #
93
+ def self.specify_month(year:, date:)
94
+ months = year.months
95
+
96
+ current_month = months[0]
97
+ months.each do |month|
98
+ return current_month if month.western_date > date
99
+
100
+ current_month = month
101
+ end
102
+
103
+ current_month
104
+ end
105
+ private_class_method :specify_month
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../cycle/abstract_remainder'
4
+
5
+ # :nodoc:
6
+ module Zakuro
7
+ # :nodoc:
8
+ module Calculation
9
+ # :nodoc:
10
+ module Lunar
11
+ #
12
+ # AbstractLocation 入暦
13
+ #
14
+ class AbstractLocation
15
+ # @return [True] 計算済み(前回計算あり)
16
+ # @return [False] 未計算(初回計算)
17
+ attr_reader :calculated
18
+ # @return [Integer] 西暦年
19
+ attr_reader :western_year
20
+ # @return [Cycle::LunarRemainder] 大余小余(初回:昨年天正閏余)
21
+ attr_reader :remainder
22
+
23
+ #
24
+ # 初期化
25
+ #
26
+ # @param [Cycle::LunarRemainder] lunar_age 天正閏余(大余小余)
27
+ # @param [Integer] western_year 西暦年
28
+ #
29
+ def initialize(lunar_age:, western_year:)
30
+ @calculated = false
31
+ @western_year = western_year
32
+ @remainder = lunar_age
33
+ end
34
+
35
+ #
36
+ # 入暦を計算する
37
+ #
38
+ def run
39
+ # abstract
40
+ end
41
+
42
+ #
43
+ # 弦の分だけ月地点を進める
44
+ #
45
+ def add_quarter
46
+ # abstract
47
+ end
48
+
49
+ #
50
+ # 1始まりの大余小余を取得する
51
+ #
52
+ # @return [Cycle::AbstractRemainder] 1始まりの大余小余
53
+ #
54
+ def adjusted_remainder
55
+ @remainder.add(Cycle::AbstractRemainder.new(day: 1, minute: 0, second: 0))
56
+ end
57
+
58
+ private
59
+
60
+ #
61
+ # 初回計算
62
+ #
63
+ def first
64
+ # abstract
65
+ end
66
+
67
+ #
68
+ # 大余小余に合わせて減算する(折り返す)
69
+ #
70
+ # @param [Cycle::LunarRemainder] limit 上限
71
+ #
72
+ def decrease(limit:)
73
+ # abstract
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../type/old_float'
4
+
5
+ # :nodoc:
6
+ module Zakuro
7
+ # :nodoc:
8
+ module Calculation
9
+ # :nodoc:
10
+ module Lunar
11
+ #
12
+ # ChoukeiValue 再考長慶宣明暦算法
13
+ #
14
+ module ChoukeiValue
15
+ #
16
+ # 四捨五入した大余を返す
17
+ #
18
+ # @param [Integer] per 増減率
19
+ # @param [Integer] denominator 小余の分母
20
+ # @param [Integer] minute 小余
21
+ #
22
+ # @return [Integer] 累計値(大余)
23
+ #
24
+ def self.rounded_day(per:, denominator:, minute:)
25
+ remainder_minute = Type::OldFloat.new((per * minute).to_f)
26
+ day = day_only(remainder_minute: remainder_minute.get, denominator: denominator)
27
+ # 繰り上げ結果を足す
28
+ day += carried_minute(remainder_minute: remainder_minute, denominator: denominator)
29
+
30
+ day
31
+ end
32
+
33
+ #
34
+ # 秒がない大余小余にする
35
+ #
36
+ # @param [Cycle::LunarRemainder] remainder 大余小余
37
+ #
38
+ # @note 815年で大余繰り上げあり
39
+ #
40
+ # @return [Integer] 大余
41
+ # @return [Float] 小余
42
+ #
43
+ def self.remainder_without_second(remainder:)
44
+ adjusted = remainder.class.new(
45
+ day: remainder.day, minute: remainder.floor_minute, second: 0
46
+ )
47
+ adjusted.carry!
48
+
49
+ [adjusted.day, adjusted.minute]
50
+ end
51
+
52
+ def self.day_only(remainder_minute:, denominator:)
53
+ float_day = Type::OldFloat.new(remainder_minute / denominator)
54
+ # 切り捨て(プラスマイナスに関わらず小数点以下切り捨て)
55
+ float_day.floor!
56
+ float_day.get
57
+ end
58
+ private_class_method :day_only
59
+
60
+ def self.carried_minute(remainder_minute:, denominator:)
61
+ remainder_day = remainder_minute.abs % denominator
62
+ # 四捨五入(1/2日 以上なら繰り上げる)
63
+ return remainder_minute.sign if remainder_day >= (denominator / 2)
64
+
65
+ 0
66
+ end
67
+ private_class_method :carried_minute
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module Zakuro
5
+ # :nodoc:
6
+ module Calculation
7
+ # :nodoc:
8
+ module Solar
9
+ #
10
+ # AbstractAverage 平気(太陽軌道平均)
11
+ #
12
+ class AbstractAverage
13
+ #
14
+ # 初期化
15
+ #
16
+ # @param [Cycle::AbstractSolarTerm] solar_term 入定気
17
+ #
18
+ def initialize(solar_term:)
19
+ @solar_term = solar_term
20
+ end
21
+
22
+ #
23
+ # 冬至から数えた1年データの月ごとに二十四節気を割り当てる
24
+ #
25
+ # @param [Array<Month>] annual_range 1年データ
26
+ #
27
+ # @return [Array<Month>] 1年データ
28
+ #
29
+ def set(annual_range:)
30
+ # 次月と比較しながら当月の二十四節気を決める
31
+ # NOTE: 最後の月は処理できない(=計算外の余分な月が最後に必要である)
32
+ annual_range.each_cons(2) do |(current_month, next_month)|
33
+ set_solar_term(
34
+ current_month: current_month,
35
+ next_month: next_month
36
+ )
37
+ end
38
+
39
+ annual_range
40
+ end
41
+
42
+ # :reek:TooManyStatements { max_statements: 7 }
43
+
44
+ #
45
+ # 月内(当月朔日から当月末日(来月朔日の前日)の間)に二十四節気があるか
46
+ # @note 大余60で一巡するため 以下2パターンがある
47
+ # * current_month <= next_month : (二十四節気) >= current_month && (二十四節気) < next_month
48
+ # * current_month > next_month : (二十四節気) >= current_month || (二十四節気) < next_month
49
+ #
50
+ # @param [Cycle::AbstractRemainder] solar_term 二十四節気
51
+ # @param [Cycle::AbstractRemainder] current_month 月初
52
+ # @param [Cycle::AbstractRemainder] next_month 月末
53
+ #
54
+ # @return [True] 対象の二十四節気がある
55
+ # @return [False] 対象の二十四節気がない
56
+ #
57
+ def self.in_solar_term?(solar_term:, current_month:, next_month:)
58
+ # 大余で比較する
59
+ target_time = solar_term.day
60
+ current_month_time = current_month.day
61
+ next_month_time = next_month.day
62
+ current_month_over = (target_time >= current_month_time)
63
+ next_month_under = (target_time < next_month_time)
64
+
65
+ return current_month_over && next_month_under if current_month_time <= next_month_time
66
+
67
+ current_month_over || next_month_under
68
+ end
69
+
70
+ private
71
+
72
+ # :reek:TooManyStatements { max_statements: 8 }
73
+
74
+ #
75
+ # 二十四節気を設定する
76
+ #
77
+ # @param [Month] current_month 当月
78
+ # @param [Month] next_month 次月
79
+ #
80
+ def set_solar_term(current_month:, next_month:)
81
+ # 安全策として無限ループは回避する
82
+ # * 最大試行回数:4回(設定なし => 設定あり => 設定あり => 設定なし)
83
+ # * 閏月は1回しか設定しない
84
+ # * 最大2回設定する(中気・節気)
85
+ (0..3).each do |_index|
86
+ in_range = AbstractAverage.in_solar_term?(
87
+ solar_term: @solar_term.remainder, current_month: current_month.remainder,
88
+ next_month: next_month.remainder
89
+ )
90
+
91
+ # 範囲外
92
+ unless in_range
93
+ # 1つ以上設定されていれば切り上げる(一つ飛ばしで二十四節気を設定することはない)
94
+ break unless current_month.empty_solar_term?
95
+
96
+ next_solar_term
97
+ next
98
+ end
99
+
100
+ current_month.add_term(term: @solar_term.clone)
101
+ next_solar_term
102
+
103
+ # 定気は最大2つまで
104
+ break if current_month.solar_term_size == 2
105
+ end
106
+ end
107
+
108
+ #
109
+ # 次の二十四節気に移る
110
+ #
111
+ def next_solar_term
112
+ @solar_term.next_term!
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../cycle/abstract_remainder'
4
+
5
+ # :nodoc:
6
+ module Zakuro
7
+ # :nodoc:
8
+ module Calculation
9
+ # :nodoc:
10
+ module Solar
11
+ #
12
+ # AbstractLocation 入定気
13
+ #
14
+ class AbstractLocation
15
+ # @return [True] 計算済み(前回計算あり)
16
+ # @return [False] 未計算(初回計算)
17
+ attr_reader :calculated
18
+ # @return [Integer] 連番
19
+ attr_reader :index
20
+ # @return [Cycle::AbstractRemainder] 大余小余
21
+ attr_reader :remainder
22
+ # @return [Cycle::AbstractRemainder] 弦
23
+ attr_reader :quarter
24
+
25
+ #
26
+ # 初期化
27
+ #
28
+ # @param [Cycle::AbstractRemainder] lunar_age 天正閏余(大余小余)
29
+ # @param [Cycle::AbstractRemainder] quarter 弦
30
+ #
31
+ def initialize(lunar_age:, quarter:)
32
+ @calculated = false
33
+ @index = -1
34
+ @remainder = lunar_age.clone
35
+ @quarter = quarter
36
+ end
37
+
38
+ #
39
+ # 入定気を計算する
40
+ #
41
+ def run
42
+ return current if calculated
43
+
44
+ first
45
+ end
46
+
47
+ #
48
+ # 無効かどうか
49
+ #
50
+ # @return [True] 無効
51
+ # @return [False] 有効
52
+ #
53
+ def invalid?
54
+ @index == -1
55
+ end
56
+
57
+ #
58
+ # 弦の分だけ太陽地点を進める
59
+ #
60
+ def add_quarter
61
+ @remainder.add!(quarter)
62
+ end
63
+
64
+ #
65
+ # 二十四節気番号に対応する入気定日加減数を返す
66
+ #
67
+ # @note 継承で暦ごとの入気定日加減数を返す
68
+ #
69
+ # @param [Integer] index 二十四節気番号
70
+ #
71
+ # @return [Cycle::Remainder] 入気定日加減数
72
+ #
73
+ def interval(index:)
74
+ # abstract
75
+ end
76
+
77
+ #
78
+ # 入気定日加減数の要素数を返す
79
+ #
80
+ # @note 継承で暦ごとの入気定日加減数の要素数を返す
81
+ #
82
+ # @return [Integer] 入気定日加減数の要素数
83
+ #
84
+ def interval_size
85
+ # abstract
86
+ end
87
+
88
+ private
89
+
90
+ #
91
+ # 2回目以降の計算をする
92
+ #
93
+ def current
94
+ decrease_recursively
95
+ end
96
+
97
+ #
98
+ # 初回計算する
99
+ #
100
+ def first
101
+ define_first
102
+ @calculated = true
103
+ end
104
+
105
+ #
106
+ # 初回の入定気を定める
107
+ #
108
+ def define_first
109
+ # 入定気の起算方法
110
+ # 概要:
111
+ # * 太陽の運行による補正値は、二十四節気の気ごとに定められる
112
+ # * 11月経朔の前にある気を求め、それから11月経朔との間隔を求める
113
+ # * 気ごとの補正値と、気から11月経朔までにかかる補正値を求める
114
+ # 前提:
115
+ # * 11月経朔に関わる二十四節気は、時系列から順に、小雪・大雪・冬至である
116
+ # * 小雪〜大雪の間隔は小雪定数で、大雪〜冬至の間隔は大雪定数で決められている(24気損益眺朒(ちょうじく)数のこと)
117
+ # * 11月経朔は、この小雪〜冬至の間のいずれかにある
118
+ # 計算:
119
+ # 2パターンある
120
+ # (a) 大雪〜冬至にある場合
121
+ # *「大雪定数 >= 天正閏余」の場合を指す
122
+ # * * NOTE 資料では「より大きい(>)」とされるが、大雪そのものの場合は大雪から起算すべき
123
+ # * この場合は、大雪〜経朔の間隔を求める
124
+ # (b) 小雪〜大雪にある場合
125
+ # *「大雪定数 < 天正閏余」の場合を指す
126
+ # * この場合は、小雪〜経朔の間隔を求める
127
+
128
+ # NOTE: 上記パターンとは別に、稀だが立冬のパターンも存在する
129
+ # この場合は比較方法はそのままに立冬〜経朔の間隔を求める
130
+
131
+ # 大雪(23)/小雪(22)/立冬(21)
132
+ [23, 22, 21].each do |index|
133
+ prev(index: index)
134
+
135
+ break unless invalid?
136
+ end
137
+
138
+ # 立冬(21)を超える天正閏余は成立し得ない(1朔望月をはるかに超えることになる)
139
+ return unless invalid?
140
+
141
+ raise ArgumentError.new, 'invalid winster solstice age'
142
+ end
143
+
144
+ #
145
+ # 大余小余の分だけ二十四節気を遡る
146
+ #
147
+ # @param [Integer] index 二十四節気番号
148
+ #
149
+ def prev(index:)
150
+ interval = interval(index: index)
151
+ if remainder > interval
152
+ @remainder.sub!(interval)
153
+ return
154
+ end
155
+
156
+ # 入定気が確定する
157
+ @remainder = interval.sub(@remainder)
158
+ @index = index
159
+ end
160
+
161
+ #
162
+ # 二十四節気番号を次に進める
163
+ #
164
+ def next_index
165
+ @index += 1
166
+ @index = 0 if @index >= interval_size
167
+ end
168
+
169
+ #
170
+ # 二十四節気を減算する
171
+ #
172
+ def decrease_recursively
173
+ interval = interval(index: index)
174
+ # 現在の二十四節気に留まる
175
+ return if remainder < interval
176
+
177
+ @remainder.sub!(interval)
178
+
179
+ next_index
180
+
181
+ # 再帰
182
+ decrease_recursively
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end