@@ -29,89 +29,95 @@ exports.Win = Win
29
29
class Bad extends Error { }
30
30
exports . Bad = Bad
31
31
32
+ // https://github.com/hexenq/kuroshiro/issues/64
33
+ async function toHiragana ( word ) {
34
+ const hira = await kuroshiro . convert ( word , { to : 'hiragana' } )
35
+ return wanakana . toHiragana ( hira )
36
+ }
37
+
32
38
// しりとりのルールのチェック。
33
- exports . check = ( word , chain ) => loaded . then ( ( ) => {
34
- return Promise . all ( [
35
- kuroshiro . convert ( word , { to : 'hiragana' } ) ,
36
- ...chain . map ( e => kuroshiro . convert ( e , { to : 'hiragana' } ) )
37
- ] ) . then ( ( [ word , ...chain ] ) => {
38
- // 漢字からひらがなにする。
39
- const wordHira = wanakana . toHiragana ( word )
40
- if ( wordHira [ wordHira . length - 1 ] === 'ん' ) {
41
- throw new Bad ( 'ends with ん' )
42
- }
39
+ exports . check = ( word , chain ) => loaded . then ( async ( ) => {
40
+ //「ん」で終わるかどうか?
41
+ const wordHira = await toHiragana ( word )
42
+ if ( wordHira [ wordHira . length - 1 ] === 'ん' ) {
43
+ throw new Bad ( 'ends with ん' )
44
+ }
43
45
44
- if ( ( chain === undefined ) || ( chain . length === 0 ) ) {
45
- return true
46
- }
46
+ // 漢字からひらがなにする。
47
+ if ( ( chain === undefined ) || ( chain . length === 0 ) ) {
48
+ return true
49
+ }
47
50
48
- // 使った名詞をチェックする。
49
- const chainHira = chain . map ( wanakana . toHiragana )
50
- if ( chainHira . indexOf ( wordHira , 0 ) !== - 1 ) {
51
- throw new Bad ( 'already used' )
52
- }
51
+ // 使った名詞をチェックする。
52
+ const chainHira = await Promise . all ( chain . map ( toHiragana ) )
53
+ if ( chainHira . includes ( wordHira ) ) {
54
+ throw new Bad ( 'already used' )
55
+ }
53
56
54
- // しりとりの最初の文字をチェックする。
55
- return exports . kanas ( chain [ 0 ] ) . then ( validKanas => {
56
- for ( const k of validKanas ) {
57
- const begin = wordHira . slice ( 0 , k . length )
58
- if ( begin === k ) {
59
- return true
60
- }
61
- }
62
- throw new Bad ( '文字 does not match' )
63
- } )
64
- } )
57
+ // しりとりの最初の文字をチェックする。
58
+ const validKanas = await exports . kanas ( chain [ 0 ] )
59
+ for ( const k of validKanas ) {
60
+ const begin = wordHira . slice ( 0 , k . length )
61
+ if ( begin === k ) {
62
+ return true
63
+ }
64
+ }
65
+ throw new Bad ( '文字 does not match' )
65
66
} )
66
67
67
68
// 名詞からしりとりのひらがなを選ぶ。
68
- exports . kanas = word => loaded
69
- . then ( ( ) => kuroshiro . convert ( word , { to : 'hiragana' } ) )
70
- . then ( ( word ) => {
71
- const wordKana = wanakana . toKatakana ( word )
72
- const wordHira = wanakana . toHiragana ( wordKana )
73
- const kk = wordKana [ wordKana . length - 1 ]
74
- const hk = wordHira [ wordHira . length - 1 ]
75
-
76
- if ( hk === 'ん' ) {
77
- return [ ]
78
- }
69
+ exports . kanas = word => loaded . then ( async ( ) => {
70
+ const wordKana = await kuroshiro . convert ( word , { to : 'katakana' } )
71
+ const wordHira = wanakana . toHiragana ( wordKana )
72
+ const kk = wordKana [ wordKana . length - 1 ]
73
+ const hk = wordHira [ wordHira . length - 1 ]
79
74
80
- if ( ( kk === 'ー' ) && ( wordKana . length > 1 ) ) {
81
- return [
82
- wordHira [ wordHira . length - 1 ] ,
83
- wordHira [ wordHira . length - 2 ]
84
- ]
85
- }
75
+ if ( hk === 'ん' ) {
76
+ return [ ]
77
+ }
86
78
87
- if ( smallKanas . includes ( hk ) ) {
88
- return [
89
- String . fromCharCode ( hk . charCodeAt ( 0 ) + 1 ) ,
90
- wordHira . slice ( - 2 )
91
- ]
92
- }
79
+ // サー→「さ、あ」。
80
+ if ( ( kk === 'ー' ) && ( wordKana . length > 1 ) ) {
93
81
return [
94
- wordHira [ wordHira . length - 1 ]
82
+ wordHira [ wordHira . length - 1 ] ,
83
+ wordHira [ wordHira . length - 2 ]
95
84
]
96
- } )
97
- . then ( result => new Set ( result ) )
85
+ }
86
+
87
+ // しゃ→「しゃ、や」。
88
+ if ( smallKanas . includes ( hk ) ) {
89
+ return [
90
+ String . fromCharCode ( hk . charCodeAt ( 0 ) + 1 ) ,
91
+ wordHira . slice ( - 2 )
92
+ ]
93
+ }
94
+
95
+ // 最後の文字。
96
+ return [
97
+ wordHira [ wordHira . length - 1 ]
98
+ ]
99
+ } ) . then ( result => new Set ( result ) )
98
100
99
101
// しりとりのゲームループ。
100
- exports . interact = ( dict , word , chain ) => exports . check ( word , chain )
101
- . then ( ( ) => exports . kanas ( word ) )
102
- . then ( validKanas => dict ( validKanas . values ( ) . next ( ) . value ) )
103
- . then ( words => {
104
- const unused = words ? Object . keys ( words ) . filter ( k => ! chain . includes ( words [ k ] ) ) : [ ]
105
- if ( unused . length === 0 ) {
106
- throw new Win ( 'no more unused word remaining in dictionary' )
107
- }
108
- const w = unused [ Math . floor ( Math . random ( ) * unused . length ) ]
109
- const wk = words [ w ]
110
- if ( wk . length === 0 ) {
111
- throw new Error ( `no dictionary entry for key: ${ w } ` )
112
- }
113
- if ( wk [ wk . length - 1 ] === 'ん' ) {
114
- throw new Win ( 'dictionary word ends with ん' )
115
- }
116
- return { word : w , kana : wk }
117
- } )
102
+ exports . interact = ( dict , word , chain ) => {
103
+ return exports . check ( word , chain ) . then ( async ( ) => {
104
+ const validKanas = await exports . kanas ( word )
105
+ // 他のかなもチェックしたほうかいい。
106
+ const firstValid = validKanas . values ( ) . next ( ) . value
107
+ const words = await dict ( firstValid )
108
+ const unused = words ? Object . keys ( words ) . filter ( k => ! chain . includes ( words [ k ] ) ) : [ ]
109
+ if ( unused . length === 0 ) {
110
+ throw new Win ( 'no more unused word remaining in dictionary' )
111
+ }
112
+ // ランダムでえらぶ。
113
+ const w = unused [ Math . floor ( Math . random ( ) * unused . length ) ]
114
+ const wk = words [ w ]
115
+ if ( wk . length === 0 ) {
116
+ throw new Error ( `no dictionary entry for key: ${ w } ` )
117
+ }
118
+ if ( wk [ wk . length - 1 ] === 'ん' ) {
119
+ throw new Win ( 'dictionary word ends with ん' )
120
+ }
121
+ return { word : w , kana : wk }
122
+ } )
123
+ }
0 commit comments