Satranç fayans boyama için zarif çözüm


19

Java'da yazdığım bir satranç oyununu yeniden geliştiriyorum ve numaralı satranç tahtasında satranç taşlarını renklendirmek için zarif bir algoritma olup olmadığını merak ediyordum.

Şu anda benim çözümüm, kutunun çift veya tek bir satırda olup olmadığını belirlemek için if ifadelerini kullanır ve buna dayanarak açık veya koyu bir kare olması gerekir.


Neden bu kadar basit bir şey yapmak için daha zarif bir algoritmaya ihtiyacınız var? Sadece merak mı yoksa ...?
ssb

5
Dürüst olmak gerekirse sadece merak ediyorum.
Amir Afghani

Yanıtlar:


40

rowVe columnendekslerinizin olduğu düşünüldüğünde düşünebildiğim en şık yol şudur:

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

veya tersine:

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

Temel olarak, satranç tahtasındaki bir karo, sütun ve sıranın karşılıklı olarak tek veya çift olduğu yerlerde hafiftir ve aksi takdirde karanlıktır.


4
Çok güzel bir çözüm. Yorumunuz yanıltıcı olsa da: "satranç tahtasındaki bir karo hem sütun hem de sıranın eşit olduğu her yerde hafiftir". Bu doğru değil .. satır 3 ve sütun 5 (her ikisi de düzensiz ) 3 % 2 == 1ve 5 % 2 == 1.. her ikisi de düzensiz ama "açık" renkli olacak varsayalım . Çözümünüzün yanlış olduğunu söylememek (kalıbı değiştireceği için iyi), ancak yorumunuz / açıklamanız yanlış görünüyor.
bummzack

Hata! Bummzack'i bulduğunuz için teşekkürler. Yanıt güncellendi.
kevintodisco

Kolonatların aynı pariteye sahip olduğu sürece, bir döşemenin hafif olduğunu söylemenin güzel bir yolu olabilir.
ver

34
bool isLight = ((row ^ column) & 1) == 0;

XOR birlikte satır ve sütun indeksleri ve en az anlamlı bit bakın. Satır veya sütun dizinini birer birer değiştirmek sonucu tersine çevirir, bu nedenle bir denetleyici deseni oluşturur.


5
^gayet iyi, ama +aynı derecede iyi çalışıyor. :)
Chris Burt-Brown

2
Bu konuda da -çalışıyor. :)
Trevor Powell

2
Bit işlemleri ftw :)
Mike Cluck

3
"okunamaz" olduğu için diğerlerini tercih edin (bit işlemlerini biliyorum, sürdürülebilir olduğu anlamına gelmez)
Matsemann

22

Çok basit bir başka öneri:

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

Satır ve sütun eklenmesi, sol üst döşemeden uzaktaki yatay ve dikey adımların sayısını verir.

Adım sayısı bile açık renk verir.
Tek sayıda adım koyu renk verir.


Temelde Nathan'ın yanıtı sadece farklı yazılmıştı.
API-Beast

@ Mr.Beast: İkincisi özel olarak optimize edilmedikçe & 1çok daha verimli olacak % 2. Ama genel olarak katılıyorum.
LarsH

1
@LarsH Derleyici bu tür şeylerle ilgilenir (ya da en azından öyle olmalıdır)
neeKo

@LarsH Hızı değil, okunabilirliği hedefliyordum. Ama içinde pek bir şey yok. Sadece 64 kez çağrılacağını bildiğimizde ikisi arasındaki hız farkının "çok" olarak değerlendirilebileceğinden emin değilim ve modern bir derleyicinin yine de aynı ikili dosyaları oluşturacağını düşünmek istiyorum.
Chris Burt-Brown

@Chris: Kaç kez çalıştığından etkilenmeyen% işleminin verimliliğinden bahsediyordum. Ancak katılıyorum, programın hızında pratik bir fark yaratması muhtemel değil ve ayrıca potansiyel hız iyileştirmelerine göre okunabilirliğin önemi konusunda da katılıyorum.
LarsH

4

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. :)


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?
LarsH

Ah, you're right; I read straight over the "Java" bit, and wrote the answer thinking about C++. Editing my answer.
Trevor Powell

This is clearly the best board.
Marcks Thomas

1
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.
Trevor Powell

2
  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);
}

Why do you single out the second row? This should work for all 8 rows
Amir Afghani

1
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
Jim

1
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.
MSalters

I see. +1 for the answer.
Amir Afghani

Perhaps a good example of why elegance isn't always the best solution. ;)
Jim

0

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.


8
You should post this to thedailywtf.com. :)
avakar

11
Not enterprisey enough, needs more XML.
Maximus Minimus

3
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.
Chris Burt-Brown

1
+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.
LarsH

2
I like this answer. It's the most elegant way to maximize your profits if you're being billed by the hour!
Panda Pajama
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.