
// TileNode.java 
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th

/* Objekt typu TileNode uchovává údaje o individuální dlaždici,
   které využívá algoritmus A* v objektech typu AlienAStarSprite.
   
   Celkové ohodnocení uzlu je:
           costFromStart + costToGoal

   costFromStart obsahuje cenu cesty vedoucí do tohoto uzlu od
   počáteční dlaždice. V rámci algoritmu A* se mu někdy řídká funkce g(x).
   My používáme délku cesty s krokem mezi sousedními dlaždicemi ohodnoceným
   číslem 1.

   constToGoal je (heuristickým) odhadem ceny pohybu od aktuálního uzlu
   do cílového. Někdy se mu také řídká funkce h(x).

   metoda costToGoal() počítá dolní hranici vzdálenosti od aktuální dlaždice do
   cílové. Nejedná se vždy o hodnotu menší nebo rovnu skutečně nejlevnější ceně
   cesty, takže cesta nalezená algoritmem A* nemusí být optimální. Nicméně, 
   výpočet je jednoduchý a rychlý a cesta je pro vetřelce dostatečná.

   Každý objekt typu TileNode má odkaz na svého rodiče, kterým je uzel, jenž
   byl předtím navštíven. Sekvence uzlů zpět k počáteční dlaždici definuje cestu
   k tomuto uzlu (pozpátku).
*/

import java.awt.*;
import java.util.*;


public class TileNode
{
  private Point coord;
  private double costFromStart;
  private double costToGoal;

  private TileNode parent;  
     // lze jej použít pro sestavení cesty od počátečního uzlu až sem


  public TileNode(Point p)
  { coord = p;
    parent = null;
    costFromStart = 0.0;
  }

  public void setCostFromStart(double v)
  {  costFromStart = v; }

  public double getCostFromStart()
  {  return costFromStart;  }


  public void costToGoal(Point goal)
  // vypočítá dolní hranici vzdálenosti v cíli goal
  {
    double dist = coord.distance(goal.x, goal.y);
    costToGoal = Math.floor(dist);
    // System.out.println(coord + " do " + goal + ": " + costToGoal);
  }

  public double getScore()
  { return costFromStart + costToGoal; }


  public Point getPoint()
  {  return coord;  }

  public void setParent(TileNode p)
  {  parent = p; }

  public TileNode getParent()
  {  return parent;  }


  public TileNode makeNeighbour(int quad, WorldDisplay wd)
  /* Vrátí sousedící uzel dlaždice ve směru quad, vyjma situace,
     kdy je lokace dle objektu typu WorldDisplay neplatná. */
  {
    TileNode newNode;
    int x = coord.x;    // méně psaní na následujících řádcích :)
    int y = coord.y;
    if (quad == TiledSprite.NE)
      newNode = ((y%2==0) ? makeNode(x,y-1,wd) : makeNode(x+1,y-1,wd));
    else if (quad == TiledSprite.SE)
       newNode = ((y%2==0) ? makeNode(x,y+1,wd) : makeNode(x+1,y+1,wd));
    else if (quad == TiledSprite.SW)
      newNode = ((y%2==0) ? makeNode(x-1,y+1,wd) : makeNode(x,y+1,wd));
    else if (quad == TiledSprite.NW)
      newNode = ((y%2==0) ? makeNode(x-1,y-1,wd) : makeNode(x,y-1,wd));
    else {
      System.out.println("makeNeighbour() error");
      newNode = null;
    }
    return newNode;
  } // konec metody: makeNeighbour()


  private TileNode makeNode(int x, int y, WorldDisplay wd)
  /* Vytvoří uzel sousední dlaždice. constFromStart je větší než
     hodnota aktuálního uzlu, neboť nový uzel je na cestě o jeden uzel dál. */
  {
    if (!wd.validTileLoc(x,y))
      return null;
    TileNode newNode = new TileNode( new Point(x,y));
    newNode.setCostFromStart( getCostFromStart() + 1.0 );
    newNode.setParent(this);
    return newNode;
  }  // konec metody: makeNode()


  public ArrayList buildPath()
  /* Sestaví cestu (seznam objektů typu Points) od dlaždice za počáteční dlaždicí
     až k této dlaždici. */     
  {
    ArrayList path = new ArrayList();
    path.add(coord);
    TileNode temp = parent;
    while (temp != null) {
      path.add(0, temp.getPoint());  // přidej počátek pro převrácení cesty
      temp = temp.getParent();
    }
    path.remove(0);   // odeber počáteční dlaždici, protože na ní již vetřelec stojí
    return path;
  }

}  // konec třídy: TilesNode
