チェスタイルを着色するためのエレガントなソリューション


19

私はJavaで書いたチェスゲームを再開発しており、番号付きチェスボードのチェスタイルに色を付けるためのエレガントなアルゴリズムがあるのではないかと考えていました。

現在、私のソリューションではif elseステートメントを使用して、タイルが偶数行か奇数行かを判断し、それに基づいて、明るい正方形と暗い正方形のどちらにするかを決定します。


なぜそんなに基本的なことをするために、よりエレガントなアルゴリズムが必要なのですか?ただの好奇心か...?
ssb

5
正直なところ、私は興味があります。
アミールアフガニ

回答:


40

インデックスrowcolumnインデックスがあることを考えると、私が考えることができる最もエレガントな方法は次のとおりです。

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

または、逆に:

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

基本的に、チェス盤のタイルは、列と行の両方が相互に奇数または偶数である場合は常に明るく、それ以外の場合は暗いです。


4
とてもいい解決策。あなたのコメントは誤解を招きますが、「チェス盤のタイルは、列と行の両方が偶数であればどこでも明るいです」。それは真実ではありません..行が3で列が5(両方とも不均一)である3 % 2 == 1と仮定し5 % 2 == 1ます。あなたの解決策が間違っていると言っていない(それはパターンを変えるので良い)が、あなたのコメント/説明は間違っているようだ。
bummzack

@bummzackを見つけてくれてありがとう。答えを更新しました。
ケビントディスコ

配置の良い方法は、座標が同じパリティを持つ限り、タイルが明るいと言うことです。

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

行と列のインデックスをXORし、最下位ビットを調べます。行または列のインデックスを1つずつ変更すると、結果が反転するため、チェッカーパターンが生成されます。


5
^大丈夫ですが、+同様に機能します。:)
クリスバートブラウン

2
さらに言えば、-機能します。:)
トレバーパウエル

2
ビット操作ftw :)
マイク・クルック

3
これは「読めない」であるとして、(私はビット演算を知っている、それは保守性だという意味ではありません)、他の人を好む
Matsemann

22

別の提案、非常に簡単です:

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

行と列を追加すると、左上のタイルから離れる水平方向と垂直方向のステップ数が得られます。

偶数ステップで明るい色が得られます。
奇数のステップは暗い色を与えます。


基本的に、異なる方法で書かれたネイサンの答えと同じです。
ビースト

@ Mr.Beast:& 1% 2、特別に最適化されていない限り、より効率的です。しかし、一般的には同意します。
LarsH

1
@LarsHコンパイラーはそのようなことを処理します(少なくとも、そうすべきです)
neeKo

@LarsHスピードではなく読みやすさを目指していました。しかし、そこにはあまりありません。64回しか呼び出されないことがわかっているので、この2つの速度の差が「多く」と見なされるかどうかはわかりません。
クリスバートブラウン

@Chris:%オペレーションの効率について話していましたが、これは呼び出される回数に影響されません。しかし、私は同意します、それはプログラムの速度に実際的な違いをもたらす可能性は低いです。また、潜在的な速度の改善に対する読みやすさの重要性についても同意します。
LarsH

4

これは、正方形に[0..63]の範囲の番号が付けられていることを前提としています。

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

なぜそれが機能するのかを理解することは半分の楽しみです。:)


興味深いアプローチ。しかし、戻り値をboolにするために何かをする必要はありませんreturn (i>>3 ^ i) & 1 != 0か?Javaは整数からブールへの暗黙的な変換を許可していますか?
LarsH

ああ、あなたは正しい。「Java」の部分を直読し、C ++について考えて答えを書きました。答えを編集します。
トレバーパウエル

これは明らかに最高のボードです。
マルクストーマス

1
このアプローチは、Perlが私にアピールするのと同じ方法で私にアピールします。このような簡潔でわかりにくいのは、常に書くのが楽しいです。デバッグするのが面倒です。
トレバーパウエル

2
  1. タイルに番号を付けます。この情報は、row * 8 + columnまたは同様のものを計算することにより導き出すことができます。

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

なぜ2行目を選択するのですか?これは、すべての8行のために働く必要があります
アミールアフガニスタンに

1
あなたの質問がわかりません。このmodulus 16操作により、問題が2行に減ります。2行目は、1行目とは異なるパターンに従います。ifどちらかそれは2行目の偶数タイルXORでない場合、文は唯一の真と評価されます。両方が真の場合、偽と評価されます。XOR演算子を確認します:msdn.microsoft.com/en-us/library/zkacc7k1.aspx
ジム

1
IsSecondRow本当に名前が付けられるべきでしたIsEvenRow。これは、行の下位ビットを取得するかなり複雑な方法です。最初に行3の位置のビットを右にシフトし、次に行のLSBを除くすべてを破棄し、次にcellnumの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]);
    }
}

繰り返しますが、これはチェス盤に必要なものよりもはるかに困難です。ただし、一般的には、より複雑なプロジェクトに取り組む場合、後で変更するのが難しいコードを書くのではなく、このような一般的なソリューションを考え出すのが最善だと思います。


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
+1-エレガンスは簡潔さだけではありません。ボード構成を変更できることが要件の1つである場合、これは良い方法です。私はいくつかのパズルプログラムで同様のことをしました。ただし、チェスプログラムにこの要件があるとは思わないでしょう。そして、一般化されたソリューションが常に最良であることに同意しません。LALRパーサーとOpenGLインタープリターを実装せずにHello Worldを記述できないように、一般化に終わりはありません。鍵は、いつYAGNIを知るかです。
LarsH

2
私はこの答えが好きです。時間単位で請求される場合、利益を最大化する最もエレガントな方法です!
パンダパジャマ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.