Skip to content

Instantly share code, notes, and snippets.

@warriordog
Created December 18, 2020 14:00
Show Gist options
  • Save warriordog/7c570c065adad26607e5a26cb828ada8 to your computer and use it in GitHub Desktop.
Save warriordog/7c570c065adad26607e5a26cb828ada8 to your computer and use it in GitHub Desktop.
Solution to Advent of Code 2020 Day 18 Part 1
/**
* @typedef {'*' | '+'} Operator
* @typedef {number} Operand
* @typedef {Array<Operator | Operand | Expression>} Expression
*/
const inputChars = Array.from(
require('fs')
.readFileSync('day18-input.txt', 'utf-8')
.split('\r\n')
.map(line => Array.from(line.replace(/\s/g, '')))
);
const inputExpressions = inputChars.map(line => {
// index of next token in the input
let offset = 0;
function parseSubExpr() {
/** @type {Expression} */
const sequence = [];
while (offset < line.length) {
// get next character from input
const nextChar = line[offset];
offset++;
switch (nextChar) {
case '(': {
sequence.push(parseSubExpr());
break;
}
case ')': {
return sequence;
}
case '+':
case '*': {
sequence.push(nextChar);
break;
}
default: {
sequence.push(parseInt(nextChar));
break;
}
}
}
// end of input
return sequence;
}
// kick off recursion
return parseSubExpr();
});
/**
* @param {Operand} operand1
* @param {Operator} operator
* @param {Operand} operand2
* @returns {number}
*/
function computeExpr(operand1, operator, operand2) {
switch (operator) {
case '*': return operand1 * operand2;
case '+': return operand1 + operand2;
default: throw new Error(`Unknown operator: ${ operator }`);
}
}
/**
* @param {Expression} expression
* @returns {number}
*/
function evalExpression(expression) {
/** @type {Operand} The left-hand side of the expression */
let operand1 = undefined;
/** @type {Operator} Operator to apply to expression*/
let operator = undefined;
// compute expression
for (const token of expression) {
if (typeof(token) === 'string') {
operator = token;
} else if (typeof(token) === 'number') {
if (operand1 === undefined) {
operand1 = token;
} else {
operand1 = computeExpr(operand1, operator, token);
}
} else if (Array.isArray(token)) {
const subExprValue = evalExpression(token);
if (operand1 === undefined) {
operand1 = subExprValue;
} else {
operand1 = computeExpr(operand1, operator, subExprValue);
}
} else {
throw new Error(`Unknown token: '${ token }'`);
}
}
// return total
return operand1;
}
// Part 1
const part1Answer = inputExpressions.reduce((total, expr) => total + evalExpression(expr), 0);
console.log(`Part 1: the total is ${ part1Answer }`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment