Twitter Bot おうじょったーを作るまで

ドラクエ1に出てくる「王女の愛」というアイテムの Bot おうじょったー を作った時のメモ。

とりあえず Bot の説明

oujono をフレンド登録したあと @oujono 宛てに発言すると、
ラダトームの城からどのくらい離れているかをローラ姫が教えてくれます。(詳しい使い方

マップデータの作成

おうじょったー は twitter の利用具合から移動できる範囲を決めて、その中から現在位置を算出しています。よく使っている人ほど遠くまで行くことができるようになっています。ただし、海や山など入れない場所を現在位置にしてしまうと、格好悪いので入れるのか入れないのかの判定を行っています。そのためのデータ作りを説明します。


マップデータはドラクエの地図の画像を解析して作っています。
画像の解析には ImageMagick(PerlMagick) を使いました。

手順1 画像データをゲットする

これがないと始まりません。
今回は Pledge of BAHAMUT の XB-LIM さんの画像を使わせていただきました。これをゲットする。
すばらしい仕事に感謝!

手順2 画像データを解析する

手順1でゲットした画像は1マスが 16 x 16 のサイズ、そしてドラクエのマップは 136 x 136 マスで構成されていますので、1マス毎にどんな地形なのかを調べます。調べる方法は面倒くさかったので任意の2点の色で判断しています。本当は画像を縮小してから調べたほうがいいけど、とりあえず元のデータのまま調べるソースを掲載しています。画像が大きいので実行に少し時間がかかります。


このスクリプトでは13種類の地形の判断基準を登録(set_icon)した後、136 x 136 をそれぞれどの地形か調べて(get_icon)、入れる/入れないを配列に格納しています。
真面目に 136 x 136 の地形を単純に配列にすると 18,496 個の要素が必要になりますが、今回必要なのは入れるか入れないかの2値なので、0 or 1 で表現し、32ビットの数値に格納することで、18,496 / 32 = 578 個の要素で済ませています。


最後にできた配列をprint出力しています。適当なファイルにリダイレクトしてソースにそのまま貼り付けて使いました。


これを画像化するとこんな感じになります。
白い部分が入れる場所、黒い部分が入れない場所です。
http://mohayonao.sakura.ne.jp/labs/dqbitmap.png


ちょっといじれば、2進値でなく地形ごとに色を変えて書き出すこともできます。
http://mohayonao.sakura.ne.jp/labs/dqmap.png



ソース

#!/usr/bin/perl
use strict;
use warnings;
use Image::Magick;


my $image;
my @icon;

sub set_icon {
    my ($idx, $cond1, $cond2) = @_;
    $icon[$idx] = [$cond1, $cond2];
}


sub get_icon {
    my ($x, $y) = @_;
    for (0..12) {
        next unless ($icon[$_]);
        my ($cond1, $cond2) = @{$icon[$_]};
        return $_ if (cmp_color($x, $y, $cond1) && cmp_color($x, $y, $cond2));
    }
    return -1;
}

sub cmp_color {
    my ($x , $y , $cond)  = @_;
    my ($xx, $yy, $color) = @$cond;
    
    return get_color($x * 16 + $xx, $y * 16 + $yy) == $color;
}

sub get_color {
    my ($x, $y) = @_;
    my $ret = 0;
    
    for ((split(/,/, $image->Get("pixel[$x,$y]")))[0..2]) {
        $ret *= 256;
        $ret += ($_ & 0xff);
    }
    
    return $ret;
}



##### main #####
$image = new Image::Magick();
$image->read('map.png');       # 画像とスクリプトは同じ階層におく

set_icon( 0, [ 0,  0, 0x84c600], [ 2,  1, 0x00a500]); # 0 : field
set_icon( 1, [ 0, 11, 0x84c600], [ 1, 10, 0x00a500]); # 1 : forest
set_icon( 2, [ 0,  0, 0x84c600], [ 4, 10, 0xffe784]); # 2 : rock
set_icon( 3, [ 0,  0, 0xffe784], [ 0,  2, 0x000000]); # 3 : desert
set_icon( 4, [ 0,  0, 0x000000], [ 0,  1, 0x00a500]); # 4 : poison
set_icon( 5, [ 0,  0, 0x4263e7], [ 0,  7, 0xc6c6c6]); # 5 : bridge
set_icon( 6, [ 9,  5, 0x4263e7], [10,  5, 0xffffff]); # 6 : town
set_icon( 7, [ 2, 10, 0x4263e7], [ 2,  9, 0xc6c6c6]); # 7 : catsle
set_icon( 8, [ 0,  5, 0x84c600], [ 0,  6, 0x000000]); # 8 : cave
set_icon( 9, [ 0, 15, 0x000000], [ 0, 14, 0x848484]); # 9 : step
set_icon(10, [ 0,  0, 0x4263e7], [ 1,  4, 0xffffff]); # a : sea
set_icon(11, [ 2,  0, 0x84c600], [ 2,  1, 0x848484]); # b : mountain
set_icon(12, [ 0,  2, 0x848484], [ 2,  2, 0xc6c6c6]); # c : block


my @map;

my $idx = 0;
for my $y (0..135) {
    for my $x (0..135) {
        my $flg = (get_icon($x, $y) < 10) ? 0x01 : 0x00;
        $map[int($idx / 32)] |= $flg << ($idx % 32);
        $idx++;
    }
}

my $i = 0;
for (@map) {
    printf "0x%08x, ", $_;
    $i++;
    print "\n" if !($i % 5);
}
print "\n";

undef $image;

できたデータ

0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xf000fc00, 
0x03fc0007, 0x07f80000, 0x0007fe00, 0x03fe0000, 0xff001ffc, 
0xff00003f, 0x7ff80007, 0xff000000, 0x803fff07, 0xc000ffff, 
0xff8003ff, 0x000000ff, 0x7fffffff, 0x01ffff80, 0xe0007fe0, 
0x0007ffff, 0xffc7ff00, 0xffffc0ff, 0x003fe003, 0x0ffffff8, 
0x83ff0000, 0x3ff3ffff, 0x1ff003fe, 0xfffffc00, 0xff00001f, 
0xffffff00, 0xe001fc1f, 0xffffc00f, 0x00001fff, 0xfff8783f, 
0x00fe3fff, 0xff801ff0, 0x003ff83f, 0xf1ff0f00, 0xff1fffff, 
0xc03fe000, 0x3fe38fff, 0xffcf0000, 0xfffffff3, 0xffc7007f, 
0xe7e7ffc0, 0xff00007f, 0xfffff1ff, 0xc3803fff, 0xffff81ff, 
0x00003f8f, 0xffe3fffc, 0x801fffff, 0xff01ff87, 0x007fffff, 
0xc3fff800, 0x7fffffff, 0x03ff87c0, 0xffffffff, 0xfff00000, 
0xffffff87, 0xfc0fe0ff, 0xffffff03, 0xe00000ff, 0xffff0fff, 
0x1ff1ffff, 0xfffe03f8, 0x0000ffff, 0xfe3ffff0, 0xf9ffffff, 
0xfc07f1ff, 0x001fffff, 0xffffc000, 0xffffffff, 0x0f87fff9, 
0x01fffff0, 0xfff80000, 0xffffffff, 0x1ffff3ff, 0x0ffffc1f, 
0xfc000000, 0xffffffff, 0xffe7ffff, 0xfffe3c3f, 0x000003c0, 
0xfffffffc, 0xffffffff, 0xfff87fff, 0x0007f01f, 0xfffffe00, 
0xffffffff, 0x00ffffcf, 0x1ffe0fec, 0xffff0000, 0xffffffff, 
0xffffdfff, 0xfe07e003, 0xff00003f, 0xffffffff, 0xffdfffff, 
0x07c1ffff, 0x0000ffff, 0xff1fffff, 0x9fffffff, 0xc3ffffff, 
0x00ffff8f, 0x07ffff00, 0xfffffffc, 0xffffff3f, 0xffffff87, 
0xffff0000, 0xfffff803, 0xfffe7fff, 0xffff0fff, 0xff0000ff, 
0xfff801ff, 0xfcffffff, 0xff1fffff, 0x0000ffff, 0xe001fffc, 
0xffffffff, 0x0fffffe1, 0x007ffffe, 0x00fff800, 0xffffff00, 
0xfffe0fff, 0x3fffff07, 0x7f000000, 0xfffe0000, 0xfc01ffff, 
0xffff83ff, 0x7000001f, 0xfc00003c, 0x007fc0ff, 0xffc0fff8, 
0x000007ff, 0x00000ff8, 0x1f801fff, 0x81fff000, 0x0003ffff, 
0x03c1fc00, 0x0003ffc0, 0xfff8001f, 0x0fffff01, 0xfffc0000, 
0x80fff01f, 0xfc000e07, 0xffff83ff, 0xfc00001f, 0x7ff87fff, 
0x03ff3ff8, 0xffc7fffe, 0x00003fff, 0xfcfffff8, 0xfe7fffff, 
0xe7fffc07, 0x007fffff, 0xfffff000, 0x3ffffffc, 0xfff81ffc, 
0xffffe1f3, 0xfffc0000, 0xfffff87f, 0xfffff87f, 0xffc0ffff, 
0xfe00007f, 0xfff07fff, 0xffc3ffff, 0x80f87fff, 0x00007fff, 
0xf83fffff, 0x01ffffff, 0xf80ffffe, 0x003fff07, 0x1fffff00, 
0x7ffffff8, 0x007fff00, 0x1fff0ff0, 0xffff0000, 0xfffff007, 
0x3ffc003f, 0xf83fc000, 0xff000001, 0xfffe007f, 0xe00001ff, 
0x7e000003, 0x00000000, 0xff001ffe, 0x00007fff, 0x00000000, 
0x000003f8, 0xe00ffc00, 0x001fffff, 0x00000000, 0x00038000, 
0x07fc0000, 0x07fffff0, 0x00000000, 0x000007e0, 0xf0000000, 
0xfffff81f, 0x00000001, 0x007fff80, 0x00007800, 0xffc03ff8, 
0x000380ff, 0xfffffc00, 0x00fc0003, 0x807ffc00, 0x03807fff, 
0xffff8000, 0xfe001fff, 0x3ff80000, 0x80ffff00, 0xffcee00f, 
0x03ffffff, 0xf80000ff, 0xffffc01f, 0xf87e1800, 0xffffffff, 
0x0000ff83, 0xff0007e0, 0x1f1e00ff, 0xffffffe0, 0x00ffcfff, 
0x0000f000, 0x0f007ffe, 0xffff800e, 0xfffff8ff, 0x003c0000, 
0x803ffc00, 0xfe00041f, 0xfff801ff, 0x1e0000ff, 0x1fe000fe, 
0x000c3f00, 0xe0007ffc, 0x0000ffff, 0x8001ff8f, 0x063f003f, 
0x001ff000, 0x00fffc00, 0x07ffff00, 0x1f007f00, 0x3fe00007, 
0x7ff807c0, 0xffff0000, 0x007f3e1f, 0xf000078e, 0xc00fffff, 
0xff00001f, 0x7f8fffff, 0x000fc600, 0x0ffffff0, 0x00000fe0, 
0xc7ffffff, 0x0102003f, 0xfffff000, 0x0007f807, 0xffffff00, 
0x83001f87, 0xffe00003, 0x0fffffff, 0xffff0000, 0x0000000f, 
0xe00001c6, 0xffffffff, 0xff00001f, 0x01e003ff, 0x00038c00, 
0xffffffc0, 0x00001fff, 0xff81fffe, 0x073c0003, 0xffff8000, 
0x003fffff, 0xc7fffc00, 0xf8000fff, 0xff800001, 0x7ffc03ff, 
0xfff00000, 0x001fffff, 0x00000060, 0xc0f8ffff, 0xc00000ff, 
0x0fffffff, 0x00000000, 0xfc7ffc00, 0x0000ff87, 0xffffff80, 
0x00000007, 0x7ff00000, 0x00fe0ffe, 0xffff0000, 0x001fc1ff, 
0xc0000000, 0xfe3fffff, 0xfc000000, 0x07f03fff, 0x00000000, 
0x7e0ffff0, 0x000000fc, 0xf87ffff8, 0x00000003, 0x07fffc00, 
0x0000fe7c, 0xfffff000, 0x000001ff, 0xfff80000, 0x00fc78e3, 
0xffc00000, 0x00007fff, 0xc0000000, 0xfe7fe3ff, 0x00000000, 
0x001fffe0, 0x00000000, 0x78e3ffe0, 0x000000fe, 0x3fff803f, 
0x00000000, 0x07ffc000, 0x00007f3c, 0xffc1ff80, 0x0000007f, 
0xff800000, 0x003f0e0f, 0x03ffc000, 0x0003ffff, 0x00fe0000, 
0x3fff83fe, 0xffe00000, 0x07fffe1f, 0x87f80000, 0xff07ff01, 
0xf000001f, 0xffff7fff, 0x0000000f, 0x1ffe0300, 0x00003ffe, 
0xfffffff8, 0x00001fff, 0xf80207e0, 0x00fffe3f, 0x7ffff800, 
0x001ffffe, 0x023fff00, 0xfffcfffc, 0xfffc0000, 0x3ffffcff, 
0x60018000, 0xf9fff802, 0xff0000ff, 0xfff0ffff, 0xf0c0003f, 
0xffe0024f, 0x0000fff3, 0x807fffff, 0x40003fff, 0xe002c700, 
0x00ffe3ff, 0x3fffff00, 0x001ffe00, 0x0782007f, 0x7fe7ffc0, 
0xffff0000, 0x07f8001f, 0x0200c7c0, 0xcfff8004, 0xfc00003f, 
0xe03f83ff, 0x0f8ffc01, 0xfc000e02, 0x00003fff, 0x7ff8fff8, 
0x07fe0000, 0x001ffe00, 0x003ffff0, 0xfffffc00, 0xff8000ff, 
0x3f801c07, 0x1fffe000, 0xffff0000, 0xe0007fff, 0x000fe7ff, 
0xffc0001f, 0xff000007, 0xf03fffff, 0x3ff3ffff, 0xf0000c3e, 
0x00000fff, 0x07fffffe, 0xf87f01fc, 0x0008ffff, 0x001fffe0, 
0xffffe000, 0x1fff0f01, 0x19ff9fff, 0x0fffe000, 0xf8000000, 
0x807f83ff, 0xffe1ffcf, 0xffc00030, 0x00000007, 0xfe007fff, 
0xf01fe7ff, 0x9800107f, 0x00000fff, 0xc1fffff0, 0x01f1fc3f, 
0x0039ffe0, 0x0007ffbc, 0xfffffc00, 0x7c78003f, 0x73fff000, 
0x03ff3e00, 0xfff80000, 0x9c7fffff, 0xfffe003f, 0xfe7800c7, 
0xfc000003, 0xffffffff, 0xfff01fc7, 0xfc019fff, 0x000001fc, 
0xfffffffe, 0xc00ff03f, 0x01cfffff, 0x0000fffc, 0xffffff00, 
0x07e00fff, 0x87f27fe0, 0x0079fe03, 0xfe1f0000, 0xf001ffff, 
0xf77fc003, 0x39fe0707, 0x3f000000, 0x01fffff8, 0x7f0003f0, 
0xfc0e0ff7, 0x00000003, 0xffffe0ff, 0x0079fc01, 0x1f3ff77c, 
0x000007fc, 0xff007f00, 0xfffe03ff, 0x1ff0780f, 0x007ff83f, 
0x3e7f0000, 0xff07ffe0, 0xfff0fffc, 0xffe01f8f, 0x3e00000f, 
0x81ff80ff, 0x81fffe3f, 0xc00f81ff, 0x00003fc1, 0xffc3ff38, 
0xffff1f03, 0x1fc07807, 0x003f18e0, 0xfffe6000, 0xff8f80ff, 
0xe0000fff, 0x0f3c703f, 0xf8f00000, 0x87c07fff, 0x003fffff, 
0x7e380ffe, 0xf8000006, 0xf81ffffc, 0xffffff07, 0x701fff01, 
0x00003c3e, 0x0ffffcf0, 0xffff87fc, 0x0fff83ff, 0x003f3ce0, 
0xffffe000, 0xff03fe1f, 0xffc7ffff, 0x1f88e007, 0xff800000, 
0x01ff07ff, 0xffffffff, 0xc9c003ff, 0xc000000f, 0xfe003fff, 
0xfffffe00, 0xc001ffcf, 0x000007ff, 0xfc1fff80, 0xfff8007f, 
0x00ff87ff, 0x00007fc0, 0x3fff0000, 0xe0001ffe, 0x3c03ffff, 
0x001f8000, 0xfe000000, 0x0003ffff, 0x01ffff80, 0x0f000000, 
0x00000000, 0x007f1ff8, 0xfff80000, 0x00000000, 0x0000000f, 
0x0007f000, 0xf0000000, 0x0000003f, 0x00000700, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 
0x00000000, 0x00000000, 0x00000000,