この記事は ひとりアドベントカレンダーRosettaCodeで楽しむプログラミング Advent Calendar 2025の3日めの記事です。
変わったお題。
0000~9999という数を、一つの図形で表現する。
縦棒に対して、右上が1の位、左上が10の位、右下が100の位、左下が1000の位で、それぞれ図を鏡像にするという規則らしい。
JavaScriptはまさにcanvasで描画すればよいけど、他の言語はアスキーアートだったり色々頑張ってる。
そういえばこんな記事もあった。Sixelというかなり古いっぽい規格を端末エミュレータで再現しているという話。
ここから割と時間も経ってるけど、どうやらまだ互換性がイマイチのようだ。
Windows Terminalでなら思ったように表示されたので、そっちでやる。
どんなものなのか探ってみる。
https://github.com/fumiyas/translation-ja/blob/master/vt3xx-sixel.md
https://vt100.net/docs/vt3xx-gp/chapter14.html
64個の文字に0~63の数を割り当てることで1文字で縦6ドット、文字列でそのドットの横並びを表現する。
1のドットを指定の色で塗る。カラー画像は、色ごとに何度も塗り重ねることで何とかしろ。
(カラーのインクリボンを付けたワイヤインパクトプリンタのイメージ、といっても今の人には伝わらないか。)
縦がひとまとまりなのはこのお題には好都合だ。
sixelライブラリは使わず、生の Sixel で直接描画する。
1の位の数字を縦6ドット横5ドットで表現するビットパターンを定義する。
10の位は、それを reverse するだけで完成。
100の位は、1の位をドット単位で反転させる。
1000の位は、100の位を reverse する。
それらを、中央の縦線の両側に表示する。
1ドットだと少し表示が小さいので、Sixelの機能で縦3倍に拡大し、横はドットの繰り返しで拡大する。
結果
import Data.Bits
import Data.Char
bitflip :: Int -> Int
bitflip x = sum [bit (5 - i) | i <- [0 .. 5], testBit x i]
digits :: [[Int]]
digits =
[ [0,0,0,0,0] -- 0
, [1,1,1,1,1] -- 1
, [16,16,16,16,16] -- 2
, [1,2,4,8,16] -- 3
, [16,8,4,2,1] -- 4
, [17,9,5,3,1] -- 5
, [0,0,0,0,31] -- 6
, [1,1,1,1,31] -- 7
, [16,16,16,16,31] -- 8
, [17,17,17,17,31] -- 9
]
digits10 = map reverse digits
digits100 = map (map bitflip) digits
digits1000 = map reverse digits100
showCisterian :: Int -> IO ()
showCisterian x =
do
putStr "\27Pq\"3;1;12;33"
body $ digits10 !! d1
body $ [63]
body $ digits !! d0
putChar '-'
body $ digits1000 !! d3
body $ [63]
body $ digits100 !! d2
putStrLn "\27\\\n\n"
where
[d3,d2,d1,d0] = map digitToInt $ tail $ show (x + 10000)
body = putStr . concatMap (replicate 3 . toEnum . (0x3f +))
main = mapM_ (\x -> print x >> showCisterian x) [0,1,20,300,4000,5555,6789,3579]
実行結果
ドットが荒くて PC-8001 みたい。
