亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

Bridge Repair

Dec 22, 2024 am 04:17 AM

Bridge Repair

Advent of Code 2024 Day 7

Part 1

First recursion of the year

At least that's how I intend to earn one gold star today:

  • Start with the full list
  • Check both addition and multiplication
  • For each result, continue with the remainder of the list
  • Until I have either exceeded or matched the total

The difficulty will be in the details.

Let's do this!

Crafting my algorithm

First, I need to parse each line into a list of numbers:

let eqs = input.split('\n').map(line => {
  return [...line.matchAll(/\d+/g)].map(el => +el[0])
})

The first element is the desired total.

The rest are the ordered operands of the equation.

I'll need to account for this in my recursive function.

Here's my recursive function:

function eqChecker(operands, amount, test) {
  if (amount > test) {
    return false
  } else if (amount == test && operands.length == 0) {
    return true
  } else if (operands.length) {
    let copy = operands.slice()
    let first = copy.shift()
    return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test)
  }
}

And here is the reduce that uses it:

let part1 = eqs.reduce((count, eq) => {
  if (eqChecker(eq.slice(2), eq[1], eq[0])) {
    count += eq[0]
  }
  return count
}, 0)

As I hoped but never expect, it generates the correct answer for the example input!

Will it finish processing my puzzle input?

And if so, will it generate the correct answer?

I'm honestly not sure...

IT DID!!!

Woah!!!

As excited as I am, I fear that the next part will either add more operators, or require some advanced CS to make recursion no longer a viable solution.

Part 2

Totally unexpected! And way more difficult

How am I even going to do this?

...

A few days later...

A recap of my thought process:

  • Is it as simple as adding a third clause to my return condition? Nope
  • Is my Part 1 recursive function even configured correctly for success? Nope
  • Oh no, is it even feasible to accrue an amount that's a result of prior operations? Nope
  • Am I really going to have to approach this with a new strategy? Yup

Considering all new variations

For this equation:

292: 11 6 16 20

These are all possible equations given the three operators:

11 
11+6 
11+6+16 
11+6+16+20 
11+6+16*20 
11+6+1620 
11+6*16 
11+6*16+20 
11+6*16*20 
11+6*1620 
11+616 
11*6 
11*6+16 
11*6+16+20 
11*6+16*20 
11*6+1620 
11*6*16 
11*616 
116 
116+16 
116+16+20 
116+16*20 
116+1620 
116*16 
11616 

Perhaps I can build up a string of each equation and manually evaluate it inside my recursive function.

For instance:
I start with an empty string in the outer-most function call:

""

From there, I create three variations using the next number:

"" + "+N"
"" + "*N"
"" + "N"

Hmm, but this won't work for the first number.

I need to start my first function call with the first number, not an empty string:

"N"

Same thing from there:

"N" + "+N"
"N" + "*N"
"N" + "N"

Ya, that should work.

By the end, I'll have these sample variations, all evaluable:

let eqs = input.split('\n').map(line => {
  return [...line.matchAll(/\d+/g)].map(el => +el[0])
})

Skip to: I coded it...and discovered a bigger issue

I wrote code that successfully generates all variations of equation.

function eqChecker(operands, amount, test) {
  if (amount > test) {
    return false
  } else if (amount == test && operands.length == 0) {
    return true
  } else if (operands.length) {
    let copy = operands.slice()
    let first = copy.shift()
    return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test)
  }
}
  • i is used to walk down the list of numbers
  • The last clause only proceeds if i is before or at the second-to-last index

The function gets four values:

  1. A copy of the list of numbers, minus the expected total
  2. The next index
  3. The equation string with one of three strings concatenated to it
  4. The same test number

I call the function using nearly the same signature as in Part 1:

let part1 = eqs.reduce((count, eq) => {
  if (eqChecker(eq.slice(2), eq[1], eq[0])) {
    count += eq[0]
  }
  return count
}, 0)

The difference is in what I pass as arguments:

  1. The list without the expected total amount
  2. Start at index 0
  3. A string containing the first number
  4. The expected total amount

Great news:

  • It generates all equation variations

Bad news:

  • It evaluates all equations using PEMDAS, not left-to-right

I should have known better...that the built-in JavaScript evaluator would default to the correct order of operations, not left-to-right.

This really throws an even bigger wrench into my algorithm:

  • I'm going to have to break each equation apart and evaluate it portion-by-portion

Uggghhh.

Thankfully, I think I know just how to do that.

Doing maths manually

I need to get JavaScript to evaluate an equation like this:

292: 11 6 16 20

In this order:

11 
11+6 
11+6+16 
11+6+16+20 
11+6+16*20 
11+6+1620 
11+6*16 
11+6*16+20 
11+6*16*20 
11+6*1620 
11+616 
11*6 
11*6+16 
11*6+16+20 
11*6+16*20 
11*6+1620 
11*6*16 
11*616 
116 
116+16 
116+16+20 
116+16*20 
116+1620 
116*16 
11616 

I'd like to split that equation into its parts:

""

The only way I see how is with this triple-chained expression:

"" + "+N"
"" + "*N"
"" + "N"

I pad each operator with white space only to use it as a separator.

A fact about this list of equation parts:

  • It will always contain an odd amount of items that is 3 or greater

How can I leverage that fact in some loop that iterates through each operand-operator-operand pair?

Here's my idea:

  • Remove the first three items
  • Join them as a string and evaluate that as a math expression
  • Reattach the result at the beginning of the equation list
  • Repeat until the equation list is empty

Here's to hoping it works!

My working math simulator in JavaScript:

"N"

Great news:

  • It's showing me the expected computed values

Bad news:

  • I'm still not getting the correct answer for one equation in the example input

The example answer can't be wrong...can it??

The answer I keep generating is about 7k short of the expected answer.

That makes me think my algorithm isn't identifying this equation as correct:

let eqs = input.split('\n').map(line => {
  return [...line.matchAll(/\d+/g)].map(el => +el[0])
})

In the explanation of the example input, this is the winning equation:

function eqChecker(operands, amount, test) {
  if (amount > test) {
    return false
  } else if (amount == test && operands.length == 0) {
    return true
  } else if (operands.length) {
    let copy = operands.slice()
    let first = copy.shift()
    return eqChecker(copy, amount + first, test) || eqChecker(copy, amount * first, test)
  }
}

My algorithm evaluates that equation and generates this outcome:

let part1 = eqs.reduce((count, eq) => {
  if (eqChecker(eq.slice(2), eq[1], eq[0])) {
    count += eq[0]
  }
  return count
}, 0)

That's because my algorithm runs like this:

292: 11 6 16 20

I don't see how it could be any other number.

So...I Google'd.

And I found my answer, which was hiding in plain site in the explanation, as always:

All operators are still evaluated left-to-right.

I was pre-concatenating values with each recursive function call.

Instead, my algorithm should be doing this:

11 
11+6 
11+6+16 
11+6+16+20 
11+6+16*20 
11+6+1620 
11+6*16 
11+6*16+20 
11+6*16*20 
11+6*1620 
11+616 
11*6 
11*6+16 
11*6+16+20 
11*6+16*20 
11*6+1620 
11*6*16 
11*616 
116 
116+16 
116+16+20 
116+16*20 
116+1620 
116*16 
11616 

Now that I understand what's supposed to happen, can I adjust my algorithm to match that processing behavior?

Left-to-right...for real this time

Thankfully, adjusting my algorithm was relatively easy.

I added a replaceAll() clause to account for ||.

The new while loop where I process every three items looks like this:

""

And I adjusted my return statement's || clause to include those characters, instead of instantly-concatenating the two numbers.

Testing and re-testing

I ran the algorithm on the example input.

It finally generated the correct answer!!

What a relief!!

I wonder if it will finish running and generate the correct answer on my puzzle input.

Pressing run...

...

...

I got an answer!

It's huge, so that's probably a good sign.

Is it the correct answer?

...

No. Too high.

Bummer.

Am I missing an edge case?

My condition for a winning equation is simply that the processed math equals the test amount.

But, what if one of the variant equations allows for a subset of numbers to generate a correct answer?

To catch and exclude this scenario, I updated my if condition to include one more clause:

"" + "+N"
"" + "*N"
"" + "N"

This way, only if all numbers are processed and the resulting amount equals the test number, will the equation be counted.

The big question:

  • Does this change the answer I get?

Pressing run again...

...

Hmm, it sure still looks like the same answer.

Oh, wait, there are two digits near the end that are different!

My new answer is exactly 80 less than before.

Is there an equation with 80 as the expected amount?

Yes!

"N"

Is there a way to make 80 without using all the numbers?

Yes!

"N" + "+N"
"N" + "*N"
"N" + "N"

Was this the sole edge case that I needed to exclude?

Submitting my new answer...

IT'S CORRECT!!!

Woohoo!!!

I did it!!!

That. Was. Exhausting. And exhilarating. And really run. And challenging.

And every reason why I love doing these puzzles.

Onward to the next one!

The above is the detailed content of Bridge Repair. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

PHP Tutorial
1488
72
How to make an HTTP request in Node.js? How to make an HTTP request in Node.js? Jul 13, 2025 am 02:18 AM

There are three common ways to initiate HTTP requests in Node.js: use built-in modules, axios, and node-fetch. 1. Use the built-in http/https module without dependencies, which is suitable for basic scenarios, but requires manual processing of data stitching and error monitoring, such as using https.get() to obtain data or send POST requests through .write(); 2.axios is a third-party library based on Promise. It has concise syntax and powerful functions, supports async/await, automatic JSON conversion, interceptor, etc. It is recommended to simplify asynchronous request operations; 3.node-fetch provides a style similar to browser fetch, based on Promise and simple syntax

JavaScript Data Types: Primitive vs Reference JavaScript Data Types: Primitive vs Reference Jul 13, 2025 am 02:43 AM

JavaScript data types are divided into primitive types and reference types. Primitive types include string, number, boolean, null, undefined, and symbol. The values are immutable and copies are copied when assigning values, so they do not affect each other; reference types such as objects, arrays and functions store memory addresses, and variables pointing to the same object will affect each other. Typeof and instanceof can be used to determine types, but pay attention to the historical issues of typeofnull. Understanding these two types of differences can help write more stable and reliable code.

JavaScript time object, someone builds an eactexe, faster website on Google Chrome, etc. JavaScript time object, someone builds an eactexe, faster website on Google Chrome, etc. Jul 08, 2025 pm 02:27 PM

Hello, JavaScript developers! Welcome to this week's JavaScript news! This week we will focus on: Oracle's trademark dispute with Deno, new JavaScript time objects are supported by browsers, Google Chrome updates, and some powerful developer tools. Let's get started! Oracle's trademark dispute with Deno Oracle's attempt to register a "JavaScript" trademark has caused controversy. Ryan Dahl, the creator of Node.js and Deno, has filed a petition to cancel the trademark, and he believes that JavaScript is an open standard and should not be used by Oracle

What is the cache API and how is it used with Service Workers? What is the cache API and how is it used with Service Workers? Jul 08, 2025 am 02:43 AM

CacheAPI is a tool provided by the browser to cache network requests, which is often used in conjunction with ServiceWorker to improve website performance and offline experience. 1. It allows developers to manually store resources such as scripts, style sheets, pictures, etc.; 2. It can match cache responses according to requests; 3. It supports deleting specific caches or clearing the entire cache; 4. It can implement cache priority or network priority strategies through ServiceWorker listening to fetch events; 5. It is often used for offline support, speed up repeated access speed, preloading key resources and background update content; 6. When using it, you need to pay attention to cache version control, storage restrictions and the difference from HTTP caching mechanism.

Handling Promises: Chaining, Error Handling, and Promise Combinators in JavaScript Handling Promises: Chaining, Error Handling, and Promise Combinators in JavaScript Jul 08, 2025 am 02:40 AM

Promise is the core mechanism for handling asynchronous operations in JavaScript. Understanding chain calls, error handling and combiners is the key to mastering their applications. 1. The chain call returns a new Promise through .then() to realize asynchronous process concatenation. Each .then() receives the previous result and can return a value or a Promise; 2. Error handling should use .catch() to catch exceptions to avoid silent failures, and can return the default value in catch to continue the process; 3. Combinators such as Promise.all() (successfully successful only after all success), Promise.race() (the first completion is returned) and Promise.allSettled() (waiting for all completions)

Leveraging Array.prototype Methods for Data Manipulation in JavaScript Leveraging Array.prototype Methods for Data Manipulation in JavaScript Jul 06, 2025 am 02:36 AM

JavaScript array built-in methods such as .map(), .filter() and .reduce() can simplify data processing; 1) .map() is used to convert elements one to one to generate new arrays; 2) .filter() is used to filter elements by condition; 3) .reduce() is used to aggregate data as a single value; misuse should be avoided when used, resulting in side effects or performance problems.

JS roundup: a deep dive into the JavaScript event loop JS roundup: a deep dive into the JavaScript event loop Jul 08, 2025 am 02:24 AM

JavaScript's event loop manages asynchronous operations by coordinating call stacks, WebAPIs, and task queues. 1. The call stack executes synchronous code, and when encountering asynchronous tasks, it is handed over to WebAPI for processing; 2. After the WebAPI completes the task in the background, it puts the callback into the corresponding queue (macro task or micro task); 3. The event loop checks whether the call stack is empty. If it is empty, the callback is taken out from the queue and pushed into the call stack for execution; 4. Micro tasks (such as Promise.then) take precedence over macro tasks (such as setTimeout); 5. Understanding the event loop helps to avoid blocking the main thread and optimize the code execution order.

Understanding Event Bubbling and Capturing in JavaScript DOM events Understanding Event Bubbling and Capturing in JavaScript DOM events Jul 08, 2025 am 02:36 AM

Event bubbles propagate from the target element outward to the ancestor node, while event capture propagates from the outer layer inward to the target element. 1. Event bubbles: After clicking the child element, the event triggers the listener of the parent element upwards in turn. For example, after clicking the button, it outputs Childclicked first, and then Parentclicked. 2. Event capture: Set the third parameter to true, so that the listener is executed in the capture stage, such as triggering the capture listener of the parent element before clicking the button. 3. Practical uses include unified management of child element events, interception preprocessing and performance optimization. 4. The DOM event stream is divided into three stages: capture, target and bubble, and the default listener is executed in the bubble stage.

See all articles