Created
November 24, 2016 01:17
-
-
Save dave-newson/5c0584b2730a855cdd24b8c23920702f to your computer and use it in GitHub Desktop.
PHP sum possibilities resolver.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Takes an array of input values eg. [1, 2, 3] | |
* Takes a number of math operators eg. [+, -, *] | |
* Determines all possible permutations of sums that can be made using: | |
* - any combination of operators, including repeating operators (plus one equals sign) | |
* - any sequence (but no repeating) of the given numbers. | |
* | |
* Used to solve a maths puzzle because I'm stupid. | |
*/ | |
class SumFinder | |
{ | |
/** | |
* generate all N! permutations of $str. (N = strlen($str)). | |
* | |
* @param array $str | |
* @param int $i | |
* @param int $n | |
* @param array $out | |
*/ | |
private function permute($str,$i,$n, &$out) { | |
if ($i == $n) | |
$out[] = $str; | |
else { | |
for ($j = $i; $j < $n; $j++) { | |
$this->swap($str,$i,$j); | |
$this->permute($str, $i+1, $n, $out); | |
$this->swap($str,$i,$j); // backtrack. | |
} | |
} | |
} | |
/** | |
* function to swap the item at pos $i and $j of $str. | |
*/ | |
private function swap(&$str,$i,$j) { | |
$temp = $str[$i]; | |
$str[$i] = $str[$j]; | |
$str[$j] = $temp; | |
} | |
/** | |
* Generate all possible combinations of $char for $size | |
* | |
* @param $chars | |
* @param $size | |
* @param array $combinations | |
* @return array | |
*/ | |
private function sampling($chars, $size, $combinations = array()) { | |
# if it's the first iteration, the first set | |
# of combinations is the same as the set of characters | |
if (empty($combinations)) { | |
$combinations = $chars; | |
} | |
# we're done if we're at size 1 | |
if ($size == 1) { | |
return $combinations; | |
} | |
# initialise array to put new values in | |
$new_combinations = array(); | |
# loop through existing combinations and character set to create strings | |
foreach ($combinations as $combination) { | |
foreach ($chars as $char) { | |
$new_combinations[] = $combination . $char; | |
} | |
} | |
# call same function again for the next iteration | |
return $this->sampling($chars, $size - 1, $new_combinations); | |
} | |
/** | |
* Find the answers to $numbers and $symbols | |
* | |
* @param array $numbers | |
* @param array $symbols | |
* @return string | |
*/ | |
public function find(array $numbers, array $symbols) | |
{ | |
// all number combinations | |
$combos = []; | |
$this->permute($numbers, 0, count($numbers), $combos); | |
// All mixtures of symbols | |
$all_mix_symbols = $this->sampling($symbols, (count($numbers) - 1)); | |
$matches = $this->findMatchesInCombos($combos, $all_mix_symbols); | |
// Matches? | |
if ($matches) { | |
return implode("<br />", $matches); | |
} else { | |
return "Can't be done."; | |
} | |
} | |
/** | |
* Find all in combinations provided | |
* | |
* @param $combos | |
* @param $all_mix_symbols | |
* @return array | |
*/ | |
public function findMatchesInCombos($combos, $all_mix_symbols) | |
{ | |
$matches = []; | |
foreach($combos as $comb) { | |
// Get symbol combos | |
foreach($all_mix_symbols as $sym) { | |
// Put an equals sign everywhere | |
for ($i=0; $i<count($sym); $i++) { | |
// Build the sum | |
$sum = ''; | |
foreach($comb as $k => $digit) { | |
$sum .= $digit; | |
if ($i == $k) { | |
$sum .= '=='; | |
} elseif (isset($sym[$k])) { | |
$sum .= $sym[$k]; | |
} | |
} | |
// Evaluate the maths | |
if ($this->evaluateSum($sum)) { | |
$matches[] = $sum; | |
} | |
} | |
} | |
} | |
$matches = array_unique($matches); | |
return $matches; | |
} | |
/** | |
* Evaluate the sum. | |
* | |
* @param $sum | |
* @return bool | |
*/ | |
private function evaluateSum($sum) | |
{ | |
// Prep for eval | |
$evalSum = sprintf('return (%s);', $sum); | |
return (eval($evalSum) === true); | |
} | |
} | |
$finder = new SumFinder(); | |
echo $finder->find([2,5,13,33,39], ['-', '+', '*']); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment