From 139286323cdd2c3cee1f2b883d7d5a4c86e1c289 Mon Sep 17 00:00:00 2001 From: Christos Houtouridis Date: Sun, 14 Jan 2018 21:24:27 +0200 Subject: [PATCH] Working version, no walls, no tree --- GameLog.txt | 27 + .../auth/ee/dsproject/pacman/Creature.class | Bin 5525 -> 5520 bytes src/gr/auth/ee/dsproject/node/Globals.java | 40 +- .../auth/ee/dsproject/node/Node89978445.java | 507 +++++++++--------- src/gr/auth/ee/dsproject/node/Queue2D.java | 73 +++ src/gr/auth/ee/dsproject/node/Vector.java | 76 --- src/gr/auth/ee/dsproject/pacman/Creature.java | 3 +- 7 files changed, 394 insertions(+), 332 deletions(-) create mode 100755 src/gr/auth/ee/dsproject/node/Queue2D.java delete mode 100755 src/gr/auth/ee/dsproject/node/Vector.java diff --git a/GameLog.txt b/GameLog.txt index 0083b23..9eb9e46 100755 --- a/GameLog.txt +++ b/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 11 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 diff --git a/bin/gr/auth/ee/dsproject/pacman/Creature.class b/bin/gr/auth/ee/dsproject/pacman/Creature.class index 41afca3e5c431956dbb530fa29360902fb925c85..a461bdbd4b679febd9e83aa90f4ce20ddc4f917e 100755 GIT binary patch delta 853 zcmX|eUwIpuW~aDUeuP`@=E zlJSv712Wt^Z)(Z|>JkpDh$XRWn3L_jL|{xQ!5m+mZ2vKWmq;Fyp5Y$xChDbI<{cjD zYz1BLl0y_dXhJSY^dysBWZ6BJf%Ib#V;Rf@hA`Rg^B88ikdMEn5z)lhS!31YtJdmi z^^PGmqBni0!w9SBYe*jJwv_&6g;~$V49K*@Yr)wDJjj^D8kfQ5@mpc$KWm6VMi{VV zxmSIuN^q-ug&OBp__N#-{&Y<;t2lY8flo7pd>S&HcxKRonFN_diuu}EtSfU%io*9f zp+z>=5)y2ZB$m;Q<<_jgW(twVN=C8D_^x3hYmM)E`xmmE4IE%2huO?Iws3{5Tr=-O zcJLaPw-oW2UHqb0VeCc@T!g2aakr$Fz>)+Q|tWBN20_#xwY zWOF|@0m_Z|6BbZmDnGT|ys!yhvYS`N;||Ap!)crP9F<(;opE{3Z9W)ErBzhb?stCe zLwfdqzt7xHk=1cuOy;j9^EV=?rZL~Ge>K_sDES>V+6jS24iWMYZ9>GU9szl2D<8SC zohqE+ieQu)GFg$#Q4|G=rcg0#QY<^w$i!;GNj0TZaokWd$`wzAnp3F+s+7n_wdA`3 z3R99|6jWoSsD)Z7!@l-u@~E5IYN$FYPn|SYSt?Lxtx}Gzs=La}_sC+;)yMr4yX!9+ CG_soj delta 858 zcmX|QOfLUO|I2K!G$9%@~H!Kr{3n5fRyIqMbyXKla++{`T5y?eA2EH;0df91XAO=G1wV z;(l*d&^$yWUGNj81(|M=xcdC!x(Pg1V%8Kk(63KpF+C}B?Nv> zBaV2BKT$vHP!k$p9F8%yGM+z)px8R{8El$8EMQ4f zWj!a@KrNMAU=z1-c}x{g*}^-v@{Jwx@|V)tscd#>Fx48$9*t(NCbLf^9MHT!IH(mI z(klK@6^FH(qq@j(UE_pqa8h46iws*ze_$o;jgIuF4 z*U97ty}89G?l7Larn}Az-!t>|%;i1{XfSsV*~}xhnc8aW`P&p9<(YYT!5LnfmsiI2 znwyr_^Iy~Z&Tjgf8h*cTgZn1tW72zD^9Nh=M`CCskxw?iksQ9%{2x2kDHoB7AX*;c z)Qlwg2+B`)1?aCR1}U0CHD`=sn50-{DvmP6vqlM2s1;R8WVhOIL`j@hTP`V?I<=!- z?Rl;a{HxBqRggxd$g5PvD@}>&s*XxmhBDQ&n>@->4~ PXLqdjK>6=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 acc/size; + return ret; } - /** - * @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) + private int[] ghostValidMove (int[] ghost, int move) { - double ret = 0; - - for (int i=0 ; i x[i]) - ret = x[i]; - } - return ret; + 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 - * 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 + * Check if the requested move is valid */ - private double max (double [] x, int size) { - double ret = 0; - - for (int i=0 ; i= 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; } /** * @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 + * A Breadth-first search to find the shortest path distance + * from a ghost to a point in the maze + * @param ghost Ghost (x, y) + * @param xy The x, y coordinate in Maze + * @return */ - private int bestFlagPosition (double [] x, int size) { - int pos = 0; - double min = 9999999; // Start large enough - - for (int i=0 ; i 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; + private int ghostMoveDist (int[] ghost, 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 the ghost 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 ; i0) { // 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 ret; + return dist[xy[0]][xy[1]]; } /** * @brief - * Creates the @ref ghostCurVectors - * these vectors are free vectors from current Pacman's position - * to ghosts - * @return the array holding the vectors + * 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 Vector[] makeGhostCurVectors () { - Vector [] ret = new Vector[PacmanUtilities.numberOfGhosts]; - - for (int i=0 ; i0) { // 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 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 ret; + return dist[xy[0]][xy[1]]; } /** * @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 ghostDist[i]) + minGhostDist = ghostDist[i]; } - // 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 flagDist[i]) + minFlagDist = flagDist[i]; } - 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]); + // normalize the flagEval to our interval + flagEval = (1.0 / (1+minFlagDist)) * (Globals.EVAL_MAX - Globals.EVAL_MIN) - (Globals.EVAL_MAX - Globals.EVAL_MIN)/2; - 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; + return ghostEval * Globals.EVAL_GHOSTDIST_FACTOR + + flagEval * Globals.EVAL_FLAGDIST_FACTOR; + } } diff --git a/src/gr/auth/ee/dsproject/node/Queue2D.java b/src/gr/auth/ee/dsproject/node/Queue2D.java new file mode 100755 index 0000000..f7c2866 --- /dev/null +++ b/src/gr/auth/ee/dsproject/node/Queue2D.java @@ -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 @@ -60,7 +59,7 @@ public class Creature implements gr.auth.ee.dsproject.pacman.AbstractCreature // 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); + mv = new Node89978445 (Maze, currPosition, i); if (mv.getEvaluation() > Globals.NO_EVAL) moves.add (mv); /*