Solusi elegan untuk mewarnai ubin catur

19

Saya mengembangkan kembali permainan catur yang saya tulis di Jawa, dan bertanya-tanya apakah ada algoritma yang elegan untuk mewarnai ubin catur di papan catur bernomor.

Saat ini solusi saya menggunakan pernyataan if else untuk menentukan apakah ubin berada pada baris genap atau ganjil, dan berdasarkan itu, apakah itu harus berupa kotak terang atau gelap.

Amir Afghani
sumber
Mengapa Anda membutuhkan algoritma yang lebih elegan untuk melakukan sesuatu yang sangat mendasar? Hanya ingin tahu atau ...?
ssb
5
Jujur saya hanya ingin tahu.
Amir Afghani

Jawaban:

40

Cara paling elegan yang bisa saya pikirkan, mengingat Anda memiliki rowdan columnindeks, adalah sebagai berikut:

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

atau, sebaliknya:

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

Pada dasarnya, ubin di papan catur adalah cahaya di mana pun kolom dan barisnya saling ganjil atau genap, dan sebaliknya gelap.

kevintodisco
sumber
4
Solusi yang sangat bagus Meskipun komentar Anda menyesatkan: "ubin di papan catur ringan di mana pun baik kolom dan baris". Itu tidak benar .. anggap baris 3 dan kolom 5 (keduanya tidak rata ) 3 % 2 == 1dan 5 % 2 == 1.. jadi keduanya tidak rata tetapi akan berwarna "terang". Tidak mengatakan solusi Anda salah (itu baik, karena akan mengubah pola) tetapi komentar / penjelasan Anda tampaknya salah.
bummzack
Aduh, terima kasih telah melihat @bummzack itu. Diperbarui jawabannya.
kevintodisco
Cara yang baik untuk mengatakannya adalah mengatakan ubin itu ringan asalkan koordinatnya memiliki paritas yang sama.
ver
34
bool isLight = ((row ^ column) & 1) == 0;

XOR bersama-sama indeks baris dan kolom dan lihat bit paling tidak signifikan. Mengubah indeks baris atau kolom dengan satu akan membalikkan hasilnya, sehingga menghasilkan pola checker.

Nathan Reed
sumber
5
^baik-baik saja, tetapi +berfungsi sama baiknya. :)
Chris Burt-Brown
2
Dalam hal ini, -bekerja juga. :)
Trevor Powell
2
Operasi bit ftw :)
Mike Cluck
3
lebih suka yang lain, karena ini "tidak dapat dibaca" (Saya tahu operasi bit, tidak berarti itu dapat dikelola)
Matsemann
22

Saran lain, sangat mudah:

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

Menambahkan baris dan kolom memberikan jumlah langkah horisontal dan vertikal menjauh dari ubin kiri atas.

Bahkan sejumlah langkah memberikan warna terang.
Jumlah langkah yang aneh memberi warna gelap.

Chris Burt-Brown
sumber
Pada dasarnya sama dengan jawaban Nathan yang ditulis berbeda.
API-Beast
@ Mr.Beast: & 1akan menjadi jauh lebih efisien daripada % 2, kecuali yang terakhir dioptimalkan secara khusus. Tetapi secara umum saya setuju.
LarsH
1
@ LarsH Kompiler menangani hal-hal semacam itu (atau setidaknya, seharusnya)
neeKo
@ LarsH saya bertujuan untuk keterbacaan, bukan kecepatan. Tetapi tidak banyak di dalamnya. Saya tidak yakin bahwa perbedaan kecepatan antara keduanya dapat dianggap "banyak" ketika kita tahu itu hanya akan dipanggil 64 kali, dan saya ingin berpikir bahwa kompiler modern akan menghasilkan biner yang identik pula.
Chris Burt-Brown
@ Chris: Saya berbicara tentang efisiensi operasi%, yang tidak terpengaruh oleh berapa kali itu disebut. Tapi saya setuju, itu tidak mungkin membuat perbedaan praktis dalam kecepatan program, dan saya juga setuju tentang pentingnya keterbacaan relatif terhadap peningkatan kecepatan potensial.
LarsH
4

Yang ini mengasumsikan bahwa kuadrat kita diberi nomor dalam kisaran [0..63].

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

Mencari tahu mengapa itu bekerja adalah setengah kesenangan. :)

Trevor Powell
sumber
Pendekatan yang menarik. Tapi jangan Anda harus melakukan sesuatu dengan nilai pengembalian untuk membuatnya menjadi bool, misalnya return (i>>3 ^ i) & 1 != 0? Apakah java memungkinkan konversi integer ke boolean?
LarsH
Ah, kamu benar; Saya membaca sedikit "Java", dan menulis jawaban tentang C ++. Mengedit jawaban saya.
Trevor Powell
Ini jelas merupakan papan terbaik.
Marcks Thomas
1
Pendekatan ini menarik bagi saya dengan cara yang sama seperti Perl menarik bagi saya. Jenis ketidaktahuan yang ringkas seperti ini selalu menyenangkan untuk ditulis. Kurang menyenangkan untuk di-debug.
Trevor Powell
2
  1. Beri nomor ubin. Anda dapat memperoleh informasi ini dengan menghitung baris * 8 + kolom atau yang serupa.

  2. Ambil modulus 16 dari nomor grid. (Ada 16 posisi sebelum ubin mengulangi.)

  3. Warnai ubin berdasarkan jika memiliki nomor genap atau ganjil. Balikkan warna ubin jika hasilnya lebih besar dari 7.

Kode untuk indeks berbasis nol:

int cellNum = (row*8+column) % 16;
bool isSecondRow = cellNum > 7;
if(cellNum % 2 == 0 ^ isSecondRow){ //XOR operator
    setColor(Color.White);
}else{
    setColor(Color.Charcoal);
}
Jim
sumber
Mengapa Anda memilih baris kedua? Ini harus bekerja untuk semua 8 baris
Amir Afghani
1
Saya tidak mengerti pertanyaan Anda. The modulus 16operasi mengurangi masalah untuk dua baris. Baris kedua mengikuti pola yang berbeda dari yang pertama. The ifpernyataan hanya bernilai true jika salah itu adalah genteng XOR genap tidak di baris kedua. Jika keduanya benar, itu bernilai false. Tinjau operator XOR: msdn.microsoft.com/en-us/library/zkacc7k1.aspx
Jim
1
IsSecondRowbenar-benar seharusnya dinamai IsEvenRow. Ini cara yang agak berbelit-belit untuk mendapatkan bit baris yang rendah: pertama-tama pindahkan bit dari posisi baris 3 ke kanan, lalu buang semua kecuali LSB baris, lalu periksa apakah bit ke-4 selnum diatur.
MSalters
Saya melihat. +1 untuk jawabannya.
Amir Afghani
Mungkin contoh bagus mengapa keanggunan tidak selalu merupakan solusi terbaik. ;)
Jim
0

Meskipun pendekatan ini tidak benar-benar diperlukan untuk sesuatu yang sederhana seperti papan catur, ketika saya memikirkan cara yang elegan untuk membuat sesuatu yang terkait dengan tampilan, saya ingin membuatnya semudah mungkin untuk mengubah tampilan yang diberikan sebanyak mungkin. Misalnya, Anda memutuskan ingin mengganti hitam dan putih pada setiap baris, tetapi tidak setiap kolom. Baris satu yang digunakan dalam jawaban sejauh ini harus ditulis ulang.

Jika saya melangkah sejauh mungkin dengan ini dan membuatnya mudah untuk mendesain ulang pola di papan Catur mungkin, inilah yang akan saya lakukan:

1) Saya akan membuat file yang menunjukkan warna setiap kotak di papan catur.

Misalnya, saya bisa membuat file chess_board_pattern.configyang terlihat seperti ini:

bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb

2) Saya akan menulis kelas / komponen / apa pun yang dapat membaca file ini dan membuat beberapa jenis objek yang mewakili pola papan:

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) Saya kemudian akan menggunakan kelas itu dalam fungsi yang benar-benar menggambar papan.

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

Sekali lagi, ini jauh lebih sulit daripada yang diperlukan untuk papan Catur. Saya pikir secara umum, ketika bekerja pada proyek yang lebih rumit, yang terbaik untuk datang dengan solusi umum seperti ini daripada menulis kode yang sulit diubah nanti.

Kevin
sumber
8
Anda harus memposting ini ke thedailywtf.com . :)
avakar
11
Tidak cukup tegas, membutuhkan lebih banyak XML.
Maximus Minimus
3
Halo, Kevin. Anda menulis The one-liners used in answers so far would have to be re-written.tetapi juga it's best to come up with generalized solutions like this instead of writing code that's difficult to change later.Tetapi Anda harus memahami bahwa kode ini jauh lebih sulit untuk dirobohkan dan ditulis ulang daripada satu baris. Jadi saya menurunkan Anda karena tidak elegan atau disarankan untuk melakukan ini.
Chris Burt-Brown
1
+1 - Keanggunan tidak hanya singkatnya. Jika mampu mengubah konfigurasi papan adalah salah satu persyaratan, ini adalah cara yang baik untuk dilakukan. Saya telah melakukan hal serupa di beberapa program puzzle. Saya tidak akan mengharapkan program catur memiliki persyaratan ini. Dan saya tidak akan setuju bahwa solusi umum selalu yang terbaik. Tidak ada akhir untuk generalisasi yang dapat dibuat, sehingga Anda tidak dapat menulis Hello World tanpa menerapkan parser LALR dan juru bahasa OpenGL. Kuncinya adalah mengetahui kapan YAGNI.
LarsH
2
Saya suka jawaban ini. Ini cara paling elegan untuk memaksimalkan keuntungan Anda jika Anda ditagih per jam!
Panda Pajama