/*
$Id$
Copyright (C) 2006-2007 by David Cotton
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package fr.free.jchecs.core;
import static fr.free.jchecs.core.Constants.FILE_COUNT;
import static fr.free.jchecs.core.Constants.RANK_COUNT;
import java.io.Serializable;
/**
* Description d'une cellule de l'échiquier.
* <p>
* Les instances de cette classe sont des <b>singletons immuables</b> : classe sûre vis-à-vis des
* threads et permettant des comparaisons directes sur les références d'objets.
* </p>
*
* @author David Cotton
*/
public final class Square implements Comparable<Square>, Serializable
{
/** Identifiant de la classe pour la sérialisation. */
private static final long serialVersionUID = -5504534226984844152L;
/** Liste des coordonnées de cellules. */
private static final Square [] SQUARES;
static
{
SQUARES = new Square [ FILE_COUNT * RANK_COUNT ];
int i = 0;
for (int y = 0; y < RANK_COUNT; y++)
{
for (int x = 0; x < FILE_COUNT; x++)
{
SQUARES[i++] = new Square(x, y);
}
}
}
/** Colonne. */
private final int _file;
/** Ligne. */
private final int _rank;
/** Indice de la cellule. */
private final transient int _index;
/** Chaine de description de la cellule. */
private final transient String _string;
/** Chaine FEN identifiant la cellule. */
private final transient String _fenString;
/**
* Instancie une nouvelle coordonnée.
*
* @param pColonne Colonne de la cellule (de 0 à 7).
* @param pLigne Ligne de la colonne (de 0 à 7).
*/
private Square(final int pColonne, final int pLigne)
{
assert (pColonne >= 0) && (pColonne < FILE_COUNT);
assert (pLigne >= 0) && (pLigne < RANK_COUNT);
_file = pColonne;
_rank = pLigne;
_index = pColonne + pLigne * RANK_COUNT;
final StringBuilder sb = new StringBuilder(getClass().getSimpleName());
sb.append("[file=").append((char) ('a' + getFile()));
sb.append(",rank=").append((char) ('1' + getRank()));
sb.append(']');
_string = sb.toString();
sb.delete(0, sb.length());
sb.append((char) ('a' + getFile())).append((char) ('1' + getRank()));
_fenString = sb.toString();
}
/**
* Fixe l'ordre de tri entre les cases.
*
* @param pCase Case avec laquelle comparer.
* @return -1 si pCase est inférieure, 0 si égale et 1 si supérieure.
* @see Comparable#compareTo(Object)
*/
public int compareTo(final Square pCase)
{
if (pCase == null)
{
throw new NullPointerException();
}
return getFENString().compareTo(pCase.getFENString());
}
/**
* Teste l'égalité entre deux descriptions de cellules.
*
* @param pObjet Objet avec lequel comparer.
* @return Vrai si les deux objets sont égaux.
*/
@Override
public boolean equals(final Object pObjet)
{
if (pObjet == this)
{
return true;
}
if (!(pObjet instanceof Square))
{
return false;
}
final Square o = (Square) pObjet;
return _index == o._index;
}
/**
* Renvoi la chaine FEN identifiant la cellule.
*
* @return Identifiant FEN.
*/
public String getFENString()
{
assert _fenString != null;
return _fenString;
}
/**
* Renvoi la colonne de la cellule.
*
* @return Colonne de la cellule.
*/
public int getFile()
{
assert (_file >= 0) && (_file < FILE_COUNT);
return _file;
}
/**
* Renvoi l'indice de la cellule.
*
* @return Indece de la cellule (entre 0 et 63).
*/
public int getIndex()
{
assert (_index >= 0) && (_index < FILE_COUNT * RANK_COUNT);
return _index;
}
/**
* Renvoi la ligne de la cellule.
*
* @return Ligne de la cellule.
*/
public int getRank()
{
assert (_rank >= 0) && (_rank < RANK_COUNT);
return _rank;
}
/**
* Surcharge du calcul de la clé de hachage.
*
* @return Clé de hachage.
*/
@Override
public int hashCode()
{
return _index;
}
/**
* Résout la désérialisation d'un objet pour en garantir le comportement "singleton".
*
* @return Instance correspondante dans la JVM.
*/
private Object readResolve()
{
return valueOf(getFile(), getRank());
}
/**
* Renvoi une chaine représentant la cellule.
*
* @return Chaine représentant la case.
*/
@Override
public String toString()
{
assert _string != null;
return _string;
}
/**
* Renvoi l'instance correspondant à un indice.
*
* @param pIndice Indice de la case (entre 0 et 63).
* @return Instance correspondante.
*/
public static Square valueOf(final int pIndice)
{
assert (pIndice >= 0) && (pIndice < FILE_COUNT * RANK_COUNT);
return SQUARES[pIndice];
}
/**
* Renvoi l'instance correspondant à une notation FEN.
*
* @param pChaine Chaine FEN décrivant la case.
* @return Instance correspondante.
*/
public static Square valueOf(final String pChaine)
{
if (pChaine == null)
{
throw new NullPointerException("Missing square string");
}
if (pChaine.length() != 2)
{
throw new IllegalArgumentException("Illegal square string [" + pChaine + ']');
}
return valueOf(pChaine.charAt(0) - 'a', pChaine.charAt(1) - '1');
}
/**
* Renvoi l'instance correspondant à une cellule.
*
* @param pColonne Colonne de la cellule (de 0 à 7).
* @param pLigne Ligne de la colonne (de 0 à 7).
* @return Instance correspondante.
*/
public static Square valueOf(final int pColonne, final int pLigne)
{
if ((pColonne < 0) || (pColonne >= FILE_COUNT))
{
throw new IllegalArgumentException("Illegal file [" + pColonne + ']');
}
if ((pLigne < 0) || (pLigne >= RANK_COUNT))
{
throw new IllegalArgumentException("Illegal rank [" + pLigne + ']');
}
return SQUARES[pColonne + pLigne * FILE_COUNT];
}
/**
* Renvoi la liste des cases.
*
* @return Liste des cases.
*/
public static Square [] values()
{
final Square [] res = new Square [ FILE_COUNT * RANK_COUNT ];
System.arraycopy(SQUARES, 0, res, 0, FILE_COUNT * RANK_COUNT);
return res;
}
}