Элегантное решение для окрашивания шахматной плитки

19

Я перерабатываю шахматную игру, написанную на Java, и мне было интересно, есть ли элегантный алгоритм раскраски шахматных фигур на пронумерованной шахматной доске.

Прямо сейчас мое решение использует операторы if else, чтобы определить, находится ли плитка в четной или нечетной строке, и на основании этого, должен ли он быть светлым или темным квадратом.

Амир Афганский
источник
Зачем вам нужен более элегантный алгоритм, чтобы сделать что-то такое простое? Просто любопытство или ...?
Ssb
5
Честно говоря, мне просто любопытно.
Амир Афганистан

Ответы:

40

Самый элегантный способ , которым я могу думать, учитывая , что у вас есть rowи columnпоказатели, заключается в следующем:

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

или, наоборот:

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

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

kevintodisco
источник
4
Очень хорошее решение. Хотя ваш комментарий вводит в заблуждение: «плитка на шахматной доске светлая везде, где столбец и строка ровные». Это не так ... предположим, что строка 3, а столбец 5 (оба неровные ) 3 % 2 == 1и 5 % 2 == 1... так что оба неровные, но будут окрашены "светлыми". Не сказать, что ваше решение неверно (это хорошо, поскольку оно будет чередовать шаблон), но ваш комментарий / объяснение кажется неправильным.
Буммзак
Ой, спасибо, что заметили этот @bummzack. Обновил ответ.
Kevintodisco
Хороший способ выразить это - сказать, что плитка легкая, если ее координаты имеют одинаковую четность.
вер
34
bool isLight = ((row ^ column) & 1) == 0;

Выполните XOR вместе индексы строк и столбцов и посмотрите на младший бит. Изменение индекса строки или столбца на единицу инвертирует результат, следовательно, генерирует шаблон проверки.

Натан Рид
источник
5
^хорошо, но +работает одинаково хорошо. :)
Крис Бурт-Браун
2
Впрочем -, тоже работает. :)
Тревор Пауэлл
2
Бит операции ftw :)
Майк Клак
3
предпочитаю другие, так как это «нечитаемо» (я знаю битовые операции, это не значит, что их можно обслуживать)
Matsemann
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
Этот подход привлекает меня так же, как Perl обращается ко мне. Такого рода краткая непостижимость всегда весело писать. Менее весело отлаживать.
Тревор Пауэлл
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 вправо, затем отбросьте все, кроме младшего разряда строки, а затем проверьте, установлен ли 4-й бит ячейки.
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]);
    }
}

Опять же, это намного сложнее, чем необходимо для шахматной доски. В целом, я думаю, что при работе над более сложными проектами лучше придумать такие обобщенные решения, чем писать код, который потом сложно изменить.

Kevin
источник
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
Мне нравится этот ответ. Это самый элегантный способ максимизировать свою прибыль, если вам выставляют счет каждый час!
Панда Пижама