○×ゲームを作る (6) 仕上げ

前回は、リーチを判定する関数 reach() を作成しました。今回は○×ゲームを仕上げましょう。

コンピュータ側の一連の流れを、PCturn として関数化しましょう。コンピュータは、以下の戦略をとることとします。

  1. turn 1:中心が空いていれば中心をとる。空いていなければ左上(0,0)をとる
  2. turn 3 以降:リーチがあればリーチのマスをとる。この時、コンピュータ側のリーチを優先する。リーチがなければランダム

上記の後、勝利判定を行い、turn に 1 追加します。

void PCturn(){
  if((turn % 2 == 1) && (turn < 9)){
    if(turn == 1){
      if(map[1][1] == 1){
        drawX(1, 1);
        map[1][1] = 3;
      }
      else{
        drawX(0, 0);
        map[0][0] = 3;
      }
    }
    else {
      if(reach()){
        drawX(X, Y);
        map[Y][X] = 3;
      }
      else randomCheck();
    }
    win();
    turn ++;
  }
}

 

上記のコードでは、 drawX(1, 1); のように、マスの座標を指定して × を書けるようにしています。これに合わせて、以前作成した drawX() 関数を以下のように修正します。

void drawX(int x, int y){
  line(x*200, y*200, x*200+200, y*200+200);
  line(x*200+200, y*200, x*200, y*200+200);
}

 

それではここまでを振り返りましょう。上記の PCturn と drawX 以外のタブの内容は以下の通りです。

メインタブ

int X, Y;
int map[][]={{1,1,1},{1,1,1},{1,1,1}};
int turn = 0;

void setup(){
  size(600,600);
  background(255);
  frameRate(12);
  strokeWeight(2);
  smooth();
  line(0, 200, width, 200);
  line(0, 400, width, 400);
  line(200, 0, 200, height);
  line(400, 0, 400, height);
}

void draw(){  
  myturn();
  PCturn();
}

myturnタブ

void myturn(){
  if (turn % 2 == 0){
    if(mousePressed == true){
      X = mouseX / 200;
      Y = mouseY / 200;
      if(map[Y][X] == 1) {
        fill(255);
        ellipse(X*200+100, Y*200+100, 150, 150);
        map[Y][X]=2;
        win();
        turn ++;
      }
    }
  }
}

randomタブ

void randomCheck(){
  do{
    X = int(random(3));
    Y = int(random(3));
  }while(map[Y][X] != 1);
  map[Y][X] = 3;
  drawX(X, Y);
}

reachタブ

boolean reach(){
  int line = 1;

  // vertical reach
  for (X = 0; X < 3; X++){
    for (Y = 0; Y < 3; Y++){
      line *= map[Y][X];
    }
    if(line == 9){
      for (Y = 0; Y < 3; Y ++){
        if(map[Y][X] == 1)  return true;
      }
    } else if(line == 4){
      for (Y = 0; Y < 3; Y ++){
        if(map[Y][X] == 1)  return true;
      }
    }
  }

  //horizontal reach
  line = 1;
  for (Y = 0; Y < 3; Y++){
    for (X = 0; X < 3; X++){
      line *= map[Y][X];
    }
    if(line == 9){
      for (X = 0; X < 3; X ++){
        if(map[Y][X] == 1)  return true;
      }
    } else if (line == 4){
      for (X = 0; X < 3; X ++){
        if(map[Y][X] == 1)  return true;
      }
    } 
  }

  // cross reach (right-down)
  line = map[0][0] * map[1][1] * map[2][2];
  if(line == 9){
    for(int i = 0; i < 3; i++){
      if(map[i][i] == 1) {
        X = i;
        Y = i;
        return true;
      }
    }
  } else if (line == 4){
    for(int i = 0; i < 3; i++){
      if(map[i][i] == 1) {
        X = i;
        Y = i;
        return true;
      }
    }
  } 

  // cross reach (right-up)
  line = map[2][0] * map[1][1] * map[0][2];
  if(line == 9){
    for(int i = 0; i < 3; i++){
      if(map[2-i][i] == 1) {
        X = i;
        Y = 2 - i;
        return true;
      }
    }
  } else if(line == 4){
    for(int i = 0; i < 3; i++){
      if(map[2-i][i] == 1) {
        X = i;
        Y = 2 - i;
        return true;
      }
    }
  }
  
  return false;
}

winタブ

void win(){
  textSize(100);
  fill(0);
  textAlign(CENTER, CENTER);

  if ((map[0][0]*map[0][1]*map[0][2] == 8) ||
      (map[1][0]*map[1][1]*map[1][2] == 8) ||
      (map[2][0]*map[2][1]*map[2][2] == 8) ||
      (map[0][0]*map[1][0]*map[2][0] == 8) ||
      (map[0][1]*map[1][1]*map[2][1] == 8) ||
      (map[0][2]*map[1][2]*map[2][2] == 8) ||
      (map[0][0]*map[1][1]*map[2][2] == 8) ||
      (map[2][0]*map[1][1]*map[0][2] == 8)){
    text("You WIN!", width/2, height/2);
    noLoop();
  }
  else if ((map[0][0]*map[0][1]*map[0][2] == 27) ||
      (map[1][0]*map[1][1]*map[1][2] == 27) ||
      (map[2][0]*map[2][1]*map[2][2] == 27) ||
      (map[0][0]*map[1][0]*map[2][0] == 27) ||
      (map[0][1]*map[1][1]*map[2][1] == 27) ||
      (map[0][2]*map[1][2]*map[2][2] == 27) ||
      (map[0][0]*map[1][1]*map[2][2] == 27) ||
      (map[2][0]*map[1][1]*map[0][2] == 27)){
    text("You LOSE!", width/2, height/2);
    noLoop();
  }
  
 else if (turn >= 8){
    text("DRAW", width/2, height/2);
    noLoop();
  }
}

 

これで完成です。

リセットの機能をつけたり、色を変えてみたりしてもいいかもしれませんね。また何か作ってみたいと思います。

Leave a Reply

Your email address will not be published. Required fields are marked *