|  | 
|  | 1 | +/** | 
|  | 2 | + * Finds the total number of possible combinations in which to place operator symbols for an `N`-length array | 
|  | 3 | + * @param {string[]} operators String array containing operator symbols | 
|  | 4 | + * @param {number} N Length of a linear array | 
|  | 5 | + * @returns {number} Total number | 
|  | 6 | + */ | 
|  | 7 | +const operatorCombinations = ( | 
|  | 8 | +  operators: string[] = ['+', '*'], | 
|  | 9 | +  N: number | 
|  | 10 | +) => { | 
|  | 11 | +  const combinations: string[][] = [] | 
|  | 12 | +  const totalCombinations = Math.pow(operators.length, N) | 
|  | 13 | + | 
|  | 14 | +  for (let i = 0; i < totalCombinations; i += 1) { | 
|  | 15 | +    const list: string[] = [] | 
|  | 16 | +    let seed = i | 
|  | 17 | + | 
|  | 18 | +    for (let j = 0; j < N; j += 1) { | 
|  | 19 | +      list.push(operators[seed % operators.length] as string) | 
|  | 20 | +      seed = Math.floor(seed / operators.length) | 
|  | 21 | +    } | 
|  | 22 | + | 
|  | 23 | +    combinations.push(list) | 
|  | 24 | +  } | 
|  | 25 | + | 
|  | 26 | +  return combinations | 
|  | 27 | +} | 
|  | 28 | + | 
|  | 29 | +/** | 
|  | 30 | + * Returns the result of an AoC text equation and a set of operator symbols with the condition: | 
|  | 31 | + *  - Left to write equation processing, disregarding operator precedence | 
|  | 32 | + * @param {string} eqnString Math equation expressed as string | 
|  | 33 | + * @returns {number} Result of the `eqnString` | 
|  | 34 | + */ | 
|  | 35 | +const doEquation = (numbers: number[], operators: string[]): number => { | 
|  | 36 | +  let sum = numbers[0] as number | 
|  | 37 | + | 
|  | 38 | +  operators.forEach((operator, index) => { | 
|  | 39 | +    if (operator === '+') { | 
|  | 40 | +      sum += numbers[index + 1] as number | 
|  | 41 | +    } | 
|  | 42 | + | 
|  | 43 | +    if (operator === '*') { | 
|  | 44 | +      sum *= numbers[index + 1] as number | 
|  | 45 | +    } | 
|  | 46 | +  }) | 
|  | 47 | + | 
|  | 48 | +  return sum | 
|  | 49 | +} | 
|  | 50 | + | 
|  | 51 | +/** | 
|  | 52 | + * Counts the total calibration sum of input lines whose elements (numbers) match the line's target sum | 
|  | 53 | + * after processing with one of N possible combinations of `+` and `*` operands | 
|  | 54 | + * @param input Input string array | 
|  | 55 | + * @returns {number} Total calibration sum | 
|  | 56 | + */ | 
|  | 57 | +export const totalCalibrationResult = (input: string[]): number => { | 
|  | 58 | +  const operators = ['+', '*'] | 
|  | 59 | +  let sum = 0 | 
|  | 60 | + | 
|  | 61 | +  for (let i = 0; i < input.length; i += 1) { | 
|  | 62 | +    const line = input[i] | 
|  | 63 | + | 
|  | 64 | +    if (line === undefined) break | 
|  | 65 | +    const [targetSum, data] = line.split(': ') | 
|  | 66 | +    const numbers = data?.split(' ').map(Number) as number[] | 
|  | 67 | + | 
|  | 68 | +    // Find all operator placement combinations | 
|  | 69 | +    const combinations = operatorCombinations(operators, numbers.length - 1) | 
|  | 70 | + | 
|  | 71 | +    // Build the text equation | 
|  | 72 | +    for (let j = 0; j < combinations.length; j += 1) { | 
|  | 73 | +      // Process equation | 
|  | 74 | +      const result = doEquation(numbers, combinations[j] as string[]) | 
|  | 75 | + | 
|  | 76 | +      if (result === Number(targetSum)) { | 
|  | 77 | +        sum += result | 
|  | 78 | +        break | 
|  | 79 | +      } | 
|  | 80 | +    } | 
|  | 81 | +  } | 
|  | 82 | + | 
|  | 83 | +  return sum | 
|  | 84 | +} | 
0 commit comments