2009年12月24日
Merry Quine-mas
open("/dev/dsp","wb"){|h|s=%q{d=["-KQW[UZbgu*HNT+]TNOOOTZ+cZTUUUUUZbagmssUZbagm
ss+wmpgja+KQW[dfnu","-KEKOINV[W*HBH+QHBCCCHN+WNHIIIIINVU[aUUINVU[aUU+YOR[^I+KEK
OXZbW","-W[acg vsc*TZ`+eaaaaa--vucavuca+eadsvs+W[dgvrtc","-K991LIL77777dIIIII--
LKKILKKI+Mad[ ^U+K991LHJK"].map{|l|l.unpack("C*").map{|c|[(c/6-4)*12/7-8,"012
35b"[c%6,1]. hex]}*4};y=32.chr;l="@"+[(m="Jnx4sn3sgd1")+"vnqkc!6sgd2Lnqc4gz
r4bnld;6/Ld s2dzqsg6qd2@bdhud6gdq2Khmf;77/Lds2du4@dqx4gdzqs6oqd2@ozqd4ghl
4qnnl,+Amc 2gdz++2 @udm 4z mc 2gdz 4@+u dm 2zm
c2mz+@stqd+r hmf",m+"E zq sg !6sgd2Sz u4@h nt q4qd hfm r; 6/Ld
s2ldm6sgdhq 2rnmfr6d l 2 @o knx ;77/ Wghkd2 ehdkc
r4zmc4eknn cr,6qnb jr ,2 gh kkr,4zmc 4okz hm r+Rd 2@odz s+2+,6
qd2@odzs6 +sgd2r ntmc+@ hm f+ inx" ," Nn4l nqd3k ds1rhm
r6zmc2rn 4@qqnvr4fqnv,6/Nnq2sgnqmr6hm2@edrs6sgd2fqntmc;77/Hd2bnldr4
sn4lzjd 6Hhr2ak d4@rrh mfr4eknv+Fzq2zr+2+,6ezq2zr,6+sgd2btqr
d+hr+entmc ","Hd4qtkdr3s gd1 vnqkc6vhsg2sqtsg4zmc4fqzbd,6/Amc2lzjdr6
sgd2mz6@s hnmr2oqnud77/ T gd2fk n4@q hdr4 ne6Hh r2qhfg
s4@dntr4 @mdrr,+Amc2v nm+2+6@ cd qr, 2v nm6 +@cdqr2ne+Hh
r+knud" ].map{|a| a ,b,c,e, * f =a. sp lit" +";[a,c
=b+c+f *"2",c ,b+ e+f*"4 "+ ". 8/ /"]*"6/" }.join
.tr(" a-z /","b- za\ n").gs ub (/^/ ," #"<<32)
;c=0;640.tim es{|w|c<1&&(l=~/(@)?(.*?)(\d)/m;($>.<<1ドル?2ドル:y+2ドル).flush;l=$';c
=eval3ドル);c-= 1;a=[128]*z=1200;4.times{|j|t,n=d[j].pop;f=0.3456*2**(t/12.0-j
/2);(n>0?(d[ j]<<[t,n-1];z):800).times{|i|t>-3&&a[i]+=16*Math.sin(f.*w*z+i)
}};(h.<<a.pack"C*").flush};puts(s.gsub(/./){"!">$&?"#":y}+%(\nopen("/dev/dsp#{"
(c)Y.Endoh2009";'",'}"wb"){|h|s=%q{#{s}};eval(s.split*"")}))};eval(s.split*"")}
Run it under environment where /dev/dsp is available. If you are windows user, you can use cygwin. It often abends on cygwin. Please re-run it until it works.
The structure of the program:
- Lines 1-4: encoded musical score data
- Lines 4-5: score decoder
- Lines 5-17: crypted compressed lyrics data (with timing data)
- Lines 17-19: lyrics decompressor
- Lines 20-21: lyrics player
- Lines 21-23: wave synthesizer
- Lines 23-24: quine
translated from mamememo in Japanese (2009年12月24日).
2009年11月17日
qng and qif: self-reproducing images
qng image
http://dame.dyndns.org/misc/misc/qng.png
The above image is qng, a png image that prints a Ruby script that generates the image itself.
$ cat qng.rb
eval s=%q(require"zlib";include Zlib;f=Inflate.inflate(*"eNq
1VomxQyEIpAP675IOiAjqIvqS/INh3hh1dTkN0c+FOfR5j6r4Nh98cT6xSIf
Yl4WEfi92mn1Q7WCOxRijCiXWjUfjo/Y9MBLTZqkP3sh2chfDfiKSrxxUcRg
Wa6dsfMUHbSZxkAAGHFYd202KM5EerlI9uQHU4i499MPXy0yJA0/YdR1Vzp3
DbjIVe/mEhclA8rdpJU/hexb33qch/hNxK71Uh+3AJ2ZwUHw1UyNHwX6P1LI
SJTQL4yslc+qq0OleFggW1F9QlTlGLN3zmVS2ZbTXrZCezjKsy45MqoWVsmk
I+rktkSxh05qTU3O2Y4xuvppRSL6q8d185X7mUw2uJoZaonDkvCb9gajY6Yn
yiEyg5+3GOV1XWK3OIHu/Yt37eqiu4K7nIP3oe07glFr/KR4g1lQLkIdYFBW
7ShhyI+ZYMYJS7x2FBtj2jnt3zy49YrHZsp45S04Ow16yLq4p4dD0pvek8qY
3wCynAi5tWBmrVEr3vnA+2EsP2FnIOUbJV+mBV2sgF8oRX8+Q1L1Heq8Alfj
m+j2vrhKuq1DCdRVL+N29pfOMEl49lqGlY/bzpTuDv/b9cvjbcJMXSB2OYQ=
=".unpack("m"));z="0円";s="IDAT"+Deflate.deflate(z*561+%(eva\
l s=%q(#{s})).scan(/.+/).map{|l|(0..9).map{|i|[z*4,l.bytes .
map{|c|f[c*30+i*3-960,3]},z*3]}*""}*(z*187)+z*561);print ["\
\x89PNG\r\n\x1a\n","\rIHDR",372,192,4,0,4107545177,s.size-4,
s,Zlib.crc32(s),0,"IEND\xAEB\x60\x82"].pack"a11A*NNCN3A*NNA*
"############## qng.rb (c) Yusuke Endoh 2009 ##############)
$ ruby qng.rb > qng.png
qif image
http://dame.dyndns.org/misc/misc/qif.gif
The above image is qif, a gif image that prints a Ruby script that generates the image itself.
$ cat qif.rb
Y,E=%q~260|0!e0*h0(0ドルj0($"!e0($"f0e0(0ドル!e0*p;4f4#.q9!&8*%"1(
}+0!,e4|8,e<.%}e6#g4*};!(4*%})2!e09$"u91&(#6}f0(%+#u0)6"1(7,
v0.,*%"<8{9!(4+2}!(4*%90}<.'#<(}$"!e0($")n486ドル!(0($".!e0($"$
e0w0($")k0r4*%"<8$"!9!&8*%"<0|0($"#&0()0i;f=87$};!(4+6"!e0j;
f0(',}91(4+3e0($j;!.8)2}}}}}}},4"!e0($"!2i2!i0)e0e0(#0ドル($"!e
0(,0}}o0(%2"1(4~,%~y;0('&!e=8}}q9!($"!"<0}}}}}}y0g4f0+2}441$
!}g;0&<}h211ドル!{0!q0}h0m0|20!&8*%9s9!(7$%"<0p0!e4"g3.q9!(7&!(
(0o9!(3&!e=8o0(&>#01(t9!(2$$"<0o;0*"$$"<0o9e0($")e0o9!(4.%"<
0n4"g0*!h0(o0}}k;0{0!}}g0+."!}f0?$'!t0!($"!e0e2i0e2!e0($f4}t
0($k=!-%%!040r70&8!;}%3#,0/,"r8->#!78}z8,&s0g0($"!g~;eval$s=
%q(h=eval"0b"+(Y+"}"*39+E).bytes.map{|x|x<95?("%05b".%x-32if
32<x):"0"*(x-96)}*"";z=[2,128].pack"vC";print [71,73,70,"89\
a",372,192,736,0,0,65535,11519,0,0,372,192,768,z*372,%(Y,E=\
%q~#{Y}~,%~#{E}~;eval$s=\n%q(#$s)).scan(/.+/).map{|l|(0..9).
map{|i|[z*2,l.bytes.map{|c|[4,17&n=h>>60*c-1980+i*6,17&n>>1,
n[2]+n[3]*16,136].pack "C*"},z*2]}*""}*(z*124),z*372,"0円;"].
pack"C3a3v12"+"a*"*4 #### qif.rb (c) Yusuke Endoh 2009 ####)
$ ruby qif.rb > qif.gif
COPYRIGHTS
The two images contain Proggy Programming Fonts:
Copyright (c) 2004, 2005 Tristan Grimmer
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
translated from mamememo in Japanese (2009年07月23日) and (2009年11月16日).
2009年11月15日
_ : a library that allows you to write Ruby script by using only _
I published one of my darling libraries into gemcutter, named _. By using _, you can write Ruby script that consist only of _.
Getting started
$ gem install _
Source code: http://github.com/mame/_
Gem info: http://gemcutter.org/gems/_
Example
This is "Hello, world!" __script__ written in Ruby:
require "_" ____ _ _____ ____ __ ____ ____ __ ___ ____ __ __ _ ______ _____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _ ____ _ ____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____ ____ __ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____
This is nothing but normal Ruby __script__. Works on Ruby 1.8 and 1.9. You can rearrenge line breaks but can not change the order of _s.
$ ruby18 -rubygems __hello__.rb
Hello, world!
$ ruby19 __hello__.rb
Hello, world!
If you mind the first `require' line, the option `-r_' can be used in Ruby 1.9.
$ ruby19 -r_ -e '____ _ _____ ____ __ ____ ____ __ ___ ____ __
__ _ ______ _____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _
____ _ ____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____
____ __ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____
'
Hello, world!
And, you can translate your own script into __script__ by __script__ method.
$ echo -n 'puts"Hello, world!"' | ruby19 -r_ -e 'puts __script__($<.read)'
require "_"
____ _ _____ ____ __ ____ ____ __ ___ ____ __ __ _ ______
_____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _ ____ _
____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____ ____
__ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____
translated from mamememo in Japanese (2009年04月02日) and (2009年11月15日).
2009年11月11日
enumerabler.rb: Enumerable lazy-version method library
When you want to gather first ten even numbers from an integer array, what do you do?
ary.select {|x| x.even? }.take(10)
The above program is very simple. But it may cause a lot of unnecessary checks when array is big. Also, `select' creates intermediate array.
ret = [] ary.each do |x| ret << x if x.even? break if ret.size == 10 end
This will stop the loop when enough even numbers is found, and create no unnecessary array. But, it has trouble with readability and maintainability because it is very dirty, cumbersome, tricky, too long and too primitive. We live in the age of Ruby 1.9. We need more elegance.
"We can use Enumerator and `to_enum' in Ruby 1.9!"
It's a good idea, but you are unfortunate.
(1..50).to_enum(:select) {|x| x.even? }.take(10) #=> [1,2,3,4,5,6,7,8,9,10] # never selected!
Please think yourself the reason why it does not work. `to_enum' is too difficult for me, to explain in English :-p
No matter how you combine `to_enum' and `select', it will never work, I guess. You can (must) use Enumerator.new without using Enumearble#select:
module Enumerable def selector(&blk) Enumerator.new do |e| each do |x| e << x if blk[x] end end end end
Also troublesome...
proposed `enumerabler.rb'
I wrote a library, named enumerabler.rb, which is a collection of the above method definitions.
require "enumerabler" ary.selector {|x| x.even? }.take(10)
You use `selector' instead of `select.' While `select' returns an array, `selector' returns an Enumerator corresponding the array. Because of Enumerator, the evaluation is delayed. So, the above program using `selector' is not only simple but also effective, which will stop its loop as soon as ten even numbers is found. No intermediate array.
enumerabler.rb defines:
- Enumerable#grepper
- Enumerable#finder_all (alias: all_finder, selector)
- Enumerable#rejecter
- Enumerable#collector (alias: mapper)
- Enumerable#flat_mapper (alias: concat_collector)
- Enumerable#zipper
- Enumerable#taker
- Enumerable#taker_while
- Enumerable#dropper
- Enumerable#dropper_while
All of them returns corresponding Enumerator. In an aside, I cannot distinguish -er and -or without a dictionary.
"Does it use a Fiber? Isn't it slow?"
No, enumerabler.rb does neither generate nor yield a Fiber. Trust me. If you worry, please read and check the source code of Ruby!
However, it is actually slow because it calls Proc frequently. `selector' is about two or three times slower than the original `select', but it is faster than a Fiber, and actually reduces memory usage.
Examples
p ary.selector {|x| x.even? }.taker(100).take_while {|x| x>= 0 }
gathers first 100 even numbers, however terminates before the negative element, without unnecessary check and intermediate array.
require "enumerabler" def sieve(e, &blk) yield n = e.first sieve(e.rejecter {|x| x % n == 0 }, &blk) end sieve(2..(1.0/0.0)) {|x| p x } #=> 2, 3, 5, 7, 11, 13, 17, 19, 23, ...
Sieve of Eratosthenes using `rejecter.'
require "enumerabler" def fibonacci Enumerator.new do |e| e << 1 e << 1 fibonacci.zip(fibonacci.dropper(1)) {|x, y| e << x + y } end end fibonacci.each {|x| p x } #=> 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
Fibonacci numbers. `dropper' can drop an infinite sequence. Note that this is very slow because of call-by-name evaluation and because `zip' internally uses a Fiber.
how to install
$ gem install enumerabler
http://github.com/mame/enumerabler
translated from mamememo in Japanese (2009年11月11日).
2009年10月08日
Piet Quine
$ ../npiet-1.1/npiet quine.gif > quine2.gif
$ diff quine.gif quine2.gif
translated (?) from mamememo in Japanese (2009年10月06日).
2009年10月06日
Piet is Turing-complete
I proved Turing-completeness of the programming language Piet by defining a translation from brainfuck to Piet.
translation approach
1. Correspond brainfuck's tape and piet's stack.
- The top of the piet's stack must equal to the value that the brainfuck's pointer indicates.
- The second top must equal to current index of pointer, plus 3.
- The third top must equal to total length of the whole tape, plus 3.
- The remain part of the stack must equal to data of type except the value on the current pointer.
For example, the following brainfuck's tape:
+---+---+---+---+---+---+
| A | B | C | D | E | F |
+---+---+---+---+---+---+
^
pointer
corresponds to the following piet's stack:
(top) D 6 9 A B C E F (bottom)
where 6 is current index of pointer + 3
9 is total length of tape + 3
2. Define auxiliary functions.
pick(n): push the n-th top value of the stack.
(top) A B C D E F (bottom)
|
| pick(3)
v
(top) D A B C D E F (bottom)
deposit: insert the top value to the n-th index
(top) D 6 9 A B C E F (bottom)
|
| deposit
v
(top) 6 9 A B C D E F (bottom)
withdraw: pull the n-th value to the top (inversion of deposit)
(top) 5 9 A B C D E F (bottom)
|
| withdraw
v
(top) C 5 9 A B D E F (bottom)
definitions:
pick(0) = dup
pick(n) = push(n+1); push(-1); roll; dup; push(n+2); push(1); roll
deposit: pick(1); push(1); roll
withdraw: dup; push(-1); roll
3. Put initializer of the piet's stack.
initial state of the stack:
(top) 0 3 3 (bottom)
4. Put piet's instractions correspoinding to each brainfuck's instruction.
+: push(1); add
-: push(1); sub
>: deposit
if (the second top value) > (top value)
# extend tape
# (top) 9 9 A B C D E F (bottom)
# |
# | extend
# v
# (top) 0 10 10 A B C D E F (bottom)
pop; push(1); add; dup; push(0)
else
push(1); iadd; withdraw
end
<: deposit; push(1); sub; withdraw
[: if (top value) * 2 <= 0
jump the corresponding ']'
end
]: jump the corresponding '['
,: pop; in(char)
.: dup; out(char)
Of course, branches and jumps are represented by "greater", "switch" and "pointer". Note that the piet's stack is not required to hold arbitrarily long number.
5. Put a terminator of execution.
See Piet Speficication.
full implementation
http://github.com/mame/piet-misc/blob/master/bf2piet.rb
example
An echo program written in brainfuck
,[.,]
is translated to the following Piet program:
$ ruby19 bf2piet.rb echo.bf > echo.piet.png
echo.piet.png
You can see ',', '[', '.', ',' and ']' above each corresponding sequence of instructions.
$ echo foobar | ../npiet-1.1/npiet -q echo.piet.png
foobar
You can also see hello.piet.png which is translated from brainfuck's Hello world!
$ ../npiet-1.1/npiet hello.piet.png
Hello, world!
And now, we can obtain brainfuck interpreter written in Piet, by translating Keymaker's brainfuck interpreter written in brainfuck!
$ ruby19 bf2piet.rb -c 1 kbfi.b > kbfi.piet.png
$ time ../npiet-1.1/npiet -q kbfi.b < hello.bf
Hello, world!
real 2m35.729s
user 2m35.342s
sys 0m0.128s
conclusion
Given a stack of unlimited size, Piet is Turing-complete. It does not require the stack holding arbitrarily long number.
translated from mamememo in Japanese (2009年09月25日).
2009年10月04日
English blog
I write a blog in English. Main contents will be translations from some favorite entries of mamememo in Japanese.
One of the purpose of this blog is English practice. So, please point my Engrish! :-)