Пример #1
0
  /**
   * Min-Max法。最善手を探索する。打つ場所を探すだけで実際には打たない。
   *
   * @param flag AIの手番のときtrue、プレイヤーの手番のときfalse。
   * @param level 先読みの手数。
   * @return 子ノードでは盤面の評価値。ルートノードでは最大評価値を持つ場所(bestX + bestY * MAS)。
   */
  private int minMax(boolean flag, int level) {
    // ノードの評価値
    int value;
    // 子ノードから伝播してきた評価値
    int childValue;
    // Min-Max法で求めた最大の評価値を持つ場所
    int bestX = 0;
    int bestY = 0;

    // ゲーム木の末端では盤面評価
    // その他のノードはMIN or MAXで伝播する
    if (level == 0) {
      return valueBoard();
    }

    if (flag) {
      // AIの手番では最大の評価値を見つけたいので最初に最小値をセットしておく
      value = Integer.MIN_VALUE;
    } else {
      // プレイヤーの手番では最小の評価値を見つけたいので最初に最大値をセットしておく
      value = Integer.MAX_VALUE;
    }

    // もしパスの場合はそのまま盤面評価値を返す
    if (panel.countCanPutDownStone() == 0) {
      return valueBoard();
    }

    // 打てるところはすべて試す(試すだけで実際には打たない)
    for (int y = 0; y < MainPanel.MASU; y++) {
      for (int x = 0; x < MainPanel.MASU; x++) {
        if (panel.canPutDown(x, y)) {
          Undo undo = new Undo(x, y);
          // 試しに打ってみる(盤面描画はしないのでtrue指定)
          panel.putDownStone(x, y, true);
          // ひっくり返す(盤面描画はしないのでtrue指定)
          panel.reverse(undo, true);
          // 手番を変える
          panel.nextTurn();
          // 子ノードの評価値を計算(再帰)
          // 今度は相手の番なのでflagが逆転する
          childValue = minMax(!flag, level - 1);
          // 子ノードとこのノードの評価値を比較する
          if (flag) {
            // AIのノードなら子ノードの中で最大の評価値を選ぶ
            if (childValue > value) {
              value = childValue;
              bestX = x;
              bestY = y;
            }
          } else {
            // プレイヤーのノードなら子ノードの中で最小の評価値を選ぶ
            if (childValue < value) {
              value = childValue;
              bestX = x;
              bestY = y;
            }
          }
          // 打つ前に戻す
          panel.undoBoard(undo);
        }
      }
    }

    if (level == SEARCH_LEVEL) {
      // ルートノードなら最大評価値を持つ場所を返す
      return bestX + bestY * MainPanel.MASU;
    } else {
      // 子ノードならノードの評価値を返す
      return value;
    }
  }