/* Copyright 1996 Rujith de Silva. This code is in the public domain. */ package NET.industry.pento; import java.awt.*; import java.util.*; import NET.industry.util.*; import NET.industry.pento.*; public class Board extends Canvas { private int data[][][] = { { { 0, -2 }, /* I */ { 0, -1 }, { 0, 0 }, { 0, 1 }, { 0, 2 } }, { { 0, -2 }, /* L */ { 0, -1 }, { 0, 0 }, { 0, 1 }, { 1, 1 } }, { { 0, -2 }, /* Y */ { 0, -1 }, { 0, 0 }, { 0, 1 }, { 1, 0 } }, { { 0, -2 }, /* N */ { 0, -1 }, { 0, 0 }, { 1, 0 }, { 1, 1 } }, { { 0, 0 }, /* V */ { 0, 1 }, { 0, 2 }, { 1, 0 }, { 2, 0 } }, { { 0, -1 }, /* T */ { 0, 0 }, { 0, 1 }, { 1, 0 }, { 2, 0 } }, { { 0, -1 }, /* P */ { 0, 0 }, { 0, 1 }, { 1, 0 }, { 1, -1 } }, { { 0, -1 }, /* U */ { 0, 0 }, { 0, 1 }, { 1, -1 }, { 1, 1 } }, { { 0, -1 }, /* F */ { 0, 0 }, { 0, 1 }, { 1, 0 }, { -1, 1 } }, { { 0, -1 }, /* X */ { 0, 0 }, { 0, 1 }, { 1, 0 }, { -1, 0 } }, { { 0, -1 }, /* Z */ { 0, 0 }, { 0, 1 }, { 1, -1 }, { -1, 1 } }, { { 0, 0 }, /* W */ { 0, -1 }, { 1, -1 }, { -1, 0 }, { -1, 1 } } }; private int startpos[][] = { { 2, 12 }, { 5, 12 }, { 8, 12 }, { 11, 12 }, { 14, 10 }, { 18, 11 }, { 22, 11 }, { 2, 18 }, { 6, 18 }, { 10, 18 }, { 14, 18 }, { 18, 18 } }; private int xsize = 25, ysize = 25; private int squareSize = 14; private Dimension thisSize = new Dimension (xsize * squareSize, ysize * squareSize); protected BoardPiece board[][] = new BoardPiece [xsize][ysize]; protected BoardPiece boardtop[][] = new BoardPiece [xsize][ysize]; private boolean updated[][] = new boolean [xsize][ysize]; private Stack stack = new Stack (); private BoardPiece bps[] = new BoardPiece[12]; /* private double oldx, oldy; */ private int startx, starty; private int startDirection; private Position pos = new Position (0.0, 0.0); private BoardPiece currentbp, topbp; private boolean topbpSelected; private Color boardColor = new Color (100, 160, 255); private Color targetColor = new Color (0, 80, 180); private Color pieceColor = new Color (240, 0, 0); private Color pieceHighlightColor = new Color (255, 150, 100); private Color pieceTopColor = new Color (255, 230, 180); private int targetminx = 2; private int targetminy = 2; private int height = 6; private boolean needPaint = false; private int targetmaxy = targetminy + height; private int targetmaxx = targetminx + (60 / height); private BoardChange bc; private int boardStatus = 0; public Board (BoardChange bc) { this.bc = bc; setBackground (Color.lightGray); /* resize (squareSize * xsize, squareSize * ysize); */ pos.setNonRotateRadius (squareSize * 1.1); for (int i = 0; i < 12; ++i) bps[i] = new BoardPiece (data[i], this, startpos[i][0], startpos[i][1]); } public int getBoardStatus () { return boardStatus; } public int getHeight () { return height; } public void setHeight (int height) { if (height >= 3 && height <= 6 && this.height != height) { this.height = height; targetmaxy = targetminy + height; targetmaxx = targetminx + (60 / height); needPaint = true; repaint (); } } public boolean inTarget (int x, int y) { return x >= targetminx && x < targetmaxx && y >= targetminy && y < targetmaxy; } public void updateSquare (int x, int y) { if (inBounds (x, y)) { synchronized (stack) { if (! updated[x][y]) { updated[x][y] = true; stack.push (new Point (x, y)); } } } } private Point getUpdateSquare () { Point retval = null; synchronized (stack) { if (! stack.empty ()) { retval = (Point) stack.pop (); updated[retval.x][retval.y] = false; } } return retval; } public boolean inBounds (int x, int y) { return x >= 0 && x < xsize && y >= 0 && y < ysize; } public boolean mouseMove (Event evt, int x, int y) { int bx = x / squareSize; int by = y / squareSize; if (topbp == null && inBounds (bx, by)) { BoardPiece mbp = board[bx][by]; if (mbp != currentbp) { boardStatus = 0; bc.boardChanged (); if (currentbp != null) { currentbp.setStatus (0); currentbp = null; } if (mbp != null) { currentbp = mbp; currentbp.setStatus (1); } } } return true; } public boolean mouseDown (Event evt, int x, int y) { int bx = x / squareSize; int by = y / squareSize; if (inBounds (bx, by)) { BoardPiece mbp = getVisibleBoardPiece (bx, by); if (mbp != null && (topbp == null || topbp == mbp)) { pos.x = (mbp.xpos + 0.5) * squareSize; pos.y = (mbp.ypos + 0.5) * squareSize; if (pos.reset (x, y)) boardStatus = 2; else boardStatus = 1; /* bc.setCursor (Frame.HAND_CURSOR); bc.setCursor (Frame.MOVE_CURSOR); */ bc.boardChanged (); if (topbp != mbp) mbp.toTop (); topbp = mbp; topbpSelected = true; currentbp = null; startx = x; starty = y; startDirection = topbp.direction (); } } return true; } public boolean mouseUp (Event evt, int x, int y) { /* bc.setCursor (Frame.DEFAULT_CURSOR); */ boardStatus = 0; bc.boardChanged (); if (topbp != null && topbpSelected) { if (Math.abs (startx - x) <= 1 && Math.abs (starty - y) <= 1) topbp.doSwap (); if (topbp.toBottom ()) { topbp = null; } } topbpSelected = false; currentbp = null; return true; } public boolean mouseDrag (Event evt, int x, int y) { if (topbpSelected) { pos.move (x, y); int newbpx = (int) (pos.x / squareSize); int newbpy = (int) (pos.y / squareSize); int newdir = (((int) ((pos.azimuth + 2.0 * Math.PI) / (Math.PI / 2.0) + 0.5)) + startDirection) % 4; if ((newbpx != topbp.xpos || newbpy != topbp.ypos)) topbp.doMove (newbpx, newbpy); /* System.out.println ("azimuth: " + new Double (pos.azimuth) + ", newdir: " + new Integer (newdir) + ", topbp.dir: " + new Integer (topbp.direction ())); */ if (newdir != topbp.direction ()) topbp.changeDir (newdir); } return true; } public BoardPiece piece (int x, int y) { if (inBounds (x, y)) return board[x][y]; return null; } public BoardPiece pieceTop (int x, int y) { if (inBounds (x, y)) return boardtop[x][y]; return null; } private BoardPiece getVisibleBoardPiece (int x, int y) { if (! inBounds (x, y)) return null; else if (boardtop[x][y] != null) return boardtop[x][y]; else return board[x][y]; } private Color getPieceColor (BoardPiece bp) { switch (bp.getStatus ()) { case 0: return pieceColor; case 1: return pieceHighlightColor; default: return pieceTopColor; } } private void paintSquare (Graphics g, int x, int y) { Color sqc; BoardPiece sqbp; sqbp = getVisibleBoardPiece (x, y); if (sqbp != null) sqc = getPieceColor (sqbp); else if (inTarget (x, y)) sqc = targetColor; else sqc = boardColor; g.setColor (sqc); g.fillRect (x * squareSize, y * squareSize, squareSize, squareSize); if (sqbp != null) { g.setColor (Color.black); if (sqbp.getStatus () == 2) { if (pieceTop (x - 1, y) != sqbp) g.drawLine (x * squareSize, y * squareSize, x * squareSize, (y + 1) * squareSize - 1); if (pieceTop (x, y - 1) != sqbp) g.drawLine (x * squareSize, y * squareSize, (x + 1) * squareSize - 1, y * squareSize); if (pieceTop (x + 1, y) != sqbp) g.drawLine ((x + 1) * squareSize - 1, y * squareSize, (x + 1) * squareSize - 1, (y + 1) * squareSize - 1); if (pieceTop (x, y + 1) != sqbp) g.drawLine (x * squareSize, (y + 1) * squareSize - 1, (x + 1) * squareSize - 1, (y + 1) * squareSize - 1); } else { if (piece (x - 1, y) != sqbp) g.drawLine (x * squareSize, y * squareSize, x * squareSize, (y + 1) * squareSize - 1); if (piece (x, y - 1) != sqbp) g.drawLine (x * squareSize, y * squareSize, (x + 1) * squareSize - 1, y * squareSize); if (piece (x + 1, y) != sqbp) g.drawLine ((x + 1) * squareSize - 1, y * squareSize, (x + 1) * squareSize - 1, (y + 1) * squareSize - 1); if (piece (x, y + 1) != sqbp) g.drawLine (x * squareSize, (y + 1) * squareSize - 1, (x + 1) * squareSize - 1, (y + 1) * squareSize - 1); } } } private Color getSeparatorColor (int x1, int y1, int x2, int y2) { BoardPiece thisbp = getVisibleBoardPiece (x1, y1); BoardPiece otherbp = getVisibleBoardPiece (x2, y2); if (thisbp != null && thisbp == otherbp) return getPieceColor (thisbp); else if ((thisbp != null || otherbp != null) && thisbp != otherbp) return Color.black; else if (inTarget (x1, y1)) return targetColor; else return boardColor; } private void drawSeparatorX (Graphics g, int x, int y) { g.setColor (getSeparatorColor (x, y, x - 1, y)); g.drawLine (x * squareSize, y * squareSize, x * squareSize, (y + 1) * squareSize); } private void drawSeparatorY (Graphics g, int x, int y) { g.setColor (getSeparatorColor (x, y, x, y - 1)); g.drawLine (x * squareSize, y * squareSize, (x + 1) * squareSize, y * squareSize); } protected void paintPiece (Graphics g, BoardPiece bp) { if (bp != null) { for (int i = 0; i < 5; ++i) { paintSquare (g, bp.current[i][0] + bp.xpos, bp.current[i][1] + bp.ypos); } } } private void updateSquares (Graphics g) { Point d; while ((d = getUpdateSquare ()) != null) { paintSquare (g, d.x, d.y); } } public void paint (Graphics g) { g.setColor (boardColor); g.fillRect (0, 0, xsize * squareSize, ysize * squareSize); g.setColor (targetColor); g.fillRect (targetminx * squareSize, targetminy * squareSize, (targetmaxx - targetminx) * squareSize, (targetmaxy - targetminy) * squareSize); for (int i = 0; i < 12; ++i) paintPiece (g, bps[i]); updateSquares (g); needPaint = false; } public void update (Graphics g) { if (needPaint) paint (g); updateSquares (g); } public Dimension preferredSize () { return thisSize; } public Dimension minimumSize () { return thisSize; } }