fork download
  1. <?php
  2.  
  3.  
  4. const PLACEHOLDER = " .";
  5. const CAT = " K";
  6.  
  7. /** Класс Игра */
  8. class Game
  9. {
  10. /** @var Field игровое поле */
  11. private $field;
  12. /** @var array массив животных */
  13. private $animals;
  14. /** @var int кол-во ходов */
  15. private $numOfMoves;
  16. /**
  17. * Конструктор класса Игра
  18. * @param Animal $animals,... Объекты-животные через запятую
  19. * @param Field $field Игровое поле
  20. * @param int $numOfMoves сколько ходов нужно отобразить
  21. */
  22. public function __construct(Field $field, int $numOfMoves, Animal ...$animals){
  23. $this->animals = $animals;
  24. $this->field = $field;
  25. $this->numOfMoves = $numOfMoves;
  26. }
  27. /** запустить игру */
  28. public function play(){
  29. $this->getStats();
  30. $this->field->displayField();
  31. echo "\n";
  32. for($i = 0; $i < $this->numOfMoves; $i++){
  33. foreach ($this->animals as $activeAnimal) {
  34. $result = $activeAnimal->go($this->field);
  35. if ($result > 0) {
  36. foreach ($this->animals as $key => $passiveAnimal) {
  37. if ($result == $passiveAnimal->getPosition() and $activeAnimal !== $passiveAnimal) {
  38. unset($this->animals[$key]);
  39. }
  40. }
  41. }
  42. }
  43. $this->getStats();
  44. $this->field->displayField();
  45. echo "\n";
  46. }
  47. }
  48. /** сколько зверей в игре */
  49. private function getStats(){
  50. $uniqNames = [];
  51. $stats = [];
  52. foreach ($this->animals as $animal) {
  53. $uniqNames[] = get_class($animal);
  54. }
  55. $uniqNames = array_unique($uniqNames);
  56. $stats = array_fill_keys($uniqNames, 0);
  57. foreach ($stats as $key => &$value) {
  58. foreach ($this->animals as $animal) {
  59. if ($key == get_class($animal)) {
  60. $value++;
  61. }
  62. }
  63. }
  64. unset($value);
  65. foreach ($stats as $key => $value) {
  66. echo "$key: $value ";
  67. }
  68. echo "\n";
  69. }
  70.  
  71. }
  72.  
  73. /** Класс Игровое поле */
  74. class Field
  75. {
  76. /** @var int кол-во столбцов(ширина) */
  77. private $cols;
  78. /** @var array игровое поле */
  79. private $field;
  80. /**
  81. * @param int $rows кол-во строк
  82. * @param int $cols кол-во столбцов
  83. * @param string $placeholder вид клеточки
  84. */
  85. public function __construct(int $rows, int $cols, string $placeholder)
  86. {
  87. $this->field = array_fill(1, $rows * $cols, $placeholder);
  88. $this->rows = $rows;
  89. $this->cols = $cols;
  90. }
  91. /** отобразить поле */
  92. public function displayField(){
  93. $i = 1;
  94. foreach ($this->field as $value) {
  95. if ($i == $this->cols) {
  96. echo $value . "\n";
  97. $i = 1;
  98. } else {
  99. echo $value;
  100. $i++;
  101. }
  102. }
  103. }
  104.  
  105. /**
  106. * вернуть значение позиции поля
  107. * @param int $position координата
  108. * @return string
  109. */
  110. public function read(int $position):string {
  111. if ($position < 1 or $position > $this->getSize()) {
  112. throw new OutOfRangeException("Выход за пределы игрового поля!\n");
  113. } else {
  114. return $this->field[$position];
  115. }
  116. }
  117.  
  118. /**
  119. * записать значение в позицию
  120. * @param int $position координата
  121. * @param string $value значение
  122. * @return string
  123. */
  124. public function write(int $position, string $value) {
  125. if ($position < 1 or $position > $this->getSize()) {
  126. throw new OutOfRangeException("Выход за пределы игрового поля!\n");
  127. } else {
  128. $this->field[$position] = $value;
  129. }
  130. }
  131.  
  132. /**
  133. * получить ширину поля
  134. * @return int
  135. */
  136. public function getWidth():int {
  137. return $this->cols;
  138. }
  139.  
  140. /**
  141. * получить размер поля (кол-во клеток)
  142. * @return int
  143. */
  144. public function getSize():int {
  145. return count($this->field);
  146. }
  147. }
  148.  
  149. /** Класс Животное */
  150. abstract class Animal
  151. {
  152. /** варианты сторон для шага */
  153. const DOWN = 1;
  154. const UP = 2;
  155. const RIGHT = 3;
  156. const LEFT = 4;
  157. const NORTHWEST = 5;
  158. const NORTHEAST = 6;
  159. const SOUTHWEST = 7;
  160. const SOUTHEAST = 8;
  161. const STAND = 9;
  162. const ALL = 10;
  163. const AROUND = 11;
  164.  
  165. /** @var int позиция на поле */
  166. protected $position;
  167. /** @var string символ животного */
  168. protected $symbol;
  169.  
  170. public function __construct(string $symbol, Field $field)
  171. {
  172. $this->symbol = $symbol;
  173. $this->generatePosition($field);
  174. }
  175.  
  176. /** Возвращает позицию */
  177. public function getPosition():int {
  178. return $this->position;
  179. }
  180.  
  181. /**
  182. * Генерирует начальную позицию
  183. * @param Field $field Объект-Поле
  184. */
  185. private function generatePosition(Field $field):void {
  186. $position = rand(1, $field->getSize());
  187. if (!($field->read($position) == PLACEHOLDER)) {
  188. $this->generatePosition($field);
  189. } else {
  190. $field->write($position, $this->symbol);
  191. $this->position = $position;
  192. }
  193. }
  194.  
  195. /**
  196. * Проверяет cвободен ли путь, не занятали сама клеточка и клеточки в ее направлении
  197. * @param callable $isMe калбек ф-я
  198. * @param Field $field игровое поле
  199. * @param int $move ход
  200. * @param int $step длина шага
  201. * @param int $way направление хода(если шаг больше 1)
  202. * @return bool
  203. */
  204. protected function isOccupied(callable $isMe, Field $field, int $move, int $step = 1, int $way = 0):bool {
  205. if ($isMe($field, $move)) {
  206. return true;
  207. } elseif ($step == 1 and $way == 0) {
  208. return false;
  209. } else {
  210. $position = $this->position;
  211. $stepsToGoal = --$step;
  212. for ($i = 1; $i <= $stepsToGoal; $i++) {
  213. $result = $this->generateMoves($isMe, $field, $position, 1, $way);
  214. if ($result == false) {
  215. return true;
  216. } else {
  217. $position = $result[0];
  218. }
  219. }
  220. return false;
  221. }
  222. }
  223.  
  224. /**
  225. * Универсальная ф-я для ген-ии возможных ходов
  226. * @param Field $field поле
  227. * @param callable $isMe калбек ф-я определяет есть ли на клеточке сородич, принимает объект-поле и ход, возвращает true/false
  228. * @param int $position позиция животного
  229. * @param int $step величина шага
  230. * @param int $ways,... направления для шага через запятую, принимает константы
  231. * @return array
  232. */
  233. protected function generateMoves(callable $isMe, Field $field, int $position, int $step, int ...$ways){
  234. if (count($ways) == 1) {
  235. if ($ways[0] == self::ALL) {
  236. $ways = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  237. }
  238. if ($ways[0] == self::AROUND) {
  239. $ways = [1, 2, 3, 4, 5, 6, 7, 8];
  240. }
  241. }
  242.  
  243. $moves = [];
  244.  
  245. //если шаг = 1
  246. if ($step == 1) {
  247. foreach ($ways as $way) {
  248. if ($way == self::DOWN) {
  249. if (!($position + $field->getWidth() > $field->getSize())) { //Ход вниз
  250. $move = $position + $field->getWidth();
  251. if (!$this->isOccupied($isMe, $field, $move)) {
  252. $moves[] = $move;
  253. }
  254. }
  255. }
  256. if ($way == self::UP){
  257. if (!($position - $field->getWidth() < 1)) { //Ход вверх
  258. $move = $position - $field->getWidth();
  259. if (!$this->isOccupied($isMe, $field, $move)) {
  260. $moves[] = $move;
  261. }
  262. }
  263. }
  264. if ($way == self::RIGHT){
  265. if (!(($position % $field->getWidth()) == 0)) { //Ход вправо
  266. $move = $position + $step;
  267. if (!$this->isOccupied($isMe, $field, $move)) {
  268. $moves[] = $move;
  269. }
  270. }
  271. }
  272. if ($way == self::LEFT){
  273. if (!((($position - 1) % $field->getWidth()) == 0)) { //Ход влево
  274. $move = $position - $step;
  275. if (!$this->isOccupied($isMe, $field, $move)) {
  276. $moves[] = $move;
  277. }
  278. }
  279. }
  280. if ($way == self::NORTHWEST){
  281. if (!(((($position - 1) % $field->getWidth()) == 0) or ($position - $field->getWidth() < 1))) { // диагональ влево вверх
  282. $move = $position - ($field->getWidth() + $step);
  283. if (!$this->isOccupied($isMe, $field, $move)) {
  284. $moves[] = $move;
  285. }
  286. }
  287. }
  288. if ($way == self::NORTHEAST){
  289. if (!((($position % $field->getWidth()) == 0) or ($position - $field->getWidth() < 1))) { //диагональ вправо вверх
  290. $move = $position - ($field->getWidth() - $step);
  291. if (!$this->isOccupied($isMe, $field, $move)) {
  292. $moves[] = $move;
  293. }
  294. }
  295. }
  296. if ($way == self::SOUTHWEST){
  297. if (!(((($position - 1) % $field->getWidth()) == 0) or ($position + $field->getWidth() > $field->getSize()))) { //диаг влево вниз
  298. $move = $position + ($field->getWidth() - $step);
  299. if (!$this->isOccupied($isMe, $field, $move)) {
  300. $moves[] = $move;
  301. }
  302. }
  303. }
  304. if ($way == self::SOUTHEAST){
  305. if (!((($position % $field->getWidth() == 0) or ($position + $field->getWidth() > $field->getSize())))) { //диаг вправо вниз
  306. $move = $position + ($field->getWidth() + $step);
  307. if (!$this->isOccupied($isMe, $field, $move)) {
  308. $moves[] = $move;
  309. }
  310. }
  311. }
  312. if ($way == self::STAND) {
  313. $moves[] = $position;
  314. }
  315. }
  316. } else { //если шаг больше 1
  317. foreach ($ways as $way) {
  318. if ($way == self::DOWN) {
  319. if (!($position + ($field->getWidth() * $step) > $field->getSize())) { //Ход вниз
  320. $move = $position + ($field->getWidth() * $step);
  321. if (!$this->isOccupied($isMe, $field,$move,$step, $way)) {
  322. $moves[] = $move;
  323. }
  324. }
  325. }
  326. if ($way == self::UP){
  327. if (!($position - ($field->getWidth() * $step) < 1)) { //Ход вверх
  328. $move = $position - ($field->getWidth() * $step);
  329. if (!$this->isOccupied($isMe, $field, $move,$step, $way)) {
  330. $moves[] = $move;
  331. }
  332. }
  333. }
  334. if ($way == self::RIGHT){
  335. if (!(($position % $field->getWidth()) == 0)) { //Ход вправо
  336. $partOfStep = $step;
  337. $partOfStep--;
  338. while ($partOfStep > 0) {
  339. if ((($position + $step) - $partOfStep) % $field->getWidth() == 0) {
  340. continue 2;
  341. } else {
  342. $partOfStep--;
  343. }
  344. }
  345. $move = $position + $step;
  346. if (!$this->isOccupied($isMe, $field, $move,$step, $way)) {
  347. $moves[] = $move;
  348. }
  349. }
  350. }
  351. if ($way == self::LEFT){
  352. if (!((($position - 1) % $field->getWidth()) == 0)) { //Ход влево
  353. $partOfStep = $step - 2;
  354. while ($partOfStep >= 0) {
  355. if ((($position - $step) + $partOfStep) % $field->getWidth() == 0) {
  356. continue 2;
  357. } else {
  358. $partOfStep--;
  359. }
  360. }
  361. $move = $position - $step;
  362. if (!$this->isOccupied($isMe, $field, $move,$step, $way)) {
  363. $moves[] = $move;
  364. }
  365. }
  366. }
  367. if ($way == self::NORTHWEST){
  368. if (!(((($position - 1) % $field->getWidth()) == 0) or ($position - ($field->getWidth() * $step) < 1))) { // диагональ влево вверх
  369. $partOfStep = $step - 2;
  370. while ($partOfStep >= 0) {
  371. if ((($position - $step) + $partOfStep) % $field->getWidth() == 0) {
  372. continue 2;
  373. } else {
  374. $partOfStep--;
  375. }
  376. }
  377. $move = $position - (($field->getWidth() * $step) + $step);
  378. if (!$this->isOccupied($isMe, $field, $move,$step, $way)) {
  379. $moves[] = $move;
  380. }
  381. }
  382. }
  383. if ($way == self::NORTHEAST){
  384. if (!((($position % $field->getWidth()) == 0) or ($position - ($field->getWidth() * $step) < 1))) { //диагональ вправо вверх
  385. $partOfStep = $step;
  386. $partOfStep--;
  387. while ($partOfStep > 0) {
  388. if ((($position + $step) - $partOfStep) % $field->getWidth() == 0) {
  389. continue 2;
  390. } else {
  391. $partOfStep--;
  392. }
  393. }
  394. $move = $position - (($field->getWidth() * $step) - $step);
  395. if (!$this->isOccupied($isMe, $field, $move,$step, $way)) {
  396. $moves[] = $move;
  397. }
  398. }
  399. }
  400. if ($way == self::SOUTHWEST){
  401. if (!(((($position - 1) % $field->getWidth()) == 0) or ($position + $field->getWidth() * $step > $field->getSize()))) { //диаг влево вниз
  402. $partOfStep = $step - 2;
  403. while ($partOfStep >= 0) {
  404. if ((($position - $step) + $partOfStep) % $field->getWidth() == 0) {
  405. continue 2;
  406. } else {
  407. $partOfStep--;
  408. }
  409. }
  410. $move = $position + (($field->getWidth() * $step) - $step);
  411. if (!$this->isOccupied($isMe, $field,$move,$step, $way)) {
  412. $moves[] = $move;
  413. }
  414. }
  415. }
  416. if ($way == self::SOUTHEAST){
  417. if (!((($position % $field->getWidth()) == 0) or ($position + $field->getWidth() * $step > $field->getSize()))) { //диаг вправо вниз
  418. $partOfStep = $step;
  419. $partOfStep--;
  420. while ($partOfStep > 0) {
  421. if ((($position + $step) - $partOfStep) % $field->getWidth() == 0) {
  422. continue 2;
  423. } else {
  424. $partOfStep--;
  425. }
  426. }
  427. $move = $position + (($field->getWidth() * $step) + $step);
  428. if (!$this->isOccupied($isMe, $field, $move,$step, $way)) {
  429. $moves[] = $move;
  430. }
  431. }
  432. }
  433. if ($way == self::STAND) {
  434. $moves[] = $position;
  435. }
  436. }
  437. }
  438. if (count($moves) == 0) {
  439. return $moves;
  440. } else {
  441. return $moves;
  442. }
  443. }
  444.  
  445. /**
  446. * Метод для оценки ходов
  447. * @param array $moves - массив ходов полученный функцией generateMoves()
  448. * @return int ход с наибольшим весом
  449. */
  450. abstract protected function rateMoves(Field $field, array $moves):int;
  451.  
  452. /**
  453. * Сделать ход
  454. * Тут происходит вызов generateMoves() и rateMoves()
  455. * @return int возвращаем 0 если ход обычный либо позицию съеденного животного
  456. */
  457. abstract public function go(Field $field):int;
  458. }
  459.  
  460. class Cat extends Animal
  461. {
  462. /** @var int кол-во ходов без отдыха */
  463. private $movesWithoutRest;
  464. /** @var int съеденные мышки */
  465. private $eatenMice;
  466.  
  467. protected function rateMoves(Field $field, array $moves):int {
  468. $movesWithRate = [];
  469. foreach ($moves as $move) {
  470. $rate = 0;
  471. if (is_numeric(trim($field->read($move)))) { //клетка с мышкой
  472. $neighboringMice = 0;
  473. $aroundArea = $this->generateMoves(function($f,$m){return false;}, $field, $move, 1, self::AROUND); //берем клетки вокруг мыша
  474. foreach ($aroundArea as $cell) {
  475. if (is_numeric(trim($field->read($cell)))) {
  476. $neighboringMice++;
  477. }
  478. }
  479. if ($neighboringMice >= 2) {//если рядом с мышкой еще две мышки 0 баллов
  480. $movesWithRate[] = [$rate,$move];
  481. } else {
  482. $rate = 12; //иначе высокий балл
  483. $movesWithRate[] = [$rate,$move];
  484. }
  485. } elseif($field->read($move) == PLACEHOLDER) { //пустая клетка
  486. $rate++; //просто пустая клеточка 1 балл
  487. $mice = 0;
  488. $aroundArea = $this->generateMoves(function($f,$m){return false;}, $field, $move, 1, self::AROUND);//берем клетки вокруг клетки
  489. foreach ($aroundArea as $cell) {
  490. if (is_numeric(trim($field->read($cell)))) {
  491. $mice++; // по +1 за мышку рядом с пустой клеточкой
  492. }
  493. }
  494. $rate += $mice;
  495. $movesWithRate[] = [$rate, $move];
  496. } else { //своя позиция
  497. if (empty($movesWithRate)) { //других ходов нет
  498. return $move;
  499. } else {
  500. $sumRate = 0;
  501. foreach ($movesWithRate as $moveWithRate) {//посчитаем сумму предыдущих ходов
  502. $sumRate += $moveWithRate[0];
  503. }
  504. if ($sumRate == 0) {
  505. return $move;
  506. } else { //если сумма больше 1 стоять не нужно
  507. $movesWithRate[] = [$rate, $move];
  508. }
  509. }
  510. }
  511. }
  512. $rates = array_column($movesWithRate, 0);
  513. $moves = array_column($movesWithRate, 1);
  514. array_multisort($rates, SORT_DESC, $moves);
  515. //Если есть несколько одинаковых крупнейших оценок выберем рандомно одну из них
  516. $largestRateKeys = array_keys($rates, $rates[0]);
  517. if ($largestRateKeys > 1) {
  518. $key = $largestRateKeys[rand(0, count($largestRateKeys) - 1)];
  519. return $moves[$key];
  520. } else {//Иначе самую крупную
  521. return $moves[0];
  522. }
  523. }
  524.  
  525. public function go(Field $field):int {
  526. if ($this->eatenMice > 0) {
  527. $this->eatenMice = 0;
  528. $this->movesWithoutRest = 0;
  529. $field->write($this->position, " @");
  530. return 0;
  531. }
  532. if ($this->movesWithoutRest == 8) {
  533. $this->movesWithoutRest = 0;
  534. $field->write($this->position, " @");
  535. return 0;
  536. }
  537. $isMe = function(Field $field, int $move){
  538. if ($field->read($move) == $this->symbol or $field->read($move) == " @") {
  539. return true;
  540. } else {
  541. return false;
  542. }
  543. };
  544. $moves = $this->generateMoves($isMe, $field, $this->position, 1, self::ALL);
  545. $move = $this->rateMoves($field, $moves);
  546. if (is_numeric(trim($field->read($move)))) {
  547. $this->eatenMice++;
  548. }
  549. $field->write($this->position, PLACEHOLDER);
  550. $this->position = $move;
  551. $field->write($move, $this->symbol);
  552. $this->movesWithoutRest++;
  553. if ($this->eatenMice > 0) {
  554. return $move;
  555. } else {
  556. return 0;
  557. }
  558. }
  559. }
  560.  
  561. class Mouse extends Animal
  562. {
  563. protected function rateMoves(Field $field, array $moves):int {
  564. $cellsWithCats = [];
  565. $emptyCellsWithCats = [];
  566. $emptyCells = [];
  567. $myCell = [];
  568. foreach($moves as $move){
  569. $rate = 0;
  570. if (!is_numeric(trim($field->read($move))) and $field->read($move) != PLACEHOLDER) { // на клеточке враг 0 баллов
  571. $cellsWithCats[] = [$rate, $move];
  572. } elseif ($field->read($move) == PLACEHOLDER) { // клеточка пуста
  573. /* Посчитаем есть ли рядом с клеткой враги */
  574. if ($move == current($this->generateMoves(function($f,$m){return false;}, $field, $this->position, 1, self::UP))) {
  575. $neighboringCells = $this->generateMoves(function($f,$m){return false;}, $field, $move, 1, self::LEFT, self::RIGHT, self::SOUTHEAST, self::SOUTHWEST);
  576. } elseif($move == current($this->generateMoves(function($f,$m){return false;}, $field, $this->position, 1, self::DOWN))) {
  577. $neighboringCells = $this->generateMoves(function($f,$m){return false;}, $field, $move, 1, self::LEFT, self::RIGHT, self::NORTHEAST, self::NORTHWEST);
  578. } elseif ($move == current($this->generateMoves(function($f,$m){return false;}, $field, $this->position, 1, self::LEFT))) {
  579. $neighboringCells = $this->generateMoves(function($f,$m){return false;}, $field, $move, 1, self::UP, self::DOWN, self::NORTHEAST, self::SOUTHEAST);
  580. } else {
  581. $neighboringCells = $this->generateMoves(function($f,$m){return false;}, $field, $move, 1, self::UP, self::DOWN, self::NORTHWEST, self::SOUTHWEST);
  582. }
  583. $cats = 0;
  584. foreach ($neighboringCells as $cell) {
  585. if (!is_numeric(trim($field->read($cell))) and $field->read($cell) != PLACEHOLDER) {
  586. $cats++;
  587. }
  588. }
  589. if ($cats > 0) { // враги рядом с клеткочкой есть - 1 балл
  590. $rate++;
  591. $emptyCellsWithCats[] = [$rate, $move];
  592. } else {
  593. $rate += 10; // путь свободен - 10 баллов
  594. $emptyCells[] = [$rate, $move];
  595. }
  596. } else {
  597. if (empty($emptyCells)) { // ходов на 10 баллов нет
  598. if (array_sum(array_column(array_merge($cellsWithCats, $emptyCellsWithCats), 0)) == 0) { // все пути закрыты, стоим
  599. return $move;
  600. } else { // иначе выбор между ходом в 1 балл и стоять
  601. $friends = 0;
  602. $aroundArea = $this->generateMoves(function($f,$m){return false;}, $field, $move, 1, self::AROUND);
  603. foreach ($aroundArea as $cell) {
  604. if (is_numeric(trim($field->read($cell)))) {
  605. $friends++;
  606. }
  607. }
  608. if ($friends >= 2) { // если рядом друзья - стоим
  609. return $move;
  610. }
  611. $myCell[] = [$rate, $move]; // иначе стоять оценим в 0 баллов
  612. }
  613. } else {
  614. $myCell[] = [$rate, $move];
  615. }
  616. }
  617. }
  618. $movesWithRate = array_merge($cellsWithCats, $emptyCellsWithCats, $emptyCells, $myCell);
  619. $rates = array_column($movesWithRate, 0);
  620. $moves = array_column($movesWithRate, 1);
  621. array_multisort($rates, SORT_DESC, $moves);
  622. //Если есть несколько одинаковых крупнейших оценок выберем рандомно одну из них
  623. $largestRateKeys = array_keys($rates, $rates[0]);
  624. if ($largestRateKeys > 1) {
  625. $key = $largestRateKeys[rand(0, count($largestRateKeys) - 1)];
  626. return $moves[$key];
  627. } else {//Иначе самую крупную
  628. return $moves[0];
  629. }
  630. }
  631.  
  632. public function go(Field $field):int {
  633. $isMe = function(Field $field, int $move){
  634. if (is_numeric(trim($field->read($move)))) {
  635. return true;
  636. } else {
  637. return false;
  638. }
  639. };
  640. $moves = $this->generateMoves($isMe, $field, $this->position, 1, self::UP, self::DOWN, self::LEFT, self::RIGHT, self::STAND);
  641. $move = $this->rateMoves($field, $moves);
  642. $field->write($this->position, PLACEHOLDER);
  643. $this->position = $move;
  644. $field->write($move, $this->symbol);
  645. return 0;
  646. }
  647. }
  648.  
  649.  
  650. $field = new Field(10, 10, PLACEHOLDER);
  651. $m = new Mouse(" 1", $field);
  652. $m2 = new Mouse(" 2", $field);
  653. $m3 = new Mouse(" 3", $field);
  654. $c = new Cat(CAT, $field);
  655. $c2 = new Cat(CAT, $field);
  656. $c3 = new Cat(CAT, $field);
  657. $game = new Game($field, 20, $m, $m2, $m3, $c, $c2, $c3);
  658. $game->play();
  659.  
Success #stdin #stdout 0.02s 24816KB
stdin
Standard input is empty
stdout
Mouse: 3 Cat: 3 
 . . . . . . . . . .
 . . . . . . . . . K
 . . 3 . . . . . . 1
 . . . . . . . . . K
 . 2 . . . . . . . .
 . . . . . . . . . .
 K . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Mouse: 1 Cat: 3 
 . . . . . . . . . K
 . . . . . . . . . .
 . . . . . . . . K .
 . . 3 . . . . . . .
 . . . . . . . . . .
 . K . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Mouse: 1 Cat: 3 
 . . . . . . . . . .
 . . . . . . . . K .
 . . . . . . . . @ .
 . 3 . . . . . . . .
 . . . . . . . . . .
 . @ . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Mouse: 1 Cat: 3 
 . . . . . . . . . .
 . . . . . . . . . K
 . . . . . . . . . .
 3 . . . . . . K . .
 K . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Mouse: 1 Cat: 3 
 . . . . . . . . . K
 . . . . . . . . . .
 3 . . . . . . . . .
 . K . . . . . . . .
 . . . . . . . K . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Mouse: 1 Cat: 3 
 . . . . . . . . . .
 3 . . . . . . . K .
 . K . . . . . . . .
 . . . . . . . . K .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Mouse: 1 Cat: 3 
 3 . . . . . . . . K
 K . . . . . . . . .
 . . . . . . . . . K
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . K . . . . . . . .
 . . . . . . . . K K
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . @ . . . . . . K .
 . . . . . . . . . .
 . . . . . . . . . K
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . K . . . . K . .
 . . . . . . . . . .
 . . . . . . . . . @
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . . . . . . . K .
 . . . K . . . . . .
 . . . . . . . . K .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . . . . . . . @ .
 . . . . . . . . . K
 . . . K . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . . . . . . K . .
 . . . . . . . . . .
 . . . . . . . . . K
 . . . . K . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . . . . . . . . .
 . . . . . . K . . K
 . . . . . . . . . .
 . . . . . K . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . . . . . . . K .
 . . . . . . . . . .
 . . . . . . . K . .
 . . . . . . K . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . . . . . . . . .
 . . . . . . . K . .
 . . . . . . . . K .
 . . . . . . . . . .
 . . . . . . K . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . . . . . . . . .
 . . . . . . . . . K
 . . . . . . K . . .
 . . . . . . K . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . . . . . . . K .
 . . . . . . . K . .
 . . . . . . . . . .
 . . . . . . @ . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . . . . . . . . .
 . . . . . . . @ K .
 . . . . . . K . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . . . . . . . . .
 . . . . . K . . . .
 . . . . . . K K . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .

Cat: 3 
 . . . . . . K . . .
 . . . . . . K . . .
 . . . . . . . @ . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .
 . . . . . . . . . .