16
\$\begingroup\$

The flick input method is a way of inputting Japanese kana on a modern smartphone. It is arranged in a 12-key layout, with the following labels:

あかさ
たなは
まやら
小わ、

When a key is tapped, it produces its respective kana. However, when the key is flicked in one of the four cardinal directions (up, down, left, right) it produces the kana with the respective vowel:

 u
iae
 o

where the center vowel is the key, just tapped and not flicked.

So, when the key is swiped up, it will produce the kana.

A special key is the key. By default, just tapping on the key will cycle the previous kana between it's "small" and "large" forms.

Swiping down-left will apply a dakuten, and down-right a handakuten, if it can be applied to the kana.

For this challenge, the key will have the following flick mapping:

 小
゛小゜
 ゛ <-- this is a dakuten

Kana with dakuten, handakuten, and small forms are in the table below. If the kana does not have a small form when is pressed, it is a NOP. Similarly, if a kana does not have a dakuten or handakuten form when one is applied, it is also a NOP.

Some keys have either a special layout and punctuation characters assigned to them:

flick input from wikimedia commons

Image source: Wikimedia Commons

Note here that the and keys have punctuation assigned:

 ゆ
(や) <-- unicode FF08, FF09
 よ

 ん
をわー <-- unicode 30FC
 〜  <-- unicode 301C

You will need to handle punctuation, but only on and . This challenge will not be using the key.

Hiragana

Hiragana is Japanese's native syllabic writing system. Most hiragana can be considered as a pair of a consonant and a vowel:

a i u e o
k
s
t
n
h
m
y    
r
w      

"ん" is special because it is the only hiragana without a vowel.

Some hiragana can have a diacritic applied called a "dakuten" or "handakuten" that either voices the consonant (e.g. "k" to "g") or "half-voices" the consonant (only for h-series kana, from "h" to "p"). Some kana also have a small form (applies to vowels, y-series kana, and つ).

Kana Dakuten Handakuten Small
あいうえお ぁぃぅぇぉ
かきくけこ がぎぐげご
さしすせそ ざじずぜぞ
たちつてと だぢづでど
はひふへほ ばびぶべぼ ぱぴぷぺぽ
やゆよ ゃゅょ

Input

Input is a string of hiragana using any reasonable input format: a string, a list/array of characters, a sequence of raw Unicode bytes, etc.

Output

Output is a sequence of inputs for the 12-key flick input method. You may use any reasonable output format. However, each input in the sequence must be at least 2 distinguishable parts, and must encode at minimum the following:

  • Which key is tapped, and
  • Which direction it is swiped, if at all.

You must specify what encoding you use for your output. (The two-part output is to prevent mapping kana to a single value one-to-one.)

Test Cases

For these test cases, output will be in the format of space-separated KD, where K is the kana's consonant (or "a" if it is ), and D is one of 58426 (directions on a numpad, 5 for no swipe). The key will be represented as x.

かな --> k5 n5
ありがとう --> a5 r4 k5 x4 t2 a8
ありがとうございます --> a5 r4 k5 x4 t2 a8 k2 x4 s5 x4 a4 m5 s8
だがことわる -->  t5 x4 k5 x4 k2 t2 w5 r8
おまえはもうしんでいる --> a2 m5 a6 h5 m2 a8 s4 w8 t6 x4 a4 r8
かかります --> k5 k5 r4 m5 s8
あ --> a5
た --> t5
っ --> t8 x5
ぬ --> n8
ぎゅうにゅ --> k4 x4 y8 x5 a8 n4 y8 x5
やつた --> y5 t8 t5
やづた --> y5 t8 x4 t5
やった --> y5 t8 x5 t5
は --> h5
ば --> h5 x4
ぱ --> h5 x6
(わらい) --> y4 w5 r5 a4 y6
どじゃあぁーん〜 --> t2 x4 s4 x4 y5 x5 a5 a5 x5 w6 w8 w2
を --> w2

This is a related inverse of this post for keitai to kana.

\$\endgroup\$
4
  • 2
    \$\begingroup\$ This is a very interesting question but assumes a lot of understanding of Kana. It would get a lot more interest if you add a good explanation of the writng system, including a standard table showing the english consonants down one side and the 5 english vowels along the top, as well as the unicode for each symbol. \$\endgroup\$ Dec 18, 2023 at 14:32
  • 1
    \$\begingroup\$ @LevelRiverSt done \$\endgroup\$
    – bigyihsuan
    Dec 18, 2023 at 15:24
  • \$\begingroup\$ Is trailing space allowed? \$\endgroup\$
    – Fmbalbuena
    Dec 18, 2023 at 19:26
  • \$\begingroup\$ @Fmbalbuena per the "reasonable output" link above yes \$\endgroup\$
    – bigyihsuan
    Dec 18, 2023 at 21:06

2 Answers 2

3
\$\begingroup\$

Python 3, 511 410 chars

[print('わあ  わい  わう  やい  やえ  わお  わえ  ああ小あああ  あい小ああい  あう小ああう  あえ小ああえ  あお小ああお  かあ  かあ小おかい  かい小おかう  かう小おかえ  かえ小おかお  かお小おさあ  さあ小おさい  さい小おさう  さう小おさえ  さえ小おさお  さお小おたあ  たあ小おたい  たい小おたう小あたう  たう小おたえ  たえ小おたお  たお小おなあ  ない  なう  なえ  なお  はあ  はあ小おはあ小えはい  はい小おはい小えはう  はう小おはう小えはえ  はえ小おはえ小えはお  はお小えはお小えまあ  まい  まう  まえ  まお  やあ小あやあ  やう小あやう  やお小あやお  らあ  らい  らう  らえ  らお'[x:x+4])for x in[(ord(x)-126)%188%153%111%87%85*4for x in input()]]

Try it online!

more bytes since using kana as output, but they are just for output. it works the exact same in 511 bytes if you use boring ascii:

Python 3, 511 410 bytes

[print('wa  wi  wu  yi  ye  wo  we  aaxaaa  aixaai  auxaau  aexaae  aoxaao  ka  kaxoki  kixoku  kuxoke  kexoko  koxosa  saxosi  sixosu  suxose  sexoso  soxota  taxoti  tixotuxatu  tuxote  texoto  toxona  ni  nu  ne  no  ha  haxohaxehi  hixohixehu  huxohuxehe  hexohexeho  hoxehoxema  mi  mu  me  mo  yaxaya  yuxayu  yoxayo  ra  ri  ru  re  ro'[x:x+4])for x in[(ord(x)%188-126)%188%153%111%87%85*4for x in input()]]

Try it online!

it gives you 4 chars of output for every char of input, and you read it in pairs; ie if you give it ぁあ it'll give you ああ小あ and ああ meaning the first char is made by selecting the あ key in the あ direction and the 小 key in the あ direction and that the second char is just selecting the あ key in the あ direction. (so the first is one of あかさたなはまやら小わ and the second is one of あいうえお). the tio links just have all the characters for your convenience. they're ordered by unicode codepoint, lowest to highest. any other characters you put in there will just tell you about a random key. I tried to find something mathematically that would let me build the first then the second char but there's so many exceptions that it's faster to just manually map each one.

-101 bytes because I finally got around to swapping out the if statements for modulus operations

Explanation:

[                #open main for loop
print(           #open print statement
'は...え'         #list of instructions, spaced at 4 chars per instruction
[x:x+4]          #chars from index x to index x+4
)                #end of print statement; print the slice we just indexed
for x in[        #says 'do the previous on each item in the coming list'
(ord(x)-126)%188 #188 is a magic number mapping the output of ord to unique values in a small range. subtracting 126 keeps the consecutive kana consecutive.
%153%111%87%85   #these slot the rest of the values which were at random locations into the start of the string.
*4               #spaces out the values we are indexing into
for x in input() #input() defaults to a string, so to iterate against it you have to add this extra loop
]                #close the input for loop and make it into a list for the main loop to iterate on
]                #close main for loop and save it as a list into a non-existent variable; we're sending output as we go along with the print statement so we don't need it

since it's just manually mapping to the string, adding in the punctuation key doesn't cost that much:

Python 3, 444 chars

[print('わえ  、あ  、い  やい  やえ  、う  、お  わお  ああ小あああ  あい小ああい  あう小ああう  あえ小ああえ  あお小ああお  かあ  かあ小おかい  かい小おかう  かう小おかえ  かえ小おかお  かお小おさあ  さあ小おさい  さい小おさう  さう小おさえ  さえ小おさお  さお小おたあ  たあ小おたい  たい小おたう小あたう  たう小おたえ  たえ小おたお  たお小おなあ  ない  なう  なえ  なお  はあ  はあ小おはあ小えはい  はい小おはい小えはう  はう小おはう小えはえ  はえ小おはえ小えはお  はお小えはお小えまあ  まい  まう  まえ  まお  やあ小あやあ  やう小あやう  やお小あやお  らあ  らい  らう  らえ  らお  ,   わあ  .   .   わい  わう  、え  '[x:x+4])for x in[(ord(x)%195-60)%152%126%116%95*4for x in input()]]

Try it online!

the moduluses you preform on ord are different ((ord(x)%195-60)%152%126%116%95) but the idea is the same. the additional characters were added to the test cases on the tio link

\$\endgroup\$
2
\$\begingroup\$

Go + golang.org/x/text/unicode/runenames, 603 bytes

import(."strings";."golang.org/x/text/unicode/runenames")
func f(s []rune)(o string){V,F,C,K,G,Q,I:="AIUEO","54862",Fields(".KS TNH MYR XW."),"KSTH","GZDB",CutPrefix,Index
for _,k:=range s{n,_:=Q(Name(k),"HIRAGANA LETTER ")
n,s:=Q(n,"SMALL ")
a,v:=IndexByte(G,n[0]),n[1:]
if len(n)==1{if n=="N"{o+="W8"}else{o+="A"+string(F[I(V,n)])}}else if k=='ー'{o+="W6"}else if k=='〜'{o+="W2"}else if k=='('{o+="Y4"}else if k==')'{o+="Y6"}else{if v=string(F[I(V,v)]);a<0{if n[0]=='P'{o+="H"+v+"X6"}else{for _,R:=range C{if i:=I(R,n[0:1]);i>-1{o+=R[i:i+1]+v}}}}else{o+=K[a:a+1]+v+"X4"}}
if s{o+="X5"}}
return}

You Cannot Attempt This Online!

Do it on the Playground instead!

An extremely scuffed, straightforward solution. Uses the Name function from golang.org/x/text/unicode/runenames to get the name of each kana, then selects the flick input based on that.

Output is a concatenated string of the form Cn where C is the uppercase consonant of the flick input, and n is one of 54862.

Ungolfed Explanation

func f(inputString []rune) (o string) {
    VOWEL := "AIUEO"
    FLICKS := "54862"
    CONSONANTS := Fields(".KS TNH MYR XW.")
    UNVOICED := "KSTH"
    VOICED := "GZDB"
// for each kana in the string...
    for _, kana := range inputString {
// cutout the Unicode prefixes
        name, _ := CutPrefix(Name(kana), "HIRAGANA LETTER ")
// we need to know if it's a small kana or not
        name, hasSmall := CutPrefix(name, "SMALL ")
// we also need to know if it's a voiced ("GZDB") kana
        voicedIndex := IndexByte(VOICED, name[0])
// and the vowel of the kana
        vowel := name[1:]
// if the kana is あいうえお or ん, just output it
        if len(name) == 1 {
            if name == "N" {
                o += "W8"
            } else {
                o += "A" + string(FLICKS[Index(VOWEL, name)])
            }
// special cases for punctuation
        } else if kana == 'ー' {
            o += "W6"
        } else if kana == '〜' {
            o += "W2"
        } else if kana == '(' {
            o += "Y4"
        } else if kana == ')' {
            o += "Y6"
// if not a voiced kana...
        } else if voicedIndex < 0 {
// if it's a handakuten kana, add to the output immediately
            if name[0] == 'P' {
                o += "H" + string(FLICKS[Index(VOWEL, vowel)]) + "X6"
// otherwise, find the kana's location
            } else {
                for _, row := range CONSONANTS {
                    i := IndexByte(row, name[0])
                    if i > -1 {
// if the (unvoiced) consonant is found, add it to the output
                        o += row[i:i+1] + string(FLICKS[Index(VOWEL, vowel)])
                    }
                }
            }
        } else {
// otherwise, it's a voiced kana, and needs the extra X
            o += UNVOICED[voicedIndex:voicedIndex+1] + string(FLICKS[Index(VOWEL, vowel)])
            o += "X4"
        }
// if it's small, add the extra X.
        if hasSmall {
            o += "X5"
        }
    }
    return o
}

Do the ungolfed version on the Playground!

\$\endgroup\$
2
  • \$\begingroup\$ following your links, it looks like the playground autoformats your code but then it just runs without printing anything but the start and end header ;; am I missing something? \$\endgroup\$
    – guest4308
    Dec 20, 2023 at 19:01
  • 1
    \$\begingroup\$ @guest4308 My submission test harnesses are set up to print something when the output is incorrect, so the expected, correct output is nothing at all (except the start and end headers). The Go playground autoformats, and AFAIK there's no way of turning it off. \$\endgroup\$
    – bigyihsuan
    Dec 20, 2023 at 19:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.