import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.ArrayList;
import java.net.*;

class Point
{
	private int x;
	private int y;

	public Point(int x, int y)
	{
		this.x = x;
		this.y = y;
	}

	public int getX()
	{
		return x;
	}

	public int getY()
	{
		return y;
	}
}

public class RobotsApplet extends JApplet implements MouseListener, ActionListener
{
	private final int SQUARE_SIZE = 20;
	private final int WIDTH = 640 / SQUARE_SIZE;
	private final int HEIGHT = 480 / SQUARE_SIZE;
	private final int NUM_ROBOTS = 50;
	private final int MIN_START_DISTANCE = 8;

	private enum FieldType {
		EMPTY,
		HUMAN,
		ROBOT,
		COLLISION,
		DEAD
	};

	private FieldType[][] fields = new FieldType[WIDTH][HEIGHT];
	private JLabel[][] fieldLabels = new JLabel[WIDTH][HEIGHT];

	private ImageIcon emptyIcon;
	private ImageIcon humanIcon;
	private ImageIcon robotIcon;
	private ImageIcon collisionIcon;
	private ImageIcon deadIcon;

	private JPanel panel = new JPanel();

	private int humanX;
	private int humanY;

	private boolean done = false;
	private boolean dead = false;

	public void init()
	{
		try {
			emptyIcon = new ImageIcon(new URL("http://www.nooskewl.com/java/Robots/empty.png"));
			humanIcon = new ImageIcon(new URL("http://www.nooskewl.com/java/Robots/human.png"));
			robotIcon = new ImageIcon(new URL("http://www.nooskewl.com/java/Robots/robot.png"));
			collisionIcon = new ImageIcon(new URL("http://www.nooskewl.com/java/Robots/collision.png"));
			deadIcon = new ImageIcon(new URL("http://www.nooskewl.com/java/Robots/dead.png"));
		}
		catch (MalformedURLException e) {
		}

		setLayout(new BorderLayout());
		add(panel, BorderLayout.CENTER);

		panel.setLayout(new GridLayout(HEIGHT, WIDTH));

		JPanel teleportPanel = new JPanel();
		teleportPanel.setLayout(new FlowLayout());
		JButton teleportButton = new JButton("Teleport");
		teleportButton.addActionListener(this);
		teleportPanel.add(teleportButton);
		add(teleportPanel, BorderLayout.SOUTH);

		for (int y = 0; y < HEIGHT; y++) {
			for (int x = 0; x < WIDTH; x++) {
				fieldLabels[x][y] = new JLabel(emptyIcon);
				fieldLabels[x][y].addMouseListener(this);
				panel.add(fieldLabels[x][y]);
				fields[x][y] = FieldType.EMPTY;
			}
		}

		humanX = WIDTH/2;
		humanY = HEIGHT/2;

		setField(humanX, humanY, FieldType.HUMAN);

		for (int i = 0; i < NUM_ROBOTS; i++) {
			boolean set = false;
			while (!set) {
				int x = (int)(Math.random() * WIDTH);
				int y = (int)(Math.random() * HEIGHT);
				if (fields[x][y] == FieldType.ROBOT) {
					continue;
				}
				int dx = (int)Math.abs(humanX - x);
				int dy = (int)Math.abs(humanY - y);
				if ((dx+dy) < MIN_START_DISTANCE) {
					continue;
				}
				setField(x, y, FieldType.ROBOT);
				set = true;
			}
		}
	}

	public void start()
	{
	}
	
	public void stop()
	{
	}

	public void destroy()
	{
		done = true;
	}

	private void setField(int x, int y, FieldType type)
	{
		fields[x][y] = type;
		switch (type) {
			case EMPTY:
				fieldLabels[x][y].setIcon(emptyIcon);
				break;
			case HUMAN:
				fieldLabels[x][y].setIcon(humanIcon);
				break;
			case ROBOT:
				fieldLabels[x][y].setIcon(robotIcon);
				break;
			case COLLISION:
				fieldLabels[x][y].setIcon(collisionIcon);
				break;
			case DEAD:
				fieldLabels[x][y].setIcon(deadIcon);
				break;
		}
	}

	public void mouseClicked(MouseEvent e)
	{
		if (dead) {
			return;
		}

		for (int y = 0; y < HEIGHT; y++) {
			for (int x = 0; x < WIDTH; x++) {
				if (e.getSource() == fieldLabels[x][y]) {
					int dx = (int)Math.abs(humanX - x);
					int dy = (int)Math.abs(humanY - y);
					if (dx > 1 || dy > 1) {
						return;
					}
					if (fields[x][y] == FieldType.COLLISION) {
						return;
					}
					else if (fields[x][y] == FieldType.ROBOT) {
						dead = true;
						setField(humanX, humanY, FieldType.EMPTY);
						humanX = x;
						humanY = y;
						setField(humanX, humanY, FieldType.DEAD);
					}
					else {
						setField(humanX, humanY, FieldType.EMPTY);
						humanX = x;
						humanY = y;
						setField(humanX, humanY, FieldType.HUMAN);
						moveRobots();
					}
				}
			}
		}
	}

	public void moveRobots()
	{
		ArrayList<Point> robots = new ArrayList<Point>();

		for (int y = 0; y < HEIGHT; y++) {
			for (int x = 0; x < WIDTH; x++) {
				if (fields[x][y] == FieldType.ROBOT) {
					robots.add(new Point(x, y));
				}
			}
		}

		for (Point p : robots) {
			int x = p.getX();
			int y = p.getY();
			if (fields[x][y] == FieldType.COLLISION) {
				continue;
			}
			int destX;
			int destY;
			if (humanX < x) {
				destX = x-1;
			}
			else if (humanX > x) {
				destX = x+1;
			}
			else {
				destX = x;
			}
			if (humanY < y) {
				destY = y-1;
			}
			else if (humanY > y) {
				destY = y+1;
			}
			else {
				destY = y;
			}
			setField(x, y, FieldType.EMPTY);
			if (fields[destX][destY] == FieldType.HUMAN) {
				dead = true;
				setField(destX, destY, FieldType.DEAD);
				return;
			}
			else if (fields[destX][destY] == FieldType.ROBOT
					|| fields[destX][destY] == FieldType.COLLISION) {
				setField(destX, destY, FieldType.COLLISION);
			}
			else {
				setField(destX, destY, FieldType.ROBOT);
			}
		}
	}

	public void actionPerformed(ActionEvent e)
	{
		if (dead) {
			return;
		}

		setField(humanX, humanY, FieldType.EMPTY);
		int x = (int)(Math.random() * WIDTH);
		int y = (int)(Math.random() * HEIGHT);
		humanX = x;
		humanY = y;
		if (fields[x][y] != FieldType.EMPTY) {
			dead = true;
			setField(x, y, FieldType.DEAD);
		}
		else {
			setField(x, y, FieldType.HUMAN);
			moveRobots();
		}
	}

	/* Unused methods of MouseListener */

	public void mouseEntered(MouseEvent e) {}
	public void mouseExited(MouseEvent e) {}
	public void mousePressed(MouseEvent e) {}
	public void mouseReleased(MouseEvent e) {}
}

