Елегантне рішення для фарбування шахових плиток


19

Я переробляю шахову гру, яку я писав на Java, і мені було цікаво, чи є елегантний алгоритм кольорової шахової плитки на нумерованій шаховій дошці.

Зараз моє рішення використовує, якщо йнакше, твердження, щоб визначити, чи є плитка на парному чи непарному рядку, і на основі цього, чи має бути світлий або темний квадрат.


Для чого потрібен більш елегантний алгоритм, щоб зробити щось таке базове? Просто цікавість чи ...?
ssb

5
Чесно кажучи, мені просто цікаво.
Амір Афгані

Відповіді:


40

Найелегантніший спосіб, про який я можу придумати, враховуючи, що у вас є rowі columnіндекси, є наступний:

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

або, навпаки:

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

В основному, плитка на шаховій дошці світла там, де і стовпчик, і ряд взаємно непарні або парні, інакше темно.


4
Дуже приємне рішення. Хоча ваш коментар вводить в оману: "плитка на шаховій дошці світла там, де і колонка, і рядок рівні". Це неправда. Припустимо, рядок 3, а стовпець - 5 (обидва нерівні ) 3 % 2 == 1і 5 % 2 == 1.. тому обидва нерівні, але будуть кольоровими "світлими". Не кажучи, що ваше рішення неправильне (це добре, оскільки воно буде чергувати шаблон), але ваш коментар / пояснення здається неправильним.
bummzack

Ой, дякую, що помітили, що @bummzack. Оновлено відповідь.
kevintodisco

Хороший спосіб розміщення, можливо, говорить про те, що плитка є легкою, якщо її координати мають однаковий паритет.
вер

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

XOR разом індекси рядків і стовпців і подивіться на найменш значимий біт. Якщо змінити індекс рядка чи стовпця на один, то це перетворить результат, отже, він створить шаблон шашки.


5
^добре, але +працює однаково добре. :)
Кріс Берт-Браун

2
З цього приводу -працює і теж. :)
Тревор Пауелл

2
Біт операцій ftw :)
Майк Клук

3
віддайте перевагу іншим, оскільки це "нечитабельно" (я знаю, що бітові операції не означають, що їх можна здійснити)
Матсман

22

Ще одна пропозиція, дуже відверта:

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

Додавання рядка та стовпця дає кількість горизонтальних та вертикальних кроків від лівої верхньої плитки.

Рівна кількість кроків дає світлий колір.
Непарні числа кроків надають темний колір.


В основному те саме, що відповідь Натана просто написана інакше.
API-Beast

@ Mr.Beast: & 1буде набагато ефективнішим % 2, якщо тільки остання не буде спеціально оптимізована. Але загалом я згоден.
LarsH

1
@LarsH Компілятор піклується про такі речі (або, принаймні, слід)
neeKo

@LarsH Я прагнув до читабельності, а не швидкості. Але в ньому мало що. Я не впевнений, що різницю швидкостей між цими двома можна вважати "значною", коли ми знаємо, що вона буде називатися лише 64 рази, і я хотів би подумати, що сучасний компілятор все одно генерує однакові бінарні файли.
Кріс Берт-Браун

@Chris: Я говорив про ефективність операції%, на яку не впливає кількість разів, коли вона викликається. Але я погоджуюся, що швидкість програми практично не зміниться, і я також погоджуюся з важливістю читабельності відносно потенційного покращення швидкості.
LarsH

4

Цей передбачає, що наші квадрати пронумеровані в діапазоні [0..63].

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

З'ясувати, чому це працює, - це половина задоволення. :)


Цікавий підхід. Але чи не потрібно робити щось із зворотним значенням, щоб отримати його в булі, наприклад return (i>>3 ^ i) & 1 != 0? Чи дозволяє java неявна конверсія цілого числа в булева?
LarsH

Ах, ти маєш рацію; Я читав прямо над бітом "Java" і писав відповідь, думаючи про C ++. Редагування моєї відповіді.
Тревор Пауелл

Це, очевидно, найкраща рада.
Маркс Томас

1
Цей підхід апелює до мене так само, як звертається до мене Перл. Про такий стислий незрозумілість завжди цікаво писати. Менш весело налагоджувати.
Тревор Пауелл

2
  1. Пронумеруйте плитки. Ви можете отримати цю інформацію, обчисливши рядок * 8 + стовпець або щось подібне.

  2. Візьміть модуль 16 числа сітки. (Перед повторенням плитки є 16 позицій.)

  3. Пофарбуйте плитку на основі, якщо вона має парне або непарне число. Переверніть колір плитки, якщо результат більший за 7.

Код для нульових індексів:

int cellNum = (row*8+column) % 16;
bool isSecondRow = cellNum > 7;
if(cellNum % 2 == 0 ^ isSecondRow){ //XOR operator
    setColor(Color.White);
}else{
    setColor(Color.Charcoal);
}

Чому ви виділяєте другий ряд? Це повинно працювати для всіх 8 рядів
Амір Афгані

1
Я не розумію вашого запитання. modulus 16Операція зводить задачу до двох рядках. Другий ряд дотримується іншого шаблону, ніж перший. Оператор ifоцінює справжній лише той факт, що будь-який це плитка XOR з парним номером не у другому ряду. Якщо обидва вірні, це оцінюється як хибне. Перегляньте оператора XOR: msdn.microsoft.com/en-us/library/zkacc7k1.aspx
Джим

1
IsSecondRowдійсно повинні були бути названі IsEvenRow. Це досить складний спосіб отримати низький біт рядка: спочатку змістіть біти позицій рядка 3 вправо, потім відкиньте всі, крім LSB рядка, а потім перевірте, чи встановлено 4-й біт Cellnum.
MSalters

Я бачу. +1 для відповіді.
Амір Афгані

Можливо, хороший приклад того, чому елегантність не завжди є найкращим рішенням. ;)
Джим

0

Хоча цей підхід насправді не потрібен для чогось такого простого, як шахова дошка, коли я думаю про елегантний спосіб зробити щось, що стосується виду, я хочу зробити якомога простіше змінити винесений вигляд. Наприклад, припустимо, що ви вирішили, що хочете чергувати чорно-біле в кожному рядку, але не в кожному стовпчику. Однокласники, які використовувались у відповідях до цих пір, доведеться переписати.

Якби я пішов так далеко, як міг із цим, і полегшив переробку шаблону на шаховій дошці, ось що я б робив:

1) Я зробив би файл, який вказує, якого кольору має кожен квадрат у шаховій дошці.

Наприклад, я міг би створити файл, chess_board_pattern.configякий виглядає приблизно так:

bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb

2) Я б написав клас / компонент / все, що може прочитати цей файл, і створити якийсь об'єкт, який представляє шаблон дошки:

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) Я б тоді використовував цей клас у функції, яка фактично малює дошку.

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

Знову ж таки, це набагато важче, ніж це потрібно для шахової дошки. Я думаю, що в цілому, працюючи над більш складними проектами, краще придумати узагальнені рішення, як це замість написання коду, який важко змінити згодом.


8
Ви повинні опублікувати це на thedailywtf.com . :)
avakar

11
Не достатньо підприємницька, потребує більше XML.
Максим Мінімус

3
Привіт, Кевін. Ви писали, The one-liners used in answers so far would have to be re-written.але також it's best to come up with generalized solutions like this instead of writing code that's difficult to change later.Ви повинні розуміти, що цей код набагато складніше зірвати та переписати, ніж один рядок. Тож я прихилився до вас, тому що це не елегантно і не радимо робити.
Кріс Берт-Браун

1
+1 - Елегантність полягає не тільки в стислість. Якщо можливість змінити конфігурацію плати є однією з вимог, це хороший шлях. Я робив подібні речі в деяких головоломкових програмах. Я б не очікував, що в шаховій програмі є ця вимога. І я не погоджуюся, що узагальнені рішення завжди найкращі. НІКОЛИ КІН не може бути зроблено узагальнень, таким, що ви не можете написати Hello World, не застосовуючи парсер LALR та інтерпретатор OpenGL. Ключове значення - знання, коли ЯГНІ.
LarsH

2
Мені подобається ця відповідь. Це найелегантніший спосіб максимізувати прибуток, якщо вам виставляють рахунок за годину!
Піжама Panda
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.