anyone working through the do-stuff chapter?
I’m having trouble following what’s happening within the hobbit violence section
the (loop … ) part makes sense. But I can’t follow the let part
Are you doing the online version of Brave? Can you link to the part you’re having trouble with?
Yeah, I’m doing the online version. https://www.braveclojure.com/do-things/#Hobbit_Violence
basically I don’t quite understand let or loop/recur
actually, maybe I’m jumping to asking questions too soon. 🙂 I’ll keep struggling some more
I've set a reminder for myself to check in again once I'm off work.
thanks!
Back to the violence here: https://www.braveclojure.com/do-things/#Hobbit_Violence
I think I figured it out, but I don’t understand how it weights the hits based on the body part size
I tried to put comments to explain what I think is happening
; here we define a function called hit that takes one parameter asym-body-...;
; it's going to return the body part that we want to hit
(defn hit
[asym-body-parts]
; let defines 3 scoped variables, it looks like it happens in order
; first, sym-parts is defined as the output of the better-sym... function
; second, body-part-size is the sum of all body parts
; target is a number < body-part-size...
(let [sym-parts (better-symmetrize-body-parts asym-body-parts)
body-part-size-sum (reduce + (map :size sym-parts))
target (rand body-part-size-sum)]
; now we start he loop, the [[]] causes destructuring, we take just the
; first element from sym parts and assign it to "part" and "remaining"
; for tail-recursion
; we accumulate size
(loop [[part & remaining] sym-parts
accumulated-size (:size part)]
(if (> accumulated-size target)
; if acc-size > target, then we've found a large enough body part
part
; otherwise recurse and add up the size of the next remaining item
(recur remaining (+ accumulated-size (:size (first remaining))))))))
it seems to me like this will hit the next body part in the list after the accumulated weight of those parts listed beforehand reaches the target
so it’s not exactly a weighted likelihood of hitting a larger part
or … more likely, I don’t get it
No, I think you're understanding it correctly. Maybe it would help to picture it graphically. Imagine we've got 4 body parts of different sizes, represented by an vector like this: [1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 3 3 3 4 4 ]. Body part #1 is the biggest, so it takes up twice as much space in the vector as body part #2 for example. If I've counted right, that's 20 elements in the array. So now we pick a random number between 0 and 19 (since vectors are zero based). On average, it'll pick body part 1 half the time since it occupies half the vector. Body part 2 occupies about 25% of the vector, so it would get picked a quarter of the time.
So the code above is basically walking through the vector and saying "Did our random target land in the first 10 element of the vector? No? Ok, let's look at the other half of the vector."
By subtracting 10 from the target, and dropping off the first 10 elements of the vector, we can continue to check whether the target landed in the next 5 elements, i.e. body part 2.
Is that clear? It all seems so clear in my head, but it's been a long day and I'm afraid I'm just confusing the issue with my graphical metaphor.
Let me try an even more graphical example. Suppose target
is 13. So, to use my graph metaphor, that would look like this:
[1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 3 3 3 4 4 ]
[= = = = = = = = = = = = = ^ ] ;; target
So target
is 13, and the :size
of body part 1 is 10. So we know it didn't hit body part number 1, and we can discard it
[X X X X X X X X X X 2 2 2 2 2 3 3 3 4 4 ]
[X X X X X X X X X X = = ^ ] ;; target
Let's just remove all those X's to clean things up.
[ 2 2 2 2 2 3 3 3 4 4 ]
[ = = ^ ] ;; target
So, we removed 10 from target
to account for the 10 elements we deleted, since they were body part 1. That leaves us with a target
of 3, and we're ready to check body part 2. The :size
of body part 2 is 5, and the target is less than that, so boom, there's our hit.
Or another way to put it is that by subtracting the :size
of body part 1 from the target
of 13, we're keeping the pointer lined up with the original target.
Does that help or am I just muddying the waters here?
@manutter51 that made sense. But is that vector sorted? I thought it wasn’t sorted which makes it like:
[1 1 1 1 1 1 1 2 2 3 3 3 3 3 3 3 3 3 4 4 4 5 5 5 5 5 5 5 5 5 ]
also, thanks so much for making that explanation.
if the vector is sorted, could you point out where that happens? (That would help me understand)