initial commit, lordsawar source, slightly modified
[lordsawar] / src / PathCalculator.cpp
diff --git a/src/PathCalculator.cpp b/src/PathCalculator.cpp
new file mode 100644 (file)
index 0000000..c9b449f
--- /dev/null
@@ -0,0 +1,721 @@
+// Copyright (C) 2009 Ben Asselstine
+//
+//  This program is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU Library General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
+//  02110-1301, USA.
+
+#include <stdlib.h>
+#include <string.h>
+#include <queue>
+#include "PathCalculator.h"
+#include "GameMap.h"
+#include "path.h"
+#include "stack.h"
+#include "maptile.h"
+#include "city.h"
+#include "stacklist.h"
+#include "armysetlist.h"
+#include "armyprodbase.h"
+
+#define ENEMY_CITY_WEIGHT 10
+#define ENEMY_STACK_WEIGHT 10
+using namespace std;
+//#define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<flush<<endl;}
+#define debug(x)
+
+void PathCalculator::populateNodeMap()
+{
+  Vector<int> start = stack->getPos();
+  int width = GameMap::getWidth();
+  int height = GameMap::getHeight();
+  if (start.x >= width || start.x < 0)
+    return;
+  if (start.y >= height || start.y < 0)
+    return;
+  size_t length = width * height * sizeof (struct node);
+  nodes = (struct node*) malloc (length);
+  memset (nodes, 0, length);
+
+  // Some notes concerning the path finding algorithm. The algorithm
+  // uses two different lists. There is a nodes array, which contains how
+  // many MP one needs to get to the location (x,y), and a process queue that
+  // tells you at what point the number of movement points is calculated next.
+  //
+  // What we basically do is to start at the stack's position and calculate
+  // the distance (i.e. MP needed to get there) in circles around the starting
+  // position with the circles becoming increasingly larger. In detail, we
+  // start by appending the starting position in the queue of positions to be
+  // processed. Then, recursively, we take the first point in the queue and
+  // recalculate the distance for all bordering tiles, assuming that we go
+  // over this point and overwriting their current value if it is larger
+  // than what we find now. Then, we append each modified tile to the queue of
+  // tiles to be processed and continue. We stop when there are no more tiles
+  // to process.
+  //
+  // Finally, all that is left is finding the minimum distance way from start
+  // point to destination.
+
+  // the conversion between x/y coordinates and index is (size is map size)
+  // index = y*width + x    <=>    x = index % width;   y = index / width
+  std::queue<Vector<int> > process;
+
+  // initial filling of the nodes vector
+  for (int i = 0; i < width*height; i++)
+    {
+      // -1 means don't know yet
+      // -2 means can't go there at all
+      // 0 or more is number of movement points needed to get there
+      nodes[i].moves = -1;
+      nodes[i].moves_left = 0;
+      nodes[i].turns = 0;
+      if (isBlocked(Vector<int>(i % width, i / width)))
+       nodes[i].moves = -2;
+    }
+  int idx = start.toIndex();
+  nodes[idx].moves = 0;
+  nodes[idx].moves_left = stack->getMoves();
+  nodes[idx].turns = 0;
+
+  // now the main loop
+  process.push(start);
+  while (!process.empty())
+    {
+      Vector<int> pos = process.front();
+      process.pop();                          // remove the first item
+
+      std::list<Vector<int> > next = calcMoves(pos);
+      for (std::list<Vector<int> >::iterator it = next.begin(); 
+          it != next.end(); it++)
+       process.push(*it);
+    }
+}
+
+PathCalculator::PathCalculator(const Stack *s, bool zig, int city_avoidance, int stack_avoidance)
+:stack(s), flying(s->isFlying()), d_bonus(s->calculateMoveBonus()),
+    land_reset_moves(s->getMaxLandMoves()),
+    boat_reset_moves(s->getMaxBoatMoves()), zigzag(zig), on_ship(stack->hasShip()), enemy_city_avoidance(city_avoidance), enemy_stack_avoidance(stack_avoidance), delete_stack(false)
+{
+  populateNodeMap();
+}
+
+PathCalculator::PathCalculator(Player *p, Vector<int> src, const ArmyProdBase *prodbase, bool zig, int city_avoidance, int stack_avoidance)
+{
+  Stack *new_stack = Stack::createNonUniqueStack(p, src);
+  Army *army;
+  if (!prodbase)
+    {
+      ArmyProto *proto = Armysetlist::getInstance()->getScout(p->getArmyset());
+      if (!proto)
+       return;
+      army = Army::createNonUniqueArmy (*proto, p);
+    }
+  else
+    army = Army::createNonUniqueArmy (*prodbase, p);
+
+  if (!army)
+    return;
+  new_stack->push_back(army);
+  stack = new_stack;
+  flying = stack->isFlying();
+  d_bonus = stack->calculateMoveBonus();
+  land_reset_moves = stack->getMaxLandMoves();
+  boat_reset_moves = stack->getMaxBoatMoves();
+  zigzag = zig; 
+  enemy_city_avoidance = city_avoidance;
+  enemy_stack_avoidance = stack_avoidance;
+  on_ship = stack->hasShip();
+  delete_stack = true;
+  populateNodeMap();
+}
+
+PathCalculator::PathCalculator(const Stack &s, bool zig, int city_avoidance, int stack_avoidance)
+{
+  stack = new Stack(s);
+  flying = stack->isFlying();
+  d_bonus = stack->calculateMoveBonus();
+  land_reset_moves = stack->getMaxLandMoves();
+  boat_reset_moves = stack->getMaxBoatMoves();
+  zigzag = zig; 
+  enemy_city_avoidance = city_avoidance;
+  enemy_stack_avoidance = stack_avoidance;
+  on_ship = stack->hasShip();
+  delete_stack = true;
+  populateNodeMap();
+}
+
+
+PathCalculator::PathCalculator(const PathCalculator &p)
+:stack(new Stack(*p.stack)), flying(p.flying), d_bonus(p.d_bonus),
+    land_reset_moves(p.land_reset_moves),
+    boat_reset_moves(p.boat_reset_moves), zigzag(p.zigzag), on_ship(p.on_ship),
+    enemy_city_avoidance(p.enemy_city_avoidance), enemy_stack_avoidance(p.enemy_stack_avoidance), delete_stack(p.delete_stack)
+{
+  int width = GameMap::getWidth();
+  int height = GameMap::getHeight();
+  size_t length = width * height * sizeof (struct node);
+  nodes = (struct node*) malloc (length);
+  for (size_t i = 0; i < length; i++)
+    nodes[i] = p.nodes[i];
+}
+
+bool PathCalculator::calcFinalMoves(Vector<int> pos, Vector<int> next)
+{
+  bool traversable = false;
+  int mp;
+  int dxy = nodes[pos.toIndex()].moves;   // always >= 0
+  //am i blocked from entering sx,sy from pos?
+  bool is_blocked_dir = isBlockedDir(pos, next);
+  printf("checking %d,%d to %d,%d\n", pos.x, pos.y, next.x, next.y);
+  //printf("flying is %d\n", flying);
+  //printf("isblockeddir is %d\n", is_blocked_dir);
+  printf("moves of source is %d\n", dxy);
+  if (!flying && is_blocked_dir)
+    return false;
+  //flyers can't go through the void
+  if (flying && is_blocked_dir &&
+      GameMap::getInstance()->getTile(next)->getMaptileType() == Tile::VOID)
+    return false;
+
+  int dsxy = nodes[next.toIndex()].moves;
+  printf("moves of dest is %d\n", dsxy);
+  if (dsxy < -1)
+    return false; //can't move there anyway
+
+  if (zigzag == false)
+    {
+      Vector<int> diff = pos - next;
+      if (diff.x && diff.y)
+       return false;
+    }
+  int newDsxy = dxy;
+  mp = pointsToMoveTo(pos, next);
+  printf("number of moves to get from source to dest is %d\n", mp);
+  if (mp < 0)
+    mp = 0;
+  if (!flying && load_or_unload(pos, next, on_ship) == true)
+    {
+      printf("moves left for %d,%d is %d\n", pos.x, pos.y, nodes[pos.toIndex()].moves_left);
+    mp = nodes[pos.toIndex()].moves_left;
+  printf("correction, number of moves to get from source to dest is %d\n", mp);
+    }
+  newDsxy += mp;
+  if (newDsxy == -1)
+    printf("new algo STILL put -1 in for moves\n");
+
+  //printf("new value for source moves is %d\n", newDsxy);
+  //printf("%d == -1 || %d > %d\n", dsxy, dsxy, newDsxy);
+  if (dsxy == -1 || dsxy > newDsxy)
+    {
+      int idx = next.toIndex();
+      nodes[idx].moves = newDsxy;
+      nodes[idx].moves_left = nodes[pos.toIndex()].moves_left - mp;
+      nodes[idx].turns = nodes[pos.toIndex()].turns;
+      while (nodes[idx].moves_left <= 0)
+       {
+         if (on_ship)
+           nodes[idx].moves_left += boat_reset_moves;
+         else
+           nodes[idx].moves_left += land_reset_moves;
+         nodes[idx].turns++;
+       }
+
+      // append the item to the queue
+      traversable = true;
+    }
+  return traversable;
+}
+
+bool PathCalculator::calcMoves(Vector<int> pos, Vector<int> next)
+{
+  bool traversable = false;
+  int mp;
+  int dxy = nodes[pos.toIndex()].moves;   // always >= 0
+  //am i blocked from entering sx,sy from pos?
+  bool is_blocked_dir = isBlockedDir(pos, next);
+  if (!flying && is_blocked_dir)
+    return false;
+  //flyers can't go through the void
+  if (flying && is_blocked_dir &&
+      GameMap::getInstance()->getTile(next)->getMaptileType() == Tile::VOID)
+    return false;
+
+  int dsxy = nodes[next.toIndex()].moves;
+  if (dsxy < -1)
+    return false; //can't move there anyway
+
+  if (zigzag == false)
+    {
+      Vector<int> diff = pos - next;
+      if (diff.x && diff.y)
+       return false;
+    }
+  int newDsxy = dxy;
+  mp = pointsToMoveTo(pos, next);
+  if (mp < 0)
+    mp = 0;
+  if (!flying && load_or_unload(pos, next, on_ship) == true)
+    mp = nodes[pos.toIndex()].moves_left;
+  newDsxy += mp;
+
+  if (dsxy == -1 || dsxy > newDsxy)
+    {
+      int idx = next.toIndex();
+      nodes[idx].moves = newDsxy;
+      nodes[idx].moves_left = nodes[pos.toIndex()].moves_left - mp;
+      nodes[idx].turns = nodes[pos.toIndex()].turns;
+      while (nodes[idx].moves_left <= 0)
+       {
+         if (on_ship)
+           nodes[idx].moves_left += boat_reset_moves;
+         else
+           nodes[idx].moves_left += land_reset_moves;
+         nodes[idx].turns++;
+       }
+
+      // append the item to the queue
+      traversable = true;
+    }
+  return traversable;
+}
+
+bool PathCalculator::calcFinalMoves(Vector<int> pos)
+{
+  bool traversable = false;
+  int width = GameMap::getWidth();
+  int height = GameMap::getHeight();
+  for (int sx = pos.x-1; sx <= pos.x+1; sx++)
+    {
+      if (sx < 0 || sx >= width)
+       continue;
+
+      for (int sy = pos.y-1; sy <= pos.y+1; sy++)
+       {
+         if (sy < 0 || sy >= height)
+           continue;
+
+         Vector<int> next = Vector<int>(sx, sy);
+         if (pos == next)
+           continue;
+
+         if (nodes[next.toIndex()].moves <= -1)
+           continue;
+         if (calcMoves(next, pos))
+           traversable = true;
+
+       }
+    }
+  return traversable;
+}
+
+std::list<Vector<int> > PathCalculator::calcMoves(Vector<int> pos)
+{
+  int width = GameMap::getWidth();
+  int height = GameMap::getHeight();
+  std::list<Vector<int> > process;
+  for (int sx = pos.x-1; sx <= pos.x+1; sx++)
+    {
+      if (sx < 0 || sx >= width)
+       continue;
+
+      for (int sy = pos.y-1; sy <= pos.y+1; sy++)
+       {
+         if (sy < 0 || sy >= height)
+           continue;
+
+         Vector<int> next = Vector<int>(sx, sy);
+         if (pos == next)
+           continue;
+
+         if (calcMoves(pos, next) == true)
+           process.push_back(next);
+
+       }
+    }
+  return process;
+}
+
+bool PathCalculator::load_or_unload(Vector<int> src, Vector<int> dest, bool &on_ship)
+{
+  Stack *new_stack = Stack::createNonUniqueStack(stack->getOwner(), src);
+  //do we load or unload if we step from SRC to DEST?
+  bool retval = new_stack->isMovingToOrFromAShip(dest, on_ship);
+  delete new_stack;
+  return retval;
+}
+int PathCalculator::pointsToMoveTo(Vector<int> pos, Vector<int> next) const
+{
+  guint32 moves;
+  const Maptile* tile = GameMap::getInstance()->getTile(next);
+
+  if (pos == next) //probably shouldn't happen
+    return 0;
+
+  moves = tile->getMoves();
+
+  if (enemy_city_avoidance >= 1)
+    {
+      //We will still try to avoid enemy cities a little.
+      if (GameMap::getEnemyCity(pos))
+       moves += enemy_city_avoidance;
+    }
+  if (enemy_stack_avoidance >= 1)
+    {
+      //We will still try to avoid enemy stacks a little.
+      if (GameMap::getEnemyStack(pos))
+       moves += enemy_stack_avoidance;
+    }
+
+  // does everything in the stack have a bonus to move onto this square?
+  if (tile->getMaptileType() & d_bonus && moves != 1)
+    return 2;
+
+  return moves;
+}
+
+PathCalculator::~PathCalculator()
+{
+  free (nodes);
+  if (delete_stack)
+    delete stack;
+}
+//am i blocked from entering destx,desty from x,y when i'm not flying?
+bool PathCalculator::isBlockedDir(Vector<int> pos, Vector<int> next)
+{
+  int diffx = next.x - pos.x;
+  int diffy = next.y - pos.y;
+  if (diffx >= -1 && diffx <= 1 && diffy >= -1 && diffy <= 1) 
+    {
+      int idx = 0;
+      if (diffx == -1 && diffy == -1)
+       idx = 0;
+      else if (diffx == -1 && diffy == 0)
+       idx = 1;
+      else if (diffx == -1 && diffy == 1)
+       idx = 2;
+      else if (diffx == 0 && diffy == 1)
+       idx = 3;
+      else if (diffx == 0 && diffy == -1)
+       idx = 4;
+      else if (diffx == 1 && diffy == -1)
+       idx = 5;
+      else if (diffx == 1 && diffy == 0)
+       idx = 6;
+      else if (diffx == 1 && diffy == 1)
+       idx = 7;
+      else
+       return false;
+      return GameMap::getInstance()->getTile(pos)->d_blocked[idx];
+    }
+
+  return false;
+}
+
+bool PathCalculator::isBlocked(const Stack *s, Vector<int> pos, bool enemy_cities_block, bool enemy_stacks_block)
+{
+  const Maptile* tile = GameMap::getInstance()->getTile(pos);
+
+  // Return true on every condition which may prevent the stack from
+  // entering the tile, which are...
+
+  // ...enemy stacks which stand in the way...
+  if (enemy_stacks_block == true)
+    {
+      Stack* target = GameMap::getEnemyStack(pos);
+      if (target)
+       return true;
+    }
+
+  //...enemy cities
+  // saves some computation time here
+  if (tile->getBuilding() == Maptile::CITY && enemy_cities_block == true)
+    {
+      City* c = GameMap::getCity(pos);
+      if (c && (c->getOwner() != s->getOwner()))
+       return true;
+    }
+
+  //no obstacles??? well, then...
+  return false;
+}
+
+bool PathCalculator::isBlocked(Vector<int> pos)
+{
+  return isBlocked(stack, pos, enemy_city_avoidance < 0, enemy_stack_avoidance < 0);
+}
+
+bool PathCalculator::canMoveThere(Vector<int> dest)
+{
+  Vector<int> pos = stack->getPos();
+  if (flying && isBlockedDir(pos, dest) &&
+      GameMap::getInstance()->getTile(dest)->getMaptileType()
+      == Tile::VOID)
+    return false;
+  if (isBlocked(pos))
+    {
+      //psst. if it's our last step we can step into cities.
+      //psst. if it's our last step we can step onto enemy stacks
+      //psst.  if it's our last step and we're a computer player who was diligently walking around friendly stacks, we can merge on our last step
+      return false;
+    }
+  if (isBlockedDir(pos, dest) && !flying)
+    return false;
+  return true;
+}
+
+int PathCalculator::calculate(Vector<int> dest, bool zigzag)
+{
+  int retval = 0;
+  guint32 moves = 0;
+  guint32 turns = 0;
+  Path *p = calculate(dest, moves, turns, zigzag);
+  if (p->size() == 0)
+    retval = -1;
+  delete p;
+  if (retval == 0)
+    retval = (int) moves;
+  return retval;
+}
+
+Path* PathCalculator::calculate(Vector<int> dest, guint32 &moves, guint32 &turns, bool zigzag)
+{
+  Path *path = new Path();
+  int width = GameMap::getWidth();
+  int height = GameMap::getHeight();
+  if (dest.x >= width || dest.x < 0)
+    return path;
+  if (dest.y >= height || dest.y < 0)
+    return path;
+
+
+  int idx = dest.toIndex();
+  struct node orig_dest = nodes[idx];
+  //now change dest node
+  if (nodes[idx].moves == -2)
+    {
+      nodes[idx].moves = -1;
+      nodes[idx].moves_left = 0;
+      nodes[idx].turns = 0;
+      bool traversable = calcFinalMoves(dest);
+      if (traversable == false)
+       {
+         nodes[idx] = orig_dest;
+         return path;
+       }
+    }
+
+  // The nodes array is now completely populated.
+  // What we have to do now is find the shortest path to the destination.
+  // We do that by starting at the destination and moving at each step to
+  // the neighbour closest to the start.
+
+  int dist = nodes[idx].moves;
+  if (dist < 0)
+    {
+      path->setMovesExhaustedAtPoint(0);
+      moves = 0;
+      turns = 0;
+      nodes[idx] = orig_dest;
+      return path;
+    }
+
+  // choose the order in which we process directions so as to favour
+  // diagonals over straight lines
+  std::list<Vector<int> > diffs;
+  if (zigzag)
+    {
+      diffs.push_back(Vector<int>(-1, -1));
+      diffs.push_back(Vector<int>(-1, 1));
+      diffs.push_back(Vector<int>(1, -1));
+      diffs.push_back(Vector<int>(1, 1));
+      diffs.push_back(Vector<int>(1, 0));
+      diffs.push_back(Vector<int>(-1, 0));
+      diffs.push_back(Vector<int>(0, -1));
+      diffs.push_back(Vector<int>(0, 1));
+    }
+  else
+    {
+      diffs.push_back(Vector<int>(1, 0));
+      diffs.push_back(Vector<int>(-1, 0));
+      diffs.push_back(Vector<int>(0, -1));
+      diffs.push_back(Vector<int>(0, 1));
+    }
+
+  Vector<int> pos = dest;
+  while (dist > 0)
+    {
+      path->push_front(pos);
+
+      int min = dist;
+      Vector<int> minpos = pos;
+      for (std::list<Vector<int> >::iterator it = diffs.begin();
+          it != diffs.end(); it++)
+       {
+         Vector<int> next = pos + (*it);
+         if (next.x < 0 || next.x == width || next.y < 0 || next.y == height)
+           continue;
+         //isBlockedDir is needed to catch crossings from land to sea when not thru a port/city
+         if (!flying && isBlockedDir(pos, next))
+           continue;
+
+         dist = nodes[next.toIndex()].moves;
+         if (dist >= 0 && dist < min)
+           {
+             min = dist;
+             minpos = next;
+           }
+       }
+      // found the best spot to go to from
+      pos = minpos;
+      dist = min;
+    }
+
+  //calculate when the waypoints show no more movement possible
+  guint32 pathcount = 0;
+  guint32 moves_left = stack->getMoves();
+  for (Path::iterator it = path->begin(); it != path->end(); it++)
+    {
+      guint32 moves = stack->calculateTileMovementCost(*it);
+      if (moves_left >= moves)
+       moves_left -= moves;
+      else
+       break;
+      pathcount++;
+    }
+  path->setMovesExhaustedAtPoint(pathcount);
+
+  debug("...done");
+
+  moves = nodes[idx].moves;
+  turns = nodes[idx].turns;
+
+  //change dest back
+  nodes[idx] = orig_dest;
+  return path;
+}
+void PathCalculator::dumpNodeMap(Vector<int> dest)
+{
+  int width = GameMap::getWidth();
+  int height = GameMap::getHeight();
+  printf ("==2=====================================\n");
+  for (int i = 0; i < width; i++)
+    {
+    for (int j = 0; j < height; j++)
+      {
+       int moves = nodes[j*width+i].moves;
+       if (stack->getPos() == Vector<int>(i,j))
+         printf("0");
+       else if (dest == Vector<int>(i, j))
+         printf("1");
+       else if (moves == -2)
+         printf ("Z");
+       else if (moves == -1)
+         printf ("X");
+       else
+         printf("%c", (moves % 26) + 'a');
+      }
+    printf ("\n");
+      }
+  printf ("=======================================\n");
+  return;
+} 
+bool PathCalculator::compareNodeMaps(void *map)
+{
+  bool found = false;
+  int width = GameMap::getWidth();
+  int height = GameMap::getHeight();
+  struct node * othernodes = (struct node *) map;
+  for (int i = 0; i < width; i++)
+    for (int j = 0; j < height; j++)
+      {
+       if (othernodes[j*width+i].moves != nodes[j*width+i].moves)
+         {
+         found = true;
+         break;
+         }
+      }
+  return found;
+}
+bool PathCalculator::isReachable(Vector<int> pos)
+{
+  return nodes[pos.toIndex()].moves >= 0;
+}
+
+Path *PathCalculator::calculateToCity (City *c, guint32 &moves, guint32 &turns, bool zigzag)
+{
+  int min_dist = -1;
+  Vector<int> shortest = c->getPos();
+  bool checkJoin = stack->getOwner() == c->getOwner();
+
+  for (unsigned int i = 0; i < c->getSize(); i++)
+    for (unsigned int j = 0; j < c->getSize(); j++)
+      {
+       if (checkJoin == true)
+         {
+           Stack *other_stack = GameMap::getStack(c->getPos() + Vector<int>(i,j));
+           if (other_stack && GameMap::canJoin(stack,other_stack) == false)
+             continue;
+         }
+       int distance = dist (stack->getPos(), c->getPos() + Vector<int>(i, j));
+       if (distance > 0)
+         {
+           if (distance < min_dist || min_dist == -1)
+             {
+               min_dist = distance;
+               shortest = c->getPos() + Vector<int>(i, j);
+             }
+         }
+      }
+  Path *p = calculate(shortest, moves, turns, zigzag);
+  if (p->size() > 0)
+    return p;
+  delete p;
+
+  //okay.. try really hard
+  min_dist = -1;
+  for (unsigned int i = 0; i < c->getSize(); i++)
+    for (unsigned int j = 0; j < c->getSize(); j++)
+      {
+       if (checkJoin == true)
+         {
+           Stack *other_stack = GameMap::getStack(c->getPos() + Vector<int>(i,j));
+           if (other_stack && GameMap::canJoin(stack, other_stack) == false)
+             continue;
+         }
+       p = calculate(c->getPos() + Vector<int>(i,j), moves, turns, zigzag);
+       int dist = (int) moves;
+       delete p;
+       if (dist > 0)
+         {
+           if (dist < min_dist || min_dist == -1)
+             {
+               min_dist = dist;
+               shortest = c->getPos() + Vector<int>(i, j);
+             }
+         }
+      }
+  return calculate(shortest, moves, turns, zigzag);
+}
+
+std::list<Vector<int> > PathCalculator::getReachablePositions(int mp)
+{
+  std::list<Vector<int> > positions;
+  int width = GameMap::getWidth();
+  int height = GameMap::getHeight();
+  for (int i = 0; i < width*height; i++)
+    {
+      if (nodes[i].moves < mp || mp == 0)
+       positions.push_back(Vector<int>(i % width, i / width));
+    }
+  return positions;
+}