8月 032014
 

リーダー 光槍の魔術神・オーディン(緑おでん)
フレンド 豊穣神・イービルセレス
サブ 超覚醒ゼウス、覚醒ヘラ・イース、翠石龍・アダマント、防御態勢(自動回復持ちのセイレーンまたはパールヴァティー推奨、高スキルレベル推奨)

で、ゼウス・ディオス降臨をクリアするときのメモ。
ポイントはリーダーチェンジのアダマントと自動回復3000です。
プラスもスキルレベルもパズル力も運もそれほどいりませんが、時間がかかります。

今回使ったパーティーはこちらです。
http://www.loglesslove.net/pad_team/?m1=1423.99.0.0.1.8&m2=917.99.1.0.0.3&m3=597.99.4.0.1.1&m4=1117.99.99.99.99.4&m5=739.96.0.0.0.1&m6=393.99.30.0.10.4

disk

1階

ベルセルクから倒します。ハイランダーがHP75%以下から連続攻撃を使い始めるので、ギガグラは使いません。
ベルセルクとハイランダー(通常攻撃)の同時攻撃ターンに守りの衣を確実に発動させればOK。
ベルセルクを倒したらアダマントにリーダーチェンジします。

[詳細]
ベルセルクが一刀両断を使う場合、ハイランダーの通常攻撃と合計すると約9090ダメージ(ヘライースの水軽減込み)。
自動回復が3000あるので、次のハイランダーのみのターンで守りの衣を発動させる場合は6060を回復させる必要があります。
今回の回復力3109の場合、回復含む5コンボで可能。(3045ぐらいあれば5コンボ?)
ここで回復できた場合次のハイランダーのダメージを守りの衣で736に減らすことができ、自動回復のみで全快できるのでこのターンは回復する必要がなくなります。
できなかった場合は次のターンのハイランダーのダメージが3681で、回復ドロップさえあれば全快できます。
回復ドロップがなくても、防御態勢、グングニール、完治の光があります。
2階

3階で緑おでんをリーダーにできる準備が整ったら、グリフォンのHP30%付近からギガグラとラースとグングニールで倒します。

HP21196を用意しておけばリーダーアダマントで神風を耐えることができ、それを目印にすることもできるかと思いますが、その必要はないでしょう。
3階

リーダー緑おでん。以上。

4階

リーダーアダマントで、魔力を溜め始めたら緑おでんにリーダーチェンジ。

5階

ディオスブレードを使い始めるまでにリーダーをアダマントにします。
最終的に1ターンのダメージが、ディオスブレード7605(自動回復で実質4605)、ジュピタージェネシス8450(5450)になるので、あとはひたすら耐えてスキルで倒すだけです。

ハクが出た場合(未検証)

西方七星陣までにアダマントをリーダーにしておきます。
西方七星陣のダメージが約9447→自動回復で6447になるので、ひたすら耐えながらHP約40万を削ります。

実際はHP40万からギガグラとラースを使うと約18万で、グングニールが弱点属性で13万になるのでもう少し楽になるはず。
 Posted by at 11:53 PM
3月 272012
 

多段 if 文はプログラムの可読性を損いバグの温床となるため、多くのプログラマーがそれによって悶え苦しみ、日夜命を落としています。
今日は、そんな憎き多段 if 文をやっつける方法を考えたいと思います。

たとえば、次のような条件分岐があるとします。
flowchart

これを、素直に次のようにコーディングします。

code 1

// $condition1~5 には条件式が入るとします。つまり boolean が入ります。
// $goal に数値を入れているだけですが、実際にはここに具体的な処理を置きます。

$goal = 0;

if ($condition1) {
	if ($condition2) {
		$goal = 1;
	} else {
		if ($condition4) {
			if ($condition5) {
				$goal = 1;
			} else {
				$goal = 2;
			}
		} else {
			$goal = 3;
		}
	}
} else {
	if ($condition3) {
		$goal = 4;
	} else {
		if ($condition4) {
			if ($condition5) {
				$goal = 1;
			} else {
				$goal = 2;
			}
		} else {
			$goal = 3;
		}
	}
}

多段 if 文の下地ができました。これを応用してネストを深くしていくとプログラマーを殺すことができます。
さらにコードの 7 ~ 15 行目と 21 ~ 29 行目が重複しています。
もし、条件4と条件5の間に新しい条件6が挿入される、つまり
・条件4が真のときに条件6の判定を行う
・条件6が真のときに条件5の判定を行う
という仕様変更が発生すると2カ所にまったく同じ修正が必要になり、プログラマーは死にます。

条件分岐を見るとついこのように書きたくなりますが、一寸ここでフローチャートを眺めてみると、だんだんと次のように見えてきます。
state transition diagram

なんと、状態遷移図っぽくなりましたね!
while 文の中で状態を遷移させていき、それぞれの状態を switch-case 文で記述するような感じで、この図の処理を次のようにコーディングしてみましょう。

code 2

$state = 1;
$goal = -1;
while ($goal == -1) {
	switch ($state) {
		case 1:
			if ($condition1) {
				$state = 2;
			} else {
				$state = 3;
			}
			break;
		case 2:
			if ($condition2) {
				$goal = 1;
			} else {
				$state = 4;
			}
			break;
		case 3:
			if ($condition3) {
				$goal = 4;
			} else {
				$state = 4;
			}
			break;
		case 4:
			if ($condition4) {
				$state = 5;
			} else {
				$goal = 3;
			}
			break;
		case 5:
			if ($condition5) {
				$goal = 1;
			} else {
				$goal = 2;
			}
			break;
		default:
			$goal = 0;
			break;
	}
}

それぞれの状態で条件の判定を行い、次に移るべき状態がある場合は $state に対応する値を代入し、ゴールに到達すれば $goal に値を代入してループを抜けます。
行数は増えましたが、シンプルな case 文によって構成されたコードになりネストが浅くなりました。また、条件4の重複もなくなりました。
条件4と条件5の間に条件6が挿入される場合は、$condition4 が true のときに $state に条件6を差す別の値を代入し、それに対応する case を書いてやればOKです。図でいうと矢印の行き先を変更するイメージです。

常にこの方法が適用できるわけではないかと思いますが、上手くいくこともあるんじゃないか、ということで。

 Posted by at 1:56 AM
2月 242012
 

すでに要素が格納されている配列に後から添え字 0 の要素を作っても、添え字 0 の要素は先頭の要素にはなりません。
そのため、「その配列から添え字 0 の要素を取り除き」「添え字を 0 から振り直す」ために array_shift を使用すると、意図した結果になりません。

この場合は添え字 0 の要素があれば unset し、なければそのままで array_values を使用すると添え字を 0 から振り直せます。

結論は以上ですが、詳しく見るために以下の要件を想定します。

  • 配列は for 文で処理するため 0 から 1 ずつ添え字が増えていく形で作りたい。
  • 場合によって 0 番目に優先的に入る要素がある。

それってどんなとき?聖闘士星矢で説明してくれ。

  • 4 人の聖闘士が戦っている。
  • ある人物がピンチのときに助けにきて大活躍してくれる聖闘士がいる。
  • 戦いの中で全員がセブンセンシズに目覚める。

ということで、以下のコードを書き、4 人もしくは 5 人の聖闘士をセブンセンシズに目覚めさせてみましょう。

// 聖闘士集合
$saints = array(
    'Pegasus' => 'Seiya', 
    'Dragon' => 'Shiryu', 
    'Cyguns' => 'Hyouga', 
    'Andromeda' => 'Shun'
);
// 聖闘士、闘いに赴く
$fightingSaints = array();
$i = 0;
foreach ($saints as $saint) {
    $fightingSaints[++$i] = $saint;
}
// 瞬がピンチだ
if ($shunIsInAPinch) {
    // 兄貴、颯爽と現れ先頭に躍り出る
    $fightingSaints[0] = 'Ikki';
} else {
    $fightingSaints[0] = null;
    array_shift($fightingSaints);
}
// 聖闘士、セブンセンシズに目覚める
for ($i = 0; $i < count($fightingSaints); $i++) {
    seventhSense($fightingSaints&#91;$i&#93;);
}
&#91;/PHP&#93;

もし $shunIsInAPinch が true の場合は
<ol>
<li>Ikki</li>
<li>Seiya</li>
<li>Shiryu</li>
<li>Hyouga</li>
<li>Shun</li>
</ol>
の 5 人全員がセブンセンシズに目覚めることができます。
じゃあ $shunIsInAPinch が false の場合どうなるか。Ikki が来ないので 4 人がセブンセンシズに目覚めるはずです。ところが…
<ol>
<li>Shiryu</li>
<li>Hyouga</li>
<li>Shun</li>
</ol>
哀れ、Seiya はアナザーディメンションで異次元に飛ばされました。
何が悪かったのでしょうか?
コードの 21 行目の直後で $fightingSaints の中身を見てみましょう。

$shunIsInAPinch が true のとき
[PHP]
Array
(
    [1] => Seiya
    [2] => Shiryu
    [3] => Hyouga
    [4] => Shun
    [0] => Ikki
)

先頭に躍り出たと思われた Ikki は一番後ろに。鳳凰幻魔拳を受けましたね。

$shunIsInAPinch が false のとき

Array
(
    [0] => Shiryu
    [1] => Hyouga
    [2] => Shun
    [3] => 
)

$shunIsInAPinch が false のとき、コードの 19 行目では何が起きているのか?

Array
(
    [1] => Seiya
    [2] => Shiryu
    [3] => Hyouga
    [4] => Shun
    [0] => 
)

添え字 0 の要素を後から作っても、先頭は相変わらず添え字 1 の Seiya で、array_shift によって 先頭の Seiya がアナザーディメンションされてしまう、というわけですね。
19 ~ 20 行目は素直にこう書き換えましょう。

$fightingSaints = array_values($fightingSaints);

これで Ikki が来なくてもみんなセブンセンシズに目覚めることができます。

  1. Seiya
  2. Shiryu
  3. Hyouga
  4. Shun

聖闘士は二度同じ技は受けませんので、このロジックで失敗することはもうありませんね。

 Posted by at 1:13 AM

PHPで機種依存文字判定ツールを作ってみた

 PHP  コメントは受け付けていません。
11月 302011
 

近年はWebで文字化けを見ることがずいぶんと減ったかと思いますが、古いシステムを使っていたり、メールを送信したり、ガラケー向けのWebサイトを作ったりする場合に、機種依存文字(NEC機種依存文字、IBM拡張文字など)に困ることがあります。

ちなみに携帯Twitterでは機種依存文字がガラケーで表示されません。
Twitter / @loglesslove: 濵﨑髙德(はまさきたかのり)さんは携帯Twitterで表示される?

そんなわけで、全部の機種依存文字を判定するにはどうすればいいんだ?と思ってPHPで作ってみました。
機種依存文字判定ツール

判定は文字を SJIS と SJIS-win にそれぞれエンコードして、その結果の文字列を比較して行っています。

以下のクラスのインスタンスを作成して、文字列を与えて処理する形です。

   	class ExternalString
	{
		private $_encoding = 'UTF-8';

		/**
		 * 外字インスタンスの配列
		 * @var array
		 */
		private $_externalCharacters;

		/**
		 * コンストラクタ
		 * 文字列をセットすると外字インスタンスの配列を作る
		 * @param string $string 文字列
		 */
		public function __construct($string = null) {
			$this->_string = $string;
			$this->_externalCharacters = $this->_partStringAndJudgeExternal($string);
		}
		/**
		 * 文字列をセットするついでに外字インスタンスの配列を作る
		 * @param string $string
		 */
		public function setString($string) {
			$this->_externalCharacters = $this->_partStringAndJudgeExternal($string);
		}

		/**
		 * 文字列を文字に分解して外字インスタンスをつくり、その配列として返す
		 * @param string $string
		 */
		private function _partStringAndJudgeExternal($string) {
			$chars = array();
			$length = mb_strlen($string, $this->_encoding);
			for ($i = 0; $i < $length; $i++) {
				$char = mb_substr($string, $i, 1, $this->_encoding);
				$exChar = new ExternalCharacter($char);
				$external = strcmp(mb_convert_encoding($char, 'SJIS', $this->_encoding), mb_convert_encoding($char, 'SJIS-win', $this->_encoding)) !== 0;
				$exChar->setExternal($external);
				$chars[$i] = $exChar;
			}
			return $chars;
		}

		/**
		 * 外字を取り除く
		 * @return array
		 */
		public function filter() {
			return $this->_getEitherChars(false);
		}

		/**
		 * 外字だけ返す
		 * @return array
		 */
		public function pickup() {
			return $this->_getEitherChars(true);
		}

		/**
		 * 外字か通常の文字かのどちらかを配列として返す
		 * @param boolean $external
		 * @return array
		 */

		private function _getEitherChars($external) {
			$chars = array();
			foreach ($this->_externalCharacters as $key => $exChar) {
				if ($exChar->isExternal() === $external) {
					$chars[] = $exChar->getCharacter();
				}
			}
			return $chars;
		}

		/**
		 * 外字に色(のスタイル)を付けて文字列として返す
		 * @param string $color
		 * @return string
		 */
		public function getColoredString($color = '#ffff00') {
			if (preg_match('/^#[0-9a-f]{6}$/', $color) == 0) {
				$color = '#ffff00';
			}
			$chars = array();
			foreach ($this->_externalCharacters as $key => $exChar) {
				$char = htmlspecialchars($exChar->getCharacter());
				if ($exChar->isExternal()) {
					$char = '<span style="background-color: ' . $color . ';">' . $char . '</span>';
				}
				$chars[] = $char;
			}
			$string = implode('', $chars);
			return $string;
		}

	}


	class ExternalCharacter
	{
		/**
		 * 文字
		 * @var string
		 */
		private $_character;
		/**
		 * 外字フラグ
		 * @var boolean
		 */
		private $_external;
		/**
		 * コンストラクタ
		 * @param string $character
		 */
		public function __construct($character = null) {
			$this->_character = $character;
			$this->_external = false;
		}

		/**
		 * 文字setter
		 * @param string $character
		 */
		public function setCharacter($character) {
			$this->_character = $character;
		}

		/**
		 * 外字フラグsetter
		 * @param boolean $external
		 */
		public function setExternal($external) {
			$this->_external = $external;
		}

		/**
		 * 文字getter
		 * @return string
		 */
		public function getCharacter() {
			return $this->_character;
		}

		/**
		 * 外字かどうかを言う
		 * @return boolean
		 */
		public function isExternal() {
			return $this->_external;
		}
	}

あとは以下のようにして文字を処理して取り出しています。


	$xStr = new ExternalString($string); // インスタンス生成
	$coloredString = $xStr->getColoredString(); // 色付き文字列
	$regularString = implode("", $xStr->filter()); // 機種依存文字除く文字
	$externalString = implode("", $xStr->pickup()); // 機種依存文字

※ソース・コメントはもっといい書き方があれば修正すると思います。(文字列で返すか配列で返すかというところもそのうち。)

参考サイト:
Windowsの機種依存文字
PHP で機種依存文字をフィルタリングする関数を作ってみた | ウェブル
floatingdays: PHPの SJISと SJIS-WINの違い
 Posted by at 12:10 AM