Soluzione elegante per colorare le tessere degli scacchi


19

Sto ri-sviluppando un gioco di scacchi che ho scritto in Java e mi chiedevo se esiste un algoritmo elegante per colorare le tessere di scacchi su una scacchiera numerata.

In questo momento la mia soluzione utilizza le istruzioni if ​​else per determinare se la piastrella si trova su una riga pari o dispari e, in base a ciò, se dovrebbe essere un quadrato chiaro o scuro.


Perché hai bisogno di un algoritmo più elegante per fare qualcosa di così semplice? Solo curiosità o ...?
SSB

5
Onestamente sono solo curioso.
Amir Afghani,

Risposte:


40

Il modo più elegante che mi viene in mente, dato che hai gli indici rowe column, è il seguente:

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

o, al contrario:

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

Fondamentalmente, una tessera su una scacchiera è leggera ovunque sia la colonna che la riga siano uguali o dispari, e altrimenti è scura.


4
Soluzione molto bella. Sebbene il tuo commento sia fuorviante: "una piastrella su una scacchiera è leggera ovunque siano uguali sia la colonna che la riga". Questo non è vero .. supponiamo che la riga sia 3 e la colonna sia 5 (entrambe sono irregolari ) 3 % 2 == 1e 5 % 2 == 1.. quindi entrambe sono irregolari ma saranno colorate "chiare". Non dire che la tua soluzione è sbagliata (va bene, in quanto alternerà lo schema) ma il tuo commento / spiegazione sembra sbagliato.
Bummzack,

Spiacenti, grazie per aver individuato @bummzack. Aggiornato la risposta.
kevintodisco,

Un buon modo per dirlo potrebbe essere dire che una tessera è leggera purché le sue coordinate abbiano la stessa parità.
ver

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

XOR insieme gli indici di riga e colonna e osserva il bit meno significativo. La modifica dell'indice di riga o colonna di uno invertirà il risultato, quindi genera un modello di controllo.


5
^va bene, ma +funziona ugualmente bene. :)
Chris Burt-Brown il

2
Del resto, -funziona anche. :)
Trevor Powell il

2
Operazioni bit ftw :)
Mike Cluck,

3
preferisco gli altri, poiché questo è "illeggibile" (conosco le operazioni di bit, non significa che sia mantenibile)
Matsemann,

22

Un altro suggerimento, molto semplice:

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

Aggiungendo la riga e la colonna si ottiene il numero di passi orizzontali e verticali dal riquadro in alto a sinistra.

Il numero pari di passaggi fornisce un colore chiaro.
I numeri dispari di passaggi danno il colore scuro.


Sostanzialmente la stessa della risposta di Nathan scritta in modo diverso.
API-Beast

@ Mr.Beast: & 1sarà molto più efficiente di % 2, a meno che quest'ultimo non sia appositamente ottimizzato. Ma in generale sono d'accordo.
LarsH

1
@LarsH Il compilatore si occupa di quel tipo di cose (o almeno, dovrebbe)
neeKo

@LarsH miravo alla leggibilità, non alla velocità. Ma non c'è molto in esso. Non sono sicuro che la differenza di velocità tra i due possa essere considerata "molto" quando sappiamo che verrà chiamata solo 64 volte, e vorrei pensare che un moderno compilatore genererebbe comunque binari identici.
Chris Burt-Brown,

@ Chris: Stavo parlando dell'efficienza dell'operazione%, che non è influenzata dal numero di volte che viene chiamata. Ma sono d'accordo, non è probabile che faccia una differenza pratica nella velocità del programma e sono anche d'accordo sull'importanza della leggibilità rispetto ai potenziali miglioramenti della velocità.
LarsH il

4

Questo presuppone che i nostri quadrati siano numerati nell'intervallo [0..63].

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

Capire perché funziona è metà del divertimento. :)


Approccio interessante Ma non devi fare qualcosa per il valore di ritorno per farlo diventare un bool, ad esempio return (i>>3 ^ i) & 1 != 0? Java consente la conversione implicita di un numero intero in booleano?
LarsH

Ah, hai ragione; Ho letto direttamente il bit "Java" e ho scritto la risposta pensando al C ++. Modifica la mia risposta.
Trevor Powell,

Questa è chiaramente la migliore tavola.
Marcks Thomas,

1
Questo approccio mi piace allo stesso modo in cui Perl mi attira. Questo tipo di incomprensibilità sintetica è sempre divertente da scrivere. Meno divertente per il debug.
Trevor Powell,

2
  1. Numera le tessere. Puoi ricavare queste informazioni calcolando la riga * 8 + colonna o qualcosa di simile.

  2. Prendi il modulo 16 del numero di griglia. (Ci sono 16 posizioni prima che le tessere si ripetano.)

  3. Colora la tessera in base al numero pari o dispari. Capovolgi il colore della piastrella se il risultato è maggiore di 7.

Codice per indici a base zero:

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

Perché scegli la seconda fila? Questo dovrebbe funzionare per tutte le 8 file
Amir Afghani

1
Non capisco la tua domanda. L' modulus 16operazione riduce il problema a due file. La seconda riga segue uno schema diverso rispetto alla prima. L' ifistruzione viene valutata vera solo se si tratta di una tessera XOR con numero pari non nella seconda riga. Se entrambi sono veri, viene valutato falso. Esaminare l'operatore XOR: msdn.microsoft.com/en-us/library/zkacc7k1.aspx
Jim

1
IsSecondRowavrebbe davvero dovuto essere nominato IsEvenRow. È un modo piuttosto contorto per ottenere il bit basso della riga: prima sposta i bit della riga 3 posizioni verso destra, quindi scarta tutto tranne l'LSB della riga, quindi controlla se il 4o bit di cellnum è impostato.
MSalters il

Vedo. +1 per la risposta.
Amir Afghani,

Forse un buon esempio del perché l'eleganza non è sempre la soluzione migliore. ;)
Jim,

0

Sebbene questo approccio non sia realmente necessario per qualcosa di semplice come una scacchiera, quando penso a un modo elegante per rendere qualcosa legato alla vista, voglio rendere il più semplice possibile cambiare la vista renderizzata possibile. Ad esempio, supponiamo che tu abbia deciso di voler alternare il bianco e il nero su ogni riga, ma non su ogni colonna. Le linee di risposta utilizzate finora nelle risposte dovrebbero essere riscritte.

Se dovessi andare il più lontano possibile con questo e rendere più facile riprogettare il modello sulla scacchiera, ecco cosa farei:

1) Vorrei creare un file che indichi di che colore è ogni quadrato nella scacchiera.

Ad esempio, potrei creare un file chess_board_pattern.configsimile a questo:

bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb
bwbwbwbw
wbwbwbwb

2) Scriverei una classe / componente / qualunque cosa sia in grado di leggere questo file e creare un tipo di oggetto che rappresenti lo schema della scheda:

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) Vorrei quindi utilizzare quella classe nella funzione che effettivamente disegna il tabellone.

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

Ancora una volta, questo è molto più difficile di quanto sia necessario per una scacchiera. Penso in generale, tuttavia, quando si lavora su progetti più complicati, è meglio trovare soluzioni generalizzate come questa invece di scrivere codice che è difficile cambiare in seguito.


8
Dovresti pubblicarlo su thedailywtf.com . :)
avakar,

11
Non abbastanza intraprendente, ha bisogno di più XML.
Maximus Minimus,

3
Ciao Kevin. Hai scritto The one-liners used in answers so far would have to be re-written.ma anche it's best to come up with generalized solutions like this instead of writing code that's difficult to change later.tu Ma devi capire che questo codice è molto più difficile da abbattere e riscrivere di una singola riga. Quindi ti ho sottovalutato perché non è elegante o consigliabile farlo.
Chris Burt-Brown,

1
+1 - L'eleganza non è solo in breve. Se essere in grado di cambiare le configurazioni della scheda è uno dei requisiti, questo è un buon modo di procedere. Ho fatto cose simili in alcuni programmi di puzzle. Non mi aspetto che un programma di scacchi abbia questo requisito. E non sarei d'accordo sul fatto che le soluzioni generalizzate siano sempre le migliori. Non vi è alcuna fine alle generalizzazioni che potrebbero essere fatte, in modo tale che non è possibile scrivere Hello World senza implementare un parser LALR e un interprete OpenGL. La chiave è sapere quando YAGNI.
LarsH

2
Mi piace questa risposta. È il modo più elegante per massimizzare i profitti se ti viene addebitato ogni ora!
Panda Pajama,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.