1

I'm currently working on a tic-tac-toe game, and I keep track of the cells' values using a State enum.

protected static enum State {
    BLANK, X, O;

    @Override
    public String toString() {
        if (this.name().equals("BLANK"))
            return " ";
        else
            return this.name();
    }

    @Override
    public boolean equals(Object o2) {
        if (this == o2)
            return true;

        if (!(o2 instanceof State))
            return false;

        State state2 = (State)o2;
        if (state2.name().equals("BLANK"))
            return false;

        return this.name().equals(state2.name());
    }
};

A winner can then be determined if the necessary cells are equal. The issue is, if the cell is BLANK, "BLANK" will win. My original thought was to override it with what I have above, but this creates a compile error because apparently boolean equals(Object) is final in an enum (I understand it's because of this article). So, my next thought was to just overload it as follows:

public boolean equals(State state2) {
    if (state2.name().equals("BLANK"))
        return false;

    return this.name().equals(state2.name());
}

But we know this won't work all the time, because some things like Collections will only look at the equals(Object) signature. The issue here is that, semantically, a blank cell doesn't exist at all; there's nothing there, so there should be nothing to compare against to be equal to another blank cell. Another similar example would be if I had an enum for numbers: enum Sign { Positive, Negative, NaN }. An efficient way of multiplying the two numbers and finding the resulting sign would be (pretending of course the computer didn't already handle signs) would be:

if (this.sign.equals(number2.sign))
    sign = Sign.Positive;
else
    sign = Sign.Negative;

Undefined numbers can't share a sign because they're undefined! You can always inelegantly check to see later if the sign is undefined and change stuff at that point, but that seems very backwards and inefficient, because it's still had to check equality and do a lot of work already in vain. The number example kind of falls apart where it can just be made to equal NaN, but my point is that really isn't accurate, and I'm sure there are plenty of other instances where two enum constants wouldn't semantically be equal and wouldn't work like that, such as in my tic-tac-toe example. Is there an elegant way of handling these kinds of situations in Java?

Community
  • 1
  • 1
BrainFRZ
  • 437
  • 3
  • 15
  • Remove blank, and fill your board with `Optional`(s); use blank and modify your win detector routines to ignore blanks, remove blank and use `null`(s). Those are the options that spring to mind. – Elliott Frisch Apr 10 '16 at 18:18
  • Would that always be the way to go? Or would that only be a solution to some problems? – BrainFRZ Apr 10 '16 at 18:23
  • 2
    42. Wouldn't it be nice if there was a universal answer to every question. – Elliott Frisch Apr 10 '16 at 18:24
  • @ElliottFrisch Also, this causes issues in my example at least with generic array creation... – BrainFRZ Apr 10 '16 at 18:30
  • Why not make a method `boolean samePlayer(State that) { return this == that && that != BLANK; }`? Seems like you are overthinking it. If the contract for `equals` doesn't fit your need, don't use it. – Radiodef Apr 10 '16 at 18:37

0 Answers0