ux00ff

ビールとプログラミングと

トレイトと自分型を利用してPAppletを分割する

引き続きProcessingです。自分型を設定したトレイトを利用すると、トレイトを実装する側のクラスを縛ることができます。Scalaスケーラブルプログラミングに「大きなクラスをトレイトを利用して分割するときにめっちゃ便利だよ」と書いていたが確かに便利ですね。

rubyの「おっと Enumerable をミックスインしたんだけど each メソッドがないよ?」みたいなことを、こちらはコンパイラが弾いてくれるのだな的理解で先へ進みます。

以下のようなデバッグ情報を表示するトレイトを作ったとして、

trait DebugView {
  self: PApplet =>

  def showDebugView(): Unit = {
    fill(255)
    textSize(13)
    textAlign(LEFT, TOP)
    text(s"(x, y) : ($mouseX, $mouseY)", 0, 0)
    text(s"${millis} ms", 0, 15)
    text(s"${frameRate} fps", 0, 30)
    text(s"${frameCount} frame count", 0, 45)
    text(s"mouse => ($mouseButton) key => ($keyCode)", 0, 60)
  }
}

利用側はこんな感じにします。

class Applet extends PApplet with DebugView {
  override def settings(): Unit = size(320, 240, JAVA2D)

  override def draw(): Unit ={
    background(0, 0, 100)
    showDebugView()
  }
}

f:id:ux00ff:20170221235542p:plain

トレイト側で self: PApplet => しているため、この DebugViewPApplet かまたはそのサブ型からしか利用できず、その制約の中で showDebugView のメソッド内では PApplet のメソッドを呼び出すことができます。

ProcessingをScalaで書く用のgiter8テンプレート

学習も兼ねて Processing 用のプロジェクトテンプレートを作って見ました。「scala-processing g8」 で検索しても最近のものが出てこなかったのでこれはきっと需要があるのだろうと信じて(苦しい)

コードはこちらに置きました。

sbt がインストールされている状態で、以下コマンドで Processing プロジェクトを作成することができます。なお sbt は公式通り brew でインストールしました

$ sbt new ma2saka/scala-processing.g8
続きを読む

読書の春

Scalaスケーラブルプログラミング第3版、なんだかんだで読み終わるまでに四日くらいかかった。良い本でした。 やっぱり紙の方が読みやすい・・・んだけど、お風呂で読んでいたのでちょいちょいふやけていたりします。

普通にJavaからの置き換えで学習してるだけだとたどり着かないあたり、for式の書き換えの理屈や implicit の使われ方、抽象メンバとトレイトの組み合わせ(withの前に初期化ブロック置く設計とか…)、それにLISTの実装解説はテンション上がった。少しだけ言語設計者やコンパイラの気持ちになれる気がします。ただあくまでも標準のコンパイラと実行系、そしてなにより言語の本であって、周辺のエコシステム周りについての情報は全くない。こちらは別にやっていかないとだ。どっから手をつけたものかしら。

Scalaスケーラブルプログラミング第3版

通称コップ本。版を重ねるごとにコップが増えている。どうも Better Java っぽい書き方が抜けないなーと思って、買った。

第三版は2016年出版で2.11、2.12対応。

自分はだいたいプログラミング言語の基礎はオライリーの「プログラミング○○」から入るんだけど、Scalaの場合は2.7, 2.8対応版で止まっていて、ちょっと古いんですよね・・・ということでこちらをチョイス。

最初から順に読んでるけど、ところどころ気の利いた Tips が差し込まれていたり、ためになる訳注が多かったりしていい本感ある。なにより愛が溢れてる。各所から「ほらね、Scalaすごいでしょう?」っていう嫌味のないドヤ感が伝わってきて読んでいて楽しい。ざっと読んでから、ゆっくり読み直そう。

Scalaでコンウェイのライフゲーム with Processing

定番ということで、書いてみました。ライフゲームについては Wikipedia の記事がわかりやすいので参照してください。本当に Better Java (というか普通に手続き的) な書き方ができてしまうところに面白みというか味を感じます。昔はライフゲーム書くときは二次元配列を多用していたけど、最近は一次元配列の方が自然に思える。ふしぎ。

f:id:ux00ff:20170212125812p:plain

フレームレートを明示的に指定することで世代交代をちゃんと眺めることができます。普通に実行すると一瞬で安定するので面白くありません。

シンプル版

import processing.core.PApplet
import processing.core.PConstants._

class App extends PApplet {
  private[this] val CELL_SIZE = 10
  private[this] val W = 50
  private[this] val H = 50
  private[this] val arr = new Array[Boolean](W * H)
  private[this] val tmp_arr = new Array[Boolean](W * H)

  override def settings(): Unit = {
    size(W * CELL_SIZE, H * CELL_SIZE, JAVA2D)
  }

  override def setup(): Unit = {
    frameRate(5)
    fill(60)
  }

  override def mousePressed(): Unit = {
    for (x <- 0 to W * H - 1) {
      arr(x) = if (random(1.0f) < 0.5f) {
        true
      } else {
        false
      }
    }
  }

  override def draw(): Unit = {
    background(200)
    write_lines()
    update_cells()
    write_cells()
  }

  private[this] def write_lines() = {
    for (x <- 0 to W * CELL_SIZE by CELL_SIZE) line(x, 0, x, height)
    for (y <- 0 to H * CELL_SIZE by CELL_SIZE) line(0, y, width, y)
  }

  private[this] def update_cells(): Unit = {
    for (i <- 0 to W * H - 1) {
      var c = 0
      // 左側
      if (i % W > 0 && arr(i - 1)) {
        c += 1
      }

      // 右側
      if (i % W != W - 1 && arr(i + 1)) {
        c += 1
      }

      // 上、右上、左上
      if (i / W > 0) {
        if (arr(i - W)) c += 1
        if (i % W != W - 1 && arr(i + 1 - W)) c += 1
        if (i % W > 0 && arr(i - 1 - W)) c += 1
      }

      // 下、左下、右下
      if (i / W < H - 1) {
        if (arr(i + W)) c += 1
        if (i % W != W - 1 && arr(i + 1 + W)) c += 1
        if (i % W > 0 && arr(i - 1 + W)) c += 1
      }

      // 生存判定
      if (arr(i) && (c == 2 || c == 3)) {
        tmp_arr(i) = true
      } else if (arr(i)) {
        tmp_arr(i) = false
      } else if (c == 3) {
        tmp_arr(i) = true
      } else {
        tmp_arr(i) = false
      }
    }

    tmp_arr.copyToArray(arr)
  }

  private[this] def write_cells(): Unit = {
    for (i <- 0 to W * H - 1) {
      val y = i / W
      val x = i % W
      if (arr(i)) {
        rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE)
      }
    }
  }
}

こいつをScalaっぽく書き直すのはまたこんど。

続きを読む

文字を画像化してピクセルデータを利用する

もともと文字の形状を扱いたかったのですが、まずはピクセルベースでの処理を試そうと思い、 OpenProcessing に公開されている「create ‘webby’ numbers and letters」を参考に Scala に手元で書き直してみました。

www.openprocessing.org

こういうやつです。

f:id:ux00ff:20170211114014p:plain

PFont

createFont メソッドを用いて PFont を作成するのが手っ取り早いのですが、このやり方だとシステムにあるフォントしか利用できません。

ポータブルなアプリケーションを目指す場合、.vlw ファイルを作成し、アプリケーションと一緒に配布して loadFontメソッドを用いて読み込むようにします。

Loads a .vlw formatted font into a PFont object. Create a .vlw font by selecting “Create Font…” from the Tools menu. This tool creates a texture for each alphanumeric character and then adds them as a .vlw file to the current sketch’s data folder. Because the letters are defined as textures (and not vector data) the size at which the fonts are created must be considered in relation to the size at which they are drawn.

と、あるようにvlwファイルはベクターデータだけでなく指定サイズまでのテクスチャも同時に生成してくれています。含める文字を「一般的な文字」にするか「全てのUnicode文字」にするかでだいぶサイズが違います。

f:id:ux00ff:20170211112808p:plain

手元で動かすぶんには createFont が手軽なのでこっちを使っています。

移植してみた

結果はこちら。少し長くなってしまった。コードはGistにも置いてあります。

続きを読む

PAppletはインターフェイスPConstantsの実装である

えっ? というか PConstants ってインターフェイスだったの?

f:id:ux00ff:20170210123751p:plain

驚いたというかこれは完全に思いこみがあった。つまり、これまで以下のように書いていたところは、

import processing.core.PApplet
import processing.core.PConstants._

これでもいいってことになるよね。

import processing.core.PApplet
import processing.core.PApplet._

というか PApplet#println を利用していたつもりだった箇所は実はscala.Predef#println を呼んでいたということである。なんてこった。

なんてこった、とびっくりはしたけどよくよく考えて見ると PApplet#cos とか PApplet#map とかを気がつかないうちに呼んでいるより、あくまで定数だけをインポートしたいわけなので、PConstants._ をインポートする方が結果的には見通し良さそうだ。だからまあ、あまり気にしない方向でいきます。