summer_tree_home

Check iOでPython3をマスターするぜっ

Morse Clock (Scientific Expedition) - バイナリ時計

どんな問題?

Morse Clock
http://www.checkio.org/mission/morse-clock/

バイナリ時計を作成せよ。
時刻(時・分・秒)を各桁ごとに二進数に変換し、「1」を「-」、「0」を「.」に置き換える。

引数は、文字列で表記された時刻。
戻り値は、「-」と「.」で表した時刻を文字列として返す。フォーマットは以下の通り。

h h : m m : s s
h h 2桁 + 4桁
m m 3桁 + 4桁
s s 3桁 + 4桁

時は2+4桁、分と秒は3+4桁なので注意。

例題:

assert checkio( "10:37:49" ) == ".- .... : .-- .--- : -.. -..-", "First Test"
assert checkio( "21:34:56" ) == "-. ...- : .-- .-.. : -.- .--.", "Second Test"
assert checkio( "00:1:02" ) == ".. .... : ... ...- : ... ..-.", "Third Test"
assert checkio( "23:59:59" ) == "-. ..-- : -.- -..- : -.- -..-", "Fourth Test"

ちなみに、単に二進数にするのではなく、十進数の各桁ごとに二進数に変換することを、二進化十進(BCD)というらしい。

十進数 二進数 二進化十進数
9 1001 00 1001
10 1010 01 0000
15 1111 01 0101

どうやって解く?

  1. 引数を時・分・秒に分解する。
  2. 時・分・秒を、十の桁と一の桁に分ける。
  3. format()で、二進数表記の時刻を作成する。
  4. 「1」→「-」、「0」→「.」に置換する。

という流れかな。そのまま書いてみた。

def checkio(data):
    hms = [int(t) for t in data.split(':')]
    (h10, h1), (m10, m1), (s10, s1) = [(n // 10, n % 10) for n in hms]
    s = '{:02b} {:04b} : {:03b} {:04b} : {:03b} {:04b}'.format(h10, h1, m10, m1, s10, s1)
    return s.replace('0', '.').replace('1', '-')

複数の置換を同時に行うことはできないのかなと思って調べてみたら、translate()とmaketrans()というメソッドを使えばいいようだ。
「1」→「-」、「0」→「.」に置換するには、

    return s.translate(str.maketrans('01', '.-'))

とするだけ。こりゃ便利だ。

まとめ

def checkio(data):
    hms = [int(t) for t in data.split(':')]
    (h10, h1), (m10, m1), (s10, s1) = [(n // 10, n % 10) for n in hms]
    s = '{:02b} {:04b} : {:03b} {:04b} : {:03b} {:04b}'.format(h10, h1, m10, m1, s10, s1)
    return s.translate(str.maketrans('01', '.-'))

http://www.checkio.org/mission/morse-clock/publications/natsuki/python-3/first/

他の人の答え

  • 時・分・秒ともに、3+4桁で作成しておいて、最後にs[1:]で先頭一文字を削除している解が多かった。なるほど。
  • zfill() というのを使っている人が多かったが、これは左側をゼロ埋めする文字列のメソッドのようだ。知らんかった。
  • (n // 10, n % 10) は divmod(n) を使えば良かったかな。


おまけ
これカッコイイ!
f:id:summer_tree:20140320224417j:plain
バイナリ時計(Wikipedia)