Skip to content

Instantly share code, notes, and snippets.

@dave-newson
Created November 24, 2016 01:17
Show Gist options
  • Save dave-newson/5c0584b2730a855cdd24b8c23920702f to your computer and use it in GitHub Desktop.
Save dave-newson/5c0584b2730a855cdd24b8c23920702f to your computer and use it in GitHub Desktop.
PHP sum possibilities resolver.
/**
* 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