// 最も近いユニットナンバー
 public int mostNear(int id1, int i, int id2) {
   int nearUnit = 0;
   int nearLength = 10;
   int length = 0;
   for (int j = 0; j < 3; j++) {
     length = GameBoard.distance(this.board.unitLocation[id1][i], this.board.unitLocation[id2][j]);
     if (length < nearLength) {
       nearUnit = j;
       nearLength = length;
     }
   }
   return nearUnit;
 }
예제 #2
0
  /**
   * ユニットを任意の場所に動かす
   *
   * <p>2015/08/31追加 失敗する条件は次の通り ・現在の座標と移動先の座標が同じ場合 ・座標が範囲外を参照した場合 ・移動距離が1マス以上を超えた場合
   *
   * @param x 動かした先の座標
   * @param y 動かした先の座標
   * @param index 動かすユニット番号 0-3
   * @return trure 成功 false 失敗
   */
  public boolean movePos(int x, int y, int index) {
    int id = this.whoIsPlay();

    //  範囲外参照チェック
    if (!GameBoard.availableArea(x, y)) {
      return false;
    }

    //  距離が0もしくは2以上の移動は無効
    if (GameBoard.distance(unitLocation[id][index], new Point(x, y)) != 1) {
      return false;
    }

    unitLocation[id][index].x = x;
    unitLocation[id][index].y = y;

    this.lastIndex = index;
    this.lastX = x;
    this.lastY = y;
    this.lastId = this.whoIsPlay();

    nextPhase();
    return true;
  }
  @Override
  public double STATIC_VALUE() {
    double score = 0.0;
    int enemyTeamId = playerTeamId == 0 ? 1 : 0;

    //  点数さによる評価
    //  バイアスをかけておかないとマイナスになる可能性がある
    score += k1 * (board.teamPoint[playerTeamId] - board.teamPoint[enemyTeamId] + 100);

    //  自分のユニットとタワーまでの距離
    //  2015/09/03変更
    //  平均値が小さく、分散が小さいものを選択する
    int eDist = 0;
    int pDist = 0;
    for (int i = 0; i < 4; i++) {
      pDist +=
          Math.pow(
              GameBoard.distanceTower(board.unitLocation[playerTeamId][i]),
              2); //  距離が多くなればなるほど点数が下がる
      eDist += Math.pow(GameBoard.distanceTower(board.unitLocation[enemyTeamId][i]), 2); //
    }

    score += k2 * (-pDist + eDist + 100);

    //  保持状態
    int tower = 0;
    for (int i = 0; i < 3; i++) {
      if (board.towerHold[i] == playerTeamId) {
        tower++;
      } else {
        tower--;
      }
    }
    score += k3 * (tower + 3);

    //  相性評価
    int length = 0;
    for (int i = 0; i < 3; i++) { // 全ての駒に対して
      int MNE = mostNear(playerTeamId, i, enemyTeamId); // MNE = mostNearEnemy
      Point P = this.board.unitLocation[playerTeamId][i];
      Point E = this.board.unitLocation[enemyTeamId][MNE];
      if (multiple(i, playerTeamId) < multiple(MNE, enemyTeamId)) // 相手のほうが多い
      {
        length -= GameBoard.distance(P, E);
      } else if (multiple(MNE, enemyTeamId) < multiple(i, playerTeamId)) // 自分のほうが多い
      {
        length += multiple(MNE, enemyTeamId);
      } else { // 同数
        if ((i != 3 && i == MNE + 1) || (i == 3 && MNE == 0)) // 勝てる時
        {
          length += multiple(MNE, enemyTeamId);
        } else if ((i != 0 && i == MNE - 1) || (i == 0 && MNE == 3)) // 負ける時
        {
          length -= GameBoard.distance(P, E);
        }
        // 引き分けは加算無し
      }
    }
    score += k4 * length;

    //  最後に打った手が自分の手ならマイナスを付けておく
    // if(board.lastId==playerTeamId) score = -score;
    //  現在の局面が相手なら
    /*
    if (playerTeamId == board.whoIsPlay()) {
        score = -score;
    }
            */
    this.score = score;
    return score;
  }
 @Override
 public boolean isPlayerTurn() {
   return board.whoIsPlay() == this.playerTeamId;
 }
예제 #5
0
  /**
   * ランダムにゲーム終了までプレイする
   *
   * @return ture プレイヤーの勝ち
   */
  public boolean doPlayout() {

    //  ゲームボードをコピーしおておく
    GameBoard playout = new GameBoard(this);

    //  プレイアウト専用移動履歴
    LinkedList<Hand> history = new LinkedList<>();

    //  ゲーム終了まで繰り返す
    while (playout.isGameEnd() == -1) {

      //  移動候補手
      ArrayList<Hand> canditate = new ArrayList();

      int id = playout.whoIsPlay();
      for (int j = 0; j < 4; j++) { //  すべての手について

        //  タワーマスにいて苦手とするユニットが接近していなければタワーにいる
        boolean f4 = formula4(unitLocation, j, id, this.turnState, this.firstTeamId);
        if (!f4) continue;

        for (int i = 0; i < 8; i++) {

          int x = playout.unitLocation[id][j].x + movex[i];
          int y = playout.unitLocation[id][j].y + movey[i];

          //  x,yが範囲外なら無視
          if (!availableArea(x, y)) {
            continue;
          }

          //  定石1を適用
          boolean f1 = formula1(movex[i], movey[i], x, y, id);
          if (!f1) continue; //  定石外

          //  定石2を適用
          boolean f2 = formula2(history, x, y, j, id);
          if (!f2) continue; //  定石外

          //  定石3
          /*
          boolean f3 = formula3(playout.unitLocation,x,y,j,id,playout.firstTeamId,playout.turnState);
          if(!f3) continue;
          */

          //  ここまできたら候補に追加
          canditate.add(new Hand(x, y, j, id));
        }
      }

      //  候補からランダム選択
      //  候補が1個もない場合はgetAnyHand()でなんでもいいから動かす
      Hand hand;
      if (canditate.size() == 0) {
        hand = getAnyHand(this.whoIsPlay());

      } else {
        int rand = (int) (canditate.size() * Math.random());
        hand = canditate.get(rand);
      }

      //  動かす
      boolean result = playout.movePos(hand.x, hand.y, hand.index);

      //  ログに保存
      history.addLast(hand);
      if (history.size() > 5) history.removeFirst();
    }

    //  勝ちの場合は勝ちの回数を増やす
    //  ここを修正
    //  チームIDではなく現在プレイ中のプレイヤーID
    if (playout.isGameEnd() == this.whoIsPlay()) {
      return true;
    }
    return false;
  }
예제 #6
0
  /**
   * 定石を適用し、考えられるすべての手を実行した子ノードのゲームボードを返します
   *
   * @return
   */
  public ArrayList<GameBoard> extpand() {

    /** 子ノードを定石を使って拡張する */
    ArrayList<GameBoard> children = new ArrayList<>();

    //  くじ引き
    ArrayList<Integer> omikuji = new ArrayList<Integer>();
    omikuji.add(0);
    omikuji.add(1);
    omikuji.add(2);
    omikuji.add(3);

    int id = this.whoIsPlay();

    //  タワーに存在するユニットの数を取得
    int towerUnit = 0;
    for (int j = 0; j < 4; j++) {
      if (isTowerPos(unitLocation[id][j])) towerUnit++;
    }

    //  実行可能手をすべて展開
    for (int j = 0; j < 4; j++) {
      int index = omikuji.remove((int) (omikuji.size() * Math.random()));

      //  すべてタワーにいない場合に限り
      //  タワーマスにいて苦手とするユニットが接近していなければタワーにいる
      if (towerUnit < 3) {
        boolean f4 = formula4(unitLocation, index, id, this.turnState, this.firstTeamId);
        if (!f4) continue;
      }

      for (int i = 0; i < 8; i++) {

        int x = this.unitLocation[id][index].x + movex[i];
        int y = this.unitLocation[id][index].y + movey[i];

        //  x,yが範囲外なら無視
        if (!availableArea(x, y)) {
          continue;
        }

        boolean f1 = formula1(movex[i], movey[i], x, y, id); // 移動範囲漏れチェック
        if (!f1) continue; //  定石外

        // boolean f2 = formula2(handHistory,x,y,index,id);    //  過去の動き重複チェック
        // if(!f2) continue;   //  定石外

        //  ボードを複製し、動かす
        GameBoard tmp = new GameBoard(this);
        tmp.move(movex[i], movey[i], index);
        tmp.handHistory.addLast(new Hand(x, y, index, id));
        //  一定数以上の履歴は破棄する
        if (tmp.handHistory.size() > HAND_HISTORY_NUM) {
          tmp.handHistory.removeFirst();
        }
        //  候補に追加
        children.add(tmp);
      }
    }
    return children;
  }