20
\$\begingroup\$

I am re-developing a chess game I wrote in Java, and was wondering if there is an elegant algorithm to color chess tiles on a numbered chess board.

Right now my solution uses if else statements to determine if the tile is on an even or odd row, and based on that, if it should be a light or dark square.

\$\endgroup\$
2
  • \$\begingroup\$ Why do you need a more elegant algorithm to do something so basic? Just curiosity or...? \$\endgroup\$
    – ssb
    Commented Dec 5, 2012 at 5:45
  • 5
    \$\begingroup\$ Honestly I'm just curious. \$\endgroup\$ Commented Dec 5, 2012 at 5:54

6 Answers 6

42
\$\begingroup\$

The most elegant way I can think of, given that you have the row and column indices, is the following:

bool isLight = (row % 2) == (column % 2);

or, conversely:

bool isDark = (row % 2) != (column % 2);

Basically, a tile on a chessboard is light wherever both the column and row are mutually odd or even, and is dark otherwise.

\$\endgroup\$
3
  • 4
    \$\begingroup\$ Very nice solution. Although your comment is misleading: "a tile on a chessboard is light wherever both the column and row are even". That's not true.. assume row is 3 and column is 5 (both are uneven) 3 % 2 == 1 and 5 % 2 == 1.. so both are uneven but will be colored "light". Not saying your solution is wrong (it's good, as it will alternate the pattern) but your comment/explanation seems wrong. \$\endgroup\$
    – bummzack
    Commented Dec 5, 2012 at 7:00
  • \$\begingroup\$ Whoops, thanks for spotting that @bummzack. Updated the answer. \$\endgroup\$ Commented Dec 5, 2012 at 7:11
  • \$\begingroup\$ A nice way of putting it might be saying a tile is light as long as its coordinates have the same parity. \$\endgroup\$
    – ver
    Commented Dec 31, 2012 at 11:03
35
\$\begingroup\$
bool isLight = ((row ^ column) & 1) == 0;

XOR together the row and column indices and look at the least-significant bit. Changing the row or column index by one will invert the result, hence it generates a checker pattern.

\$\endgroup\$
4
  • 5
    \$\begingroup\$ ^ is fine, but + works equally well. :) \$\endgroup\$ Commented Dec 5, 2012 at 10:46
  • 2
    \$\begingroup\$ For that matter, - works, too. :) \$\endgroup\$ Commented Dec 5, 2012 at 11:00
  • 2
    \$\begingroup\$ Bit operations ftw :) \$\endgroup\$
    – Mike Cluck
    Commented Dec 5, 2012 at 15:44
  • 3
    \$\begingroup\$ prefer the others, as this is "unreadable" (I know bit operations, doesn't mean it's maintainable) \$\endgroup\$
    – Matsemann
    Commented Dec 5, 2012 at 22:26
22
\$\begingroup\$

Another suggestion, very straightforward:

isLight = (row + column) % 2 == 0;

Adding the row and column gives the number of horizontal and vertical steps away from the top-left tile.

Even number of steps gives light colour.
Odd numbers of steps gives dark colour.

\$\endgroup\$
6
  • \$\begingroup\$ Basically the same as Nathan's answer just written differently. \$\endgroup\$
    – API-Beast
    Commented Dec 5, 2012 at 15:07
  • \$\begingroup\$ @Mr.Beast: & 1 is going to be a lot more efficient than % 2, unless the latter is specially optimized. But in general I agree. \$\endgroup\$
    – LarsH
    Commented Dec 5, 2012 at 20:19
  • 1
    \$\begingroup\$ @LarsH The compiler takes care of those kind of things (or at least, it should) \$\endgroup\$
    – neeKo
    Commented Dec 5, 2012 at 22:29
  • \$\begingroup\$ @LarsH I was aiming for readability, not speed. But there is not much in it. I'm not sure that the speed difference between the two can be considered "a lot" when we know it will only be called 64 times, and I would like to think that a modern compiler would generate identical binaries anyway. \$\endgroup\$ Commented Dec 5, 2012 at 22:48
  • \$\begingroup\$ @Chris: I was talking about the efficiency of the % operation, which is not affected by the number of times it is called. But I agree, it's not likely to make a practical difference in speed of the program, and I also agree about the importance of readability relative to potential speed improvements. \$\endgroup\$
    – LarsH
    Commented Dec 6, 2012 at 0:20
4
\$\begingroup\$

This one assumes that our squares are numbered in the range [0..63].

bool IsLight(int i)
{
    return 0!=(i>>3^i)&1;
}

Figuring out why it works is half the fun. :)

\$\endgroup\$
4
  • \$\begingroup\$ Interesting approach. But don't you have to do something to the return value to get it into a bool, e.g. return (i>>3 ^ i) & 1 != 0? Does java allow implicit conversion of integer to boolean? \$\endgroup\$
    – LarsH
    Commented Dec 5, 2012 at 20:20
  • \$\begingroup\$ Ah, you're right; I read straight over the "Java" bit, and wrote the answer thinking about C++. Editing my answer. \$\endgroup\$ Commented Dec 5, 2012 at 20:45
  • \$\begingroup\$ This is clearly the best board. \$\endgroup\$ Commented Dec 5, 2012 at 21:21
  • 1
    \$\begingroup\$ This approach appeals to me the same way that Perl appeals to me. This sort of succinct incomprehensibility is always fun to write. Less fun to debug. \$\endgroup\$ Commented Dec 5, 2012 at 22:54
2
\$\begingroup\$
  1. Number the tiles. You could derive this information by calculating row*8+column or something similar.

  2. Take modulus 16 of the grid number. (There are 16 positions before the tiles repeat.)

  3. Color the tile based on if it has an even or an odd number. Flip the tile color if the result is greater than 7.

Code for zero-based indices:

int cellNum = (row*8+column) % 16;
bool isSecondRow = cellNum > 7;
if(cellNum % 2 == 0 ^ isSecondRow){ //XOR operator
    setColor(Color.White);
}else{
    setColor(Color.Charcoal);
}
\$\endgroup\$
5
  • \$\begingroup\$ Why do you single out the second row? This should work for all 8 rows \$\endgroup\$ Commented Dec 5, 2012 at 5:55
  • 1
    \$\begingroup\$ I don't understand your question. The modulus 16 operation reduces the problem to two rows. The second row follows a different pattern than the first. The if statement only evaluates to true if either it is an even-numbered tile XOR not in the second row. If both are true, it evaluates to false. Review the XOR operator: msdn.microsoft.com/en-us/library/zkacc7k1.aspx \$\endgroup\$
    – Jim
    Commented Dec 5, 2012 at 6:20
  • 1
    \$\begingroup\$ IsSecondRow really should have been named IsEvenRow. It's a rather convoluted way to get the low bit of row: first shift the bits of row 3 positions to the right, then discard all but the LSB of row, then check if the 4th bit of cellnum is set. \$\endgroup\$
    – MSalters
    Commented Dec 5, 2012 at 15:10
  • \$\begingroup\$ I see. +1 for the answer. \$\endgroup\$ Commented Dec 5, 2012 at 17:56
  • \$\begingroup\$ Perhaps a good example of why elegance isn't always the best solution. ;) \$\endgroup\$
    – Jim
    Commented Dec 5, 2012 at 22:46
0
\$\begingroup\$

Although this approach isn't really necessary for something as simple as a chess board, when I think of an elegant way to render something related to the view, I want to make it as easy as possible to change the rendered view as possible. For example, suppose you decided you wanted to alternate black and white on each row, but not each column. The one-liners used in answers so far would have to be re-written.

If I was to go as far as I could with this and make it as easy to redesign the pattern on the Chess board as possible, here is what I would do:

1) I would make a file that indicates what color each square in the chess board is.

For example, I could make a file chess_board_pattern.config that looks something like this:

bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb

2) I would write a class/component/whatever that can read this file and create some kind of object that represents the board pattern:

public class BoardPattern {
    private Color[][] pattern;

    public BoardPattern(File patternFile)
    {
        pattern = new Color[8][8];
        //Parse the file and fill in the values of pattern
    }

    public Color[][] getPattern {
        return pattern;
    }
}

3) I would then use that class in the function that actually draws the board.

File patternFile = new File("chess_board_pattern.ini");
Color[][] pattern = new BoardPattern(patternFile).getPattern();
ChessBoardDrawable chessBoard = new ChessBoardDrawable();

for(int row = 0; row < 8; row++) {
    for(int column; column < 8; column++) {
        chessBoard.drawSquare(row, column, Color[row][column]);
    }
}

Again, this is a lot harder than is necessary for a Chess board. I think in general, though, when working on more complicated projects, it's best to come up with generalized solutions like this instead of writing code that's difficult to change later.

\$\endgroup\$
9
  • 8
    \$\begingroup\$ You should post this to thedailywtf.com. :) \$\endgroup\$
    – avakar
    Commented Dec 5, 2012 at 13:04
  • 11
    \$\begingroup\$ Not enterprisey enough, needs more XML. \$\endgroup\$ Commented Dec 5, 2012 at 13:32
  • 3
    \$\begingroup\$ Hello, Kevin. You wrote The one-liners used in answers so far would have to be re-written. but also it's best to come up with generalized solutions like this instead of writing code that's difficult to change later. But you must understand that this code is much harder to tear down and rewrite than a single line. So I downvoted you because it isn't elegant or advisable to do this. \$\endgroup\$ Commented Dec 5, 2012 at 14:22
  • 1
    \$\begingroup\$ +1 - Elegance is not just in brevity. If being able to change board configurations is one of the requirements, this is a good way to go. I've done similar things in some puzzle programs. I wouldn't expect a chess program to have this requirement though. And I wouldn't agree that generalized solutions are always best. There is NO END to generalizations that could be made, such that you can't write Hello World without implementing an LALR parser and an OpenGL interpreter. The key is knowing when YAGNI. \$\endgroup\$
    – LarsH
    Commented Dec 5, 2012 at 21:11
  • 2
    \$\begingroup\$ I like this answer. It's the most elegant way to maximize your profits if you're being billed by the hour! \$\endgroup\$ Commented Dec 6, 2012 at 3:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .