• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Bear Bibeault
  • Tim Cooke
  • Junilu Lacar
Sheriffs:
  • Paul Clapham
  • Devaka Cooray
  • Knute Snortum
Saloon Keepers:
  • Ron McLeod
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Frits Walraven
Bartenders:
  • Carey Brown
  • salvin francis
  • Claude Moore

Exercism: Darts  RSS feed

 
Marshal
Posts: 13447
222
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I was browsing through community solutions in the Java track at http://exercism.io and stumbled upon what is probably Knute's solution for the Darts problem: https://exercism.io/tracks/java/exercises/darts/solutions/917be5db60e74d71a03e7aee56762d47

For comparison, my published solution for the same problem uses streams: https://exercism.io/tracks/java/exercises/darts/solutions/5946e5ad593c44b5adcc41bfc5a1e74a

My first iteration was an imperative one with pretty much the same logic. I don't know if you'd be able to access it so I'll paste the code here.

I'd like to discuss the difference in mine and Knute's solution, mainly, the choice to do the calculation in the constructor vs. in the score() method.

I chose to perform the calculation because the class looks like it is designed to be immutable given that the cartesian coordinates are passed to constructor with no getter/setter for them.
 
Junilu Lacar
Marshal
Posts: 13447
222
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just came across this one, from here: https://exercism.io/tracks/java/exercises/darts/solutions/d747168784c24b3c80bb56cceaed075d

One thing I find a bit disconcerting about this logic is that the scores are separated from their corresponding ring boundary distances so there appears to be a misalignment of values based on my reading of the requirements. I think using > instead of >= is costing a bit of clarity and readability.

I do like the use of the Point2D class and the distance() method though.
 
Master Rancher
Posts: 3189
119
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi Junilu,

these kinds of exercises are always fun. My very first thought is: why is everyone using the sqrt? If |x| < radius, then certainly iff x^2 < radius^2?

Knutes solution has the advantage of the simplicity of it. It is immediately obvious what is going on.
Your solution is very elegant, but has the disadvantage of using the max, meaning that all possibilities must be calculated. You can limit it by having the ring-method return a tuple<boolean, score>, and using findFirst. But admittedly, that is quite heavy for a small exercise like this, and to be honest, not very elegant.
I like the solution where a Point2D is used, the best. There, you let Java do the hard work of determining the distance.

My favorite way (and one I've been using recently in determining the next (alphabetically) permutation of a given string) is to use a (static) TreeMap<distance, score>, and using the ceiling method of a TreeMap for the lookup. This way, I let Java also do the lookup part (for the distance, I would use the Point2D).

But the most interesting part for me would be the model that determines where the dart lands on the board (or, in my case, where the dart hits the wall)!
 
Saloon Keeper
Posts: 10136
214
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:I chose to perform the calculation because the class looks like it is designed to be immutable given that the cartesian coordinates are passed to constructor with no getter/setter for them.


Really, either of the two is fine and depends on personal taste. I would go Knute's way, doing the calculation in the score() method. That's because I have a huge allergy for doing more than just validation in the constructor. Usually you would also have accessors for the properties that were given as constructor parameters.

If the calculation is expensive enough that you don't want to do it more than once, you'd usually cache the calculation in a transient field:

Even though the transient keyword is only used in serializable classes, I like to use it to indicate that a field is only used to cache a calculation that is based on other fields.

Of course, this particular application does not warrant caching the calculation, so I would just do the calculation in the score() method every time.

Piet Souris wrote:My very first thought is: why is everyone using the sqrt?


Because they're using the Pythagorean theorem, which is the first thing I would think to use as well.
 
Piet Souris
Master Rancher
Posts: 3189
119
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
@Stephan
If you add the entry: Double.MAX_VALUE, 0 to your map, you then don't need to test for null.

And yes, Pythagoras, but sqr(x) < rad iff x < rad*rad (x >= 0, assuming)

----------------------------------------------------------------

What about using polar coordinates and a suitable BiFunction, in case you want to implement the real darts score?

@Junilu
I was overlooking the fact that if a point is within radius 1, it then is also in the radii 5 and 10. You could check to see in what particular ring a dart has landed, and value the other rings to 0. In that way, you can use findFirst, testing for a positive score. Requires to add a lower bound parameter to your ring functions, and may not be worth it.
 
Junilu Lacar
Marshal
Posts: 13447
222
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yeah, I had to quickly remind myself of Knuth and the root of all evil when I was considering against max(). In this case, it's three values being chosen from so a difference of a couple of milliseconds at most.

Thanks for the elegance comment but I'm still on the fence about the approach. On one hand, the closure was cool and it helps meet the criteria for coding without if statements, which is an exercise I still find challenging. On the other hand, it's not code that most people can immediately understand. Without tests to back the code up, it would be more difficult to understand and maintain for more people than the straightforward imperative code.
 
Junilu Lacar
Marshal
Posts: 13447
222
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Re the use of sqrt(), I saw quite a few other community solutions that avoided it as well, opting to just square everything instead as you suggested. I thought the code made me do more double-takes because calculations related to Pythagorean theory got spread out more across the code. That is, you'd have to work with the square of the distance from center and each ring radius as well. This tended to result in wanting to use more symbolic constants, I think as a way to mitigate confusion caused by dealing with squares rather than the square root values. Remember, the squares represents the relationship whereas the square root is the actual length.

Using squares also creates inconsistency in the naming, making them kind of misleading.

These names are all lies; the values are actually squares of what the names represent. I saw this kind of code a number times in the other solutions.
 
Stephan van Hulst
Saloon Keeper
Posts: 10136
214
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Piet Souris wrote:If you add the entry: Double.MAX_VALUE, 0 to your map, you then don't need to test for null.


Good advice.

And yes, Pythagoras, but sqr(x) < rad iff x < rad*rad (x >= 0, assuming)


I'm not sure what you're trying to say with this. Maybe you can elaborate.
 
Piet Souris
Master Rancher
Posts: 3189
119
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
For non-negative values of x the mapping between x and sqrt(x) is 1-1, so you can avoid the costly sqrt-operation. But as Junilu rightly remarks, it makes it less clear and not worth it.

I'm wondering about this: I usually program 'to the interface', as everyone tells I should, but when it comes to TreeSets and -Maps, without a second of thought I use the implementation, while you use the interface. I wonder why I do this (because TreeMaps are the only implementation? Shorter to type?). Hmmm...
 
Marshal
Posts: 64171
215
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
. . . and why not use this method?
 
Stephan van Hulst
Saloon Keeper
Posts: 10136
214
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
D'oh, Campbell has it. That's definitely the most elegant approach in my book.

Piet, I know exactly what you mean. For the longest time I would write TreeMap if I needed a SortedMap or NavigableMap. I think it has to do with that the most common example we use when we say one should program to an interface is ArrayList vs List, so we have that one drilled into our minds, but not others. Using TreeMap and TreeSet as the formal types of variabless is just a bad habit that we have to get rid of by practicing.
 
Junilu Lacar
Marshal
Posts: 13447
222
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:D'oh, Campbell has it. That's definitely the most elegant approach in my book.


Cow-fully agree.

Solution stolen.  
 
Piet Souris
Master Rancher
Posts: 3189
119
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
@Stepahn
fully agree.

@Campbell
While I prefer the Point.distance, a cow from me as well for reminding us of that method!
 
Junilu Lacar
Marshal
Posts: 13447
222
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Great discussion, by the way. Good insights from everyone. Thanks!
 
Campbell Ritchie
Marshal
Posts: 64171
215
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Piet Souris wrote:. . . a cow from me as well  . . .

Thank you
 
Piet Souris
Master Rancher
Posts: 3189
119
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're welcome!    
 
I love a good mentalist. And so does this tiny ad:
Create Edit Print & Convert PDF Using Free API with Java
https://coderanch.com/wiki/703735/Create-Convert-PDF-Free-Spire
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!