four-pillars 0.1.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.
@@ -0,0 +1,320 @@
1
+ require 'date'
2
+
3
+ class FourPillarsLogic
4
+ JIKKAN = ["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
5
+ JYUNISHI = ["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
6
+ TSUHENSEI = ["比肩","劫財","食神","傷官","偏財","正財","偏官","正官","偏印","印綬"]
7
+ JYUNIUNSEI = ["長生","沐浴","冠帯","建禄","帝旺","衰","病","死","墓","絶","胎","養"]
8
+ GOGYO = ["木","火","土","金","水"]
9
+ KUUBOU = ["戌亥","申酉","午未","辰巳","寅卯","子丑"]
10
+
11
+ # 60干支表
12
+ def self.kanshi_array
13
+ a = []
14
+ 60.times do |i|
15
+ j1 = FourPillarsLogic::JIKKAN[i%10]
16
+ j2 = FourPillarsLogic::JYUNISHI[i%12]
17
+ a += [j1+j2]
18
+ end
19
+ return a
20
+ end
21
+ KANSHI_ARRAY = kanshi_array
22
+
23
+ # 60干支表
24
+ def self.kanshi_hash
25
+ h = {}
26
+ kanshi_array.each_with_index do |v,i|
27
+ h[v] = i+1
28
+ end
29
+ return h
30
+ end
31
+ KANSHI_HASH = kanshi_hash
32
+
33
+ # 陰干通表
34
+ def self.jikkan_in
35
+ j = [nil] * 10
36
+ [0,2,4,6,8].each do |i|
37
+ j[i] = JIKKAN[i+1]
38
+ j[i+1] = JIKKAN[i]
39
+ end
40
+ return j
41
+ end
42
+ JIKKAN_IN = jikkan_in
43
+ JYUNISHI_IN = JYUNISHI.reverse
44
+
45
+ # 十二運星エネルギー
46
+ def self.jyuniunsei_energy
47
+ h = {}
48
+ energies = [9,7,10,11,12,8,4,2,5,1,3,6]
49
+ 12.times do |i|
50
+ h[JYUNIUNSEI[i]] = energies[i]
51
+ end
52
+ return h
53
+ end
54
+ JYUNIUNSEI_ENERGY = jyuniunsei_energy
55
+
56
+ # 年月の節入り日時 (注:時 = 時間 x 60 + 分)
57
+ def self.load_setsuiri
58
+ l = []
59
+ h = {}
60
+ open(__dir__+"/four-pillars-setsuiri.txt").each do |line|
61
+ next if line.strip.empty? || line.start_with?("#")
62
+ vs = line.split(",")
63
+ if vs.count != 5 || vs[0].empty?
64
+ puts "Invalid row: #{line}"
65
+ next
66
+ end
67
+ vs.map! { |v| v.to_i }
68
+ h[vs[0]*100+vs[1]] = [vs[2],vs[3]*60+vs[4]]
69
+ l += [vs]
70
+ end
71
+ return h, l
72
+ end
73
+ SETSUIRI_HASH, SETSUIRI_LIST = load_setsuiri
74
+
75
+ # 生年月日時間, 性別(鑑定には使用しない)
76
+ attr_reader :birth_dt,:gender
77
+
78
+ def initialize(birth_dt,gender)
79
+ @birth_dt = birth_dt.map {|v| v.to_i }
80
+ @gender = gender
81
+ raise "Incorrect birth date: #{birth_dt}" if @birth_dt.count != 5
82
+ raise "Gender must be m,f or o(other): #{gender}" unless ['o','m','f'].include? @gender
83
+ raise "Year must be larger than 1863" if @birth_dt[0] < 1864
84
+ end
85
+
86
+ # 生年月日と性別
87
+ def input
88
+ y,m,d,h,i = @birth_dt
89
+ case @gender
90
+ when 'm' then
91
+ g = "男性"
92
+ when 'f' then
93
+ g = "女性"
94
+ else
95
+ g = ""
96
+ end
97
+ "#{y}年#{m}月#{d}日#{h}時#{i}分生 #{g}"
98
+ end
99
+
100
+ # 前月の日数
101
+ def days_of_previous_month
102
+ y,m,d,h,i = @birth_dt
103
+ (Date.new(y,m,1) - 1).day
104
+ end
105
+
106
+ # 前月の節入日
107
+ def setsuiri_of_previous_month
108
+ y,m,d,h,i = @birth_dt
109
+ if m == 1
110
+ y -= 1
111
+ m = 12
112
+ else
113
+ m -= 1
114
+ end
115
+ SETSUIRI_HASH[y*100+m] || [0,0]
116
+ end
117
+
118
+ # 生年月に対する節入日時を知っているか?
119
+ # このメソッドがfalseを返す場合、干支、蔵干が仮の節入日で計算されています。
120
+ def know_setsuiri?
121
+ y,m,d,h,i = @birth_dt
122
+ SETSUIRI_HASH.include? y*100+m
123
+ end
124
+
125
+ # 生年月に対応する節入り日時 ファイルに登録がない場合は、4日12時を返す
126
+ def setsuiri
127
+ y,m,d,h,i = @birth_dt
128
+ SETSUIRI_HASH[y*100+m] || [4,12*60]
129
+ end
130
+
131
+ # 生まれた日が節入日にあたる場合、true
132
+ def setsuiri?
133
+ return false unless know_setsuiri?
134
+ y,m,d,h,i = @birth_dt
135
+ setsuiri[0] == d
136
+ end
137
+
138
+ # 干支(日,月,年)
139
+ def kanshi
140
+ y,m,d,h,i = @birth_dt
141
+ sd, st = setsuiri
142
+ yd = y - 1864 # (till 1865.02.0?) = 甲子
143
+ yd -= 1 if m < 2 || (m == 2 && d < sd) || (m == 2 && d == sd && h*60+i < st)
144
+ md = (y - 1863) * 12 + (m - 12) # (till 1864.01.05) = 甲子
145
+ md -= 1 if d < sd || (d == sd && h*60+i < st)
146
+ dd = Date.new(y,m,d) - Date.new(1863,12,31) # 1923.10.18 = 甲子
147
+
148
+ return [KANSHI_ARRAY[dd % 60],KANSHI_ARRAY[md % 60],KANSHI_ARRAY[yd % 60]]
149
+ end
150
+
151
+ # 干支(数字)
152
+ def kanshi_as_number
153
+ kanshi.map {|v| KANSHI_HASH[v] }
154
+ end
155
+
156
+ # 蔵干数字
157
+ def zokan_number
158
+ y,m,d,h,i = @birth_dt
159
+ sd, st = setsuiri
160
+ if d < sd || (d == sd && h*60+i < st)
161
+ # 誕生日 + (前月の日数 - 前月の節入日) + 1
162
+ return d + (days_of_previous_month - setsuiri_of_previous_month[0]) + 1
163
+ else
164
+ # 誕生日 - 節入日 + 1
165
+ return d - sd + 1
166
+ end
167
+ end
168
+
169
+ def zokan
170
+ zokan_hash1 = {"子" => "癸","卯" => "乙","酉" => "辛"}
171
+ zokan_hash2 = {"午" => ["己",19,"丁"],"亥" => ["甲",12,"壬"]}
172
+ zokan_hash3 = {"丑" => ["癸",9,"辛",12,"己"],"寅" => ["戊",7,"丙",14,"甲"],
173
+ "辰" => ["乙",9,"癸",12,"戊"],"巳" => ["戊",5,"庚",14,"丙"],"未" => ["丁",9,"乙",12,"己"],
174
+ "申" => ["戊",10,"壬",13,"庚"],"戌" => ["辛",9,"丁",13,"戊"]}
175
+ zn = zokan_number
176
+ z = []
177
+ kanshi.each do |k|
178
+ j = k[1] # 十二支
179
+ if zokan_hash1.keys.include? j
180
+ z += [zokan_hash1[j]]
181
+ elsif zokan_hash2.keys.include? j
182
+ arr = zokan_hash2[j]
183
+ if zn <= arr[1]
184
+ z += [arr[0]]
185
+ else
186
+ z += [arr[2]]
187
+ end
188
+ elsif zokan_hash3.keys.include? j
189
+ arr = zokan_hash3[j]
190
+ if zn <= arr[1]
191
+ z += [arr[0]]
192
+ elsif zn <= arr[3]
193
+ z += [arr[2]]
194
+ else
195
+ z += [arr[4]]
196
+ end
197
+ end
198
+ end
199
+ return z
200
+ end
201
+
202
+ # 通変星(nil,月,年)
203
+ def tsuhensei
204
+ j = JIKKAN.index(kanshi[0][0])
205
+ if j % 2 == 0 # 陽
206
+ jikkan = JIKKAN
207
+ else # 陰
208
+ jikkan = JIKKAN_IN
209
+ end
210
+ j = jikkan.index(kanshi[0][0])
211
+ j_month = jikkan.index(kanshi[1][0])
212
+ j_year = jikkan.index(kanshi[2][0])
213
+ t_month = j_month - j
214
+ t_month += 10 if t_month < 0
215
+ t_year = j_year - j
216
+ t_year += 10 if t_year < 0
217
+ [nil,TSUHENSEI[t_month],TSUHENSEI[t_year]]
218
+ end
219
+
220
+ # 蔵干通変星
221
+ def zokan_tsuhensei
222
+ j = JIKKAN.index(kanshi[0][0])
223
+ if j % 2 == 0 # 陽
224
+ jikkan = JIKKAN
225
+ else # 陰
226
+ jikkan = JIKKAN_IN
227
+ end
228
+ j = jikkan.index(kanshi[0][0])
229
+ j_day = jikkan.index(zokan[0])
230
+ j_month = jikkan.index(zokan[1])
231
+ j_year = jikkan.index(zokan[2])
232
+ t_day = j_day - j
233
+ t_day += 10 if t_day < 0
234
+ t_month = j_month - j
235
+ t_month += 10 if t_month < 0
236
+ t_year = j_year - j
237
+ t_year += 10 if t_year < 0
238
+ [TSUHENSEI[t_day],TSUHENSEI[t_month],TSUHENSEI[t_year]]
239
+ end
240
+
241
+ # 十二運星
242
+ def jyuniunsei
243
+ j = JIKKAN.index(kanshi[0][0])
244
+ if j % 2 == 0 # 陽
245
+ jyunishi = JYUNISHI
246
+ else # 陰
247
+ jyunishi = JYUNISHI_IN
248
+ end
249
+ offset = [1,7,10,10,10,10,7,1,4,4][j] # 十二運表より求めたオフセット
250
+ j_day = jyunishi.index(kanshi[0][1])
251
+ j_month = jyunishi.index(kanshi[1][1])
252
+ j_year = jyunishi.index(kanshi[2][1])
253
+ u_day = (j_day + offset) % 12
254
+ u_month = (j_month + offset) % 12
255
+ u_year = (j_year + offset) % 12
256
+ [JYUNIUNSEI[u_day],JYUNIUNSEI[u_month],JYUNIUNSEI[u_year]]
257
+ end
258
+
259
+ def jyuniunsei_energy
260
+ jyuniunsei.map {|v| JYUNIUNSEI_ENERGY[v] }
261
+ end
262
+
263
+ # 空亡 = 天中殺
264
+ def kuubou
265
+ k_day = (kanshi_as_number[0] - 1) / 10
266
+ k_year = (kanshi_as_number[2] - 1) / 10
267
+ [KUUBOU[k_day],KUUBOU[k_year]]
268
+ end
269
+
270
+ # テーブル表示用に配列にして返す (デバッグ用)
271
+ # 0:干支, 1:干支数字, 2:蔵干, 3:通変星, 4:蔵干通変星, 5:十二運星
272
+ # 五行、天中殺、十二運星エネルギーは別途
273
+ def tell
274
+ m = [kanshi]
275
+ m += [kanshi_as_number]
276
+ m += [zokan]
277
+ m += [tsuhensei]
278
+ m += [zokan_tsuhensei]
279
+ m += [jyuniunsei]
280
+ m += [jyuniunsei_energy]
281
+ end
282
+
283
+ # 五行(十干)
284
+ def gogyo_jikkan
285
+ arr = []
286
+ 3.times do |i|
287
+ j = JIKKAN.index(kanshi[i][0])
288
+ arr += [(j % 2 == 0 ? "+" : "-") + GOGYO[j / 2]]
289
+ end
290
+ return arr
291
+ end
292
+
293
+ # 五行(十二支)
294
+ def gogyo_jyunishi
295
+ arr = []
296
+ gogyo_j = ["水","土","木","木","土","火","火","土","金","金","土","水"]
297
+ 3.times do |i|
298
+ j = JYUNISHI.index(kanshi[i][1])
299
+ arr += [(j % 2 == 0 ? "+" : "-") + gogyo_j[j]]
300
+ end
301
+ return arr
302
+ end
303
+ end
304
+
305
+ if __FILE__ == $0
306
+ require 'optparse'
307
+ Version = "1.0.0"
308
+
309
+ bd = ["1980","7","27","1","20"]
310
+ gender = 'm' # m or f
311
+
312
+ opt = OptionParser.new
313
+ opt.on('-b y,m,d,h,m') { |v| bd = v.split(",")}
314
+ opt.on('-g (m|f)') { |v| gender = v }
315
+ opt.parse!(ARGV)
316
+
317
+ res = FourPillarsLogic.new(bd,gender)
318
+ puts res.input
319
+ puts res.tell
320
+ end
metadata ADDED
@@ -0,0 +1,44 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: four-pillars
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yosei Ito
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-07-30 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Tell your meishiki from your birthday and time.
14
+ email: y-itou@lumber-mill.co.jp
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/four-pillars-setsuiri.txt
20
+ - lib/four-pillars.rb
21
+ homepage: https://github.com/lumbermill/four-pillars
22
+ licenses:
23
+ - MIT
24
+ metadata: {}
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ requirements: []
40
+ rubygems_version: 3.0.3
41
+ signing_key:
42
+ specification_version: 4
43
+ summary: Fortune telling
44
+ test_files: []