Bowl a Strike explainer

The aim of this puzzle: Make the ball roll and knock down all the pins.
Walkthrough of the solution: You see that in the `bowlBall` function of the starter code has a `.transition()` with nothing after it – it should at least have an `.attr()`, and specifically, `'cy'` should go to zero so that the ball moves toward the top of the screen and toward the pins. The other part to add to this command is changing the duration. Without `.duration()` the transition will default to 250ms – set the duration to 2000ms by attaching `.duration(2000)` to the `.transition()`. Finally, the `bowlBall` should be complete, but it won’t do anything until it gets called into action, and you want it to run when you tap on the ball – this is the time to use `.on('click',...)`! You want `bowlBall` to run when you click on the `ball`, so the command looks like: `ball.on('click', bowlBall);` Remember you can read the `.on('click',...)` command backwards to make sure you have each part in the right place.
Sample code solution:
(Tap below to reveal)

``````function bowlBall(){
ball.transition()
.duration(2000)
.attr('cy', 0);
knockPins();
}

ball.on('click', bowlBall);
``````

JavaScript Concepts: Code Block (function), Identifiers, Member Expression
D3 Concepts: .transition(), .duration(), .attr(‘cy’,), .on(‘click’,)
Additional Code (hidden code that runs before the puzzle’s code):

``````var floor = svg.append('rect').attr('fill', 'tan').attr('width',190).attr('height', 300);
var laneDivider1 = svg.append('rect').attr('fill', 'red').attr('width', 5).attr('height', 300).attr('x', 175);
var laneDivider2 = svg.append('rect').attr('fill', 'red').attr('width', 5).attr('height', 300).attr('x', 10);

// First Row
var pin1 = svg.append('circle').attr('r', 10).attr('fill', 'white').attr('cx', 95).attr('cy', 110);

// Second Row
var pin2 = svg.append('circle').attr('r', 10).attr('fill', 'white').attr('cx', 80).attr('cy', 80);
var pin3 = svg.append('circle').attr('r', 10).attr('fill', 'white').attr('cx', 110).attr('cy', 80);

// Third Row
var pin4 = svg.append('circle').attr('r', 10).attr('fill', 'white').attr('cx', 65).attr('cy', 50);
var pin5 = svg.append('circle').attr('r', 10).attr('fill', 'white').attr('cx', 95).attr('cy', 50);
var pin6 = svg.append('circle').attr('r', 10).attr('fill', 'white').attr('cx', 125).attr('cy', 50);

// Fourth Row
var pin7 = svg.append('circle').attr('r', 10).attr('fill', 'white').attr('cx', 50).attr('cy', 20);
var pin8 = svg.append('circle').attr('r', 10).attr('fill', 'white').attr('cx', 80).attr('cy', 20);
var pin9 = svg.append('circle').attr('r', 10).attr('fill', 'white').attr('cx', 110).attr('cy', 20);
var pin10 = svg.append('circle').attr('r', 10).attr('fill', 'white').attr('cx', 140).attr('cy', 20);

// Moving to draw on top of pins, and cy from 250 to 200 because ball was off screen- Frankie
var ball = svg.append('circle').attr('r', 20).attr('cx', 95).attr('cy', 190).attr('fill', 'blue');

function knockPins(){
pin1.transition().delay(725).remove();

pin2.transition().delay(800).remove();
pin3.transition().delay(800).remove();

pin4.transition().delay(875).remove();
pin5.transition().delay(850).remove();
pin6.transition().delay(875).remove();

pin7.transition().delay(925).remove();
pin8.transition().delay(900).remove();
pin9.transition().delay(900).remove();
pin10.transition().delay(925).remove();
}
``````
1 Like

The ball will move automatically although I haven’t click on the ball yet

1 Like

Hello,
Can you please paste your code? So we can analyze it to see where there might be an issue? Based upon the code sample it should be triggered once a click event happens which basically means either a mouse or finger press of the ball object. I hope that helps

Thanks,
Ahsen

1 Like

I have find the mistake that I have made. Thanks!

1 Like

Hello all ,

I have a stupid question to ask. I wrote the same code and passed, but I was wondering why my pins disappeared after my ball already ran to the top… Looked not natural enough lol thanks!

The `knockPins` function is defined in some additional code that runs right before your code runs. It simply removes each pin after a simple time delay. These delay times could be adjusted to give a more natural look – making the outer pins remove slower than the center line pins.

``````function knockPins(){
pin1.transition().delay(750).remove();

pin2.transition().delay(800).remove();
pin3.transition().delay(800).remove();

pin4.transition().delay(850).remove();
pin5.transition().delay(850).remove();
pin6.transition().delay(850).remove();

pin7.transition().delay(900).remove();
pin8.transition().delay(900).remove();
pin9.transition().delay(900).remove();
pin10.transition().delay(900).remove();
}
``````

–Frankie

2 Likes

I made the same mistake, it was that i typed bowlball after click, but i chose the blue one instead of the green one… Which is the difference btw both? First attempt the green one was greyed out, that lead me to choose the blue one instead

When you declare a function like `function bowlBall()`, 2 buttons are created:

• Function Call: `bowlBall()`, colored blue and has parentheses at the end
• Function Identifier: `bowlBall`, colored grey and does not have parentheses

The function call means, “run this function now”.
You can think of the `bowlBall` identifier as a shortcut to all the code that comes after `function bowlBall`. It is like a variable that stores all the code from the function definition including what parameters it uses.

When you put `ball.on('click',...)` in your code, it takes the function you place in the `...` and combines it with some code that can detect a “click” or “tap” and attaches that code to the `ball`. You want to use the function identifier inside of `.on('click', bowlBall)` because that references all the code that defines the function. If you do `.on('click', bowlBall())`, the `bowlBall` function will run immediately while attaching the “on click” event listener.

–Frankie

3 Likes

Really good explanation, thanks! So, if we use listeners, like .on(‘click’), we always have to use function identifier in it to prevent immediate execution?

Yes. Although, there could be times when you want your function to run right away. For example:

``````function bowlBall(){
return function contents(){
ball.transition().duration(2000).attr('cy', 0);
knockPins();
}
}
ball.on('click', bowlBall());
``````

I stuck the meat of the `bowlBall` function into a new arrow function called `contents`. Calling `bowlBall()` now basically transforms it into the function definition for `contents`. This would give you the same behavior as the normal solution. This is a messier way to do this puzzle, but there are scenarios when it makes sense for a function to return another function.

–Frankie

1 Like

Hi why can’t I pass this one… I checked answer tho

This seems to be a bug that was also reported here. We’re trying to figure out how to reproduce this issue. If you remember the steps you took to get this error, it would help us a lot. To fix the problem for now, you’ll have to use the reset button.

–Frankie

2 Likes

What is the difference between
`ball.transition().duaratiton(2000).attr(“cy”, 0)` and
`ball.transition().attr(“cy”, 0).duration(2000)` ?

I tried both and they produce similar results. Is there norm for order for these in JavaScript or D3.js?

You’re correct; those two examples will produce the same result, and both are readable. I would suggest keeping the order the same throughout your code, but there’s no standard order.

–Frankie

1 Like

Hello, I’m stuck! Here’s my code, which is as close as I can get to the code provided in help

The `.on('click',...)` should be attached to a shape – the shape you click on to trigger the function. You’ll want to change `bowlBall.on(...)` to `ball.on(...)`.

–Frankie

can u tell me whats wrong?

The `.duration()` is a property of a `.transition()`; it doesn’t make sense to have it on its own. You can think of `ball.transition()` as “attaching a transition to the ball”. Then you attach an `attr` to the `transition` to tell it what it should be animating. To change how long the animation (`transition`) takes, you want to apply a `duration` to it. If you move the `.duration(2000)` to be attached to the `.transition()` it will work. You can also attach the `.duration(2000)` to the `attr` since the `attr` is also connected to the `transition`.

–Frankie

I am having the same issue, I’m glad it’s not me… hehehe!

Hey there. It looks like you make one `ball.transition().attr('cy', 0);` and another is `ball.duration(2000);`.

Delete the `ball.duration(2000);`. And then, on
the `ball.transition().attr('cy', 0);`.Rewrite the code below. Tap to reveal.

`ball.transition ().duration (2000).attr ('cy', 0)`