-- / --
--
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

12 / 31
Tue

大晦日だということをすっかり忘れていた Ziphil です。

突然ですが、 Project Euler に登録してみました。 せっかくなので、 微妙な空き時間があるときは、 これの問題を解いてみることにしました。 ということで、 第 1 問。

3 または 5 の倍数である、 10 未満の全ての自然数を並べると、 3, 5, 6, 9 を得る。 これらの倍数の総和は 23 である。 1000 未満の数であって、 3 または 5 の倍数であるもの全ての和を求めよ。

1 問目ということもあって、 非常に簡単。 Ruby で書いてみる。

def project_euler_1
  puts (1...1000).select{|i| (i % 3) * (i % 5) == 0}.inject(&:+)
end

1 以上 1000 未満の Range インスタンスを作って、 3 の倍数または 5 の倍数のものだけを抽出して、 和をとるだけです。 3 でわった余りと 5 でわった余りの積が 0 としているのは、 ただのオシャレです。 オシャレしたい年頃なんです。 意味分かりません。 実行してみます。

project_euler_1  # => 233168

ということで、 記念すべき最初の解答は 233168 ですね。 Project Euler 第 1 問でした。


スポンサーサイト
comment ×0
12 / 30
Mon

Ziphil です。

モンスターのデータベース作成の傍ら、 プログラミングの方もやっていました。 そして、 ようやく完成しました。 ジャーン!!

708_製作過程A

何が完成したかって? 画面下部のテキストフィールドですよ。 ゲーム画面になじむように背景色とかを変えているので、 微妙に分かりにくいですが、 テキストフィールドになっています。

いや、 「JTextField 使えば普通じゃん」 とか言わないでくださいよ。 いろいろ大変だったんですから・・・。 実は、 ゲームループを制御するのにアクティブレンダリングを採用してるので、 普通に使うとコンポーネントが正しく表示されずに点滅したり、 全く表示されなかったりで、 これまでうまくいかなかったんです。 結局、 BufferStrategy を用いて Canvas インスタンスにゲーム画面を描画して、 LayeredPane を用いて Canvas と JTextField の前後関係を設定することになりました。

ちなみに、 テキストフィールドが使われるのは、 おそらくゲーム開始時の名前入力のときだけだと思います。 いろいろ試行錯誤した上での結果ですが、 使われるのはたった 1 回というね。


comment ×0
12 / 29
Sun

Computer Modern フォントの美しさに気づき始めた Ziphil です。

最近プログラミングの話題ばっかりですねー。 ということで、 久々にドット絵を描いてみました! ・・・ではなく、 データベース設定の話です。

RPG を作るのは大変で、 多くの人が挫折するっていうのはよく聞く話で、 RPG ツクールとか買って最初は意気込んで作り始めても、 結局完成しないなんてことも、 よくあるみたいですね。 何で挫折するかって、 設定すべきデータベースが多いことでしょうね。 作ってみて始めてわかるものですが、 RPG のデータベースが多いこと多いこと。 ステータスやら、 状態異常やら、 武器やら、 防具やら・・・。 でも、 こういうデータベースを作るのも、 また楽しいんですよねぇ。

さて、 このごろプログラミングばかりでしたが、 実はゲーム製作は進んでいません! なぜかというと、 次にプログラミングすべき部分が、 敵キャラとのバトルに関する処理だからです。 実は、 敵キャラのデータベースをまだ何も設定してないんです。

で、 困ってるのが、 敵モンスターってどういう風にプレイヤーに攻撃して、 どういう風に防御するのかなー、ということです。 プレイヤーは武器を持ってますから、 武器で攻撃するじゃないですか。 じゃ、 モンスターは何で攻撃するんでしょう。 剣とか持ってるんですかね、 それとも素手? じゃ、 モンスターの防御は? プレイヤーと同じように、 鎧とか着ているのか、 それとも防御は屈強な体だけ?

私の RPG にはペットシステムを導入して、 モンスターを仲間にできるようにしようと思っているので、 プレイヤー自身と、 NPC の人間の仲間と、 ペットにしたモンスターという、 3 つの要素を同等に扱いたいんです。 そうすると、 もちろん、 ペットにも武器を持たせ防具を着せることができるということになります。 でも、 野生で出てくるモンスターが武器を持ってるってのも、 何か不自然・・・。 かといって、 野生のモンスターが素っ裸だとすると、 野生が弱すぎるか、 武装したペットが強すぎるか、 どちらかになってしまいます。 それに、 野生のモンスターが武器や防具を持つと、 その武器や防具によって、 モンスターの強さにかなり差が出ます。 序盤に出てくるスライムみたいな敵でも、 エクスカリバーみたいな最強武器を身につけていれば、 かなりの強さになりますからね。

さて、 どうしましょうか。 今のところ、 モンスターも最初はいくつか武器や防具を持っていて、 その武器や防具はモンスターごとに定まっている、 ということにしようと思っています。 まあ、 その分、 それぞれのモンスターがもつ武器とか防具の分だけ、 データベース量が増えて、 ただでさえ量が多いデータベースをさらに増やすことになりますが。 まあ、 楽しいんで問題ないですけどねー。


comment ×0
12 / 25
Wed

「with」 を打とうとすると 「width」 になってる Ziphil です。

Ruby でハッシュを使っていたら、 予期しない出来事に遭遇したので、 それについてまとめてみましたよー。

とりあえず、 まずは Hash クラスのコンストラクタを使って、 デフォルト値が空のハッシュになるような、 ハッシュ hash1 を作成します。 で、 値を設定します。 こんなコードを書きました。

hash1 = Hash.new{{}}
hash1[0][:a] = 100

さて、 ここで問題です! このとき、 hash1[0][:a] の返り値は何でしょう? え、 そんなの当たり前じゃないかって?

p hash1[0][:a]  #=> nil

答えは nil です。 あれ?

じゃ、 続いて次の問題にいきますよー! 同じようにハッシュ hash2 を定義して、 値を設定します。

hash2 = Hash.new({})
hash2[0][:a] = 100

このとき、 hash2[0][:a] の返り値は何でしょう? 今度こそ間違えないですよね・・・?

p hash2[0][:a]  #=> 100

答えは 100 でした! あれれ?

じゃ、 続いて続いて問題! またまた同じようにハッシュ hash3 を定義して、 値を設定します。

hash3 = Hash.new{|h, k| h[k] = {}}
hash3[0][:a] = 100

何が聞かれるか分かってると思いますが、 hash3[0][:a] の返り値は何でしょう? 大丈夫ですよね?

p hash3[0][:a]  #=> 100

答えは 100 でした! あれれれ?

混乱しちゃいましたか? じゃ、 別のキーに対する値を取得しようとしたらどうなるでしょうか? 例えば、 hash1[1][:a]hash2[1][:a]hash3[1][:a] それぞれの返り値は?

p hash1[1][:a]  #=> nil
p hash2[1][:a]  #=> 100
p hash3[1][:a]  #=> nil

さて、 そろそろ解説しましょうか。

ブロックを使わない Hash の定義 (hash2) では、 デフォルト値として、 常に同一のオブジェクトが返されます。 オブジェクト ID を調べてみれば一目瞭然です。

p hash2[0].object_id  #=> 10730174
p hash2[1].object_id  #=> 10730174

一方、 ブロックを使う Hash の定義 (hash1) では、 存在しないキーに対する値を呼び出そうとするたびに、 ブロックが実行されます。 そのため、 値が ([]= メソッドとか store メソッドとかで) 直接設定されない限り、 同じキーを指定しても、 異なるオブジェクトが返ってきます。

p hash1[0].object_id  #=> 10238340
p hash1[1].object_id  #=> 10238256
p hash1[0].object_id  #=> 10238200

したがって、 hash2[0][:a] = 100 は、 hash2 のデフォルト値のオブジェクトそのものを書き換えてしまっているため、 それ以降、 存在しないキーの値を取得しようとすると、 書き換えられた後のオブジェクトが返ってきてしまい、 hash2[1][:a] の結果も 100 になります。 一方、 hash1[0][:a] = 100 は、 ブロックを実行するときに生成された空のハッシュにキーと値を設定しているだけなので、 次に hash1[0] を実行しても、 ブロックの実行結果である空のハッシュが返され、 hash1[0][:a] の結果は nil になるわけです。

さて、 それをふまえて hash3 のような定義について考えてみましょう。 これに対して存在しないキーの値を取得しようとすると、 ブロックが実行されます。 ブロック内では、 自分自身にキーと値を設定しています。 また、 Hash#[]= メソッド や Hash#store メソッドの返り値は、 設定された値そのものになっています。 つまり、 hash3[0] が呼ばれた時点で、 hash3 のキー 0 に対して空のハッシュが格納され、 同時に hash3[0] の結果として、 同一オブジェクトの空のハッシュが返されます。 そして、 その空のハッシュに対し、 キー :a と値 100 を設定しているわけです。 オブジェクト ID を調べてみれば、 さらに理解できると思います。

p hash3[0].object_id  #=> 10696952
p hash3[1].object_id  #=> 10696868
p hash3[0].object_id  #=> 10696952
p hash3[1].object_id  #=> 10696868

まあ、 要するに、 ハッシュとか配列のデフォルト値の設定には、 十分注意しましょうということです。 特に、 デフォルト値に対し破壊的なメソッドを実行する場合は、 hash3 みたいな定義の仕方をしないと痛い目にあいます。


comment ×0
12 / 24
Tue

「1,500 万」 ではなく 「15,00 万」 だろ、 とか思う Ziphil です。

今日の昼ごろ、 このエントリーでこんなコードを書きました。

class String
  def camel_case
    name = split("_")
    ([name.first] + name[1, name.size - 1].map{|i| i.capitalize}).join
  end
end
class Module
  def def_java(*names)
    names.each do |name|
      class_eval("alias :#{name.to_s.camel_case} :#{name} ")
    end
  end
end
#
class MainPanel < JPanel 
  def paint_component(graphics)
    super
    # 処理
  end
  def_java :paint_component
end

自分でコードを書いておいて、 何が起こっているのか実は把握してなかったり。 特に def_java :paint_component のあたりとか。 ということで、 何が起こっているのか調査してみます。

まずは状況を簡略化するために、 Test クラスに foo メソッドを定義し、 Module クラスを拡張して bar メソッドを定義した、 こんなコードを用意してみました。

class Module
  def bar
    puts("bar in Module")
  end
end
class Test
  def foo
    puts("foo in Test")
  end
end

さて、 このとき、 Test クラスの定義内で bar メソッドを呼び出すことができます。

class Test
  def foo
    puts("foo in Test")
  end
  bar                    #=> bar in Module
end

これが不思議なんですよねぇ・・・。 bar メソッドは Module クラスで定義されたメソッドだから、 Module クラスのインスタンスに対してでしか呼び出せないはずです。 Test クラスの定義内で、 なぜ bar メソッドが呼べるんでしょう・・・?

ん、 そもそも、 Module クラスって何なんでしょうか? 確か、 クラスのクラスみたいな存在だったはず・・・。

p Test.class  #=> Class

あれ・・・? あ、 違う違う。 さらにそのスーパークラスでしたね。

p Test.class.superclass  #=> Module

よしよし。 Test が属するクラスは Class で、 その Class クラスは Module クラスを継承してるってわけですね。 ということは、 Module クラスで定義された bar メソッドは、 Class クラスのインスタンスに対して呼び出せることになります。 ん、 じゃ、 Test クラスの定義内で呼び出された bar メソッドのレシーバは、 Class クラスのインスタンスでなければならないはず・・・。 クラスの定義内の self のクラスを調べてみましょう。

class Test
  def foo
    puts("foo in Test")
  end
  p self                 # => Test
  p self.class           # => Class
end

予想通り! でも、 メソッド定義の内部だと・・・?

class Test
  def foo
    puts("foo in Test")
    p self               # => #<Test:0x1567908>
    p self.class         # => Test
  end
end
Test.new.foo

・・・そりゃそうですよねぇ。 これでかなり掴めてきました。 クラス定義内でメソッド定義外では、 self がそのクラスそのものになり、 メソッド定義内になると、 self はそのクラスのインスタンスになります。 と、 こういう感じですね。

これが分かると少し気になることがあります。 インスタンス変数のゲッタやセッタを定義するときに attr_reader :hoge とか attr_accessor :huga とか書きますが、 これってもしかして Module クラスのメソッドなのでは・・・? 早速調べてみます。

p Module.methods.include?(:attr_accessor)  #=> false

あれ、 違う・・・? どういうこと? じゃ、 Module クラスのインスタンス作って、 attr_accessor メソッドを呼んでみましょう。

p Module.new.attr_accessor  #=> private method `attr_accessor' called for #<Module:0x14876f4> (NoMethodError)

ははーん。 private だったんですねぇ。 なるほどなるほどー。 ということは・・・?

p Module.private_methods.include?(:attr_accessor)  #=> true

やっぱりやっぱり! あー、 これですっきりしました。 つまり、 Module クラスで attr_accessor メソッドが定義されてるわけですね! ということは、 attr_accessor ってのは予約語でもなんでもなかったということです。 たいていの IDE が attr_accessor を予約語っぽくハイライトしてたから、 勘違いしてましたよ。

もう、 途中で 「Class」 とか 「Module」 ってのが、 クラスを表してるのか、 Module クラスのインスタンスを表してるのか、 頭がごちゃごちゃになりました。 何か不思議ですねぇ・・・、 Ruby の Class の世界。


comment ×0
12 / 23
Mon

本屋で買った本が重くて腕が痛い Ziphil です。

Kotlin で書いたコードを JRuby に移植して、 これからの開発は Kotlin にしようかな JRuby にしようかなー、 な状態なんですが、 JRuby への移植は機械的に行っただけなので、 Ruby っぽくないというか、 美しくないというか、 そんなところが結構あるんですよね。 さっきコードを眺めてて気になったのがこの処理。

def actual_power
  power = 0
  for i in 1..@roll
    power += rand(@power) + 1
  end
  power += @addition
  return power
end

武器で攻撃したときにどの程度威力が出るかを計算する部分です。 計算の説明は前のエントリーにあるので省略するとして、 このコード、 何かスッキリしてませんねぇ。 というか、 for 文の変数 i、 一度も使ってませんし。

Ruby っぽい書き方かどうかは分かりませんが、 実はこんなスマートに書けます。

def actual_power
  return Array.new(@roll){rand(@power) + 1}.inject{|a, b| a + b} + @addition
end

・・・なんと 1 行。 ちなみに、 inject{|a, b| a + b} はもっと短く inject(:+) と書けます。 こっちは端的ですが、 いまいち何やってるのか分かりにくいので、 私はあんまり使いません。

いやー、 Ruby のスローガンが 「Enjoy Programming」 なだけあって、 Ruby でのコーディングは楽しいです。 工夫のしがいがあるというか、 可能性無限大な感じです。


12/23 コードがスマートになったのは良いんですが、 よくよく考えると Array インスタンスを作るわけだから、 余計に時間がかかる気がする・・・。 ということで、 10 万回の実行速度を計測してみました。 結果がこれ。

              user     system      total        real
before:   0.561000   0.000000   0.561000 (  0.555000)
after:    0.734000   0.000000   0.734000 (  0.726000)

上が最初のコードで、 下が変更後のスマートなコードです。 変更後の方が若干遅いですね。 といっても、 10 万回の実行結果ですし、 このメソッドを 10 万回も一度に実行することはないですから、 それほど気にする程のことでもないでしょうけど。 いや、 「塵も積もれば山となる」 でしょうか・・・?


comment ×0
12 / 23
Mon

間違えて 5 時に起きてしまった Ziphil です。

もともと私が Rubyist だったということもあって、 JRuby を導入してみました。 およそ 4 時間くらいかけて、 Kotlin で書かれているプログラムを JRuby に移植して、 早速実行! 動いた! Ruby は動的言語なので、 十分な速度が出るかどうか不安でしたが、 実用可能レベルでした。 Java とか Kotlin とかよりは少し遅いけど。

ちょっと JRuby のコードを見てましょう。

def draw_tilemap(tilemap, cx, cy, width, height, mode, observer)
  previous_color = self.color
  previous_font = self.font
  images = tilemap.images
  for x in 0...width
    for y in 0..height
      if tilemap.contain?(x + cx, y + cy)
        data = tilemap[x + cx, y + cy]
        if mode == 0 || (mode == 1 && tilemap.wall?(x + cx, y + cy)) || (mode == 2 && tilemap.floor?(x + cx, y + cy))
          if images.key?(data)
            if tilemap.autotile?(x + cx, y + cy)
              numbers = tilemap.autotile_number(x + cx, y + cy)
              numbers.each_with_index do |number, i|
                draw_image(images[data],
                           24 * x + i % 2 * 12, 24 * y + i / 2 * 12 - 12, 24 * x + i % 2 * 12 + 12, 24 * y + i / 2 * 12,
                           number % 4 * 12, number / 4 * 12, number % 4 * 12 + 12, number / 4 * 12 + 12,
                           observer)
              end
            else
              draw_image(images[data], 24 * x, 24 * y, observer)
            end
          else
            self.color = Color.new(68, 17, 17)
            fill_rect(24 * x, 24 * y, 24, 24)
            self.color = Color.new(102, 51, 51)
            draw_line(24 * x, 24 * y, 24 * x + 23, 24 * y + 23)
            draw_line(24 * x + 23, 24 * y, 24 * x, 24 * y + 23)
            self.color = Color.new(187, 136, 136)
            self.font = Font.new(self.font.font_name, 0, 9)
            draw_string(data.to_s, 24 * x + 2, 24 * y + 22)
          end
        end
      end
    end
  end
  self.color = previous_color
  self.font = previous_font
end

RPG では欠かせないマップの描画を行う部分のコードです。 getColor(newColor) とするところを color = new_color と、 代入文のように書けるのとか、 スマートでかなり良いです。 余分なカッコもなくなるので、 コードが見やすくなります。 ただし、 Ruby (JRuby) は動的型付けなので、 静的型付けの Kotlin などに比べて安全性は落ちます。

さて、 1 つだけ困った点があったので、 書いておきます。 以下のコードです。

class MainPanel < JPanel 
  def paint_component(graphics)
    super
    # 処理
  end
end

関係ないところは省いています。 JPanel クラスを継承した MainPanel クラスを作って、 paint_component メソッドをオーバーライドしました。 ちなみに、 JRuby は Java のキャメルケース (paintComponent みたいな) のメソッド名に対して、 スネークケース (paint_component みたいな) の Ruby らしい名前のメソッドを自動的に定義してくれます。 で、 これを実行してみると、 repaint メソッドを読んでも paint_component メソッドが呼ばれない。 おかしいなぁ・・・。

ということで調べてみると、 どうやらオーバーライドはキャメルケースのメソッド名で行わないといけないらしいです。 まあ、 そうすれば良いんですが、 キャメルケースのメソッド名は Ruby の慣習に反しますし、 キャメルケースとスネークケースが混ざるのが美しくない。 ということで、 良い感じに書けるように補助メソッドを作成してみました。

class String
  def camel_case
    name = split("_")
    ([name.first] + name[1, name.size - 1].map{|i| i.capitalize}).join
  end
end
class Module
  def def_java(*names)
    names.each do |name|
      class_eval("alias :#{name.to_s.camel_case} :#{name} ")
    end
  end
end

String クラスに、 スネークケースをキャメルケースに変換する camel_case メソッドを追加し、 さらに Module クラスに def_java メソッドを追加します。 こうすると、 こんな風に書くことで、 キャメルケースのメソッドが作られ、 オーバーライドが成功します。

class MainPanel < JPanel 
  def paint_component(graphics)
    super
    # 処理
  end
  def_java :paint_component
end

いちいち追加するのは面倒ですが、 途中でキャメルケースが混ざるよりも Ruby らしいコードが書けるような気がします。

さーて、 これで StarRuby とか Ruby/SDL に頼らなくてもゲームが作れるぞー。


comment ×0
12 / 20
Fri

インフルエンザの予防接種で肩が痛い Ziphil です。

せっかく Kotlin 慣れてきたー、 なのに、 Ceylon という新しい JVM 言語をやり始めています。 RPG を作る言語を選ぶときに、 JVM 言語を 10 個くらい試したんですが、 そのときにこの Ceylon もかじってました。 概略とかを見た第一印象が 「複雑そう」 だったので、 Ceylon はやめて Kotlin にしたわけです。 ・・・が、 最近 Ceylon についていろいろ調べてみると、 結構良い感じだったんですよ。

ということで、 Ceylon 環境を構築しているところです。 IntelliJ IDEA のプラグインはないみたいなので、 Eclipse を入れています。 でも私は IDEA の方が好きです。

あー、 新しい環境にするとセットアップが面倒なんですよねー。 私の場合、 細かいところが気になってこだわっちゃうので、 環境構築だけに 2 時間くらいかかるんですよねー。 主にコードの配色の設定とか。

まあ、 環境が整ったら、 しばらく Ceylon と戯れて、 今後の RPG 開発で使うかどうか決めます。


comment ×0
12 / 19
Thu

Ziphil じゃないときがあるはずないのに、 毎回名乗っている Ziphil です。

前のエントリーで、 Kotlin のアクセス修飾子について触れました。 そこで internal は 「モジュール内で可視」 という意味だと言ったんですが、 「モジュール」 って何やねんという話なので、 ちょっと調べてみました。

さて、 ここに説明がありました。

モジュールは、 Kotlin におけるコンパイル時の一単位です。 本質的には、 モジュールはビルドスクリプトとして表現されます。 モジュールそのもの, そのモジュールの従属関係, そのモジュールを構築するためのコンパイラのオプションなど、 これらを構成するソースファイルに関する情報を伝えるスクリプトは、 プログラム内で 「モジュール記述子」 というものを構築します。 コンパイルの一単位であるということは、 解析や最適化の全てがモジュールに従って行われるということであり、 バイナリが両立可能かどうかに関する問題が、 モジュール内でしか起こらないということでもあります。

(´・ω・`)? つまりどういうことですか?

いまいちよく分からないのが現状です・・・。 私の推測でしかありませんが、 クラスを統括するのがパッケージで、 パッケージを統括するのがモジュール、 みたいな感じでしょうか。

というか、 プログラミング関連の英語の専門用語の知識がなさ過ぎて、 英語読めても全然意味分からないです。


comment ×0
12 / 19
Thu

Kotlin Advenent Calender 2013 に勢いで参加してしまった Ziphil です。

19 日目のエントリーになります。 せっかく Kotlin について何か書くんだし、 Kotlin じゃないとできないようなことについて書きたかったんですが・・・、 いまいち思いつきませんでした! ・・・ということで、 12 月 6 日にリリースされた Kotlin M6.2 での新機能、 末尾再帰最適化についてもう少し詳しくまとめてみようと思います。 少し詳しめに書いたので、 もともとこれについて知ってる人は、 特に得るものはないかもしれません・・・。

さて、 「末尾再帰」 とは、 とあるサブルーチン内の最後の命令として、 他のサブルーチンが呼ばれることです。 つまりは、 こんな感じのコードですね!

fun fibonacci(n: Int, a: Int = 0, b: Int = 1): Int {
  if (n < 1) {
    return a
  }
  return fibonacci(n - 1, b, a + b)
}

フィボナッチ数を求めるコードでーす。 if 文で場合分けされているものの、 関数 fibonacci の 1 回分で最後に実行されるのは、 関数 fibonacci そのものになっています。 関数型言語なんか (Scala とか) では、 こういう書き方の方が好まれますね!

で、 この末尾再帰にはちょっとした問題があるんですが・・・。 例として、 fibonacci(4) を考えてみましょうか。 Kotlin は、 4 番目のフィボナッチ数を、 こんな感じで順に計算します。 ・・・あ、 計算するのは JVM ですけど、 Kotlin が計算してるって考えた方がかわいいですよね!

  • fibonacci(4)
  • fibonacci(3, 1, 1)
  • fibonacci(2, 1, 2)
  • fibonacci(1, 2, 3)
  • fibonacci(0, 3, 5)
  • 3

さて、 こんな感じでようやく 3 が得られます。 ちょっとした問題というのは、 この計算の中に潜んでいます。

fibonacci(4) が呼ばれると、 Kotlin は fibonacci(3, 1, 1) を返そうとしますが、 この値は分かっていません。 そこで、 Kotlin は 「fibonacci(3, 1, 1) の値を計算し終わったら、 その値を関数の返り値として返すぞー」 ということを覚えておいて、 fibonacci(3, 1, 1) の値を求めにいきます。 すると、 今度はその結果は fibonacci(2, 1, 2) で、 これも値が分かっていないので、 Kotlin はまた 「fibonacci(2, 1, 2) の値が分かったら、 それを返すぞー」 と覚えておきます。

とまあ、 こんな風に、 再帰的に fibonacci が呼ばれるたびに、 Kotlin は 「あれを求めた結果を返そう」 と頭に覚えるわけですが、 fibonacci(100) を実行しようと言われちゃったら、 もう頭がパンパンになって破裂しちゃうわけですよ。 ちなみに、 こういうのを 「スタックオーバーフロー」 と言ったり言わなかったり・・・。 とにかく、 困りますねー。

そこで、 M6.2 から新しく実装された 「末尾再帰最適化」 が便利なんですね。 これによって、 Kotlin が頭の中に覚えておくべき内容が減って、 fibonacci(100) でも楽々計算できるようになるわけです。 Kotlin がより賢くなるのです。 やったね!

末尾再帰最適化の使い方はこうです。

tailRecursive fun fibonacci(n: Int, a: Int = 0, b: Int = 1): Int {
  if (n < 1) {
    return a
  }
  return fibonacci(n - 1, b, a + b)
}

はい、 アノテーション tailRecursive をつけるだけ! 簡単でしょ?

これで本当に頭がパンパンにならずに計算できるようになったのかなぁ? ・・・と疑いの目を向けている方もいるかもしれませんね。 じゃ、 コンパイルされたバイトコードを逆コンパイルしてみましょう。 どうなってるでしょうか。

まずは、 tailRecursive アノテーションをつけず、 最適化をしなかった場合のバイトコードです。 ちなみに、 デフォルト引数の処理は別の関数を介しているみたいで、 その部分は省略したので、 下のコードはデフォルト引数の情報がなくなってます。 あ、 それと、 読みやすいように多少コードを整形してあります。

public static final int fibonacci(int n, int a, int b) {
  if (n < 1) {
    return a;
  } else {
    return fibonacci(n - 1, b, a + b);
  }
}

・・・見事にそのまんまですね! まあ、 そりゃそうなんですけど。

じゃ、 次に tailRecursive アノテーションをつけて、 最適化をした場合のバイトコードです。 こんな感じー。

public static final int fibonacci(int n, int a, int b) {
  do {
    if (n < 1) {
      return a;
    }
    b = a + b;
    a = b;
    n = n - 1;
  } while (true);
}

お? do ~ while ループが入ってますねー。 これによって、 「これを計算したらこれを返す」 とかいう無駄な記憶をせずに、 単にループをこなすだけでよくなるわけです。

ちなみに、 末尾再帰最適化をすると、 使用するスタックの量を節約できるだけでなく、 速度も向上するようです。 最適化をする場合としない場合とで、 50 番目のフィボナッチ数を計算してみると、 私の環境では最適化をした方が 40 倍も速いことが分かりました。

ところで、 疑問に思った方もいるんじゃないでしょうか? 末尾再帰してる関数があったら、 Kotlin が自動的に最適化してくれれば良いのにー、 とか。 いちいち tailRecursive とか面倒だよー、 とか。 公式ブログにちゃんと説明が書いてありました。

デバッグのためです。 末尾再帰が最適化された関数では、 実際に再帰呼び出しがされるわけではないので、 デバッガによって、 再帰されていることを示すスタックフレームが残されず、 再帰の前段階におけるローカル変数について詳しく調べることができなくなります。 したがって私たちは、 このことに対する最も普通な解決策は、 それをコード内で明示的に行うことだと思っています。

それともう 1 つ。

安全性のためです。 皆さんがよく知っているように、 コードというものは、 行うだろうと予想される処理を行わないことがありますよね (≧∇≦)。 同じことが末尾再帰に対しても成り立ち、 末尾再帰のような関数呼び出しが、 実はそうでなかったということもよくあります。 これによって、 最適化がなされずパフォーマンスの向上が妥協されてしまいます。 しかし、 tailRecursive アノテーションによって、 コンパイラは、 どの関数呼び出しが最適化されるべきか分かり、 間違いがあった場合は警告を発することができるのです。

・・・ということで、 アノテーションは省略できないようになったわけですね。

さて、 こんな感じで、 Kotlin の末尾再帰最適化について書いてみましたー。 Kotlin を知ったのが最近であるという上に、 この最適化処理を知ったのも最近なので、 至らない部分など多いと思いますが、 温かい目で見守ってください・・・。


comment ×0
12 / 17
Tue

最近寒くなったと感じる Ziphil です。

Kotlin は Java に比べてコードが短くなるという話なので、 Kotlin 初心者ながらも、 コードゴルフに挑戦してみました。 テーマは 1 から 100 までの FizzBuzz です。 なお、 FizzBuzz の結果は標準出力に表示するものとして、 fun main(args: Array<String>) とかを除いた、 処理部分だけを短くします。 それと、 標準ライブラリ以外はインポートしないものとします。

さて、 まずは何も気にせず普通にコードを書いてみましょうー!

for (i in 1..100) {
  if (i % 15 == 0) {
    println("FizzBuzz")
  } else if (i % 3 == 0) {
    println("Fizz")
  } else if (i % 5 == 0) {
    println("Buzz")
  } else {
    println(i)
  }
}

200 Byte です。 これをこれから短くしていきます! まず、 for 文は in やその前後のスペースとかで文字数を稼いでしまっているので、 代わりに forEach を使ってみます。 ついでに、 不要なスペースやカッコを除去します。

(1..100).forEach{if(it%15==0)println("FizzBuzz")else if(it%3==0)println("Fizz")else if(it%5==0)println("Buzz")else println(it)}

127 Byte です。 さて、 コードゴルフでは、 同じものが繰り返されているは良くないと言われていますね。 コードを見てみると、 else if とか else が何個もあって文字数を稼いでいるので、 これを何とかして消したいものです。 そこで、 when 文を使ってみます。 Kotlin の when 文は、 単に if ~ else if の連続を見やすく書き直すことにも使われます。

(1..100).forEach{when{it%15==0->println("FizzBuzz");it%3==0->println("Fizz");it%5==0->println("Buzz");else->println(it)}}

121 Byte です。 さて、 println もたくさんありますから、 これも 1 つにまとめちゃいましょう!

(1..100).forEach{println(when{it%15==0->"FizzBuzz";it%3==0->"Fizz";it%5==0->"Buzz";else->it})}

93 Byte です。 100 Byte を切りましたが、 ここからが難しいんです・・・。 まず、 剰余算の返り値は必ず 0 以上の整数なので、 == 0< 1 に置き換えて、 悪あがきします。

(1..100).forEach{println(when{it%15<1->"FizzBuzz";it%3<1->"Fizz";it%5<1->"Buzz";else->it})}

91 Byte になりました。 うー・・・。 限界ですかねぇ・・・。 FizzBuzz が 2 回出てくるので、 これをそれぞれ 1 回ずつにしたいところですが・・・。 そこで、 Fizz と Buzz の表示判定をそれぞれ別々に行ってみましょう。

(1..100).forEach{println(when{it%3<1->"Fizz";else->""}+when{it%5<1->"Buzz";else->""})}

これだと 3 の倍数でも 5 の倍数でもない場合に数字が表示できませんね・・・。 だったら、 最後に数字をつけ足せばいいじゃない。

(1..100).forEach{println(when{it%3<1->"Fizz";else->""}+when{it%5<1->"Buzz";else->""}+"${it}")}

・・・いやいや、 これだと Fizz とかを表示する場合も数字が表示されちゃいます。 だったら、 Fizz とか Buzz が表示される場合は数字を消せば良いじゃない。

(1..100).forEach{println((when{it%3<1->"Fizz";else->""}+when{it%5<1->"Buzz";else->""}+"${it}").replaceAll("z\\d+","z"))}

120 Byte です。 いや、 増えてるじゃないですか!! ・・・んー、 ということで、 何か使える関数がないか、 Kotlin の API を眺めてみると・・・、 drop ってのがありました! これを使うと、 指定した文字数分だけ最初から取り除いた文字列が得られます。 これで when 文が消せるんじゃないか・・・?

とりあえず、 Fizz の表示判定を考えてみます。 it が 3 の倍数のとき 0 になり、 それ以外なら 4 になるような計算式があれば、 それを drop の引数にすれば、 うまくいきそうです。 できるのか・・・?

考えた結果、 導き出された式は it % 3 * 4 です。 3 の倍数でないとき 4 じゃなきゃいけないわけじゃないんです。 要は 「Fizz」 って文字列を全部消したいだけですから、 4 以上なら何でも良いわけです。 ということで、 書き直します。

(1..100).forEach{println(("Fizz".drop(it%3*4)+"Buzz".drop(it%5*4)+"${it}").replaceAll("z\\d+","z"))}

100 Byte です。 うわ、 短くなってないですねー・・・。 "Fizz".drop(it%3*4) という発想は良かったかもしれませんが、 やっぱり replaceAll 関数が文字数取ってますね・・・。

結局、 私には 91 Byte が限界でした。 最後の drop の発想は良かったと思うんですけどねー。 substring も使えそうなんですが、 そもそも関数名が長いから乱用できませんし。

コードゴルフ、 考えるのは楽しいですけど難しいですね。 80 Byte くらいにはなりそうですが、 良い方法が思いつきません。 皆さんも考えてみてはどうでしょうか?


12/17・・・が、 Twitter でコードゴルフをやってみたということを呟いたら、 @ngsw_taro さんからさらに短くなったコードをいただきました。

(1..100)map{a->println(when{a%15<1->"FizzBuzz";a%5<1->"Buzz";a%3<1->"Fizz";else->a})}

85 Byte です。 forEach にする必要がなかったというのは盲点でしたね。


12/27・・・これが最短かなーとか思っていたら、 @ayato_p さんから指摘が。

1..100map{a->println(when{a%15<1->"FizzBuzz";a%5<1->"Buzz";a%3<1->"Fizz";else->a})}

83 Byte になりました。 カッコいらないんですねー・・・。


comment ×0
12 / 14
Sat

腹痛が痛い Ziphil です。

綺麗なコードが書けない。 動くコードはかけるが、 綺麗なコードが書けない。 納得のいくコードが書けない。 モチベーションが下がる。 テンションが下がる。

・・・そんなわけで、 ゲーム製作が進んでおりません。 いや、 言い訳です。 良いコードがかけないのも事実ですが、 製作が進まないのは時間がないだけです。

Ruby は綺麗なコード、 少なくとも自分が納得のいくコードが書けて、 すごく気に入ってたんですが、 やっぱりスクリプト言語なだけあって、 速度が出ないんですよね。 実は、 Java (Kotlin) でゲームを作り始めて、 ゲーム起動後の CPU 使用率が起動前と比べて 10% しか違わない上に、 1 フレーム (FPS 40) の待機時間がほとんど丸々 25 ミリ秒だったりするのに、 昔は驚きました。 Ruby だと、 こんなに速く処理できませんでしたからね。 Ruby 2.0 がリリースされてから一度も触れてないんですが、 速度の方は向上したんでしょうか。

ちなみに、 Java を捨てて Kotlin を始めたのは、 クロージャや拡張関数があるってのも大きいんですけど、 一番の理由はコードが綺麗に見えたからです。 たぶん、 他人には分からないと思うので、 ここで詳しく述べたりはしませんが、 とにかく綺麗なんですよ。 Scala も好きでしたけど、 あれはちょっと複雑だったので、 結局 Kotlin になりました。

にしても、 Kotlin の日本における知名度、 まだ低いですねぇ・・・。 そもそも、 日本語で書かれた Web ページが少ないですから、 仕方ないといえば仕方ないですが。 日本語で書かれた Web ページが少ない、 つまり日本人が Kotlin を使いにくく感じる、 つまり日本語で書かれた情報が増えない、 つまり日本人が Kotlin を使わない、 みたいな悪循環?

だったら、 私がやれば良いんじゃないか・・・? 私が日本語の文献を増やせばいいんじゃ・・・? 英語もそれなりに読めるわけですし。 うーん・・・。


comment ×0
12 / 12
Thu

夜に寝る気が湧かない Ziphil です。

Kotlin のアノテーションについて調べてたら、 こんなコードが。

import org.junit.Test 
import org.junit.Assert.* 
class Tests { 
  test fun simple() { 
    assertEquals(42, getTheAnswer()) 
  } 
}

メソッド名に 「the」 なんて冠詞がついてるのが奇妙だなー、 とか思っていたら、 その隣に 「42」 という数字が。 はい、 かの有名な 「生命, 宇宙, そして万物についての究極の疑問の答え」 ですね。 結構ネタとして使われるんだなー、 と感動。 ・・・それだけです。


comment ×0
12 / 08
Sun

「blockquote」 を打とうとするとたいてい 「blocuqote」 になってしまう Ziphil です。

この記事でゲッタとセッタに関するエラーについて書きましたが、 気になったので Kotlin のフォーラムで質問してみました。 するとこんな答えが。

プロパティ foo に対する getFoo, setFoo メソッドは、 あなたがおっしゃる通り、Java との連携のために生成されています。

・・・ということで、 思った通りでした。

非常に古い要望 (KT-1) に、 JVM と同じ名前をもつ関数の定義を禁じてほしいというものがありました。 また、 この場合に対して、 新しい要望 (KT-4287) をしておきました。

うーん・・・。 やっぱり getFoo, setFoo みたいなメソッドの定義は推奨されないようですし、 おそらく禁止されるでしょう。 まあ、 そりゃそうですけどね、 冗長ですし。

Java との一貫性は諦めて、 Kotlin の機能を利用しましょうかねぇ・・・。


comment ×0
12 / 08
Sun

視力が 0.03 の Ziphil です。

IntelliJ IDEA 13 と Kotlin M6.2 がリリースされてましたね。 ということで、 Kotlin M6.2 の新機能を調べてみました。

関数型プログラミング好きの人に良いお知らせです。 Kotlin は末尾再帰最適化 (Tail Call Optimization, TCO) に対応しました。 これによって、 スタック領域を使いすぎる心配をすることなく、 関数型的なコードを書けるようになりました。

・・・なるほど。 で、 「末尾再帰最適化」 というのは何なのか調べてみると、 再帰的に関数を呼び出すような関数を効率良く実行できるようにすることらしいです。

知られている通り、 Kotlin は型に非常に厳密で、 数値型でさえも暗黙に型変換されるのが許されていません。 これは、 全ての型をクラスとして同様に定義し、 ときどき Java によって作られる奇妙なコードを避けるために、 不可欠なものです。 幸いにも、 Kotlin には定数表現に関する機能が組み込まれているため、 これによって多少不便になるような部分を、 ほとんど除くことができます。 今回のアップデートで、 この機能が完成され、 val x: Long = -1val x: Byte = -1 のように書くことができるようになりました。 より詳しく言えば、 コンパイラが定数表現を計算し、 その定数が予期されている (Long や Byte といった) 型に対応できるかどうか調べ、 定数を変換する、 ということが内部で起こっています。

確かに、 Int 型以外の数値の変数を初期化するとき、 val x: Long = 1.toLong() と書かなければいけなくて、 少し面倒でしたね。 今回のアップデートで、 型変換を自分でやる必要がなくなったわけです。

また、 よく知られている接尾辞 「L」 を数値につけることができるようになりました。 なお、 Long 型に対する接尾辞 「l」 は、 この文字が多くのフォントで 「1」 と良く似ているということで有名なため、 使うことが許されていません。 同様に、 Float 型に対し接尾辞 「F」 を使えるようになりました。 「f」 はどの数字にも似ていないし、 けっこう良い感じに見えるので、 こちらは使うことは禁止されていません。

Java にもあった、 型を示す接尾辞が実装されたようです。 「1」 と似てるからといって 「l」 を禁止する必要はなかった気もしますが、 見やすいコードを書かせるためでしょうかね。

M6.2 での主なアップデートはこの 2 つでしょうか。 これ以外にも Java との連携などに関する新機能がいくつかありますが、 ここで詳しくは説明せず、 箇条書きにとどめておきます。 詳細は、 公式ブログを見てください。

  • Java で @ReadOnly アノテーションをつけることで、 Kotlin ではイミュータブルな配列にすることができるようになった。
  • Kotlin のコードをコンパイルすると、 バイトコードに @Nullable と @NotNull が自動的につけられるようになった。
  • Android SDK 用のアノテーションが追加された。
  • JavaScript への変換が改良された。

これに合わせて、 IDEA 13 の方もアップデートされていて、 コード保管などが改良されているみたいです。


comment ×0
12 / 05
Thu

紙で中指を結構深く切ってしまった Ziphil です。

前のエントリーの続きです。 Kotlin のプロパティの概念は素晴らしいと思うんですが、 これを使うと Java との統一感が失われてしまいます。 ということで、 Java の get, set で始まるメソッドを、 Kotlin のプロパティのゲッタとセッタの呼び出しのように書けるようになれば、 統一感もありますし、 コードも綺麗になります。 ついでに、 引数のないメソッドはカッコを省略できるようにもしてほしいですね。 つまり、 こういうことです。

// 従来の書き方
buffer.setFont(Font("sans-serif", 0, 12))
buffer.setColor(Color(0xFF, 0xFF, 0xFF))
val y: Int = buffer.getFontMetrics()!!.getAscent() * 2 / 3 + 5
// 提案する書き方
buffer.font = Font("sans-serif", 0, 12)
buffer.color = Color(0xFF, 0xFF, 0xFF)
val y: Int = buffer.fontMetrics!!.ascent * 2 / 3 + 5

・・・と思っていましたが、 同じことがここですでに提言されてました。 Kotlin 製作者の応答はこんな感じです。

あなたの提言にはかなりの微妙な点があります。 Kotlin は、 強い静的型付け言語であるという点 Groovy との大きく異なっているので、 厳密にものごとを考えなくてはなりません。 例えば、 もし何らかのクラスから name と getName の両方のメソッドを継承したとしたら、 そのプログラムはどう動くべきでしょうか?

・・・はい、 ごもっともです。 しかし、 name メソッドが呼ばれた場合、 name という名前のメソッドが可視ならそれを実行し、 不可視なら getName メソッドを実行しようとするようにすれば、 問題はない気がするんですが・・・。


comment ×0
12 / 05
Thu

Ziphil です。

また Kotlin の謎の挙動に遭遇したので、 メモしておきます。

どうやら、 1 つのクラスに、 例えばプロパティ foo とメソッド getFoo を両方定義すると、 コンパイルは通りますが、 実行時に ClassFormatError が投げられるようです。 原因は不明ですが、 おそらく Java のバイトコードを生成する際に、 内部で getFoo を定義しているのだと思います。

まあ、 Kotlin 使っているなら、 ゲッタやセッタはいちいち書かないでしょうし、 この問題に直面することはほとんどないでしょうけどね。 私の場合、 Java との一貫性を保つためにゲッタをいちいち書いていたので、 この問題にぶつかりましたが。 じゃ、 どうしていまさらこれに気づいたかというと、 これまではちょっとした諸事情で、 プロパティの変数名の最初にアンダバーをつけていたためです。 さすがにこれでは Kotlin の慣習を壊しすぎだと思い、 全コードのアンダーバーを削除して実行したら、 エラーになったわけです。 原因が分かるまで 30 分くらい悩みました。

ちょっと困ってます。 ゲッタやセッタを手動で書かずに、 Kotlin の機能を活用すれば良いんですけど、 Java 由来のクラスの get, set で始まるメソッドはそのままなので、 統一感がなくなっちゃうんですよね。


comment ×0
12 / 04
Wed

正常稼動には最低 7 時間の睡眠が必要な Ziphil です。

Kotlin でプログラミングしていて、 奇妙なことに遭遇したのでまとめてみます。

Kotlin のアクセス修飾子は public, internal, protected, private の 4 つで、 デフォルトは internal です。 Java をやってる人には、 この 「internal」 ってのは初めて聞くものでしょうが、 これは 「モジュール内部でのみ可視」 を意味します。 じゃ、 その 「モジュール」 ってのは何かという話になりますが、 調べてみたんですが、 私もいまいちよく分かってません。

さて、 モジュールはおいておいて、 初め私は、 internal 以外の 3 つは Java にも存在する修飾子だから、 挙動も Java と同じかなーと思ったわけです。 ・・・が、 protected だけ違うみたいです。

open class Foo() {
  protected fun protectedFunction() {
    println("test")
  }
}
class Bar() {
  fun test() {
    Foo().protectedFunction()  // 非継承クラスから呼び出し 
  }
}
class Baz() : Foo() {
  fun test() {
    Foo().protectedFunction()  // 継承クラスから呼び出し
  }
}

Java に慣れている人にとっては、 これは正しいコードの見えるかもしれませんが、 Bar クラスの protectedFunction でコンパイルエラーになります。 どうやら、 Kotlin の protected は 「サブクラスと同ファイル内でのみ可視」 ではなく、 「サブクラスでのみ可視」 のようです。 ちなみに、 残りの private と public は、 それぞれ 「自クラスでのみ可視」 と 「全クラスから可視」 を意味し、 Java と同じです。

Kotlin はメジャーではないので、 情報が少ないのが難点ですね・・・。 日本語の情報はないに等しいです。 ちなみに、 Kotlin のアクセス修飾子については、 私が探した限り、 公式サイトには記載がありませんでした。 JetBrains のフォーラムのスレッド (これ) で見つけたくらいです。

ちなみに、 この事実は、 CharacterData というキャラクターを扱うトレイトを継承して、 PlayerData というプレイヤーを扱うクラスを作ろうとしたときに、 変数を継承しようとして気づきました。 個人的には、 Java の protected よりも Kotlin の protected の方が使い道が広くて好みです。


comment ×0
12 / 01
Sun

風邪がなかなか治ってくれない Ziphil です。

これまで真っ黒で何もなかった部分に、 プレイヤーのステータスなどを表示しました。

679_製作過程A

プレイヤーの HP, MP, SP に加えて、 ゲーム内の日時とかいろいろ表示します。 一番下の行は、 まだ何を表示するかすら決まってないので、 未完成です。

これ、 文字の位置を調整するの面倒なんですよねー。 座標を調整しては実行して、 また座標を調整しては実行して、 みたいなのを繰り返さないといけないので。 画像データから計算すれば良いんでしょうけど、 それはそれで面倒です。

ちなみに、 レイアウトの関係で、 ゲーム画面の縦の長さが 1 ピクセルだけ伸びています。 もしかすると、 アイテム表示欄の大きさとの関係で、 横の長さも 2 タイル分 (48 ピクセル) 伸びるかもしれないです。


comment ×0
back-to-top
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。