| 
<?php
 /**
 * Copyright (c) <2015>, Ghali Ahmed<[email protected]>
 *
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This class find similarity for given cel on 2D array
 * the search strategie can be easly modified with the given direction
 * @Exemple: when the given direction array is: [[0, 1],[-1, 0],[0, -1],[1, 0]]
 * the script will look recursively to the right, top, bottom, left, right of the given cel
 * @author Ghali Ahmed<[email protected]>
 * @version 1.0
 */
 class MathMatrixHelper
 {
 protected $atomes = [];
 
 protected $tile = [];
 
 protected $visited = [];
 
 protected $tileDim = 20;
 
 private $maxNest;
 
 /**
 * Direction to find friend cell
 */
 protected $directions = [];
 
 public function __construct($atomes, $directions, $tileDim)
 {
 $this->atomes = $atomes;
 $this->directions = $directions;
 $this->tileDim = $tileDim;
 $this->maxNest = ini_set('xdebug.max_nesting_level', 0);
 $this->init();
 }
 
 public function init()
 {
 $i = 0;
 while ($i < $this->tileDim) {
 $j = 0;
 $this->tile[$i] = [];
 while ($j < $this->tileDim) {
 $this->tile[$i][$j] = $this->atomes[array_rand($this->atomes)];
 $this->visited[$i][$j] = [];
 $j++;
 }
 $i++;
 }
 }
 
 public function getAllConnexion($i, $j, &$result = [])
 {
 foreach ($this->directions as $key => $direction) {
 $iTarget = $i + $direction[0];
 $jTarget = $j + $direction[1];
 
 if (isset($this->tile[$iTarget][$jTarget])) {
 if (($this->tile[$i][$j] == $this->tile[$iTarget][$jTarget])
 && !isset($this->visited[$i][$j][$key])
 && !isset($this->visited[$iTarget][$jTarget][$key])) {
 $result[] = "$i:$j";
 $this->visited[$i][$j][$key] = true;
 
 $this->getAllConnexion($iTarget, $jTarget, $result);
 }
 }
 }
 
 return $result;
 }
 
 /**
 * Search for connexion in regular mode until there length reached the max value
 * @var $m x0
 * @var $n y0
 */
 public function getRegularConnexion($m, $n, $max, $onlyFirst=false)
 {
 $result = [];
 $len = count($this->tile);
 foreach ($this->directions as $key => $direction) {
 if (!isset($result[$key])) {
 $result[$key] = [];
 }
 for ($i = 0; $i < $len; $i++) {
 $iTarget = $m + $i*$direction[0];
 $jTarget = $n + $i*$direction[1];
 if ($this->tile[$m][$n] != @$this->tile[$iTarget][$jTarget]) {
 break;
 } else {
 $result[$key][] = "$iTarget:$jTarget";
 if ($onlyFirst && (count($result[$key]) == $max)) {
 return $result[$key];
 }
 }
 }
 if (!$onlyFirst && count($result[$key]) <$max) {
 $result[$key] = [];
 }
 };
 
 return $this->flatten($result);
 }
 
 /**
 * Print array like a matrix
 * and display connexion with special color
 */
 public function printTile($result, $m, $n)
 {
 $linePattern = "[%s]<br />";
 $itemPattern = "%s<span style='%s'>%s</span>";
 $output = "";
 for ($i = 0; $i<$this->tileDim; $i++) {
 $sep = '';
 $j = 0;
 $str = '';
 for ($j = 0; $j<$this->tileDim; $j++) {
 $in = in_array("$i:$j", $result);
 $from = $i == $m && $j == $n;
 $str .= sprintf($itemPattern, $sep, ($in ? 'color: red;' : '').($from ? 'border: 1px solid;' : ''), @$this->tile[$i][$j]);
 $sep = ',';
 }
 $output .= sprintf($linePattern, $str);
 }
 
 print '<pre>'.$output.'</pre>';
 }
 
 public function __destruct()
 {
 if (!empty($this->maxNest)) {
 ini_set('xdebug.max_nesting_level', $this->maxNest);
 }
 }
 
 /**
 * Thnaks to http://stackoverflow.com/users/28835/too-much-php
 * http://stackoverflow.com/questions/1319903/how-to-flatten-a-multidimensional-array
 */
 protected function flatten(array $array)
 {
 $return = array();
 array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
 
 return $return;
 }
 }
 
 $letters = ['a', 'b'];
 $directions = [
 'knight' => [[2, 1],[2, -1],[-2, 1],[-2, -1],[1, 2],[-1,2],[1,-2],[-1,-2]],
 'plus' => [[0, 1],[-1, 0],[0, -1],[1, 0]],
 'plus_and_coin' => [[0, 1],[-1, 0],[0, -1],[1, 0],[1, 1],[-1, 1],[1, -1],[-1, -1]],
 ];
 
 $strategie = 'plus_and_coin';
 
 $x = 6;
 $y = 6;
 $matrix = new MathMatrixHelper($letters, $directions[$strategie], 40);
 print '<b>getAllConnexion:</b><br>';
 $startTime = microtime(true);
 //$result = $matrix->getAllConnexion($x, $y);
 //$matrix->printTile($result, $x, $y);
 
 print '<b>getRegularConnexion:</b><br>';
 $result = $matrix->getRegularConnexion($x, $y, 5, false);
 $matrix->printTile($result, $x, $y);
 $endTime = microtime(true);
 echo "Execution time : ".($endTime - $startTime)." seconds<br/><br/>";
 
 |