Browse Source

Import Part B

master
Christos Houtouridis 6 years ago
parent
commit
e7ad441ac2
8 changed files with 675 additions and 60 deletions
  1. +1
    -0
      GameLog.txt
  2. BIN
      bin/gr/auth/ee/dsproject/node/Node.class
  3. BIN
      bin/gr/auth/ee/dsproject/pacman/Creature.class
  4. +57
    -0
      src/gr/auth/ee/dsproject/node/Globals.java
  5. +0
    -52
      src/gr/auth/ee/dsproject/node/Node.java
  6. +499
    -0
      src/gr/auth/ee/dsproject/node/Node89978445.java
  7. +76
    -0
      src/gr/auth/ee/dsproject/node/Vector.java
  8. +42
    -8
      src/gr/auth/ee/dsproject/pacman/Creature.java

+ 1
- 0
GameLog.txt View File

@@ -3,3 +3,4 @@ Team 0.00 Mine 0 Team 0.00 Mine 1 4
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 1 Team 0.00 Mine 0 131

BIN
bin/gr/auth/ee/dsproject/node/Node.class View File


BIN
bin/gr/auth/ee/dsproject/pacman/Creature.class View File


+ 57
- 0
src/gr/auth/ee/dsproject/node/Globals.java View File

@@ -0,0 +1,57 @@
/**
* @file Globals.java
* @brief
* File containing the Globals 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 Globals
* @brief
* Contains constants and factors to trick
* the Node evaluation algorithm
*/
public class Globals {
/*
* Global constants
*/
public static final int NO_PLACE = -1; // out of region square
//public static final int NO_MOVE = -1;
public static final int INVALID_MOVE = -1; // invalid move marker
public static final int EVAL_MAX = 100; // out max evaluation value
public static final int EVAL_MIN = -100; // our minimum evaluation value
public static final int NO_EVAL = EVAL_MIN-1; // mark the invalid move or no evaluation
/*
* Evaluation settings
*/
/**
* Mixing factor for the minimum distance for life algorithm
*/
public static final double EVAL_LIFE_MIN_FACTOR = 0.8;
/**
* 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
* in the final evaluation value
*/
public static final double EVAL_LIFE_FACTOR = 0.35;
/**
* Evaluation mixing factor representing how mutch of goal will be
* in 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;
}

+ 0
- 52
src/gr/auth/ee/dsproject/node/Node.java View File

@@ -1,52 +0,0 @@
package gr.auth.ee.dsproject.node;
import gr.auth.ee.dsproject.pacman.Room;
import java.util.ArrayList;
public class Node
{
int nodeX;
int nodeY;
int depth;
int nodeMove;
double nodeEvaluation;
int[][] currentGhostPos;
int[][] flagPos;
boolean[] currentFlagStatus;
Node parent;
ArrayList<Node> children = new ArrayList<Node>();
// Constructor
public Node ()
{
// TODO Fill This
}
private int[][] findGhosts (Room[][] Maze)
{
// TODO Fill This
}
private int[][] findFlags (Room[][] Maze)
{
// TODO Fill This
}
private boolean[] checkFlags (Room[][] Maze)
{
// TODO Fill This
}
private double evaluate ()
{
double evaluation = (200 * Math.random()) - 100;
return evaluation;
}
}

+ 499
- 0
src/gr/auth/ee/dsproject/node/Node89978445.java View File

@@ -0,0 +1,499 @@
/**
* @file Node89978445.java
* @brief
* File containing the Node class witch represents
* the moves of Pacman
*
* @author Christos Choutouridis 8997 cchoutou@ece.auth.gr
* @author Konstantina Tsechelidou 8445 konstsec@ece.auth.gr
*/
package gr.auth.ee.dsproject.node;
//import java.awt.image.PackedColorModel;
import gr.auth.ee.dsproject.pacman.PacmanUtilities;
import gr.auth.ee.dsproject.pacman.Room;
import gr.auth.ee.dsproject.node.Vector;
/**
* @class Node
* @brief
* This class holds each move of the current round and it's evaluation
*
*/
public class Node89978445
{
double nodeEvaluation; /**<
* Pacman's current move evaluation
* This is used also as the "return status" of the object
*/
int nodeMove; // Pacman's current move
int nodeX; // Pacman's current x coordinate
int nodeY; // Pacman's current 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[][] flagPos; // Array holding the flag (x,y) pairs
boolean[] currentFlagStatus; // Array holding the flag captuder status
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 ==============
*/
/**
* @brief
* The simple constructor. Just initialize the data
* @note
* Using this constructor means that the user MUST call setMaze(), setPosition()
* and setMove manually after the creation of the Nodexxxx object
*/
public Node89978445 ()
{
// Fill members
nodeX = newX = Globals.NO_PLACE;
nodeY = newY = Globals.NO_PLACE;
nodeMove = Globals.INVALID_MOVE;
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
currentGhostPos = new int [PacmanUtilities.numberOfGhosts][2];
flagPos = new int [PacmanUtilities.numberOfFlags][2];
currentFlagStatus = new boolean[PacmanUtilities.numberOfFlags];
//evaluation data init
ghostNorms = new double [PacmanUtilities.numberOfGhosts];
flagDots = new double [PacmanUtilities.numberOfFlags][PacmanUtilities.numberOfGhosts];
}
/**
* @brief
* Constructor for the node
* @param Maze The current maze object
* @param curX The current pacman's x position
* @param curY The current pacman's y position
* @param move The move under inspection
*/
public Node89978445 (Room[][] Maze, int curX, int curY, int move)
{
this.Maze = Maze; // Fill members
nodeX = newX = curX;
nodeY = newY = curY;
nodeMove = move;
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
currentGhostPos = new int [PacmanUtilities.numberOfGhosts][2];
flagPos = new int [PacmanUtilities.numberOfFlags][2];
currentFlagStatus = new boolean[PacmanUtilities.numberOfFlags];
//evaluation data init
ghostNorms = new double [PacmanUtilities.numberOfGhosts];
flagDots = new double [PacmanUtilities.numberOfFlags][PacmanUtilities.numberOfGhosts];
}
/*
* ============== Setters ===============
*/
/**
* @brief SetMaze (Room) to Node object
* @param maze The room to set
*/
public void setMaze (Room[][] maze) {
this.Maze = maze;
}
/**
* @brief Set pacman's position
* @param curX Pacman's current X position
* @param curY Pacman's current Y position
*/
public void setPosition (int curX, int curY) {
nodeX = curX;
nodeY = curY;
}
/**
* @brief Set the move to Node object
* @param move The move under inspection
*/
public void setMove (int move) {
nodeMove = move;
//update 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;
}
/*
* ============== getters =================
*/
/**
* @brief If not done runs the evaluation algorithm and returns the result
* @return The evaluation result
*/
public double getEvaluation ()
{
// calculate helper arrays
currentGhostPos = findGhosts ();
flagPos = findFlags ();
currentFlagStatus = checkFlags ();
// validation and evaluate move
if (isValidMove ()) {
// If already evaluated do not re-evaluate the move
if (nodeEvaluation == Globals.NO_EVAL)
nodeEvaluation = evaluate ();
}
else {
nodeEvaluation = Globals.NO_EVAL;
}
return nodeEvaluation;
}
/**
* @return
* The current move of the Nodexxxxxxx
*/
public int getMove () {
return nodeMove;
}
/*
* ============= Node's private methods =============
*/
/**
* @brief
* Loop entire maze and return an object that holds Ghost positions
* @param none
* @return Object with Ghost position
* The first dimension holds the number of the ghost
* The 2nd dimension holds the (x, y) coordinates of the ghost
*/
private int[][] findGhosts ()
{
int [][] ret = new int [PacmanUtilities.numberOfGhosts][2]; // Make an object to return
int g = 0; // Ghost index
boolean keepGoing = true; // Boundary check helper variable
// Loop entire Maze (i, j)
for (int x=0 ; keepGoing && x<PacmanUtilities.numberOfRows ; ++x) {
for (int y=0 ; keepGoing && y<PacmanUtilities.numberOfColumns ; ++y) {
if (Maze[x][y].isGhost ()) {
// In case of a Ghost save its position to return object
ret[g][0] = x;
ret[g][1] = y;
// boundary check
if (++g > PacmanUtilities.numberOfGhosts)
keepGoing = false;
}
}
}
return ret;
}
/**
* @brief
* Loop entire maze and return an object that holds flags positions
* @param none
* @return Object with flag positions
* The first dimension holds the number of the flag
* The 2nd dimension holds the (x, y) coordinates of the flag
*/
private int[][] findFlags ()
{
int [][] ret = new int [PacmanUtilities.numberOfFlags][2]; // Make an object to return
int g = 0; // Flag index
boolean keepGoing = true; // Boundary check helper variable
// Loop entire Maze (i, j)
for (int x=0 ; keepGoing && x<PacmanUtilities.numberOfRows ; ++x) {
for (int y=0 ; keepGoing && y<PacmanUtilities.numberOfColumns ; ++y) {
if (Maze[x][y].isFlag()) {
// In case of a Ghost save its position to return object
ret[g][0] = x;
ret[g][1] = y;
// boundary check
if (++g > PacmanUtilities.numberOfFlags)
keepGoing = false;
}
}
}
return ret;
}
/**
* @brief
* Loop through flags and check their status
* @param none
* @return Object with flag status
*/
private boolean[] checkFlags ()
{
boolean[] ret = new boolean [PacmanUtilities.numberOfFlags];
int x, y;
for (int i=0 ; i<PacmanUtilities.numberOfFlags ; ++i) {
x = flagPos[i][0]; // Get row,col coordinates
y = flagPos[i][1];
ret[i] = (Maze[x][y].isCapturedFlag()) ? true : false;
}
return ret;
}
/**
* @brief
* Check if the requested move is valid
*/
private boolean isValidMove ()
{
boolean status = true; //have faith
// filters for the move
if (Maze[nodeX][nodeY].walls[nodeMove] == 0)
status = false;
// keep filling the filters [if any]
return status;
}
/*
* ============ evaluation helper methods ==============
*/
/**
* @brief
* return the average valued of the array
* @param x The array to calculate
* @param size The size of the array
* @return The average value
*/
private double aver (double [] x, int size)
{
double acc = 0; // accumulator
for (int i=0 ; i<size ; ++i) {
acc += x[i];
}
return acc/size;
}
/**
* @brief
* return 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 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;
}
/**
* @brief
* Creates the @ref flagCurVectors
* these vectors are free vectors from current Pacman's position
* to Flags
* @note
* in case of captured flag the corresponding vector is [0, 0]
* @return the array holding the vectors
*/
private Vector[] makeFlagCurVectors () {
Vector[] ret = new Vector[PacmanUtilities.numberOfFlags];
for (int i=0 ; i<PacmanUtilities.numberOfFlags ; ++i) {
if (currentFlagStatus[i] == true)
ret[i] = new Vector (); // eliminate the capture vectors
else
ret[i] = new Vector (nodeX, nodeY, flagPos[i][0], flagPos[i][1]);
}
return ret;
}
/**
* @brief
* Creates the @ref ghostCurVectors
* these vectors are free vectors from current Pacman's position
* to ghosts
* @return the array holding the vectors
*/
private Vector[] makeGhostCurVectors () {
Vector [] ret = new Vector[PacmanUtilities.numberOfGhosts];
for (int i=0 ; i<PacmanUtilities.numberOfGhosts ; ++i) {
ret[i] = new Vector (nodeX, nodeY, currentGhostPos[i][0], currentGhostPos[i][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
* 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 ()
{
double l=0, g=0; // life and goal helpers
int bestFlag = 0; // best flag index in flagPos array
double [] M = new double[PacmanUtilities.numberOfFlags];
//< Array holding the max normalized dot product for each of the flags
Vector candidate; // the distance from Pacman's net position to goal flag
// Create the vectors
flagCurVectors = makeFlagCurVectors ();
ghostCurVectors = makeGhostCurVectors ();
ghostNextVectors = makeghostNextVectors ();
/*
* 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
l = Globals.EVAL_LIFE_MIN_FACTOR * min (ghostNorms, ghostNorms.length)
+ Globals.EVAL_LIFE_AVER_FACTOR * aver (ghostNorms, ghostNorms.length);
// normalize the life to our interval
life = (-1.0 / (1+l)) * (Globals.EVAL_MAX - Globals.EVAL_MIN) + (Globals.EVAL_MAX - Globals.EVAL_MIN)/2;
/*
* goal part
*/
for (int i=0 ; i<PacmanUtilities.numberOfGhosts ; ++i) {
for (int j=0 ; j<PacmanUtilities.numberOfGhosts ; ++j) {
flagDots[i][j] = Vector.dot (flagCurVectors[i], ghostCurVectors[j]) / ghostCurVectors[j].norm();
// 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
// create a vector from pacman's next position to best flag
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
return life * Globals.EVAL_LIFE_FACTOR
+ goal * Globals.EVAL_GOAL_FACTOR;
}
}

+ 76
- 0
src/gr/auth/ee/dsproject/node/Vector.java View File

@@ -0,0 +1,76 @@
/**
* @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);
}
}

+ 42
- 8
src/gr/auth/ee/dsproject/pacman/Creature.java View File

@@ -1,6 +1,10 @@
package gr.auth.ee.dsproject.pacman;
import gr.auth.ee.dsproject.node.Node;
import java.util.ArrayList;
import gr.auth.ee.dsproject.node.Globals;
import gr.auth.ee.dsproject.node.Node89978445;
import gr.auth.ee.dsproject.node.Node89978445;
/**
* <p>
@@ -40,24 +44,54 @@ public class Creature implements gr.auth.ee.dsproject.pacman.AbstractCreature
}
/**
* @brief
* Create node for each one of the possible moves (0, 1, 2, 3) and
* evaluate these moves. After that feeds the valid ones to an ArrayList
* and select the best of them to return
*/
public int calculateNextPacmanPosition (Room[][] Maze, int[] currPosition)
{
// TODO Fill This
Node89978445 mv;
double ev, max = Globals.NO_EVAL;
int decision = -1;
return 0;
ArrayList<Node89978445> moves = new ArrayList<Node89978445> ();
// loop the possible moves and fill them to list
for (int i=0 ; i<4 ; ++i) {
mv = new Node89978445 (Maze, currPosition[0], currPosition[1], i);
if (mv.getEvaluation() > Globals.NO_EVAL)
moves.add (mv);
/*
* how can i rant for not to have a "stay still" move?
*/
}
// Find the best of the moves in list
for (int i=0 ; i<moves.size() ; ++i) {
if ((ev = moves.get(i).getEvaluation()) >= max) {
max = ev;
decision = i;
}
}
return moves.get (decision).getMove();
/*
* The stock version of function:
*
* int moveToReturn = (int) (4 * Math.random());
* return moveToReturn;
*/
}
void createSubTreePacman (int depth, Node parent, Room[][] Maze, int[] currPacmanPosition)
void createSubTreePacman (int depth, Node89978445 parent, Room[][] Maze, int[] currPacmanPosition)
{
// TODO Fill This
}
void createSubTreeGhosts (int depth, Node parent, Room[][] Maze, int[][] currGhostsPosition)
void createSubTreeGhosts (int depth, Node89978445 parent, Room[][] Maze, int[][] currGhostsPosition)
{
// TODO Fill This
}


Loading…
Cancel
Save