This week's book giveaway is in the Reactive Progamming forum.
We're giving away four copies of Reactive Streams in Java: Concurrency with RxJava, Reactor, and Akka Streams and have Adam Davis on-line!
See this thread for details.
Win a copy of Reactive Streams in Java: Concurrency with RxJava, Reactor, and Akka Streams this week in the Reactive Progamming forum!
  • 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
  • Junilu Lacar
  • Jeanne Boyarsky
  • Bear Bibeault
Sheriffs:
  • Knute Snortum
  • Tim Cooke
  • Devaka Cooray
Saloon Keepers:
  • Ron McLeod
  • Stephan van Hulst
  • Tim Moores
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Piet Souris
  • Frits Walraven
  • Ganesh Patekar

Is there a way to compare two objects on the same Map?

 
Ranch Hand
Posts: 301
6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I tried Googling for this but everything that comes up is how to compare one Map to another but that's not what I want.   Two requirements of my assignment has me comparing whether a Vampire in a specific position or not .   If a Player moves to a Vampire's position then the Player kills the Vampire.  If a Vampire moves to a position but another Vampire is already in that spot, the move is not executed.

I can compare Player to Vampire but my Vampires are a type List.  On Line 132 I create a Map for the Vampire's positions which I already did for the Players at line 32.    However I do not think there is a way to compare each Vampire on a Map type against each other is there?     Is there another way I can compare a Vampire object against another Vampire object?   I am thinking that perhaps I shouldn't have used a List initially at line 86.

Thank You very much for your help.






















 
Marshal
Posts: 65782
250
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Don't call your monsters Character. There already is a class of that name.

Two Vampires on the same square? Just as well I have two jugular veins: one on the left and one on the right. A third Vampire wouldn't work; there would be nothing left for it to bite.
What information do you keep about location in the Vampire object? I see you have row and column fields. Can you create a Location class?
What are you doing about Vampire equality? (Apart from the fact that vampires can't vote?) Have you defined an equals() method? There are eight bullet points in that link. I know you can only see five at the moment, but I can see eight. They are all very simple to understand
  • 1: Reflexivity: any object is equal to itself
  • 2: Symmetry: calling x.equals(y) and y.equals(x) give the same result
  • 3: Transitivity: if x.equals(y) and y.equals(z), then x.equal(z) too
  • 4: Consistency: You always get the same result if nothing else changes
  • 5: Consistency (2): If you always get the same result, your equals() method mustn't throw any exceptions
  • 6: Non-nullity: An object which exists is not equal to an object which doesn't exist
  • 7: Overriding: It says override this method. Always override equals and don't overload it
  • 8: Hash codes: You must also override hashCode()
  • The reason for overriding equals() is that it is used by most Collections Framework classes to determine equality amongst their contents. For three useful resources about equals, see this recent post.
    HashMap also uses the hash code to insert keys, so it will fail miserably if you don't override hashCode() correctly. It will fail just as badly if your keys change their state and thereby their hash codes, which is why this link (4th paragraph) warns against using mutable objects as keys. You may need a location and your grid records which locations are vacant and which occupied.
    What does your Map used to contain locations mean? Is that the best way to store locations in your grid? Since a Map has one key‑one value, you can&apost; get two vampires onto the same row, so your grid will look like some sort of escape from the n Queens puzzle.

    I know how to avoid your vampires (lines 14‑15). I simply work out whether your indices are 0‑based or 1‑based, and hide in the opposite corner. How are lines 39 and 50 going to work when you have already reached the bottom row?
     
    Ranch Hand
    Posts: 30
    1
    MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    judging from your text it might be sufficient to use the 'instanceof' operator. Saves a lot of pain.
     
    Campbell Ritchie
    Marshal
    Posts: 65782
    250
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I start worrying whenever I see instanceof. It makes me suspect there is a problem with the inheritance design. One of the few places where instanceof is respectable is inside the equals() method.
     
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    First of all, nice job on decomposing your program into many (mostly) small methods. It's refreshing to see this kind of work from a novice. Well done. You also have quite a few composed methods, so good job on that, too!

    As for comparing one Vampire with another Vampire object, I don't think you really need to go through all that trouble.

    If I were trying to do this, I'd probably not worry about the internal representation up front. Instead, I'd try to experiment with code I'd want to be able to write. Once I figure out what my intent is, then I'll worry about what implementation I'd use that would best support it.

    For example, I might experiment with this first:

    At this point, I already have a sense that I don't really need to override equals() and hashCode() because I may be able to use reference equality (the default Object.equals() or even just ==) to see if there's a different object in that position. This will make my implementation much simpler. From there, I'd simply want to write the following to "make a move":

    I know this may be a significant departure from your current direction but if it were me, I'd rather make that trip rather than continue to paint myself into a corner with an overly-complex design approach.
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Jan Daermann wrote:judging from your text it might be sufficient to use the 'instanceof' operator. Saves a lot of pain.


    Not necessarily. As Campbell suggested, the use of instanceof should be treated as a red flag. In programs like this, it's a big red flag that indicates the improper use of polymorphism (including not using it at all).
     
    Campbell Ritchie
    Marshal
    Posts: 65782
    250
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Junilu Lacar wrote:. . . to see if there's a different object in that position. . . ..

    Surely every monster object knows where it is, so if a different square is occupied, it must be occupied by something else.
    Of course, that sort of test won't tell you whether it is a rival monster or a potential victim occupying that square.
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Campbell Ritchie wrote:Surely every monster object knows where it is, so if a different square is occupied, it must be occupied by something else.


    There's not a right or wrong, just a matter of perspective, at least when it comes to these things. I suppose you could also imagine some kind of code you'd like to write to be able to express that idea.

    Of course, that sort of test won't tell you whether it is a rival monster or a potential victim occupying that square.


    Again, I imagine the kind of code I'd like to write:

    With that, my first instinct would be to overload kills():

    That would suffice for a small set of game player types but might start to smell once you start adding more types.
     
    Jan Daermann
    Ranch Hand
    Posts: 30
    1
    MySQL Database Spring Tomcat Server
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Junilu Lacar wrote:

    Jan Daermann wrote:judging from your text it might be sufficient to use the 'instanceof' operator. Saves a lot of pain.


    Not necessarily. As Campbell suggested, the use of instanceof should be treated as a red flag. In programs like this, it's a big red flag that indicates the improper use of polymorphism (including not using it at all).



    What issue do you foresee in this specific case?
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Jan Daermann wrote:What issue do you foresee in this specific case?


    I try not to foresee anything when I'm coding. In this particular case, I actually might start with using instanceof just to get something that works. In the back of my mind though, I'll take a mental note of the smell and start looking out for any problems that it creates for me down the road. If I can get away with that little bit of smelliness with just two types, then I might just go with it. However, if requirements expand and I need to support more types, that's when my mental note starts becoming more weighty in any design considerations.

    Google for why instanceof is a code smell if you want to learn more about the cons of using instanceof instead of polymorphism.
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Campbell Ritchie wrote:Surely every monster object knows where it is, so if a different square is occupied, it must be occupied by something else.


    "Surely" suggests some assumptions that I'd probably have to explore and experiment with first. It might be perfectly reasonable to imagine a vampire knowing where it is but when it comes to OO design, I think of responsibility assignment: assign the responsibility to the object that has most of the information. In this case, what object has the information about location? It's the Position object. I would also think the Position object is responsible for determining if it is occupied and if so, checking whether a certain object occupies it. It's the Tell, Don't Ask Principle.

    If you want to take a different perspective, you could certainly argue that if a Vampire knows what Position it occupies, it would need to manage that information:

    Only when I see this code and other situations where this idea will be expressed will I start to reason whether or not the responsibility has been appropriately assigned.
     
    Lisa Austin
    Ranch Hand
    Posts: 301
    6
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thanks everyone for responding and I apologize for being so late .  Yesterday , work had me going all day so I didn't have a chance to check.   I'll try and respond to everything.
     
    Lisa Austin
    Ranch Hand
    Posts: 301
    6
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Junilu Lacar wrote:First of all, nice job on decomposing your program into many (mostly) small methods. It's refreshing to see this kind of work from a novice. Well done. You also have quite a few composed methods, so good job on that, too!



    Thank you.  I'm trying.   I'm sure there are things I can improve on so if you have any time please feel free to let me know.   I appreciate it.     Also thanks for giving me terms to look at.   I am always saving what I learn to try and learn more.  



    Junilu Lacar wrote:
    As for comparing one Vampire with another Vampire object, I don't think you really need to go through all that trouble.

    If I were trying to do this, I'd probably not worry about the internal representation up front. Instead, I'd try to experiment with code I'd want to be able to write. Once I figure out what my intent is, then I'll worry about what implementation I'd use that would best support it.

    For example, I might experiment with this first:

    At this point, I already have a sense that I don't really need to override equals() and hashCode() because I may be able to use reference equality (the default Object.equals() or even just ==) to see if there's a different object in that position. This will make my implementation much simpler. From there, I'd simply want to write the following to "make a move":

    I know this may be a significant departure from your current direction but if it were me, I'd rather make that trip rather than continue to paint myself into a corner with an overly-complex design approach.



    Okay so it seems in your experiment you would look at the option of whether the position is occupied rather than if Vampire  A  and  Vampire B has the same y,x cords.    I think I also understand that's just an example of what you would try.   If I understand you correctly.  You are suggesting I experiment with coding what I want to do ( I want to know if Vampire A is going to step on Vampire B. )  I'll look at that and Thank you

     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Lisa Austin wrote:If I understand you correctly.  You are suggesting I experiment with coding what I want to do


    Yes, but I'd take that farther. Experiment with coding your intent rather than the implementation.

    For example, with this:

    (I want to know if Vampire A is going to step on Vampire B.)


    You could easily fall into the "implementation mindset" and start writing things like:

    but this isn't intentful programming. Something like this is though:

    See how there are no "formulas" in that code and how it's all about intent? In the other if statement, the instanceof, &&, and != operators make the conditional expression a formula, which is about implementation.

    Also, I'm not saying your approach of having a game character know their position in the game is wrong either. That's what Campbell is also suggesting and the code I experimented with (see my reply above) doesn't look too bad. I would look out for Vampire and Person having too much logic about Position though. If you start to call many different methods (particularly getters) of Position from Vampire and Person, that could be hint of the smell of "envy": that Vampire and Person wish they could do what Position does or know what Position knows. If it starts to look like "envy" then I'd think about moving the responsibility out to the Position object.

    See Feature Envy Code Smell
       
     
    Lisa Austin
    Ranch Hand
    Posts: 301
    6
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Campbell Ritchie wrote:Don't call your monsters Character. There already is a class of that name.

    Two Vampires on the same square? Just as well I have two jugular veins: one on the left and one on the right. A third Vampire wouldn't work; there would be nothing left for it to bite.
    What information do you keep about location in the Vampire object? I see you have row and column fields. Can you create a Location class?
    What are you doing about Vampire equality? (Apart from the fact that vampires can't vote?) Have you defined an equals() method? There are eight bullet points in that link. I know you can only see five at the moment, but I can see eight. They are all very simple to understand

  • 1: Reflexivity: any object is equal to itself
  • 2: Symmetry: calling x.equals(y) and y.equals(x) give the same result
  • 3: Transitivity: if x.equals(y) and y.equals(z), then x.equal(z) too
  • 4: Consistency: You always get the same result if nothing else changes
  • 5: Consistency (2): If you always get the same result, your equals() method mustn't throw any exceptions
  • 6: Non-nullity: An object which exists is not equal to an object which doesn't exist
  • 7: Overriding: It says override this method. Always override equals and don't overload it
  • 8: Hash codes: You must also override hashCode()
  • The reason for overriding equals() is that it is used by most Collections Framework classes to determine equality amongst their contents. For three useful resources about equals, see this recent post.
    HashMap also uses the hash code to insert keys, so it will fail miserably if you don't override hashCode() correctly. It will fail just as badly if your keys change their state and thereby their hash codes, which is why this link (4th paragraph) warns against using mutable objects as keys. You may need a location and your grid records which locations are vacant and which occupied.
    What does your Map used to contain locations mean? Is that the best way to store locations in your grid? Since a Map has one key‑one value, you can&apost; get two vampires onto the same row, so your grid will look like some sort of escape from the n Queens puzzle.

    I know how to avoid your vampires (lines 14‑15). I simply work out whether your indices are 0‑based or 1‑based, and hide in the opposite corner. How are lines 39 and 50 going to work when you have already reached the bottom row?




    Oh geeze.  I wrote a reply to you but I guess I took too long and the forum timed me out and I lost everything.   Oiy.

    So I'll try again.  Dang it.  

    Thank You for explaining the equals method to me.  I'll take a look at that.  
    The Vampires aren't supposed to step off the board but I haven't yet got to remedying that.  Currently if the Vampire or Player is at position 0 ( row or column ) I have measures in place to prevent them from going to -1 but I haven't quite worked out the opposite way.
    You mention creating a Location class.  I assume that is to be different than my PositionManager class which I use to manage the Vampire and Player object's positions.   If it's to store everyone's location , I'll look at that.  I have a LOT Of code for that already on the Dungeon class so that makes sense.  

    I had better responses earlier   I'll come back and retry .
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Lisa Austin wrote:I assume that is to be different than my PositionManager class which I use to manage the Vampire and Player object's positions.


    Names that include the word "manager" in it are usually sometimes a smell of unclear responsibility and that can lead to these classes being kitchen sinks of sorts, at worst. At best, you could find a more expressive name, like GameBoard or even Dungeon. "PositionManager" is one of those names that looks authoritative and technical but actually falls short of being truly expressive of intent (there's that word again). I know, you could argue "Well, doesn't it express the intent of 'managing' positions?" but "manager" is kind of a generic term along the lines of "Helper" and "Handler".

    And yes, there are quite a few classes out there with those kind of titles that suit their purpose in life fine but just consider trying out other, more specific, names. It might just lead you to writing better, more expressive code.
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Here's an example of code that's very implementation-oriented and probably has some responsibilities assigned improperly:

    First, it's unclear why a Vampire is responsible for turning the String positions to a char[] before passing it to the PositionManager object. What's the intent here and how does that relate to what the method name suggests is the purpose of this method: "Instruct <who?> on position change using these positions." Is there some kind of specific format we're supposed to know about? If so, the code doesn't tell us much. And why do we have to care about that here? The transformation from String to char[] in this method seems odd and completely random.

    This code also has a strong smell of Feature Envy. Notice that it's more interested in what the PositionManager object, boardPositions, can do rather than what a Vampire can do. If anything, I would try this instead:

    At least with this code, the current Vampire gets involved, thus making the code have less of a Feature Envy smell and looking more like this is a delegation (Vampire says, "Hey, PositionManager, I'm now going to move into this new position. Can you please take a note of that? Thanks!")

    My sense is though that something like this makes more sense:
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Looking at your code, it seems you only have one player and a dungeon that can hold a number of Vampire objects. If you only ever have one Player, then it might be simpler if you just make the Player object responsible for knowing its Position in the Dungeon. That way, your Dungeon only ever needs to track Vampire positions and your only checks would be:
     
    Lisa Austin
    Ranch Hand
    Posts: 301
    6
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Junilu Lacar wrote:

    Lisa Austin wrote:I assume that is to be different than my PositionManager class which I use to manage the Vampire and Player object's positions.


    Names that include the word "manager" in it are usually sometimes a smell of unclear responsibility and that can lead to these classes being kitchen sinks of sorts, at worst. At best, you could find a more expressive name, like GameBoard or even Dungeon. "PositionManager" is one of those names that looks authoritative and technical but actually falls short of being truly expressive of intent (there's that word again). I know, you could argue "Well, doesn't it express the intent of 'managing' positions?" but "manager" is kind of a generic term along the lines of "Helper" and "Handler".

    And yes, there are quite a few classes out there with those kind of titles that suit their purpose in life fine but just consider trying out other, more specific, names. It might just lead you to writing better, more expressive code.



    Okay Thank You.  I'll keep that in mind.  Would just "Positions" work since it holds that.  Or maybe "<>Positions"  I just came back and haven't thought of what to rename "Character" too just yet but I figure it would be whatever I decide to change "Character" into.  

     
    Lisa Austin
    Ranch Hand
    Posts: 301
    6
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Junilu Lacar wrote:Here's an example of code that's very implementation-oriented and probably has some responsibilities assigned improperly:

    First, it's unclear why a Vampire is responsible for turning the String positions to a char[] before passing it to the PositionManager object. What's the intent here and how does that relate to what the method name suggests is the purpose of this method: "Instruct <who?> on position change using these positions." Is there some kind of specific format we're supposed to know about? If so, the code doesn't tell us much. And why do we have to care about that here? The transformation from String to char[] in this method seems odd and completely random.

    This code also has a strong smell of Feature Envy. Notice that it's more interested in what the PositionManager object, boardPositions, can do rather than what a Vampire can do. If anything, I would try this instead:

    At least with this code, the current Vampire gets involved, thus making the code have less of a Feature Envy smell and looking more like this is a delegation (Vampire says, "Hey, PositionManager, I'm now going to move into this new position. Can you please take a note of that? Thanks!")

    My sense is though that something like this makes more sense:



    I'm struggling to understand "Implementation-oriented" ,  "implementation mindset" vs intentful programming and coding your intent.   I need to read more about that to get some understanding so I apologize but I can't really speak to that just yet.  I'll come back to it.

    Junilu Lacar wrote:
    First, it's unclear why a Vampire is responsible for turning the String positions to a char[] before passing it to the PositionManager object. What's the intent here and how does that relate to what the method name suggests is the purpose of this method: "Instruct <who?> on position change using these positions." Is there some kind of specific format we're supposed to know about? If so, the code doesn't tell us much. And why do we have to care about that here? The transformation from String to char[] in this method seems odd and completely random.




    Would it be more clear if the instructPositionChange was on the (formally known as ) PositionManager class?   I was thinking that both my Player Class and my Vampire class are the same so I when I started out I created an abstract Character class to extend them from.  As I started working things out I realized that a lot of my code had to do with positions so I figure I would combine those instructions into a PositionManager class because it made sense not to duplicate the code.  Looking at it more now,  I realize the same can said for the instructPositionChange method on each of these and getBoardPosition.  However does that mean I probably do not need that Character class even if Player and Vampire both are ( right now ) Characters in my mind?  





     
    Lisa Austin
    Ranch Hand
    Posts: 301
    6
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Junilu Lacar wrote:Looking at your code, it seems you only have one player and a dungeon that can hold a number of Vampire objects. If you only ever have one Player, then it might be simpler if you just make the Player object responsible for knowing its Position in the Dungeon. That way, your Dungeon only ever needs to track Vampire positions and your only checks would be:



    I need to think about what you are saying here.  At this time I think I'm a bit confused by what you are suggesting but I wanted to acknowledge this.  I'll  get back to you after I think this through.  Thank You
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Let me try to explain what I mean by "implementation-oriented" and "intent-oriented".  It's kind of like this:

    Intent-based: I want an egg, sunny-side up.

    Implementation-based: Open up the refrigerator, take carton marked "Eggs" out, take pan out of cupboard, put on stove, turn knob and light front left burner, put pan on burner that's on, put some oil in pan, wait for pan to heat up, take egg out of the carton, crack the egg, yada, yada, yada, ...

    I teach people to write code that's more "conversational," i.e., it tells a story. That's all a program really is, a story of what you want the computer to do. That's kind of why they call us "authors" sometimes (the JavaDoc tag is @author after all, not @coder or @programmer). The "story" is not really for the computer though. The computer could care less about us expressing intent. The story really is for ourselves and more importantly, for other people who are going to read, and maybe maintain, the code. If you don't tell a clear and concise story that is coherent and cohesive, then you're likely to confuse yourself. Likewise, anybody coming in to your code who can't immediately get a sense of the story you're trying to tell will not find reading your code (and much less, maintaining your code) a good experience. The likelihood of bugs getting introduced to the program is much greater and the aggravation factor of working with the code is higher when the code does not tell a clear, understandable story.

    Implementation-oriented code tends to hide the story (intent) with lots of nitty-gritty details, just like the second description for cooking a sunny side up egg.

    Intent-oriented code gets right to the meat of the story, hiding details in the bowels of private methods. For someone looking to get a general understanding of the program, intent-oriented code is so much more enjoyable to read. It also saves a lot of time. It is also much easier to debug. And more often than not, easier to extend.
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Let's look at that method, instructPositionChange() again.

    First, it's a method in the Vampire class. So right off the bat, the semantics of it are weird. Why would you want to tell a Vampire, "Hey, vampire, instruct position change with this string that represents positions"? What kind of conversation/story is that?

    Wouldn't it make more sense to say, "Hey, Vampire, move to this Position." As code, that would be written as:

    That line of code tells a perfectly logical and semantically sensical story.

    The way you designed it would look something like this:

    I'd be like, "Wait, what?"

    Just the name alone tells me that you were probably more focused on the implementation details of this operation, i.e. how this operation was going to be done, not the intent or what you wanted these objects to do.

    Does that help?
     
    Lisa Austin
    Ranch Hand
    Posts: 301
    6
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Junilu Lacar wrote:Let me try to explain what I mean by "implementation-oriented" and "intent-oriented".  It's kind of like this:

    Intent-based: I want an egg, sunny-side up.

    Implementation-based: Open up the refrigerator, take carton marked "Eggs" out, take pan out of cupboard, put on stove, turn knob and light front left burner, put pan on burner that's on, put some oil in pan, wait for pan to heat up, take egg out of the carton, crack the egg, yada, yada, yada, ...

    I teach people to write code that's more "conversational," i.e., it tells a story. That's all a program really is, a story of what you want the computer to do. That's kind of why they call us "authors" sometimes (the JavaDoc tag is @author after all, not @coder or @programmer). The "story" is not really for the computer though. The computer could care less about us expressing intent. The story really is for ourselves and more importantly, for other people who are going to read, and maybe maintain, the code. If you don't tell a clear and concise story that is coherent and cohesive, then you're like to confuse yourself. Likewise, anybody coming in to your code who can't immediately get a sense of the story you're trying to tell will not find reading your code (and much less, maintaining your code) a good experience. The likelihood of bugs getting introduced to the program is much greater and the aggravation factor of working with the code is higher when the code does not tell a clear, understandable story.

    Implementation-oriented code tends to hide the story (intent) with lots of nitty-gritty details, just like the second description for cooking a sunny side up egg.

    Intent-oriented code gets right to the meat of the story, hiding details in the bowels of private methods. For someone looking to get a general understanding of the program, intent-oriented code is so much more enjoyable to read. It also saves a lot of time. It is also much easier to debug. And more often than not, easier to extend.



    Oh okay I think I get it.  I think I remember reading somewhere that variable names and method names etc should be able to explain what is happening rather than someone relying on code comments.  I was going through the Cattle Drive for a bit but realized I need more  Java experience but I think that maybe where I got it from.

    So I think I get that this would apply to the code itself.
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Lisa Austin wrote:I think I remember reading somewhere that variable names and method names etc should be able to explain what is happening rather than someone relying on code comments.


    The book "Clean Code" by Robert Martin has a whole chapter about naming. That chapter was actually contributed by Tim Ottinger and you can find a number of references to it by searching for "Tim Ottinger choosing good names"

    Choosing good names is difficult when you are thinking about implementation because the implementation details tend to find their way into the name, creating what Joel Spolsky calls a "Leaky Abstraction"

    If you think about it, "Instruct Position Change" is really just a roundabout and "technical-sounding" way to say "Move to", right? The latter, however, is more conversational, more natural to read, and is much easier to understand.

    Another example of a poor name: sizeExceedsArrayMaxIndex() -- this name leaks the implementation detail of a size variable, an array, and an array index limit. Better: atCapacity() -- just tells pure intent, nothing about implementation.

    From your code: checkForVampireAtCoordinates(x, y) -- probably better: position.isOccupiedBy(vampire)
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    probably better: position.isOccupiedBy(vampire)


    And given that statement of intent, it's not hard to finally figure out how to tell if a Vampire occupies a certain position in the dungeon:

    That line of code could certainly work without even overriding the equals() method. And even if you do override equals(), this code should still work.

    See how working through your intent first makes figuring out the best implementation so much easier? And quite frankly, the code is so much more beautiful.
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    I wrote:"Hey, Vampire, move to this Position." As code, that would be written as:


    This one isn't hard to implement either:

    Again, focusing on intent first often leads to much simpler implementations.
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Additional comment, unrelated to your original question.

    Watch out for duplication in your code. This is duplicated code (in the Vampire class):

    You might ask, "How is it duplicated? It's not found anywhere else in the rest of the program... ?"

    Ah, but the idea is. Those same constant values are found in another class, as case labels in a switch statement. Find it yet? That's a violation of the DRY Principle which states "Every piece of knowledge or logic must have a single, unambiguous representation within a system." The idea of what designates up, down, left, right movement is spread across those two classes in your program. Clearly, if you change those values in one place, you have to remember to change them in the other place otherwise your program will break.
     
    Campbell Ritchie
    Marshal
    Posts: 65782
    250
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Junilu Lacar wrote:. . . probably better: position.isOccupiedBy(vampire)

    That would require you to pass a particular Vampire reference to find whether that particular vampire is at a position. What about myVampire.getPosition() instead?
    Would you say position.isOccupied() or position.getOccupant() to find whether the position contains a vampire? The former doesn't tell you what is in that location, and the latter risks returning null from an empty position. So I don't think I have got the right answer here yet.
     
    Campbell Ritchie
    Marshal
    Posts: 65782
    250
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I think you have, at least partially, answered my question already.
     
    Junilu Lacar
    Marshal
    Posts: 14039
    234
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    All those examples were meant to illustrate my points about intent-oriented code vs implementation-oriented code, not necessarily suggestions on how to solve the problem. Once OP understands the difference, we can start talking about how to use intent to guide the design choices you make.

    Here are some intentions I can see:

    - Need to know if Player is moving to a position that is occupied by a Vampire, in which case the Vampire is killed.
    - Need to know if a Vampire is moving to the Player's position, in which case the Player loses a life.
    - Need to know if a Vampire is trying to move to a position already occupied by a Vampire.

    For each one, I would try to write intent-ful code and having done so, I would have a better idea of how I might implement it.
     
    Lisa Austin
    Ranch Hand
    Posts: 301
    6
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Junilu Lacar wrote:All those examples were meant to illustrate my points about intent-oriented code vs implementation-oriented code, not necessarily suggestions on how to solve the problem. Once OP understands the difference, we can start talking about how to use intent to guide the design choices you make.

    Here are some intentions I can see:

    - Need to know if Player is moving to a position that is occupied by a Vampire, in which case the Vampire is killed.
    - Need to know if a Vampire is moving to the Player's position, in which case the Player loses a life.
    - Need to know if a Vampire is trying to move to a position already occupied by a Vampire.

    For each one, I would try to write intent-ful code and having done so, I would have a better idea of how I might implement it.



    I wanted to thank you and Campbell Ritchie for the help.  I know I disappeared for a bit but I got a bit overwhelmed by all of this.  I finally got things working and passed BUT I don't think it's structurally correct which I want to revisit later and try and solve correctly.  However I have two weeks left in this course and I want to try and finish the course .  Hopefully when I go back, I have learned more and will be able to try this assignment again.

    The one thing I found I do and did with another assignment is I make things way more complicated than what the suggested solution gives.    The suggested solution didn't have my PositionManager class, they kept the Vampire positions and Player positions IN their respective classes.  I know Campbell Ritchie had suggested this as well.   My initial thought was Vampire and Player movements were same so I shouldn't repeat it.     However the suggested solution didn't repeat the code even though I thought it would be the same .






     
    You showed up just in time for the waffles! And this tiny ad:
    Java file APIs (DOC, XLS, PDF, and many more)
    https://products.aspose.com/total/java
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!