import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.RenderingHints; import java.awt.Stroke; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import javax.swing.JComponent; import javax.swing.Timer; @SuppressWarnings("serial") public class WedgeWorld extends JComponent { public static final Color BOARD_COLOR = new Color(0, 0, 128); public static final int CELL_SIZE = 30; public static final Stroke BOARD_STROKE = new BasicStroke(12.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); public static final double COLLISION_DISTANCE = 5.0; private Timer timer; private int[][] worldInts = new int[][] { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1}, {1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1}, {1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1}, {1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1}, {1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1}, {1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1}, {1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1}, {1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1}, {1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1}, {1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1}, {1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} }; private Space[][] world; private int foodX = -1; private int foodY = -1; private int poisonX = -1; private int poisonY = -1; private WedgeFrame wedgeFrame; private WedgeDude wedgeDude; private Image foodImage; private Image poisonImage; public WedgeWorld(WedgeFrame wedgeFrame) throws IOException { this.wedgeFrame = wedgeFrame; this.wedgeDude = new WedgeDude(this); this.world = initWorld(); placeItems(); this.foodImage = this.wedgeFrame.loadImage("Food.png"); this.poisonImage = this.wedgeFrame.loadImage("Poison.png"); new GameThread().start(); } private void placeItems() { int[] food = place(Space.FOOD, 10, 10, 15); this.foodX = food[0]; this.foodY = food[1]; int[] poison; do { // Try to get the poison in the path of WedgeDude poison = place(Space.POISON, (this.wedgeDude.getX() + this.foodX) / 2, (this.wedgeDude.getY() + this.foodY) / 2, 3); } while (poison[0] == this.foodX && poison[1] == this.foodY); this.poisonX = poison[0]; this.poisonY = poison[1]; } private int[] place(Space item, int centerX, int centerY, int maxDistance) { int itemX = -1, itemY = -1; boolean placed = false; while (!placed) { itemX = centerX + (int)((Math.random() * 2 - 1.0) * maxDistance); itemY = centerY + (int)((Math.random() * 2 - 1.0) * maxDistance); if (itemY >= 0 && itemY < this.world.length && itemX >= 0 && itemX < this.world[0].length && this.world[itemY][itemX] == Space.OPEN && Point.distance(this.wedgeDude.getX(), itemX, this.wedgeDude.getY(), itemY) > 3.0) placed = true; } this.world[itemY][itemX] = item; return new int[] { itemX, itemY }; } private Space[][] initWorld() { Space[] values = Space.values(); Space[][] world = new Space[this.worldInts.length][this.worldInts[0].length]; for (int i = 0; i < this.worldInts.length; i++) for (int j = 0; j < this.worldInts[i].length; j++) world[i][j] = values[this.worldInts[i][j]]; if (this.foodX > -1 && this.foodY > -1) world[this.foodY][this.foodX] = Space.FOOD; if (this.poisonX > -1 && this.poisonY > -1) world[this.poisonY][this.poisonX] = Space.POISON; return world; } public Space getContents(int gridX, int gridY) { return this.world[gridY][gridX]; } public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D)g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Dimension size = getSize(); g2d.setColor(Color.WHITE); g2d.fillRect(0, 0, size.width, size.height); g2d.setColor(BOARD_COLOR); Stroke str = g2d.getStroke(); g2d.setStroke(BOARD_STROKE); int halfCell = WedgeWorld.CELL_SIZE / 2; for (int i = 0; i < this.world.length; i++) { for (int j = 0; j < this.world[i].length; j++) { int x = getPixel(j); int y = getPixel(i); Space s = this.world[i][j]; if (s == Space.WALL) { // Decide which line segments to draw to represent the maze boolean top = i == 0; boolean left = j == 0; boolean bottom = i == this.world.length - 1; boolean right = j == this.world[i].length - 1; boolean upLeftWall = !top && !left && this.world[i - 1][j - 1] == Space.WALL; boolean upWall = !top && this.world[i - 1][j] == Space.WALL; boolean upRightWall = !top && !right && this.world[i - 1][j + 1] == Space.WALL; boolean leftWall = !left && this.world[i][j - 1] == Space.WALL; boolean rightWall = !right && this.world[i][j + 1] == Space.WALL; boolean downLeftWall = !bottom && !left && this.world[i + 1][j - 1] == Space.WALL; boolean downWall = !bottom && this.world[i + 1][j] == Space.WALL; boolean downRightWall = !bottom && !right && this.world[i + 1][j + 1] == Space.WALL; if (!(leftWall && rightWall && upWall && downWall)) { if (leftWall && !(upWall && downWall && upLeftWall && downLeftWall)) g2d.drawLine(x, y, x - halfCell, y); if (rightWall && !(upWall && downWall && upRightWall && downRightWall)) g2d.drawLine(x, y, x + halfCell, y); if (upWall && !(leftWall && rightWall && upLeftWall && upRightWall)) g2d.drawLine(x, y, x, y - halfCell); if (downWall && !(leftWall && rightWall && downLeftWall && downRightWall)) g2d.drawLine(x, y, x, y + halfCell); // g2d.drawOval(x - 10, y - 10, 20, 20); } } } } g2d.setStroke(str); if (this.foodX > -1 && this.foodY > -1) { int foodPixelX = getPixel(this.foodX); int foodPixelY = getPixel(this.foodY); g2d.drawImage(this.foodImage, foodPixelX - 15, foodPixelY - 15, null); } if (this.poisonX > -1 && this.poisonY > -1) { int poisonPixelX = getPixel(this.poisonX); int poisonPixelY = getPixel(this.poisonY); g2d.drawImage(this.poisonImage, poisonPixelX - 15, poisonPixelY - 15, null); } this.wedgeDude.draw(g2d, this); if (this.timer == null) { this.timer = new Timer(25, new ActionListener() { public void actionPerformed(ActionEvent event) { repaint(WedgeWorld.this.wedgeDude.getBoundingBox()); } }); this.timer.start(); } } private int getPixel(int grid) { return WedgeWorld.CELL_SIZE / 2 + CELL_SIZE * grid; } public class GameThread extends Thread { public void run() { int lifeSpan = Integer.MAX_VALUE; while (lifeSpan-- > 0) { try { Thread.sleep(10L); } catch (Exception e) { } WedgeDude wd = WedgeWorld.this.wedgeDude; Space[][] world = initWorld(); long t1 = System.nanoTime(); Move mg = null; try { mg = WedgeBrain.nextMove(wd.getX(), wd.getY(), world); } catch (Throwable t) { System.out.println(t); } long t2 = System.nanoTime(); // System.out.println(t2 - t1); if (mg != null && mg.getDirection() != null) wd.move(mg.getDirection()); // Detect proximity to items and react int wdx = wd.getPixelX(); int wdy = wd.getPixelY(); int fx = getPixel(WedgeWorld.this.foodX); int fy = getPixel(WedgeWorld.this.foodY); int px = getPixel(WedgeWorld.this.poisonX); int py = getPixel(WedgeWorld.this.poisonY); double foodDistance = Point.distance(wdx, wdy, fx, fy); double poisonDistance = Point.distance(wdx, wdy, px, py); if (poisonDistance < COLLISION_DISTANCE) { WedgeWorld.this.poisonX = -1; WedgeWorld.this.poisonY = -1; WedgeWorld.this.foodX = -1; WedgeWorld.this.foodY = -1; wd.die(); lifeSpan = 15; } if (foodDistance < COLLISION_DISTANCE) { placeItems(); repaint(); } } System.out.println("Exiting"); } } }