Working version, no walls, no tree
This commit is contained in:
parent
e7ad441ac2
commit
139286323c
27
GameLog.txt
27
GameLog.txt
@ -4,3 +4,30 @@ Team 0.00 Mine 0 Team 0.00 Mine 1 25
|
|||||||
Team 0.00 Mine 0 Team 0.00 Mine 1 25
|
Team 0.00 Mine 0 Team 0.00 Mine 1 25
|
||||||
Team 0.00 Mine 0 Team 0.00 Mine 1 11
|
Team 0.00 Mine 0 Team 0.00 Mine 1 11
|
||||||
Team 0.00 Mine 1 Team 0.00 Mine 0 131
|
Team 0.00 Mine 1 Team 0.00 Mine 0 131
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 25
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 44
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 44
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 36
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 36
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 71
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 71
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 165
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 165
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 105
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 88
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 88
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 73
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 73
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 59
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 59
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 140
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 140
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 140
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 62
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 83
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 67
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 75
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 75
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 75
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 75
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 75
|
||||||
|
Binary file not shown.
@ -33,25 +33,37 @@ public class Globals {
|
|||||||
* Evaluation settings
|
* Evaluation settings
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Mixing factor for the minimum distance for life algorithm
|
* Mixing factor for the minimum distance
|
||||||
*/
|
*/
|
||||||
public static final double EVAL_LIFE_MIN_FACTOR = 0.8;
|
public static final double EVAL_GHOSTDIST_MIN_FACTOR = 0.8;
|
||||||
/**
|
public static final double EVAL_LGHOSTDIST_AVER_FACTOR = 1 - EVAL_GHOSTDIST_MIN_FACTOR;
|
||||||
* mixing factor for the average distances for live algorithm
|
|
||||||
* @note the factor is the complementary of the EVAL_LIFE_MIN_FACTOR
|
|
||||||
*/
|
|
||||||
public static final double EVAL_LIFE_AVER_FACTOR = 1 - EVAL_LIFE_MIN_FACTOR;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluation mixing factor representing how mutch of life will be
|
* Evaluation mixing factor representing how much the ghost distances will
|
||||||
* in the final evaluation value
|
* affect the final evaluation value
|
||||||
*/
|
*/
|
||||||
public static final double EVAL_LIFE_FACTOR = 0.35;
|
public static final double EVAL_GHOSTDIST_FACTOR = 0.6;
|
||||||
/**
|
/**
|
||||||
* Evaluation mixing factor representing how mutch of goal will be
|
* Evaluation mixing factor representing how much the flag distances will
|
||||||
* in the final evaluation value
|
* affect the final evaluation value
|
||||||
* @note the factor is the complementary of the EVAL_LIFE_FACTOR
|
|
||||||
*/
|
*/
|
||||||
public static final double EVAL_GOAL_FACTOR = 1 - EVAL_LIFE_FACTOR;
|
public static final double EVAL_FLAGDIST_FACTOR = 1 - EVAL_GHOSTDIST_FACTOR;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In order to find out when a ghost is inside a cavity we manualy
|
||||||
|
* define the box limits of the cavity boxes of the current maze here
|
||||||
|
* :)
|
||||||
|
*/
|
||||||
|
public static final int BOXES[][][] = {
|
||||||
|
{ { 5, 5}, { 8, 8} },
|
||||||
|
{ { 5, 16}, { 8, 19} },
|
||||||
|
{ {11, 5}, {14, 8} },
|
||||||
|
{ {11, 16}, {14, 19} }
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final int[] FALSE_POS = {-1, -1};
|
||||||
|
|
||||||
|
public static final int MAX_DISTANCE = 100;
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,10 @@ package gr.auth.ee.dsproject.node;
|
|||||||
//import java.awt.image.PackedColorModel;
|
//import java.awt.image.PackedColorModel;
|
||||||
import gr.auth.ee.dsproject.pacman.PacmanUtilities;
|
import gr.auth.ee.dsproject.pacman.PacmanUtilities;
|
||||||
import gr.auth.ee.dsproject.pacman.Room;
|
import gr.auth.ee.dsproject.pacman.Room;
|
||||||
import gr.auth.ee.dsproject.node.Vector;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Node
|
* @class Node89978445
|
||||||
* @brief
|
* @brief
|
||||||
* This class holds each move of the current round and it's evaluation
|
* This class holds each move of the current round and it's evaluation
|
||||||
*
|
*
|
||||||
@ -28,43 +28,16 @@ public class Node89978445
|
|||||||
* This is used also as the "return status" of the object
|
* This is used also as the "return status" of the object
|
||||||
*/
|
*/
|
||||||
int nodeMove; // Pacman's current move
|
int nodeMove; // Pacman's current move
|
||||||
int nodeX; // Pacman's current x coordinate
|
int[] nodeXY; // Pacman's current x,y coordinate
|
||||||
int nodeY; // Pacman's current y coordinate
|
int[] newXY; // Pacman's new x,y coordinate
|
||||||
int newX; // Pacman's new x coordinate
|
|
||||||
int newY; // Pacman's new y coordinate
|
|
||||||
int[][] currentGhostPos; // Array holding the Ghost (x,y) pairs
|
int[][] currentGhostPos; // Array holding the Ghost (x,y) pairs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int[][] flagPos; // Array holding the flag (x,y) pairs
|
int[][] flagPos; // Array holding the flag (x,y) pairs
|
||||||
boolean[] currentFlagStatus; // Array holding the flag captuder status
|
boolean[] currentFlagStatus; // Array holding the flag capture status
|
||||||
Room[][] Maze; // copy of the current Maze
|
Room[][] Maze; // copy of the current Maze
|
||||||
|
|
||||||
/*
|
|
||||||
* ======== evaluation data ===========
|
|
||||||
*/
|
|
||||||
Vector[] flagCurVectors; /**<
|
|
||||||
* Array holding the free vectors from current Pacman's position
|
|
||||||
* to Flags
|
|
||||||
* @note
|
|
||||||
* in case of captured flag the corresponding vector is [0, 0]
|
|
||||||
*/
|
|
||||||
Vector[] ghostCurVectors; /**<
|
|
||||||
* Array holding the free vectors from current Pacman's position
|
|
||||||
* to ghosts
|
|
||||||
*/
|
|
||||||
Vector[] ghostNextVectors; /**<
|
|
||||||
* Array holding the free vectors from next Pacman's position
|
|
||||||
* to ghosts. This next position is the one is been evaluated.
|
|
||||||
*/
|
|
||||||
double [] ghostNorms; //*< Helping array holding the norms of the ghostNextVectors vectors
|
|
||||||
double [][] flagDots; /**<
|
|
||||||
* 2d array holding the normalized dot products of all the compinations
|
|
||||||
* in flagCurVectors and ghostCurVectors vectors
|
|
||||||
* rows represent the flags and columns the ghosts
|
|
||||||
*/
|
|
||||||
|
|
||||||
double goal, life; // evaluation factors
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ============ Constructors ==============
|
* ============ Constructors ==============
|
||||||
@ -74,62 +47,44 @@ public class Node89978445
|
|||||||
* The simple constructor. Just initialize the data
|
* The simple constructor. Just initialize the data
|
||||||
* @note
|
* @note
|
||||||
* Using this constructor means that the user MUST call setMaze(), setPosition()
|
* Using this constructor means that the user MUST call setMaze(), setPosition()
|
||||||
* and setMove manually after the creation of the Nodexxxx object
|
* and setMove manually after the creation of the Node89978445 object
|
||||||
*/
|
*/
|
||||||
public Node89978445 ()
|
public Node89978445 ()
|
||||||
{
|
{
|
||||||
// Fill members
|
// Fill members
|
||||||
nodeX = newX = Globals.NO_PLACE;
|
nodeXY = newXY = Globals.FALSE_POS;
|
||||||
nodeY = newY = Globals.NO_PLACE;
|
|
||||||
nodeMove = Globals.INVALID_MOVE;
|
nodeMove = Globals.INVALID_MOVE;
|
||||||
nodeEvaluation = Globals.NO_EVAL;
|
nodeEvaluation = Globals.NO_EVAL;
|
||||||
|
|
||||||
//calculate members
|
|
||||||
//newX += (nodeMove == Room.SOUTH) ? 1:0;
|
|
||||||
//newX -= (nodeMove == Room.NORTH) ? 1:0;
|
|
||||||
//newY += (nodeMove == Room.EAST) ? 1:0;
|
|
||||||
//newY -= (nodeMove == Room.WEST) ? 1:0;
|
|
||||||
|
|
||||||
// allocate objects
|
// allocate objects
|
||||||
currentGhostPos = new int [PacmanUtilities.numberOfGhosts][2];
|
currentGhostPos = new int [PacmanUtilities.numberOfGhosts][2];
|
||||||
flagPos = new int [PacmanUtilities.numberOfFlags][2];
|
flagPos = new int [PacmanUtilities.numberOfFlags][2];
|
||||||
currentFlagStatus = new boolean[PacmanUtilities.numberOfFlags];
|
currentFlagStatus = new boolean[PacmanUtilities.numberOfFlags];
|
||||||
|
|
||||||
//evaluation data init
|
|
||||||
ghostNorms = new double [PacmanUtilities.numberOfGhosts];
|
|
||||||
flagDots = new double [PacmanUtilities.numberOfFlags][PacmanUtilities.numberOfGhosts];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Constructor for the node
|
* Constructor for the Node89978445
|
||||||
* @param Maze The current maze object
|
* @param Maze The current maze object
|
||||||
* @param curX The current pacman's x position
|
* @param curXY The current pacman's (x, y) position
|
||||||
* @param curY The current pacman's y position
|
|
||||||
* @param move The move under inspection
|
* @param move The move under inspection
|
||||||
*/
|
*/
|
||||||
public Node89978445 (Room[][] Maze, int curX, int curY, int move)
|
public Node89978445 (Room[][] Maze, int[] curXY, int move)
|
||||||
{
|
{
|
||||||
this.Maze = Maze; // Fill members
|
this.Maze = Maze; // Fill members
|
||||||
nodeX = newX = curX;
|
nodeXY = newXY = curXY;
|
||||||
nodeY = newY = curY;
|
|
||||||
nodeMove = move;
|
nodeMove = move;
|
||||||
nodeEvaluation = Globals.NO_EVAL;
|
nodeEvaluation = Globals.NO_EVAL;
|
||||||
|
|
||||||
//calculate members
|
//calculate members
|
||||||
newX += (nodeMove == Room.SOUTH) ? 1:0;
|
newXY = pacmanValidMove (nodeXY, move);
|
||||||
newX -= (nodeMove == Room.NORTH) ? 1:0;
|
|
||||||
newY += (nodeMove == Room.EAST) ? 1:0;
|
|
||||||
newY -= (nodeMove == Room.WEST) ? 1:0;
|
|
||||||
|
|
||||||
// allocate objects
|
// allocate objects
|
||||||
currentGhostPos = new int [PacmanUtilities.numberOfGhosts][2];
|
currentGhostPos = new int [PacmanUtilities.numberOfGhosts][2];
|
||||||
flagPos = new int [PacmanUtilities.numberOfFlags][2];
|
flagPos = new int [PacmanUtilities.numberOfFlags][2];
|
||||||
currentFlagStatus = new boolean[PacmanUtilities.numberOfFlags];
|
currentFlagStatus = new boolean[PacmanUtilities.numberOfFlags];
|
||||||
|
|
||||||
//evaluation data init
|
|
||||||
ghostNorms = new double [PacmanUtilities.numberOfGhosts];
|
|
||||||
flagDots = new double [PacmanUtilities.numberOfFlags][PacmanUtilities.numberOfGhosts];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -145,12 +100,12 @@ public class Node89978445
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set pacman's position
|
* @brief Set pacman's position
|
||||||
* @param curX Pacman's current X position
|
* @param curXY Pacman's current X, Y position
|
||||||
* @param curY Pacman's current Y position
|
|
||||||
*/
|
*/
|
||||||
public void setPosition (int curX, int curY) {
|
public void setPosition (int[] curXY) {
|
||||||
nodeX = curX;
|
nodeXY = curXY;
|
||||||
nodeY = curY;
|
//update members
|
||||||
|
newXY = pacmanValidMove (curXY, nodeMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,12 +114,8 @@ public class Node89978445
|
|||||||
*/
|
*/
|
||||||
public void setMove (int move) {
|
public void setMove (int move) {
|
||||||
nodeMove = move;
|
nodeMove = move;
|
||||||
|
|
||||||
//update members
|
//update members
|
||||||
newX += (nodeMove == Room.SOUTH) ? 1:0;
|
newXY = pacmanValidMove (nodeXY, move);
|
||||||
newX -= (nodeMove == Room.NORTH) ? 1:0;
|
|
||||||
newY += (nodeMove == Room.EAST) ? 1:0;
|
|
||||||
newY -= (nodeMove == Room.WEST) ? 1:0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -183,7 +134,7 @@ public class Node89978445
|
|||||||
currentFlagStatus = checkFlags ();
|
currentFlagStatus = checkFlags ();
|
||||||
|
|
||||||
// validation and evaluate move
|
// validation and evaluate move
|
||||||
if (isValidMove ()) {
|
if (newXY != Globals.FALSE_POS) {
|
||||||
// If already evaluated do not re-evaluate the move
|
// If already evaluated do not re-evaluate the move
|
||||||
if (nodeEvaluation == Globals.NO_EVAL)
|
if (nodeEvaluation == Globals.NO_EVAL)
|
||||||
nodeEvaluation = evaluate ();
|
nodeEvaluation = evaluate ();
|
||||||
@ -196,7 +147,7 @@ public class Node89978445
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return
|
* @return
|
||||||
* The current move of the Nodexxxxxxx
|
* The current move of the Node89978445
|
||||||
*/
|
*/
|
||||||
public int getMove () {
|
public int getMove () {
|
||||||
return nodeMove;
|
return nodeMove;
|
||||||
@ -284,216 +235,292 @@ public class Node89978445
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ============ evaluation helper methods ==============
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param creature creature's (x,y)
|
||||||
|
* @return
|
||||||
|
* Return true if the creature is inside the maze boxes
|
||||||
|
*/
|
||||||
|
private boolean isInsideBox (int[] creature)
|
||||||
|
{
|
||||||
|
boolean ret = false; //have faith
|
||||||
|
for (int i=0 ; i<4 ; ++i) {
|
||||||
|
if ((creature[0]>=Globals.BOXES[i][0][0] && creature[0]<=Globals.BOXES[i][1][0]) &&
|
||||||
|
(creature[1]>=Globals.BOXES[i][0][1] && creature[1]<=Globals.BOXES[i][1][1]))
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] ghostValidMove (int[] ghost, int move)
|
||||||
|
{
|
||||||
|
int[] newPos = new int[2];
|
||||||
|
|
||||||
|
// find hypothetical new position
|
||||||
|
newPos[0] = ghost[0];
|
||||||
|
newPos[1] = ghost[1];
|
||||||
|
newPos[0] += (move == Room.SOUTH) ? 1:0;
|
||||||
|
newPos[0] -= (move == Room.NORTH) ? 1:0;
|
||||||
|
newPos[1] += (move == Room.EAST) ? 1:0;
|
||||||
|
newPos[1] -= (move == Room.WEST) ? 1:0;
|
||||||
|
|
||||||
|
// Valid filters
|
||||||
|
if (!((newPos[0] >= 0 && newPos[0] < PacmanUtilities.numberOfRows) &&
|
||||||
|
(newPos[1] >= 0 && newPos[1] < PacmanUtilities.numberOfColumns)))
|
||||||
|
return Globals.FALSE_POS;
|
||||||
|
if (!isInsideBox(ghost) && (Maze[ghost[0]][ghost[1]].walls[move] == 0))
|
||||||
|
return Globals.FALSE_POS;
|
||||||
|
return newPos;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Check if the requested move is valid
|
* Check if the requested move is valid
|
||||||
*/
|
*/
|
||||||
private boolean isValidMove ()
|
private int[] pacmanValidMove (int[] pacman, int move)
|
||||||
{
|
{
|
||||||
boolean status = true; //have faith
|
int[] newPos = new int[2];
|
||||||
|
|
||||||
// filters for the move
|
// find hypothetical new position
|
||||||
if (Maze[nodeX][nodeY].walls[nodeMove] == 0)
|
newPos[0] = pacman[0];
|
||||||
status = false;
|
newPos[1] = pacman[1];
|
||||||
// keep filling the filters [if any]
|
newPos[0] += (move == Room.SOUTH) ? 1:0;
|
||||||
return status;
|
newPos[0] -= (move == Room.NORTH) ? 1:0;
|
||||||
|
newPos[1] += (move == Room.EAST) ? 1:0;
|
||||||
|
newPos[1] -= (move == Room.WEST) ? 1:0;
|
||||||
|
|
||||||
|
// Pacman curves Maze plane to a Torus
|
||||||
|
if (newPos[0] < 0) newPos[0] = PacmanUtilities.numberOfRows;
|
||||||
|
if (newPos[0] >= PacmanUtilities.numberOfRows ) newPos[0] = 0;
|
||||||
|
if (newPos[1] < 0) newPos[1] = PacmanUtilities.numberOfColumns;
|
||||||
|
if (newPos[1] >= PacmanUtilities.numberOfColumns ) newPos[1] = 0;
|
||||||
|
|
||||||
|
// Valid filters
|
||||||
|
if (!isInsideBox(pacman) && (Maze[pacman[0]][pacman[1]].walls[move] == 0))
|
||||||
|
return Globals.FALSE_POS;
|
||||||
|
return newPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* ============ evaluation helper methods ==============
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* return the average valued of the array
|
* A Breadth-first search to find the shortest path distance
|
||||||
* @param x The array to calculate
|
* from a ghost to a point in the maze
|
||||||
* @param size The size of the array
|
* @param ghost Ghost (x, y)
|
||||||
* @return The average value
|
* @param xy The x, y coordinate in Maze
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
private double aver (double [] x, int size)
|
private int ghostMoveDist (int[] ghost, int[] xy)
|
||||||
{
|
{
|
||||||
double acc = 0; // accumulator
|
int move;
|
||||||
|
int steps, qStepItems; // distance and group counters
|
||||||
|
boolean done = false; // algo ending flag
|
||||||
|
int r = PacmanUtilities.numberOfRows; // helper for shorting names
|
||||||
|
int c = PacmanUtilities.numberOfColumns; // helper for shorting names
|
||||||
|
int[] xyItem = new int [2]; // Coordinates of the current position of the algo
|
||||||
|
int[] xyNext = new int [2]; // Coordinates of the next valid position of the algo
|
||||||
|
Queue2D q = new Queue2D (r+c - 1); // Queue to feed with possible position
|
||||||
|
int [][] dist = new int [r][c];
|
||||||
|
/*
|
||||||
|
* 2D array holding all the distances from the ghost to each square of the maze
|
||||||
|
*/
|
||||||
|
|
||||||
for (int i=0 ; i<size ; ++i) {
|
// If target square is inside a box abort with max distance
|
||||||
acc += x[i];
|
if (isInsideBox(xy))
|
||||||
}
|
return Globals.MAX_DISTANCE;
|
||||||
return acc/size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* @brief
|
* init data for algorithm
|
||||||
* return the minimum valued item of the array
|
*/
|
||||||
* @param x The array to filter
|
for (int i=0 ; i<r ; ++i) {
|
||||||
* @param size The size of the array
|
for (int j=0 ; j<c ; ++j) {
|
||||||
* @return The minimum value
|
dist[i][j] = -1;
|
||||||
*/
|
// dist array starts with -1
|
||||||
private double min (double [] x, int size)
|
|
||||||
{
|
|
||||||
double ret = 0;
|
|
||||||
|
|
||||||
for (int i=0 ; i<size ; ++i) {
|
|
||||||
if (i==0 || ret > x[i])
|
|
||||||
ret = x[i];
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
* return the maximum valued item of the array
|
|
||||||
* @param x The array to filter
|
|
||||||
* @param size The size of the array
|
|
||||||
* @return The maximum value
|
|
||||||
*/
|
|
||||||
private double max (double [] x, int size) {
|
|
||||||
double ret = 0;
|
|
||||||
|
|
||||||
for (int i=0 ; i<size ; ++i) {
|
|
||||||
if (i==0 || ret<x[i])
|
|
||||||
ret = x[i];
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
* return the best flag index which is the minimum
|
|
||||||
* valued item of the array
|
|
||||||
* @param x The array to filter
|
|
||||||
* @param size The size of the array
|
|
||||||
* @return The minimum value
|
|
||||||
*/
|
|
||||||
private int bestFlagPosition (double [] x, int size) {
|
|
||||||
int pos = 0;
|
|
||||||
double min = 9999999; // Start large enough
|
|
||||||
|
|
||||||
for (int i=0 ; i<size ; ++i) {
|
|
||||||
if ((min > x[i]) && (x[i] != 0)) {
|
|
||||||
/*<
|
|
||||||
* here we exclude the zero vectors from been candidates
|
|
||||||
* as these vectors represent the captured flags
|
|
||||||
*/
|
|
||||||
min = x[i];
|
|
||||||
pos = i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pos;
|
// loop data
|
||||||
|
dist [ghost[0]][ghost[1]] = 0; //starting point is the ghost position
|
||||||
|
q.insert (ghost); // feed first loop data
|
||||||
|
qStepItems = 1; // init counters
|
||||||
|
steps = 1;
|
||||||
|
/*
|
||||||
|
* Main loop of the algorithm
|
||||||
|
*
|
||||||
|
* For every position we check the valid moves, we apply to them
|
||||||
|
* the step number and we push them to queue. We group the items in
|
||||||
|
* queue with their step number by measuring how many we push them for
|
||||||
|
* the current steps variable value.
|
||||||
|
*/
|
||||||
|
while (done == false) {
|
||||||
|
if (qStepItems>0) { // Have we any item on the current group?
|
||||||
|
xyItem = q.remove (); //load an item of the current group
|
||||||
|
--qStepItems; // mark the removal of the item
|
||||||
|
for (move=0 ; move<4 ; ++move) {
|
||||||
|
// loop every valid next position for the current position
|
||||||
|
if ((xyNext = ghostValidMove (xyItem, move)) != Globals.FALSE_POS) {
|
||||||
|
if (dist[xyNext[0]][xyNext[1]] == -1) {
|
||||||
|
// If we haven't been there
|
||||||
|
dist[xyNext[0]][xyNext[1]] = steps; // mark the distance
|
||||||
|
if ((xyNext[0] == xy[0]) && (xyNext[1] == xy[1])) {
|
||||||
|
/*
|
||||||
|
* first match:
|
||||||
|
* The first time we reach destination we have count the
|
||||||
|
* distance. No need any other try
|
||||||
|
*/
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If we are not there yet, feed queue with another position
|
||||||
|
q.insert (xyNext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// We are done with group, mark how many are for the next one
|
||||||
|
if ((qStepItems = q.size()) <= 0)
|
||||||
|
return dist[xy[0]][xy[1]]; // fail safe return
|
||||||
|
++steps; // Update distance counter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dist[xy[0]][xy[1]];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Creates the @ref flagCurVectors
|
* A Breadth-first search to find the shortest path distance
|
||||||
* these vectors are free vectors from current Pacman's position
|
* from the pacman to a point in the maze. The point will normaly
|
||||||
* to Flags
|
* represent a flag
|
||||||
* @note
|
* @param pacman Pacman's (x, y)
|
||||||
* in case of captured flag the corresponding vector is [0, 0]
|
* @param xy The x, y coordinate in Maze
|
||||||
* @return the array holding the vectors
|
* @return
|
||||||
*/
|
*/
|
||||||
private Vector[] makeFlagCurVectors () {
|
private int pacmanMoveDist (int[] pacman, int[] xy)
|
||||||
Vector[] ret = new Vector[PacmanUtilities.numberOfFlags];
|
{
|
||||||
|
int move;
|
||||||
|
int steps, qStepItems; // distance and group counters
|
||||||
|
boolean done = false; // algo ending flag
|
||||||
|
int r = PacmanUtilities.numberOfRows; // helper for shorting names
|
||||||
|
int c = PacmanUtilities.numberOfColumns; // helper for shorting names
|
||||||
|
int[] xyItem = new int [2]; // Coordinates of the current position of the algo
|
||||||
|
int[] xyNext = new int [2]; // Coordinates of the next valid position of the algo
|
||||||
|
Queue2D q = new Queue2D (r+c - 1); // Queue to feed with possible position
|
||||||
|
int [][] dist = new int [r][c];
|
||||||
|
/*
|
||||||
|
* 2D array holding all the distances from pacman to each square of the maze
|
||||||
|
*/
|
||||||
|
|
||||||
for (int i=0 ; i<PacmanUtilities.numberOfFlags ; ++i) {
|
// If target square is inside a box abort with max distance
|
||||||
if (currentFlagStatus[i] == true)
|
if (isInsideBox (xy))
|
||||||
ret[i] = new Vector (); // eliminate the capture vectors
|
return Globals.MAX_DISTANCE;
|
||||||
else
|
|
||||||
ret[i] = new Vector (nodeX, nodeY, flagPos[i][0], flagPos[i][1]);
|
/*
|
||||||
|
* init data for algorithm
|
||||||
|
*/
|
||||||
|
for (int i=0 ; i<r ; ++i) {
|
||||||
|
for (int j=0 ; j<c ; ++j) {
|
||||||
|
dist[i][j] = -1;
|
||||||
|
// dist array starts with -1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// loop data
|
||||||
return ret;
|
dist [pacman[0]][pacman[1]] = 0; //starting point is the pacman position
|
||||||
}
|
q.insert (pacman); // feed first loop data
|
||||||
|
qStepItems = 1; // init counters
|
||||||
/**
|
steps = 1;
|
||||||
* @brief
|
/*
|
||||||
* Creates the @ref ghostCurVectors
|
* Main loop of the algorithm
|
||||||
* these vectors are free vectors from current Pacman's position
|
*
|
||||||
* to ghosts
|
* For every position we check the valid moves, we apply to them
|
||||||
* @return the array holding the vectors
|
* the step number and we push them to queue. We group the items in
|
||||||
*/
|
* queue with their step number by measuring how many we push them for
|
||||||
private Vector[] makeGhostCurVectors () {
|
* the current steps variable value.
|
||||||
Vector [] ret = new Vector[PacmanUtilities.numberOfGhosts];
|
*/
|
||||||
|
while (done == false) {
|
||||||
for (int i=0 ; i<PacmanUtilities.numberOfGhosts ; ++i) {
|
if (qStepItems>0) { // Have we any item on the current group?
|
||||||
ret[i] = new Vector (nodeX, nodeY, currentGhostPos[i][0], currentGhostPos[i][1]);
|
xyItem = q.remove (); //load an item of the current group
|
||||||
|
--qStepItems; // mark the removal of the item
|
||||||
|
for (move=0 ; move<4 ; ++move) {
|
||||||
|
// loop every valid next position for the current position
|
||||||
|
if ((xyNext = pacmanValidMove (xyItem, move)) != Globals.FALSE_POS) {
|
||||||
|
if (dist[xyNext[0]][xyNext[1]] == -1) {
|
||||||
|
// If we haven't been there
|
||||||
|
dist[xyNext[0]][xyNext[1]] = steps; // mark the distance
|
||||||
|
if ((xyNext[0] == xy[0]) && (xyNext[1] == xy[1])) {
|
||||||
|
/*
|
||||||
|
* first match:
|
||||||
|
* The first time we reach destination we have count the
|
||||||
|
* distance. No need any other try
|
||||||
|
*/
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If we are not there yet, feed queue with another position
|
||||||
|
q.insert (xyNext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// We are done with group, mark how many are for the next one
|
||||||
|
if ((qStepItems = q.size()) <= 0)
|
||||||
|
return dist[xy[0]][xy[1]]; // fail safe return
|
||||||
|
++steps; // Update distance counter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return dist[xy[0]][xy[1]];
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
* Creates the @ref ghostNextVectors
|
|
||||||
* these vectors are free vectors from next Pacman's position
|
|
||||||
* to ghosts. This next position is the one is been evaluated.
|
|
||||||
* @return the array holding the vectors
|
|
||||||
*/
|
|
||||||
private Vector[] makeghostNextVectors () {
|
|
||||||
Vector [] ret = new Vector[PacmanUtilities.numberOfGhosts];
|
|
||||||
|
|
||||||
for (int i=0 ; i<PacmanUtilities.numberOfGhosts ; ++i) {
|
|
||||||
ret[i] = new Vector (newX, newY, currentGhostPos[i][0], currentGhostPos[i][1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Evaluate the current move
|
* Evaluate the current move
|
||||||
*
|
|
||||||
* The evaluation is made is two faces.
|
|
||||||
* 1) We measure distances between Pacman's next position and
|
|
||||||
* ghosts and we extract a value we call life
|
|
||||||
* 2) We consider the dot products of flag and ghost vector compinations in
|
|
||||||
* order to find which flag has the clearest path to it. This path represent
|
|
||||||
* our goal direction. So we measure the direction from pacman's next move to this
|
|
||||||
* flag and from this distance we extract a value we call goal
|
|
||||||
*/
|
*/
|
||||||
private double evaluate ()
|
private double evaluate ()
|
||||||
{
|
{
|
||||||
double l=0, g=0; // life and goal helpers
|
double ghostEval=0, gd=0;
|
||||||
int bestFlag = 0; // best flag index in flagPos array
|
double flagEval=0;
|
||||||
double [] M = new double[PacmanUtilities.numberOfFlags];
|
int i;
|
||||||
//< Array holding the max normalized dot product for each of the flags
|
int[] flagDist = new int[PacmanUtilities.numberOfFlags];
|
||||||
Vector candidate; // the distance from Pacman's net position to goal flag
|
int[] ghostDist = new int[PacmanUtilities.numberOfGhosts];
|
||||||
|
int minGhostDist=Globals.MAX_DISTANCE+1;
|
||||||
|
int averGhostDist; // cast to integer
|
||||||
|
int minFlagDist=Globals.MAX_DISTANCE+1;
|
||||||
|
|
||||||
// Create the vectors
|
// Find ghost distances, min and average
|
||||||
flagCurVectors = makeFlagCurVectors ();
|
for (i=0, averGhostDist=0 ; i<PacmanUtilities.numberOfGhosts ; ++i) {
|
||||||
ghostCurVectors = makeGhostCurVectors ();
|
ghostDist [i] = ghostMoveDist (currentGhostPos[i], newXY);
|
||||||
ghostNextVectors = makeghostNextVectors ();
|
averGhostDist += ghostDist [i];
|
||||||
|
if (minGhostDist > ghostDist[i])
|
||||||
/*
|
minGhostDist = ghostDist[i];
|
||||||
* life part
|
|
||||||
*/
|
|
||||||
for (int i=0 ; i<PacmanUtilities.numberOfGhosts ; ++i) {
|
|
||||||
ghostNorms[i] = ghostNextVectors[i].norm ();
|
|
||||||
// fill the norm array
|
|
||||||
}
|
}
|
||||||
// extract the life as a combination of the minimum distance and the average
|
averGhostDist /= PacmanUtilities.numberOfGhosts;
|
||||||
l = Globals.EVAL_LIFE_MIN_FACTOR * min (ghostNorms, ghostNorms.length)
|
// extract the ghostEval as a combination of the minimum distance and the average
|
||||||
+ Globals.EVAL_LIFE_AVER_FACTOR * aver (ghostNorms, ghostNorms.length);
|
gd = Globals.EVAL_GHOSTDIST_MIN_FACTOR * minGhostDist + Globals.EVAL_GHOSTDIST_MIN_FACTOR * averGhostDist;
|
||||||
// normalize the life to our interval
|
// normalize the ghostEval to our interval
|
||||||
life = (-1.0 / (1+l)) * (Globals.EVAL_MAX - Globals.EVAL_MIN) + (Globals.EVAL_MAX - Globals.EVAL_MIN)/2;
|
ghostEval = (-1.0 / (1+gd)) * (Globals.EVAL_MAX - Globals.EVAL_MIN) + (Globals.EVAL_MAX - Globals.EVAL_MIN)/2;
|
||||||
|
|
||||||
/*
|
// Find flag distances and min
|
||||||
* goal part
|
for (i=0 ; i<PacmanUtilities.numberOfFlags ; ++i) {
|
||||||
*/
|
if (currentFlagStatus[i] == false) {
|
||||||
for (int i=0 ; i<PacmanUtilities.numberOfGhosts ; ++i) {
|
flagDist[i] = pacmanMoveDist (newXY, flagPos[i]);
|
||||||
for (int j=0 ; j<PacmanUtilities.numberOfGhosts ; ++j) {
|
if (minFlagDist > flagDist[i])
|
||||||
flagDots[i][j] = Vector.dot (flagCurVectors[i], ghostCurVectors[j]) / ghostCurVectors[j].norm();
|
minFlagDist = flagDist[i];
|
||||||
// fill the dot product array
|
|
||||||
}
|
}
|
||||||
M[i] = max (flagDots[i], flagDots[i].length); // take the max dot product for each flag
|
|
||||||
}
|
}
|
||||||
bestFlag = bestFlagPosition (M, M.length); // select the best flag
|
// normalize the flagEval to our interval
|
||||||
// create a vector from pacman's next position to best flag
|
flagEval = (1.0 / (1+minFlagDist)) * (Globals.EVAL_MAX - Globals.EVAL_MIN) - (Globals.EVAL_MAX - Globals.EVAL_MIN)/2;
|
||||||
candidate = new Vector (newX, newY, flagPos [bestFlag][0], flagPos [bestFlag][1]);
|
|
||||||
|
|
||||||
g = candidate.norm(); // take the candidate length
|
|
||||||
// normalize the length to our interval
|
|
||||||
goal = (1.0 / (1+g)) * (Globals.EVAL_MAX - Globals.EVAL_MIN) - (Globals.EVAL_MAX - Globals.EVAL_MIN)/2;
|
|
||||||
|
|
||||||
// mix the life and goal to output
|
// mix the life and goal to output
|
||||||
return life * Globals.EVAL_LIFE_FACTOR
|
return ghostEval * Globals.EVAL_GHOSTDIST_FACTOR
|
||||||
+ goal * Globals.EVAL_GOAL_FACTOR;
|
+ flagEval * Globals.EVAL_FLAGDIST_FACTOR;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
73
src/gr/auth/ee/dsproject/node/Queue2D.java
Executable file
73
src/gr/auth/ee/dsproject/node/Queue2D.java
Executable file
@ -0,0 +1,73 @@
|
|||||||
|
package gr.auth.ee.dsproject.node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* A queue implementation for (x, y) coordinates
|
||||||
|
*/
|
||||||
|
public class Queue2D
|
||||||
|
{
|
||||||
|
int [][] q;
|
||||||
|
//int f;
|
||||||
|
int r;
|
||||||
|
int size, nItem;
|
||||||
|
|
||||||
|
public Queue2D () {
|
||||||
|
//f = 0;
|
||||||
|
r = 0;
|
||||||
|
size = nItem = 0;
|
||||||
|
q = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Queue2D (int size) {
|
||||||
|
//f = 0;
|
||||||
|
r = -1;
|
||||||
|
nItem = 0;
|
||||||
|
this.size = size;
|
||||||
|
q = new int[size][2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size () { return nItem; }
|
||||||
|
public boolean isEmpty () { return (nItem == 0) ? true : false; }
|
||||||
|
public boolean isFull () { return (nItem >= size) ? true : false; }
|
||||||
|
|
||||||
|
public int [] peek () {
|
||||||
|
int [] none = {-1, -1};
|
||||||
|
if (!isEmpty ()) {
|
||||||
|
return q[0]; //return q[f];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return none;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int [] insert (int [] it) {
|
||||||
|
int [] none = {-1, -1};
|
||||||
|
|
||||||
|
if (!isFull ()) {
|
||||||
|
++r;
|
||||||
|
q[r][0] = it[0];
|
||||||
|
q[r][1] = it[1];
|
||||||
|
++nItem;
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return none;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int [] remove () {
|
||||||
|
int [] ret = {-1, -1};
|
||||||
|
if (!isEmpty ()) {
|
||||||
|
ret[0] = q[0][0]; //ret[0] = q[f][0];
|
||||||
|
ret[1] = q[0][1]; //ret[1] = q[f][1];
|
||||||
|
for (int i=0 ; i<r ; ++i) {
|
||||||
|
q[i][0] = q[i+1][0];
|
||||||
|
q[i][1] = q[i+1][1];
|
||||||
|
}
|
||||||
|
//++f;
|
||||||
|
--r;
|
||||||
|
--nItem;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
@ -1,76 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file Vector.java
|
|
||||||
* @brief
|
|
||||||
* File containing the Vector class, a helper class for the
|
|
||||||
* vector based evaluation system
|
|
||||||
*
|
|
||||||
* @author Christos Choutouridis 8997 cchoutou@ece.auth.gr
|
|
||||||
* @author Konstantina Tsechelidou 8445 konstsec@ece.auth.gr
|
|
||||||
*/
|
|
||||||
|
|
||||||
package gr.auth.ee.dsproject.node;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class Vector
|
|
||||||
* @brief
|
|
||||||
* A helper class to represent vectors in the Maze
|
|
||||||
*/
|
|
||||||
public class Vector {
|
|
||||||
public int x, y; // the coordinate alternative to vector representation
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief the plain constructor makes a zero vector
|
|
||||||
*/
|
|
||||||
public Vector () {
|
|
||||||
x = y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
* Makes a vector from x,y coordinates of two points in Maze
|
|
||||||
* @param p1x Point 1 x coordinate
|
|
||||||
* @param p1y Point 1 y coordinate
|
|
||||||
* @param p2x Point 2 x coordinate
|
|
||||||
* @param p2y Point 2 y coordinate
|
|
||||||
*/
|
|
||||||
public Vector (int p1x, int p1y, int p2x, int p2y) {
|
|
||||||
x = p2x - p1x;
|
|
||||||
y = p2y - p1y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ========== setters =========
|
|
||||||
*/
|
|
||||||
public int setX (int x) { return (this.x = x); } // set x
|
|
||||||
public int setY (int y) { return (this.y = y); } // set y
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
* The Euclidean norm of the vector
|
|
||||||
* @return the norm
|
|
||||||
*/
|
|
||||||
public double norm () {
|
|
||||||
return Math.sqrt (x*x + y*y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
* The dot product of the vector with another vector
|
|
||||||
* @param a The 2nd vector of the product
|
|
||||||
* @return the dot product value
|
|
||||||
*/
|
|
||||||
public double dot (Vector a) {
|
|
||||||
return (a.x*this.x + a.y*this.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
* A static version of dot product of 2 vectors
|
|
||||||
* @param a Vector a
|
|
||||||
* @param b Vector b
|
|
||||||
* @return The dot product of a and b
|
|
||||||
*/
|
|
||||||
public static double dot (Vector a, Vector b) {
|
|
||||||
return (a.x*b.x + a.y*b.y);
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,6 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
import gr.auth.ee.dsproject.node.Globals;
|
import gr.auth.ee.dsproject.node.Globals;
|
||||||
import gr.auth.ee.dsproject.node.Node89978445;
|
import gr.auth.ee.dsproject.node.Node89978445;
|
||||||
import gr.auth.ee.dsproject.node.Node89978445;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -60,7 +59,7 @@ public class Creature implements gr.auth.ee.dsproject.pacman.AbstractCreature
|
|||||||
|
|
||||||
// loop the possible moves and fill them to list
|
// loop the possible moves and fill them to list
|
||||||
for (int i=0 ; i<4 ; ++i) {
|
for (int i=0 ; i<4 ; ++i) {
|
||||||
mv = new Node89978445 (Maze, currPosition[0], currPosition[1], i);
|
mv = new Node89978445 (Maze, currPosition, i);
|
||||||
if (mv.getEvaluation() > Globals.NO_EVAL)
|
if (mv.getEvaluation() > Globals.NO_EVAL)
|
||||||
moves.add (mv);
|
moves.add (mv);
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user