トップ 最新 追記

Route 477



2006-12-01

[Ruby/SDL] C言語のenumの代わりには、StringじゃなくてSymbolを使おう

要するに、

 case key
 when "UP"    then @y -= 1
 when "DOWN"  then @y += 1
 when "RIGHT" then @x += 1
 when "LEFT"  then @x -= 1
 end

じゃなくて

 case key
 when :up    then @y -= 1
 when :down  then @y += 1
 when :right then @x += 1
 when :left  then @x -= 1
 end

のように書こう、って話を少し。

この手の「プログラム内部でしか使わない文字列」は、以下のような理由でSymbolを使ったほうが良いです。

Symbolとは (概念的に)

シンボルはLisp由来の機能で、 リファレンスでは「任意の文字列と一対一に対応するオブジェクトです」と定義されています。

概念的には、何かを「指し示す」ためのものがSymbolだと思えば良さそうです。 例えば 「attr_accessor :x」の「:x」 のように「インスタンス変数@xを指し示す」とか、上の例のように「上下左右の方向を指し示す」とか。 ゲームプログラミングでは、C言語のenumのように「何かの種類」を指し示す時に使うことが多いと思います。

Symbolとは (実際的に)

実装上は、シンボルの実体は数値になっています。 また、同じ文字列のシンボルは実体を共有します。 つまり、文字列一つに対し一つの数値が対応します。*1

シンボルは、to_sを呼ぶことで文字列に変換することができます(:hoge.to_s は "hoge" を返す)。

シンボル名には大文字も小文字も使えますが、小文字が使われることが多いようです(また、:hoge と :HOGE は区別される)。

Symbolを使うメリットを以下に挙げます。

(1) シンボルの方が軽い

Symbolは数値で実装されているので、

  • オブジェクト生成が速い
  • 文字列よりも高速に比較できる

といった特徴があります。特に、シンボルは最初の :hoge のときのみインスタンスが作られるので非常に高速です。 (文字列はリテラルが出てくるごとにString.newが呼ばれる)。

(2) コードが読みやすくなる

シンボルは文字列に比べて使い道がはっきりしているので、可読性が向上します。

(3) 無用なバグを避けることができる

シンボルはimmutableなので、Stringのように内容があとから書き換えられる心配がありません。

(4) Symbolの方がタイプ数が少ない

文字列だと「"」が2個要る(しかもシフトも必要)のに対し、Symbolは「:」1個なので打つのが楽です(^^;

参考

*1 といってもmd5みたいなものではなく、使われたシンボルから順に番号を振っていく感じ

[ruby] immutableについての補足

immutableとは、「内容が不変である」という意味です。

例えばStringはimmutableではないので、

# 銭形警部
keibu = "Zenigata Keibu"
p keibu   #=> "Zenigata Keibu"

# だと思ったら…(べりべり)
keibu.gsub!(/Zenigata/, "Lupin")
keibu.gsub!(/Keibu/, "the 3rd")

# ばかもーん、そいつがルパンだ!追えーっ!
p keibu   #=> "Lupin the 3rd"

という感じで、「同じインスタンスなのにいつの間にか内容が入れ替わっている」ということが起こり得ます。

一方Symbolにはgsub!のような内容を変えてしまうメソッド(「破壊的なメソッド」と呼ぶ)は存在しないので、 このようなことは起こりません。

Rubyの組み込みクラスの中では、シンボルや数値がimmutableです。配列やハッシュはmutableです。


2006-12-02

[softs] SVKのチュートリアルを書いた

http://mono.kmc.gr.jp/~yhara/w/?SvkTutorial

超適当ですが。

学園祭の間は部室のサーバが止まるので、その間はSVKを利用してローカルのリポジトリにコミットしてました。 普通にTortoiseSVNのdiffとか「元に戻す」が使えるので便利でした。

途中でローカルブランチを増やしたりややこしいことをしたせいで、元のリポジトリへの反映に結構苦労しましたが、 なんとかコミットできたようです。(^^;

今日知ったこと:

  • svk smerge --baseless を使うと、祖先が共通してなくてもむりやりマージできる
  • svkの本がある (Free Bookなので、出版されたわけではない?)

2006-12-04

[ruby] define_methodで変なメソッド名が作れるんだが

Hpricotのソースを見てたら 意味不明な記述に遭遇。

 module Container::Trav
   def self.filter(tok, &blk)
     define_method("filter[#{tok.is_a?(String) ? tok : tok.inspect}]", &blk)
   end
   中略
   filter '@^=' do |attr,val,i|
      get_attribute(attr).to_s.index(val) == 0
   end

メソッド名が filter[@^=] とか、ありえないですよね。

irb(main):011:0> class Object; define_method("filter[@^=]"){ "asdffdsa" }; end
=> #<Proc:0x00002aaaabb5db68@(irb):11>

irb(main):017:0> 1.methods.find{|m| m=~/filter/}
=> "filter[@^=]"

と思いきや、普通に定義できたwww

irb(main):013:0> 1.filter[@^=]
SyntaxError: compile error
(irb):13: syntax error
1.filter[@^=]
         ^
       from (irb):13

呼び出しはもちろんsyntax error。

irb(main):014:0> 1.__send__("filter[@^=]")
=> "asdffdsa"
irb(main):015:0>

と思いきや、__send__使えば呼べるらしい。

define_methodで普通許されない名前のメソッドが定義できるのって仕様なんですかね?


2006-12-06

[ruby] やたーSubversionのログビューアできたよー

ViewVCがうまくインストールできなかったので自分で作った。後悔はしていない。

repotch 0.0

画像を拡大する

実装はRubyのCGI + Subversion付属のRubyバインディングです。svnコマンドは使っていません。

機能的には大したことないんですが(というかまだログ見るしかできない)、 「コミットログがリビジョンとリビジョンの間に表示される」というのが特徴かも知れません。 (この方が時系列から考えると自然な気がしませんか?)

「部内のプロジェクトの進行状況を適当に眺めたい」というのが開発動機なんで、今後の方針としては 実用よりも変な機能をいっぱい搭載して遊びたいです(笑)。「各プロジェクトのコミット時刻グラフ」とか。

ちなみに「(diff)」って書いてあるところを押すとdiffが見れる予定なんですが、まだ動きません。 というかワーキングコピー作らずにdiff取る方法がわかんね。ファイル2つ取ってきて Algorithm::Diffでも使うかなぁ。

年末の忙しさによってはこのまま更新しない可能性もあるので、 ソースをこっそり上げておきます

あと調査メモがRuby/SVNに。


2006-12-09

[ruby] Subversionのログビューアできたよ(2)

現実逃避の生産性の高さは異常。

更新:

  • diffが取れるようになった
  • リポジトリ一覧モードが付いた
  • リポジトリを直接アクセスするのではなく、Svn::Raを使うようにした

画像の説明 拡大

画像の説明 拡大

ダウンロード


2006-12-10

[ruby][memo] Hpricot気になることメモ

  • "E F" と "E > F"が逆じゃね? > http://code.whytheluckystiff.net/hpricot/wiki/SupportedCssSelectors
  • inner_textってないんだっけ => HEADでは実装されてる
  • nth-child(n) って0 originでいいのか
  • 「spanタグとaタグの間」みたいのはうまく書けないなぁ
  • Elem#children ってユーザが触っていいのかな

しかしHpricotって、それ自身がオリジナルの言語っぽい感じだな。正規表現リテラルがそうであるように。 複雑なことをやろうとするとどうしても泥臭くなるのも似てる。


2006-12-11

[Plagger] WindowsにPlaggerを入れる手順 (2006年年末版)

Windows版のPerl(ActivePerl)にはppmというパッケージマネージャがあって、非常に簡単にインストールできます (パッケージを提供してくれているppm.tcool.orgの中の人に感謝)。

下記の情報は2002年12月(Plagger 0.7.17)時点のものなので、最新版では事情が変わっているかも知れません。 まぁ何かあったらきっと誰かが記事(もしくは公式Wikiとか?)に書いてくれるでしょう。きっと。

必要な知識

  • MS-DOSプロンプトが使える
  • tar.gzが解凍できる

ActivePerlを入れる

最新版のはppm4が入っていてややこしいらしいので、ppm3の入っている5.8.7.815をインストールします。

ppmでPlaggerを入れる

C:\>ppm
ppm> rep add tcool http://ppm.tcool.org/server/ppmserver.cgi?urn:PPMServer
Repositories:
[1] ActiveState Package Repository
[2] tcool
ppm> rep up tcool
Repositories:
[1] tcool
[2] ActiveState Package Repository
ppm> install Plagger
...
ppm> q

数十分かかるので気長に待ちましょう。途中でdllをダウンロードするか?みたいに聞かれたらEnterを押してください。

assetsを入れる

現時点ではppm経由ではassetsが入らないので、 Plagger-0.7.17.tar.gz をダウンロードし、Plagger-0.7.17\assets を適当な場所(C:\Perl\site\lib\Plagger\ とか)にコピーしてください。

使ってみる

以下の内容を sample.yaml という名前で保存します。(c:/perl 等はインストールしたフォルダに合わせて書き換えてください)

global:
  plugin_path:
     - c:/perl/site/lib/Plagger/Plugin/
  assets_path: c:/perl/site/lib/Plagger/assets
  timezone: Asia/Tokyo
  log:
    level: info
plugins:
  - module: Subscription::Config
    config:
      feed:
        - url: http://d.hatena.ne.jp/keyworddiary/Plagger?mode=rss
#一度送信した記事を除く場合
#  - module: Filter::Rule
#    rule:
#        module: Deduped
#本文も取ってくる場合
#  - module: Filter::EntryFullText?

  - module: Publish::Gmail
    config:
      mailto: yhara@example.jp
      mailroute:
        via: smtp
        host: (プロバイダのメールサーバのアドレス)

MS-DOSプロンプトを開いて、Plaggerを実行してみます。

C:\> plagger -c sample.yaml
Plagger [info] plugin Plagger::Plugin::Subscription::Config loaded.
Plagger [info] plugin Plagger::Plugin::Publish::Gmail loaded.
(略)
Plagger::Plugin::Aggregator::Simple [info] Fetch http://d.hatena.ne.jp/keyworddi
ary/Plagger?mode=rss
Plagger::Plugin::Aggregator::Simple [info] Aggregate http://d.hatena.ne.jp/keywo
rddiary/Plagger?mode=rss success: 21 entries.
Plagger::Plugin::Publish::Gmail [info] Sending はてなダイアリー - 「Plagger」を
含む日記 to yhara@example.jp

のようになったらOKです。指定したメールアドレスにはてなの新着日記が送信されたことと思います。

注:

  • 以上の手順でインストールできるのはPlaggerの標準機能のみです(プラグインによっては追加のライブラリを必要とするものがあります)。

参考:

[Plagger] Filter::Pipeがうまく動かない

なんかタイムアウトとか言われる。

調査したのは

  • Win32 + Plagger 0.7.17
  • Linux + Plagger 0.7.15

で、エラーメッセージは

  • Windows
IPC::Run: timeout on timer #1 at C:/Perl/site/lib/IPC/Run.pm line 2932
  • Unix
Plagger::Plugin::Filter::Pipe [error] filter timeout

という感じ。

パイプ先のプログラムは、タイムアウトエラーになるのが

  • ruby -e "print $stdin.read"
  • nkf --unix
  • /usr/bin/nkf

で、OKなのが

  • cat
  • tee /tmp/asdf

とか。むー。Publish::Pipeの方はrubyでもnkfでもうまく行くんだけど。

本日のツッコミ(全6件) [ツッコミを入れる]

Before...

yhara [r1911にて、 * ruby -e 'print ARGF.read' * nkf --unix いずれも正しく実..]

yhara [っと、Windowsだとまだ動かないみたい? 家に帰ったら追試してみます。 あと、0.7.17だとnkf -uでもt..]

yhara [Windowsでも正しく動くのを確認しました。ありがとうございました。]


2006-12-20

[Ruby/SDL] キーボード情報の扱い(Ver.2)

danさんのところで話がでてたので、思い出したように書いてみる。

前回から紆余曲折を経て、現在はこんな感じになってます。 最初にキーと通称(symbol)の対応を定義しておいて、以降のコードでは通称のみを使います。 こうすると、ゲーム内では「:up」というシンボル一つで「上キーとKキー*1とジョイパッドの上方向」を まとめて扱うことが出来て便利です。

class Input
  #ユーザ用
  define_key SDL::Key::ESCAPE, :exit
  define_key SDL::Key::UP    , :up
  define_key SDL::Key::DOWN  , :down
  define_key SDL::Key::LEFT  , :left
  define_key SDL::Key::RIGHT , :right
  define_key SDL::Key::K     , :up
  define_key SDL::Key::J     , :down
  define_key SDL::Key::H     , :left
  define_key SDL::Key::L     , :right
  define_key SDL::Key::RETURN, :ok
  define_key SDL::Key::Z     , :ok
  define_key SDL::Key::X     , :cancel
  define_pad 1, :ok         # ○
  define_pad 2, :cancel     # ×

  #NF用
  define_key SDL::Key::F1, :reset
  define_key SDL::Key::F10, :goal

  if DEBUG_MODE
    #デバッグ用(そのうち消す)
    define_key SDL::Key::W     , :toggle_window
    define_key SDL::Key::K0    , :fast_move
    define_key SDL::Key::V     , :event_sample

    #製作補助用
    define_key SDL::Key::R     , :reload_images
    define_key SDL::Key::I     , :inspect
    define_key SDL::Key::A     , :auto_reload
    define_key SDL::Key::Y     , :inspect_events

    #マップエディタ用
    define_pad 3, :put_chip   # □
    define_pad 0, :erase_chip # △
    define_pad 9, :yuutai     # select
    define_pad 6, :prev_chip  # L1
    define_pad 7, :next_chip  # R1
    define_key_shift SDL::Key::K1, :force_encount #!
    define_key SDL::Key::B     , :set_base_chip
    define_key SDL::Key::P     , :put_chip
    define_key SDL::Key::G     , :get_chip
    define_key SDL::Key::E     , :erase_chip
    define_key SDL::Key::COMMA , :prev_chip,   :repeats
    define_key SDL::Key::PERIOD, :next_chip,   :repeats
    define_key SDL::Key::S     , :save_map
    define_key SDL::Key::U     , :yuutai
    define_key SDL::Key::TAB   , :next_capital
  end
end

定義用メソッド(Rails風?)には以下のような種類があります。

define_key キー定数, シンボル
キーを定義する
define_key キー定数, シンボル, :repeats
キーを定義する(擬似キーリピートあり)
define_key_shift キー定数, シンボル
シフト+キーを定義する(ctrl,alt,metaもあるよ!)
define_pad ボタン番号, シンボル
パッドのボタンを定義する

パッドの上下左右は、自動的に :up, :down, :left, :right というシンボルに対応づけられます。固定です。

使い方は

input = Input.new
loop do
  input.clear #12/23追記:これを忘れてました。すいません
  input.poll

  input[:up]         #=>「上が押されていたか」
  input.pushed? :ok  #=>「OKボタンが押されたか」
  ..
end

という感じで、実装はinput.rbに。

*1 roguelike風


2006-12-21

[junk] 磁石

ハードディスクにあんなに強い磁石が入っているとは…。*1

*1 研究室の廃棄物を分解して遊ん…いや、セキュリティ的にね(という口実)

[Ruby/SDL][memo] コンパイルについて

  • -MDではなく-MTを使うと静的リンクする
  • SDL.lib, SDLmain.libを自動的に書いてほしいな
  • 環境変数LIB, INCLUDEを設定するのが面倒なんだがなんとかならないか

2006-12-24

[ruby] Ruby勉強会@関西

ふと思ったのだが、実はプログラミング自体が初めてって人は少なくて、「C/Java/Perlは知ってるけどRubyは初めてです」 みたいな人が多いんじゃないかなぁ…と思った。

アンケートに「使える言語に丸を付けてください」みたいな欄があると面白いかも。

本日のツッコミ(全2件) [ツッコミを入れる]

keisuken [> アンケートに「使える言語に丸を付けてください」みたいな欄 ああ,それ興味ありますね. #Webやってる人ならなん..]

yhara [おお、ありがとうございます。 前回の勉強会で、僕のまわりに他言語経験者が多かったのでふとこう思ったのでした。 Web..]


2006-12-25

[Ruby/SDL] Ruby/SDLスターターキット : Rubyはbetter HSPに成り得るか

面倒なインストールは一切不要、ダウンロードして解凍するだけでゲーム開発が始められる「Ruby/SDLスターターキット」をリリースしました。

http://mono.kmc.gr.jp/~yhara/w/?RubySDLStarterKit

今まで「Ruby/SDLは面白そうだけどインストールが面倒だなぁ…」と思っていた人はぜひ試してみてください。 簡単*1 なサンプルゲームも入っています。

最近まつもとさんの日記でHSPの話が出ていましたが、 そこでHSPのメリットとして挙げられていた条件は

  • フリーウェアである → OK
  • セットアップが簡単 → 解凍するだけでOK
  • ウィンドウ、画像の操作が簡単 → ゲームについてはOK*2
  • 文法が単純で習得が容易 → たぶんOK (チュートリアル次第?)
  • 自作EXEの配布が可能 → OK

のように、これでほぼ満たすことができたと思います。これでRubyも、HSPの「手軽さ」にだいぶ近づけたのではないでしょうか。

が、本当にHSPくらい普及するためには、

  • チュートリアル
  • 豊富なサンプル
  • ユーザー掲示板
  • 1キーでヘルプが見られたり、デバッグを補助してくれたりする開発環境(RDEが使えるか?)
  • 入門書(書きたいなぁ)

など、道のりはまだまだ長そうです。*3

ともあれ、まずは実際にゲームを作ってみる人が増えないことにはどうしようもありません。 ということで、Ruby初心者な人も、Rubyistな人も、正月休みにゲーム製作にチャレンジしてみませんか? 楽しいゲームをお待ちしています。 (あと、apple catcherに見栄えのいい絵を付けてくれる方も募集しています^^;)

*1 simpleな、という意味です。easyではないかも知れません :-) 難しすぎるよ!という人はソースをハックしてください。簡単すぎるぜ!という人は隠しモード(真ん中辺のコメント参照)をどうぞ…

*2 HSPはGUIアプリも作れるが、RSKitはゲームのみを対象としている

*3 「○○の10倍の生産性が〜」みたいなキャッチフレーズと共に、Railsばりに革新的なゲームフレームワークが登場すれば 分かりませんが… :-)

本日のツッコミ(全4件) [ツッコミを入れる]

Before...

サイロス [早速ダウンロードしてみました。 面白いですね、これ。 Miyakoとくっつければもっと面白いかも(笑)。]

yhara [ありがとうございます。 いまのRuby/SDLに一番足らないものは知名度だと思うので(笑)、 使ったり作ったり記事を..]

サイロス [>yharaさん かなり良い環境になると思いますので、 お互いがんばりましょう。]


2006-12-27

[Ruby/SDL] RSKit(2)

(まさか、 i386-mswin32/ 内はライブラリサーチの対象外とか!?)。

[http://d.hatena.ne.jp/cyross/20061226#p1より引用]

_|‾|○

ごめんなさい、その通りです…。年内に修正版をリリースします。とりあえず、lib/rskit/on_*.rbを修正すれば直ります。

[Ruby/SDL][memo] exe生成器

よく考えると、Exerb使ったexe生成器を同梱すればいいんだよな。 「pack.exeをダブルクリックすると、必要なリソースを全てまとめたexeファイルを生成します」みたいな。 vrubyでGUI作ってアイコンとか指定できるようにすると良さそう。

exeに入れるもの:

  • *.rb
  • *.so
  • *.dll

あと音声や画像もexeに入るといいんだけど…exeに入れてしまうとUnixで動かせないんだよなぁ。 せっかくRuby/SDLなんだから「WindowsでもUnixでも遊べるゲームができます!」って方が格好いいんだが。

まぁとりあえず音声・画像は後回しか。

[Ruby/SDL] HID デバイスってどうやって制御するんだろう。

Wiiリモコンきたー!

pygameにできてRubyにできないのはなんか 悔しいので(笑)、応援してます。

本日のツッコミ(全2件) [ツッコミを入れる]

サイロス [今年もよろしくです。 >とりあえず、lib/rskit/on_*.rbを修正すれば直ります。 ありがとうございます..]

yhara [確認ありがとうございます。今年もよろしくお願いします。 > .rbまで入れてしまうと、Unixでプレイできないと思..]


2006-12-28

[ruby] tempdir.rbが欲しい

Tempfileのディレクトリ版みたいなやつ。tmpdirはシステムのテンポラリディレクトリのパスを教えてくれるだけだ し*1

いつもは

   tmpdir = Dir.tmpdir
   k = 0
   k += 1 while File.exist?(File.join(tmpdir, "hoge#{k}"))
   dir = File.join(tmpdir, "hoge#{k}")
   Dir.mkdir(dir)

みたいな感じで作ってるんだが。dir = Tempdir.new("hoge") でディレクトリ作ってパス名返してくれると嬉しい。

あ、Tempdir.new("hoge") do |dir| ... end とかだともっといいかも(ブロック抜けるときにディレクトリをrm_fする)。

*1 あと片方がtempで片方がtmpなのは気持ち悪い(笑)

[prog] HSPの凄さ

HSPってのは多分、「必要最低限」で成り立ってるんだな。

HSPのサイトを見てもおにたま氏の名前しかないから、多分ほとんどを一人で開発しているのだろう。 GUIアプリからゲームやネットワークまで、さまざまなソフトが作れる環境を開発し、なおかつそれが ここまで広く使われるってのは並みのことじゃない。ていうか、普通は一人でできるってレベルじゃない(笑)。

一人で開発を進める欠点は、どうしても作業量が限られてしまうってことだ。少ない作業量で 言語とライブラリとエディタとドキュメントとウェブサイトを開発しようと思ったら、 どうしたってそれぞれは「広く浅く」にならざるを得ないだろう。 そういう視点で見れば、HSPの言語仕様ってのは限りなく「パーズが簡単なように」できてることに気づく *1

おにたま氏の凄さは「どこまで実装すれば使ってもらえるのに十分か」という「必要最低限」を 見切る能力にあるんじゃないか。

*1 たとえば、最近まで戻り値の構文が無かったりとか、最近まで演算子が右から順に結合してたとか

[ruby] .と..がうざい

Dir.entriesとかDir.foreachとかDir#eachが.と..を渡してくるのがうざい!デフォルトで削っといてくれよ!

まぁDir.glob("foo/bar/*") とかやればいいんだけどさ。

つーかRubyのFileとDirって、他の標準ライブラリに比べて全体的にわかりにくい気がする。 抽象度が低い(ファイルシステム寄りな)APIだからか?

Ruby初心者だったときに結構はまった。 ファイルの移動がmoveじゃなくてrenameだったりとか。ディレクトリの移動もFile.rename使うとか。 Unixに慣れてる人なら当たり前なんだろうけどなぁ。

(追記:そうか、Pathname使えばいいのか。)