Digital root Fixed

Digital root Fixed が終了した。この問題は、与えられた数値の各桁の数の和を取り、それが2桁以上であれば、同様の操作を繰り返し、最終的に一桁の数字(0〜9) に対応させる、という問題。ちょっと考えると、元の数値の mod 9 を求めればよいことがわかる。ただし、結果が 0 の場合は、代わりに 9 にする必要がある。以下の通り。

  0 -> 0
  1 -> 1
  2 -> 2
  3 -> 3
    :
  8 -> 8
  9 -> 9
 10 -> 1
 11 -> 2
 12 -> 3
    :
 17 -> 8
 18 -> 9
 19 -> 10 -> 1
 20 -> 2
 21 -> 3
    :

楽しみにしていた tails さんの 103B@sed 解。以下の通り。

h
:
y/0123456789/8-12345678/
s/\w/&-/g
t
x
G
s/.*/digital_root(&987654321/
s/\n\(.\{9\}\)*\(.\).*/)=\2/

前半の y と s は、与えられた数値の各桁の数字を、その値を長さに持つ文字列に変換している。みごとだな。自分では以下のような方法を考えていたが、長さに歴然の差がある。

s/9/80/g
s/8/70/g
s/7/60/g
s/6/50/g
s/5/40/g
s/4/30/g
s/3/20/g
s/2/10/g
s/1/00/g

後半の 2 つの s は、出力整形もあるが、mod 9 を実行している。前半で作成した文字列の後ろに "987654321" を付加し、先頭から、長さ 9 の文字列セグメントを可能な限り取り除くことで、mod 9 (ただし、0 は 9 に置換)を求めている。ここも、みごとだ。

追記

試行錯誤を重ね 1B 縮めることができた。102B
イデアは、数値を「長さを表す文字列」に変換する際、文字列の要素を '1' にすることで、後半の mod 9 を求める部分が、

s/.*/digital_root(&987654321/
s/\n\(.\{9\}\)*\(.\).*/)=\2/
↓
s/.*/digital_root(&98765432/
s/\n\(.\{9\}\)*\(.\).*/)=\2/

のように 1B 縮めることができる、というもの。