package eu.semberal.migmang.graphics;
import eu.semberal.migmang.enums.GameColor;
import java.awt.event.MouseEvent;
import eu.semberal.migmang.logic.Move;
import eu.semberal.migmang.logic.Board;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import javax.swing.JComponent;
import eu.semberal.migmang.logic.Referee;
import eu.semberal.migmang.logic.MoveContainer;
/**
* Component the board will be painted on. Will also handle event from the user.
*
* @author lukas.sembera
*
*/
public class MigmangBoardComponent extends JComponent {
private int width, height;
private int squareWidth;
private Point topLeftBoardPosition;
private int pieceRadius;
private final int boardMargin;
private Board currentBoard = null;
GameColor movingColor = null;
MoveContainer moveContainer = null;
int movingPiece = -1;
/**
* Array of upper left corner point of pieces on the board
*/
private Point[] piecesTopLeftCorners;
public void allowMove(GameColor color, MoveContainer container) {
this.moveContainer = container;
this.movingColor = color;
}
public void setBoard(Board board) {
this.currentBoard = board;
}
public MigmangBoardComponent() {
topLeftBoardPosition = new Point();
boardMargin = 50;
piecesTopLeftCorners = new Point[81];
BoardComponentsEvent tridaUdalosti = new BoardComponentsEvent();
this.addMouseListener(tridaUdalosti);
this.addMouseMotionListener(tridaUdalosti);
}
@Override
public synchronized void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if (movingPiece == -1) {
MigmangBoardComponent.this.updatePiecesCoordinates(true);
MigmangBoardComponent.this.updateBoardVariables(true);
}
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.GRAY);
g.fillRect(0, 0, this.getSize().width, this.getSize().height);
drawBoard(g2d);
drawCoordinates(g2d);
if (currentBoard != null) {
drawPieces(g2d);
}
if (movingPiece != -1) {
drawPossibleMoves(g2d);
}
}
private void drawPieces(Graphics2D g) {
for (int i = 0; i < 81; i++) {
if (piecesTopLeftCorners[i] == null) {
continue;
}
if (currentBoard.getSquare(i) != null) {
g.setColor(currentBoard.getSquare(i) == GameColor.White ? Color.WHITE : Color.BLACK);
g.fillOval(piecesTopLeftCorners[i].x, piecesTopLeftCorners[i].y, 2 * pieceRadius, 2 * pieceRadius);
g.setColor(currentBoard.getSquare(i) == GameColor.Black ? Color.WHITE : Color.BLACK);
g.drawOval(piecesTopLeftCorners[i].x, piecesTopLeftCorners[i].y, 2 * pieceRadius, 2 * pieceRadius);
}
}
}
private void drawBoard(Graphics2D g) {
for (int i = 0; i < 64; i++) {
g.setStroke(new BasicStroke(2));
int tempX = topLeftBoardPosition.x + (i % 8) * squareWidth;
int tempY = topLeftBoardPosition.y + (i / 8) * squareWidth;
g.setColor((i / 8 + i % 8) % 2 == 0 ? Color.RED : Color.YELLOW);
g.fillRect(tempX, tempY, squareWidth,
squareWidth);
g.setColor(Color.black);
g.drawRect(tempX, tempY, squareWidth,
squareWidth);
}
}
private void drawPossibleMoves(Graphics2D g2d) {
g2d.setStroke(new BasicStroke(1));
g2d.setColor(Color.BLACK);
for (Move t : Referee.getAvailableMoves(currentBoard, movingPiece)) {
int vykresli = t.getTo();
g2d.drawOval(topLeftBoardPosition.x + (vykresli % 9) * squareWidth - pieceRadius,
topLeftBoardPosition.y + (vykresli / 9) * squareWidth - pieceRadius,
2 * pieceRadius,
2 * pieceRadius);
}
}
/**
* Updates variables such as board size, etc. Values are different on each
* resize
*
* @param repaint Whether the board should be repainted
*/
public void updateBoardVariables(boolean repaint) {
this.width = this.getSize().width;
this.height = this.getSize().height;
this.squareWidth = (Math.min(width, height) - 2 * boardMargin) / 8;
this.topLeftBoardPosition.x = (width - 8 * squareWidth) / 2;
this.topLeftBoardPosition.y = (height - 8 * squareWidth) / 2;
this.pieceRadius = Math.min(squareWidth / 4, 30);
if (repaint) {
this.repaint();
}
}
/**
* Recalculates coordinates of pieces
*
* @param repaint Whether the board should be repainted
*/
public synchronized void updatePiecesCoordinates(boolean repaint) {
if (currentBoard != null) {
GameColor s;
for (int i = 0; i < piecesTopLeftCorners.length; i++) {
s = currentBoard.getSquare(i);
int aktX, aktY;
if (s == null) {
piecesTopLeftCorners[i] = null;
} else {
aktX = topLeftBoardPosition.x + (i % 9) * squareWidth;
aktY = topLeftBoardPosition.y + (i / 9) * squareWidth;
piecesTopLeftCorners[i] = new Point(aktX - pieceRadius, aktY - pieceRadius);
}
}
}
if (repaint) {
this.repaint();
}
}
/**
* Draws coordinates ('A', '1', ...)
*/
public synchronized void drawCoordinates(Graphics g2d) {
int h;
g2d.setFont(new Font("serif", Font.BOLD, h = squareWidth / 2));
for (int i = 0; i < 9; i++) {
String s = String.valueOf(i);
g2d.drawString(s, topLeftBoardPosition.x + squareWidth * i, topLeftBoardPosition.y - 7);
}
for (int i = 0; i < 9; i++) {
char c = (char) ('A' + i);
String s = String.valueOf(c);
g2d.drawString(s, topLeftBoardPosition.x - squareWidth / 2,
topLeftBoardPosition.y + h / 2 + squareWidth * i);
}
}
/**
* Events of the board component, will call methods of the main window and
* notify controller
*/
private class BoardComponentsEvent extends MouseAdapter {
/*
* Difference between point pushed and topleft corner of the piece.
* Necessary to draw draggin correctly.
*/
private int diffX, diffY;
/**
* How large rectangle will be repainted on move (speed optimization)
*/
private final int REDRAW_MARGIN = 3;
@Override
public void mouseDragged(MouseEvent e) {
if (movingPiece != -1) {
piecesTopLeftCorners[movingPiece] = new Point(e.getPoint().x - diffX, e.getPoint().y - diffY);
MigmangBoardComponent.this.repaint(
e.getX() - REDRAW_MARGIN * squareWidth,
e.getY() - REDRAW_MARGIN * squareWidth,
2 * REDRAW_MARGIN * squareWidth,
2 * REDRAW_MARGIN * squareWidth);
}
}
@Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
if (movingColor == null) {
return;
}
for (int i = 0; i < piecesTopLeftCorners.length; i++) {
if (currentBoard.getSquare(i) != movingColor) {
continue;
}
if (new Rectangle(piecesTopLeftCorners[i].x, piecesTopLeftCorners[i].y, 2 * pieceRadius, 2 * pieceRadius).contains(e.getPoint())) {
diffX = e.getPoint().x - piecesTopLeftCorners[i].x;
diffY = e.getPoint().y - piecesTopLeftCorners[i].y;
movingPiece = i;
break;
}
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (movingPiece == -1) {
return;
}
for (int i = 0; i < piecesTopLeftCorners.length; i++) {
if (new Rectangle(topLeftBoardPosition.x + (i % 9) * squareWidth - pieceRadius,
topLeftBoardPosition.y + (i / 9) * squareWidth - pieceRadius,
2 * pieceRadius,
2 * pieceRadius).contains(e.getPoint())) {
moveContainer.setMove(new Move(movingPiece, i, movingColor));
movingColor = null;
movingPiece = -1;
return;
}
}
movingColor = null;
movingPiece = -1;
/*
* If not placed on incorrect square, report incorrect move.
* Controller will then ask for new one.
*/
moveContainer.setMove(Move.createIncorrectMove());
}
}
}