package game.entries.ghosts;
import game.controllers.GhostController;
import game.core.Game;
import game.core.GameView;
import game.entries.ghosts.GD.Direction;
import java.awt.Color;
import java.awt.Point;
import java.util.Collections;
import java.util.List;
/**
* Ghost Controller for AI
* @author toriscope
*
*/
public class MyGhosts implements GhostController {
private boolean Debugging = false;
final Point[] targets = new Point[Game.NUM_GHOSTS];
private GhostState allState = GhostState.CHASE;
public final static Point BLINKY_SCATTER_POINT = new Point(104, 4);
public final static Point PINKY_SCATTER_POINT = new Point(4, 4);
public final static Point INKY_SCATTER_POINT = new Point(104, 116);
public final static Point CLYDE_SCATTER_POINT = new Point(4, 116);
final private GD grid = new GD();
private Direction pacLook = Direction.NONE;
public MyGhosts(boolean debugging) {
Debugging = debugging;
}
public int[] getActions(Game game, long timeDue) {
grid.rebuildMap(game);
updateStates(game);
final Direction possibleLook = Direction.getDIR(game.getCurPacManDir());
if (possibleLook != Direction.NONE) {
pacLook = possibleLook;
}
int[] directions = new int[Game.NUM_GHOSTS];
for (int i = 0; i < directions.length; i++) {
if (true) { // more logic used to be here, leave for now.
GhostState state = allState;
if (game.getEdibleTime(i) > 0) {
state = GhostState.SCARED;
}
// BLINKY
if (i == 0) {
switch (state) {
case CHASE: {
directions[i] = ghostMove_target(i, game,
grid.toPoint(game.getCurPacManLoc()));
break;
}
case SCARED: {
directions[i] = (int) (Math.random() * 4);
targets[i] = null;
break;
}
case SCATTER: {
directions[i] = ghostMove_target(i, game,
BLINKY_SCATTER_POINT);
break;
}
}
}
// PINKY
else if (i == 1) {
switch (state) {
case CHASE: {
final Point pDir = GD.scale(new Point(pacLook.offset),
4);
final Point pac4 = GD.add(
grid.toPoint(game.getCurPacManLoc()), pDir);
directions[i] = ghostMove_target(i, game, pac4);
break;
}
case SCARED: {
directions[i] = (int) (Math.random() * 4);
targets[i] = null;
break;
}
case SCATTER: {
directions[i] = ghostMove_target(i, game,
PINKY_SCATTER_POINT);
break;
}
}
}
// CLYDE
else if (i == 2) {
switch (state) {
case SCARED: {
directions[i] = (int) (Math.random() * 4);
targets[i] = null;
break;
}
case CHASE: {
final Point pos = grid.toPoint(game.getCurGhostLoc(i));
final Point pacPos = grid.toPoint(game
.getCurPacManLoc());
final float tilesAppart = GD.distance(pos, pacPos)
/ GD.CELL_PIXEL_SEPERATION;
if (tilesAppart > 8) {
directions[i] = ghostMove_target(i, game,
grid.toPoint(game.getCurPacManLoc()));
break;
}
}
case SCATTER: {
directions[i] = ghostMove_target(i, game,
CLYDE_SCATTER_POINT);
break;
}
}
}
// INKY
else if (i == 3) {
switch (state) {
case SCARED: {
directions[i] = (int) (Math.random() * 4);
targets[i] = null;
break;
}
case CHASE: {
final Point pac2 = GD.add(
grid.toPoint(game.getCurPacManLoc()),
GD.scale(new Point(pacLook.offset), 2));
final Point blinkyVect = GD.scale(
GD.sub(pac2,
grid.toPoint(game.getCurGhostLoc(0))),
2);
final Point target = GD.add(
grid.toPoint(game.getCurGhostLoc(0)),
blinkyVect);
directions[i] = ghostMove_target(i, game, target);
break;
}
case SCATTER: {
directions[i] = ghostMove_target(i, game,
INKY_SCATTER_POINT);
break;
}
}
}
}
if (Debugging) {
Color color = Color.GRAY;
if (i == 0) {
color = Color.RED;
} else if (i == 1) {
color = Color.PINK;
} else if (i == 2) {
color = Color.ORANGE;
} else {
color = Color.BLUE;
}
if (targets[i] != null) {
GameView.addLines(game, color,
grid.toPoint(game.getCurGhostLoc(i)), targets[i]);
}
}
}
return directions;
}
private int ghostMove_target(int i, Game game, Point target) {
targets[i] = target;
Point ghostLoc = grid.toPoint(game.getCurGhostLoc(i));
final List<Direction> p = grid.getAllowedCellsSurrounding(ghostLoc);
for (Direction d : p) {
GameView.addLines(game, Color.GREEN,
grid.toPoint(game.getCurGhostLoc(i)),
GD.add(d.offset, grid.toPoint(game.getCurGhostLoc(i))));
}
p.remove(Direction.getOpDIR(game.getCurGhostDir(i)));
Collections.sort(p, GD.buildTargetComparator(ghostLoc, target));
if (p.isEmpty()) {
return -1;
} else {
return p.get(0).num;
}
}
public enum GhostState {
CHASE, SCATTER, SCARED;
}
private long milliElapsed = 0;
private long lastTime = 0;
private int lives = -1, level = -1;
private void updateStates(Game game) {
long c = System.currentTimeMillis();
if (game.getLivesRemaining() != lives || level != game.getCurLevel()) {
lives = game.getLivesRemaining();
level = game.getCurLevel();
lastTime = System.currentTimeMillis();
milliElapsed = 0;
}
boolean anyGhostScared = false;
for (int i = 0; i < game.NUM_GHOSTS && !anyGhostScared; i++) {
if (game.getEdibleTime(i) > 0) {
anyGhostScared = true;
}
}
if(!anyGhostScared) {
milliElapsed += c - lastTime;
}
lastTime = c;
float time = (float) milliElapsed / 1000f;
float[] table = null;
if (level >= 4) {
table = l5;
} else if (level >= 1) {
table = l2;
} else if (level >= 0) {
table = l1;
}
float sum = 0;
int i = 0;
for (; i < table.length; i++) {
sum += table[i];
if (sum > time ) {
break;
}
}
final GhostState newState = i % 2 == 0 ? GhostState.SCATTER : GhostState.CHASE;
if (allState != newState) {
GHOST_REVERSAL = 1f;
allState = newState;
} else {
GHOST_REVERSAL = 0f;
}
//System.out.println(time + ": " + allState);
}
/**
* Wave Tables
*/
final private float[] l1 = new float[]{ 7, 20,
7, 20,
5, 20,
5, 0};
final private float[] l2 = new float[]{ 7, 20,
7, 20,
5, 1033,
1f/60f, 0};
final private float[] l5 = new float[]{ 5, 20,
5, 20,
5, 1037,
1f/60f, 0};
//Force reversals
public static float GHOST_REVERSAL = 0;
}