/**
  * $Id: A5BDA1BCA5B92852656E7361596F6D693129.txt,v 1.1.1.1 2009/06/01 12:21:03 kamoi Exp $
  * Copyright 2004 kamoland.com All rights reserved.
  */
 package com.kamoland.rensacommon.ai.decider;
 
 import com.kamoland.rensacommon.Const;
 import com.kamoland.rensacommon.ai.AiUtil;
 import com.kamoland.rensacommon.ai.Tumi;
 import com.kamoland.rensacommon.ai.TumiDecider;
 import com.kamoland.rensacommon.rule.LinkedPuyo;
 import com.kamoland.rensacommon.rule.PuField;
 
 /**
  * 連鎖形成読みの実装 part1
  *
  * @author kamoland.com
  * @version
  * <pre>
  * 2004/05/29 新規作成
  * </pre>
  */
 public class RensaYomi1 implements TumiDecider {
 
    /**
     * デフォルトコンストラクタ
     */
    public RensaYomi1() {
    }
 
    /**
     * 積みに対する評価得点を算出する
     * @param beforeField 自分のフィールド(NEXT積み適用前)
     * @param afterField 自分のフィールド(NEXT積み適用後)
     * @param fallenTumi NEXT積み(重力落下後)
     * @param nextTumos ツモ色.NEXT:[0][0]〜[0][1],NEXT2:[1][0]〜[1][1]
     * @param enemyFields 敵のフィールド
     * @param isAnyEnemyDoingRensa いずれかの敵が連鎖を発動中
     */
    public long evaluateTumi(
        PuField beforeField,
        PuField afterField,
        Tumi fallenTumi,
        byte[][] nextTumos,
        PuField[] enemyFields,
        boolean isAnyEnemyDoingRensa) {
 
        int fpRange[] = new int[]{
            3, 2, 30000, Const.FIELD_Y * 4 + 1, Const.FIELD_Y * Const.FIELD_Y * 2 + 1, Const.FIELD_Y * 2 + 1};
        int fp[] = new int[fpRange.length];
        
        boolean isRensaStart = afterField.duplicate().vanish(0).any_rensa;
        
        // ★1.窒息を予防する
        int df = 0; 
        for (int k = 0; k < 2; k++) {
            if (fallenTumi.getI()[k] == 2 && fallenTumi.getJ()[k] <= 1 && !isRensaStart) {
                // 窒息する
            } else {
                // 窒息しない
                df++;
            }
        }
        fp[0] = df; // [0,2]
        
        // ★2.連鎖の誤発動を予防する
        boolean badFire = false;
        if (isRensaStart) {
            if (beforeField.getPuyo(1, 3) > 0 ||
            beforeField.getPuyo(2, 4) > 0 ||
            beforeField.getPuyo(3, 4) > 0 ||
                beforeField.getPuyo(4, 3) > 0) {
                // 中央部が詰まってきたら,発火しても良い
            
            } else {
                if (!isAnyEnemyDoingRensa) {
                    // 余裕があり,かつ敵が連鎖中でないなら,発火不可
                    badFire = true;
                }
            }
        }
        fp[1] = badFire? 0: 1;
 
        // ★3,4.連結個数を求める
        // 発火候補点で発火された状況も考慮する版
        int cc1 = AiUtil.countConnected(afterField, fallenTumi.getI()[0], fallenTumi.getJ()[0], fallenTumi.getCol()[0]);
        int cc2 = AiUtil.countConnected(afterField, fallenTumi.getI()[1], fallenTumi.getJ()[1], fallenTumi.getCol()[1]);
        int cc = cc1 + cc2; // [0,32] * 2 = [0,64]
        if (cc1 > 0 && cc2 > 0) {
            // 2色優先
            cc += 64;
        }
 
        // 発火候補点で発火した結果
        int ifr = 0;
        PuField[] fired = AiUtil.imagineFiredField(afterField);
        for (int i = 0; i < fired.length; i++) {
            int currentRensa = 0;
            PuField target = fired[i];
            while (target.vanish(currentRensa).any_rensa) {
                currentRensa++;
                target = target.createVanishedField();
                target.gravitate();
            }
            if (currentRensa > 0) {
                ifr += Math.pow(2, currentRensa);
            }
        }
 
        fp[2] = cc + ifr; // [0,128]
 
        // ★5.同色を同列にまとめる(縦ばさみ)
        int yc = 0;
        LinkedPuyo lp = AiUtil.queryByI(afterField, fallenTumi.getI()[0], fallenTumi.getCol()[0]);
        int yc1 = lp.num; // [0,Const.FIELD_Y]
        lp = AiUtil.queryByI(afterField, fallenTumi.getI()[1], fallenTumi.getCol()[1]);
        int yc2 = lp.num; // [0,Const.FIELD_Y]
        yc = yc1 + yc2;  // [0,Const.FIELD_Y*2]
        if (yc1 > 0 && yc2 > 0) {
            // 2色優先
            yc += Const.FIELD_Y * 2;
        }
        fp[3] = yc; // [0,Const.FIELD_Y*4]
        
        // ★6.隣接行の上に置く
        int dan = 0;
        for (int k = 0; k < 2; k++) {
            if (fallenTumi.getI()[k] > 0) {
                lp = AiUtil.queryByI(beforeField, fallenTumi.getI()[k] - 1, fallenTumi.getCol()[k]);
                if (lp.p_j[0] > fallenTumi.getJ()[k]) {
                    // 右上に置こうとしている
                    dan += (lp.p_j[0] - fallenTumi.getJ()[k]) * lp.num / 2; // [0,Const.FIELD_Y*Const.FIELD_Y/2]
                }
            }
            if (fallenTumi.getI()[k] < Const.FIELD_X - 1) {
                lp = AiUtil.queryByI(beforeField, fallenTumi.getI()[k] + 1, fallenTumi.getCol()[k]);
                if (lp.p_j[0] > fallenTumi.getJ()[k]) {
                    // 左上に置こうとしている
                    dan += (lp.p_j[0] - fallenTumi.getJ()[k]) * lp.num / 2; // [0,Const.FIELD_Y*Const.FIELD_Y/2]
                }
            }
        }
        fp[4] = dan; // [0,Const.FIELD_Y*Const.FIELD_Y*2]
 
        // ★7.できるだけ下に置く
        fp[5] = fallenTumi.getJ()[0] + fallenTumi.getJ()[1]; // [0,Const.FIELD_Y*2]
 
        // 各ルールによる評価点を,優先順位を考慮して集計する
        long result = 0;
        long eff = 1;       
        for (int i = fp.length - 1; i >= 0; i--) {
            result += eff * fp[i];
            eff *= fpRange[i];
        }
 
        return result;
    }
 }


© 2024 KMIソフトウェア