DEV Community

Cover image for My family solves a code challenge 🎁
Lucia Cerchie
Lucia Cerchie

Posted on • Updated on

My family solves a code challenge 🎁

This is a story about what happens when you give a software engineer, a mechanical engineer, and a toddler too much free time...

When I saw @cassidoo 's latest newsletter code challenge, it sparked my interest because it reminded me of old SAT problems I used to practice. Here's the problem:

You have to order wrapping paper for presents. 

Given the length, width, and height of the boxes 
you need to wrap, 
return the number of square feet (or whatever units you want) 
of wrapping paper you need to order. 

Extra credit: allow for other shapes 
of presents and their dimensions!
Enter fullscreen mode Exit fullscreen mode

So, just finding the surface area of an orthotope (gift with rectangular or square sides) could look like this:

function getOrthotopeSurfaceArea(length, width, height) {
    let firstVal = length * width * 2
    let secondVal = length * height * 2
    let thirdVal = height * width * 2

    return firstVal + secondVal + thirdVal
}
Enter fullscreen mode Exit fullscreen mode

And, as Cassidy suggests, we could make this more difficult by incorporating other shapes. I thought of spheres or Klein bottles.

But then, I thought about how this would work if I wanted to wrap a present in real life. How would I account for the overlap? The little bit of extra that you fold over the ends?

This is when I turned to my husband, who has a degree in mechanical engineering, so I guessed he'd be really good at making this challenge harder simplifying the problem.

He came up with this solution:

Image description - lined page with equations and scribbles

^ As you can see, our toddler helped him. She informed us that she had written an 'A, a O, a E'. We took note in case this information became useful later. It did not. But we are a team so the goal is respecting each other's input, even if it is not used in the final version of the solution.

Basically, there are these steps from the notes:

  1. Re-order the length, width, and height from longest to shortest. (This would prove to be the hardest step for me to code.)

  2. Find the overlap, or length and width tolerances. If the length or width was greater than 4 inches, the tolerance would be 2 inches, otherwise it would be half the length or width.

  3. Based on these values, he wrote two equations to solve for the paper's width and length.
    Length = longest entered value + 2(shortest value) + 2(length tolerance)
    Width = shortest entered value + 2(middle value) + 2(width tolerance)

Now, the first thing I did was write the code for step 1, how to order three integer values according to magnitude. It was placeholder stuff -- a bunch of 'if... then' conditions that probably covered it, right? But then my husband came back into the room with all the possibilities listed:

Image description -many boolean expressions written on white paper

Holy boolean expressions, batman! I did not want to type all that out.

So I ended up using a pointer approach for this step.

function arrangeByValue(l, w, h) {
    let arrayToSort = [l, w, h]

    for (let i = 0; i < arrayToSort.length - 1; i++) {
        let firstPointer = arrayToSort[i]
        let secondPointer = arrayToSort[i + 1]

        if (secondPointer > firstPointer) {
            let originalSmallerVal = arrayToSort[i]
            arrayToSort[i] = arrayToSort[i + 1]
            arrayToSort[i + 1] = originalSmallerVal
        }
    }
    return arrayToSort
}
Enter fullscreen mode Exit fullscreen mode

Now I could use that function in my code for steps 2 & 3!

Here's what I did:

function wrapThatGift(length, width, height) {
    let arrangedArray = arrangeByValue(length, width, height)

    let longest = arrangedArray[0]
    let middle = arrangedArray[1]
    let shortest = arrangedArray[2]

    let widthTolerance
    if (middle <= 4) {
        widthTolerance = middle * 0.5
    }
    if (middle > 4) {
        widthTolerance = 2
    }

    let lengthTolerance
    if (length <= 4) {
        lengthTolerance = length * 0.5
    }
    if (length > 4) {
        lengthTolerance = 2
    }
    let paperWidth = shortest + 2 * middle + 2 * widthTolerance
    let paperLength = longest + 2 * shortest + 2 * lengthTolerance

    let wrappingPaperSurfaceArea = paperLength * paperWidth

    return `${paperLength} inches by ${paperWidth} inches `
}
Enter fullscreen mode Exit fullscreen mode

First, I re-arranged the values using the previous function:

    let arrangedArray = arrangeByValue(length, width, height)

    let longest = arrangedArray[0]
    let middle = arrangedArray[1]
    let shortest = arrangedArray[2]
Enter fullscreen mode Exit fullscreen mode

Then, I found the tolerances:

    let widthTolerance
    if (middle <= 4) {
        widthTolerance = middle * 0.5
    }
    if (middle > 4) {
        widthTolerance = 2
    }

    let lengthTolerance
    if (length <= 4) {
        lengthTolerance = length * 0.5
    }
    if (length > 4) {
        lengthTolerance = 2
    }
Enter fullscreen mode Exit fullscreen mode

Then, I translated the equations into code:

    let paperLength = longest + 2 * shortest + 2 * lengthTolerance

    let wrappingPaperSurfaceArea = paperLength * paperWidth
Enter fullscreen mode Exit fullscreen mode

And returned the desired values:

    return `${paperLength} inches by ${paperWidth} inches `
Enter fullscreen mode Exit fullscreen mode

And voila!

When I ran node index.js with a console.logged
wrapThatGift(30, 100, 2)

I got my answer!

108 inches by 66 inches

The original repo is here: https://github.com/Cerchie/crinkle-crinkle

We'd love to hear suggestions for improvement or other ways to solve! (If I go back to this, I'm going to create a toleranceFinder func to reduce that logic) Leave me comments to let me know what you think. :)

Discussion (7)

Collapse
darrylnoakes profile image
Darryl Noakes • Edited on

Could you not just use Array.sort for ordering the dimensions?

Then the relevant piece of code would be:

let [shortest, middle, longest] = [length, width, height].sort((a, b) => a - b);
Enter fullscreen mode Exit fullscreen mode

Oh, by the way (not being trying to be snarky), you have the wrong variable in the tolerance calculation code. You're using middle length instead of width longest.
And for that tolerance logic, you can if/else blocks instead of multiple separateif blocks.
Or just use a ternary expression:

let widthTolerance = (middle <= 4) ? width * 0.5 : 2
let lengthTolerance = (longest <= 4) ? length * 0.5 : 2
Enter fullscreen mode Exit fullscreen mode

And since this is just making sure the tolerance never goes above 2, you can just use this:

let widthTolerance = Math.min(middle * 0.5, 2)
let lengthTolerance = Math.min(longest * 0.5, 2)
Enter fullscreen mode Exit fullscreen mode

Also, you never actually use that calculated area.

As a nice-to-have, you can use const instead of let for most of the variables.

If you want, you can return the length and width as an array or object of numbers instead of a string directly, so you could use it for other purposes as well, and just do the string templating when you log it.

So the code can go from this:

function wrapThatGift(length, width, height) {
    let arrangedArray = arrangeByValue(length, width, height)

    let longest = arrangedArray[0]
    let middle = arrangedArray[1]
    let shortest = arrangedArray[2]

    let widthTolerance
    if (middle <= 4) {
        widthTolerance = middle * 0.5
    }
    if (middle > 4) {
        widthTolerance = 2
    }

    let lengthTolerance
    if (length <= 4) {
        lengthTolerance = length * 0.5
    }
    if (length > 4) {
        lengthTolerance = 2
    }
    let paperWidth = shortest + 2 * middle + 2 * widthTolerance
    let paperLength = longest + 2 * shortest + 2 * lengthTolerance

    let wrappingPaperSurfaceArea = paperLength * paperWidth

    return `${paperLength} inches by ${paperWidth} inches `
}
Enter fullscreen mode Exit fullscreen mode

To this:

function wrapThatGift(length, width, height) {

  const [shortest, middle, longest] = [length, width, height].sort((a, b) => a - b);

  const widthTolerance = Math.min(middle * 0.5, 2)
  const lengthTolerance = Math.min(longest * 0.5, 2)

  const paperWidth = shortest + 2 * middle + 2 * widthTolerance
  const paperLength = longest + 2 * shortest + 2 * lengthTolerance

  return { 
    length: paperLength,
    width: paperWidth
  }
}
Enter fullscreen mode Exit fullscreen mode

Hope this is useful!

P.S.
Add a language tag to you code blocks to get syntax highlighting.

Collapse
cerchie profile image
Lucia Cerchie Author

Thanks Darryl! I didn't google anything, so I ended up with longer syntax for some of these -- your solution pares it down nicely! And the code block suggestion is great for blogging on DEV, thanks!
I believe 'middle' is the correct variable though-- and it's actually length that's wrong -- according to the equation we need the middle length for calculating the width tolerance and the longest length for the length tolerance -- so it should be if (longest <= 4) { ...etc.

Collapse
darrylnoakes profile image
Darryl Noakes

Ah, yes, I understand now.
Will update my comment. 👍

Collapse
poposki317 profile image
Philip Edekobi

Wow

Collapse
raibtoffoletto profile image
Raí B. Toffoletto

Loved this. Great team work!!!

Collapse
bvince77 profile image
bvince77

This looks like fun. I really want to try it myself. Never would have thought of doing this, but it's a great problem. Thanks for sharing!!!

Collapse
narnillian profile image
Narnillian

Suggestion: set overlap to ½ of length & width no matter what, then if it's greater than 2 set it back down to 2.
This is very interesting. I'm definitely signing up for that newsletter.