package kakuro.gui;
import kakuro.table.ITable;
import kakuro.table.Position;
import kakuro.table.TableException;
import java.awt.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
/** Játéktábla a grafikus felületen. */
class Gametable extends JPanel {
static final long serialVersionUID = 1245754545l;
/** Grafikus felület */
private Gui _gui = null;
/** A megjelenítés mögött álló táblamodell, innen jönnek az adatok */
private ITable _table = null;
/** tábla szélessége */
private int _x = 4;
/** tábla magassága */
private int _y = 4;
/** a cellákat tartalmazó kétdimenziós tömb */
private Gamefield _fields[][] = new Gamefield[_x][_y];
/** Alap konstruktor. Méretet állítja be, hátteret, és a cellákat tartalmazó GridLayout-ot rakja össze.
*
* @param gui grafikus felület
* */
Gametable(Gui gui) {
super();
_gui = gui;
setOpaque(false);
setDoubleBuffered(true);
setPreferredSize(new Dimension(_x * 80, _y * 80));
setMinimumSize(new Dimension(_x * 40, _y * 40));
GridLayout layout = new GridLayout(_x, _y, 1, 1);
setLayout(layout);
clear();
}
/** Törli a táblát. */
public void clear() {
removeAll();
for (int i = 0; i < _x; i++) {
for (int j = 0; j < _y; j++) {
add(new GamefieldNone(_gui, this, i + "," + j, new Position(i,
j)));
}
}
validate();
}
/** Adatok betöltése a kapott modellből. Létrehozza a cellákat, és elhelyezi őket.
*
* @param table tábla adatmodellje
* */
public void load(ITable table) throws TableException {
removeAll();
_table = table;
_x = table.getColumnCount();
_y = table.getRowCount();
_fields = new Gamefield[_x][_y];
setPreferredSize(new Dimension(_x * 80, _y * 80));
setMinimumSize(new Dimension(_x * 40, _y * 40));
GridLayout layout = new GridLayout(_y, _x, 1, 1);
setLayout(layout);
for (int j = 0; j < _y; j++) {
for (int i = 0; i < _x; i++) {
Gamefield g = null;
Position pos = new Position(i, j);
switch (table.getType(pos)) {
case ITable.BLACK_NONE:
g = new GamefieldNone(_gui, this, "", pos);
break;
case ITable.BLACK_VERTICAL:
g = new GamefieldBlack(_gui, this, table.getSum(pos,
ITable.SUM_VERTICAL), 0, pos);
break;
case ITable.BLACK_HORIZONTAL:
g = new GamefieldBlack(_gui, this, 0, table.getSum(pos,
ITable.SUM_HORIZONTAL), pos);
break;
case ITable.BLACK_BOTH:
g = new GamefieldBlack(_gui, this, table.getSum(pos,
ITable.SUM_VERTICAL), table.getSum(pos,
ITable.SUM_HORIZONTAL), pos);
break;
case ITable.WHITE:
int user = table.readCell(pos, ITable.VALUE_NORMAL);
g = new GamefieldWhite(_gui, this, ""
+ table.readCell(pos, ITable.VALUE_TRUE), pos, (user>0?""+user:null));
break;
}
add(g);
_fields[i][j] = g;
}
}
validate();
repaint();
}
/** Adatmodell lekérése
*
* @return adatmodell
* */
public ITable getModel() {
return _table;
}
/** Adott pozíciótól jobbra hol található az első nem fehér cella. Szóhossz számításhoz kell.
*
* @param p kiindulási pozíció
* @return távolság jobbra
* */
public int getRunToRight(Position p) {
for (int i = p.x + 1; i < _x; i++) {
Position _p = new Position(i, p.y);
if (_table.getType(_p) != ITable.WHITE)
return i - p.x - 1;
}
return _x - p.x - 1;
}
/** Adott pozíciótól lefelé hol található az első nem fehér cella. Szóhossz számításhoz kell.
*
* @param p kiindulási pozíció
* @return távolság lefelé
* */
public int getRunToDown(Position p) {
for (int i = p.y + 1; i < _y; i++) {
Position _p = new Position(p.x, i);
if (_table.getType(_p) != ITable.WHITE)
return i - p.y - 1;
}
return _y - p.y - 1;
}
/** Adott pozíciótól balra hol található az első fekete cella. Szóhossz számításhoz kell.
*
* @param p kiindulási pozíció
* @return távolság balra
* */
public Position getFirstBlackToLeft(Position p) {
for (int i = p.x - 1; i >= 0; i--) {
if (_table.getType(new Position(i, p.y)) != ITable.WHITE)
return new Position(i, p.y);
}
return new Position(0, p.y);
}
/** Adott pozíciótól felfelé hol található az első fekete cella. Szóhossz számításhoz kell.
*
* @param p kiindulási pozíció
* @return távolság felfelé
* */
public Position getFirstBlackToUp(Position p) {
for (int i = p.y - 1; i >= 0; i--) {
if (_table.getType(new Position(p.x, i)) != ITable.WHITE)
return new Position(p.x, i);
}
return new Position(p.x, 0);
}
/** Adott pozícióhoz tartozó összeg lekérése.
*
* @param p pozíció
* @param type összeg típusa, lehetséges értékek: {@link ITable#SUM_HORIZONTAL}, {@link ITable#SUM_HORIZONTAL}
* @return összeg
* */
public int getSum(Position p, int type) {
try {
return _table.getSum(p, type);
} catch (TableException te) {
te.printStackTrace();
return 0;
}
}
/** Az adott pozícióhoz tartozó vízszintes blokk celláinak értéke
*
* @param p adott pozíció
* @return vízszintes szó számjegyei
* */
public int[] getHorizontalBlock(Position p)throws TableException {
int length;
Position _p_sum;
_p_sum = getFirstBlackToLeft(p);
length = getRunToRight(_p_sum);
int[] block = new int[length];
for (int i=_p_sum.x+1; i<=_p_sum.x+length; i++) {
Position _p = new Position(i, p.y);
block[i-_p_sum.x-1] = _table.readCell(_p,1);
}
return block;
}
/** Az adott pozícióhoz tartozó függőleges blokk celláinak értéke
*
* @param p adott pozíció
* @return függőleges szó számjegyei
* */
public int[] getVerticalBlock(Position p)throws TableException {
int length;
Position _p_sum;
_p_sum = getFirstBlackToUp(p);
length = getRunToDown(_p_sum);
int[] block = new int[length];
for (int i=_p_sum.y+1; i<=_p_sum.y+length; i++) {
Position _p = new Position(p.x,i);
block[i-_p_sum.y-1] = _table.readCell(_p,1);
}
return block;
}
/** Megkeresi az adott blokkban az adott számjegyet, ha megtalálja, visszaadja az indexét, egyébként -1-et.
*
* @param b számjegyek
* @param c keresett szám
* @return számjegy helye a tömbben, ha nincs benne akkor -1
* */
public int duplicatedDigitInBlock(int[] b, int c) {
int index = -1;
for(int i = 0; i < b.length; i++)
if (b[i] == c)
index = i;
return index;
}
/** Egy teljesen kitöltött blokkra leellenőrzi, hogy stimmel-e a vízszintes összeg.
*
* @param p a blokk egy tetszőleges tagja
* @param b az egyes számjegyek
* @return helyes-e az összeg
* */
public boolean horizontalSumIsOK(Position p, int[] b){
int sum = 0;
for (int i = 0;i < b.length; i++){
sum = sum + b[i];
}
return (getSum(getFirstBlackToLeft(p),ITable.SUM_HORIZONTAL) == sum);
}
/** Egy teljesen kitöltött blokkra leellenőrzi, hogy stimmel-e a függőleges összeg.
*
* @param p a blokk egy tetszőleges tagja
* @param b az egyes számjegyek
* @return helyes-e az összeg
* */
public boolean verticalSumIsOK(Position p, int[] b){
int sum = 0;
for (int i = 0;i < b.length; i++){
sum = sum + b[i];
}
return (getSum(getFirstBlackToUp(p),ITable.SUM_VERTICAL) == sum);
}
/** Végignéz egy adott blokkot, ki van-e töltve teljesen.
*
* @param b számjegyek
* @return ki van-e töltve teljesen
* */
public boolean blockIsFull(int[] b) {
int count = 0;
for (int i= 0; i<b.length; i++) {
if (b[i] == 0) count++;
}
return (count == 0);
}
/**
* Felvillantja a kapott pozíciókhoz tartozó mezőket a képernyőn.
*
* @param positions pozíciók listája
* */
public void flashFields(List<Position> positions) {
Iterator<Position> it = positions.iterator();
while (it.hasNext()) {
Position p = it.next();
_fields[p.x][p.y].flash();
}
}
}