<?php

error_reporting(-1);

class Field
{
    private $size;
    private $mapOfField = array();
    private $numberOfCats = 0;
    private $cats = array();
    private $numberOfMouses = 0;
    private $mouses = array();
    public function __construct($size)
    {
        $this->size = $size;
        $string     = array();
        for ($a = 0; $a <= $size; $a++) {
            $string[$a] = null;
        }
        for ($i = 0; $i <= $size; $i++) {
            $this->mapOfField[$i] = $string;
        }
    }
    public function add(Animal $animal)
    {
        $type = $animal->getType();
        if ($type == 'mouse') {
            $this->mouses[$this->numberOfMouses] = $animal;
            $animal->setNumber($this->numberOfMouses);
            $this->numberOfMouses++;
        } elseif ($type == 'cat') {
            $this->cats[$this->numberOfCats] = $animal;
            $animal->setNumber($this->numberOfCats);
            $this->numberOfCats++;
        }
        $x                        = $animal->getCoordinate('x');
        $y                        = $animal->getCoordinate('y');
        $this->mapOfField[$x][$y] = $animal;
    }
    public function delete($animal)
    {
        $x = $animal->getCoordinate('x');
        $y = $animal->getCoordinate('y');
        $this->mapOfField[$x][$y] = null;
        $number                = $animal->getNumber();
        if ($number != $this->numberOfMouses) {
            $this->mouses[$number] = array_pop($this->mouses);
        } elseif($number == $this->numberOfMouses) {
            $this->mouses[$number] = null;
        }
    }
    public function getAllCats ()
    {
		return $this->cats;
	}
    public function getMouses()
    {
        return $this->mouses;
    }
    public function getSize()
    {
        return $this->size;
    }
	public function getMap ()
	{
		return $this->mapOfField;
	}
    public function updateCoordinates($animal, $x, $y)
    {
        $type = $animal->getType();
        if (($x <= $this->size && $x >= 0) && ($y <= $this->size && $y >= 0)) {
            if ($type == 'cat') {
                $cell = $this->mapOfField[$x][$y];
                if (($cell == null) || (($aimType = $cell->getType()) == 'mouse')) {
                    $startX                             = $animal->getCoordinate('x');
                    $startY                             = $animal->getCoordinate('y');
                    $this->mapOfField[$startX][$startY] = null;
                    $animal->setCoordinate($x,$y);
                    $this->mapOfField[$x][$y] = $animal;
                }
            } elseif ($type == 'mouse') {
                $cell = $this->mapOfField[$x][$y];
                if ($cell == null) {
                    $startX                             = $animal->getCoordinate('x');
                    $startY                             = $animal->getCoordinate('y');
                    $this->mapOfField[$startX][$startY] = null;
                    $animal->setCoordinate($x,$y);
                    $this->mapOfField[$x][$y] = $animal;
                }
            }
        }
    }
}

abstract class Animal
{
    protected $type;
    protected $number;
    protected $x;
    protected $y;
    public function __construct($type, $x, $y)
    {
        $this->type = $type;
        $this->x    = $x;
        $this->y    = $y;
    }
    public function getCoordinate($orXY)
    {
        if ($orXY == 'x') {
            return $this->x;
        } elseif ($orXY == 'y') {
            return $this->y;
        }
    }
    public function setCoordinate($x, $y)
    {
        $this->x = $x;
        $this->y = $y;
    }
    public function setNumber($number)
    {
        $this->number = $number;
    }
    public function getType()
    {
        return $this->type;
    }
    public function getNumber()
    {
        return $this->number;
    }
    abstract public function move($field);
}

class Cat extends Animal
{
    private $hungry = 1;

    public function move($field)
    {
        $x   = $this->x;
        $y   = $this->y;
        $min = $field->getSize();
        if ($this->hungry == 1) {
            $mouses = $field->getMouses();
            foreach ($mouses as &$value) {
                $mouseX   = $value->getCoordinate('x');
                $mouseY   = $value->getCoordinate('y');
                $distance = sqrt(pow($mouseX - $x, 2) + pow($mouseY - $y, 2));
                if ($distance <= $min) {
                    $aimAnimal = $value;
                    $aimX      = $mouseX;
                    $aimY      = $mouseY;
                }
            }
            if ($x < $aimX) {
                $x++;
            } elseif ($x > $aimX) {
                $x--;
            } else {
                if ($y == $aimY) {
                    $this->hungry = 0;
                    $field->delete($aimAnimal);
                }
            }
            if ($y < $aimY) {
                $y++;
            } elseif ($y > $aimY) {
                $y--;
            } else {
                if ($x == $aimX) {
                    $this->hungry = 0;
                    $field->delete($aimAnimal);
                }
            }
            $field->updateCoordinates($this, $x, $y);
        } elseif ($this->hungry == 0) {
            $this->hungry = 1;
        }
    }
}

function printField($array)
{
    foreach ($array as &$value) {
        foreach ($value as &$value) {
            if ($value == null) {
                echo '.';
            } else {
                $type = $value->getType();
                if ($type == 'mouse') {
                    echo 'M';
                } elseif ($type == 'cat') {
                    echo 'C';
                }
            }
        }
        echo "\n";
    }
}

class Mouse extends Animal
{
    public $overview = 5;
    public function move($field)
    {
		$cats = $field->getAllCats();
		$x = $this->x;
		$y = $this->y;
		foreach ($cats as &$value) {
			$catX = $value->getCoordinate('x');
			$catY = $value->getCoordinate('y');
			$distance = sqrt(pow($mouseX - $x, 2) + pow($mouseY - $y, 2));
			if ($distance <= $this->overview) {
				$vectorX = $vectorX + (($catX - $x) / pow($distance, 2));
				$vectorY = $vectorY + (($catX - $y) / pow($distance, 2));
			}
		}
		$vectorX = $vectorX*(-1);
		$vectorY = $vectorY*(-1);
		if ($vectorX < 0) {
			$x--;
		} elseif ($vectorX > 0) {
			$x++;
		}
		if ($vectorY < 0) {
			$y--;
		} elseif ($vectorY > 0) {
			$y++;
		}
		$field->updateCoordinates($this, $x, $y);
	}

}

$field = new Field(7);
$cat   = new Cat('cat', 0, 0);
$cat1 = new Cat ('cat', 4, 4);
$mouse = new Mouse('mouse', 2, 2);
$mouse1 = new Mouse ('mouse', 2, 3);

$field->add($cat);
$field->add($cat1);
$field->add($mouse);
$field->add($mouse1);

$map = $field->getMap();

printField($map);
echo "\n";
function giveLive ($field, $step) {
    $map = $field->getMap();
	for ($i = 1; $i < $step; $i++) {
    	$cats = $field->getAllCats();
		$mouses = $field->getMouses();
		foreach ($mouses as &$value) {
			$value->move($field);
		}
		foreach ($cats as &$value) {
			$value->move($field);
		}
        $map = $field->getMap();
    	printField($map);
    	echo "\n";
	}
}

giveLive($field, 8);