🐟
GitHubプロフィール用のアスキーアートQuineを作った
作ったもの
quine.rb
eval$s=%w(s=%(eval$s=%w(#{$s})*"");f=->n{s.slice!(0,n)};fish="#70@#23H
23#24@#18A34#18@#14R12# 8A22#14@#11D12#11A25#11@
#9H12#12A28#9@#7R1 2#8A36#7@#5D13#6A4
1#5@#4H13#9A40 #4@#3R14 #11A39#3@#2D14
#15A37#2@#2 H15#18A33#2 @#R16#22A30
#@#D17#24 A27#@#H19#26 A23#@#2R2
0#27A19 #2@#2D22 #27A17#
2@#3H 24#25A 15#3@
#4R2 9#20A13#4 @#5D
33# 14A13#5@#6H 57#
7@ #8A54#8@#11R48# 11
@# 13A44#13@#17D36#17 @#
22A26#22@#70";output="
";i=0;len=fish.size;i=0;
len.times{c=fish[i];if(c!=
'@ '&&c!='#');j=i+1;len="";(fi sh
.s ize-j).times{|k|if(!(fish[j ]=
~/[ 0-9]/));break;end;len<<fi sh[
j];j +=1;};count=len.to_i ;pri
nt(32 .chr*count);i= j;els
if(c== "@");pr
int("\n" );i+=1;e
lse;j=i+1;l ="";(fish.s
ize-j).times{ |k|if(!(fish[
j]=~/[0-9]/));bre ak;end;l<<fish[j]
;j+=1;};len=l.to_i;pri nt(f[len]);i=j;end;};p
uts();#This_program_is_a_Ruby_quine.___##arad166##Kento_Harada####)*""

私のアイコン
縦に伸びているように見えますが、GitHubでは正しく表示されています。
アスキーアートQuineとは
まずQuineとは、自身のソースコードと同じ文字列を出力するプログラムです。アスキーアートQuineとは、Quineをアスキーアートにしたものです。詳しくは以下の参考文献をご覧ください。
参考文献
遠藤 侑介, 『あなたの知らない超絶技巧プログラミングの世界』, 技術評論社, 2015年, Amazon
自分のGitHubのプロフィールにこれがあったら格好良いと思い、作ってみました。言語はrubyです。
作成過程
まずはアイコンの画像をアスキーアートにしやすいように加工します。
パワーポイントで頑張りました。

加工前/加工後
最終的に正しい縦横比になるようにするため、この段階では少し横に伸ばしています[1]。
これをこちらのサイトでアスキーアートにします。
(mmmmmmmmmmmmmmmmmmmmmmmmmkkV7777????7777OXQmmmmmmmmmmmmmmmmmmmmmmmmm[
J@H@H@H@H@H@H@H@H@HMY"=` -?"WMH@H@H@H@H@H@H@H@H@]
JH@H@@@H@@@H@@H#"^ ?TM@H@@@H@@@H@@H@]
J@@H@HH@HH@HY= ..kMMHa, ?WH@H@HH@H@@H]
J@H@H@@H@#" .dHHHHHHHHF 7MH@@H@H@H]
JH@H@HH#^ .MHHHHHHMW"^ (HH@H@H@]
J@@H@M^ .HHHHMY"` ` ?M@H@@]
J@H@P gHHHH| ` ` ` 4H@H]
JH@t .HHHHHHN, ` 7H@]
J@t ` dHHHHHHHHm, ` ` ` ` OH]
JF ` ` .HHH@HH@HHHHMa, ` W]
J! OHHHHHHHHHHHHHHmJ. ` ` ,]
J ` .MHHHHHHHHHHHHHHHHHN,. ` ` ` ` ]
( ` .WHH@HH@HHHHHHHHHHHHHN&. ` [
( ` (MHHHHH@HHHHHHHHHHHHHHHMm, ` ` ` ]
J. ` ` 7HHHHHH@HH@HHHHHHHHHHHHHNa, ` ` .]
J] ` .YMHHHHHHH@HHHHHHHHHHHHHHN, ` J]
J@, ?YHHHHHHH@HHHHHHHHHHHHHHL ` ` .H]
JHN, ` ` ` ` ?"HHHH@HHHHHHHHHHHH- ` .H@]
J@HM, ` ?""WMMHH@HHHMY` ` .H@H]
J@@HHh ` ` .JH@@@]
JH@H@@M, ` ` ` ` ` .H@@HH@]
J@H@HH@HMx. ` ` ` ..H@@H@@HH]
J@@H@@H@H@Hh, ` .dH@@H@HH@@@]
JH@H@H@H@H@H@HN.. ` ..dH@@H@H@H@@HH@]
J@H@H@H@@H@@H@@HHHH+.. ` ` ..JdHH@H@H@@H@H@@H@@H]
J@H@H@HH@HH@H@H@@H@HHHHHHaJ................(gHH@H@H@H@H@H@HH@H@HH@HH@L
これをさらに加工します。まず、バッククオートをスペースで置換します。
cat ascii.csv | sed 's/`/ /g' > ascii2.csv
さらにスペース以外の部分を#で置換します。
cat ascii2.csv | sed 's/[^ ]/#/g' > ascii-sharp.csv
######################################################################
####################### ########################
################## ##################
############## ######## ##############
########### ########### ###########
######### ############ #########
####### ######## #######
##### ###### #####
#### ######### ####
### ########### ###
## ############### ##
## ################## ##
# ###################### #
# ######################## #
# ########################## #
## ########################### ##
## ########################### ##
### ######################### ###
#### #################### ####
##### ############## #####
###### #######
######## ########
########### ###########
############# #############
################# #################
###################### ######################
######################################################################
出来たものをランレングス圧縮します。
圧縮アルゴリズム
prev = nil
count = 0
result = ""
harada = %w(H A R A D A)
harada_idx = 0
ARGF.each_char do |c|
if c == "\n"
c = "@"
end
if c == prev
count += 1
else
if prev
if prev == " "
result << harada[harada_idx]
harada_idx = (harada_idx + 1) % harada.size
result << (count > 1 ? count.to_s : "")
else
result << (count > 1 ? "#{prev}#{count}" : prev)
end
end
prev = c
count = 1
end
end
if prev
if prev == " "
result << harada[harada_idx]
harada_idx = (harada_idx + 1) % harada.size
result << (count > 1 ? count.to_s : "")
else
result << (count > 1 ? "#{prev}#{count}" : prev)
end
end
puts result
圧縮後
#70@#23H23#24@#18A34#18@#14R12#8A22#14@#11D12#11A25#11@#9H12#12A28#9@#7R12#8A36#7@#5D13#6A41#5@#4H13#9A40#4@#3R14#11A39#3@#2D14#15A37#2@#2H15#18A33#2@#R16#22A30#@#D17#24A27#@#H19#26A23#@#2R20#27A19#2@#2D22#27A17#2@#3H24#25A15#3@#4R29#20A13#4@#5D33#14A13#5@#6H57#7@#8A54#8@#11R48#11@#13A44#13@#17D36#17@#22A26#22@#70
改行は@、スペースはアルファベットで表しています[2]。
また、これの復元アルゴリズムも作っておきます。
アスキーアートの準備はここまでです。
quine.gen.rb
eval$s=%w(
s=%(eval$s=%w(#{$s})*"");
#ここに成形用のプログラムを書く
)*""
アスキーアートQuineを作るには、上のプログラムの適切な部分に成形用のコードを入れれば良いです。ここに圧縮後の文字列と復元アルゴリズムを書いて実行すると、冒頭で示したアスキーアートQuineが得られます[3]。
Quine.gen.rb(完全版)
quine.gen.rb
eval$s=%w(
s=%(eval$s=%w(#{$s})*"");
f=->n{s.slice!(0,n)};
fish="#70@#23H23#24@#18A34#18@#14R12#8A22#14@#11D12#11A25#11@#9H12#12A28#9@#7R12#8A36#7@#5D13#6A41#5@#4H13#9A40#4@#3R14#11A39#3@#2D14#15A37#2@#2H15#18A33#2@#R16#22A30#@#D17#24A27#@#H19#26A23#@#2R20#27A19#2@#2D22#27A17#2@#3H24#25A15#3@#4R29#20A13#4@#5D33#14A13#5@#6H57#7@#8A54#8@#11R48#11@#13A44#13@#17D36#17@#22A26#22@#70";
output = "";
i = 0;
len=fish.size;
i=0;
len.times{
c = fish[i];
if(c!='@'&&c!='#');
j = i + 1;
len = "";
(fish.size - j).times{|k|
if(!(fish[j] =~ /[0-9]/));
break;
end;
len << fish[j];
j += 1;
};
count = len.to_i;
print(32.chr * count);
i = j;
elsif(c == "@");
print("\n");
i += 1;
else;
j = i + 1;
l = "";
(fish.size - j).times{|k|
if(!(fish[j] =~ /[0-9]/));
break;
end;
l << fish[j];
j += 1;
};
len = l.to_i;
print(f[len]);
i = j;
end;
};
puts();#This_program_is_a_Ruby_quine.___##arad166##Kento_Harada####
)*""
harada@pc:~/projects/quine/prof-quine$ ruby quine.gen.rb > quine.rb
harada@pc:~/projects/quine/prof-quine$ ruby quine.rb > output.rb
harada@pc:~/projects/quine/prof-quine$ diff -s quine.rb output.rb
Files quine.rb and output.rb are identical
Quineになっているようです。
感想
アスキーアートQuineは敷居が高いイメージがありましたが、この程度であれば思ったより簡単に作ることができました。より芸術点の高いQuineが作れるよう、精進を続けたいと思います。
Discussion