[OCP 17 book] | [OCP 11 book] | [OCA 8 book] [OCP 8 book] [Practice tests book] [Blog] [JavaRanch FAQ] [How To Ask Questions] [Book Promos]
Other Certs: SCEA Part 1, Part 2 & 3, Core Spring 3, TOGAF part 1 and part 2
[OCP 17 book] | [OCP 11 book] | [OCA 8 book] [OCP 8 book] [Practice tests book] [Blog] [JavaRanch FAQ] [How To Ask Questions] [Book Promos]
Other Certs: SCEA Part 1, Part 2 & 3, Core Spring 3, TOGAF part 1 and part 2
Jeanne Boyarsky wrote:In World, the indentation of this code misleads about what it does. Since the two forEach() statements are aligned, they imply that they are operating on the same stream.
Jeanne Boyarsky wrote:More importantly, calling map.put() in a forEach isn't good practice. Is there any reason you can't use a collector which would dispense with the inner forEach() entirely.
Jeanne Boyarsky wrote:I'm not a fan of the default method in Mutate. It feels like a hack since it isn't used for legacy code.
salvin francis wrote:I ran that program and it just printed a huge log of dots and zeros !!!
Even a simple JFrame with a single textarea would be great.
salvin francis wrote:I am glad to see that your glider "wraps-around" the world.
salvin francis wrote:minor suggestions: Maybe World.SIZE could have an access modifier (probably public) ?
There are three kinds of actuaries: those who can count, and those who can't.
salvin francis wrote:I looked at your code a bit more in-depth today and the following questions came to my mind :
Why can one not instantiate World ? The only way you are allowing is via a empty() method which generates according to a fixed SIZE of 10 Why is World square ? (as in number of rows=number of columns)
salvin francis wrote:
I see that you have implemented this as a fixed world with cells which are either Alive or Empty. The way I approached this was that I made an implementation which only kept Alive cells. There were no "Empty" cells.
Actually this is what fits in the real world philosophy too. In real life, we would observe a 'petri dish' with some cells. These cells would grow/die depending on various conditions, the 'petri dish' is their domain/world. With the implementation of "Empty" it looks like the world has some "slots" where a cell can reside or not.
Just food for thought![]()
Piet Souris wrote:I also had a look at your code. My first impression is that I get a sense of over-desinging here and there, making things more complex than necessay. Perhaps it is the modern way of dong, I don't know, but for instance this Builder.build() looks a bit cumbersome.
...
About the RegenerationRules, why do you fix the 2 and the 3, given that the class is final? I had a similar class, with two fields: List<Integer> stayAlive and ditto: becomeAlive, that were parameters of my constructor.
Good point, missed it. Thanks for the comments!Piet Souris wrote:...determine the neighbors of a Location... but that method is not foolproof...
Piet Souris wrote:But please report your impressions at the GDCR with your code!
Sresh Rangi wrote:
I don't see what the Regenerable interface is adding. You could replace any call to regenerate like:
with:
Sresh Rangi wrote:For the rules, withLivingNeighbors is required to construct an instance of them. I would think that livingNeighbors is not part of the rules, but the world state that would be passed to the rules instance when it's used.
Sresh Rangi wrote:Also, I would allow the rules class to be subclassed, or configured in some way so you can have different rules.
Gerard Charles wrote:Cell seems to be an enum replacing what is functionally a boolean; the two states (ALIVE/EMPTY) aren't logically intuitive -- that is, I'd expect ALIVE/DEAD or FULL/EMPTY.
Gerard Charles wrote:The symbol field seems to be mixing representative with logic (Not following Model-View-Controller).
Gerard Charles wrote:If each location had a current state and a separate numNeighbors field, you wouldn't need to copy the map -- simply pass through twice. First calculate the number of neighbors, then make a second pass to update the alive/dead state.
Most importantly, Location has too much information about World in it. Make World an interface that tells each location who its neighbors are. This would only have to happen at program startup -- the neighbors don't change during execution.
Piet Souris wrote:I also had a look at your code. My first impression is that I get a sense of over-desinging here and there, making things more complex than necessay. Perhaps it is the modern way of dong, I don't know, but for instance this Builder.build() looks a bit cumbersome.
#1
I wrote:
Here's what might have made sense to me instead:
live_cell_with_three_neighbors_lives_on_in_next_generation()
...
#2
#3
#4
#5
Junilu Lacar wrote:Looked over previous comments and found those made by Piet and Gerald interesting and worth pursuing, which I think you did: you took out knowledge about World from Location and Location.Direction. That's a good start.
Here's another way to push your design and see if there's some more refactoring you can do. I have a sense that there is. Think about having a World that represents a toroidal coordinate system. That is, given a World that is 100 x 100 spaces, then Location.of(0, 0) would be neighbors with (99, 99), (99, 0), (99, 1), (0, 99), (1, 99) as well as the obvious (0, 1), (1, 1), and (1, 0). What would you need to change in your program to account for toroidal cell coordinates like this? How easy/difficult would it be to introduce that change?
There are three kinds of actuaries: those who can count, and those who can't.
#7
#8
#9
Liutauras Vilda wrote:The thought behind that was, that I took some hypothetical future requirement of some extra rules let's say:...
#10
Junilu Lacar wrote:Late to the party, as usual. I will have a look and share my thoughts. In the meantime, I hope you're doing this in preparation for Global Day of Coderetreat which is less than two weeks away as of today. If not, please consider signing up if there's one being hosted near you.
Junilu Lacar wrote:Think about having a World that represents a toroidal coordinate system... What would you need to change in your program to account for toroidal cell coordinates like this? How easy/difficult would it be to introduce that change?
Piet Souris wrote:Interesting. Initially Liutauras had indeed implemented toroidal coordinates, see my remark about the use of the modulo operator. But it looks as if that has been removed.
Junilu Lacar wrote:I think I pulled a brain muscle trying to reach an understanding of what the code in Regenerable.java is trying to say.
What are you trying to say with that code? Can you please explain your thought process there?
Junilu Lacar wrote:
Liutauras Vilda wrote:The thought behind that was, that I took some hypothetical future requirement of some extra rules let's say:...
(Emphasis is mine) The key words that should raise a red flag and start waving it crazily around. Avoid doing that unless you are truly a psychic who can foresee the future. Otherwise, you are just adding unnecessary complexity to your design to accomodate a future that may never materialize. Why waste time and effort doing that? Keep things simple and clean and well-factored enough so that when you do get new requirements, it will be easy to change your code and adapt it to exhibit the new behaviors you need.
Junilu Lacar wrote:I forgot to mention this earlier but I really like the choice of name for the Location.of(int, int) factory method. It is symmetrical with other such methods that have been introduced to the Standard Java Library...
This is a double-edge sword though. You have to make sure you don't break the Principle of Least Astonishment (POLA) by making your method behave in any unexpectedly different ways from the well-known API's behavior.
Junilu Lacar wrote:I think I'll give this as a challenge for GDCR this year: Write a functional implementation of GoL where you're not changing the state of any object. That is, all objects created in your implementation should be immutable.