<?php
abstract class Animal
{
protected $x;
protected $y;
protected $icon;
protected $field;
public function __construct($coordinateX, $coordinateY, $symbol)
{
$this->x = $coordinateX;
$this->y = $coordinateY;
$this->icon = $symbol;
}
public function getCoordinateX()
{
return $this->x;
}
public function getCoordinateY()
{
return $this->y;
}
public function showCoordinates()
{
echo "Координата X = [$this->x] ";
echo "Координата Y = [$this->y]";
}
public function getIcon()
{
return $this->icon;
}
public function moveTo($x, $y)
{
$this->x = $x;
$this->y = $y;
}
public function setField(GameField $field)
{
$this->field = $field;
}
public function unsetField()
{
$this->field = null;
}
}
class Mouse extends Animal
{
public function findAllCats()
{
$animals = $this->field->shareAnimals();
foreach ($animals as $animal) {
if ($animal instanceof Cat
&& (abs($this->x - $animal->getCoordinateX()) <= 9 || abs($this->y - $animal->getCoordinateY()) <= 9)) { $cats[] = $animal;
}
}
return $cats;
}
public function findClosestCat($x, $y)
{
$cats = $this->findAllCats();
$previous = INF;
$target = null;
foreach ($cats as $cat) {
$distanceX = abs($this->x - $cat->getCoordinateX()); $distanceY = abs($this->y - $cat->getCoordinateY()); $distance = max($distanceX, $distanceY); if ($distance < $previous) {
$target = $cat;
$previous = $distance;
}
}
return $target;
}
public function defineAllAvaibleTurns($x, $y)
{
'x' => $x + 1,
'y' => $y,
'score' => INF
),
'x' => $x - 1,
'y' => $y,
'score' => INF
),
'x' => $x,
'y' => $y - 1,
'score' => INF
),
'x' => $x,
'y' => $y + 1,
'score' => INF
)
);
'x' => $x,
'y' => $y,
'score' => INF
)
);
foreach ($ways as $key => $value) {
if ($this->field->canMoveTo($value['x'], $value['y'])) {
$list[$key] = $value;
}
}
return $list;
}
public function calculateScore($list)
{
foreach ($list as $key => $direction) {
$cat = $this->findClosestCat($direction['x'], $direction['y']);
$distanceX = abs($cat->getCoordinateX() - $direction['x']); $distanceY = abs($cat->getCoordinateY() - $direction['y']); $distance = max($distanceX, $distanceY); $extra = min($distanceX, $distanceY);
$furtherTurns = $this->defineAllAvaibleTurns($direction['x'], $direction['y']);
$list[$key]['score'] = $distance * 2 + $extra;
}
return $list;
}
public function chooseBestTurn()
{
$list = $this->calculateScore($this->defineAllAvaibleTurns($this->x, $this->y));
$turn = null;
$previous = 0;
foreach ($list as $key => $value) {
if ($value['score'] > $previous) {
$turn = $value;
$previous = $value['score'];
}
}
return $turn;
}
public function makeMove()
{
$turn = $this->chooseBestTurn();
$this->moveTo($turn['x'], $turn['y']);
}
}
class Cat extends Animal
{
protected $sleepCount = 0;
protected $moveCount = 0;
public function getIcon()
{
if ($this->sleepCount == 0) {
return parent::getIcon();
} else {
return "@";
}
}
public function fallAsleep()
{
$this->sleepCount = 1;
$this->moveCount = 0;
}
public function move($x, $y)
{
if ($this->sleepCount == 0) {
if (!($this->field->checkTile($this->x + $x, $this->y + $y) instanceof Cat)) {
$this->x = $this->x + $x;
$this->y = $this->y + $y;
$this->moveCount++;
}
if ($this->moveCount == 8) {
$this->fallAsleep();
}
$tile = $this->field->checkTile($this->x, $this->y);
if ($tile instanceof Mouse) {
$this->field->killMouse($tile->getCoordinateX(), $tile->getCoordinateY());
$this->fallAsleep();
}
}
else {
$this->sleepCount--;
}
}
public function makeMove()
{
$x = 0;
$y = 0;
$target = $this->findClosestMouse();
if ($target) {
if ($target->getCoordinateX() > $this->x) {
$x = 1;
} elseif ($target->getCoordinateX() < $this->x) {
$x = -1;
}
if ($target->getCoordinateY() > $this->y) {
$y = 1;
} elseif ($target->getCoordinateY() < $this->y) {
$y = -1;
}
$this->move($x, $y);
}
}
public function findClosestMouse()
{
$previous = INF;
$target = 0;
foreach ($this->field->shareAnimals() as $animal) {
if (!($animal instanceof Mouse)) {
continue;
}
$distanceX = abs($this->x - $animal->getCoordinateX()); $distanceY = abs($this->y - $animal->getCoordinateY()); $distance = max($distanceX, $distanceY); if ($distance < $previous) {
$target = $animal;
$previous = $distance;
}
}
if ($target) {
return $target;
}
}
}
class GameField
{
protected $field;
protected $animals = array(); protected $height;
protected $width;
public function __construct($height, $width)
{
$this->height = $height;
$this->width = $width;
}
public function printField()
{
foreach ($this->animals as $animal) {
$x = $animal->getCoordinateX();
$y = $animal->getCoordinateY();
$this->field[$x][$y] = $animal->getIcon();
}
foreach ($this->field as $value) {
foreach ($value as $dot) {
echo $dot;
}
echo "\n";
}
}
public function acquireAnimal(Animal $animal)
{
$this->animals[] = $animal;
$animal->setField($this);
}
public function shareAnimals()
{
return $this->animals;
}
public function shareHeight()
{
return $this->height - 1;
}
public function shareWidth()
{
return $this->width - 1;
}
public function killMouse($x, $y)
{
for ($i = 0; $i < count($this->animals); $i++) {
if ($this->animals[$i] instanceof Mouse && $this->animals[$i]->getCoordinateX() == $x && $this->animals[$i]->getCoordinateY() == $y) {
$this->animals[$i]->unsetField();
unset($this->animals[$i]); }
}
}
public function checkTile($x, $y)
{
foreach ($this->animals as $animal) {
if ($animal->getCoordinateX() == $x && $animal->getCoordinateY() == $y) {
return $animal;
}
}
return false;
}
public function isXOnMap($x)
{
if ($x < 0 || $x > ($this->height - 1)) {
return false;
} else {
return true;
}
}
public function isYOnMap($y)
{
if ($y < 0 || $y > ($this->width - 1)) {
return false;
} else {
return true;
}
}
public function canMoveTo($x, $y)
{
if ($this->isXOnMap($x) && $this->isYOnMap($y) && !$this->checkTile($x, $y)) {
return true;
}
return false;
}
public function testTheKitty()
{
foreach ($this->animals as $animal) {
if ($animal instanceof Cat) {
$animal->makeMove();
}
}
foreach ($this->animals as $animal) {
if ($animal instanceof Mouse) {
$animal->makeMove();
}
}
}
}
$test = new GameField(6, 6);
$mouse1 = new Mouse(3, 5, "1");
$mouse2 = new Mouse(2, 0, "2");
$kitty = new Cat(5, 2, "K");
$kitty2 = new Cat(5, 3, "k");
$test->acquireAnimal($mouse1);
$test->acquireAnimal($mouse2);
$test->acquireAnimal($kitty);
$test->acquireAnimal($kitty2);
$test->printField();
echo "\n";
for ($i = 0; $i < 40; $i++) {
$test->testTheKitty();
$test->printField();
echo "\n";
}