DEV: A first semi-working version with tree
This commit is contained in:
parent
60118bf1a7
commit
27ad8b6f40
0
.classpath
Executable file → Normal file
0
.classpath
Executable file → Normal file
0
.settings/org.eclipse.jdt.core.prefs
Executable file → Normal file
0
.settings/org.eclipse.jdt.core.prefs
Executable file → Normal file
28
GameLog.txt
Executable file → Normal file
28
GameLog.txt
Executable file → Normal file
@ -80,3 +80,31 @@ 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 77
|
||||||
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 94
|
Team 0.00 Mine 1 Team 0.00 Mine 0 94
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 61
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 14
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 4
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 12
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 97
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 97
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 22
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 22
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 104
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 7
|
||||||
|
Team 0.00 Mine 0 Team 0.00 Mine 1 7
|
||||||
|
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 67
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 67
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 63
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 63
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 65
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 65
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 79
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 79
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 61
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 61
|
||||||
|
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 78
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 71
|
||||||
|
Team 0.00 Mine 1 Team 0.00 Mine 0 71
|
||||||
|
0
bin/.gitignore
vendored
Normal file → Executable file
0
bin/.gitignore
vendored
Normal file → Executable file
BIN
bin/gr/auth/ee/dsproject/pacman/Creature.class
Normal file → Executable file
BIN
bin/gr/auth/ee/dsproject/pacman/Creature.class
Normal file → Executable file
Binary file not shown.
0
ghosts.gif
Executable file → Normal file
0
ghosts.gif
Executable file → Normal file
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
0
lib/pacman.jar
Executable file → Normal file
0
lib/pacman.jar
Executable file → Normal file
0
pacman.gif
Executable file → Normal file
0
pacman.gif
Executable file → Normal file
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
4
src/gr/auth/ee/dsproject/node/Globals.java
Executable file → Normal file
4
src/gr/auth/ee/dsproject/node/Globals.java
Executable file → Normal file
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
package gr.auth.ee.dsproject.node;
|
package gr.auth.ee.dsproject.node;
|
||||||
|
|
||||||
|
import gr.auth.ee.dsproject.pacman.PacmanUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Globals
|
* @class Globals
|
||||||
* @brief
|
* @brief
|
||||||
@ -69,5 +71,5 @@ public class Globals {
|
|||||||
|
|
||||||
public static final int[] FALSE_POS = {-1, -1};
|
public static final int[] FALSE_POS = {-1, -1};
|
||||||
|
|
||||||
public static final int MAX_DISTANCE = 100;
|
public static final int MAX_DISTANCE = PacmanUtilities.numberOfRows + PacmanUtilities.numberOfColumns - 1;
|
||||||
}
|
}
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
/**
|
|
||||||
* @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 static 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 static 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 static 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
179
src/gr/auth/ee/dsproject/node/Node89978445.java
Executable file → Normal file
179
src/gr/auth/ee/dsproject/node/Node89978445.java
Executable file → Normal file
@ -25,17 +25,15 @@ import gr.auth.ee.dsproject.pacman.Room;
|
|||||||
*/
|
*/
|
||||||
public class Node89978445
|
public class Node89978445
|
||||||
{
|
{
|
||||||
double nodeEvaluation; /**<
|
double nodeEvaluation; /*<
|
||||||
* Pacman's current move evaluation
|
* Pacman's current move evaluation
|
||||||
* This is used also as the "return status" of the object
|
* This is used also as the "return status" of the object
|
||||||
*/
|
*/
|
||||||
int[] nodeXY; // Pacman's current x,y coordinate
|
int[] nodeXY; // Pacman's current x,y coordinate
|
||||||
int[][] currentGhostPos; // Array holding the Ghost (x,y) pairs
|
int[][] curGhostPos; // 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 capture status
|
boolean[] curFlagStatus; // Array holding the flag capture status
|
||||||
Room[][] Maze; // copy of the current Maze
|
Room[][] Maze; // copy of the current Maze
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -65,9 +63,9 @@ public class Node89978445
|
|||||||
parent = null;
|
parent = null;
|
||||||
|
|
||||||
// allocate objects
|
// allocate objects
|
||||||
currentGhostPos = new int [PacmanUtilities.numberOfGhosts][2];
|
curGhostPos = new int [PacmanUtilities.numberOfGhosts][2];
|
||||||
flagPos = new int [PacmanUtilities.numberOfFlags][2];
|
flagPos = new int [PacmanUtilities.numberOfFlags][2];
|
||||||
currentFlagStatus = new boolean[PacmanUtilities.numberOfFlags];
|
curFlagStatus = new boolean[PacmanUtilities.numberOfFlags];
|
||||||
children = new ArrayList<Node89978445> ();
|
children = new ArrayList<Node89978445> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,10 +83,18 @@ public class Node89978445
|
|||||||
parent = null;
|
parent = null;
|
||||||
|
|
||||||
// allocate objects
|
// allocate objects
|
||||||
currentGhostPos = new int [PacmanUtilities.numberOfGhosts][2];
|
curGhostPos = new int [PacmanUtilities.numberOfGhosts][2];
|
||||||
flagPos = new int [PacmanUtilities.numberOfFlags][2];
|
flagPos = new int [PacmanUtilities.numberOfFlags][2];
|
||||||
currentFlagStatus = new boolean[PacmanUtilities.numberOfFlags];
|
curFlagStatus = new boolean[PacmanUtilities.numberOfFlags];
|
||||||
children = new ArrayList<Node89978445> ();
|
children = new ArrayList<Node89978445> ();
|
||||||
|
|
||||||
|
// calculate helper arrays
|
||||||
|
curGhostPos = findGhosts ();
|
||||||
|
flagPos = findFlags ();
|
||||||
|
curFlagStatus = checkFlags ();
|
||||||
|
|
||||||
|
//Evaluate the position
|
||||||
|
nodeEvaluation = evaluate ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -123,10 +129,15 @@ public class Node89978445
|
|||||||
{
|
{
|
||||||
// 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) {
|
||||||
|
// Safety filters
|
||||||
|
if (Maze == null)
|
||||||
|
return Globals.NO_EVAL;
|
||||||
|
if (nodeXY == Globals.FALSE_POS)
|
||||||
|
return Globals.NO_EVAL;
|
||||||
// calculate helper arrays
|
// calculate helper arrays
|
||||||
currentGhostPos = findGhosts ();
|
curGhostPos = findGhosts ();
|
||||||
flagPos = findFlags ();
|
flagPos = findFlags ();
|
||||||
currentFlagStatus = checkFlags ();
|
curFlagStatus = checkFlags ();
|
||||||
|
|
||||||
return nodeEvaluation = evaluate ();
|
return nodeEvaluation = evaluate ();
|
||||||
}
|
}
|
||||||
@ -134,16 +145,30 @@ public class Node89978445
|
|||||||
return nodeEvaluation;
|
return nodeEvaluation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[] getCurentPacmanPos () {
|
public int[] getCurrentPacmanPos () {
|
||||||
return nodeXY;
|
return nodeXY;
|
||||||
}
|
}
|
||||||
public int[][] getCurrentGhostPos () {
|
public int[][] getCurrentGhostPos () {
|
||||||
return currentGhostPos;
|
return curGhostPos;
|
||||||
|
}
|
||||||
|
public int getDepth () {
|
||||||
|
return depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ============= Helper API ============
|
* ============= Helper API ============
|
||||||
*/
|
*/
|
||||||
|
public static int moveConv (int[] nextPos, int[] curPos)
|
||||||
|
{
|
||||||
|
int dx = nextPos[0] - curPos[0];
|
||||||
|
int dy = nextPos[1] - curPos[1];
|
||||||
|
|
||||||
|
if (dx < 0) return Room.NORTH;
|
||||||
|
else if (dx > 0) return Room.SOUTH;
|
||||||
|
else if (dy < 0) return Room.WEST;
|
||||||
|
else return Room.EAST;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param creature creature's (x,y)
|
* @param creature creature's (x,y)
|
||||||
* @return
|
* @return
|
||||||
@ -273,9 +298,17 @@ public class Node89978445
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ============ evaluation helper methods ==============
|
* ============ private evaluation helper methods ==============
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
private enum Creature {
|
||||||
|
GHOST, PACMAN
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* Check if the requested ghost move is valid
|
||||||
|
*/
|
||||||
private int[] ghostValidMove (int[] ghost, int move)
|
private int[] ghostValidMove (int[] ghost, int move)
|
||||||
{
|
{
|
||||||
int[] newPos = new int[2];
|
int[] newPos = new int[2];
|
||||||
@ -299,7 +332,7 @@ public class Node89978445
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Check if the requested move is valid
|
* Check if the requested pacman move is valid
|
||||||
*/
|
*/
|
||||||
private int[] pacmanValidMove (int[] pacman, int move)
|
private int[] pacmanValidMove (int[] pacman, int move)
|
||||||
{
|
{
|
||||||
@ -328,12 +361,14 @@ public class Node89978445
|
|||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* A Breadth-first search to find the shortest path distance
|
* A Breadth-first search to find the shortest path distance
|
||||||
* from a ghost to a point in the maze
|
* from an origin point to another point in the maze as if a
|
||||||
* @param ghost Ghost (x, y)
|
* a creature could walk through
|
||||||
|
* @param origin origin (x, y)
|
||||||
* @param xy The x, y coordinate in Maze
|
* @param xy The x, y coordinate in Maze
|
||||||
* @return
|
* @param creature The type of creature for whom the path is for
|
||||||
|
* @return The number of steps from origin to xy
|
||||||
*/
|
*/
|
||||||
private int ghostMoveDist (int[] ghost, int[] xy)
|
private int moveDist (int[] origin, int[] xy, Creature creature)
|
||||||
{
|
{
|
||||||
int move;
|
int move;
|
||||||
int steps, qStepItems; // distance and group counters
|
int steps, qStepItems; // distance and group counters
|
||||||
@ -342,10 +377,10 @@ public class Node89978445
|
|||||||
int c = PacmanUtilities.numberOfColumns; // 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[] 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
|
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
|
Queue2D q = new Queue2D (Globals.MAX_DISTANCE - 1); // Queue to feed with possible position
|
||||||
int [][] dist = new int [r][c];
|
int [][] dist = new int [r][c];
|
||||||
/*<
|
/*<
|
||||||
* 2D array holding all the distances from the ghost to each square of the maze
|
* 2D array holding all the distances from the origin to each square of the maze
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// If target square is inside a box abort with max distance
|
// If target square is inside a box abort with max distance
|
||||||
@ -362,8 +397,8 @@ public class Node89978445
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// loop data
|
// loop data
|
||||||
dist [ghost[0]][ghost[1]] = 0; //starting point is the ghost position
|
dist [origin[0]][origin[1]] = 0; //starting point is the origin position
|
||||||
q.insert (ghost); // feed first loop data
|
q.insert (origin); // feed first loop data
|
||||||
qStepItems = 1; // init counters
|
qStepItems = 1; // init counters
|
||||||
steps = 1;
|
steps = 1;
|
||||||
/*
|
/*
|
||||||
@ -380,94 +415,12 @@ public class Node89978445
|
|||||||
--qStepItems; // mark the removal of the item
|
--qStepItems; // mark the removal of the item
|
||||||
for (move=0 ; move<4 ; ++move) {
|
for (move=0 ; move<4 ; ++move) {
|
||||||
// loop every valid next position for the current position
|
// loop every valid next position for the current position
|
||||||
if ((xyNext = ghostValidMove (xyItem, move)) != Globals.FALSE_POS) {
|
switch (creature) {
|
||||||
if (dist[xyNext[0]][xyNext[1]] == -1) {
|
case GHOST: xyNext = ghostValidMove (xyItem, move); break;
|
||||||
// If we haven't been there
|
case PACMAN: xyNext = pacmanValidMove (xyItem, move); break;
|
||||||
dist[xyNext[0]][xyNext[1]] = steps; // mark the distance
|
default: xyNext = Globals.FALSE_POS;
|
||||||
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 (xyNext != Globals.FALSE_POS) {
|
||||||
// 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
|
|
||||||
* A Breadth-first search to find the shortest path distance
|
|
||||||
* from the pacman to a point in the maze. The point will normaly
|
|
||||||
* represent a flag
|
|
||||||
* @param pacman Pacman's (x, y)
|
|
||||||
* @param xy The x, y coordinate in Maze
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private int pacmanMoveDist (int[] pacman, int[] xy)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
// If target square is inside a box abort with max distance
|
|
||||||
if (isInsideBox (xy))
|
|
||||||
return Globals.MAX_DISTANCE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
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;
|
|
||||||
/*
|
|
||||||
* 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 = pacmanValidMove (xyItem, move)) != Globals.FALSE_POS) {
|
|
||||||
if (dist[xyNext[0]][xyNext[1]] == -1) {
|
if (dist[xyNext[0]][xyNext[1]] == -1) {
|
||||||
// If we haven't been there
|
// If we haven't been there
|
||||||
dist[xyNext[0]][xyNext[1]] = steps; // mark the distance
|
dist[xyNext[0]][xyNext[1]] = steps; // mark the distance
|
||||||
@ -515,7 +468,7 @@ public class Node89978445
|
|||||||
|
|
||||||
// Find ghost distances, min and average
|
// Find ghost distances, min and average
|
||||||
for (i=0, averGhostDist=0 ; i<PacmanUtilities.numberOfGhosts ; ++i) {
|
for (i=0, averGhostDist=0 ; i<PacmanUtilities.numberOfGhosts ; ++i) {
|
||||||
ghostDist [i] = ghostMoveDist (currentGhostPos[i], nodeXY);
|
ghostDist [i] = moveDist (curGhostPos[i], nodeXY, Creature.GHOST);
|
||||||
averGhostDist += ghostDist [i];
|
averGhostDist += ghostDist [i];
|
||||||
if (minGhostDist > ghostDist[i])
|
if (minGhostDist > ghostDist[i])
|
||||||
minGhostDist = ghostDist[i];
|
minGhostDist = ghostDist[i];
|
||||||
@ -528,8 +481,8 @@ public class Node89978445
|
|||||||
|
|
||||||
// Find flag distances and min
|
// Find flag distances and min
|
||||||
for (i=0 ; i<PacmanUtilities.numberOfFlags ; ++i) {
|
for (i=0 ; i<PacmanUtilities.numberOfFlags ; ++i) {
|
||||||
if (currentFlagStatus[i] == false) {
|
if (curFlagStatus[i] == false) {
|
||||||
flagDist[i] = pacmanMoveDist (nodeXY, flagPos[i]);
|
flagDist[i] = moveDist (nodeXY, flagPos[i], Creature.PACMAN);
|
||||||
if (minFlagDist > flagDist[i])
|
if (minFlagDist > flagDist[i])
|
||||||
minFlagDist = flagDist[i];
|
minFlagDist = flagDist[i];
|
||||||
}
|
}
|
||||||
|
0
src/gr/auth/ee/dsproject/node/Queue2D.java
Executable file → Normal file
0
src/gr/auth/ee/dsproject/node/Queue2D.java
Executable file → Normal file
100
src/gr/auth/ee/dsproject/node/Tree.java
Normal file
100
src/gr/auth/ee/dsproject/node/Tree.java
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/**
|
||||||
|
* @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 Tree
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* ============ Constructor ==============
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* The simple constructor. Do nothing (this is a static class)
|
||||||
|
*/
|
||||||
|
public Tree () { }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ========== private helpers ==============
|
||||||
|
*/
|
||||||
|
private static double min (double x, double y) {
|
||||||
|
return (x < y) ? x : y;
|
||||||
|
}
|
||||||
|
private static double max (double x, double y) {
|
||||||
|
return (x > y) ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ========== Tree-like public 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 static Node89978445 grow (Node89978445 node, Node89978445 parent) {
|
||||||
|
if (parent.children.add (node)) {
|
||||||
|
node.parent = parent;
|
||||||
|
node.depth = parent.depth + 1;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Node89978445 minmaxAB (Node89978445 node, int depth, double a, double b, boolean maxingPlayer)
|
||||||
|
{
|
||||||
|
double v, ev;
|
||||||
|
Node89978445 vNode = null;
|
||||||
|
|
||||||
|
if ((depth == 0) || (node.children.isEmpty()))
|
||||||
|
return node;
|
||||||
|
|
||||||
|
if (maxingPlayer) {
|
||||||
|
v = Globals.EVAL_MIN - 1;
|
||||||
|
for (int i=0 ; i<node.children.size() ; ++i) {
|
||||||
|
ev = minmaxAB (node.children.get (i), depth-1, a, b, false).getEvaluation();
|
||||||
|
if (ev > v) {
|
||||||
|
v = ev;
|
||||||
|
vNode = node.children.get (i);
|
||||||
|
}
|
||||||
|
a = max (v, a);
|
||||||
|
if (b <= a)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return vNode;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = Globals.EVAL_MAX + 1;
|
||||||
|
for (int i=0 ; i<node.children.size() ; ++i) {
|
||||||
|
ev = minmaxAB(node.children.get (i), depth-1, a, b, true).getEvaluation();
|
||||||
|
if (ev < v) {
|
||||||
|
v = ev;
|
||||||
|
vNode = node.children.get (i);
|
||||||
|
}
|
||||||
|
b = min (v, b);
|
||||||
|
if (b <= a)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return vNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
69
src/gr/auth/ee/dsproject/pacman/Creature.java
Executable file → Normal file
69
src/gr/auth/ee/dsproject/pacman/Creature.java
Executable file → Normal file
@ -3,7 +3,7 @@ package gr.auth.ee.dsproject.pacman;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import gr.auth.ee.dsproject.node.Globals;
|
import gr.auth.ee.dsproject.node.Globals;
|
||||||
import gr.auth.ee.dsproject.node.MinMaxTree;
|
import gr.auth.ee.dsproject.node.Tree;
|
||||||
import gr.auth.ee.dsproject.node.Node89978445;
|
import gr.auth.ee.dsproject.node.Node89978445;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,33 +38,42 @@ public class Creature implements gr.auth.ee.dsproject.pacman.AbstractCreature
|
|||||||
private int step = 1;
|
private int step = 1;
|
||||||
private boolean amPrey;
|
private boolean amPrey;
|
||||||
|
|
||||||
public Creature (boolean isPrey)
|
public Creature (boolean isPrey) {
|
||||||
{
|
|
||||||
amPrey = isPrey;
|
amPrey = isPrey;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
*
|
||||||
* Create node for each one of the possible moves (0, 1, 2, 3) and
|
|
||||||
* evaluate these moves.
|
|
||||||
*/
|
*/
|
||||||
public int calculateNextPacmanPosition (Room[][] Maze, int[] currPosition)
|
public int calculateNextPacmanPosition (Room[][] Maze, int[] currPosition)
|
||||||
{
|
{
|
||||||
Node89978445 cur = new Node89978445 (Maze, currPosition);
|
int [] bestPos = {-1, -1}; // Best position in maze to play
|
||||||
MinMaxTree mmTree = new MinMaxTree (cur); /*<
|
Node89978445 bestNode; // The node with the best evaluation
|
||||||
* Plant a tree with dummy root
|
Node89978445 cur = new Node89978445 (Maze, currPosition); // The node with the current position
|
||||||
* Null parent and no evaluation
|
|
||||||
*/
|
|
||||||
|
|
||||||
createSubTreePacman (0, cur, Maze, currPosition); //make the tree
|
//make the tree
|
||||||
// min-max
|
createSubTreePacman (cur.getDepth (), cur, Maze, currPosition);
|
||||||
return 0;
|
|
||||||
|
// min-max to find best node and consequently the best position
|
||||||
|
bestNode = Tree.minmaxAB (cur, Globals.MINMAXTREE_MAX_DEPTH-1, Globals.EVAL_MIN - 1, Globals.EVAL_MAX + 1, true);
|
||||||
|
bestPos = bestNode.getCurrentPacmanPos();
|
||||||
|
|
||||||
|
// convert back to move encoding
|
||||||
|
return Node89978445.moveConv (bestPos, currPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
void createSubTreePacman (int depth, Node89978445 parent, Room[][] Maze, int[] curPacmanPosition)
|
void createSubTreePacman (int depth, Node89978445 parent, Room[][] Maze, int[] curPacmanPosition)
|
||||||
{
|
{
|
||||||
if (++depth > Globals.MINMAXTREE_MAX_DEPTH)
|
if (depth >= Globals.MINMAXTREE_MAX_DEPTH-1)
|
||||||
|
/*<
|
||||||
|
* As the depth starts from 0 and MINMAXTREE_MAX_DEPTH
|
||||||
|
* is strictly even, with this comparison we accept that there
|
||||||
|
* is no need for a max-depth layer of ghosts-evaluation based nodes.
|
||||||
|
* As soon as we accept the depth-1 layers max evaluated node.
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
else {
|
else {
|
||||||
Node89978445 newNode;
|
Node89978445 newNode;
|
||||||
@ -76,23 +85,31 @@ public class Creature implements gr.auth.ee.dsproject.pacman.AbstractCreature
|
|||||||
if ((nextPosition = Node89978445.pacmanValidMove (parent, move)) != Globals.FALSE_POS) {
|
if ((nextPosition = Node89978445.pacmanValidMove (parent, move)) != Globals.FALSE_POS) {
|
||||||
// Make a copy of the maze in order to simulate next move and move Pacman
|
// Make a copy of the maze in order to simulate next move and move Pacman
|
||||||
newMaze = PacmanUtilities.copy (Maze);
|
newMaze = PacmanUtilities.copy (Maze);
|
||||||
PacmanUtilities.movePacman (newMaze, parent.getCurentPacmanPos(), nextPosition);
|
PacmanUtilities.movePacman (newMaze, parent.getCurrentPacmanPos(), nextPosition);
|
||||||
|
|
||||||
// Create a node for the move in the new stated game maze
|
// Create a node for the move in the new stated game maze
|
||||||
newNode = new Node89978445 (newMaze, nextPosition);
|
newNode = new Node89978445 (newMaze, nextPosition);
|
||||||
newNode.getEvaluation();
|
Tree.grow (newNode, parent); // add node to the min-max tree
|
||||||
MinMaxTree.insert (newNode, parent); // add node to the min-max tree
|
|
||||||
|
|
||||||
// call the recursive ranch creator
|
// call the recursive ranch creator
|
||||||
createSubTreeGhosts (depth, newNode, newMaze, newNode.getCurrentGhostPos());
|
createSubTreeGhosts (newNode.getDepth (), newNode, newMaze, newNode.getCurrentGhostPos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
void createSubTreeGhosts (int depth, Node89978445 parent, Room[][] Maze, int[][] currGhostsPosition)
|
void createSubTreeGhosts (int depth, Node89978445 parent, Room[][] Maze, int[][] currGhostsPosition)
|
||||||
{
|
{
|
||||||
if (++depth > Globals.MINMAXTREE_MAX_DEPTH)
|
if (depth >= Globals.MINMAXTREE_MAX_DEPTH-1)
|
||||||
|
/*<
|
||||||
|
* As the depth starts from 0 and MINMAXTREE_MAX_DEPTH
|
||||||
|
* is strictly even, with this comparison we accept that there
|
||||||
|
* is no need for a max-depth layer of ghosts-evaluation based nodes.
|
||||||
|
* As soon as we accept the depth-1 layers max evaluated node.
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
else {
|
else {
|
||||||
Node89978445 newNode;
|
Node89978445 newNode;
|
||||||
@ -103,19 +120,17 @@ public class Creature implements gr.auth.ee.dsproject.pacman.AbstractCreature
|
|||||||
ghostMoves = PacmanUtilities.allGhostMoves(Maze, currGhostsPosition);
|
ghostMoves = PacmanUtilities.allGhostMoves(Maze, currGhostsPosition);
|
||||||
|
|
||||||
// loop all ghost moves
|
// loop all ghost moves
|
||||||
int s = ghostMoves.size();
|
for (int i=0 ; i<ghostMoves.size() ; ++i) {
|
||||||
for (int i=0 ; i<s ; ++i) {
|
|
||||||
// Make a copy of the maze in order to simulate next move and move ghosts
|
// Make a copy of the maze in order to simulate next move and move ghosts
|
||||||
newMaze = PacmanUtilities.copy (Maze);
|
newMaze = PacmanUtilities.copy (Maze);
|
||||||
PacmanUtilities.moveGhosts(newMaze, currGhostsPosition, ghostMoves.get(i));
|
PacmanUtilities.moveGhosts(newMaze, currGhostsPosition, ghostMoves.get(i));
|
||||||
|
|
||||||
// Create a node for the move in the new stated game maze
|
// Create a node for the move in the new stated game maze
|
||||||
newNode = new Node89978445 (newMaze, parent.getCurentPacmanPos());
|
newNode = new Node89978445 (newMaze, parent.getCurrentPacmanPos());
|
||||||
newNode.getEvaluation();
|
Tree.grow (newNode, parent); // add node to the min-max tree
|
||||||
MinMaxTree.insert (newNode, parent); // add node to the min-max tree
|
|
||||||
|
|
||||||
//recursive call for the rest of the tree
|
//recursive call for the rest of the tree
|
||||||
//createSubTreePacman (depth, newNode, newMaze, parent.getCurentPacmanPos());
|
createSubTreePacman (newNode.getDepth (), newNode, newMaze, parent.getCurrentPacmanPos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user