Yuki Nakata's Blog

One color just reflects another

カテゴリ:プログラミング > processing

素数を渦巻き状に並べて、素数に色を付けていくと対角線や水平線
が現れるようです。
 Ulam_1
これがウラムの螺旋。

こういう視覚情報を伴ったプログラミングはprocessingと相場が決まっていますので、processingでプログラミングしてみましょう。

ウラムの螺旋 wikipedia

wikipediaを見ると左回りですが、右回りでも良さそうです。

プログラミングをすると下の図のように感じになります。数字6000までやってみました。

確かに対角線っぽいものが現れる。
 ulam_spiral

processing 3.01で動作確認しています。

//素数らせんプログラム
final int maxx = 800;
final int maxy = 800;


int i = 0;
int[][] cell = new int[80][80];
int[][] flag = new int[80][80];
int[][] prime = new int[80][80];
int tmpX, tmpY;

int x = 40;
int y = 40;
//数字の進む方向 右 -> 下 -> 左 -> 上 の順に進む
int direction = 0;

void setup(){
  size(800, 800);
  //frameRate(20);
  background(255);
  noLoop();
}

boolean isPrime(int num) {
  int x;
  
  if ( num < 2){
    return false;
  } else if (num == 2 || num == 3) {
    return true;
  } else if (num % 2 == 0 || num % 3 == 0) {
    return false;
  } else {
    for ( x = 5; x * x <= num; x+= 6) {
      if(num % 5 == 0|| num %(x + 2) == 0) {
        return false;
      }
    }
  }
  return true;
  
}

void mouseMoved() {
  if(tmpX != (mouseX / 10) || tmpY != (mouseY / 10)) {
    println(cell[mouseX / 10][mouseY / 10] + " " + prime[mouseX / 10][mouseY / 10]);
    tmpX = mouseX / 10;
    tmpY = mouseY / 10;
  }
}
void draw() {
  
  fill(255, 0, 0);
  
  for ( i = 0; i < (maxx / 10); i++) {    
    line( i * 10, 0, i * 10, 800);
  }
   
  for ( i = 0; i < (maxy  / 10); i++) {
    line(0, i * 10, 800, i * 10);
  }
  
  for (i = 0; i < 6000; i++) {
    if(isPrime(i)) { //素数のとき
      
      rect(x * 10, y * 10, 10, 10);
      prime[x][y] = 1;
    }
    cell[x][y] = i;
    flag[x][y] = 1;
    if(direction == 0) { //右に進む
      if(flag[x + 1][y] == 0) {
        x += 1;
        direction = 1;        
      } else {
        y += -1;
      }      
    }else if(direction == 1) {//下に進む
      if(flag[x][y + 1] == 0) {
        y += 1;
        direction = 2;       
      } else {
        x += 1;
      }      
    }else if(direction == 2) { //左に進む
      if(flag[x - 1][y] == 0) {
        x += -1;
        direction = 3;
      } else {
        y += 1;
      }
    }else if(direction == 3) {  //上に進む
      if(flag[x][y - 1] == 0) {
        y += -1;
        direction = 0;
      }else {
        x += -1;
      }
    }
  }
  

}

次はyoutubeで見つけた吉原宏治さんの素数はスパイラル上にきれいに並んでいた、面白そうでなのプログラミングしてみます。


spiral3
このスパイラルを再現してみたいと思います。

ただの素数ではなくて、ここからnを求めるようです。
spiral2
nの求め方 
素数11の場合、n = ((11^2) - 1) / 24   
n = 5となります。 5の数字で色を塗ります。

もう一つ 素数13の場合、 n = ((13^2) - 1) / 24
n = 7 7の数字で色を塗ります。

400までやってみた結果が下の図。
primespiral6


//素数らせんプログラム

// [20, 20]のマスを用意、スタート地点[10, 10]から右回りに進む。

final int maxx = 400;
final int maxy = 400;

int maxnumber = 400;  //最大値
int[] color4 = new int[maxnumber * maxnumber];
int[] primeflag = new int[maxnumber * maxnumber];
int n;

int i = 0;
int[][] cell = new int[40][40];
int[][] flag = new int[40][40];
int[][] prime = new int[40][40];
int tmpX, tmpY;

int x = 10;  //スタート地点x
int y = 10;  //スタート地点y
int cellsize = 20;
//数字の進む方向 右 -> 下 -> 左 -> 上 の順に進む
int direction = 0;

void setup(){
  size(400, 400);
  //frameRate(20);
  background(255);
  noLoop();
  
  for (i = 0; i < maxnumber; i++) {
    if(isPrime(i)) {
      n = ((i * i) - 1) / 24;
      primeflag[n] = 1;
      if(i % 10 == 1) {
        color4[n] = 1;
      } else if (i % 10 == 3) {
        color4[n] = 3;
      } else if (i % 10 == 7) {
        color4[n] = 7;
      } else if (i % 10 == 9) {
        color4[n] = 9;
      }
    }
  }
}

boolean isPrime(int num) {
  int x;
  
  if ( num < 2){
    return false;
  } else if (num == 2 || num == 3) {
    return true;
  } else if (num % 2 == 0 || num % 3 == 0) {
    return false;
  } else {
    for ( x = 5; x * x <= num; x+= 6) {
      if(num % 5 == 0|| num %(x + 2) == 0) {
        return false;
      }
    }
  }
  return true;
  
}

void mouseMoved() {
  if(tmpX != (mouseX / cellsize) || tmpY != (mouseY / cellsize)) {
    println(cell[mouseX / cellsize][mouseY / cellsize] + " " + prime[mouseX / cellsize][mouseY / cellsize]);
    tmpX = mouseX / cellsize;
    tmpY = mouseY / cellsize;
  }
}
void draw() {
  
  fill(255, 0, 0);
  
  for ( i = 0; i < (maxx / cellsize); i++) {    
    line( i * cellsize, 0, i * cellsize, 400);
  }
   
  for ( i = 0; i < (maxy  / cellsize); i++) {
    line(0, i * cellsize, 800, i * cellsize);
  }
  
  for (i = 0; i < maxnumber; i++) {
    if(primeflag[i] == 1) { //素数のとき
      //print (i);
      if(color4[i] == 1) {
        fill(255, 0, 0);
      } else if (color4[i] == 3) {
        fill(255, 255, 0);
      } else if (color4[i] == 7) {
        fill(255, 0, 255);
      } else if (color4[i] == 9) {
        fill(0, 255, 255);
      }
      rect(x * cellsize, y * cellsize, cellsize, cellsize);
      prime[x][y] = 1;
    }
    cell[x][y] = i;
    flag[x][y] = 1;
    if(direction == 0) { //右に進む
      if(flag[x + 1][y] == 0) {
        x += 1;
        direction = 1;        
      } else {
        y += -1;
      }      
    }else if(direction == 1) {//下に進む
      if(flag[x][y + 1] == 0) {
        y += 1;
        direction = 2;       
      } else {
        x += 1;
      }      
    }else if(direction == 2) { //左に進む
      if(flag[x - 1][y] == 0) {
        x += -1;
        direction = 3;
      } else {
        y += 1;
      }
    }else if(direction == 3) {  //上に進む
      if(flag[x][y - 1] == 0) {
        y += -1;
        direction = 0;
      }else {
        x += -1;
      }
    }
  }
  
}

数字4600までやってみたのが下の図。 

確かに綺麗にスパイラルになっています。
 primespiral7

//素数らせんプログラム

// [80, 80]のマスを用意、スタート地点[40, 40]から右回りに進む。
//一つ進むごとに右 -> 下 -> 左 -> 上と進行方向を変える。
//既に数字が埋まっている場合には、方向を変えず直進する。これを繰り返す。

final int maxx = 800;
final int maxy = 800;
final int cellsize = 10;

int x = 40;  //スタート地点x
int y = 40;  //スタート地点y

int maxnumber = 4600;  //最大値
int[] color4 = new int[maxnumber * maxnumber];
int[] primeflag = new int[maxnumber * maxnumber];
int n;

int i = 0;
int[][] cell = new int[80][80];
int[][] flag = new int[80][80];
int[][] prime = new int[80][80];
int tmpX, tmpY;

//数字の進む方向 右 -> 下 -> 左 -> 上 の順に進む
int direction = 0;

void setup(){
  size(800, 800);
  //frameRate(20);
  background(255);
  noLoop();
  
  //最初に素数からnを求める
  for (i = 0; i < maxnumber; i++) {
    if(isPrime(i)) {
      n = ((i * i) - 1) / 24;
      primeflag[n] = 1;
      if(i % 10 == 1) {
        color4[n] = 1;
      } else if (i % 10 == 3) {
        color4[n] = 3;
      } else if (i % 10 == 7) {
        color4[n] = 7;
      } else if (i % 10 == 9) {
        color4[n] = 9;
      }
    }
  }
}

//素数判定
boolean isPrime(int num) {
  int x;
  
  if ( num < 2){
    return false;
  } else if (num == 2 || num == 3) {
    return true;
  } else if (num % 2 == 0 || num % 3 == 0) {
    return false;
  } else {
    for ( x = 5; x * x <= num; x+= 6) {
      if(num % 5 == 0|| num %(x + 2) == 0) {
        return false;
      }
    }
  }
  return true;
  
}

//マウスが動いたらコンソールに数字を表示
void mouseMoved() {
  if(tmpX != (mouseX / cellsize) || tmpY != (mouseY / cellsize)) {
    println(cell[mouseX / cellsize][mouseY / cellsize] + " " + prime[mouseX / cellsize][mouseY / cellsize]);
    tmpX = mouseX / cellsize;
    tmpY = mouseY / cellsize;
  }
}

void draw() {
  
  fill(255, 0, 0);
  
  for ( i = 0; i < (maxx / cellsize); i++) {    
    line( i * cellsize, 0, i * cellsize, 800);
  }
   
  for ( i = 0; i < (maxy  / cellsize); i++) {
    line(0, i * cellsize, 800, i * cellsize);
  }
  
  for (i = 0; i < maxnumber; i++) {
    
    //nの数字のとき、色でマスを塗る。
    if(primeflag[i] == 1) {
      //print (i);
      if(color4[i] == 1) {//赤
        fill(255, 0, 0);
      } else if (color4[i] == 3) {//黄色
        fill(255, 255, 0);
      } else if (color4[i] == 7) {//紫
        fill(255, 0, 255);
      } else if (color4[i] == 9) {//水色
        fill(0, 255, 255);
      }
      rect(x * cellsize, y * cellsize, cellsize, cellsize);
      prime[x][y] = 1;
    }
    cell[x][y] = i;
    flag[x][y] = 1;
    if(direction == 0) { //右に進む
      if(flag[x + 1][y] == 0) {
        x += 1;
        direction = 1;        
      } else {
        y += -1;
      }      
    }else if(direction == 1) {//下に進む
      if(flag[x][y + 1] == 0) {
        y += 1;
        direction = 2;       
      } else {
        x += 1;
      }      
    }else if(direction == 2) { //左に進む
      if(flag[x - 1][y] == 0) {
        x += -1;
        direction = 3;
      } else {
        y += 1;
      }
    }else if(direction == 3) {  //上に進む
      if(flag[x][y - 1] == 0) {
        y += -1;
        direction = 0;
      }else {
        x += -1;
      }
    }
  }
  
}


   

探偵ナイトスクープで素数をやっていました。これを見たのがきっかけです。

これも簡単にprocessingでできてしまいます。やってみましょう。 

processinglifegame
以前、はむくんのライフゲームの世界を再現しようでライフゲームを再現しました。

今回はprocessingを使ってライフゲームを作成しましょう。

といっても他の人が作ってくれていますので、それを参考に改造していきます。

新米コンサルの日常 のライフゲームを改造しています。

このライフゲームでは2つのモードを設定しています。

セルを作成したり、削除するEditモードとライフゲームを動かすPlayモードです。

遊び方
起動すると最初にエディットモードになります。
マウスをクリックしてセルを作成してください。
スペースキーを押すとプレイモードとなります。
再びスペースキーを押すとプレイモードとエディットモードを切り替えることができます。

ゴスパーのグライダー銃も再現することができますよ。楽しめます。

final int SIZE_OF_CELL = 20;
final int FRAME_SIZE_OF_X = 800;
final int FRAME_SIZE_OF_Y = 800;
int num_of_row = FRAME_SIZE_OF_Y / SIZE_OF_CELL; //gyou  
int num_of_col = FRAME_SIZE_OF_X / SIZE_OF_CELL; //retsu
int num_of_cell = num_of_row * num_of_col;
Cell[][] cells = new Cell[num_of_row][num_of_col];
boolean game_state = false;


void setup(){
  size(FRAME_SIZE_OF_X, FRAME_SIZE_OF_Y);
  frameRate(20);
  for(int row=0; row<num_of_row; row++){
    for(int col=0; col<num_of_col; col++){
      int position_x = col * SIZE_OF_CELL;
      int position_y = row * SIZE_OF_CELL;
      cells[row][col] = new Cell(position_x, position_y, false);
    }
  }
  print("Edit Mode");
}

class Point{
  int row, col;
  Point(int my_row, int my_col){
    row = my_row;
    col = my_col;
  }
  int getRow(){
    return row;
  }
  int getCol(){
    return col;
  }
}

class Cell{
  int x, y;
  boolean state;

  Cell(int my_x, int my_y, boolean s){
    x = my_x;
    y = my_y;
    state = s;
  }
  
  void changeState(){
    state = !state;
  }
  
  void appear(){
    if(state){
      fill(34, 139, 34);
      //fill(50, 50, 50);
    }else{
      fill(50, 50, 50);
      //fill(255, 255, 255);
    }
    rect(x, y, SIZE_OF_CELL, SIZE_OF_CELL);
  }
}

void check_life_and_death(){
  ArrayList<Point> points = new ArrayList<Point>();
  for(int row=0; row<num_of_row; row++){
    for(int col=0; col<num_of_col; col++){
      //jibun no mawari check
      int num_of_alivers = 0;
      for(int r=-1; r<=1; r++){
        for(int c=-1; c<=1; c++){
          if(row+r<0 || row+r>=num_of_row || col+c<0 || col+c>=num_of_col){
            continue;
          } 
          if(cells[row+r][col+c].state){
            num_of_alivers++;
          }
        }
      }
      if(cells[row][col].state){ //jibun no bun wo hiku
        num_of_alivers--;
      }
      //joutai change no note
      if(cells[row][col].state){
        if(num_of_alivers<=1  || num_of_alivers>=4){
          points.add(new Point(row, col));
        }
      }else{
        if(num_of_alivers==3){
          points.add(new Point(row, col));
        }
      }
    }
  } 
  for(int i=0; i<points.size(); i++){
    Point point = points.get(i);
    int point_row = point.getRow();
    int point_col = point.getCol();
    cells[point_row][point_col].changeState();
  }
}

//random setup
void randomSetup(){
  //size(FRAME_SIZE_OF_X, FRAME_SIZE_OF_Y);
  frameRate(20);
  for(int row=0; row<num_of_row; row++){
    for(int col=0; col<num_of_col; col++){
      int position_x = col * SIZE_OF_CELL;
      int position_y = row * SIZE_OF_CELL;
      float coin_seed = random(1);
      boolean coin;
      if(coin_seed>0.8){
        coin = true;
      }else{
        coin = false;
      }
      cells[row][col] = new Cell(position_x, position_y, coin);
    }
  }  
}



void keyPressed(){
  
  
  if(key == ' '){
    game_state = !game_state;
  }
  
  if(game_state) {
    print("Play Mode  ");
  } else {
    print("Edit Mode  ");
  }
}

void mouseClicked(){
  int cell_col = mouseX/SIZE_OF_CELL;
  int cell_row = mouseY/SIZE_OF_CELL;
  cells[cell_row][cell_col].changeState();
  
  print("(" + cell_col + ",");
  print(cell_row + ") ");
}

void draw() {
  if(!game_state){
  }else{
    check_life_and_death();
  }
  for(int row=0; row<num_of_row; row++){
    for(int col=0; col<num_of_col; col++){
      cells[row][col].appear();
    }
  }
  //delay(500);
}

↑このページのトップヘ