/*
CuckooChess - A java chess program.
Copyright (C) 2011 Peter Ă–sterlund, peterosterlund2@gmail.com
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 3 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, see <http://www.gnu.org/licenses/>.
*/
package org.petero.cuckoochess;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import chess.Move;
import chess.Piece;
import chess.Position;
public class ChessBoard extends View {
private Position pos;
private int selectedSquare;
private float cursorX, cursorY;
private boolean cursorVisible;
private int x0, y0, sqSize;
private boolean flipped;
private Paint darkPaint;
private Paint brightPaint;
private Paint redOutline;
private Paint greenOutline;
private Paint whitePiecePaint;
private Paint blackPiecePaint;
public ChessBoard(Context context, AttributeSet attrs) {
super(context, attrs);
pos = new Position();
selectedSquare = -1;
cursorX = cursorY = 0;
cursorVisible = false;
x0 = y0 = sqSize = 0;
flipped = false;
darkPaint = new Paint();
darkPaint.setARGB(255, 128, 128, 128);
brightPaint = new Paint();
brightPaint.setARGB(255, 190, 190, 90);
redOutline = new Paint();
redOutline.setARGB(255, 255, 0, 0);
redOutline.setStyle(Paint.Style.STROKE);
redOutline.setAntiAlias(true);
greenOutline = new Paint();
greenOutline.setARGB(255, 0, 255, 0);
greenOutline.setStyle(Paint.Style.STROKE);
greenOutline.setAntiAlias(true);
whitePiecePaint = new Paint();
whitePiecePaint.setARGB(255, 255, 255, 255);
whitePiecePaint.setAntiAlias(true);
blackPiecePaint = new Paint();
blackPiecePaint.setARGB(255, 0, 0, 0);
blackPiecePaint.setAntiAlias(true);
}
public void setFont(Typeface tf) {
whitePiecePaint.setTypeface(tf);
blackPiecePaint.setTypeface(tf);
invalidate();
}
/**
* Set the board to a given state.
* @param pos
*/
final public void setPosition(Position pos) {
this.pos = pos;
invalidate();
}
/**
* Set/clear the board flipped status.
* @param flipped
*/
final public void setFlipped(boolean flipped) {
this.flipped = flipped;
invalidate();
}
/**
* Set/clear the selected square.
* @param square The square to select, or -1 to clear selection.
*/
final public void setSelection(int square) {
if (square != selectedSquare) {
selectedSquare = square;
invalidate();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int minSize = Math.min(width, height);
setMeasuredDimension(minSize, minSize);
}
@Override
protected void onDraw(Canvas canvas) {
final int width = getWidth();
final int height = getHeight();
sqSize = (Math.min(width, height) - 4) / 8;
x0 = (width - sqSize * 8) / 2;
y0 = (height - sqSize * 8) / 2;
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
final int xCrd = getXCrd(x);
final int yCrd = getYCrd(y);
Paint paint = Position.darkSquare(x, y) ? darkPaint : brightPaint;
canvas.drawRect(xCrd, yCrd, xCrd+sqSize, yCrd+sqSize, paint);
int sq = Position.getSquare(x, y);
int p = pos.getPiece(sq);
drawPiece(canvas, xCrd + sqSize / 2, yCrd + sqSize / 2, p);
}
}
if (selectedSquare >= 0) {
int selX = Position.getX(selectedSquare);
int selY = Position.getY(selectedSquare);
redOutline.setStrokeWidth(sqSize/(float)16);
int x0 = getXCrd(selX);
int y0 = getYCrd(selY);
canvas.drawRect(x0, y0, x0 + sqSize, y0 + sqSize, redOutline);
}
if (cursorVisible) {
int x = Math.round(cursorX);
int y = Math.round(cursorY);
int x0 = getXCrd(x);
int y0 = getYCrd(y);
greenOutline.setStrokeWidth(sqSize/(float)16);
canvas.drawRect(x0, y0, x0 + sqSize, y0 + sqSize, greenOutline);
}
}
private final void drawPiece(Canvas canvas, int xCrd, int yCrd, int p) {
String ps;
switch (p) {
case Piece.EMPTY:
ps = "";
break;
case Piece.WKING:
ps = "k";
break;
case Piece.WQUEEN:
ps = "q";
break;
case Piece.WROOK:
ps = "r";
break;
case Piece.WBISHOP:
ps = "b";
break;
case Piece.WKNIGHT:
ps = "n";
break;
case Piece.WPAWN:
ps = "p";
break;
case Piece.BKING:
ps = "l";
break;
case Piece.BQUEEN:
ps = "w";
break;
case Piece.BROOK:
ps = "t";
break;
case Piece.BBISHOP:
ps = "v";
break;
case Piece.BKNIGHT:
ps = "m";
break;
case Piece.BPAWN:
ps = "o";
break;
default:
ps = "?";
break;
}
if (ps.length() > 0) {
Paint paint = Piece.isWhite(p) ? whitePiecePaint : blackPiecePaint;
paint.setTextSize(sqSize);
Rect bounds = new Rect();
paint.getTextBounds(ps, 0, ps.length(), bounds);
int xCent = bounds.centerX();
int yCent = bounds.centerY();
canvas.drawText(ps, xCrd - xCent, yCrd - yCent, paint);
}
}
private final int getXCrd(int x) {
return x0 + sqSize * (flipped ? 7 - x : x);
}
private final int getYCrd(int y) {
return y0 + sqSize * (flipped ? y : (7 - y));
}
/**
* Compute the square corresponding to the coordinates of a mouse event.
* @param evt Details about the mouse event.
* @return The square corresponding to the mouse event, or -1 if outside board.
*/
final int eventToSquare(MotionEvent evt) {
int xCrd = (int)(evt.getX());
int yCrd = (int)(evt.getY());
int sq = -1;
if ((xCrd >= x0) && (yCrd >= y0) && (sqSize > 0)) {
int x = (xCrd - x0) / sqSize;
int y = 7 - (yCrd - y0) / sqSize;
if ((x >= 0) && (x < 8) && (y >= 0) && (y < 8)) {
if (flipped) {
x = 7 - x;
y = 7 - y;
}
sq = Position.getSquare(x, y);
}
}
return sq;
}
final Move mousePressed(int sq) {
if (sq < 0)
return null;
cursorVisible = false;
if (selectedSquare >= 0) {
int p = pos.getPiece(selectedSquare);
if ((p == Piece.EMPTY) || (Piece.isWhite(p) != pos.whiteMove)) {
setSelection(-1); // Remove selection of opponents last moving piece
}
}
int p = pos.getPiece(sq);
if (selectedSquare >= 0) {
if (sq != selectedSquare) {
if ((p == Piece.EMPTY) || (Piece.isWhite(p) != pos.whiteMove)) {
Move m = new Move(selectedSquare, sq, Piece.EMPTY);
setSelection(sq);
return m;
}
}
setSelection(-1);
} else {
boolean myColor = (p != Piece.EMPTY) && (Piece.isWhite(p) == pos.whiteMove);
if (myColor) {
setSelection(sq);
}
}
return null;
}
public static class OnTrackballListener {
public void onTrackballEvent(MotionEvent event) { }
}
OnTrackballListener otbl = null;
public void setOnTrackballListener(OnTrackballListener onTrackballListener) {
otbl = onTrackballListener;
}
@Override
public boolean onTrackballEvent(MotionEvent event) {
if (otbl != null) {
otbl.onTrackballEvent(event);
return true;
}
return false;
}
public Move handleTrackballEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
invalidate();
if (cursorVisible) {
int x = Math.round(cursorX);
int y = Math.round(cursorY);
cursorX = x;
cursorY = y;
int sq = Position.getSquare(x, y);
return mousePressed(sq);
}
return null;
}
cursorVisible = true;
int c = flipped ? -1 : 1;
cursorX += c * event.getX();
cursorY -= c * event.getY();
if (cursorX < 0) cursorX = 0;
if (cursorX > 7) cursorX = 7;
if (cursorY < 0) cursorY = 0;
if (cursorY > 7) cursorY = 7;
invalidate();
return null;
}
}