@@ -31,3 +31,52 @@ 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 78 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 78 | |||
Team 2 Mine 1 Team 1 Mine 0 78 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 76 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 76 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 98 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 98 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 97 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 54 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 67 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 67 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 85 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 85 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 80 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 80 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 70 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 70 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 70 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 94 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 94 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 85 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 85 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 82 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 82 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 64 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 64 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 129 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 129 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 127 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 127 | |||
Team 0.00 Mine 0 Team 0.00 Mine 1 79 | |||
Team 0.00 Mine 0 Team 0.00 Mine 1 79 | |||
Team 0.00 Mine 0 Team 0.00 Mine 1 27 | |||
Team 0.00 Mine 0 Team 0.00 Mine 1 27 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 106 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 106 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 74 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 74 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 62 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 62 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 159 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 159 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 65 | |||
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 77 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 77 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 94 | |||
Team 0.00 Mine 1 Team 0.00 Mine 0 94 |
@@ -50,6 +50,10 @@ public class Globals { | |||
*/ | |||
public static final double EVAL_FLAGDIST_FACTOR = 1 - EVAL_GHOSTDIST_FACTOR; | |||
/* | |||
* Tree settings | |||
*/ | |||
public static final int MINMAXTREE_MAX_DEPTH = 2; | |||
/* | |||
* In order to find out when a ghost is inside a cavity we manualy | |||
@@ -0,0 +1,115 @@ | |||
/** | |||
* @file MinMaxTree.java | |||
* @brief | |||
* File containing the Pacman Min-Max Tree class. | |||
* | |||
* @author Christos Choutouridis 8997 cchoutou@ece.auth.gr | |||
* @author Konstantina Tsechelidou 8445 konstsec@ece.auth.gr | |||
*/ | |||
package gr.auth.ee.dsproject.node; | |||
/** | |||
* @brief | |||
* A tree-like data structure containing move nodes to apply the min-max | |||
* algorithm. | |||
* @note | |||
* This is NOT a real tree. We do not insert node based on a key etc... | |||
*/ | |||
public class MinMaxTree | |||
{ | |||
private Node89978445 root; | |||
/* | |||
* ============ Constructors ============== | |||
*/ | |||
/** | |||
* @brief | |||
* The simple constructor. Just initialize the root to null | |||
*/ | |||
public MinMaxTree () { | |||
root = null; // No root yet | |||
} | |||
/** | |||
* @brief | |||
* A constructor with root | |||
*/ | |||
public MinMaxTree (Node89978445 root) { | |||
setRoot (root); | |||
} | |||
/* | |||
* ========= setter ============ | |||
*/ | |||
/** Set root */ | |||
public Node89978445 setRoot (Node89978445 root) { | |||
return this.root = root; | |||
} | |||
/* | |||
* ========== Tree-like methods ============= | |||
*/ | |||
/** | |||
* @brief | |||
* Insert a node to a parent directly. | |||
* This is NOT a real tree. We do not insert node based on a key | |||
* @param node Node to insert | |||
* @param parent The parent in witch to insert | |||
* @return Reference to inserted node | |||
* If insert fail, returns null | |||
*/ | |||
public Node89978445 insert (Node89978445 node, Node89978445 parent) { | |||
if (parent.children.add (node)) { | |||
node.parent = parent; | |||
return node; | |||
} | |||
else | |||
return null; | |||
} | |||
/** | |||
* @brief | |||
* Find the child with the minimum evaluation value of a | |||
* specific parent and return a reference to it | |||
* @param parent The parent of children we scan | |||
* @return Reference to the child with the minimum evaluation value | |||
* If parent has no children null. | |||
*/ | |||
public Node89978445 minChild (Node89978445 parent) | |||
{ | |||
Node89978445 node = null; | |||
double ev, min = Globals.EVAL_MAX+1; | |||
for (int i=0 ; i<parent.children.size() ; ++i) { | |||
if ((ev = parent.children.get(i).getEvaluation()) < min) { | |||
min = ev; | |||
node = parent.children.get (i); | |||
} | |||
} | |||
return node; | |||
} | |||
/** | |||
* @brief | |||
* Find the child with the maximum evaluation value of a | |||
* specific parent and return a reference to it | |||
* @param parent The parent of children we scan | |||
* @return Reference to the child with the maximum evaluation value | |||
* If parent has no children null. | |||
*/ | |||
public Node89978445 maxChild (Node89978445 parent) | |||
{ | |||
Node89978445 node = null; | |||
double ev, max = Globals.EVAL_MIN-1; | |||
for (int i=0 ; i<parent.children.size() ; ++i) { | |||
if ((ev = parent.children.get(i).getEvaluation()) > max) { | |||
max = ev; | |||
node = parent.children.get (i); | |||
} | |||
} | |||
return node; | |||
} | |||
} |
@@ -10,6 +10,8 @@ | |||
package gr.auth.ee.dsproject.node; | |||
import java.util.ArrayList; | |||
//import java.awt.image.PackedColorModel; | |||
import gr.auth.ee.dsproject.pacman.PacmanUtilities; | |||
import gr.auth.ee.dsproject.pacman.Room; | |||
@@ -27,9 +29,7 @@ public class Node89978445 | |||
* Pacman's current move evaluation | |||
* This is used also as the "return status" of the object | |||
*/ | |||
int nodeMove; // Pacman's current move | |||
int[] nodeXY; // Pacman's current x,y coordinate | |||
int[] newXY; // Pacman's new x,y coordinate | |||
int[][] currentGhostPos; // Array holding the Ghost (x,y) pairs | |||
@@ -38,6 +38,13 @@ public class Node89978445 | |||
boolean[] currentFlagStatus; // Array holding the flag capture status | |||
Room[][] Maze; // copy of the current Maze | |||
/* | |||
* Tree navigation references. These variables are handled by | |||
* PacTree | |||
*/ | |||
Node89978445 parent; | |||
ArrayList<Node89978445> children; | |||
int depth; | |||
/* | |||
* ============ Constructors ============== | |||
@@ -52,15 +59,16 @@ public class Node89978445 | |||
public Node89978445 () | |||
{ | |||
// Fill members | |||
nodeXY = newXY = Globals.FALSE_POS; | |||
nodeMove = Globals.INVALID_MOVE; | |||
this.Maze = null; | |||
nodeXY = Globals.FALSE_POS; | |||
nodeEvaluation = Globals.NO_EVAL; | |||
parent = null; | |||
// allocate objects | |||
currentGhostPos = new int [PacmanUtilities.numberOfGhosts][2]; | |||
flagPos = new int [PacmanUtilities.numberOfFlags][2]; | |||
currentFlagStatus = new boolean[PacmanUtilities.numberOfFlags]; | |||
ArrayList<Node89978445> children = new ArrayList<Node89978445> (); | |||
} | |||
/** | |||
@@ -68,23 +76,19 @@ public class Node89978445 | |||
* Constructor for the Node89978445 | |||
* @param Maze The current maze object | |||
* @param curXY The current pacman's (x, y) position | |||
* @param move The move under inspection | |||
*/ | |||
public Node89978445 (Room[][] Maze, int[] curXY, int move) | |||
public Node89978445 (Room[][] Maze, int[] curXY) | |||
{ | |||
this.Maze = Maze; // Fill members | |||
nodeXY = newXY = curXY; | |||
nodeMove = move; | |||
nodeXY = curXY; | |||
nodeEvaluation = Globals.NO_EVAL; | |||
//calculate members | |||
newXY = pacmanValidMove (nodeXY, move); | |||
parent = null; | |||
// allocate objects | |||
currentGhostPos = new int [PacmanUtilities.numberOfGhosts][2]; | |||
flagPos = new int [PacmanUtilities.numberOfFlags][2]; | |||
currentFlagStatus = new boolean[PacmanUtilities.numberOfFlags]; | |||
ArrayList<Node89978445> children = new ArrayList<Node89978445> (); | |||
} | |||
/* | |||
@@ -104,18 +108,6 @@ public class Node89978445 | |||
*/ | |||
public void setPosition (int[] curXY) { | |||
nodeXY = curXY; | |||
//update members | |||
newXY = pacmanValidMove (curXY, nodeMove); | |||
} | |||
/** | |||
* @brief Set the move to Node object | |||
* @param move The move under inspection | |||
*/ | |||
public void setMove (int move) { | |||
nodeMove = move; | |||
//update members | |||
newXY = pacmanValidMove (nodeXY, move); | |||
} | |||
/* | |||
@@ -124,34 +116,72 @@ public class Node89978445 | |||
/** | |||
* @brief If not done runs the evaluation algorithm and returns the result | |||
* @note We assume the current position was a valid position | |||
* @return The evaluation result | |||
*/ | |||
public double getEvaluation () | |||
{ | |||
// calculate helper arrays | |||
currentGhostPos = findGhosts (); | |||
flagPos = findFlags (); | |||
currentFlagStatus = checkFlags (); | |||
// validation and evaluate move | |||
if (newXY != Globals.FALSE_POS) { | |||
// If already evaluated do not re-evaluate the move | |||
if (nodeEvaluation == Globals.NO_EVAL) | |||
nodeEvaluation = evaluate (); | |||
} | |||
else { | |||
nodeEvaluation = Globals.NO_EVAL; | |||
} | |||
return nodeEvaluation; | |||
} | |||
// If already evaluated do not re-evaluate the move | |||
if (nodeEvaluation == Globals.NO_EVAL) { | |||
// calculate helper arrays | |||
currentGhostPos = findGhosts (); | |||
flagPos = findFlags (); | |||
currentFlagStatus = checkFlags (); | |||
return nodeEvaluation = evaluate (); | |||
} | |||
else | |||
return nodeEvaluation; | |||
} | |||
/* | |||
* ============= Helper API ============ | |||
*/ | |||
/** | |||
* @param creature creature's (x,y) | |||
* @return | |||
* The current move of the Node89978445 | |||
* Return true if the creature is inside the maze boxes | |||
*/ | |||
public int getMove () { | |||
return nodeMove; | |||
public static 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; | |||
} | |||
/** | |||
* @brief | |||
* Static version of move validation | |||
* Check if the requested move for a node is valid | |||
*/ | |||
public static int[] pacmanValidMove (Node89978445 node, int move) | |||
{ | |||
int[] newPos = new int[2]; | |||
// find hypothetical new position | |||
newPos[0] = node.nodeXY[0]; | |||
newPos[1] = node.nodeXY[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; | |||
// 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(node.nodeXY) && | |||
(node.Maze[node.nodeXY[0]][node.nodeXY[1]].walls[move] == 0)) | |||
return Globals.FALSE_POS; | |||
return newPos; | |||
} | |||
/* | |||
* ============= Node's private methods ============= | |||
@@ -239,23 +269,6 @@ public class Node89978445 | |||
* ============ 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]; | |||
@@ -324,7 +337,7 @@ public class Node89978445 | |||
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 | |||
*/ | |||
@@ -495,7 +508,7 @@ public class Node89978445 | |||
// Find ghost distances, min and average | |||
for (i=0, averGhostDist=0 ; i<PacmanUtilities.numberOfGhosts ; ++i) { | |||
ghostDist [i] = ghostMoveDist (currentGhostPos[i], newXY); | |||
ghostDist [i] = ghostMoveDist (currentGhostPos[i], nodeXY); | |||
averGhostDist += ghostDist [i]; | |||
if (minGhostDist > ghostDist[i]) | |||
minGhostDist = ghostDist[i]; | |||
@@ -509,7 +522,7 @@ public class Node89978445 | |||
// Find flag distances and min | |||
for (i=0 ; i<PacmanUtilities.numberOfFlags ; ++i) { | |||
if (currentFlagStatus[i] == false) { | |||
flagDist[i] = pacmanMoveDist (newXY, flagPos[i]); | |||
flagDist[i] = pacmanMoveDist (nodeXY, flagPos[i]); | |||
if (minFlagDist > flagDist[i]) | |||
minFlagDist = flagDist[i]; | |||
} | |||
@@ -1,3 +1,12 @@ | |||
/** | |||
* @file Queue2D.java | |||
* @brief | |||
* File containing the Queue2D class. A queue for x,y coordinate | |||
* pairs | |||
* | |||
* @author Christos Choutouridis 8997 cchoutou@ece.auth.gr | |||
* @author Konstantina Tsechelidou 8445 konstsec@ece.auth.gr | |||
*/ | |||
package gr.auth.ee.dsproject.node; | |||
/** | |||
@@ -6,11 +15,21 @@ package gr.auth.ee.dsproject.node; | |||
*/ | |||
public class Queue2D | |||
{ | |||
int [][] q; | |||
int [][] q; //!< The queue array | |||
//int f; | |||
int r; | |||
int size, nItem; | |||
int r; // Rear pointer | |||
int size, nItem; // Queue helper size and queued items | |||
/* | |||
* ============ Constructors ============== | |||
*/ | |||
/** | |||
* @brief | |||
* Simple constructor. Initialize all to zero | |||
* @note | |||
* As long as there is no Setter for buffer and read pointer | |||
* this constructor is useless. | |||
*/ | |||
public Queue2D () { | |||
//f = 0; | |||
r = 0; | |||
@@ -18,18 +37,37 @@ public class Queue2D | |||
q = null; | |||
} | |||
/** | |||
* @brief | |||
* Constructor with buffer size | |||
* @param size The size of buffer to allocate | |||
*/ | |||
public Queue2D (int size) { | |||
//f = 0; | |||
r = -1; | |||
r = -1; // Init the rear value | |||
nItem = 0; | |||
this.size = size; | |||
q = new int[size][2]; | |||
} | |||
/** | |||
* @return The "waiting" items in queue | |||
*/ | |||
public int size () { return nItem; } | |||
/** | |||
* @return True if queue is empty | |||
*/ | |||
public boolean isEmpty () { return (nItem == 0) ? true : false; } | |||
/** | |||
* @return True if queue is full | |||
*/ | |||
public boolean isFull () { return (nItem >= size) ? true : false; } | |||
/** | |||
* @return | |||
* The first item waiting in queue, without removing it | |||
* If the queue is empty return {-1, -1} | |||
*/ | |||
public int [] peek () { | |||
int [] none = {-1, -1}; | |||
if (!isEmpty ()) { | |||
@@ -38,26 +76,18 @@ public class Queue2D | |||
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; | |||
} | |||
/** | |||
* @return | |||
* The first item waiting in queue and removes it | |||
* If the queue is empty return {-1, -1} | |||
*/ | |||
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]; | |||
// shift the buffered items | |||
for (int i=0 ; i<r ; ++i) { | |||
q[i][0] = q[i+1][0]; | |||
q[i][1] = q[i+1][1]; | |||
@@ -70,4 +100,25 @@ public class Queue2D | |||
else | |||
return ret; | |||
} | |||
/** | |||
* @brief | |||
* Insert an item to the queue | |||
* @param it Reference to item to insert | |||
* @return The inserted item | |||
* If the queue is full return {-1, -1} | |||
*/ | |||
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; | |||
} | |||
} |
@@ -3,6 +3,7 @@ package gr.auth.ee.dsproject.pacman; | |||
import java.util.ArrayList; | |||
import gr.auth.ee.dsproject.node.Globals; | |||
import gr.auth.ee.dsproject.node.MinMaxTree; | |||
import gr.auth.ee.dsproject.node.Node89978445; | |||
/** | |||
@@ -49,38 +50,42 @@ public class Creature implements gr.auth.ee.dsproject.pacman.AbstractCreature | |||
* 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) | |||
// { | |||
// Node89978445 node = new Node89978445 (); // make a dummy node | |||
// MinMaxTree rt = new MinMaxTree (node); /*< | |||
// * Plant a tree with dummy root | |||
// * Null parent and no evaluation | |||
// */ | |||
// | |||
// createSubTreePacman (0,node, Maze, currPosition); | |||
// return 0; | |||
// } | |||
public int calculateNextPacmanPosition (Room[][] Maze, int[] currPosition) | |||
{ | |||
Node89978445 mv; | |||
Node89978445 cur = new Node89978445 (Maze, currPosition); | |||
Node89978445 moveNode; | |||
//ArrayList<Node89978445> moveNodes = new ArrayList<Node89978445> (); | |||
double ev, max = Globals.NO_EVAL; | |||
int decision = -1; | |||
ArrayList<Node89978445> moves = new ArrayList<Node89978445> (); | |||
// loop the possible moves and fill them to list | |||
int[] nextPosition = {-1, -1}; | |||
/* | |||
* loop the possible moves and fill them to list | |||
* mark the move with the maximum evaluation value | |||
*/ | |||
for (int i=0 ; i<4 ; ++i) { | |||
mv = new Node89978445 (Maze, currPosition, 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; | |||
if ((nextPosition = Node89978445.pacmanValidMove(cur, i)) != Globals.FALSE_POS) { | |||
moveNode = new Node89978445 (Maze, nextPosition); | |||
ev = moveNode.getEvaluation(); | |||
if (ev > max) { | |||
max = ev; | |||
decision = i; | |||
} | |||
} | |||
} | |||
return moves.get (decision).getMove(); | |||
/* | |||
* The stock version of function: | |||
* | |||
* int moveToReturn = (int) (4 * Math.random()); | |||
* return moveToReturn; | |||
*/ | |||
return decision; | |||
} | |||
void createSubTreePacman (int depth, Node89978445 parent, Room[][] Maze, int[] currPacmanPosition) | |||