zakuro 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +9 -0
  3. data/.gitignore +69 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +14 -0
  6. data/.travis.yml +6 -0
  7. data/Gemfile +19 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +44 -0
  10. data/Rakefile +20 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/images/12/346/234/210/344/273/245/351/231/215/343/201/256/345/205/245/345/256/232/346/260/227.png +0 -0
  14. data/images/12/346/234/210/344/273/245/351/231/215/343/201/256/346/234/210/343/201/256/351/200/262/351/200/200.png +0 -0
  15. data/images/source/description.numbers +0 -0
  16. data/images//345/205/245/345/256/232/346/260/227/343/201/256/350/265/267/347/256/227.png +0 -0
  17. data/images//345/220/204/346/234/210/343/201/256/346/261/202/343/202/201/346/226/271.png +0 -0
  18. data/images//345/244/252/351/231/275/343/201/250/346/234/210.png +0 -0
  19. data/lib/zakuro.rb +9 -0
  20. data/lib/zakuro/condition.rb +239 -0
  21. data/lib/zakuro/cycle/abstract_remainder.rb +457 -0
  22. data/lib/zakuro/cycle/zodiac.rb +103 -0
  23. data/lib/zakuro/era/gengou/set-001-until-south.yaml +375 -0
  24. data/lib/zakuro/era/gengou/set-002-from-north.yaml +166 -0
  25. data/lib/zakuro/era/gengou/set-003-modern.yaml +12 -0
  26. data/lib/zakuro/era/japan.rb +630 -0
  27. data/lib/zakuro/era/western.rb +412 -0
  28. data/lib/zakuro/merchant.rb +57 -0
  29. data/lib/zakuro/output/error.rb +10 -0
  30. data/lib/zakuro/output/logger.rb +64 -0
  31. data/lib/zakuro/output/response.rb +170 -0
  32. data/lib/zakuro/output/result.rb +219 -0
  33. data/lib/zakuro/output/stringifier.rb +62 -0
  34. data/lib/zakuro/version.rb +7 -0
  35. data/lib/zakuro/version/abstract_version.rb +29 -0
  36. data/lib/zakuro/version/genka/genka.rb +19 -0
  37. data/lib/zakuro/version/gihou/gihou.rb +19 -0
  38. data/lib/zakuro/version/gregorio/gregorio.rb +19 -0
  39. data/lib/zakuro/version/houryaku/houryaku.rb +19 -0
  40. data/lib/zakuro/version/joukyou/joukyou.rb +19 -0
  41. data/lib/zakuro/version/kansei/kansei.rb +19 -0
  42. data/lib/zakuro/version/senmyou/README.md +586 -0
  43. data/lib/zakuro/version/senmyou/base/era.rb +81 -0
  44. data/lib/zakuro/version/senmyou/base/gengou.rb +210 -0
  45. data/lib/zakuro/version/senmyou/base/remainder.rb +60 -0
  46. data/lib/zakuro/version/senmyou/base/solar_term.rb +66 -0
  47. data/lib/zakuro/version/senmyou/base/year.rb +58 -0
  48. data/lib/zakuro/version/senmyou/monthly/lunar_phase.rb +220 -0
  49. data/lib/zakuro/version/senmyou/monthly/month.rb +112 -0
  50. data/lib/zakuro/version/senmyou/senmyou.rb +34 -0
  51. data/lib/zakuro/version/senmyou/stella/lunar_orbit.rb +332 -0
  52. data/lib/zakuro/version/senmyou/stella/solar_average.rb +192 -0
  53. data/lib/zakuro/version/senmyou/stella/solar_orbit.rb +398 -0
  54. data/lib/zakuro/version/senmyou/stella/winter_solstice.rb +106 -0
  55. data/lib/zakuro/version/senmyou/summary/annual_data.rb +186 -0
  56. data/lib/zakuro/version/senmyou/summary/gengou_data.rb +294 -0
  57. data/lib/zakuro/version/taien/taien.rb +19 -0
  58. data/lib/zakuro/version/tenpou/tenpou.rb +19 -0
  59. data/lib/zakuro/version_factory.rb +59 -0
  60. data/zakuro.gemspec +31 -0
  61. metadata +106 -0
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../output/logger'
4
+
5
+ require_relative '../stella/winter_solstice'
6
+
7
+ # :nodoc:
8
+ module Zakuro
9
+ # :nodoc:
10
+ module Senmyou
11
+ # :reek:TooManyStatements { max_statements: 7 }
12
+ # :reek:TooManyInstanceVariables { max_instance_variables: 7 }
13
+
14
+ #
15
+ # LunarPhase 月の位相
16
+ #
17
+ class LunarPhase
18
+ #
19
+ # QuarterMoon 弦
20
+ #
21
+ module QuarterMoon
22
+ # @return [Remainder] 弦(1分=8秒)
23
+ DEFAULT = Remainder.new(day: 7, minute: 3214, second: 2)
24
+ # @return [Remainder] 弦(1分=100秒)
25
+ BASE_HUNDRED = LunarRemainder.new(day: 7, minute: 3214, second: 25)
26
+ end
27
+
28
+ # @return [Logger] ロガー
29
+ LOGGER = Logger.new(location: 'lunar_phase')
30
+
31
+ # @return [Array<String>] 月内の弦
32
+ PHASE_INDEXES = %w[朔日 上弦 望月 下弦].freeze
33
+
34
+ # @return [Integer] 西暦年
35
+ attr_reader :western_year
36
+ # @return [Remainder]] 経
37
+ attr_reader :average_remainder
38
+ # @return [True] 初回計算
39
+ # @return [False] 次回以降計算
40
+ attr_reader :first
41
+ # @return [SolarTerm] 二十四節気(入定気)
42
+ attr_reader :solar_term
43
+ # @return [Remainder] 入暦
44
+ attr_reader :moon_remainder
45
+ # @return [True] 進(遠地点より数える)
46
+ # @return [False] 退(近地点より数える)
47
+ attr_reader :is_forward
48
+ # @return [Integer] 弦
49
+ attr_reader :phase_index
50
+
51
+ #
52
+ # 初期化
53
+ #
54
+ # @param [Integer] western_year 西暦年
55
+ #
56
+ def initialize(western_year:)
57
+ @western_year = western_year
58
+ # 経
59
+ @average_remainder = WinterSolstice.calc_averaged_last_november_1st(
60
+ western_year: @western_year
61
+ )
62
+ # 天正冬至
63
+ winter_solstice_age = \
64
+ WinterSolstice.calc_moon_age(western_year: @western_year)
65
+ # 入定気
66
+ @solar_term = SolarTerm.new(remainder: winter_solstice_age)
67
+ # 入暦
68
+ @moon_remainder = LunarRemainder.new(total: 0).add!(winter_solstice_age)
69
+
70
+ @is_forward = false
71
+ @first = true
72
+
73
+ # 弦
74
+ @phase_index = 0
75
+ end
76
+
77
+ #
78
+ # 次の弦に進める
79
+ #
80
+ # @return [Remainder] 定朔
81
+ #
82
+ def next_phase
83
+ adjusted = current_remainder
84
+
85
+ @first = false if @first
86
+
87
+ add_quarter_moon_size
88
+
89
+ adjusted
90
+ end
91
+
92
+ #
93
+ # 次の月に進める
94
+ # @note 進めた後の月の定朔ではなく、当月のものを返却する
95
+ #
96
+ # @return [Remainder] 当月初の定朔
97
+ #
98
+ def next_month
99
+ result = nil
100
+ PHASE_INDEXES.each_with_index do |_phase, index|
101
+ adjust = next_phase
102
+ result = adjust if index.zero?
103
+ end
104
+
105
+ result
106
+ end
107
+
108
+ private
109
+
110
+ #
111
+ # 次の弦に進める
112
+ #
113
+ # @return [Integer] 弦
114
+ #
115
+ def next_phase_index
116
+ @phase_index += 1
117
+ @phase_index = 0 if @phase_index >= PHASE_INDEXES.size
118
+ @phase_index
119
+ end
120
+
121
+ #
122
+ # 朔月(月初)かを確認する
123
+ #
124
+ # @return [True] 朔月である
125
+ # @return [False] 朔月ではない
126
+ #
127
+ def first_phase?
128
+ @phase_index.zero?
129
+ end
130
+
131
+ #
132
+ # 朔月のみログ出力する
133
+ #
134
+ # @param [String] messages メッセージ(可変長)
135
+ #
136
+ def debug(*messages)
137
+ return unless first_phase?
138
+
139
+ LOGGER.debug(*messages)
140
+ end
141
+
142
+ #
143
+ # 現在の定朔を取得する
144
+ #
145
+ # @return [Remainder] 定朔
146
+ #
147
+ def current_remainder
148
+ debug('@average_remainder.format:' + @average_remainder.format)
149
+
150
+ sum = correction_value
151
+ adjusted = @average_remainder.add(
152
+ Remainder.new(day: 0, minute: sum, second: 0)
153
+ )
154
+ adjusted.up_on_new_moon!
155
+
156
+ debug("result: #{adjusted.format}")
157
+
158
+ adjusted
159
+ end
160
+
161
+ #
162
+ # 補正値を得る
163
+ #
164
+ # @return [Integer] 補正値
165
+ #
166
+ def correction_value
167
+ sun = correction_solar_value
168
+ moon = correction_moon_value
169
+
170
+ sum = sun + moon
171
+
172
+ debug("sun: #{sun}", "moon: #{moon}", "sun + moon : #{sum}")
173
+
174
+ sum
175
+ end
176
+
177
+ #
178
+ # 太陽運動の補正値を得る
179
+ #
180
+ # @return [Integer] 太陽運動の補正値
181
+ #
182
+ def correction_solar_value
183
+ @solar_term = SolarOrbit.calc_solar_term_by_remainder(
184
+ solar_term: @solar_term
185
+ )
186
+ debug("@solar_term.remainder: #{@solar_term.remainder.format(form: '%d-%d.%d')}")
187
+ debug("@solar_term.index: #{@solar_term.index}")
188
+
189
+ SolarOrbit.calc_sun_orbit_value(solar_term: @solar_term)
190
+ end
191
+
192
+ #
193
+ # 月運動の補正値を得る
194
+ #
195
+ # @return [Integer] 月運動の補正値
196
+ #
197
+ def correction_moon_value
198
+ @moon_remainder, @is_forward = \
199
+ LunarOrbit.calc_moon_point(remainder: @moon_remainder,
200
+ western_year: @western_year,
201
+ is_forward: @is_forward,
202
+ first: @first)
203
+
204
+ debug("@moon_remainder.format: #{@moon_remainder.format}")
205
+ debug("@is_forward: #{@is_forward}")
206
+
207
+ LunarOrbit.calc_moon_orbit_value(remainder_month: @moon_remainder,
208
+ is_forward: @is_forward)
209
+ end
210
+
211
+ def add_quarter_moon_size
212
+ @average_remainder.add!(QuarterMoon::DEFAULT)
213
+ @solar_term.remainder.add!(QuarterMoon::DEFAULT)
214
+ @moon_remainder.add!(QuarterMoon::BASE_HUNDRED)
215
+
216
+ next_phase_index
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module Zakuro
5
+ # :nodoc:
6
+ module Senmyou
7
+ #
8
+ # Month 月情報
9
+ #
10
+ class Month
11
+ # @return [True] 昨年の月
12
+ # @return [False] 今年の月
13
+ # @note 冬至基準で1年データを作成するため昨年の11月-12月である可能性がある
14
+ attr_accessor :is_last_year
15
+ # @return [True] 大の月(30日)
16
+ # @return [False] 小の月(29日)
17
+ attr_accessor :is_many_days
18
+ # @return [Integer] 月(xx月のxx)
19
+ attr_accessor :number
20
+ # @return [True] 閏月
21
+ # @return [False] 平月
22
+ attr_accessor :leaped
23
+ # @return [SolarTerm] 二十四節気(中気)
24
+ attr_accessor :even_term
25
+ # @return [SolarTerm] 二十四節気(節気)
26
+ attr_accessor :odd_term
27
+ # @return [Remainder] 月初日の大余小余
28
+ attr_reader :remainder
29
+ # @return [String] 月齢(朔月、上弦、望月、下弦)
30
+ attr_reader :phase_index
31
+
32
+ # rubocop:disable Metrics/ParameterLists
33
+ # :reek:BooleanParametere
34
+
35
+ #
36
+ # 初期化
37
+ #
38
+ # @param [True, False] is_last_year 昨年の月/今年の月
39
+ # @param [Integer] number 月(xx月のxx)
40
+ # @param [True, False] is_many_days 大の月(30日)/小の月(29日)
41
+ # @param [True, False] leaped 閏月/平月
42
+ # @param [Remainder] remainder 月初日の大余小余
43
+ # @param [String] phase_index 月齢(朔月、上弦、望月、下弦)
44
+ # @param [SolarTerm] even_term 二十四節気(中気)
45
+ # @param [SolarTerm] odd_term 二十四節気(節気)
46
+ #
47
+ def initialize(is_last_year: -1, number: -1, is_many_days: false,
48
+ leaped: false, remainder: Remainder.new, phase_index: -1,
49
+ even_term: SolarTerm.new, odd_term: SolarTerm.new)
50
+ # 年
51
+ @is_last_year = is_last_year
52
+ # 月の大小
53
+ @is_many_days = is_many_days
54
+ # 月
55
+ @number = number
56
+ # 閏
57
+ @leaped = leaped
58
+ # 日
59
+ @remainder = remainder
60
+ # 月齢(朔月、上弦、望月、下弦)
61
+ @phase_index = phase_index
62
+ # 中気(二十四節気)
63
+ @even_term = even_term
64
+ # 節気(二十四節気)
65
+ @odd_term = odd_term
66
+ end
67
+ # rubocop:enable Metrics/ParameterLists
68
+
69
+ #
70
+ # 月の日数を返す
71
+ #
72
+ # @return [Integer] 日数
73
+ #
74
+ def days
75
+ @is_many_days ? 30 : 29
76
+ end
77
+
78
+ #
79
+ # 月の名前(大小)を返す
80
+ #
81
+ # @return [String] 月の名前(大小)
82
+ #
83
+ def days_name
84
+ @is_many_days ? '大' : '小'
85
+ end
86
+
87
+ #
88
+ # 同一の月情報かを検証する
89
+ #
90
+ # @param [Month] other 他の月情報
91
+ #
92
+ # @return [True] 同一の月
93
+ # @return [False] 異なる月
94
+ #
95
+ def same?(other:)
96
+ @number == other.number && @leaped == other.leaped
97
+ end
98
+
99
+ #
100
+ # 文字化する
101
+ #
102
+ # @return [String] 文字
103
+ #
104
+ def to_s
105
+ "is_last_year: #{@is_last_year}, number: #{@number}, leaped: #{@leaped}, " \
106
+ "remainder: #{@remainder.format}, phase_index: #{@phase_index}, " \
107
+ "even_term: #{@even_term.remainder.format}: #{@even_term.index}, " \
108
+ "odd_term: #{@odd_term.remainder.format}: #{@odd_term.index}"
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require_relative '../abstract_version'
5
+ require_relative '../../era/western'
6
+ require_relative 'summary/gengou_data'
7
+
8
+ # :nodoc:
9
+ module Zakuro
10
+ #
11
+ # Senmyou 宣明暦
12
+ #
13
+ module Senmyou
14
+ #
15
+ # Gateway アクセサメソッド群
16
+ #
17
+ class Gateway < AbstractVersion
18
+ # @return [True] リリースあり
19
+ RELEASE = true
20
+
21
+ #
22
+ # 西暦日から和暦日に変換する
23
+ #
24
+ # @param [Date] western_date 西暦日
25
+ #
26
+ # @return [Result::SingleDay] 和暦日
27
+ #
28
+ def self.to_japan_date(western_date:)
29
+ date = Western::Calendar.create(date: western_date)
30
+ GengouData.get_ancient_date(date: date)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,332 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module Zakuro
5
+ # :nodoc:
6
+ module Senmyou
7
+ #
8
+ # LunarOrbit 月軌道
9
+ #
10
+ module LunarOrbit
11
+ # @return [Integer] 暦周(1近日点)
12
+ ANOMALISTIC_MONTH = 231_458.19
13
+ # @return [Integer] 暦中日
14
+ # @note ANOMALISTIC_MONTH の半分に相当する
15
+ HALF_ANOMALISTIC_MONTH = \
16
+ LunarRemainder.new(day: 13, minute: 6529, second: 9.5)
17
+
18
+ #
19
+ # Adjustment 補正値情報
20
+ #
21
+ module Adjustment
22
+ #
23
+ # Item 補正値
24
+ #
25
+ class Item
26
+ # @return [Integer] 損益率
27
+ attr_reader :per
28
+ # @return [Integer] 眺朒(ちょうじく)積
29
+ attr_reader :stack
30
+
31
+ #
32
+ # 初期化
33
+ #
34
+ # @param [Integer] per 損益率
35
+ # @param [Integer] stack 眺朒(ちょうじく)積
36
+ #
37
+ def initialize(per:, stack:)
38
+ @per = per
39
+ @stack = stack
40
+ end
41
+
42
+ #
43
+ # 文字化
44
+ #
45
+ # @return [String] 文字
46
+ #
47
+ def to_s
48
+ "per:#{@per}, stack:#{@stack}"
49
+ end
50
+ end
51
+
52
+ # @return [Array<Item>] 月の補正値
53
+ # @note キーは複合キーであり、以下のパターンに対応する
54
+ # * 進退
55
+ # * forward: 進(遠地点より数える)
56
+ # * back: 退(近地点より数える)
57
+ # * 入暦(1-14)
58
+ # * 小余(0-8400)
59
+ LIST = {
60
+ forward_01_0000_8400: Item.new(per: +830, stack: 0),
61
+ forward_02_0000_8400: Item.new(per: +726, stack: +830),
62
+ forward_03_0000_8400: Item.new(per: +606, stack: +1556),
63
+ forward_04_0000_8400: Item.new(per: +471, stack: +2162),
64
+ forward_05_0000_8400: Item.new(per: +337, stack: +2633),
65
+ forward_06_0000_8400: Item.new(per: +202, stack: +2970),
66
+ forward_07_0000_7465: Item.new(per: +53, stack: +3172),
67
+ forward_07_7465_8400: Item.new(per: -7, stack: +3225), # +3172 + 53(初益)
68
+ forward_08_0000_8400: Item.new(per: -82, stack: +3218),
69
+ forward_09_0000_8400: Item.new(per: -224, stack: +3136),
70
+ forward_10_0000_8400: Item.new(per: -366, stack: +2912),
71
+ forward_11_0000_8400: Item.new(per: -509, stack: +2546),
72
+ forward_12_0000_8400: Item.new(per: -643, stack: +2037),
73
+ forward_13_0000_8400: Item.new(per: -748, stack: +1394),
74
+ forward_14_0000_6529: Item.new(per: -646, stack: +646), # 14日の小余は常に6529以下
75
+ back_01_0000_8400: Item.new(per: -830, stack: 0),
76
+ back_02_0000_8400: Item.new(per: -726, stack: -830),
77
+ back_03_0000_8400: Item.new(per: -598, stack: -1556),
78
+ back_04_0000_8400: Item.new(per: -464, stack: -2154),
79
+ back_05_0000_8400: Item.new(per: -329, stack: -2618),
80
+ back_06_0000_8400: Item.new(per: -195, stack: -2947),
81
+ back_07_0000_7465: Item.new(per: -53, stack: -3142),
82
+ back_07_7465_8400: Item.new(per: +7, stack: -3195), # -3142 - 53(初益)
83
+ back_08_0000_8400: Item.new(per: +82, stack: -3188),
84
+ back_09_0000_8400: Item.new(per: +225, stack: -3106),
85
+ back_10_0000_8400: Item.new(per: +366, stack: -2881),
86
+ back_11_0000_8400: Item.new(per: +501, stack: -2515),
87
+ back_12_0000_8400: Item.new(per: +628, stack: -2014),
88
+ back_13_0000_8400: Item.new(per: +740, stack: -1386),
89
+ back_14_0000_6529: Item.new(per: +646, stack: -646) # 14日の小余は常に6529以下
90
+ }.freeze
91
+ end
92
+
93
+ #
94
+ # 月の運行による補正値を算出する
95
+ #
96
+ # @param [Remainder] remainder_month 月の大余小余
97
+ # @param [True, False] is_forward 進(遠地点より数える)/退(近地点より数える)
98
+ #
99
+ # @return [Integer] 補正値
100
+ #
101
+ def self.calc_moon_orbit_value(remainder_month:, is_forward:)
102
+ valid?(remainder: remainder_month)
103
+
104
+ day, minute = make_calculable_remainder_value(remainder: remainder_month)
105
+
106
+ # 引き当て
107
+ adjustment, diff, minute = specify_moon_adjustment(
108
+ is_forward: is_forward, day: day, minute: minute
109
+ )
110
+ day = make_cumulative_value_for_days(per: adjustment.per,
111
+ denominator: diff, minute: minute)
112
+
113
+ adjustment.stack + day
114
+ end
115
+
116
+ #
117
+ # 大余小余を検証する
118
+ #
119
+ # @param [Remainder] remainder 大余小余
120
+ #
121
+ # @return [True] 正しい(月の位相計算に使う大余小余)
122
+ # @return [True] 正しくない
123
+ #
124
+ def self.valid?(remainder:)
125
+ return if remainder.is_a?(LunarRemainder)
126
+
127
+ raise ArgumentError, "unmatch parameter type: #{remainder.class}"
128
+ end
129
+ private_class_method :valid?
130
+
131
+ #
132
+ # 大余小余を計算可能な値にする
133
+ # @note 大余の秒(second)は使わない
134
+ #
135
+ # @param [LunarRemainder] remainder 大余小余
136
+ #
137
+ # @return [Integer] 大余
138
+ # @return [Integer] 小余
139
+ #
140
+ def self.make_calculable_remainder_value(remainder:)
141
+ day = remainder.day
142
+ minute = remainder.minute + (remainder.second / 100)
143
+ minute = minute.floor
144
+
145
+ [day, minute]
146
+ end
147
+ private_class_method :make_calculable_remainder_value
148
+
149
+ # :reek:TooManyStatements { max_statements: 9 }
150
+
151
+ #
152
+ # 累計値(大余)を作成する
153
+ #
154
+ # @param [Integer] per 入暦(1-14)
155
+ # @param [Integer] denominator 小余の分母
156
+ # @param [Integer] minute 小余
157
+ #
158
+ # @return [Integer] 累計値(大余)
159
+ #
160
+ def self.make_cumulative_value_for_days(per:, denominator:, minute:)
161
+ remainder_minute = (per * minute).to_f
162
+ day = remainder_minute / denominator
163
+ # 切り捨て(プラスマイナスに関わらず小数点以下切り捨て)
164
+ day = day.negative? ? day.ceil : day.floor
165
+ sign = remainder_minute.negative? ? -1 : 1
166
+ remainder_day = (sign * remainder_minute) % denominator
167
+ # 四捨五入(8400ならその半分の4200以上を繰り上げる)
168
+ day += sign if remainder_day >= (denominator / 2)
169
+
170
+ day
171
+ end
172
+ private_class_method :make_cumulative_value_for_days
173
+
174
+ # :reek:TooManyStatements { max_statements: 9 }
175
+
176
+ #
177
+ # 月軌道の補正に必要な基本値を引き当てる
178
+ #
179
+ # @note 戻り値は calc_moon_orbit_value で使用する
180
+ #
181
+ # @param [True, False] is_forward 進(遠地点より数える)/退(近地点より数える)
182
+ # @param [Integer] day 大余
183
+ # @param [Integer] minute 小余
184
+ #
185
+ # @return [Adjustment::Item] 補正値
186
+ # @return [Integer] (小余を処理する時の)分母
187
+ # @return [Integer] 小余の下げ幅
188
+ #
189
+ def self.specify_moon_adjustment(is_forward:, day:, minute:)
190
+ prefix = { true => 'forward', false => 'back' }[is_forward]
191
+
192
+ targets = Adjustment::LIST.select \
193
+ { |key, _| key.match(/^#{prefix}_#{format('%<day>02d', day: day)}_.*/) }
194
+
195
+ targets.each do |key, value|
196
+ # NOTE 境界値は上から順に引き当てた方を返す(7日の境界値7465は上のキーで返す)
197
+ matched, diff = \
198
+ extract_data_from_moon_adjustment_key(key, minute)
199
+ # 小余の下げ幅
200
+ calc_minute = (day == 7 && minute > 7465 ? minute - 7465 : minute)
201
+ return value, diff, calc_minute if matched
202
+ end
203
+
204
+ [nil, nil, nil]
205
+ end
206
+ private_class_method :specify_moon_adjustment
207
+
208
+ #
209
+ # 補正値を引き当てる
210
+ #
211
+ # @param [String] key 補正値のキー
212
+ # @param [Integer] minute 小余
213
+ #
214
+ # @return [Adjustment::Item] 補正値
215
+ # @return [Integer] (小余を処理する時の)分母
216
+ #
217
+ def self.extract_data_from_moon_adjustment_key(key, minute)
218
+ matched = key.match(/([0-9]{4})_([0-9]{4})$/)
219
+ start = matched[1].to_i
220
+ finish = matched[2].to_i
221
+
222
+ matched = minute >= start && minute <= finish
223
+ [matched, (finish - start)]
224
+ end
225
+ private_class_method :extract_data_from_moon_adjustment_key
226
+
227
+ # :reek:ControlParameter and :reek:BooleanParameter
228
+ # :reek:LongParameterList { max_params: 4 }
229
+
230
+ #
231
+ # 月地点を計算する
232
+ #
233
+ # @param [LunarRemainder] remainder 初回(昨年冬至), 前回計算結果(入暦)
234
+ # @param [Integer] western_year 西暦年
235
+ # @param [True, False] is_forward 進(遠地点より数える)/退(近地点より数える)
236
+ # @param [True, False] first 初回計算, 次回以降計算
237
+ #
238
+ # @return [LunarRemainder] 入暦
239
+ # @return [True] 進(遠地点より数える)
240
+ # @return [False] 退(近地点より数える)
241
+ #
242
+ def self.calc_moon_point(remainder:, western_year:,
243
+ is_forward: true, first: true)
244
+ if first
245
+ return calc_first_moon_point(winter_solstice_age: remainder,
246
+ western_year: western_year)
247
+ end
248
+ calc_following_moon_point(remainder: remainder, is_forward: is_forward)
249
+ end
250
+
251
+ # :reek:TooManyStatements { max_statements: 7 }
252
+
253
+ #
254
+ # 入暦(月の遠地点から数えた日数/近地点から数えた日数)を求める
255
+ #
256
+ # 天正冬至(入暦前回未計算)を求める
257
+ #
258
+ # @param [Remainder] winter_solstice_age 昨年冬至
259
+ # @param [Integer] western_year 西暦年
260
+ #
261
+ # @return [LunarRemainder] 入暦
262
+ # @return [True] 進(遠地点より数える)
263
+ # @return [False] 退(近地点より数える)
264
+ #
265
+ def self.calc_first_moon_point(winter_solstice_age:, western_year:)
266
+ # 積年の開始から対象年までの年数
267
+ total_year = \
268
+ WinterSolstice::TOTAL_YEAR + western_year - WinterSolstice::BEGIN_YEAR
269
+
270
+ # 通積分 - 天正閏余
271
+ total_day = \
272
+ total_year * WinterSolstice::YEAR - winter_solstice_age.to_minute
273
+
274
+ remainder_month = \
275
+ LunarRemainder.new(total: (total_day % ANOMALISTIC_MONTH))
276
+
277
+ remainder_month, is_forward = decrease_moon_point(
278
+ remainder_month: remainder_month,
279
+ remainder_limit: HALF_ANOMALISTIC_MONTH, is_forward: true
280
+ )
281
+
282
+ remainder_month.add!(Remainder.new(day: 1, minute: 0, second: 0))
283
+
284
+ [remainder_month, is_forward]
285
+ end
286
+ private_class_method :calc_first_moon_point
287
+
288
+ #
289
+ # 入暦(月の遠地点から数えた日数/近地点から数えた日数)を求める
290
+ #
291
+ # 前回計算結果を補正する
292
+ #
293
+ # @param [LunarRemainder] remainder 前回計算結果(入暦)
294
+ # @param [True, False] is_forward 進(遠地点より数える)/退(近地点より数える)
295
+ #
296
+ # @return [LunarRemainder] 入暦
297
+ # @return [True] 進(遠地点より数える)
298
+ # @return [False] 退(近地点より数える)
299
+ #
300
+ def self.calc_following_moon_point(remainder:, is_forward:)
301
+ # 前回計算結果を引き継いた場合、暦中日ではなく損益眺朒(ちょうじく)数の上限とする
302
+ remainder_month, is_forward = \
303
+ decrease_moon_point(
304
+ remainder_month: remainder,
305
+ remainder_limit: Remainder.new(day: 14, minute: 6529, second: 0),
306
+ is_forward: is_forward
307
+ )
308
+
309
+ [remainder_month, is_forward]
310
+ end
311
+ private_class_method :calc_following_moon_point
312
+
313
+ #
314
+ # 月地点を減算する
315
+ #
316
+ # @param [LunarRemainder] remainder_month 大余小余
317
+ # @param [Remainder] remainder_limit 大余小余の上限(最大の入暦)
318
+ # @param [True, False] is_forward 進(遠地点より数える)/退(近地点より数える)
319
+ #
320
+ # @return [LunarRemainder] 大余小余の減算結果(上限値超えした場合)
321
+ # @return [True] 進(遠地点より数える)
322
+ # @return [False] 退(近地点より数える)
323
+ #
324
+ def self.decrease_moon_point(remainder_month:, remainder_limit:, is_forward:)
325
+ return remainder_month, is_forward if remainder_month < remainder_limit
326
+
327
+ [remainder_month.sub(HALF_ANOMALISTIC_MONTH), !is_forward]
328
+ end
329
+ private_class_method :decrease_moon_point
330
+ end
331
+ end
332
+ end