HTML paragraph

新年だ。今年も気長に Anarchy Golf の話を中心に書いていこうと思う。
さて、HTML paragraphA Japanese counting system の問題説明中に書いた『正』の字が、<pre> で囲まなかったために潰れてしまった。でもこの程度で、shinh さんのお手を煩わすのはもうしわけないと思い、思いついた方法が、この挙動そのものを問題にしてしまい、その問題説明の中で『正』文字の潰れた言い訳もしてしまおう、というもの。でも、こちらの問題の方が、むしろ面白い問題となったようだ。『瓢箪から駒』といった感じかな。
『正』の字を思いついたのは、もちろん『正月』にかけた問題を考えていたから。まぁ、なかなか良い、年末・正月の暇つぶしとなったのではないかな。
問題記述の英語もちょっと駄目だな。

HTML paragraph does not preserve the consecutive number of spaces.

は、

HTML paragraph does not preserve the number of consecutive spaces.

こっちの方が正しそうだ。

The previous problem description of "A Japanese counting system" should...

The description of the previous problem, "A Japanese counting system", should...

だろうな。これらも、何か、あなごる問題になるだろうか?なんて。

前置きが長くなったが、HTML paragraph が終了・公開になったので、いくつか感想・コメントなどを。

C

nai さん@61B、かなり来てるな。nai さんは、年末、GolfScript / FlogScript にも手を出していた。とうとう魔界の入り口に足を突っ込んでしまったか。カイオウ、ヒョウ、ハンの師匠は何て名前だったか?まぁいいや。

c;main(n){for(;read(c%8&&putchar(n?n=c:32)-c,&c,1);)n^=74%c;}

なかなか読めないコード。まず、入力だが、文字種は3種で、そのコードと、"c%8"、"74%c" をまとめると以下のよう。

文字  文字コード  c%8  74%c
 NL    10(0a)      2     4
 SP    32(20)      0    10
 '*'   42(2a)      2    32

これを踏まえて、

  • n は、putchar() で出力された文字(ひとつ前の文字)か、0 を保持している。
  • n は、74%c と xor されると、n==NL で c==SP のケースと、n==SP で c=='*' のケースの時(のみ)、0 になる。
  • n==0 だと、putchar() は、SP を出力し、n!=0 だと、c を出力するが、ただし、c%8 により、c==SP の場合は、そもそも、putchar() は呼ばれない。
  • n!=0 の時、putchar() は c を出力するので、putchar() - c は 0 となり、次の read() は成功する。n==0 の時は、c==SP の時のみ、read() は成功する。
    • この点は総合すると、n==SP で c=='*' の場合、SP を出力後、read() は一回休みで、続けて、'*' が出力されることになる。
    • この際、SP を出力したのち、n^=74%c は、32 となるが、その後、'*' を出力すると、n は、'*' となる。

以上を場合分けしてまとめてみると、

    n    c    n^74%c   c%8   出力    出力直後のn
a)  NL   NL     14      2     NL       NL
b)  NL   SP      0      0    (なし)    0
c)  NL    *     42      2     *        *
d)  SP   NL     36      2     NL       NL
e)  SP   SP     42      0    (なし)    *
f)  SP    *      0      2     SP + *   *
g)   *   NL     46      2     NL       NL
h)   *   SP     32      0    (なし)    SP
i)   *    *     10      2     *        *
j)   0   NL      4      2     NL       NL
k)   0   SP     10      0    (なし)    NL
l)   0    *     32      2     *        *
m)   1    *     33      2     *        *           <- 初期状態

といったステートマシーンだ。初期状態は n=1 で特殊だが、最初の入力は、必ず '*' なので、その後は、a 〜 l のステート内を行き来する。
NL 出力後、最初の '*' を出力するまでの SP の読み飛ばしは、

b -> (k -> b)* -> k -> c
b -> (k -> b)* -> l

の道筋。'*' 出力後、最後の '*' より前の SP の圧縮は、

h -> (e -> h)* -> f

をたどる。ここで、

h -> (e -> h)* -> e -> i

のシナリオが無いのは、入力に、'*' に挟まれた SP は常に奇数個という特殊性があったから。
最後に、最終 '*' 後の SP の読み飛ばしは、

h -> (e -> h)* -> d
h -> (e -> h)* -> e -> g

となる。とはいえ、こんな考え方はしていないだろうな。どうやって考えつくんだろう。まぁ、f ステートあたりは、本質的な部分か。

sed

sedteebee さん@16B が出たがまったくわからなかった。

s/  \|^ *\| $//g

これも、'*' に挟まれた SP は常に奇数個という入力の特殊性を使ったものだ。それに気付けなかったのが敗因。
clock さんkaki さんも同じだ。

JavaScript

JavaScriptトップ@46B を取った。他の言語が、SP を消すという考え方なのに対し、JavaScript の場合は、非 SP だけを取り出して、join するという考え方だ。ただし、join の代わりに、print() 関数が引数間に SP を挟むことを利用した、今までもしばしば出てきた定石、print.apply だ。

for(;;)print.apply(0,readline().match(/\S+/g))