-1

I asked similar question earlier this morning, and for whatever reason, I'm not getting a complete answer to my question. I'll ask it a different way.

I was attempting to understand Eric Lippert's blog series Wizard and Warriors and see the difficulties that can happen when you try to use the type system to encode the rules of a game.

Suppose I have a Weapon class and a Character class.

public abstract class Weapon 
{
    private String name;
    private int damage;

    public abstract void attack(Character character)
} 


 public abstract class Character
 {
     public final boolean tryCarry(Weapon weapon)
     {
         // code to try and add weapon to player inventory. 
     }
 }

In my linked question I asked about using an enum or a collection of enums that are attributes that describe a Weapon, so for example, a Sword might have LongBlade and Destructable as attributes, and the Character object can query that collection to determine if the Weapon can be added to the player inventory, provided it meets certain requirements.

So an implementation might look like this:

public final boolean tryCarry(Weapon weapon)
{
   if !(weapon.containsAttribute(GameObjectAttribute.LongBlade))
   {
       // add weapon to inventory
   } 
}

As the answers suggest, it complicates the problem.

The blog suggests the use of a Rule class. My linked question suggests a tryCarry(Weapon weapon) method.

Maybe I don't fully understand the blog series (and if I don't, can someone provide more detail?) but I can't see it any other way.

The way I understand it is, you have to communicate either with the Rule or Player class to determine what Weapon you have, and if it can be added. How would you do this? To me anyway, a value, if it's a string or enum must be stored somewhere to indicate exactly what weapon you're trying to add.

  • I'm not sure what the actual question is, or what problem you're trying to solve? At a guess though, maybe you need to look into an ECS, and have a "Carry" system. – Steve Smith Oct 02 '18 at 09:22
  • @SteveSmith - My question has been clearly stated, *you have to communicate either with the Rule or Player class to determine what Weapon you have, and if it can be added. How would you do this?* –  Oct 02 '18 at 13:03

1 Answers1

1

Follow the "tell, don't ask" principle.

If you want a character to pick up a weapon, call tryCarry to tell them to pick it up. If they can't, they will report that back.

Every (object of every) class should know what it is capable of doing, and should have methods to do that. So if you want it to do something, just tell it. If sometimes it can't do that, make sure you design the method with a status response.

If there are rules to check, then each character should know what rules apply to them. So checking the rule should be part of the tryCarry method. Any rules would be initialised in the constructor.

You tell the character what to pick up by passing it a reference to the object you want picked up. Don't invent other strings or enums as that just complicates things.

Simon B
  • 9,167
  • 4
  • 26
  • 33
  • Can you provide a code sample? The problem I'm having is `Weapon` is an abstract class. The `Rule` needs to know the `Weapon` I'm trying to carry, how can I tell it, I'm attempting to carry a `Sword`? –  Oct 02 '18 at 13:05
  • @BasementJoe why can't your weapon class include information about the type of the weapon? – Zavior Oct 02 '18 at 13:56
  • @Zavior - I had an `enum` in the Weapon class indicating what weapon it was, but I was told it's bad practice and violates DRY. See for yourself: https://softwareengineering.stackexchange.com/questions/373390/using-a-variable-to-indicate-object-type –  Oct 02 '18 at 14:41
  • @Zavior - The `Rule` class needs to know what Weapon I'm carrying, but it's abstracted away, how then can I enforce the rule? I need someway to communicate that I'm attempting to carry a `Sword`. –  Oct 02 '18 at 14:43
  • @BasementJoe Ultimately, you cannot pick up a Weapon, as there can never be an object that is a Weapon (it's an abstract class). You can pick up a Sword object, and the Sword should know that it's a Sword. Java supports reflection. So if the Character is actually a Wizard, and the Weapon is actually a Sword, then you can pass both into the "can I pick it up" rule, and the rule can use reflection to see if that's possible. If you really hate reflection, some kind of toString implemented on every class would do instead. – Simon B Oct 02 '18 at 16:17
  • @SimonB - A lot of trouble for a simple decision. I don't really see what a `toString()` will do that a getter can't and in long term, it's a poor version of `instanceof`. All I really want is for someone to show me an implementation of what EL Blog was suggesting, but for whatever reason nobody wants to do it. –  Oct 02 '18 at 16:24
  • One reason is that you're asking people to read a whole blog in order to answer your question. And "enums are bad" only applies if the enums are a direct copy of the class hierarchy. However, if your game has multiple types of weapon, you often won't want a new class for each type, just different values. What is it that prevents a wizard picking up a sword? Maybe your Sword class (or it's superclass if there is one) needs a "CanBePickedUpByWizard" flag, plus others depending on your game. – Steve Smith Oct 03 '18 at 10:48
  • @BasementJoe Ultimateely, we're just posting here in our spare time. Writing a useful SSCCE (http://sscce.org/) takes time. Software engineering shouldn't be "cargo cult programming" by copying other people's examples. – Simon B Oct 03 '18 at 12:58