zakuro 0.1.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -1
  3. data/doc/gengou.md +22 -22
  4. data/doc/operation/csv/month.csv +468 -202
  5. data/doc/operation/operation.xlsx +0 -0
  6. data/lib/zakuro/calculation/base/operated_year.rb +114 -0
  7. data/lib/zakuro/calculation/base/year.rb +3 -0
  8. data/lib/zakuro/calculation/cycle/abstract_remainder.rb +29 -29
  9. data/lib/zakuro/calculation/monthly/abstract_lunar_phase.rb +169 -0
  10. data/lib/zakuro/calculation/monthly/first_day.rb +1 -1
  11. data/lib/zakuro/calculation/monthly/operated_month.rb +47 -3
  12. data/lib/zakuro/calculation/range/medieval_annual_range.rb +105 -0
  13. data/lib/zakuro/calculation/range/operated_range.rb +61 -16
  14. data/lib/zakuro/calculation/stella/lunar/abstract_location.rb +78 -0
  15. data/lib/zakuro/calculation/stella/lunar/choukei_value.rb +71 -0
  16. data/lib/zakuro/calculation/stella/solar/abstract_average.rb +117 -0
  17. data/lib/zakuro/calculation/stella/solar/abstract_location.rb +187 -0
  18. data/lib/zakuro/calculation/stella/solar/choukei_value.rb +136 -0
  19. data/lib/zakuro/calculation/type/old_float.rb +69 -0
  20. data/lib/zakuro/era/japan/reki.rb +1 -1
  21. data/lib/zakuro/era/japan/yaml/set-001-until-south.yaml +22 -22
  22. data/lib/zakuro/operation/month/type.rb +58 -0
  23. data/lib/zakuro/operation/yaml/month.yaml +8512 -0
  24. data/lib/zakuro/version/context.rb +1 -1
  25. data/lib/zakuro/version/daien/const/number.rb +55 -0
  26. data/lib/zakuro/version/daien/const/remainder.rb +53 -0
  27. data/lib/zakuro/version/daien/cycle/remainder.rb +85 -0
  28. data/lib/zakuro/version/daien/cycle/solar_term.rb +34 -0
  29. data/lib/zakuro/version/daien/daien.rb +36 -0
  30. data/lib/zakuro/version/daien/monthly/lunar_phase.rb +106 -0
  31. data/lib/zakuro/version/daien/range/annual_range.rb +39 -0
  32. data/lib/zakuro/version/daien/stella/lunar/adjustment.rb +240 -0
  33. data/lib/zakuro/version/daien/stella/lunar/localization.rb +44 -0
  34. data/lib/zakuro/version/daien/stella/lunar/location.rb +80 -0
  35. data/lib/zakuro/version/daien/stella/lunar/value.rb +75 -0
  36. data/lib/zakuro/version/daien/stella/origin/average_november.rb +34 -0
  37. data/lib/zakuro/version/daien/stella/origin/lunar_age.rb +62 -0
  38. data/lib/zakuro/version/daien/stella/origin/winter_solstice.rb +55 -0
  39. data/lib/zakuro/version/daien/stella/solar/adjustment.rb +93 -0
  40. data/lib/zakuro/version/daien/stella/solar/average.rb +98 -0
  41. data/lib/zakuro/version/daien/stella/solar/interval.rb +108 -0
  42. data/lib/zakuro/version/daien/stella/solar/location.rb +61 -0
  43. data/lib/zakuro/version/daien/stella/solar/value.rb +36 -0
  44. data/lib/zakuro/version/genka/const/number.rb +43 -0
  45. data/lib/zakuro/version/genka/const/remainder.rb +33 -0
  46. data/lib/zakuro/version/genka/cycle/remainder.rb +92 -0
  47. data/lib/zakuro/version/genka/cycle/solar_term.rb +34 -0
  48. data/lib/zakuro/version/genka/genka.rb +19 -2
  49. data/lib/zakuro/version/genka/monthly/lunar_phase.rb +95 -0
  50. data/lib/zakuro/version/genka/range/annual_range.rb +77 -0
  51. data/lib/zakuro/version/genka/stella/origin/first_term.rb +55 -0
  52. data/lib/zakuro/version/genka/stella/origin/january.rb +49 -0
  53. data/lib/zakuro/version/genka/stella/solar/average.rb +41 -0
  54. data/lib/zakuro/version/gihou/const/number.rb +55 -0
  55. data/lib/zakuro/version/gihou/const/remainder.rb +54 -0
  56. data/lib/zakuro/version/gihou/cycle/remainder.rb +82 -0
  57. data/lib/zakuro/version/gihou/cycle/solar_term.rb +34 -0
  58. data/lib/zakuro/version/gihou/gihou.rb +23 -2
  59. data/lib/zakuro/version/gihou/monthly/lunar_phase.rb +106 -0
  60. data/lib/zakuro/version/gihou/range/annual_range.rb +39 -0
  61. data/lib/zakuro/version/gihou/stella/lunar/adjustment.rb +250 -0
  62. data/lib/zakuro/version/gihou/stella/lunar/localization.rb +44 -0
  63. data/lib/zakuro/version/gihou/stella/lunar/location.rb +80 -0
  64. data/lib/zakuro/version/gihou/stella/lunar/value.rb +75 -0
  65. data/lib/zakuro/version/gihou/stella/origin/average_november.rb +34 -0
  66. data/lib/zakuro/version/gihou/stella/origin/lunar_age.rb +62 -0
  67. data/lib/zakuro/version/gihou/stella/origin/winter_solstice.rb +55 -0
  68. data/lib/zakuro/version/gihou/stella/solar/adjustment.rb +93 -0
  69. data/lib/zakuro/version/gihou/stella/solar/average.rb +97 -0
  70. data/lib/zakuro/version/gihou/stella/solar/interval.rb +108 -0
  71. data/lib/zakuro/version/gihou/stella/solar/location.rb +61 -0
  72. data/lib/zakuro/version/gihou/stella/solar/value.rb +36 -0
  73. data/lib/zakuro/version/senmyou/const/number.rb +1 -1
  74. data/lib/zakuro/version/senmyou/const/remainder.rb +7 -3
  75. data/lib/zakuro/version/senmyou/cycle/remainder.rb +27 -6
  76. data/lib/zakuro/version/senmyou/cycle/solar_term.rb +4 -1
  77. data/lib/zakuro/version/senmyou/monthly/lunar_phase.rb +12 -112
  78. data/lib/zakuro/version/senmyou/range/annual_range.rb +5 -77
  79. data/lib/zakuro/version/senmyou/stella/lunar/localization.rb +2 -3
  80. data/lib/zakuro/version/senmyou/stella/lunar/location.rb +13 -34
  81. data/lib/zakuro/version/senmyou/stella/lunar/value.rb +8 -30
  82. data/lib/zakuro/version/senmyou/stella/solar/adjustment.rb +29 -29
  83. data/lib/zakuro/version/senmyou/stella/solar/average.rb +14 -92
  84. data/lib/zakuro/version/senmyou/stella/solar/location.rb +18 -121
  85. data/lib/zakuro/version/senmyou/stella/solar/value.rb +4 -103
  86. data/lib/zakuro/version/version_class_resolver.rb +12 -0
  87. data/lib/zakuro/version.rb +1 -1
  88. data/lib/zakuro/version_factory.rb +1 -1
  89. metadata +61 -7
  90. data/lib/zakuro/version/taien/taien.rb +0 -19
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative './operated_solar_terms'
4
4
  require_relative '../../operation/operation'
5
+ require_relative '../base/operated_year'
5
6
  require_relative '../../calculation/monthly/operated_month'
6
7
 
7
8
  # :nodoc:
@@ -41,13 +42,19 @@ module Zakuro
41
42
  # @return [Array<Year>] 運用結果範囲
42
43
  #
43
44
  def get
44
- rewrite
45
+ operated_years = rewrite
46
+
47
+ OperatedRange.move(operated_years: operated_years)
48
+
49
+ OperatedRange.commit(operated_years: operated_years)
50
+
51
+ operated_years
45
52
  end
46
53
 
47
54
  #
48
55
  # 運用結果に書き換える
49
56
  #
50
- # @return [Array<Year>] 運用結果範囲
57
+ # @return [Array<OperatedYear>] 運用結果範囲
51
58
  #
52
59
  def rewrite
53
60
  operated_years = []
@@ -63,6 +70,54 @@ module Zakuro
63
70
  operated_years
64
71
  end
65
72
 
73
+ #
74
+ # 運用情報で年を跨ぐ月をその年に寄せる
75
+ #
76
+ # @param [Array<OperatedYear>] operated_years 運用結果範囲
77
+ #
78
+ def self.move(operated_years:)
79
+ # FIXME: この方式は完全ではない。範囲の1年前/1年後が必要
80
+ move_into_next_year(operated_years: operated_years)
81
+ move_into_last_year(operated_years: operated_years)
82
+ end
83
+
84
+ #
85
+ # 運用情報では来年に属する月を来年に寄せる
86
+ #
87
+ # @param [Array<OperatedYear>] operated_years 運用結果範囲
88
+ #
89
+ def self.move_into_next_year(operated_years:)
90
+ operated_years.each_cons(2) do |current_year, next_year|
91
+ months = current_year.pop_next_year_months
92
+
93
+ next_year.unshift_months(months)
94
+ end
95
+ end
96
+
97
+ #
98
+ # 運用情報では昨年に属する月を昨年に寄せる
99
+ #
100
+ # @param [Array<OperatedYear>] operated_years 運用結果範囲
101
+ #
102
+ def self.move_into_last_year(operated_years:)
103
+ rerversed_year = operated_years.reverse!
104
+ rerversed_year.each_cons(2) do |current_year, last_year|
105
+ months = current_year.shift_last_year_months
106
+ last_year.push_months(months)
107
+ end
108
+
109
+ rerversed_year.reverse!
110
+ end
111
+
112
+ #
113
+ # 年を確定させる
114
+ #
115
+ # @param [Array<OperatedYear>] operated_years 運用結果範囲
116
+ #
117
+ def self.commit(operated_years:)
118
+ operated_years.each(&:commit)
119
+ end
120
+
66
121
  #
67
122
  # 年を書き換える
68
123
  #
@@ -70,10 +125,10 @@ module Zakuro
70
125
  # @param [Year] year 年
71
126
  # @param [OperatedSolarTerms] operated_solar_terms 運用時二十四節気
72
127
  #
73
- # @return [Year] 年
128
+ # @return [OperatedYear] 年
74
129
  #
75
130
  def self.rewrite_year(context:, year:, operated_solar_terms:)
76
- result = Base::Year.new(
131
+ result = Base::OperatedYear.new(
77
132
  multi_gengou: year.multi_gengou, new_year_date: year.new_year_date
78
133
  )
79
134
  year.months.each do |month|
@@ -83,8 +138,6 @@ module Zakuro
83
138
  ))
84
139
  end
85
140
 
86
- result.commit
87
-
88
141
  result
89
142
  end
90
143
 
@@ -100,8 +153,6 @@ module Zakuro
100
153
  def self.resolve_month(context:, month:, operated_solar_terms:)
101
154
  history = Operation.specify_history(western_date: month.western_date)
102
155
 
103
- return month if history.invalid?
104
-
105
156
  OperatedRange.rewrite_month(
106
157
  context: context, month: month, history: history,
107
158
  operated_solar_terms: operated_solar_terms
@@ -121,8 +172,6 @@ module Zakuro
121
172
  # @return [Month] 月(運用結果)
122
173
  #
123
174
  def self.rewrite_month(context:, month:, history:, operated_solar_terms:)
124
- return month unless month.western_date == history.western_date
125
-
126
175
  operated_month = Monthly::OperatedMonth.new(
127
176
  context: context,
128
177
  month_label: month.month_label, first_day: month.first_day,
@@ -130,13 +179,9 @@ module Zakuro
130
179
  operated_solar_terms: operated_solar_terms
131
180
  )
132
181
 
133
- operated_month.rewrite
182
+ operated_month.rewrite unless history.invalid?
134
183
 
135
- Monthly::Month.new(
136
- context: context,
137
- month_label: operated_month.month_label, first_day: operated_month.first_day,
138
- solar_terms: operated_month.solar_terms
139
- )
184
+ operated_month
140
185
  end
141
186
  end
142
187
  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