/** * $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; } } |