3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Befungeでアスキーアート変換装置を作ってみた

Posted at

ネタ記事です
Befunge知ってる前提で行きます

問題

制約

1 ≦ N ≦ 50000
S はAscii文字からなる長さ N の文字列
コード内に S を打ち込める場所を作る

出力

S を一文字づつ3×5のAscii Artに変換する
一文字ごとに改行する
制御文字以外の文字すべてに対応できるようにする
全て当てはまらなかった場合は塗りつぶしを出力する

入力

a

出力

##
  #
###
# #
###

入力

ABC

出力

 $ 
$ $
$$$
$ $
$ $

@@
@ @
@@
@ @
@@

 *
* *
*
* *
 *

入力

出力

#sf
h5j
~P=
<=J
~`+

`f=
%&6
Jz!
'6f
1)(

H|y
po@
ft7
s5I
+Gf

※処理系によっては1文字の場合もあり










解答

<v" !"+*654"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
v<_@#:<$<

>:456*+-#v _00055v
_v#!-"!":<v22202
 >:"#"- #v _57575v
_v#!-"$":<v00000
 >:"%"- #v _51245v
_v#!-"&":<v00000
 >:"'"- #v _00022v
_v#!-"(":<v21112
 >:")"- #v _24442v
_v#!-"*":<v05250
 >:"+"- #v _02720v
_v#!-",":<v00021
 >:"-"- #v _00700v
_v#!-".":<v00001
 >:"/"- #v _12224v
_v#!-"0":<v75557
 >:"1"- #v _72223v
_v#!-"2":<v74717
 >:"3"- #v _74747v
_v#!-"4":<v55744
 >:"5"- #v _74717v
_v#!-"6":<v71757
 >:"7"- #v _44557v
_v#!-"8":<v75757
 >:"9"- #v _74757v
_v#!-":":<v02020
 >:";"- #v _12002v
_v#!-"<":<v42124
 >:"="- #v _07070v
_v#!-">":<v12421
 >:"?"- #v _20247v
_v#!-"@":<v00000
 >:"A"- #v _55752v
_v#!-"B":<v35353
 >:"C"- #v _61116v
_v#!-"D":<v35553
 >:"E"- #v _71717v
_v#!-"F":<v71711
 >:"G"- #v _65516v
_v#!-"H":<v55755
 >:"I"- #v _22222v
_v#!-"J":<v44457
 >:"K"- #v _55355v
_v#!-"L":<v11117
 >:"M"- #v _55575v
_v#!-"N":<v35555
 >:"O"- #v _25552v
_v#!-"P":<v35311
 >:"Q"- #v _63552v
_v#!-"R":<v35355
 >:"S"- #v _34716v
_v#!-"T":<v72222
 >:"U"- #v _75555v
_v#!-"V":<v55572
 >:"W"- #v _57555v
_v#!-"X":<v55255
 >:"Y"- #v _22755v
_v#!-"Z":<v74217
 >:"["- #v _31113v
_v#!-"\":<v12224
 >:"]"- #v _64446v
_v#!-"^":<v25000
 >:"_"- #v _70000v
_v#!-"`":<v24000
 >:"a"- #v _75643v
_v#!-"b":<v11353
 >:"c"- #v _61160v
_v#!-"d":<v44656
 >:"e"- #v _61752v
_v#!-"f":<v62722
 >:"g"- #v _34756v
_v#!-"h":<v11355
 >:"i"- #v _22202v
_v#!-"j":<v40457
 >:"k"- #v _53511v
_v#!-"l":<v22226
 >:"m"- #v _55750v
_v#!-"n":<v03555
 >:"o"- #v _25520v
_v#!-"p":<v03531
 >:"q"- #v _46560v
_v#!-"r":<v05311
 >:"s"- #v _74370v
_v#!-"t":<v27226
 >:"u"- #v _75550v
_v#!-"v":<v05572
 >:"w"- #v _57550v
_v#!-"x":<v05225
 >:"y"- #v _27550v
_v#!-"z":<v07217
 >:"{"- #v _62126v
_v#!-"|":<v22222
 >:"}"- #v _32423v
_v#!-"~":<v03760
v>:" "- #v _00000>
v  77777 <>
<v\4
, *25$ <^
 >v  <
 v>:9`#^_
v>:3`#v #1_
<v %4\<0
v>:1`#v #1_
<v %2\<0
v>3*84*
<|-4:,+
 >6+>^

解説

まず、このコードは大きく3つに分けられます。

①入力部
②定義部
③出力部

入力部

<v" !"+*654"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

この部分ですね
この部分は純粋に右側の文字からpopしていっているだけですね。
そのため、スタックは下記のようになります

[126, 125, ...,  32]

"はエスケープできないので頑張ってください()

定義部

v<_@#:<$<

>:456*+-#v _00055v
_v#!-"!":<v22202
 >:"#"- #v _57575v
_v#!-"$":<v00000
 >:"%"- #v _51245v
_v#!-"&":<v00000

        ︙

 >:"{"- #v _62126v
_v#!-"|":<v22222
 >:"}"- #v _32423v
_v#!-"~":<v03760
v>:" "- #v _00000>
v  77777 <>

定義部はこの部分ですね。

下記のような構造になっていて、
赤い部分がブロック節、青い部分が処理を表しています。

1行が一つの文字に対応するようになっていて、
2行ごとに同じ形のコードが繰り返されています。(最上部、最下部は除く)


また、条件が一致した場合は
上記の青矢印のように数字5桁をスタックします。

数字と表示は2進数と対応して以下のようになっています

N disp
0 ___
1 #__
2 _#_
3 ##_
4 __#
5 #_#
6 _##
7 ###

その後は、下記青矢印のように下向きに流れて
左下に流れていきます。


条件が一致しなかった場合は
上記の赤矢印のようにひたすら一致しているかを確かめ続けて

最後まで一致しなければ77777がスタックされて
条件が一致した場合である青矢印と合流します。

ほとんどascii順になっていますが文字数合わせのために
エスケープが必要な"だけ先に書いてます。

あとは

 >:" "- #v _00000v
v  77777 <>      >

v>:" "- #v _00000>
v  77777 <>

にすることで少し短縮しています

出力部

v
<v\4
, *25$ <^
 >v  <
 v>:9`#^_
v>:3`#v #1_
<v %4\<0
v>:1`#v #1_
<v %2\<0
v>3*84*
<|-4:,+
 >6+>^

出力部はこの部分ですね。

出力部はさらに2つに分かれていて
①変換パート
②出力パート
となっています。

変換パート

左上の時点での時点でのスタックは下記のようになっています。

[126, 125, ...,  32, 0, 0, 0, 0, 0]     // 32 = " "

[出力する文字一覧(最初に出力する文字も含む), 最初に出力する文字のascii art配列 5]

まず最初に4\が実行されるので

[126, 125, ...,  32, 0, 0, 0, 0, 4, 0]     // 32 = " "

:9`#^_は最初のスタックと10を比較して
10以上ならループ(後で説明)を抜けます
基本的に0b111(7)が最大値なのでそれ以上の値が入って来た時は終了ですね。
また、31以下は制御文字なのでそもそも入力されることがないので無視ですね。

そして入って来た数字は2進数に変換されていきます。

v>:3`#v #1_
<     <0

ここで、もし4以上(3よりも大きい)ならば
1を返し、そうでなければ0を返す。

 v %4\

4で割った余りを求めて

v>:1`#v #1_
<     <0

4で割った余りが2以上なら
1を返し、そうでなければ0を返す。

 v %2\

そしてそれを2で割ります。
すると、数字が2進数に変換されます。

N bin
0 0, 0, 0
1 0, 0, 1
2 0, 1, 0
3 0, 1, 1
4 1, 0, 0
5 1, 0, 1
6 1, 1, 0
7 1, 1, 1

なので、現在のスタックは次のようになります

[126, 125, ...,  32, 0, 0, 0, 0, 4, 0, 0, 0]     // 32 = " "

[出力する文字一覧(最初に出力する文字も含む), 最初に出力する文字のascii art配列 5]

出力パート

そして、その次に来るのが下記のパートです。

v>3*84*
<    ,+

まず、このパートでは
0または1が3倍され32が足されます。

32, 35はそれぞれ' ', '#'に対応しているので
数字のデータを文字に変換することができます。

 |-4:

そして、次にこのパートではスタックの先頭が4かどうかを判定します。

4であれば下に行き、
4でなければ上に行ってもう一度文字出力を行います。

[126, 125, ...,  32, 0, 0, 0, 0, 4, 0, 0]     // 32 = " "

1回動作が終わった後はこのように先頭の数字が一つ消費され、
3回動作すると先頭が4となり文字出力のループが終わります。

出力部ループ

[126, 125, ...,  32, 0, 0, 0, 0, 4]     // 32 = " "

|を通過した後はスタックはこのようになっています。

そこから6を足して10となり、
10\nに相当するので改行が出力されます。

4\となるので下記のようになります。

[126, 125, ...,  32, 0, 0, 0, 4, 0]     // 32 = " "

まさかの今までのコードの中を通ったことで、
4\を通ることができて、ループの初期化をすることができてしまう!?
天才かもしれん、、、

これによりループが一周した状態となり、
右上の図のようにループ2周目が始まります。

メインループ

気持ちいところ来ました~~!!!!!
この縦の羅列のコードの中を通ってるのすごくないですか??

ラスト5週目まで終えてループの始点につくと、
スタックはこのような状態になってます。

 >:9`#^_

ここで、このコードによって上側へと行き、

, *25$

で出力した文字の文字コード32を消去、
改行を出力します。

そして、コードの中を通って上の行まで行きます。
一行空いてるので#で飛ばされることはないです!

v<_@#:<$<

そして、$でスタックから4を消去し、
次の数字が0ではないことを確認して
ループが再開されます。

この時、スタックは初期状態から一番上の数字のみを削除した
次の図のようになります。

[126, 125, ...,  33]

そして、残っている文字がなくなると、

  _@#:

_0と判定されて、コードが終了します。

あとがき

ここまで読んでいただきありがとうございました!!

コードが2回も縦断するところ、
すごいキレイに書けたなと自画自賛しております()

___

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?