箱玉系をProcessingで実装する

[明治大学総合数理AdventCalender2017](https://qiita.com/advent-calendar/2017/meiji-ims)も1週間を越えました。長いですね。。

本稿では[前回「箱玉系について」](https://qiita.com/massss/items/1f17265fbb96d1ef2e8e)に出てきた箱玉系を、Processingで実装する。(ただ実装しても面白くないので)運動方程式を求めて、それを使って実装してみる。

# 箱玉系の運動方程式
箱玉系を実装するには、まず箱玉系の時間発展がどのように
を求める必要がある。

箱玉系を、$u_n^t$が$0,1$の値をとる二値CAと捉えなおす。
![box-ball2_3.016.jpeg](https://qiita-image-store.s3.amazonaws.com/0/137522/15b6982d-fc00-b9e5-5e9e-af90601fbfda.jpeg)
![box-ball2_3.017.jpeg](https://qiita-image-store.s3.amazonaws.com/0/137522/ad47e045-4c07-eef4-d22b-a22c909cc092.jpeg)

左側にある玉の数が減らなかったときは、
箱玉系のルール(左から順に、右側の一番近い空箱へ移す)により、
次の時間において、必ず$0$になる。
![box-ball2_3.018.jpeg](https://qiita-image-store.s3.amazonaws.com/0/137522/b99543b6-7cdc-933a-5521-a0262719241a.jpeg)
![box-ball2_3.019.jpeg](https://qiita-image-store.s3.amazonaws.com/0/137522/7c72ecaa-3653-0da3-cb1a-e389b42a1beb.jpeg)
![box-ball2_3.020.jpeg](https://qiita-image-store.s3.amazonaws.com/0/137522/ce73ebea-ba0a-104b-5df9-08e663929cfd.jpeg)
これが箱玉系の運動方程式となる。(やっと実装できる。)

# 箱玉系の実装
Processing で実装した。

本体とBox classで構成。
(無駄な計算してるけどまあいいか。)

<details><summary>Code ([GitHub](https://github.com/massss/box-and-ball))</summary><div>

```java:Main
final int boxSize = 40;
final int num = 25;

int Width = num * boxSize;
boolean isRunning = false;
Box[] boxes = new Box[num];
int[] tempBoxes = new int[num];

int t = 0;
int delay = 50;
int framerate;

void settings() {
  size(Width, boxSize + 50);
}

void setup() {
  background(255);
  for (int i = 0; i < num; i++) {
    boxes[i] = new Box(i, 0);
  }
}

void draw() {
  background(255);
  if (t % delay == 0) {
    framerate = (int)frameRate;
    if (isRunning) {
      for (int i = 0; i < num; i++) {
        tempBoxes[i] = boxes[i].ball;
      }
      for (int i = 0; i < num; i++) {
        boxes[i].calcState();
      }
    }
    t = 0;
  }
  t++;
  for (int i = 0; i < num; i++) {
    boxes[i].display();
  }

  fill(250, 0, 0);
  textAlign(LEFT);
  textSize(30);
  if (isRunning) {
    text("Run", 0, height - 10);
  } else {
    text("Stop", 0, height - 10);
  }
  textAlign(RIGHT);
  textSize(18);
  text("frameRate: " + framerate +" / " + delay, width - 10, height - 10);
}

void mouseClicked() {
  int cellColumn = (int)(mouseX / boxSize);
  if (cellColumn < boxes.length) {
    boxes[cellColumn].changeState();
  }
}

void mouseDragged() {
  int cellColumn = (int)(mouseX / boxSize);
  if (0 < mouseX && mouseX < Width && 0 < mouseY && mouseY < boxSize) {
    boxes[cellColumn].changeState();
  }
}

void keyReleased() {
  if (key == ' ') {
    isRunning = !isRunning;
  } else if (key == 'r' || key == 'R') {
    randomSetup();
  } else if (key == 'c' || key == 'C') {
    setup();
  } else if (keyCode == UP) {
    if (delay != 100) {
      delay += 10;
    }
  } else if (keyCode == DOWN) {
    if (delay != 10) {
      delay -= 10;
    }
  } else if (keyCode == ENTER) {
    printInfo();
  }
}

void randomSetup() {
  for (int i = 0; i < num; i++) {
    float coinSpeed = random(1);
    int coin;
    if (coinSpeed > 0.8) {
      coin = 1;
    } else {
      coin = 0;
    }
    boxes[i].ball = coin;
  }
}

void printInfo() {
  for (int i = 0; i < num; i++) {
    if (i == num - 1) {
      println(boxes[i].ball);
    } else {
      print(boxes[i].ball + ", ");
    }
  }
}
```

```java:BoxClass
class Box {
  int pos;
  int num;
  int ball;

  Box (int num, int ball) {
    this.pos = num * boxSize;
    this.num = num;
    this.ball = ball;
  }
  
  void changeState() {
    if (ball == 1) {
      this.ball = 0;
    }else {
      this.ball = 1;
    }
  }
  
  void calcState() {
    int countPast = 0;
    int countNext = 0;
    for (int i = 0; i < this.num; i++) {
      if (boxes[i].ball == 1) {
        countNext++;
      }
      if (tempBoxes[i] == 1) {
        countPast++;
      }
    }
    this.ball = min(countPast - countNext, 1 - this.ball);
  }

  void display() {
    fill(255);
    rect(pos, 0, boxSize, boxSize);
    fill(0);
    if (ball == 1) {
      ellipse(pos + boxSize / 2, boxSize / 2, boxSize * 2/3, boxSize * 2/3);
    }
  }
}
```

</div></details>

### Command
| Key or mouse  | Processing |
| :-: | :-: |
| `click` | add or remove ball |
| `drag`  |  〃  |
| `r`, `R` | setup balls randomly |
| `c`, `C` | clear all balls |
| `↑`  | up delay rate |
| `↓`  | down delay rate |
| `space` | run or stop |
| `ENTER` | print data in console |

### Sample
![hakodama-1.gif](https://qiita-image-store.s3.amazonaws.com/0/137522/5e2e0da4-df67-65f6-b1c0-40a7c12d6e36.gif)

![hakodama-2.gif](https://qiita-image-store.s3.amazonaws.com/0/137522/9e7479e5-6202-7a31-7d50-8bdb461ec19d.gif)