Hunt The Wumpus

<< Worm Game | FinalProjectsTrailIndex | Gridworld Dice Games >>

The code here has a fairly complete user interface that has a 3D Dodectrahedron (You need red-blue 3d glasses). To fuly implement the game, you need to make a Room class that can be filled with bats, pits and a smelly wumpus. Look for "//todo" in the code for details. The Room needs to be able to report if it has

  • gold
  • a bottomless pit
  • bats that transport the player to a random room
  • a deadly wumpus that will eat the player

You would also need to a write a method in the WumpusApplet that will randomly place these hazards in the the 20 Rooms.

The UI demonstrates rotation around axes controlled by a click and drag, and double buffering that removes a flicker that occurs in Windows.

For a complete description of this classic game see the Wikipeadia article

To see a working demo of the user interface, click here

WumpusApplet.java

import java.applet.Applet;
import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;


public class WumpusApplet extends Applet implements ActionListener, MouseMotionListener, MouseListener
{
	private Button forward,turnL, turnR, grab, shoot,help, look;
	private String direction, message, message2, contents, turn;
	private int loc, nextLoc, gold;
	private Dodectrahedron d;
	private ArrayList<Button> btns;
	private Rectangle view1, view2;
	//double buffering to remove Windows flicker:
	private Image screen2;
	private Graphics g2;
	// mouse drag to rotate
	private int startX = -1, startY = -1;
	private int curX = -1, curY = -1;
	private boolean inDrag=false;
	private int  yAng, xAng, dX, dY, deaths, kills;
	private ArrayList<Integer> shot,visited;

	private static final boolean ORTHO = true;
	private static final double LEFT = 0;// Degree separation for left view
	private static final double RIGHT = 4.0;// Degree separation for right view
	private static final double LOW = .14; // HEIGHT of spikes and Dot
	private static final Color cyan = new Color(0, 255,255,50);
	private static final Color red = new Color (255, 0,0,50);

	//todo: private Room[] rooms;

	public void init(){

		setUpGame();
		int deaths=0;
		int kills=0;
		gold=0;
		this.setLayout(new FlowLayout());
		setUpButtons();
		view1= new Rectangle(425, 300, 250,250 );
		view2= new Rectangle(75, 300, 250,250 );
		yAng=0;//rot around yAxis
		xAng=0;//rot around xAxis
		dX=dY=0;//slope of the mouse dragging
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
	}
	private void setUpGame() {
		direction="straight ahead";
		contents ="You seem to be in an empty room";
		message="Hunt the Wumpus!";
		message2="";
		turn="left";
		loc=0;
		nextLoc=0;
		d=new Dodectrahedron();
		shot=new ArrayList<Integer>();
		visited=new ArrayList<Integer>();
		//todo: Initialize 20 rooms
		//todo: Randomly fill the rooms with bats, pits and a wupus.
	}
	private void setUpButtons() {
		forward = new Button("Go Forward");
		turnL = new Button("Turn Left");
		turnR = new Button("Turn Right");
		grab = new Button("Grab");
		shoot = new Button("Shoot Arrow");
		help = new Button("Help");
		look = new Button("Look");
		btns = new ArrayList<Button>();
		btns.add(forward);
		btns.add(turnL);
		btns.add(turnR);
		btns.add(grab);
		btns.add(shoot);
		btns.add(help);
		btns.add(look);		
		for(Button b:btns){
			b.addActionListener(this);
			add(b);
		}
	}
	public void paint(Graphics g){
		int width=getWidth();
		int height=getHeight();
		screen2 = createImage(width,height);
		g2 = screen2.getGraphics();

		g2.setColor(Color.WHITE);
		g2.fillRect(0, 0, width, height);
		g2.setColor(Color.BLACK);

		g2.drawString(message, 20, 120);
		g2.drawString(message2, 20, 140);
		g2.drawString("You are facing "+direction, 20, 180);
		g2.drawString(contents, 20, 200);
		g2.drawString("You have "+gold+" gold", 20, 220);
		g2.drawString("You have been killed "+deaths+" times", 20, 240);
		g2.drawString("You have killed a wumpus "+gold+" times", 20, 260);


		g2.drawString("y axis angle ="+(d.getyAxisAngle()), 350, 260);
		g2.drawString("x axis angle ="+d.getxAxisAngle(), 350, 280);


		g2.drawRect(view1.x, view1.y, view1.width, view1.height);
		g2.drawRect(view2.x, view2.y, view2.width, view2.height);
		drawStereo(g2, view1);
		drawOrtho(g2, view2);
		//draw g2 to screen 
		g.drawImage(screen2, 0,0,this);

	}
	private void drawStereo(Graphics g, Rectangle view) {
		//left cyan
				g.setColor(cyan);
				for (int i=0; i<12; i++){
					g.drawPolygon(d.getFace(i).getOrthoPolygon(view, yAng+dY, xAng+dX));
				}

				d.drawEdges(g, view, ORTHO);
				d.spikeVertex(g, view, 0, LOW, ORTHO, LEFT);
				d.drawDot(g, view, loc, LOW, ORTHO, LEFT);
				d.point2Vertex(g, view, loc, nextLoc, ORTHO, LEFT);


				//right red
				g.setColor(red);
				for (int i=0; i<12; i++){
					g.drawPolygon(d.getFace(i).getOrthoPolygon(view, yAng+dY+RIGHT, xAng+dX));					
				}

				//d.drawEdgesOrtho(g, screenR);
				d.spikeVertex(g, view, loc, 1.0, ORTHO, RIGHT);
				d.drawDot(g, view, loc, LOW, ORTHO, RIGHT);
				d.point2Vertex(g, view, loc,nextLoc, ORTHO, RIGHT);

	}
	private void drawOrtho(Graphics g, Rectangle view) {
		for (int i=0; i<12; i++){
			g.setColor(d.getFace(i).getColor());
			g.fillPolygon(d.getFace(i).getOrthoPolygon(view, yAng+dY, xAng+dX));

		}
		g.setColor(Color.BLACK);
		d.drawEdges(g, view, ORTHO);
		d.spikeVertex(g, view, loc, LOW, ORTHO, LEFT);		
		d.spikeVertex(g, view, loc,LOW, ORTHO, LEFT);
		d.drawDot(g, view, loc, LOW, ORTHO, LEFT);
		d.point2Vertex(g, view, loc, nextLoc, ORTHO, LEFT);
		//indicate the rooms you shot into with red
		g.setColor(Color.MAGENTA);
		for(Integer i:shot){
			d.spikeVertex(g, view, i, LOW, ORTHO, LEFT);					
		}
		//indicate the rooms you visited
		g.setColor(Color.GREEN);
		for(Integer i:visited){
			d.spikeVertex(g, view, i, LOW, ORTHO, LEFT);					
		}

	}
	public void update(Graphics g){
		paint(g);
	}


	@Override
	public void mouseDragged(MouseEvent e) {
		curX=e.getX();
		curY=e.getY();
		if (inDrag){
			dY = (startX-curX)/2;//y axis delta
			dX = (startY-curY)/2;//x axis delta
			d.setyAxisAngle((yAng+dY)%360);
			d.setxAxisAngle((xAng+dX)%360);
			repaint();
		}
	}
	@Override
	public void mouseMoved(MouseEvent e) {}
	@Override
	public void mouseClicked(MouseEvent e) {	}
	@Override
	public void mousePressed(MouseEvent e) {
		inDrag=true;
		startX = curX = e.getX();
		startY = curY = e.getY();
	}
	@Override
	public void mouseReleased(MouseEvent e) {
		inDrag=false;
		xAng+=dX;
		yAng+=dY;
		dX=dY=0;
		repaint();
	}
	@Override
	public void mouseEntered(MouseEvent e) {}
	@Override
	public void mouseExited(MouseEvent e) {}
	@Override
	public void actionPerformed(ActionEvent e) {
		Object src = e.getSource();
		if(src==grab){
			//todo: use room method getGold
			message="Nothing to Grab here.";
			message2="You have "+gold+" gold.";
		}else if(src==turnL){
			message="You turn left.";
			turn="left";
			nextLoc=d.getLeft(loc, nextLoc);
			direction=" a passage to room "+nextLoc;
			//todo: use Room method hasWupus(nextLoc)-- message2="You smell a wumpus"
			//todo: use Room method hasPit(nextLoc)--message2="You fell a breeze"
			//todo: use Room method hasBats(nextLoc)==message2="You hear flapping wings"
			message2="";
		}else if(src==turnR){
			message="You turn right.";
			turn="right";
			nextLoc=d.getRight(loc, nextLoc);
			direction=" a passage to room "+nextLoc;
			//todo: use Room method hasWupus(nextLoc)-- message2="You smell a wumpus"
			//todo: use Room method hasPit(nextLoc)--message2="You fell a breeze"
			//todo: use Room method hasBats(nextLoc)==message2="You hear flapping wings"
			message2="";
		}else if(src==look){
			//todo:check for contents in nextLoc
			// you might smell a wumpus, feel a draft, or hear bats 
			//todo: use Room method hasWupus(nextLoc)-- message2="You smell a wumpus"
			//todo: use Room method hasPit(nextLoc)--message2="You fell a breeze"
			//todo: use Room method hasBats(nextLoc)==message2="You hear flapping wings"
			message2="";
			message="You look around. You see a sign with the number "+loc+" on the wall";
			message2="";
		}else if(src==help){
			message= "You want to find gold and kill the wupus with your crooked arrows.";
			message2 ="Avoid drafty bottomless pits, bats that relocate you, and going into a wumpus infested room.";
		}else if (src==shoot){
			message="You shoot in the direction of room "+nextLoc;
			int[] rooms = d.getFaceNodes(loc, nextLoc, turn);
			if (rooms!=null){
				for(int i:rooms)
					shot.add(i);
				//todo: check to see if you killed the wumpus
				// needs Room method hasWumpus()
				message2="You may have shot something";
			}else{
				message2="Without aim you wasted an arrow";
			}



		}else if (src==forward){
			if (loc!=nextLoc){
				message="You go down the passage to room "+nextLoc;
				//todo: use Room method hasWupus(nextLoc)-- message2="You are eaten by wumpus"
				//todo: use Room method hasPit(nextLoc)--message2="You fell into a bottomless pit"
				//todo: use Room method hasBats(nextLoc)==message2="Bats fly you to a random room"
				message2="";
				visited.add(loc);
			}else{
				message="You walk into a wall and hit your head";
			}
			//change current room
			loc=nextLoc;
			message2="";
			direction="straight ahead";
		}
		//todo: update graphics
		repaint();
	}
}

Vertex.java

import java.awt.Point;
import java.awt.Rectangle;


public class Vertex implements Comparable
{
	private double x,y,z;
	public static final double CamX=0;//3d viewpoint coords 
	public static final double CamY=0;//3d viewpoint coords 
	public static final double CamZ=-3;//3d viewpoint coords 
	//public int xfac=90, zfac=90;

	public static final double RADIANS=Math.PI/180.0;//degree to radian conversion

	public Vertex(double x, double y, double z){
		this.x=x;
		this.y=y;
		this.z=z;
	}
	public boolean equals(Vertex o)
	{
		return x==o.getX() && y==o.getY() && z==o.getZ();
	}
	public double getZ() {
		return z;
	}
	public double getY() {
		return y;
	}
	public double getX() {
		return x;
	}
	@Override
	public int compareTo(Object o) {
		return (int)(Math.round(distance((Vertex)o)));
	}
	public double distance(Vertex o) {
		return Math.sqrt(
				Math.pow(x-o.getX(), 2)+
				Math.pow(y-o.getY(), 2)+
				Math.pow(z-o.getZ(), 2)
				);
	}
	public int screenX(Rectangle r){
		double x0 = r.width/2*(x - CamX) /(z-CamZ);
		return r.x+r.width/2+(int)Math.round(x0);
	}
	public int screenY(Rectangle r){
		double y0 = r.height/2*(y - CamY) /(z-CamZ);
		return r.y+r.height/2-(int)Math.round(y0);
	}
	public Point screenXY(Rectangle r, double yAxis, double xAxis){
		double a = 2*yAxis*RADIANS;
		double b = 2*xAxis*RADIANS;
		//rotation around y axis
		double z0 = z*Math.cos(a)-x*Math.sin(a);
		double x0 = z*Math.sin(a)+x*Math.cos(a);
		//rotation around x axis
		double y0 = y*Math.cos(b)-z0*Math.sin(b);
		double z1 = y*Math.sin(b)+z0*Math.cos(b);

		//projection
		double px = r.width/2*(x0 - CamX) /(z1-CamZ);
		double py = r.height/2*(y0 - CamY) /(z1-CamZ);
		int sy = r.y+r.height/2-(int)Math.round(py);
		int sx = r.x+r.width/2+(int)Math.round(px);
		return new Point(sx,sy);
	}
	public Point orthoXY(Rectangle r, double yAxis, double xAxis){
		double a = 2*yAxis*RADIANS;
		double b = 2*xAxis*RADIANS;
		//rotation around y axis
		double z0 = z*Math.cos(a)-x*Math.sin(a);
		double x0 = z*Math.sin(a)+x*Math.cos(a);
		//rotation around x axis
		double y0 = y*Math.cos(b)-z0*Math.sin(b);
		double z1 = y*Math.sin(b)+z0*Math.cos(b);

		//orthogonal projection of x0,y0,z1
		double theta= Math.PI/8;
		double phi= -1*Math.PI/15;
		double s=r.width/4;
		double xf=s*.89;
		double zf=s*.68;

		double px = xf*Math.cos(phi)*(x0 - CamX) + zf*Math.cos(theta)*(z1-0);
		double py = s*(y0 - CamY) + zf*Math.sin(theta)*(z1-0)+xf*Math.sin(phi)*(x0 - CamX);
		int sy = r.y+r.height/2-(int)Math.round(py);
		int sx = r.x+r.width/2+(int)Math.round(px);
		return new Point(sx,sy);
	}
	/**
	 * change the point by rotation around the y axis
	 * @param degrees
	 */
	public void rotateAxisY(double degrees){
		double a = 2*degrees*RADIANS;
		double z0 = z*Math.cos(a)-x*Math.sin(a);
		double x0 = z*Math.sin(a)+x*Math.cos(a);
		z=z0;
		x=x0;
	}
	public void rotateAxisX(double degrees){
		double a = 2*degrees*RADIANS;
		double y0 = y*Math.cos(a)-z*Math.sin(a);
		double z0 = y*Math.sin(a)+z*Math.cos(a);
		y=y0;
		z=z0;
	}
	public static Vertex midpoint(Vertex v1, Vertex v2){
		double xm = 0.5*(v1.getX()+v2.getX());
		double ym = 0.5*(v1.getY()+v2.getY());
		double zm = 0.5*(v1.getZ()+v2.getZ());
		return new Vertex(xm,ym,zm);
	}
	public static Vertex spike(Vertex v1, Vertex v2){
		double xm = 0.5*(v1.getX()+v2.getX());
		double ym = 0.5*(v1.getY()+v2.getY());
		double zm = 0.5*(v1.getZ()+v2.getZ());
		return new Vertex(v2.getX()+xm/2,v2.getY()+ym/2,v2.getZ()+zm/2);
	}
	/**
	 * 
	 * @param v1
	 * @param percent of vertex to origin
	 * @return a vertex a percentage away from origin
	 */
	public static Vertex spike(Vertex v1, double percent){
		double xm = percent*(v1.getX());
		double ym = percent*(v1.getY());
		double zm = percent*(v1.getZ());
		return new Vertex(v1.getX()+xm,v1.getY()+ym,v1.getZ()+zm);
	}
	public String toString(){
		return String.format("(%.3f, %.3f, %.3f)", x,y,z);
	}
}

Face.java

import java.awt.Color;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;


public class Face implements Comparable<Face>
{
	private Vertex[] v;
	private Color color;
	public Face(Vertex v0, Vertex v1, Vertex v2, Vertex v3, Vertex v4){
		setColor(Color.WHITE);
		v = new Vertex[5];
		v[0]=v0;
		v[1]=v1;
		v[2]=v2;
		v[3]=v3;
		v[4]=v4;
	}
	public Polygon polygon(Rectangle screen, double scale){
		Polygon p = new Polygon();
		for (int i=0; i<5; i++)
			p.addPoint(v[i].screenX(screen), v[i].screenY(screen));
		return p;
	}
	public String toString(){
		String s="[";
		for (Vertex n:v)
			s+=n.toString()+" ";
		return s+"]";
	}
	@Override
	public int compareTo(Face o) {
		return (int)(100.0*this.distanceToViewpoint()-100*o.distanceToViewpoint());
	}
	public double distanceToViewpoint(){
		return center().distance(new Vertex(Vertex.CamX, Vertex.CamY, Vertex.CamZ));
	}
	public Vertex center(){
		double x,y,z;
		x=y=z=0;
		for(Vertex n:v){
			x+=n.getX();
			y+=n.getY();
			z+=n.getZ();		
		}
		return new Vertex(x/5.0, y/5.0, z/5.0);
	}
	public Polygon getPolygon(Rectangle screen, double yAxis, double xAxis){
		Polygon p = new Polygon();
		for (int i=0; i<5; i++){
			Point pt = v[i].screenXY(screen, yAxis, xAxis);
			p.addPoint(pt.x, pt.y);
		}
		return p;
	}
	public Polygon getOrthoPolygon(Rectangle screen, double yAxis, double xAxis){
		Polygon p = new Polygon();
		for (int i=0; i<5; i++){
			Point pt = v[i].orthoXY(screen, yAxis, xAxis);
			p.addPoint(pt.x, pt.y);
		}
		return p;
	}
	public Color getColor() {
		return color;
	}
	public Color getCyan() {
		return new Color(0, 0, color.getBlue(), color.getTransparency());
	}
	public Color getRed() {
		return new Color(color.getRed(),0, 0, color.getTransparency());
	}
	public void setColor(Color color) {
		this.color = new Color(color.getRed(), color.getGreen(), color.getBlue(), 128);
	}
}

Dodectrahedron.java

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;


public class Dodectrahedron 
{
	private Vertex[] v;
	private Face[] f;
	private int [][] adjacentNodes;
	private double yAxisAngle, xAxisAngle;
	public static final double PI_5 = 2.0*Math.PI/5.0;
	public static final double PHI=1.618033988749894848204586834365638;

	public Dodectrahedron(){
		v = new Vertex[20];
		v[0]=new Vertex(1,1,1);
		v[1]=new Vertex(1,1,-1);
		v[2]=new Vertex(1,-1,1);
		v[3]=new Vertex(1,-1,-1);
		v[4]=new Vertex(-1,1,1);
		v[5]=new Vertex(-1,1,-1);
		v[6]=new Vertex(-1,-1,1);
		v[7]=new Vertex(-1,-1,-1);

		v[8]=new Vertex(0,1.0/PHI,PHI);//green
		v[9]=new Vertex(0,1.0/PHI,-PHI);
		v[10]=new Vertex(0,-1.0/PHI,PHI);
		v[11]=new Vertex(0,-1.0/PHI,-PHI);

		v[12]=new Vertex(PHI,0,1/PHI);//red
		v[13]=new Vertex(PHI,0,-1/PHI);
		v[14]=new Vertex(-PHI,0,1/PHI);
		v[15]=new Vertex(-PHI,0,-1/PHI);

		v[16]=new Vertex(1.0/PHI,PHI,0);//blu
		v[17]=new Vertex(1.0/PHI,-PHI,0);
		v[18]=new Vertex(-1.0/PHI,PHI,0);
		v[19]=new Vertex(-1.0/PHI,-PHI,0);
		f = new Face[12];
		f[0] = new Face(v[18], v[16], v[1], v[9],v[5]);//ok
		f[1] = new Face(v[18], v[16], v[0], v[8],v[4]);//ok
		f[2] = new Face(v[16], v[1], v[13], v[12],v[0]);
		f[3] = new Face(v[1], v[9], v[11], v[3],v[13]);
		f[4] = new Face(v[9], v[5], v[15], v[7],v[11]);
		f[5] = new Face(v[5], v[18], v[4], v[14],v[15]);

		f[6] = new Face(v[10], v[2], v[17], v[19],v[6]);
		f[7] = new Face(v[10], v[2], v[12], v[0],v[8]);
		f[8] = new Face(v[2], v[17], v[3], v[13],v[12]);
		f[9] = new Face(v[17], v[19], v[7], v[11],v[3]);
		f[10] = new Face(v[19], v[6], v[14], v[15],v[7]);
		f[11] = new Face(v[6], v[10], v[8], v[4],v[14]);

		for (Face side:f)
			side.setColor(randomColor());
		this.adjacentNodes = new int [20][3];
		//clockwise
		initNode(0,8,12,16);
		initNode(1,16,13, 9);
		initNode(2,12,10, 17);
		initNode(3,13, 17, 11);
		initNode(4,18, 14, 8);
		initNode(5,18, 9,15);
		initNode(6,14,19, 10);
		initNode(7,15,11,19);
		initNode(8,4,10,0);
		initNode(9,5,1,11);
		initNode(10,8,6,2);
		initNode(11,3,7,9);
		initNode(12,0,2,13);
		initNode(13,1,12,3);
		initNode(14,4,15,6);
		initNode(15,5,7,14);
		initNode(16,0,1,18);
		initNode(17,3,2,19);
		initNode(18,16,5,4);
		initNode(19,7,17,6);

	}
	public void nodeTest(Graphics g, Rectangle screen, int n){
		g.setColor(Color.BLACK);
		for(int i=0; i<3;i++)
			connect(g, n, adjacentNodes[n][i], screen, true);		
	}
	private void initNode(int n, int v0, int v1,int v2){
		adjacentNodes[n][0]=v0;
		adjacentNodes[n][1]=v1;
		adjacentNodes[n][2]=v2;
	}
	/**
	 * from a node, facing a node get the left node
	 * @return -1 if not possible to face from the node from that node error 
	 */
	public int getLeft(int from, int facing){
		int currentIndex=0;
		if(from==facing)// select first if same node
			facing=adjacentNodes[from][0];
		while (currentIndex<3 && facing!=adjacentNodes[from][currentIndex])
			currentIndex++;
		if (adjacentNodes[from][currentIndex]!=facing)
			return -1;
		int i=(currentIndex-1+3)%3;
		return adjacentNodes[from][i];
	}
	/**
	 * from a node, facing a node get the left node
	 * @return -1 if not possible to face from the node from that node error 
	 */
	public int getRight(int from, int facing){
		int currentIndex=0;
		if(from==facing)// select first if same node
			facing=adjacentNodes[from][0];
		while (currentIndex<3 && facing!=adjacentNodes[from][currentIndex])
			currentIndex++;
		if (adjacentNodes[from][currentIndex]!=facing)
			return -1;
		int i=(currentIndex+1+3)%3;
		return adjacentNodes[from][i];
	}
	/**
	 * Returns the array of 5 nodes of the pentagan from a node facing a node. 
	 * @param from
	 * @param facing
	 * @param leftOrRight
	 * @return null if not facing properly
	 */
	public int[] getFaceNodes(int from, int facing, String leftOrRight){
		if (from==facing)
			return null;
		if (getRight(from,facing)==-1)
			return null;
		int[] p=new int[5];
		p[0]=from;
		p[1]=facing;

		if (leftOrRight.equalsIgnoreCase("left")){
			for (int i=2; i<5;i++)
				p[i]=getRight(p[i-1],p[i-2]);
		}else{
			for (int i=2; i<5;i++)
				p[i]=getLeft(p[i-1],p[i-2]);
		}
		return p;
	}

	public Color randomColor(){
		return new Color((int)(255*Math.random()), (int)(255*Math.random()), (int)(255*Math.random()));
	}
	public void rotateY(double yAxisDeg){
		for (Vertex n:v)
			n.rotateAxisY(yAxisDeg);		
	}
	public void rotateX( double xAxisDeg){
		for (Vertex n:v)
			n.rotateAxisX(xAxisDeg);		
	}
	public Face getFace(int i){ return f[i]; }
	public Face[] getFaces(){ return f; }
	public Vertex getVertex(int i){ return v[i]; }
	public double getyAxisAngle() {
		return yAxisAngle;
	}
	public void setyAxisAngle(double yAxisAngle) {
		this.yAxisAngle = yAxisAngle;
	}
	public double getxAxisAngle() {
		return xAxisAngle;
	}
	public void setxAxisAngle(double xAxisAngle) {
		this.xAxisAngle = xAxisAngle;
	}
	public void drawEdges(Graphics g, Rectangle screen, boolean ortho){
		connect(g, 18, 16, screen, ortho);
		connect(g, 16, 1, screen, ortho);
		connect(g, 1, 9, screen, ortho);
		connect(g, 9, 5, screen, ortho);
		connect(g, 5, 18, screen, ortho);
		connect(g, 16, 0, screen, ortho);
		connect(g, 0, 8, screen, ortho);
		connect(g, 8, 4, screen, ortho);
		connect(g, 4, 18, screen, ortho);
		connect(g, 0, 12, screen, ortho);
		connect(g, 12, 13, screen, ortho);
		connect(g, 13, 1, screen, ortho);
		connect(g, 13, 3, screen, ortho);
		connect(g, 3, 11, screen, ortho);
		connect(g, 11, 9, screen, ortho);
		connect(g, 11, 7, screen, ortho);
		connect(g, 7, 15, screen, ortho);
		connect(g, 15, 5, screen, ortho);
		connect(g, 15, 14, screen, ortho);
		connect(g, 14, 4, screen, ortho);
		connect(g, 10, 8, screen, ortho);
		connect(g, 2, 12, screen, ortho);
		connect(g, 17, 3, screen, ortho);
		connect(g, 19, 7, screen, ortho);
		connect(g, 6, 14, screen, ortho);
		connect(g, 10, 2, screen, ortho);
		connect(g, 2, 17, screen, ortho);
		connect(g, 17, 19, screen, ortho);
		connect(g, 19, 6, screen, ortho);
		connect(g, 6, 10, screen, ortho);	
	}

	public void drawCenter2Vertex(Graphics g, Rectangle area, int i,boolean ortho, double offset){
		Vertex o=new Vertex(0,0,0);
		Point p1,p2;
		if(ortho){
			 p1=o.orthoXY(area, getyAxisAngle()+offset, getxAxisAngle());
			 p2=getVertex(i).orthoXY(area, getyAxisAngle()+offset, getxAxisAngle());			
		}else{
			 p1=o.screenXY(area, getyAxisAngle()+offset, getxAxisAngle());
			 p2=getVertex(i).screenXY(area, getyAxisAngle()+offset, getxAxisAngle());			
		}
		g.drawLine(p1.x, p1.y, p2.x, p2.y);
	}
	public void point2Vertex(Graphics g, Rectangle area, int from, int to, boolean ortho, double offset){
		Vertex o=Vertex.spike(getVertex(from), .25);
		Point p1,p2, p3;
		if(ortho){
			 p1=Vertex.midpoint(getVertex(from), getVertex(to)).orthoXY(area, getyAxisAngle()+offset, getxAxisAngle());
			 p2=getVertex(from).orthoXY(area, getyAxisAngle()+offset, getxAxisAngle());
			 p3=o.orthoXY(area, getyAxisAngle()+offset, getxAxisAngle());
		}else{
			 p1=Vertex.midpoint(getVertex(from), getVertex(to)).screenXY(area, getyAxisAngle()+offset, getxAxisAngle());
			 p2=getVertex(from).screenXY(area, getyAxisAngle()+offset, getxAxisAngle());	
			 p3=o.screenXY(area, getyAxisAngle()+offset, getxAxisAngle());	
		}
		Polygon flag = new Polygon();
		flag.addPoint(p1.x, p1.y);
		flag.addPoint(p2.x, p2.y);
		flag.addPoint(p3.x, p3.y);
		g.fillPolygon(flag);
	}
	/**
	 * 
	 * @param g
	 * @param area
	 * @param i the node
	 * @param percent how long the spike
	 * @param ortho whether or not ortho or perspectve projectoin
	 * @param offset rotation offset for stereo use
	 */
	public void spikeVertex(Graphics g, Rectangle area, int i, double percent, boolean ortho, double offset){
		Vertex o=Vertex.spike(getVertex(i), percent);
		Point p1,p2;
		if(ortho){
			p1=o.orthoXY(area, getyAxisAngle()+offset, getxAxisAngle());
			p2=getVertex(i).orthoXY(area, getyAxisAngle()+offset, getxAxisAngle());			
		}else{
			p1=o.screenXY(area, getyAxisAngle()+offset, getxAxisAngle());
			p2=getVertex(i).screenXY(area, getyAxisAngle()+offset, getxAxisAngle());			
		}
		g.drawLine(p1.x, p1.y, p2.x, p2.y);
	}
	public void connect(Graphics g,int i, int j, Rectangle screen, boolean ortho, double offset){
		Point p1,p2;
		if (ortho){
			p1=getVertex(i).orthoXY(screen, getyAxisAngle()+offset, getxAxisAngle());
			p2=getVertex(j).orthoXY(screen, getyAxisAngle()+offset, getxAxisAngle());
		}else {
			p1=getVertex(i).screenXY(screen, getyAxisAngle()+offset, getxAxisAngle());
			p2=getVertex(j).screenXY(screen, getyAxisAngle()+offset, getxAxisAngle());
		}
		g.drawLine(p1.x, p1.y, p2.x, p2.y );
	}
	public void connect(Graphics g, int i, int j, Rectangle screen, boolean ortho){
		connect(g,i,j,screen,ortho,0);
	}

	public void drawDot(Graphics g, Rectangle area, int i, double percent, boolean ortho, double offset){
		Vertex o=Vertex.spike(getVertex(i), percent);
		Point p1,p2;
		if(ortho){
			 p1=o.orthoXY(area, getyAxisAngle()+offset, getxAxisAngle());
			 p2=getVertex(i).orthoXY(area, getyAxisAngle()+offset, getxAxisAngle());			
		}else{
			 p1=o.screenXY(area, getyAxisAngle()+offset, getxAxisAngle());
			 p2=getVertex(i).screenXY(area, getyAxisAngle()+offset, getxAxisAngle());			
		}
		int size=(int)Math.round(Math.sqrt(Math.pow(p1.x-p2.x,2)+Math.pow(p1.y-p2.y,2)));
		size=Math.max(5, size);
		g.fillOval(p1.x-size, p1.y-size, 2*size, 2*size);
	}


}