13F

備忘録

Rubyを勉強中 2

2007-11-12 21:57:29 | Weblog
なんとなく以下のようなものを書いてハマるの巻。
class Foo
  def method_missing(name, *args)
    # なぜかマッチしない
    if name =~ /Aadd_(.*)/ && args.length == 1
      auto_push($1, args[0])
    end
  end

  def auto_push(name, arg)
    v_name = "@#{name}"
    array = instance_variable_get(v_name)
    unless array
      array = []
      instance_variable_set(v_name, array)
    end
    array.push(arg)
  end
end

x = Foo.new
x.add_bar('bar!')
p x

4行目の単純な正規表現がマッチしないため auto_push が呼ばれず困惑。"puts name" とか挿入してみてもきちんと "add_bar" と出てくるため、なんでだよーと思ってしまった。

よくドキュメントを見ると method_missing の第一引数は Symbol で、そのままでは正規表現にマッチしないのだった……。
:add_bar =~ /bar/  # マッチしない
100 =~ /0/         # こういうのも同じ

はじめから相手にする気がないのにTypeErrorとかにしないのは何故だろう? できるだけ例外は吐かないようにするポリシーなのかな。

教訓としては、
  • ドキュメントをきちんと読め。
  • 「printfデバッグ」をやるときは puts ではなく p を使う?(p なら :add_bar のようにシンボルとして表示された)


追記:正規表現のマッチングは、Rubyでは以下のように書くのが正しくなったらしい。
/bar/ =~ :add_bar
/0/ =~ 100

これだと期待通り(?)TypeError になる。

Rubyを勉強中

2007-11-12 21:36:40 | Weblog
12/1の試験を受けることになったので真面目に勉強することにした。

いろいろいじっていて、Array#join が
[1,2,3].join('--') {|x| x+1}
=> "2--3--4"

のように変換のためのブロックをとってほしいなあ、と思ったので拡張してみた。
class Array
  alias :join_org :join

  def join(sep=$,, &block)
    if block
      join_with_block(sep || '', block, [])
    else
      join_org(sep)
    end
  end

protected
  def join_with_block(sep, block, stack)
    result = ''
    first = true

    each do |elem|
      result += sep unless first

      if elem.kind_of? Array
        if stack.include? elem
          result += '[...]'
        else
          stack.push(self)
          result += elem.join_with_block(sep, block, stack)
          stack.pop
        end
      else
        result += block.call(elem).to_s
      end

      first = false
    end

    result
  end
end


感想としては、
  • メソッドの再定義をして、その中で元のメソッドを使いたい場合はaliasするしかないのだろうか? 継承時のsuperのように元のメソッドを呼べるとうれしいんだけど……(不必要な「名前」が増えるのがきもちわるい)
  • そもそも、上のようなことが必要なのか(既存のクラスにもっといい方法があったりして)。
  • オープンクラスってすばらしい。

まだまだ東方Projectプレイ中

2007-11-12 21:16:22 | Weblog
まだ断続的にプレイ中。

風神録は魔理沙Cで全作品中初のHardクリア。これは感動した。風神録はボムがたくさん使えるためにボスの弾幕はほとんど飛ばすことができるので、道中をパターン化できればわたしのような素人でもクリアが可能にできているようだ。

あとははじめてプレイしたときからの目標だった魔理沙(恋符)での妖々夢Normalを達成した。風神録Hardで鍛えたおかげで以前と比べて弾幕が多少「見える」ようになったみたい。

次の目標は魔理沙で妖々夢のHardをクリアすること。こっちはまだ2回くらいコンティニューが必要なので、時間がかかりそう。


Javaでメールを送るときのエンコーディング

2007-10-11 01:40:26 | Weblog
Javaでメールを送るときなどに、ふつうのISO-2022-JP でエンコードすると丸付き数字とか、草ナギ剛の「なぎ」とかが文字化けしたりする。

これの暫定対策として、JDK 5.0 update7 から、CP50220 などのエンコーディングが追加されていて、これを使うとそういった文字も文字化けしなくなる。
http://www.yks.ne.jp/~tsurucha/ChangeLog/2007-03.html#2007-03-22

ってとこまでは聞いたことがあったんだけど、全角ダッシュ(uFF0D)とかポンド記号(uFFE1)みたいな、今まで手動で代わりの文字(u2212とか)に変換して対処していたようなものも、このエンコーディングだとそのままOKになるようだ。これは知らなかった。

以下、ちょっとした確認。
import java.io.*;
import java.nio.*;
import java.nio.charset.*;

public class EncodeChecker {
  public static void main(String[] args) throws Exception {
    // 怪しげな文字。以下からいただきました。
    // http://www.ingrid.org/java/i18n/encoding/ja-conv.html
    char[] chars = {
      '\\', '\u007E', '\u00A2', '\u00A3', '\u00AC',
      '\u00A5', '\u203E', '\u2014', '\u2015', '\u2016',
      '\u2026', '\u2212', '\u2225', '\u301C', '\u22EF',
      '\uFF0D', '\uFF5E', '\uFFE0', '\uFFE1', '\uFFE2',
      '\uFFE3',
      '\u2160', '\u2468', '\u3231', '\u3336', '\u5F45',
    };
    
    PrintWriter writer = new PrintWriter(new File("result.txt"), "UTF-8");
    checkAll(writer, "ISO-2022-JP", chars);
    writer.println();
    checkAll(writer, "CP50220", chars);
    writer.close();
  }

  private static void checkAll(PrintWriter writer, String encoding, char[] target)
  throws UnsupportedEncodingException {
    EncodeChecker checker = new EncodeChecker(encoding);
    writer.println(String.format("# %s", encoding));
    for (char c : target) {
      writer.write(checker.check(c));
      writer.println();
    }
  }

  private CharsetEncoder encoder;

  public EncodeChecker(String encoding)
  throws UnsupportedEncodingException {
    Charset charset = Charset.forName(encoding);
    encoder = charset.newEncoder()
      .onMalformedInput(CodingErrorAction.REPORT)
      .onUnmappableCharacter(CodingErrorAction.REPORT);
  }

  public String check(char c) {
    StringBuilder result = new StringBuilder();
    result.append(String.format("\\u%04X [%c] : ", (int)c, c));

    CharBuffer cb = CharBuffer.wrap(new char[]{c});
    ByteBuffer bb = ByteBuffer.allocate(10);
    CoderResult cr = encoder.encode(cb, bb, true);

    if (cr.isUnderflow()) {
      result.append("○ [ ");
      int len = bb.position();
      for (int i=0; i<len; i++) {
        result.append(String.format("%02X ", bb.get(i)));
      }
      result.append("]");
    } else if (cr.isError()) {
      result.append("×");
    } else {
      result.append("?");
    }

    return result.toString();
  }
}

1.5.0_13-b05 で実行したときのresult.txtの中身。
# ISO-2022-JP
u005C [\] : ○ [ 5C ]
u007E [~] : ○ [ 7E ]
u00A2 [¢] : ○ [ 1B 24 42 21 71 ]
u00A3 [£] : ○ [ 21 72 ]
u00AC [¬] : ○ [ 22 4C ]
u00A5 [] : ○ [ 1B 28 4A 5C ]
u203E [~] : ○ [ 7E ]
u2014 [―] : ○ [ 1B 24 42 21 3D ]
u2015 [―] : ×
u2016 [∥] : ○ [ 21 42 ]
u2026 […] : ○ [ 21 44 ]
u2212 [-] : ○ [ 21 5D ]
u2225 [∥] : ×
u301C [~] : ○ [ 21 41 ]
u22EF […] : ×
uFF0D [-] : ×
uFF5E [~] : ×
uFFE0 [¢] : ×
uFFE1 [£] : ×
uFFE2 [¬] : ×
uFFE3 [ ̄] : ○ [ 21 31 ]
u2160 [Ⅰ] : ×
u2468 [⑨] : ×
u3231 [㈱] : ×
u3336 [㌶] : ×
u5F45 [] : ×

# CP50220
u005C [\] : ○ [ 5C ]
u007E [~] : ○ [ 7E ]
u00A2 [¢] : ○ [ 1B 24 42 21 71 ]
u00A3 [£] : ○ [ 21 72 ]
u00AC [¬] : ○ [ 22 4C ]
u00A5 [] : ○ [ 1B 28 4A 5C ]
u203E [~] : ○ [ 7E ]
u2014 [―] : ×
u2015 [―] : ○ [ 1B 24 42 21 3D ]
u2016 [∥] : ○ [ 21 42 ]
u2026 […] : ○ [ 21 44 ]
u2212 [-] : ○ [ 21 5D ]
u2225 [∥] : ○ [ 21 42 ]
u301C [~] : ○ [ 21 41 ]
u22EF […] : ×
uFF0D [-] : ○ [ 21 5D ]
uFF5E [~] : ○ [ 1B 24 28 44 22 37 ]
uFFE0 [¢] : ○ [ 1B 24 42 21 71 ]
uFFE1 [£] : ○ [ 21 72 ]
uFFE2 [¬] : ○ [ 22 4C ]
uFFE3 [ ̄] : ○ [ 21 31 ]
u2160 [Ⅰ] : ○ [ 2D 35 ]
u2468 [⑨] : ○ [ 2D 29 ]
u3231 [㈱] : ○ [ 2D 6A ]
u3336 [㌶] : ○ [ 2D 47 ]
u5F45 [] : ○ [ 1B 24 28 44 3C 74 ]

gooブログってEUCなのか…。

世界樹の迷宮II

2007-10-07 00:13:37 | Weblog
http://www.famitsu.com/game/coming/1210951_1407.html

前作が素晴らしかったので物凄ーーく楽しみだけど、前作のディレクターの人がいなくなってしまったのが不安要素。PodCastやインタビュー記事での数々の発言を聞いてると、この人なら「II」に対していろんな要望やらが出ても正しい判断ができるだろうな、という印象だったのでアトラスを辞めた(=次作には関わらない)と知ったときは結構ショックだった。「II」が良い方向に進化していることを祈りたい。

まだまだ東方風神録プレイ中

2007-10-06 23:42:28 | Weblog
最初はクリアできる気がしなかった風神録だけど、やってるうちに馴れてきて、魔理沙では三種類すべてノーマルノーコンティニュークリア+霊夢では三種類すべてノーマルコンティニュークリア。なんとかなるもんですね。

今回のボスはボムがほとんど無意味なので嫌が応でも避け続ける必要があり、最初はボム頼みの下手糞プレイヤーとしては途方に暮れてしまった。でも見方を変えてみると、いままでの「ヘタに避けてみようとして、ボムを残したまま被弾したらもったいない。ましてやクリアがかかっている状況では」的なチキン思考が封印されるため、なんというか堂々と避けにチャレンジできるわけだ。やっぱりボムでごまかすよりは頑張って避けまくったほうが楽しいので、この仕様は今では逆によかったと思えるようになった。

Log4Jの設定ファイル変更検知

2007-10-03 23:39:23 | Weblog
Log4Jで、log4j.xmlとかlog4j.propertiesが変更された場合に、新しい設定をアプリケーションを再起動せずに反映させたい。一番簡単なのは、ServletContextListener の contextInitialized とかで DOMConfigurator.configureAndWatch()PropertyConfigurator.configureAndWatch を呼んで、ファイルの変更を検知してくれるように設定することだけど、Log4JのFAQ にもあるようにこれは停止できないスレッドを起動して変更を確認させるようになっていて、ちょっと危ない場合があるようだ。

そこで、とりあえず この辺を参考にしてJMXで手動リロードできるようにした。
public interface Log4jAdminMBean {
    void reloadDOMConfig(String path);
}

----

import javax.management.NotCompliantMBeanException;
import javax.management.StandardMBean;

import org.apache.log4j.LogManager;
import org.apache.log4j.xml.DOMConfigurator;

public class Log4jAdminMBeanImpl extends StandardMBean
implements Log4jAdminMBean {
    public Log4jAdminMBeanImpl() throws NotCompliantMBeanException {
        super(Log4jAdminMBean.class);
    }
    public void reloadDOMConfig(String path) {
        new DOMConfigurator().doConfigure(path,
          LogManager.getLoggerRepository());
    }
}

JMXって使ってみると何気に簡単でいいなあ。

東方風神録プレイ中

2007-10-03 23:01:43 | Weblog
風神録難しい難しいと思っていたけど、冷静に考えてみると、最初の残機が3で、エクステンド4回と1upアイテムが2個あるので最終的な合計は9。stage4とstage5はチキンプレイに徹してまあ合計3回くらい撃墜されたとしても、stage6には残機6で挑戦できる。

つまりコンティニュークリアのほうが難しいんであって、何回コンティニューしてもクリアできない!と絶望するほうがおかしかったということか。6面のコンティニュープラクティス(残機3でスタート)をひたすら繰り返すうちに最後のスペルカードまで辿りつくだけならほぼ100%になっているので、残機3で最後のスペルカードを乗り切ればいいわけだ。

……で、事実あっさりとノーマルノーコンティニュークリアできましたとさ。

それにしても相変わらずエンディングを聞くと泣ける。

東方風神録難しすぎ

2007-09-29 16:53:04 | Weblog
風神録をやっているわけだが……。

これは難しすぎる。道中は弾数が多い上に見づらくて難しいわ、気合で頑張るしかないラスポスの最後のスペルカードが長すぎるわでこれまでやった4作品の中では圧倒的に難しい。Easyでコンティニュークリアがやっとで、ノーマルのstage6は100回くらいコンティニューしてもクリアできない。これでノーコンティニュークリアとか心底ありえない。

Wiki では「どれからやればいいの?」⇒「風神録が遊びやすくておすすめ」とか書かれているけど、自分が風神録からはじめてたら多分あまりの難易度に絶望して投げてたと思う。どう考えても妖々夢か永夜抄にすべき。

まだまだ東方妖々夢プレイ中

2007-09-19 23:51:01 | Weblog
幻符咲夜ではNormalもクリアできた。やっぱりボム4つは有難すぎる。

調子に乗ってHardもやってみたら、スペルカードは半分くらい入れ替わってるわ、いろんなところで追加の弾が増えたせいでパターンも通用しないわでコンティニュークリアがやっとだった。EasyとNormalはあまり違いがないように思えたけど、NormalとHardはぜんぜん違う感じ。