challenge 自分自身を表示する

いわゆるself-printing programです。
今まで出てなかったっぽいので投稿してみました。

実行すると、そのソースコードの内容をそっくりそのまま表示するコードを書いてください。
ただし、
・空白のみのコードは認めない
・コードそのものを読み込むコードは書いてはいけない
-------->print open('selfprinting.py').read() のようなコード禁止
・コードを複数のファイルに分けたときは、作成あるいは変更したファイルの内容全てを表示すること
-------->foo.pyにprint 'import foo'、main.pyにimport fooのようなコード禁止
・標準入力や引数、あらかじめあるファイルを都合よく想定するの禁止
-------->print argv[1]として引数に'print argv[1]'を指定ってのはなし
・こういったことをしないで真面目に解いてもらうことを目的としているが、目的通りにいかないことは承知しているし、ある意味、楽しみにしている
1
2
3
4
5
6
#!/usr/bin/python
# coding: utf-8
# あんまりpythonらしくないです...

s = "#!/usr/bin/python%c# coding: utf-8%c# あんまりpythonらしくないです...%c%cs = %c%s%c%cprint s %% (10, 10, 10, 10, 34, s, 34, 10)"
print s % (10, 10, 10, 10, 34, s, 34, 10)

Posted feedbacks - Flatten

Nested Hidden

久しぶりやってみました。

1
method(call message previous print) call

関数オブジェクト.toString でソースが返ってくるので…

1
2
3
(function () {
    alert("(" + arguments.callee + ")()");
})()

エラーで。

1
2
3
self.rb:1: syntax error, unexpected tINTEGER, expecting tSTRING_CONTENT or tSTRING_DBEG or tSTRING_DVAR or tSTRING_END
self.rb:1: syntax error, unexpected tINTEGER, expecting tSTRING_CONTENT or tSTRING_DBEG or tSTRING_DVAR or tSTRING_END
         ^

いわゆるクワインですね(Wikipediaにも解説があります)。
1
2
#include<stdio.h>
int main(){char c[]="\\\"#include<stdio.h>%cint main(){char c[]=%c%c%c%.109s%cn%c;printf(c+2,c[109],c[1],*c,*c,c,*c,c[1]);return 0;}\n";printf(c+2,c[109],c[1],*c,*c,c,*c,c[1]);return 0;}

Squeak Smalltalk で。

ブロックコンテキスト([])からメソッドをたぐって(method)そのデコンパイルコード文字列(decompileString)からデフォルトのメソッド名(#DoIt)などを削除(allButFirst: 8)して値を返しています。

1
[] method decompileString allButFirst: 8

よくあるコード

1
main=putStr$q++show q;q="main=putStr$q++show q;q="

ラベル付けて自分自身を write に渡します。anarchy golf に投稿したものと同じです。

REPL で実行すると戻り値の表示の際に無限ループするかもしれません。

1
#1=(WRITE '#1# :CIRCLE T)

とりあえず、一番単純なパターンで。

1
class Sample232{public static void main(String[]a){String s="class Sample232{public static void main(String[]a){String s=%c%s%c;System.out.printf(s,34,s,34);}}";System.out.printf(s,34,s,34);}}

Cyanの関数オブジェクトはJavascriptと同様の文字列化ができます。
1
(f=^(){ ["(f=", f, ")()"].map(print) })()

ごめんなさい
1
2
$ sh self.sh
cat $0

以前見たLisp版(参考ページ参照)そのままです。

1
x='x=\047%s\047;printf "$x" "$x"\n';printf "$x" "$x"

SRFI 38 を使って。

1
#0=(write/ss '#0#)


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
f=:0 :0
wd'f=:0 :0'
wd}:f
wd')'
wd}:f
exit''
)
wd'f=:0 :0'
wd}:f
wd')'
wd}:f
exit''

昔似たようなのをCで作りました懐かしい。
ファイル末の改行は無しで保存してください。
1
s=';printf "s=%c%s%c%s,39,s,39,s"';printf "s=%c%s%c%s,39,s,39,s",39,s,39,s

BASICで。
2番目の条件に該当していないと思いたい。
UBASICで確認。
1
   10   list

ほんの少しだけGroovyらしくしてみました。
1
s=';print "s=${39 as char}$s${39 as char}$s"';print "s=${39 as char}$s${39 as char}$s"

GStringで多少Groovyらしくしてみました。

1
s=';print "s=${39 as char}$s${39 as char}$s"';print "s=${39 as char}$s${39 as char}$s"

1
(let ((s "(let ((s ~s)) (format (current-output-port) s s))\n")) (format (current-output-port) s s))

1
javascript:eval(_='(u=unescape)("javascript:eval(_=%"+27)+_+u("%"+"27)")')

これがマシンを起動してから初めて実行するプログラムならいいですが、 場合によっては自分自身以外のコードも表示されてしまいませんかね?

(BASICのステートメントも忘れかけておりますけど)こういうのではいかがでしょう?

1
0 DELETE 1- : LIST

BASICが動くマシンがないので確認できませんが、DELETE命令、そういえばそんなのありましたね

行番号は0から始まって良いんでしたっけ?私はN88BASIC使いでしたが、0で始めたことは無かったです(大抵100から)

いま手元にあるUBASICだとDELETEも行番号0もダメみたいです。機種やバージョンによって言語仕様がバラバラなのもBASICの特徴。

#8545を投稿したものです。
動作確認をとらずに思いつきで書いてしまいましたが、N-BASIC, MSX-BASICではIllegal Function Callになりました(N88だとSyntax Error)。
私はF-BASIC V3.0で育ったのですが、FM-7は実家に帰らないと確認できません^^;
ちなみにF-BASICのリファレンスはなぜか手元にあり、それによると文法上は問題ないように見えますが、確認できないことには。
ちなみにちなみに、行番号0は上述のBAISICすべてで有効でした。
# せっかくどなたか+を付けてくださったようですが、-を付けときます^^;

あ、あとDELETEコマンドもちゃんと存在しました。 > N, M

# アカウント持ってないと評価はできないのかな。すいません、昨日今日立ち寄ったばかりなもので…


そういえば、REPL ではこんなのも Quine になります

1
(PRINC -)

初めて書いた。こういう風に書くのね。

1
2
3
4
5
<?php
$s='<?php
$s=%s%s%s;
printf($s,chr(39),$s,chr(39));';
printf($s,chr(39),$s,chr(39));

今回どこも参考にせず、以前書いたときに参考にしたページでは、確かこうやると書いてあったはずという記憶を頼りに完成させました。そのため、スマートではありませんがお許しください。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
std::string replace(std::string s)
{
    std::replace(s.begin(), s.end(), static_cast<char>(std::toupper('n')), '\n');
    std::replace(s.begin(), s.end(), static_cast<char>(std::toupper('t')), '\t');
    std::replace(s.begin(), s.end(), static_cast<char>(std::toupper('q')), '"');
    std::replace(s.begin(), s.end(), static_cast<char>(std::toupper('b')), '\\');
    return s;
}
void print(std::string const& s)
{
    std::cout << "\t\t\"" << s << "\",\n";
}
void print_r(std::string const& s)
{
    std::cout << replace(s);
}
int main()
{
    std::string f[] =
    {
        "#include <iostream>N#include <string>N#include <algorithm>N#include <cctype>N",
        "std::string replace(std::string s)N{N",
        "Tstd::replace(s.begin(), s.end(), static_cast<char>(std::toupper('n')), 'Bn');N",
        "Tstd::replace(s.begin(), s.end(), static_cast<char>(std::toupper('t')), 'Bt');N",
        "Tstd::replace(s.begin(), s.end(), static_cast<char>(std::toupper('q')), 'Q');N",
        "Tstd::replace(s.begin(), s.end(), static_cast<char>(std::toupper('b')), 'BB');N",
        "Treturn s;N}N",
        "void print(std::string const& s)N{N",
        "Tstd::cout << QBtBtBQQ << s << QBQ,BnQ;N}N",
        "void print_r(std::string const& s)N{N",
        "Tstd::cout << replace(s);N}N",
        "int main()N{NTstd::string f[] =NT{N",
    };
    std::for_each(f, f + sizeof f / sizeof f[0], print_r);
    std::for_each(f, f + sizeof f / sizeof f[0], print);
    std::string m = "T};NTstd::for_each(f, f + sizeof f / sizeof f[0], print_r);NTstd::for_each(f, f + sizeof f / sizeof f[0], print);NT";
    std::string b = "Q;NTstd::cout << replace(m) << Qstd::string m = BQQ << m << QBQ;BnBtstd::string b = BQQ << b << replace(b) << std::endl;N}";
    std::cout << replace(m) << "std::string m = \"" << m << "\";\n\tstd::string b = \"" << b << replace(b) << std::endl;
}

HQ9+で
1
Q

 perlがまだの様なので。

1
2
3
4
5
6
#! /usr/bin/perl

my $s = '#! /usr/bin/perl%c%cmy $s = %c%s%c;%cprintf $s, 0x0a, 0x0a, 0x27, $s, 0x27, 0x0a, 0x0a, 0x0a, 0x0a;%c%c1;%c';
printf $s, 0x0a, 0x0a, 0x27, $s, 0x27, 0x0a, 0x0a, 0x0a, 0x0a;

1;

 他の多くの投稿と同じやり方で。

1
2
3
4
#! /usr/bin/ruby

s = "#! /usr/bin/ruby%c%cs = %c%s%c%cprintf s, 0x0a, 0x0a, 0x22, s, 0x22, 0x0a, 0x0a%c"
printf s, 0x0a, 0x0a, 0x22, s, 0x22, 0x0a, 0x0a

 コード自身を読み込むコードに該当するかも知れませんが...。

1
2
3
4
5
6
7
8
#! /usr/bin/ruby

if defined? SCRIPT_LINES__
    SCRIPT_LINES__.values.shift.each { |l| print l }
else
    SCRIPT_LINES__ = {}
    require __FILE__
end

 Scalaがまだの様なので。

1
2
3
4
5
6
object PrintSelf {
    def main(args:Array[String]):Unit = {
        val    f:String = "object PrintSelf {%c%cdef main(args:Array[String]):Unit = {%c%c%cval%cf:String = %c%s%c%c%c%cprintf(f, 0x0a, 0x09, 0x0a, 0x09, 0x09, 0x09, 0x22, f, 0x22, 0x0a, 0x09, 0x09, 0x0a, 0x09, 0x0a, 0x0a)%c%c}%c}%c"
        printf(f, 0x0a, 0x09, 0x0a, 0x09, 0x09, 0x09, 0x22, f, 0x22, 0x0a, 0x09, 0x09, 0x0a, 0x09, 0x0a, 0x0a)
    }
}

言語は ViViScript です。 Cの例を元に書き換えました。
1
$s="$s=%c%s%c;cout<<format($s,34,$s,34);";cout<<format($s,34,$s,34);

F# Interactive 上で実行した場合に要件を満たすコードです。
最後の「val it : unit = ()」を削除すると、Visual Studio 上で実行した場合に要件を満たすコードとなります。
1
let s="let s=%O%s%O in printf (new PrintfFormat<char->string->char->unit,_,_,_>(s)) (char 34) s (char 34);;//" in printf (new PrintfFormat<char->string->char->unit,_,_,_>(s)) (char 34) s (char 34);;//val it : unit = ()

大昔にBASICで書いた記憶があります。

確かこんな感じをDATA文でやっていたような・・・

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#! /usr/bin/ruby
s=""
DATA.each{|d|
  s = s + d
}
puts s
puts "__END__"
puts s
__END__
#! /usr/bin/ruby
s=""
DATA.each{|d|
  s = s + d
}
puts s
puts "__END__"
puts s

C++のときと違って、引数位置を指定できることと、バックスラッシュによるエスケープ記法が必要なかったため、大変スマートになったと感じています。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
using System;
class Quine
{
  static void Main()
  {
    var s = "using System;{2}class Quine{2}{{{2}{4}static void Main(){2}{4}{{";
    var t = "{2}{4}{4}var s = {0}{1}{0};{2}{4}{4}var t = {0}{3}{0};{2}{4}{4}";
    var u = "var u = {0}{5}{0};{2}{4}{4}var v = {0}{6}{0};{2}{4}{4}var w = {0}";
    var v = "{7}{0};{2}{4}{4}Console.Write(s + t + u + v + w, '{0}', s, ";
    var w = "Environment.NewLine, t, {0}  {0}, u, v, w);{2}{4}}}{2}}}{2}";
    Console.Write(s + t + u + v + w, '"', s, Environment.NewLine, t, "  ", u, v, w);
  }
}

SQL Server 2008 で確認しました。 何の面白みもないです・・・

1
WITH Input(s) AS (SELECT 'WITH Input(s) AS (SELECT #_#) SELECT REPLACE(REPLACE(s, CHAR(35), CHAR(39)), CHAR(95), s) FROM Input;') SELECT REPLACE(REPLACE(s, CHAR(35), CHAR(39)), CHAR(95), s) FROM Input;

こうかな

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import std.stdio;

char c = 34;
auto s ="import std.stdio;

char c = 34;
auto s =%s%s%s;

void main() {
  writef(s, c, s, c);
}";

void main() {
  writef(s, c, s, c);
}

Index

Feed

Other

Link

Pathtraq

loading...