Strategyパターン。ホイミスライムがなかなかホイミを唱えないので値を少し変更してみた。
<?php
class Battle {
private $turnNumber = 1;
private $hpOfHero = 500;
private $offenseOfHero = 12;
private $monsters = array ();
public function __construct($monsterList) {
$this->monsters = $monsterList;
}
public function start() {
while (TRUE) {
if (count($this->monsters) == 0) {
print "勇者は勝利した!";
break;
} elseif ($this->hpOfHero > 0) {
$this->nextTurn();
} else {
print "勇者は死んでしまった";
break;
}
}
}
public function nextTurn() {
print $this->turnNumber . "ターン:\n";
srand(microtime(TRUE) * 100 * 17);
$targetNum = rand(0, count($this->monsters) - 1);
$target = $this->monsters[$targetNum];
$target->setHp($target->getHp() - ($this->offenseOfHero - $target->getDefence()));
print "勇者の攻撃:" . $target->getName() . "に" . ($this->offenseOfHero - $target->getDefence()) . "のダメージを与えた!\n";
if ($target->getHp() <= 0) {
print $target->getName() . "を倒した!\n";
unset($this->monsters[$targetNum]);
$this->monsters = array_values($this->monsters);
}
foreach ($this->monsters as $aMonster) {
$damage = $aMonster->act() * 3;
print $aMonster->getName() . "の攻撃:" . $damage . "のダメージを受けた!\n";
$this->hpOfHero -= $damage;
}
$this->turnNumber++;
}
}
abstract class Monster {
protected $name;
protected $hp;
protected $defence;
abstract public function act();
public function getName() {
return $this->name;
}
public function getHp() {
return $this->hp;
}
public function setHp($newHp) {
$this->hp = $newHp;
}
public function getDefence() {
return $this->defence;
}
}
class Slime extends Monster {
protected $name = "スライム";
protected $hp = 20;
protected $defence = 3;
public function act() {
return 3;
}
}
class HoimiSlime extends Monster {
protected $name = "ホイミスライム";
protected $hp = 25;
protected $defence = 2;
public function act() {
srand(microtime(TRUE) * 100 * 17);
if ($this->hp < 18 && rand(0, 1) == 0) {
$this->hp += 30;
return 0;
} else {
return 2;
}
}
}
class KingSlime extends Monster {
protected $name = "キングスライム";
protected $hp = 50;
protected $defence = 5;
function act() {
srand(microtime(TRUE) * 100 * 17);
if (rand(0, 1) == 1) {
return 8;
} else {
return 4;
}
}
}
class Demo {
public static function main() {
$monsters = array(new Slime(), new Slime(), new HoimiSlime(), new KingSlime());
$btl = new Battle($monsters);
$btl->start();
list($usec, $sec) = explode(' ', microtime());
}
}
Demo::Main();
// Result:
// 1ターン:
// 勇者の攻撃:キングスライムに7のダメージを与えた!
// スライムの攻撃:9のダメージを受けた!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:6のダメージを受けた!
// キングスライムの攻撃:24のダメージを受けた!
// 2ターン:
// 勇者の攻撃:ホイミスライムに10のダメージを与えた!
// スライムの攻撃:9のダメージを受けた!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:6のダメージを受けた!
// キングスライムの攻撃:24のダメージを受けた!
// 3ターン:
// 勇者の攻撃:スライムに9のダメージを与えた!
// スライムの攻撃:9のダメージを受けた!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:0のダメージを受けた!
// キングスライムの攻撃:12のダメージを受けた!
// 4ターン:
// 勇者の攻撃:スライムに9のダメージを与えた!
// スライムの攻撃:9のダメージを受けた!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:6のダメージを受けた!
// キングスライムの攻撃:24のダメージを受けた!
// 5ターン:
// 勇者の攻撃:キングスライムに7のダメージを与えた!
// スライムの攻撃:9のダメージを受けた!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:6のダメージを受けた!
// キングスライムの攻撃:24のダメージを受けた!
// 6ターン:
// 勇者の攻撃:キングスライムに7のダメージを与えた!
// スライムの攻撃:9のダメージを受けた!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:6のダメージを受けた!
// キングスライムの攻撃:12のダメージを受けた!
// 7ターン:
// 勇者の攻撃:スライムに9のダメージを与えた!
// スライムの攻撃:9のダメージを受けた!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:6のダメージを受けた!
// キングスライムの攻撃:12のダメージを受けた!
// 8ターン:
// 勇者の攻撃:スライムに9のダメージを与えた!
// スライムの攻撃:9のダメージを受けた!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:6のダメージを受けた!
// キングスライムの攻撃:24のダメージを受けた!
// 9ターン:
// 勇者の攻撃:キングスライムに7のダメージを与えた!
// スライムの攻撃:9のダメージを受けた!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:6のダメージを受けた!
// キングスライムの攻撃:24のダメージを受けた!
// 10ターン:
// 勇者の攻撃:ホイミスライムに10のダメージを与えた!
// スライムの攻撃:9のダメージを受けた!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:6のダメージを受けた!
// キングスライムの攻撃:24のダメージを受けた!
// 11ターン:
// 勇者の攻撃:ホイミスライムに10のダメージを与えた!
// スライムの攻撃:9のダメージを受けた!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:6のダメージを受けた!
// キングスライムの攻撃:12のダメージを受けた!
// 12ターン:
// 勇者の攻撃:スライムに9のダメージを与えた!
// スライムを倒した!
// スライムの攻撃:9のダメージを受けた!
// ホイミスライムの攻撃:6のダメージを受けた!
// キングスライムの攻撃:12のダメージを受けた!
// 勇者は死んでしまった
?>
Composite。Directoryは予約済みなのでDirに名前を変更。
<?php
abstract class Item {
protected $name;
public function getName() {
return $this->name;
}
abstract public function getSize();
}
class File extends Item {
protected $size;
public function __construct($newName, $newSize) {
$this->name = $newName;
$this->size = $newSize;
}
public function getSize() {
return $this->size;
}
}
class Dir extends Item {
private $children = array();
public function __construct($newName) {
$this->name = $newName;
}
public function getSize() {
$total = 0;
foreach ($this->children as $item) {
$total += $item->getSize();
}
return $total;
}
public function add(Item $item) {
$this->children[] = $item;
}
public function getChildren() {
return $this->children;
}
}
class Demo {
public static function main() {
$root = new Dir("root");
$root->add(new File("index.html", 2));
$root->add(new File("style.css", 3));
$about = new Dir("about");
$about->add(new File("index.html", 3));
$root->add($about);
$blog = new Dir("blog");
$blog->add(new File("index.html", 4));
$blog->add(new File("latest.rss", 3));
$root->add($blog);
$b2005 = new Dir("2005");
$b2005->add(new File("01.html", 8));
$b2005->add(new File("02.html", 5));
$blog->add($b2005);
$rootChildren = $root->getChildren();
foreach ($rootChildren as $anItem) {
print $anItem->getName() . " -- " . $anItem->getSize() . "KB\n";
}
}
}
Demo::main();
// Result:
// index.html -- 2KB
// style.css -- 3KB
// about -- 3KB
// blog -- 20KB
?>
Dir::add(Item $item)で試しにType Hintingしてみた。これによりItemクラスを継承したオブジェクト以外は受け入れないようになっている。Javaではこのような型にこだわる場面がもっと多いので、継承による型の同一視はさらに重要になってくる。
ところで、PHP5関係の情報が必要ならPHPのマニュアルは英語版を使わないと痛い目を見る。日本語版はどうやら最新版と同期されていないらしい。
17および協力者に感謝する。引き続きPHASE 2に移行する。