全裸botは23分毎に呟く

全裸botGoogle App Engine (Python) で作ったわけですが、GAEのCronというものはLinuxなどで使われているcronとは設定方法が違っていて、「○分毎」「○時間毎」もしくは「ある条件に一致した日の○時○分」といった時間指定でしか動作させることができません。
まぁbotだし適当な時間間隔で呟くようにしたいな、と思ったのだけど、1時間毎に指定してしまうと、「毎時○分に呟く」というのが分かってしまって面白くない。30分毎とか20分毎とかにした場合も、なんとなく毎回の更新時間が読めてしまいそう。
というわけで、23分ごとに呟くことにした。こうすれば「毎時○分」という予測はできなくなる!

perl -le 'print join $", map { 23 * $_ % 60 } 0..60'
0 23 46 9 32 55 18 41 4 27 50 13 36 59 22 45 8 31 54 17 40 3 26 49 12 35 58 21 44 7 30 53 16 39 2 25 48 11 34 57 20 43 6 29 52 15 38 1 24 47 10 33 56 19 42 5 28 51 14 37 0

0分から開始したとして、次の更新は23分、その次は46分、その次は9分、…という具合に推移する。60回繰り返すまで0分には戻らない。
これを視覚化すると、こんなカンジ。

なかなかキレイな幾何学模様を描いてくれる。


60と互いに素である数であれば同じように60回繰り返すまで戻ってこないようになる。2〜30の中では23の他に7, 11, 13, 17, 19, 29などがある。
:7
:11
:13
:17
:19
:29


これらのなかでも23が特に良いのは、これが「黄金角」であるから。
黄金比」「黄金角」でググってみるとわかるけど、例えば植物が効率よく日光を浴びることができるようになるための葉の生える角度とか、そういうところで存在する角度。
これを時計に当てはめると、
60\div\left(\frac{1+\sqrt{5}}{2}\right)=37.0820393249937...
と、だいたい37分くらい、になる。左右反転して考えればこれは23分ということになる。


なんとなくこの数字が美しいと思ったので、23分毎、もしくは37分毎に呟くようにこのまま動かしていこうと思います。


今回使った画像は、テオ・ヤンセンのビーチアニマルの動きをGDモジュールによるGIFアニメで作った - すぎゃーんメモで使ったプログラムを流用。

#!/opt/local/bin/perl
use strict;
use warnings;

use GD;
use Math::Trig 'pi';

my $image = GD::Image->new(300, 300);

# 色の設定
my $white = $image->colorAllocate(0xFF, 0xFF, 0xFF);
my $red   = $image->colorAllocate(0xFF, 0x00, 0x00);
my $blue  = $image->colorAllocate(0x00, 0x00, 0xFF);

# GIFデータの作成
my $gifdata = $image->gifanimbegin(1, 0);
for (0..60) {
    my $num = $_;
    # 各フレームの作成
    my $frame = GD::Image->new($image->getBounds);
    draw_frame($frame, $num);
    $gifdata .= $frame->gifanimadd(0, 0, 0, 1);
}
$gifdata .= $image->gifanimend;

# データの書き出し
binmode STDOUT;
print $gifdata;


sub draw_frame {
    my $image = shift;
    my $num   = shift;

    # (150, 150)を中心として直径240の円
    $image->arc(150, 150,
                240, 240,
                0, 360,
                $blue);
    # 線を描画
    my $x = 150 + 120 * sin(0);
    my $y = 150 - 120 * cos(0);
    for my $minute (map { $_ * 21 % 60 } 1..$num) {
        my $arg = $minute * pi / 30;
        my ($next_x, $next_y) = (150 + 120 * sin($arg), 150 - 120 * cos($arg));
        $image->line($x, $y, $next_x, $next_y, $red);
        ($x, $y) = ($next_x, $next_y);
    }
}