nature of code:今日の練習「木(L-systemを使って)」

See the Pen tree(L-system) by kanaparty (@kanaparty) on CodePen.

L-systemを使って、藻みたいな描写をする課題。
L-system - Wikipedia

フラクタル構造を管理するメカニズム。必要な要素は3つあって、

  • アルファベット
  • 公理(初期状態)
  • 規則

作ったL-systemのところはこんな感じ

//L-system
class Lsystem {
  constructor(axiom, rule) {
      this.rule = rule;
      this.sentence = axiom;
      this.generation = 0;
    }
    //次の世代の文字列を作る
  generate() {
    var nextgen = "";
    for (var i = 0; i < this.sentence.length; i++) {
      var crr = this.sentence.charAt(i);
      for (var j = 0; j < this.rule.length; j++) {
        var a = this.rule[j].getA();
        if (a === crr) {
          nextgen += this.rule[j].getB();
        } else {
          nextgen += crr;
        }
      }
    }
    this.generation++;
    this.sentence = nextgen;
  }
  getSentence() {
    return this.sentence;
  }
  getGeneration() {
    return this.generation;
  }
}

//ルール
class Rule {
  constructor(chr, sentence) {
    this.a = chr;
    this.b = sentence;
  }
  getA() {
    return this.a;
  }
  getB() {
    return this.b;
  }
}

書いていくときにはタートルグラフィックという描画フレームワークを使うのが一般的。
F G + - [ ]などは亀(ポインタ)にだす直進、回転、などの指示のこと。
今回書いたのでいうとここのぶぶん

//描写
class Turtle {
  constructor(todo, length, theta) {
    this.sentence = todo;
    this.length = length;
    this.angle = theta;
  }
  draw() {
      for (var i = 0; i < this.sentence.length; i++) {
        var chr = this.sentence.charAt(i);
        switch (chr) {
          case 'F':
            ctx.beginPath();
            ctx.moveTo(0, 0);
            ctx.lineTo(0, -this.length);
            ctx.stroke();
            ctx.closePath();
            ctx.translate(0, -this.length);
            break;
          case '+':
            ctx.rotate(this.angle);
            break;
          case '-':
            ctx.rotate(-this.angle);
            break;
          case '[':
            ctx.save();
            break;
          case ']':
            ctx.restore();
            break;
          default:
        }
      }
    }
    //長さを変更
  changeLength(ratio) {
      this.length *= ratio;
    }
    //新しい文字列を取得
  updateSentense(axiom) {
    this.sentence = axiom;
  }
}

初めて知ったLOGO言語  

LOGO - Wikipedia www.wizforest.com

ポインタを亀にみたたて動かすっていうのが面白いなぁと思ったら もともと教育のための言語なんですね。 LOGO開発者 シーモア・パパート

オブジェクト指向がタートル・グラフィックスに起源を持つことはよく知られている」 らしい。そうなんだ!

そしてこの連載がかなり面白い。また読む。

早過ぎた孤独な予言者 − @IT自分戦略研究所

nature of code:今日の練習「枝」

See the Pen tree(2) by kanaparty (@kanaparty) on CodePen.

木っぽいやつ

コッホ曲線を書いた時のようにベクトルオブジェクト(とそれをまとめるarraylist)でつくってみたのは↓ こっちは枝の長さが一定に短くなるようにしてます。

See the Pen tree by kanaparty (@kanaparty) on CodePen.

nature of code:今日の練習「コッホ曲線」

See the Pen KochLine(コッホ曲線) by kanaparty (@kanaparty) on CodePen.

これ コッホ曲線 - Wikipedia

今までは回転をさせる時、rotateでcanvasを回転させて描く、みたいなことばかりしかやっていなかったが
今回のをつくるのにあたって自作ベクトルクラスに回転させる機能を追加した。

    //回転
  rotate(angle) {
    var cos = Math.cos(angle);
    var sin = Math.sin(angle);

    var newX = this.x * cos - this.y * sin;
    var newY = this.x * sin + this.y * cos;
    this.x = newX;
    this.y = newY;
    return this;
  }

ので自作ベクトルクラスがちょっと長くなった

//ベクトル
class Vector {
  constructor(x, y) {
      this.x = x;
      this.y = y;
      return this;
    }
    //加算
  add(x, y) {
    if (x instanceof Vector) {
      this.x += x.x;
      this.y += x.y;
      return this;
    } else {
      this.x += x;
      this.y += y;
      return this;
    }
  }
  static add(vectorA, vectorB) {
      var x = vectorA.x + vectorB.x;
      var y = vectorA.y + vectorB.y;
      return new Vector(x, y);
    }
    //減算
  sub(x, y) {
    if (x instanceof Vector) {
      this.x -= x.x;
      this.y -= x.y;
      return this;
    } else {
      this.x -= x;
      this.y -= y;
      return this;
    }
  }
  static sub(vectorA, vectorB) {
      var x = vectorA.x - vectorB.x;
      var y = vectorA.y - vectorB.y;
      return new Vector(x, y);
    }
    // ベクトル乗算
  mult(n) {
    this.x = this.x * n;
    this.y = this.y * n;
    return this;
  }
    //ベクトル除算
  div(n) {
      this.x = this.x / n;
      this.y = this.y / n;
      return this;
    }
    //ベクトルの大きさを返す
  mag() {
      return Math.sqrt(this.x * this.x + this.y * this.y);
    }
    //正規化する
  normalize() {
      var size = this.mag();
      if (size === 0) {
        return this;
      }
      this.x = this.x * (1 / size);
      this.y = this.y * (1 / size);
      return this;
    }
    //最大値
  limit(max) {
      if (this.mag() > max) {
        return this.normalize().mult(max);
      } else {
        return this;
      }
    }
    //回転
  rotate(angle) {
    var cos = Math.cos(angle);
    var sin = Math.sin(angle);

    var newX = this.x * cos - this.y * sin;
    var newY = this.x * sin + this.y * cos;
    this.x = newX;
    this.y = newY;
    return this;
  }
    //ベクトルの角度を返す
  static angle(vectorA) {
      var theta = Math.atan2(vectorA.y, vectorA.x);
      return theta;
    }
    //長さ1のランダムな値を返す
  static random2D() {
      this.x = (Math.random() * 2) - 1;
      this.y = (Math.random() * 2) - 1;
      return this.normalize();
    }
    //角度から長さ1のベクトルを返す
  static fromAngle(angle) {
      return new Vector(Math.cos(angle), Math.sin(angle));
    }
    //同じ値をもったVectorを返す
  static copy(vectorA) {
      return new Vector(vectorA.x, vectorA.y);
    }
    //ベクトル内積
  static dot(vectorA, vectorB) {
      return vectorA.x * vectorB.x + vectorA.y * vectorB.y;
    }
    //ベクトル間の角度を返す
  static angleBetween(vectorA, vectorB) {
    var theta = Math.acos((this.dot(vectorA, vectorB)) / (vectorA.mag() * vectorB.mag()));
    return theta;
  }
}

Goole app script をちょっとだけ触ったときのメモ

リファレンス https://developers.google.com/apps-script/reference/calendar/

ここにいろいろまとまっている http://libro.tuyano.com/index2?id=638001

メニューから実行させたいとき https://developers.google.com/apps-script/guides/triggers/#onopen

//メニューから実行する
function onOpen() {
  var menuEntries = [ {name: "run", functionName: "run"} ];
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  ss.addMenu("Custom Menu", menuEntries);
}

oauth1ライブラリ https://github.com/googlesamples/apps-script-oauth1

スクリプト内で保持しておきたい情報とかにはこれをつかう https://developers.google.com/apps-script/reference/properties/properties-service

var props = PropertiesService.getScriptProperties();
//取得
var hoge = props.getProperty("hoge") || "";
//設定
props.setProperty("hoge", str);

jsスケッチ 水面

See the Pen 水面 by kanaparty (@kanaparty) on CodePen.

ライフゲームのルールを少し変えると水面みたいになる!

今回のルール

次の状態を決めるルール

  • セル自身は 前の状態、今の状態、次の状態を持っている。
  • 次の状態 = 自分の周りの8個の前の状態の平均 + 今の状態 - 前の状態とする
  • もし周りの平均が255か0になっていたらその逆にする(波が収まった地点でまた波が起こるようにする)

表現のルール

  • 状態は0~255、その状態をセルの青色に適用する
//周りのセルの状態を見る
updateState() {
  var sum = 0;
  for (var i = 0; i < 8; i++) {
    sum += this.neighbours[i].state;
  }
  //周りの平均値を出す
  var average = Math.floor(sum / 8);

  if (average == 255) {
    this.nextState = 0;
  } else if (average == 0) {
    this.nextState = 255;
  } else {
    this.nextState = this.state + average - this.lastState;
    if (this.nextState > 255) {
      this.nextState = 255;
    } else if (this.nextState < 0) {
      this.nextState = 0;
    }
  }
  this.lastState = this.state;
}

その他少し悩んだこと
セルの状態をアップデートするタイミングは、セル全員が次のセルの状態が決まってから、描くときまでにしなければならない

nature of code:今日の練習「ライフゲーム」

See the Pen life game by kanaparty (@kanaparty) on CodePen.

ライフゲーム

ライフゲーム - Wikipedia 複雑系の特徴をもった セルの系

セルオートマトンのときは
一つの世代を一つの列として表現し、次の世代を下二追加していったけれど
ライフゲームのときは
2次元のセルを使って、次の世代を次のアニメーションフレームで表現するのが一般的。
そうすると細菌がシャーレのなかで成長していくような動きが楽しめる!

ルール

updateState(){
  var neighborhood = cellList.neighborhood(this.colIndex, this.rowIndex);
  var count = 0;
  for (var i = 0; i < 8; i++) {
    if(neighborhood[i].prevState === true){
      count ++ ;
    }
  }

  //セルが生きていて周りにいきているセルが1しかない→死
  if(this.prevState && count < 2){
    this.state = false;
  }
  //セルが生きていて周りに4つ以上→死
  else if(this.prevState && count > 3){
    this.state = false;
  }
  //セルが死んでいて3つだと誕生
  else if(!this.prevState && count === 3){
    this.state = true;
  }
  else{
    this.state = this.prevState;
  }
}