/*
* Maze
* Copyright (C) 2000 Paul Davis, pdavis@lpccomp.bc.ca
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
import java.util.*;
import java.awt.*;
/**
* Draw a 2D maze in an AWT Component.
* There is no user input.
*/
public class Maze2D extends Component implements MazeListener {
/**
* The maze model.
* @see Maze
*/
private MazeModel model;
/**
* The width of each displayed cell of the maze.
*/
private int cellWidth;
/**
* The size of the maze displayed.
*/
private Coordinate3D siz;
/**
* The current Z co-ordinate being displayed.
*/
private int z;
/**
* The number of cells to display in the X and Y dimensions.
* They will be no larger than the dimensions of the maze.
*/
private int dispWidth,dispHeight;
/**
* Create a 2D maze display with a cell size of 20 pixels.
* @param model The MazeModel used as the source of the maze.
*/
public Maze2D(MazeModel model) {
this(model,20);
}
/**
* Create a 2D maze display.
* @param model The MazeModel used as the source of the maze.
* @param cellSize The cell size in pixels.
*/
public Maze2D(MazeModel model, int cellSize) {
this(model, cellSize, model.getSize().x, model.getSize().y);
}
/**
* Create a 2D maze display.
* @param model The MazeModel used as the source of the maze.
* @param cellSize The cell size in pixels.
* @param dispWidth The number of horizontal cells to display at a time.
* @param dispHeight The number of vertical cells to display at a time.
*/
public Maze2D(MazeModel model, int cellSize, int dispWidth, int dispHeight) {
this.model = model;
if ( dispWidth >= model.getSize().x )
dispWidth = model.getSize().x;
if ( dispHeight >= model.getSize().y )
dispHeight = model.getSize().y;
this.dispWidth = dispWidth;
this.dispHeight = dispHeight;
siz = model.getSize();
//System.out.println("model size = " + String.valueOf(siz.x) +
// "," + String.valueOf(siz.y));
cellWidth = cellSize;
z = 0;
model.addMazeListener(this);
}
/**
* From Component.getPreferredSize.
*/
public Dimension getPreferredSize() {
//Dimension d = new Dimension(siz.x * cellWidth, siz.y * cellWidth);
//System.out.println("getPreferredSize: " + d.toString());
return new Dimension(dispWidth * cellWidth+1, dispHeight * cellWidth+1);
}
/**
* From interface MazeListener.
* The maze has changed, just repaint.
*/
public void mazeChanged(EventObject e) {
repaint();
}
/**
* Set the Z co-ordinate of the maze being displayed.
* Repaints the display.
*/
public void setZ(int z) {
this.z = z;
repaint();
}
/**
* Get the Z co-ordinate of the maze being displayed.
*/
public int getZ() {
return z;
}
/**
* Paint the maze. From Component.
*/
public void paint(Graphics g) {
Dimension s = getSize();
//System.out.println("Maze2D: " + s.toString());
int x,y;
int b = cellWidth/3;
g.setColor(Color.white);
g.fillRect(0,0,s.width,s.height);
Coordinate3D current = model.getCurrent();
if ( current != null )
z = current.z;
// Figure out the X and Y offsets for when the displayed
// size is less than the maze size.
int xoff = 0;
if ( current != null ) {
xoff = current.x - dispWidth/2;
if ( xoff < 0 )
xoff = 0;
if ( xoff + dispWidth > siz.x )
xoff = siz.x - dispWidth;
}
int yoff = 0;
if ( current != null ) {
yoff = current.y - dispHeight/2;
if ( yoff < 0 )
yoff = 0;
if ( yoff + dispHeight > siz.y )
yoff = siz.y - dispHeight;
}
// Draw the outside edge.
g.setColor(Color.black);
for ( y=0 ; y<=dispHeight ; y+=dispHeight )
g.drawLine(0,y*cellWidth,s.width,y*cellWidth);
for ( x=0 ; x<=dispWidth ; x+=dispWidth )
g.drawLine(x*cellWidth,0,x*cellWidth,s.height);
byte value;
for ( y=0 ; y<dispHeight ; y++ ) {
for ( x=0 ; x<dispWidth ; x++ ) {
value = model.grid(x+xoff,y+yoff,z);
// Wall to the left
if ( (value & MazeModel.XMI) == 0 )
g.drawLine(x*cellWidth,y*cellWidth,
x*cellWidth,(y+1)*cellWidth);
// Wall above
if ( (value & MazeModel.YMI) == 0 )
g.drawLine(x*cellWidth,y*cellWidth,
(x+1)*cellWidth,y*cellWidth);
// Pathway up - draw an up arrow.
if ( (value & MazeModel.ZPL) != 0 ) {
int topx = x*cellWidth+cellWidth/2;
int topy = y*cellWidth+3;
g.drawLine(topx,topy,
topx,topy+cellWidth-6);
g.drawLine(topx-2,topy+2,topx,topy);
g.drawLine(topx+2,topy+2,topx,topy);
}
// Pathway Down - draw an down arrow.
if ( (value & MazeModel.ZMI) != 0 ) {
int botx = x*cellWidth+cellWidth/2;
int boty = (y+1)*cellWidth-3;
g.drawLine(botx,boty,
botx,boty-cellWidth+6);
g.drawLine(botx-2,boty-2,botx,boty);
g.drawLine(botx+2,boty-2,botx,boty);
}
/*
if ( (value & MazeModel.ZPL) != 0 )
System.out.print('u');
else if ( (value & MazeModel.MARK) != 0 )
System.out.print('.');
else
System.out.print(' ');
if ( (value & MazeModel.ZMI) != 0 )
System.out.print('d');
else if ( (value & MazeModel.MARK) != 0 )
System.out.print('.');
else
System.out.print(' ');
*/
if ( model.isMarked(new Coordinate3D(x+xoff,y+yoff,z)) ) {
g.fillRect(x*cellWidth+b,y*cellWidth+b,b,b);
}
}
}
// Draw a red block in the finish cell.
Coordinate3D finish = model.getFinish();
if ( finish != null && finish.z == z ) {
g.setColor(Color.red);
g.fillRect((finish.x-xoff)*cellWidth+b,(finish.y-yoff)*cellWidth+b,
b,b);
}
// Draw a green block in the current play position cell.
if ( current != null && current.z == z ) {
g.setColor(Color.green);
g.fillRect((current.x-xoff)*cellWidth+b,(current.y-yoff)*cellWidth+b,
b,b);
}
}
}