Posted at

# Processingで100行オセロ

More than 3 years have passed since last update.

# Processingで100行オセロ

その当時はif文もfor文も本を参考にしながら、しどろもどろなプログラムを組んでいたわけですが、あれから４年経ち、とうとう大学院を卒業した今、どれだけの実力がついたのか、オセロを作ってみました。

```final int BSIZE = 100;
int[][] field;
boolean bBlacksTurn;

void setup(){
size(8*BSIZE,8*BSIZE);
bBlacksTurn = true;
field = new int[8][8];
for(int i=0; i<8; ++i){
for(int j=0; j<8; ++j){
if((i==3||i==4)&&(j==3||j==4)){
field[i][j] = ((i+j)%2==0)?1:-1; // initial stones;
}else{
field[i][j] = 0;
}
}
}
}

void draw(){
//draw field
background(0,160,0);
stroke(0);
for(int i=1; i<8; ++i){
line(i*BSIZE,0,i*BSIZE,height);
line(0, i*BSIZE, width, i*BSIZE);
}
noStroke();
fill(0);
ellipse(BSIZE*2,BSIZE*2,10,10);
ellipse(BSIZE*6,BSIZE*2,10,10);
ellipse(BSIZE*2,BSIZE*6,10,10);
ellipse(BSIZE*6,BSIZE*6,10,10);

// draw stones
noStroke();
for(int i=0; i<8; ++i){
for(int j=0; j<8; ++j){
if(field[i][j]==1){
fill(0);
ellipse((i*2+1)*BSIZE/2,(j*2+1)*BSIZE/2, BSIZE*0.8, BSIZE*0.8);
}else if(field[i][j]==-1){
fill(255);
ellipse((i*2+1)*BSIZE/2,(j*2+1)*BSIZE/2, BSIZE*0.8, BSIZE*0.8);
}
}
}
}

void mouseReleased(){
int x = mouseX/BSIZE;
int y = mouseY/BSIZE;

boolean puttable = false;
if(field[x][y]==0){
puttable = checkDirection(x,y,-1,-1) | puttable;
puttable = checkDirection(x,y,-1,0) | puttable;
puttable = checkDirection(x,y,-1,1) | puttable;

puttable = checkDirection(x,y,0,-1) | puttable;
puttable = checkDirection(x,y,0,1) | puttable;

puttable = checkDirection(x,y,1,-1) | puttable;
puttable = checkDirection(x,y,1,0) | puttable;
puttable = checkDirection(x,y,1,1) | puttable;

if(puttable){
field[x][y] = currentStone();
bBlacksTurn = !bBlacksTurn;
}
}
}

boolean checkDirection(int x, int y, int directionX, int directionY){
if(checkBound(x+directionX, y+directionY) && field[x+directionX][y+directionY] != currentStone()){
return checkStones(x, y, directionX, directionY);
}
return false;
}

boolean checkStones(int x, int y, int directionX, int directionY){
if(checkBound(x+directionX, y+directionY) && field[x+directionX][y+directionY]==currentStone()){ // find
return true;
}else if(checkBound(x+directionX, y+directionY) && field[x+directionX][y+directionY]==0){ // not find
return false;
}else if(checkBound(x+directionX, y+directionY) && checkStones(x+directionX, y+directionY, directionX, directionY)){
field[x+directionX][y+directionY] = currentStone(); // reverse
return true;
}else{
return false;
}
}

boolean checkBound(int x, int y){
return x>=0 && x<8 && y>=0 && y<8;
}

int currentStone(){
return (bBlacksTurn)?1:-1;
}
```

さらに改造して、色数も盤面のサイズも自由に設定できるようにしました。

```final int BSIZE = 50;
final int COLS = 16, ROWS = 16;
final int PLAYER_NUM = 8;
int[][] field;
int currentColor;

void setup(){
size(COLS*BSIZE,ROWS*BSIZE);
colorMode(HSB);
currentColor = 1;
field = new int[COLS][ROWS];
for(int i=0; i<COLS; ++i){
for(int j=0; j<ROWS; ++j){
field[i][j] = 0;
}
}
for(int i=0; i<PLAYER_NUM; ++i){
for(int j=0; j<PLAYER_NUM; ++j){
field[floor(COLS/2)+i-floor(PLAYER_NUM/2)][floor(ROWS/2)+j-floor(PLAYER_NUM/2)] = ((i+j)%PLAYER_NUM)+1;
}
}
}

void draw(){
//draw field
background(0);
stroke(64);
for(int i=1; i<COLS; ++i) line(i*BSIZE,0,i*BSIZE,height);
for(int i=1; i<ROWS; ++i) line(0, i*BSIZE, width, i*BSIZE);

// draw stones
noStroke();
for(int i=0; i<COLS; ++i){
for(int j=0; j<ROWS; ++j){
for(int k=1; k<=PLAYER_NUM; ++k){
if(field[i][j]==k){
fill(255*(k-1)/PLAYER_NUM,255,255);
ellipse((i*2+1)*BSIZE/2,(j*2+1)*BSIZE/2, BSIZE*0.8, BSIZE*0.8);
}
}
}
}
}

void mouseReleased(){
int x = mouseX/BSIZE;
int y = mouseY/BSIZE;

boolean puttable = false;
if(field[x][y]==0){
puttable = checkDirection(x,y,-1,-1) | puttable;
puttable = checkDirection(x,y,-1,0) | puttable;
puttable = checkDirection(x,y,-1,1) | puttable;

puttable = checkDirection(x,y,0,-1) | puttable;
puttable = checkDirection(x,y,0,1) | puttable;

puttable = checkDirection(x,y,1,-1) | puttable;
puttable = checkDirection(x,y,1,0) | puttable;
puttable = checkDirection(x,y,1,1) | puttable;

if(puttable){
field[x][y] =currentColor;
currentColor = (currentColor==PLAYER_NUM)?1:currentColor+1;
}
}
}

boolean checkDirection(int x, int y, int directionX, int directionY){
if(checkBound(x+directionX, y+directionY) && field[x+directionX][y+directionY] != currentColor&&field[x+directionX][y+directionY] != 0){
return checkStones(x, y, directionX, directionY);
}
return false;
}

boolean checkStones(int x, int y, int directionX, int directionY){
if(checkBound(x+directionX, y+directionY) && field[x+directionX][y+directionY]==currentColor){ // find
return true;
}else if(checkBound(x+directionX, y+directionY) && field[x+directionX][y+directionY]==0){ // not find
return false;
}else if(checkBound(x+directionX, y+directionY) && checkStones(x+directionX, y+directionY, directionX, directionY)){
field[x+directionX][y+directionY] = currentColor; // reverse
return true;
}else{
return false;
}
}

boolean checkBound(int x, int y){
return x>=0 && x<COLS && y>=0 && y<ROWS;
}
```

こんな感じ。

あと、３Ｄオセロも作ってみた。操作感が超悪い。

```final int BSIZE = 40;
final int COLS = 8, ROWS = 8, DEPTH = 8;
final int PLAYER_NUM = 2;
int[][][] field;
int currentColor;
int x=0, y=0, z=0;

void setup() {
size(COLS*BSIZE*4, ROWS*BSIZE*4, P3D);
colorMode(HSB);
frameRate(10);
currentColor = 1;
field = new int[COLS][ROWS][DEPTH];
for (int i=0; i<COLS; ++i) {
for (int j=0; j<ROWS; ++j) {
for (int k=0; k<DEPTH; ++k) {
field[i][j][k] = 0;
}
}
}
for (int i=0; i<PLAYER_NUM; ++i) {
for (int j=0; j<PLAYER_NUM; ++j) {
for (int k=0; k<PLAYER_NUM; ++k)
field[floor(COLS/2)+i-floor(PLAYER_NUM/2)][floor(ROWS/2)+j-floor(PLAYER_NUM/2)][floor(DEPTH/2)+k-floor(PLAYER_NUM/2)] = ((i+j+k)%PLAYER_NUM)+1;
}
}
}

void draw() {
//  directionalLight(204, 204, 204, -3, -5, -1);

lights();
pushMatrix();
translate(COLS*BSIZE/2*4, ROWS*BSIZE/2*4, DEPTH*BSIZE/2*2);
rotateX(radians(-20.0));
rotateY(frameCount / 50.0);
translate(-COLS*BSIZE/2, -ROWS*BSIZE/2, -DEPTH*BSIZE/2);
//draw field
background(0);
stroke(255, 64);
for (int k=0; k<=DEPTH; ++k) {
for (int i=0; i<=COLS; ++i) {
line(i*BSIZE, 0, k*BSIZE, i*BSIZE, ROWS*BSIZE, k*BSIZE);
}
for (int j=0; j<=ROWS; ++j) {
line(0, j*BSIZE, k*BSIZE, COLS*BSIZE, j*BSIZE, k*BSIZE);
}
}
for (int i=0; i<=COLS; ++i) {
for (int j=0; j<=ROWS; ++j) {
line(i*BSIZE, j*BSIZE, 0, i*BSIZE, j*BSIZE, DEPTH*BSIZE);
}
}
// draw stones
noStroke();
for (int i=0; i<COLS; ++i) {
for (int j=0; j<ROWS; ++j) {
for (int k=0; k<DEPTH; ++k) {
for (int l=1; l<=PLAYER_NUM; ++l) {
if (field[i][j][k]==l) {
fill(255*(l-1)/PLAYER_NUM, 255, 255);
pushMatrix();
translate((i*2+1)*BSIZE/2, (j*2+1)*BSIZE/2, (k*2+1)*BSIZE/2);
sphere(BSIZE*0.3);
popMatrix();
}
}
}
}
}
pushMatrix();
translate((x*2+1)*BSIZE/2, (y*2+1)*BSIZE/2, (z*2+1)*BSIZE/2);
stroke(255*(currentColor-1)/PLAYER_NUM, 255, 255);
noFill();
box(BSIZE);
popMatrix();
popMatrix();
}

void keyReleased() {
if (key==' ') {
boolean puttable = false;
if (field[x][y][z]==0) {
for (int i=-1; i<=1; ++i) {
for (int j=-1; j<=1; ++j) {
for (int k=-1; k<=1; ++k) {
if (!(i==0 && j==0 && k==0)) puttable = checkDirection(x, y, z, i, j, k) | puttable;
}
}
}
if (puttable) {
field[x][y][z] =currentColor;
currentColor = (currentColor==PLAYER_NUM)?1:currentColor+1;
}
}
}
else if (key=='x') y = ( y+1==ROWS ) ? 0: y+1;
else if (key=='e') y = ( y-1<0 ) ? ROWS-1: y-1;
else if (key=='a') x = ( x+1==ROWS ) ? 0: x+1;
else if (key=='d') x = ( x-1<0 ) ? ROWS-1: x-1;
else if (key=='w') z = ( z+1==ROWS ) ? 0: z+1;
else if (key=='z') z = ( z-1<0 ) ? ROWS-1: z-1;
}

boolean checkDirection(int x, int y, int z, int directionX, int directionY, int directionZ) {
if (checkBound(x+directionX, y+directionY, z+directionZ) && field[x+directionX][y+directionY][z+directionZ] != currentColor&&field[x+directionX][y+directionY][z+directionZ] != 0) {
return checkStones(x, y, z, directionX, directionY, directionZ);
}
return false;
}

boolean checkStones(int x, int y, int z, int directionX, int directionY, int directionZ) {
if (checkBound(x+directionX, y+directionY, z+directionZ) && field[x+directionX][y+directionY][z+directionZ]==currentColor) { // find
return true;
}
else if (checkBound(x+directionX, y+directionY, z+directionZ) && field[x+directionX][y+directionY][z+directionZ]==0) { // not find
return false;
}
else if (checkBound(x+directionX, y+directionY, z+directionZ) && checkStones(x+directionX, y+directionY, z+directionZ, directionX, directionY, directionZ)) {
field[x+directionX][y+directionY][z+directionZ] = currentColor; // reverse
return true;
}
else {
return false;
}
}

boolean checkBound(int x, int y, int z) {
return x>=0 && x<COLS && y>=0 && y<ROWS && z>=0 && z<DEPTH;
}
```

こんな感じ。

よきかな、よきかな。