diff --git a/AStar/AStar.csproj b/AStar/AStar.csproj new file mode 100755 index 0000000..638fe4b --- /dev/null +++ b/AStar/AStar.csproj @@ -0,0 +1,62 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {CD3F949D-54AA-4D38-99DB-92905A375D84} + Library + Properties + AStar + AStar + v4.0 + + + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AStar/AuthorAttribute.cs b/AStar/AuthorAttribute.cs new file mode 100755 index 0000000..a011279 --- /dev/null +++ b/AStar/AuthorAttribute.cs @@ -0,0 +1,24 @@ +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +// PURPOSE. IT CAN BE DISTRIBUTED FREE OF CHARGE AS LONG AS THIS HEADER +// REMAINS UNCHANGED. +// +// Email: gustavo_franco@hotmail.com +// +// Copyright (C) 2006 Franco, Gustavo +// +using System; + +namespace AStar +{ + internal class AuthorAttribute : Attribute + { + #region Constructors + public AuthorAttribute(string authorName) + { + } + #endregion + } +} diff --git a/AStar/HighResolutionTime.cs b/AStar/HighResolutionTime.cs new file mode 100755 index 0000000..4179fa0 --- /dev/null +++ b/AStar/HighResolutionTime.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AStar +{ + public static class HighResolutionTime + { + #region Win32APIs + [System.Runtime.InteropServices.DllImport("Kernel32.dll")] + private static extern bool QueryPerformanceCounter(out long perfcount); + + [System.Runtime.InteropServices.DllImport("Kernel32.dll")] + private static extern bool QueryPerformanceFrequency(out long freq); + #endregion + + #region Variables Declaration + private static long mStartCounter; + private static long mFrequency; + #endregion + + #region Constuctors + static HighResolutionTime() + { + QueryPerformanceFrequency(out mFrequency); + } + #endregion + + #region Methods + public static void Start() + { + QueryPerformanceCounter(out mStartCounter); + } + + public static double GetTime() + { + long endCounter; + QueryPerformanceCounter(out endCounter); + long elapsed = endCounter - mStartCounter; + return (double) elapsed / mFrequency; + } + #endregion + } +} + diff --git a/AStar/IPathFinder.cs b/AStar/IPathFinder.cs new file mode 100755 index 0000000..e62ca3f --- /dev/null +++ b/AStar/IPathFinder.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Text; +using AStar; +using System.Drawing; + +namespace AStar +{ + [Author("Franco, Gustavo")] + interface IPathFinder + { + #region Events + event PathFinderDebugHandler PathFinderDebug; + #endregion + + #region Properties + bool Stopped + { + get; + } + + HeuristicFormula Formula + { + get; + set; + } + + bool Diagonals + { + get; + set; + } + + bool HeavyDiagonals + { + get; + set; + } + + int HeuristicEstimate + { + get; + set; + } + + bool PunishChangeDirection + { + get; + set; + } + + bool TieBreaker + { + get; + set; + } + + int SearchLimit + { + get; + set; + } + + double CompletedTime + { + get; + set; + } + + bool DebugProgress + { + get; + set; + } + + bool DebugFoundPath + { + get; + set; + } + #endregion + + #region Methods + void FindPathStop(); + List FindPath(Point start, Point end); + #endregion + + } +} diff --git a/AStar/PathFinder.cs b/AStar/PathFinder.cs new file mode 100755 index 0000000..9216df9 --- /dev/null +++ b/AStar/PathFinder.cs @@ -0,0 +1,404 @@ +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +// PURPOSE. IT CAN BE DISTRIBUTED FREE OF CHARGE AS LONG AS THIS HEADER +// REMAINS UNCHANGED. +// +// Email: gustavo_franco@hotmail.com +// +// Copyright (C) 2006 Franco, Gustavo +// +//#define DEBUGON + +using System; +using System.Drawing; +using System.Collections.Generic; + +namespace AStar +{ + #region Structs + [Author("Franco, Gustavo")] + public struct PathFinderNode + { + #region Variables Declaration + public int F; + public int G; + public int H; // f = gone + heuristic + public int X; + public int Y; + public int PX; // Parent + public int PY; + #endregion + } + #endregion + + #region Enum + [Author("Franco, Gustavo")] + public enum PathFinderNodeType + { + Start = 1, + End = 2, + Open = 4, + Close = 8, + Current = 16, + Path = 32 + } + + public enum HeuristicFormula + { + Manhattan = 1, + MaxDXDY = 2, + DiagonalShortCut = 3, + Euclidean = 4, + EuclideanNoSQR = 5, + Custom1 = 6 + } + #endregion + + #region Delegates + public delegate void PathFinderDebugHandler(int fromX, int fromY, int x, int y, PathFinderNodeType type, int totalCost, int cost); + #endregion + + [Author("Franco, Gustavo")] + public class PathFinder : IPathFinder + { + [System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint="RtlZeroMemory")] + public unsafe static extern bool ZeroMemory(byte* destination, int length); + + #region Events + public event PathFinderDebugHandler PathFinderDebug; + #endregion + + #region Variables Declaration + private byte[,] mGrid = null; + private PriorityQueueB mOpen = new PriorityQueueB(new ComparePFNode()); + private List mClose = new List(); + private bool mStop = false; + private bool mStopped = true; + private int mHoriz = 0; + private HeuristicFormula mFormula = HeuristicFormula.Manhattan; + private bool mDiagonals = true; + private int mHEstimate = 2; + private bool mPunishChangeDirection = false; + private bool mTieBreaker = false; + private bool mHeavyDiagonals = false; + private int mSearchLimit = 2000; + private double mCompletedTime = 0; + private bool mDebugProgress = false; + private bool mDebugFoundPath = false; + #endregion + + #region Constructors + public PathFinder(byte[,] grid) + { + if (grid == null) + throw new Exception("Grid cannot be null"); + + mGrid = grid; + } + #endregion + + #region Properties + public bool Stopped + { + get { return mStopped; } + } + + public HeuristicFormula Formula + { + get { return mFormula; } + set { mFormula = value; } + } + + public bool Diagonals + { + get { return mDiagonals; } + set { mDiagonals = value; } + } + + public bool HeavyDiagonals + { + get { return mHeavyDiagonals; } + set { mHeavyDiagonals = value; } + } + + public int HeuristicEstimate + { + get { return mHEstimate; } + set { mHEstimate = value; } + } + + public bool PunishChangeDirection + { + get { return mPunishChangeDirection; } + set { mPunishChangeDirection = value; } + } + + public bool TieBreaker + { + get { return mTieBreaker; } + set { mTieBreaker = value; } + } + + public int SearchLimit + { + get { return mSearchLimit; } + set { mSearchLimit = value; } + } + + public double CompletedTime + { + get { return mCompletedTime; } + set { mCompletedTime = value; } + } + + public bool DebugProgress + { + get { return mDebugProgress; } + set { mDebugProgress = value; } + } + + public bool DebugFoundPath + { + get { return mDebugFoundPath; } + set { mDebugFoundPath = value; } + } + #endregion + + #region Methods + public void FindPathStop() + { + mStop = true; + } + + public List FindPath(Point start, Point end) + { + HighResolutionTime.Start(); + + PathFinderNode parentNode; + bool found = false; + int gridX = mGrid.GetUpperBound(0); + int gridY = mGrid.GetUpperBound(1); + + mStop = false; + mStopped = false; + mOpen.Clear(); + mClose.Clear(); + + #if DEBUGON + if (mDebugProgress && PathFinderDebug != null) + PathFinderDebug(0, 0, start.X, start.Y, PathFinderNodeType.Start, -1, -1); + if (mDebugProgress && PathFinderDebug != null) + PathFinderDebug(0, 0, end.X, end.Y, PathFinderNodeType.End, -1, -1); + #endif + + sbyte[,] direction; + if (mDiagonals) + direction = new sbyte[8,2]{ {0,-1} , {1,0}, {0,1}, {-1,0}, {1,-1}, {1,1}, {-1,1}, {-1,-1}}; + else + direction = new sbyte[4,2]{ {0,-1} , {1,0}, {0,1}, {-1,0}}; + + parentNode.G = 0; + parentNode.H = mHEstimate; + parentNode.F = parentNode.G + parentNode.H; + parentNode.X = start.X; + parentNode.Y = start.Y; + parentNode.PX = parentNode.X; + parentNode.PY = parentNode.Y; + mOpen.Push(parentNode); + while(mOpen.Count > 0 && !mStop) + { + parentNode = mOpen.Pop(); + + #if DEBUGON + if (mDebugProgress && PathFinderDebug != null) + PathFinderDebug(0, 0, parentNode.X, parentNode.Y, PathFinderNodeType.Current, -1, -1); + #endif + + if (parentNode.X == end.X && parentNode.Y == end.Y) + { + mClose.Add(parentNode); + found = true; + break; + } + + if (mClose.Count > mSearchLimit) + { + mStopped = true; + return null; + } + + if (mPunishChangeDirection) + mHoriz = (parentNode.X - parentNode.PX); + + //Lets calculate each successors + for (int i=0; i<(mDiagonals ? 8 : 4); i++) + { + PathFinderNode newNode; + newNode.X = parentNode.X + direction[i,0]; + newNode.Y = parentNode.Y + direction[i,1]; + + if (newNode.X < 0 || newNode.Y < 0 || newNode.X >= gridX || newNode.Y >= gridY) + continue; + + int newG; + if (mHeavyDiagonals && i>3) + newG = parentNode.G + (int) (mGrid[newNode.X, newNode.Y] * 2.41); + else + newG = parentNode.G + mGrid[newNode.X, newNode.Y]; + + + if (newG == parentNode.G) + { + //Unbrekeable + continue; + } + + if (mPunishChangeDirection) + { + if ((newNode.X - parentNode.X) != 0) + { + if (mHoriz == 0) + newG += 20; + } + if ((newNode.Y - parentNode.Y) != 0) + { + if (mHoriz != 0) + newG += 20; + + } + } + + int foundInOpenIndex = -1; + for(int j=0; j=0; i--) + { + if (fNode.PX == mClose[i].X && fNode.PY == mClose[i].Y || i == mClose.Count - 1) + { + #if DEBUGON + if (mDebugFoundPath && PathFinderDebug != null) + PathFinderDebug(fNode.X, fNode.Y, mClose[i].X, mClose[i].Y, PathFinderNodeType.Path, mClose[i].F, mClose[i].G); + #endif + fNode = mClose[i]; + } + else + mClose.RemoveAt(i); + } + mStopped = true; + return mClose; + } + mStopped = true; + return null; + } + #endregion + + #region Inner Classes + [Author("Franco, Gustavo")] + internal class ComparePFNode : IComparer + { + #region IComparer Members + public int Compare(PathFinderNode x, PathFinderNode y) + { + if (x.F > y.F) + return 1; + else if (x.F < y.F) + return -1; + return 0; + } + #endregion + } + #endregion + } +} diff --git a/AStar/PathFinderFast.cs b/AStar/PathFinderFast.cs new file mode 100755 index 0000000..1e84bb5 --- /dev/null +++ b/AStar/PathFinderFast.cs @@ -0,0 +1,460 @@ +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +// PURPOSE. IT CAN BE DISTRIBUTED FREE OF CHARGE AS LONG AS THIS HEADER +// REMAINS UNCHANGED. +// +// Email: gustavo_franco@hotmail.com +// +// Copyright (C) 2006 Franco, Gustavo +// +#define DEBUGON + +using System; +using System.Text; +using System.Drawing; +using System.Threading; +using System.Collections; + +using System.Drawing.Drawing2D; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using AStar; + +namespace AStar +{ + [Author("Franco, Gustavo")] + public class PathFinderFast : IPathFinder + { + #region Structs + [Author("Franco, Gustavo")] + [StructLayout(LayoutKind.Sequential, Pack=1)] + internal struct PathFinderNodeFast + { + #region Variables Declaration + public int F; // f = gone + heuristic + public int G; + public ushort PX; // Parent + public ushort PY; + public byte Status; + #endregion + } + #endregion + + #region Win32APIs + [System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint="RtlZeroMemory")] + public unsafe static extern bool ZeroMemory(byte* destination, int length); + #endregion + + #region Events + public event PathFinderDebugHandler PathFinderDebug; + #endregion + + #region Variables Declaration + // Heap variables are initializated to default, but I like to do it anyway + private byte[,] mGrid = null; + private PriorityQueueB mOpen = null; + private List mClose = new List(); + private bool mStop = false; + private bool mStopped = true; + private int mHoriz = 0; + private HeuristicFormula mFormula = HeuristicFormula.Manhattan; + private bool mDiagonals = true; + private int mHEstimate = 2; + private bool mPunishChangeDirection = false; + private bool mTieBreaker = false; + private bool mHeavyDiagonals = false; + private int mSearchLimit = 2000; + private double mCompletedTime = 0; + private bool mDebugProgress = false; + private bool mDebugFoundPath = false; + private PathFinderNodeFast[] mCalcGrid = null; + private byte mOpenNodeValue = 1; + private byte mCloseNodeValue = 2; + + //Promoted local variables to member variables to avoid recreation between calls + private int mH = 0; + private int mLocation = 0; + private int mNewLocation = 0; + private ushort mLocationX = 0; + private ushort mLocationY = 0; + private ushort mNewLocationX = 0; + private ushort mNewLocationY = 0; + private int mCloseNodeCounter = 0; + private ushort mGridX = 0; + private ushort mGridY = 0; + private ushort mGridXMinus1 = 0; + private ushort mGridYLog2 = 0; + private bool mFound = false; + private sbyte[,] mDirection = new sbyte[8,2]{{0,-1} , {1,0}, {0,1}, {-1,0}, {1,-1}, {1,1}, {-1,1}, {-1,-1}}; + private int mEndLocation = 0; + private int mNewG = 0; + #endregion + + #region Constructors + public PathFinderFast(byte[,] grid) + { + if (grid == null) + throw new Exception("Grid cannot be null"); + + mGrid = grid; + mGridX = (ushort) (mGrid.GetUpperBound(0) + 1); + mGridY = (ushort) (mGrid.GetUpperBound(1) + 1); + mGridXMinus1 = (ushort) (mGridX - 1); + mGridYLog2 = (ushort) Math.Log(mGridY, 2); + + // This should be done at the constructor, for now we leave it here. + if (Math.Log(mGridX, 2) != (int) Math.Log(mGridX, 2) || + Math.Log(mGridY, 2) != (int) Math.Log(mGridY, 2)) + throw new Exception("Invalid Grid, size in X and Y must be power of 2"); + + if (mCalcGrid == null || mCalcGrid.Length != (mGridX * mGridY)) + mCalcGrid = new PathFinderNodeFast[mGridX * mGridY]; + + mOpen = new PriorityQueueB(new ComparePFNodeMatrix(mCalcGrid)); + } + #endregion + + #region Properties + public bool Stopped + { + get { return mStopped; } + } + + public HeuristicFormula Formula + { + get { return mFormula; } + set { mFormula = value; } + } + + public bool Diagonals + { + get { return mDiagonals; } + set + { + mDiagonals = value; + if (mDiagonals) + mDirection = new sbyte[8,2]{{0,-1} , {1,0}, {0,1}, {-1,0}, {1,-1}, {1,1}, {-1,1}, {-1,-1}}; + else + mDirection = new sbyte[4,2]{{0,-1} , {1,0}, {0,1}, {-1,0}}; + } + } + + public bool HeavyDiagonals + { + get { return mHeavyDiagonals; } + set { mHeavyDiagonals = value; } + } + + public int HeuristicEstimate + { + get { return mHEstimate; } + set { mHEstimate = value; } + } + + public bool PunishChangeDirection + { + get { return mPunishChangeDirection; } + set { mPunishChangeDirection = value; } + } + + public bool TieBreaker + { + get { return mTieBreaker; } + set { mTieBreaker = value; } + } + + public int SearchLimit + { + get { return mSearchLimit; } + set { mSearchLimit = value; } + } + + public double CompletedTime + { + get { return mCompletedTime; } + set { mCompletedTime = value; } + } + + public bool DebugProgress + { + get { return mDebugProgress; } + set { mDebugProgress = value; } + } + + public bool DebugFoundPath + { + get { return mDebugFoundPath; } + set { mDebugFoundPath = value; } + } + #endregion + + #region Methods + public void FindPathStop() + { + mStop = true; + } + + public List FindPath(Point start, Point end) + { + lock(this) + { + HighResolutionTime.Start(); + + // Is faster if we don't clear the matrix, just assign different values for open and close and ignore the rest + // I could have user Array.Clear() but using unsafe code is faster, no much but it is. + //fixed (PathFinderNodeFast* pGrid = tmpGrid) + // ZeroMemory((byte*) pGrid, sizeof(PathFinderNodeFast) * 1000000); + + mFound = false; + mStop = false; + mStopped = false; + mCloseNodeCounter = 0; + mOpenNodeValue += 2; + mCloseNodeValue += 2; + mOpen.Clear(); + mClose.Clear(); + + #if DEBUGON + if (mDebugProgress && PathFinderDebug != null) + PathFinderDebug(0, 0, start.X, start.Y, PathFinderNodeType.Start, -1, -1); + if (mDebugProgress && PathFinderDebug != null) + PathFinderDebug(0, 0, end.X, end.Y, PathFinderNodeType.End, -1, -1); + #endif + + mLocation = (start.Y << mGridYLog2) + start.X; + mEndLocation = (end.Y << mGridYLog2) + end.X; + mCalcGrid[mLocation].G = 0; + mCalcGrid[mLocation].F = mHEstimate; + mCalcGrid[mLocation].PX = (ushort) start.X; + mCalcGrid[mLocation].PY = (ushort) start.Y; + mCalcGrid[mLocation].Status = mOpenNodeValue; + + mOpen.Push(mLocation); + while(mOpen.Count > 0 && !mStop) + { + mLocation = mOpen.Pop(); + + //Is it in closed list? means this node was already processed + if (mCalcGrid[mLocation].Status == mCloseNodeValue) + continue; + + mLocationX = (ushort) (mLocation & mGridXMinus1); + mLocationY = (ushort) (mLocation >> mGridYLog2); + + #if DEBUGON + if (mDebugProgress && PathFinderDebug != null) + PathFinderDebug(0, 0, mLocation & mGridXMinus1, mLocation >> mGridYLog2, PathFinderNodeType.Current, -1, -1); + #endif + + if (mLocation == mEndLocation) + { + mCalcGrid[mLocation].Status = mCloseNodeValue; + mFound = true; + break; + } + + if (mCloseNodeCounter > mSearchLimit) + { + mStopped = true; + mCompletedTime = HighResolutionTime.GetTime(); + return null; + } + + if (mPunishChangeDirection) + mHoriz = (mLocationX - mCalcGrid[mLocation].PX); + + //Lets calculate each successors + for (int i=0; i<(mDiagonals ? 8 : 4); i++) + { + mNewLocationX = (ushort) (mLocationX + mDirection[i,0]); + mNewLocationY = (ushort) (mLocationY + mDirection[i,1]); + mNewLocation = (mNewLocationY << mGridYLog2) + mNewLocationX; + + if (mNewLocationX >= mGridX || mNewLocationY >= mGridY) + continue; + + // Unbreakeable? + if (mGrid[mNewLocationX, mNewLocationY] == 0) + continue; + + if (mHeavyDiagonals && i>3) + mNewG = mCalcGrid[mLocation].G + (int) (mGrid[mNewLocationX, mNewLocationY] * 2.41); + else + mNewG = mCalcGrid[mLocation].G + mGrid[mNewLocationX, mNewLocationY]; + + if (mPunishChangeDirection) + { + if ((mNewLocationX - mLocationX) != 0) + { + if (mHoriz == 0) + mNewG += Math.Abs(mNewLocationX - end.X) + Math.Abs(mNewLocationY - end.Y); + } + if ((mNewLocationY - mLocationY) != 0) + { + if (mHoriz != 0) + mNewG += Math.Abs(mNewLocationX - end.X) + Math.Abs(mNewLocationY - end.Y); + } + } + + //Is it open or closed? + if (mCalcGrid[mNewLocation].Status == mOpenNodeValue || mCalcGrid[mNewLocation].Status == mCloseNodeValue) + { + // The current node has less code than the previous? then skip this node + if (mCalcGrid[mNewLocation].G <= mNewG) + continue; + } + + mCalcGrid[mNewLocation].PX = mLocationX; + mCalcGrid[mNewLocation].PY = mLocationY; + mCalcGrid[mNewLocation].G = mNewG; + + switch(mFormula) + { + default: + case HeuristicFormula.Manhattan: + mH = mHEstimate * (Math.Abs(mNewLocationX - end.X) + Math.Abs(mNewLocationY - end.Y)); + break; + case HeuristicFormula.MaxDXDY: + mH = mHEstimate * (Math.Max(Math.Abs(mNewLocationX - end.X), Math.Abs(mNewLocationY - end.Y))); + break; + case HeuristicFormula.DiagonalShortCut: + int h_diagonal = Math.Min(Math.Abs(mNewLocationX - end.X), Math.Abs(mNewLocationY - end.Y)); + int h_straight = (Math.Abs(mNewLocationX - end.X) + Math.Abs(mNewLocationY - end.Y)); + mH = (mHEstimate * 2) * h_diagonal + mHEstimate * (h_straight - 2 * h_diagonal); + break; + case HeuristicFormula.Euclidean: + mH = (int) (mHEstimate * Math.Sqrt(Math.Pow((mNewLocationY - end.X) , 2) + Math.Pow((mNewLocationY - end.Y), 2))); + break; + case HeuristicFormula.EuclideanNoSQR: + mH = (int) (mHEstimate * (Math.Pow((mNewLocationX - end.X) , 2) + Math.Pow((mNewLocationY - end.Y), 2))); + break; + case HeuristicFormula.Custom1: + Point dxy = new Point(Math.Abs(end.X - mNewLocationX), Math.Abs(end.Y - mNewLocationY)); + int Orthogonal = Math.Abs(dxy.X - dxy.Y); + int Diagonal = Math.Abs(((dxy.X + dxy.Y) - Orthogonal) / 2); + mH = mHEstimate * (Diagonal + Orthogonal + dxy.X + dxy.Y); + break; + } + if (mTieBreaker) + { + int dx1 = mLocationX - end.X; + int dy1 = mLocationY - end.Y; + int dx2 = start.X - end.X; + int dy2 = start.Y - end.Y; + int cross = Math.Abs(dx1 * dy2 - dx2 * dy1); + mH = (int) (mH + cross * 0.001); + } + mCalcGrid[mNewLocation].F = mNewG + mH; + + #if DEBUGON + if (mDebugProgress && PathFinderDebug != null) + PathFinderDebug(mLocationX, mLocationY, mNewLocationX, mNewLocationY, PathFinderNodeType.Open, mCalcGrid[mNewLocation].F, mCalcGrid[mNewLocation].G); + #endif + + //It is faster if we leave the open node in the priority queue + //When it is removed, it will be already closed, it will be ignored automatically + //if (tmpGrid[newLocation].Status == 1) + //{ + // //int removeX = newLocation & gridXMinus1; + // //int removeY = newLocation >> gridYLog2; + // mOpen.RemoveLocation(newLocation); + //} + + //if (tmpGrid[newLocation].Status != 1) + //{ + mOpen.Push(mNewLocation); + //} + mCalcGrid[mNewLocation].Status = mOpenNodeValue; + } + + mCloseNodeCounter++; + mCalcGrid[mLocation].Status = mCloseNodeValue; + + #if DEBUGON + if (mDebugProgress && PathFinderDebug != null) + PathFinderDebug(0, 0, mLocationX, mLocationY, PathFinderNodeType.Close, mCalcGrid[mLocation].F, mCalcGrid[mLocation].G); + #endif + } + + mCompletedTime = HighResolutionTime.GetTime(); + if (mFound) + { + mClose.Clear(); + int posX = end.X; + int posY = end.Y; + + PathFinderNodeFast fNodeTmp = mCalcGrid[(end.Y << mGridYLog2) + end.X]; + PathFinderNode fNode; + fNode.F = fNodeTmp.F; + fNode.G = fNodeTmp.G; + fNode.H = 0; + fNode.PX = fNodeTmp.PX; + fNode.PY = fNodeTmp.PY; + fNode.X = end.X; + fNode.Y = end.Y; + + while(fNode.X != fNode.PX || fNode.Y != fNode.PY) + { + mClose.Add(fNode); + #if DEBUGON + if (mDebugFoundPath && PathFinderDebug != null) + PathFinderDebug(fNode.PX, fNode.PY, fNode.X, fNode.Y, PathFinderNodeType.Path, fNode.F, fNode.G); + #endif + posX = fNode.PX; + posY = fNode.PY; + fNodeTmp = mCalcGrid[(posY << mGridYLog2) + posX]; + fNode.F = fNodeTmp.F; + fNode.G = fNodeTmp.G; + fNode.H = 0; + fNode.PX = fNodeTmp.PX; + fNode.PY = fNodeTmp.PY; + fNode.X = posX; + fNode.Y = posY; + } + + mClose.Add(fNode); + #if DEBUGON + if (mDebugFoundPath && PathFinderDebug != null) + PathFinderDebug(fNode.PX, fNode.PY, fNode.X, fNode.Y, PathFinderNodeType.Path, fNode.F, fNode.G); + #endif + + mStopped = true; + return mClose; + } + mStopped = true; + return null; + } + } + #endregion + + #region Inner Classes + [Author("Franco, Gustavo")] + internal class ComparePFNodeMatrix : IComparer + { + #region Variables Declaration + PathFinderNodeFast[] mMatrix; + #endregion + + #region Constructors + public ComparePFNodeMatrix(PathFinderNodeFast[] matrix) + { + mMatrix = matrix; + } + #endregion + + #region IComparer Members + public int Compare(int a, int b) + { + if (mMatrix[a].F > mMatrix[b].F) + return 1; + else if (mMatrix[a].F < mMatrix[b].F) + return -1; + return 0; + } + #endregion + } + #endregion + } +} diff --git a/AStar/PriorityQueueB.cs b/AStar/PriorityQueueB.cs new file mode 100755 index 0000000..0c7fcf8 --- /dev/null +++ b/AStar/PriorityQueueB.cs @@ -0,0 +1,213 @@ +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +// PURPOSE. IT CAN BE DISTRIBUTED FREE OF CHARGE AS LONG AS THIS HEADER +// REMAINS UNCHANGED. +// +// Email: gustavo_franco@hotmail.com +// +// Copyright (C) 2006 Franco, Gustavo +// +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace AStar +{ + #region Interfaces + [Author("Franco, Gustavo")] + public interface IPriorityQueue + { + #region Methods + int Push(T item); + T Pop(); + T Peek(); + void Update(int i); + #endregion + } + #endregion + + [Author("Franco, Gustavo")] + public class PriorityQueueB : IPriorityQueue + { + #region Variables Declaration + protected List InnerList = new List(); + protected IComparer mComparer; + #endregion + + #region Contructors + public PriorityQueueB() + { + mComparer = Comparer.Default; + } + + public PriorityQueueB(IComparer comparer) + { + mComparer = comparer; + } + + public PriorityQueueB(IComparer comparer, int capacity) + { + mComparer = comparer; + InnerList.Capacity = capacity; + } + #endregion + + #region Methods + protected void SwitchElements(int i, int j) + { + T h = InnerList[i]; + InnerList[i] = InnerList[j]; + InnerList[j] = h; + } + + protected virtual int OnCompare(int i, int j) + { + return mComparer.Compare(InnerList[i],InnerList[j]); + } + + /// + /// Push an object onto the PQ + /// + /// The new object + /// The index in the list where the object is _now_. This will change when objects are taken from or put onto the PQ. + public int Push(T item) + { + int p = InnerList.Count,p2; + InnerList.Add(item); // E[p] = O + do + { + if(p==0) + break; + p2 = (p-1)/2; + if(OnCompare(p,p2)<0) + { + SwitchElements(p,p2); + p = p2; + } + else + break; + }while(true); + return p; + } + + /// + /// Get the smallest object and remove it. + /// + /// The smallest object + public T Pop() + { + T result = InnerList[0]; + int p = 0,p1,p2,pn; + InnerList[0] = InnerList[InnerList.Count-1]; + InnerList.RemoveAt(InnerList.Count-1); + do + { + pn = p; + p1 = 2*p+1; + p2 = 2*p+2; + if(InnerList.Count>p1 && OnCompare(p,p1)>0) // links kleiner + p = p1; + if(InnerList.Count>p2 && OnCompare(p,p2)>0) // rechts noch kleiner + p = p2; + + if(p==pn) + break; + SwitchElements(p,pn); + }while(true); + + return result; + } + + /// + /// Notify the PQ that the object at position i has changed + /// and the PQ needs to restore order. + /// Since you dont have access to any indexes (except by using the + /// explicit IList.this) you should not call this function without knowing exactly + /// what you do. + /// + /// The index of the changed object. + public void Update(int i) + { + int p = i,pn; + int p1,p2; + do // aufsteigen + { + if(p==0) + break; + p2 = (p-1)/2; + if(OnCompare(p,p2)<0) + { + SwitchElements(p,p2); + p = p2; + } + else + break; + }while(true); + if(pp1 && OnCompare(p,p1)>0) // links kleiner + p = p1; + if(InnerList.Count>p2 && OnCompare(p,p2)>0) // rechts noch kleiner + p = p2; + + if(p==pn) + break; + SwitchElements(p,pn); + }while(true); + } + + /// + /// Get the smallest object without removing it. + /// + /// The smallest object + public T Peek() + { + if(InnerList.Count>0) + return InnerList[0]; + return default(T); + } + + public void Clear() + { + InnerList.Clear(); + } + + public int Count + { + get{ return InnerList.Count; } + } + + public void RemoveLocation(T item) + { + int index = -1; + for(int i=0; i().Position; + this.FindPath(this.Start, value); + } + } + + private Point goal; + private List path; + + public PathFinder(Entity parent) + : base(parent) + { + + } + + public override void Update(GameTime gameTime) + { + if (path != null && path.Count != 0) + { + var nextNode = path.Last(); + var nodePos = new Point(nextNode.X, nextNode.Y); + Parent.gridTransform.Position = nodePos; + if (Parent.pixelTransform.Position == Parent.gridTransform.ToWorld()) + path.Remove(nextNode); + } + + base.Update(gameTime); + } + + public void FindPath(Point start, Point goal) + { + var _start = new System.Drawing.Point(start.X, start.Y); + var _goal = new System.Drawing.Point(goal.X, goal.Y); + path = Core.PathFinder.FindPath(_start, _goal); + if (path == null) + Console.WriteLine("Path not found!"); + } + } +} diff --git a/DepthsBelow/DepthsBelow/Core.cs b/DepthsBelow/DepthsBelow/Core.cs index 15cce3a..f4fddb8 100644 --- a/DepthsBelow/DepthsBelow/Core.cs +++ b/DepthsBelow/DepthsBelow/Core.cs @@ -19,6 +19,8 @@ namespace DepthsBelow GraphicsDeviceManager graphics; SpriteBatch spriteBatch; + public static AStar.PathFinderFast PathFinder; + public Camera camera; MouseInput mouseInput; public Soldier soldier; @@ -33,7 +35,7 @@ namespace DepthsBelow graphics.PreferredBackBufferHeight = 720; graphics.IsFullScreen = false; - //graphics.SynchronizeWithVerticalRetrace = false; + graphics.SynchronizeWithVerticalRetrace = false; this.IsFixedTimeStep = false; graphics.ApplyChanges(); @@ -63,6 +65,16 @@ namespace DepthsBelow spriteBatch = new SpriteBatch(GraphicsDevice); map = Content.Load("maps/Cave.Level1"); + PathFinder = new AStar.PathFinderFast(map.GetCollisionMap()); + PathFinder.Formula = AStar.HeuristicFormula.Manhattan; + PathFinder.Diagonals = false; + PathFinder.HeavyDiagonals = false; + PathFinder.HeuristicEstimate = 2; + PathFinder.PunishChangeDirection = true; + PathFinder.TieBreaker = false; + PathFinder.SearchLimit = 50000; + PathFinder.DebugProgress = false; + PathFinder.DebugFoundPath = false; // TODO: use this.Content to load your game content here Soldier.LoadContent(this); diff --git a/DepthsBelow/DepthsBelow/DepthsBelow.csproj b/DepthsBelow/DepthsBelow/DepthsBelow.csproj index 6ba8661..c935820 100644 --- a/DepthsBelow/DepthsBelow/DepthsBelow.csproj +++ b/DepthsBelow/DepthsBelow/DepthsBelow.csproj @@ -106,6 +106,7 @@ False + False @@ -121,6 +122,7 @@ + @@ -140,9 +142,14 @@ + + {CD3F949D-54AA-4D38-99DB-92905A375D84} + AStar + - DepthsBelowContent + DepthsBelowContent %28Content%29 Content + {433A77A2-DE52-4875-A4EF-232CF59C2DD3} diff --git a/DepthsBelow/DepthsBelow/Map.cs b/DepthsBelow/DepthsBelow/Map.cs index 0ec34f0..3a99368 100755 --- a/DepthsBelow/DepthsBelow/Map.cs +++ b/DepthsBelow/DepthsBelow/Map.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; @@ -6,6 +7,7 @@ namespace DepthsBelow { public class Tile { + public int LocalId; public Texture2D Texture; public Rectangle SourceRectangle; public SpriteEffects SpriteEffects; @@ -53,5 +55,34 @@ namespace DepthsBelow } } } + + public byte[,] GetCollisionMap() + { + byte[,] collisionMap = new byte[1024, 1024]; + foreach (var layer in Layers) + { + if (layer.Name == "Collision") + { + for (int y = 0; y < layer.Height; y++) + { + for (int x = 0; x < layer.Width; x++) + { + Tile tile = layer.Tiles[y*layer.Width + x]; + if (tile == null || tile.LocalId == 0) + collisionMap[x, y] = 1; + else + collisionMap[x, y] = 0; + } + } + + break; + } + } + + //if (collisionMap == null) + // throw new Exception("Map lacks a Collision layer!"); + + return collisionMap; + } } } diff --git a/DepthsBelow/DepthsBelow/MouseInput.cs b/DepthsBelow/DepthsBelow/MouseInput.cs index 3faf64b..6dcb770 100644 --- a/DepthsBelow/DepthsBelow/MouseInput.cs +++ b/DepthsBelow/DepthsBelow/MouseInput.cs @@ -58,7 +58,9 @@ namespace DepthsBelow if (ms.LeftButton == ButtonState.Released && selectionRectangle != Rectangle.Empty) { if (!ks.IsKeyDown(Keys.LeftControl)) + { core.soldier.Selected = false; + } if (selectionRectangle.Intersects(core.soldier.GetComponent().Rectangle)) { diff --git a/DepthsBelow/DepthsBelow/Soldier.cs b/DepthsBelow/DepthsBelow/Soldier.cs index 42e581b..bc1f7ed 100644 --- a/DepthsBelow/DepthsBelow/Soldier.cs +++ b/DepthsBelow/DepthsBelow/Soldier.cs @@ -20,12 +20,18 @@ namespace DepthsBelow LoadContent(core); pixelTransform.Origin = new Vector2(16, 16); + gridTransform.Position = new Point(7, 3); + pixelTransform.Position = gridTransform.ToWorld(); var rc = new SpriteRenderer(this) {Texture = Texture, Color = Color.White}; AddComponent(rc); var cc = new Collision(this, 32, 32); AddComponent(cc); + + var pfc = new PathFinder(this); + pfc.Goal = new Point(8, 39); + AddComponent(pfc); } public bool Selected @@ -70,14 +76,14 @@ namespace DepthsBelow } lastKeyboardState = ks; - int speed = 2; + int speed = 1; if (pixelTransform.X < gridTransform.ToWorld().X) pixelTransform.X += speed; - else if (pixelTransform.X > gridTransform.ToWorld().X) + if (pixelTransform.X > gridTransform.ToWorld().X) pixelTransform.X -= speed; - else if (pixelTransform.Y < gridTransform.ToWorld().Y) + if (pixelTransform.Y < gridTransform.ToWorld().Y) pixelTransform.Y += speed; - else if (pixelTransform.Y > gridTransform.ToWorld().Y) + if (pixelTransform.Y > gridTransform.ToWorld().Y) pixelTransform.Y -= speed; } } diff --git a/DepthsBelow/DepthsBelowContent/maps/Cave.Level1.tmx b/DepthsBelow/DepthsBelowContent/maps/Cave.Level1.tmx index 5f365f6..d0dae50 100755 --- a/DepthsBelow/DepthsBelowContent/maps/Cave.Level1.tmx +++ b/DepthsBelow/DepthsBelowContent/maps/Cave.Level1.tmx @@ -3,9 +3,215 @@ + + + - - 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 - + +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,52,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,54,54,54,54,54,54,54,54,54,53,53,53,55,81, +81,68,69,69,69,69,101,102,103,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,70,69,69,69,71,81, +81,84,85,85,85,129,117,118,119,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,86,85,85,85,87,81, +81,37,7,8,21,21,133,134,135,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,7,8,7,7,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,7,8,21,21,21,21,21,21,7,8,8,7,8,21,21,21,21,21,21,21,133,134,135,87,81, +81,37,7,8,21,21,21,21,21,21,21,21,21,18,18,18,18,18,18,18,18,2,2,2,18,5,8,8,89,7,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,2,2,2,2,18,18,19,20,4,4,4,4,4,4,2,7,8,8,8,8,8,8,8,8,8,7,7,8,8,24,7,8,3,4,4,20,4,18,18,133,134,135,87,81, +81,37,7,8,19,20,20,1,1,1,1,1,21,21,1,18,19,20,20,20,20,18,18,18,5,5,7,8,89,89,5,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,18,18,18,18,18,18,19,20,20,20,20,20,20,3,4,7,8,24,24,24,24,24,24,24,24,8,8,8,24,19,7,7,8,4,20,3,2,2,18,133,134,135,49,81, +81,37,7,8,7,8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,7,8,8,89,89,5,4,20,4,17,17,17,17,17,17,17,1,1,1,1,1,17,17,17,1,2,3,5,5,5,5,5,6,2,3,4,7,8,8,2,3,2,18,2,2,2,23,24,2,2,2,3,18,19,23,24,24,24,24,20,18,23,7,8,4,4,4,2,18,19,2,3,2,39,81, +81,37,7,8,23,24,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,17,17,5,7,8,24,89,89,21,3,4,20,4,4,4,4,5,6,22,17,17,17,17,17,17,18,1,2,3,4,5,5,5,21,5,5,2,7,7,8,8,24,2,2,18,19,18,18,18,18,18,2,2,2,2,2,18,19,20,3,4,20,20,20,19,7,8,4,2,2,2,18,19,2,2,18,39,81, +81,37,7,8,24,24,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,7,8,8,89,89,89,7,7,7,7,7,7,7,7,7,6,6,6,1,2,3,4,5,6,5,7,7,7,21,21,5,7,7,7,7,7,8,7,7,7,7,8,5,20,2,3,4,2,2,18,18,18,18,2,18,19,20,3,4,20,20,18,19,7,7,8,18,18,18,18,19,2,18,19,39,81, +81,37,23,24,23,24,1,1,1,7,7,7,7,7,7,8,7,7,7,8,1,1,1,5,7,8,24,89,89,89,23,7,23,23,23,23,23,23,7,4,22,22,4,5,6,6,6,6,6,23,23,23,24,8,21,23,23,23,7,7,7,23,23,23,23,7,7,8,4,2,2,2,18,19,20,20,20,18,19,20,3,4,20,20,4,2,19,23,7,8,2,3,4,4,2,2,18,19,39,81, +81,37,7,7,7,7,7,7,7,23,23,7,7,7,7,7,23,23,7,8,1,1,1,21,7,8,8,89,89,89,89,7,7,7,7,7,7,7,7,20,4,22,6,6,6,22,22,22,22,23,23,23,7,24,24,24,24,24,23,23,23,23,23,23,24,23,7,7,8,4,18,18,19,20,4,20,3,2,3,4,4,20,4,20,2,2,3,19,7,8,2,3,4,4,2,18,19,2,39,81, +81,37,23,23,23,23,23,23,23,23,24,23,23,23,23,23,23,7,7,8,1,1,1,21,7,7,8,8,89,89,89,23,7,23,23,23,23,23,23,4,20,4,22,22,22,18,19,20,21,23,7,7,23,23,7,7,8,8,8,8,8,8,8,8,8,8,23,23,7,8,20,20,3,4,20,2,2,18,19,20,20,19,20,4,2,18,19,19,7,7,8,4,20,20,2,3,3,4,39,81, +81,37,8,8,3,1,1,1,1,1,1,1,1,1,1,1,1,23,23,24,1,1,1,19,7,8,8,24,89,89,89,23,23,23,23,23,23,23,23,20,4,20,4,6,18,19,5,5,5,23,23,7,6,22,23,23,24,24,8,24,24,24,24,24,24,8,8,8,23,24,8,8,8,9,2,18,18,19,20,4,19,20,4,4,2,3,4,19,23,7,7,8,20,2,3,3,3,4,39,81, +81,37,24,8,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,19,7,8,8,24,89,7,89,89,89,19,3,3,3,23,7,7,20,4,20,4,4,6,5,5,5,7,7,23,22,2,3,17,18,19,8,8,22,6,22,2,2,24,24,24,24,24,24,24,24,7,8,19,18,19,20,20,19,20,4,2,2,3,4,19,20,23,7,8,20,3,3,4,4,20,39,81, +81,37,8,8,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,7,7,8,89,89,89,7,19,19,19,19,19,19,19,7,7,7,7,7,7,20,4,4,5,22,23,23,23,2,1,1,17,18,19,8,8,22,22,2,3,2,2,18,18,19,20,19,20,20,7,8,8,8,2,3,18,19,20,4,2,3,4,20,19,20,3,7,8,3,19,3,4,20,20,39,81, +81,37,8,8,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,23,7,8,8,89,7,23,3,3,19,20,20,19,19,23,23,23,23,23,7,19,20,20,5,6,7,89,89,133,134,135,18,19,20,8,24,22,22,2,2,18,18,19,20,18,19,20,20,2,23,24,24,24,8,8,3,4,20,2,18,19,20,3,19,20,19,7,7,8,3,4,20,18,19,39,81, +81,37,8,8,3,1,1,1,7,8,8,8,8,8,1,1,1,1,1,1,1,1,1,4,23,7,7,8,89,23,23,19,19,19,19,20,20,2,3,4,5,6,7,7,19,5,5,5,5,23,89,89,133,134,135,19,20,21,8,24,6,20,2,2,2,18,19,20,19,20,20,2,18,2,3,23,24,24,24,3,4,2,18,19,20,3,4,19,20,4,23,7,8,4,20,3,4,2,39,81, +81,37,8,8,3,1,1,1,7,8,24,24,24,24,8,1,1,1,1,1,1,1,1,4,20,23,7,8,89,23,18,19,20,20,2,2,2,3,4,3,4,4,7,7,17,5,5,5,21,89,89,89,133,134,135,2,3,4,8,24,2,3,4,18,18,19,20,3,4,20,2,2,2,3,4,20,2,3,2,3,4,2,3,4,2,3,3,19,20,4,20,23,24,20,2,3,4,2,39,81, +81,37,24,8,3,1,4,4,5,7,7,8,8,24,24,8,20,20,19,20,4,3,19,20,2,23,7,7,8,23,18,18,19,20,4,18,18,19,20,19,20,20,7,7,4,4,5,5,2,89,89,89,6,6,5,2,3,4,24,24,2,3,2,18,8,8,8,3,4,18,2,3,18,19,20,20,3,2,3,4,2,3,4,3,3,19,19,19,20,4,20,3,4,2,3,4,20,2,39,81, +81,37,21,22,3,19,20,4,4,5,7,8,24,8,24,24,8,20,19,3,4,4,19,20,4,19,23,7,8,23,20,18,19,20,20,4,2,2,2,2,2,2,7,7,4,20,5,5,18,89,89,89,22,6,2,3,4,20,6,2,2,2,18,19,24,24,8,19,20,3,18,19,18,19,20,18,19,2,3,4,2,3,3,19,19,20,4,3,4,20,20,4,20,2,3,4,2,2,39,81, +81,37,21,22,19,4,4,5,4,4,5,8,24,24,8,24,24,8,20,19,20,20,4,19,20,7,8,8,8,23,20,4,18,19,20,7,7,18,18,18,2,3,7,23,20,18,19,20,17,89,89,89,7,5,2,3,4,20,6,2,18,18,19,8,8,8,24,20,4,2,3,2,2,3,4,18,2,3,4,2,3,3,19,19,20,4,20,19,20,20,4,20,19,2,3,22,2,2,39,81, +81,37,2,3,2,20,20,21,20,4,4,4,5,24,24,8,8,24,8,19,19,3,4,19,20,7,8,24,24,23,4,20,4,18,18,23,7,18,18,18,2,3,7,23,5,6,18,19,17,89,89,7,7,7,7,7,20,20,2,18,18,19,8,24,24,24,24,7,7,7,19,2,3,4,20,2,3,4,20,3,19,19,20,3,4,4,3,19,20,20,4,20,3,2,3,7,7,7,39,81, +81,37,2,3,18,20,21,21,5,5,5,5,5,7,8,24,24,8,24,8,8,19,20,4,7,8,8,89,89,23,20,4,20,4,18,7,7,7,20,2,3,4,23,23,21,22,6,18,19,89,89,23,23,23,23,7,7,7,7,7,7,7,24,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,53,54,53,53,54,54,54,54,7,7,7,7,23,7,7,39,81, +81,37,2,3,18,19,20,21,21,21,21,21,21,23,24,23,24,24,8,24,24,8,8,8,8,8,24,89,89,23,20,20,4,4,20,23,7,7,7,4,4,20,4,5,6,4,1,1,1,89,89,1,17,2,3,23,23,7,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,53,53,53,53,53,53,53,54,23,7,7,7,7,7,7,39,81, +81,37,2,2,3,20,89,7,7,7,7,89,89,89,89,89,23,24,24,23,24,24,24,24,24,24,89,89,89,23,18,19,20,20,4,19,23,7,7,20,4,4,1,1,1,1,17,17,17,89,89,17,2,3,4,20,20,23,23,23,23,20,6,2,3,2,18,19,20,2,18,19,20,18,2,3,2,2,3,4,7,7,20,20,4,20,19,20,20,3,4,7,8,23,23,23,23,23,39,81, +81,37,2,3,3,2,89,7,23,23,7,7,7,7,7,7,89,7,89,89,89,89,89,89,89,89,89,89,7,23,4,4,4,4,20,4,4,7,23,20,20,20,4,4,17,17,18,2,3,89,89,2,3,4,4,19,20,2,18,19,20,21,2,3,4,18,19,20,6,18,19,20,20,2,3,4,2,18,19,20,7,8,3,4,4,4,19,20,3,4,20,7,8,4,3,2,2,3,39,81, +81,37,2,3,3,3,89,7,21,21,5,5,5,5,2,2,2,5,4,3,4,4,89,89,89,7,7,7,7,23,20,20,20,20,4,20,4,23,23,18,19,20,20,20,4,2,3,4,4,89,89,2,3,4,20,5,6,2,18,19,20,6,2,3,2,3,4,20,2,18,19,20,2,3,4,2,18,19,20,20,7,7,8,20,4,4,19,20,3,4,3,23,24,4,4,2,2,3,39,81, +81,37,2,3,3,4,89,7,2,21,21,21,21,21,18,18,18,5,3,3,3,3,4,7,7,23,23,7,7,23,4,19,19,20,20,20,20,20,23,7,7,18,19,20,20,4,4,20,2,89,89,2,3,4,4,5,2,2,3,4,20,2,3,2,18,19,20,6,18,19,20,2,2,3,2,2,3,4,20,4,23,7,7,8,2,3,4,18,19,20,3,2,3,4,4,2,3,4,39,81, +81,37,2,3,19,4,89,7,2,3,4,5,6,6,17,3,3,5,3,19,19,3,3,7,7,7,7,7,7,23,20,4,20,4,4,18,19,20,2,23,7,7,7,19,20,4,2,3,2,89,89,4,4,20,5,6,2,2,3,4,21,2,7,8,8,20,5,2,2,3,4,2,3,2,2,3,4,20,3,4,7,23,7,8,3,4,20,2,3,4,2,3,4,20,4,2,3,4,39,81, +81,37,2,3,3,4,7,7,2,3,4,7,7,7,2,19,19,5,19,19,19,19,19,23,23,23,23,23,7,23,20,20,4,20,20,4,19,20,2,2,7,7,23,19,20,3,4,3,2,89,89,20,4,6,21,2,18,18,7,8,8,8,8,8,24,8,8,2,3,4,20,2,3,2,18,19,20,20,4,20,7,7,7,8,3,4,20,3,4,20,2,3,4,19,2,2,3,4,39,81, +81,37,2,2,3,4,7,7,3,4,5,23,23,7,2,2,3,21,3,4,3,3,3,3,4,3,19,19,7,23,19,20,20,19,20,20,3,3,4,18,21,7,7,19,20,4,4,2,3,89,89,20,4,22,2,2,7,8,8,8,7,8,8,8,24,24,24,8,3,4,2,3,2,18,19,20,4,19,20,20,23,7,7,7,8,4,2,3,4,3,2,3,4,4,2,2,3,4,39,81, +81,37,18,2,3,5,21,2,3,4,5,23,23,23,2,2,3,7,7,20,19,19,19,19,3,3,3,3,23,23,19,19,20,19,19,7,7,19,3,4,4,7,7,4,4,4,3,4,4,89,89,4,4,4,4,2,7,8,24,7,8,8,24,24,2,23,24,24,8,3,4,19,2,3,4,20,20,20,20,4,20,23,23,7,8,4,2,3,4,3,2,3,4,4,18,2,3,4,39,81, +81,37,2,2,3,5,1,2,3,2,2,2,18,18,2,18,19,7,7,18,19,20,19,20,19,19,19,19,19,19,3,19,20,19,19,23,7,4,4,20,20,7,7,7,20,20,19,20,20,7,89,20,20,20,20,18,23,24,7,8,8,24,2,18,18,2,23,24,24,8,8,8,2,3,4,20,20,20,19,20,4,2,2,7,7,8,2,3,4,3,2,3,4,20,18,2,3,4,39,81, +81,37,2,2,3,5,1,2,2,18,18,18,19,2,3,4,20,7,7,19,20,18,2,3,2,19,20,20,19,20,19,19,19,19,19,23,7,20,20,4,4,23,23,7,7,20,20,20,20,89,89,4,1,2,2,2,2,2,7,8,24,18,18,19,20,18,2,23,24,24,24,24,8,19,20,20,20,19,20,19,20,2,2,23,7,7,8,3,4,3,2,3,4,4,18,2,3,4,39,81, +81,37,1,2,3,4,2,2,18,19,20,2,3,4,19,20,19,7,7,2,3,4,18,2,3,19,3,3,3,19,20,20,20,20,20,7,7,19,20,20,4,7,7,7,7,7,4,20,20,89,89,4,17,2,3,2,2,18,7,8,20,3,4,22,1,2,3,4,20,2,23,24,24,20,18,19,20,20,18,19,20,2,2,3,23,7,7,7,8,2,3,4,20,20,2,3,4,4,39,81, +81,37,7,7,7,89,89,7,7,7,7,7,7,7,7,7,7,7,7,2,3,2,2,3,19,20,19,19,19,19,3,3,3,3,3,23,23,20,20,20,20,23,23,23,23,7,7,7,7,89,89,2,2,2,2,18,18,19,7,8,3,4,20,22,2,3,4,4,2,18,18,23,24,8,19,20,20,2,3,4,20,2,3,4,20,23,23,7,7,8,3,4,4,2,2,3,4,20,39,81, +81,37,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,89,89,89,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,23,23,23,23,89,89,5,5,5,5,5,20,22,7,8,3,4,22,22,2,3,4,20,18,18,19,23,24,24,8,20,20,2,3,4,4,4,2,3,4,2,3,23,7,7,8,4,20,2,2,3,4,4,39,81, +81,37,23,23,23,23,23,104,105,106,23,23,23,23,23,23,23,23,23,23,7,7,7,7,89,89,89,89,89,89,89,89,89,89,89,89,89,89,7,8,89,89,89,89,89,89,89,89,7,8,89,21,21,21,21,21,21,22,23,24,19,20,2,2,2,3,4,2,18,19,20,18,23,24,24,8,2,3,4,20,20,20,18,19,20,4,3,4,23,7,7,7,8,2,4,5,4,20,39,81, +81,37,7,8,3,3,4,120,121,122,2,2,2,2,2,2,18,3,4,4,4,20,19,20,18,18,19,3,19,19,19,20,19,7,7,7,7,7,7,7,7,8,7,8,7,7,8,7,7,7,8,17,18,19,20,20,21,22,2,3,2,3,4,2,2,3,4,2,3,4,20,19,20,23,24,24,8,8,20,2,2,3,4,18,2,3,4,20,2,23,23,7,7,8,4,5,4,20,39,81, +81,37,7,8,5,6,6,6,6,18,18,18,18,18,18,18,19,3,3,4,20,4,19,20,2,18,18,19,19,20,4,2,3,23,107,107,108,7,23,23,7,8,8,7,8,23,24,8,23,23,24,18,19,20,21,22,20,21,18,2,18,19,2,18,2,2,2,18,19,20,19,20,2,3,23,24,24,24,8,3,2,3,4,3,18,19,20,4,4,2,3,23,7,7,20,21,4,20,39,81, +81,37,8,8,23,24,7,22,2,2,2,3,4,17,17,2,2,19,3,3,4,20,19,20,4,4,19,20,18,2,3,2,3,4,123,107,108,23,23,23,23,24,24,8,7,8,24,24,8,7,8,22,17,18,19,20,21,22,2,18,19,2,3,4,23,7,7,7,22,22,20,2,3,4,2,18,23,24,24,8,2,3,4,3,4,18,19,20,2,3,4,20,23,7,20,21,4,20,39,81, +81,37,8,8,6,22,7,3,4,18,18,2,2,2,2,18,18,19,19,3,4,3,19,20,4,3,4,18,19,18,2,3,4,2,3,107,108,3,4,2,3,23,24,24,8,7,8,24,24,8,7,8,19,20,21,22,22,2,3,4,20,2,3,4,23,23,23,23,22,22,20,2,3,4,2,3,4,23,24,24,8,8,4,19,20,18,19,20,2,3,4,4,20,23,20,21,4,20,39,81, +81,38,8,8,22,17,7,2,2,2,2,18,18,18,18,19,20,4,2,19,3,3,4,19,20,19,20,4,4,20,2,2,3,4,19,107,108,2,2,18,19,20,23,24,24,8,7,8,24,24,7,8,19,20,21,22,2,18,19,20,18,2,3,4,23,23,24,23,22,22,20,2,3,2,3,4,20,3,23,24,24,24,8,8,20,18,19,20,3,4,20,4,2,3,20,21,3,4,39,81, +81,38,8,8,23,24,7,18,7,8,8,8,19,20,17,7,8,8,3,8,8,8,3,19,20,21,19,20,20,4,4,3,4,20,20,107,108,2,18,19,20,2,3,23,24,24,8,7,8,24,8,7,8,21,2,2,18,19,20,4,2,3,4,2,23,23,23,23,22,22,2,3,4,2,3,4,2,2,2,2,23,24,24,24,8,18,19,20,3,4,4,20,3,4,20,21,3,4,39,81, +81,38,8,8,4,1,7,17,23,2,2,23,4,6,2,23,1,2,3,23,5,5,3,19,20,5,1,1,19,20,20,4,4,19,20,107,108,18,19,20,20,2,3,4,7,8,24,8,7,8,24,8,8,8,3,4,19,20,3,4,2,3,4,18,23,23,23,23,22,22,2,3,2,3,4,20,18,7,8,8,8,20,23,24,24,8,8,8,8,8,20,2,3,4,20,21,4,4,39,81, +81,38,8,8,4,1,7,1,7,1,2,7,4,4,5,8,8,7,3,8,8,7,19,19,20,1,17,17,18,2,19,20,20,19,20,107,108,19,20,4,2,3,4,20,7,7,8,24,8,8,24,24,24,8,8,7,8,3,4,2,3,4,20,23,23,23,23,24,6,22,2,2,18,19,20,7,8,8,8,24,24,2,3,23,24,24,24,24,24,24,8,2,3,4,2,2,3,4,39,81, +81,38,8,7,89,89,23,1,23,8,8,8,20,1,2,3,4,23,3,4,2,23,4,20,17,17,18,19,2,3,4,19,20,4,2,107,108,20,4,20,2,3,4,3,8,7,8,23,24,24,8,24,8,24,7,7,8,8,4,2,3,4,23,23,23,23,23,24,22,2,3,18,19,20,7,8,8,24,24,4,4,3,4,2,3,4,2,3,23,24,24,8,4,20,2,2,3,4,39,81, +81,38,8,7,89,89,17,1,2,2,3,4,20,17,1,8,8,8,3,8,8,8,4,20,2,3,4,21,2,3,4,2,19,20,4,107,108,3,4,2,3,4,20,19,20,7,8,4,23,24,24,24,8,24,8,7,8,7,8,2,3,4,23,23,23,23,23,24,4,4,4,3,4,20,7,8,24,4,4,20,4,3,2,3,4,20,2,3,4,23,24,24,8,3,18,18,19,20,39,81, +81,38,8,7,89,89,2,3,4,2,3,4,4,1,17,17,17,2,3,4,2,3,4,20,2,3,4,2,3,4,20,2,3,19,20,107,108,2,2,18,19,20,2,2,18,19,20,20,4,2,3,23,24,8,24,7,7,8,7,8,3,23,23,23,23,23,23,24,20,20,20,4,4,7,8,8,4,4,20,20,4,2,18,19,20,2,2,3,4,20,23,24,24,8,8,8,20,4,39,81, +81,38,8,7,89,89,2,3,4,2,3,4,20,17,18,19,2,3,4,2,3,4,20,2,2,3,2,3,4,20,4,3,19,19,20,107,108,4,18,19,19,20,2,2,18,19,20,20,4,2,3,23,24,8,24,23,7,7,7,8,23,23,23,23,23,23,23,24,2,19,20,20,20,7,8,24,4,20,19,20,20,18,19,20,4,2,2,3,4,20,2,23,24,24,24,24,8,8,39,81, +81,38,8,7,89,89,2,3,4,2,3,4,3,4,1,17,2,3,4,2,3,4,20,2,3,2,2,3,4,2,3,19,19,20,107,108,108,4,20,3,19,19,20,2,2,18,19,20,2,3,4,23,24,24,8,8,23,23,7,7,8,7,7,7,7,23,24,18,2,3,4,20,19,7,7,8,4,2,2,3,4,19,20,4,20,2,3,4,20,2,3,4,20,3,23,24,24,24,39,81, +81,38,8,7,89,89,2,3,4,2,3,4,3,4,17,2,3,4,20,2,3,4,2,2,3,2,3,4,20,3,19,19,20,2,107,108,124,20,3,4,3,19,20,2,2,18,19,20,18,19,20,19,23,24,24,24,8,8,8,7,7,8,23,23,23,23,24,2,3,3,3,4,20,23,7,8,4,2,18,19,20,4,3,4,4,2,3,4,20,2,3,4,2,3,4,18,19,20,39,81, +81,38,8,7,89,89,3,4,20,2,3,4,4,20,20,2,3,4,20,2,3,4,2,2,3,2,3,3,3,19,20,19,2,3,107,108,20,2,3,4,3,19,20,2,2,18,19,20,19,20,1,2,1,23,24,24,24,24,24,8,8,7,8,7,8,4,18,2,3,19,3,4,20,3,7,7,8,4,19,20,19,20,3,2,2,3,4,4,4,2,3,4,2,3,4,18,19,20,39,81, +81,38,8,7,89,89,3,4,3,3,4,20,4,20,6,2,3,4,2,2,3,2,3,2,3,3,19,19,19,20,3,2,3,4,107,108,4,3,4,2,19,19,20,2,2,18,19,20,20,1,1,1,17,2,3,23,24,23,24,24,24,8,8,8,24,4,2,3,4,20,19,3,4,3,23,7,8,20,4,3,3,4,3,2,3,4,20,4,4,2,3,4,2,3,4,2,2,3,39,81, +81,38,8,7,89,4,3,2,19,19,3,3,3,3,3,3,3,3,3,3,3,3,3,3,19,19,20,4,2,3,4,4,19,107,108,108,20,19,20,18,19,19,20,2,2,18,19,20,4,4,4,4,18,2,3,4,23,24,24,23,24,24,24,24,24,3,4,4,20,2,3,19,3,3,4,7,7,8,20,4,19,20,4,2,3,4,4,20,2,3,4,20,2,3,4,3,2,3,39,81, +81,38,8,7,89,3,4,2,19,20,19,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,3,2,3,4,4,20,20,107,108,124,3,4,20,2,2,19,20,2,2,18,19,20,4,4,4,20,17,18,19,20,18,19,23,24,24,24,24,23,24,8,3,4,2,2,3,4,19,3,4,23,7,7,8,4,4,19,20,3,4,20,4,7,8,3,4,4,2,3,4,3,18,2,39,81, +81,38,8,7,89,19,3,3,4,19,20,4,3,4,2,3,4,2,2,3,4,2,2,3,4,2,2,3,4,20,20,20,107,108,108,2,3,4,2,3,4,19,20,2,2,18,19,20,20,20,3,4,6,2,3,4,6,5,6,2,2,3,7,23,24,24,8,4,18,18,3,4,19,3,4,19,23,7,7,8,4,19,20,3,4,4,4,7,8,8,4,4,2,3,4,3,2,2,39,81, +81,38,8,7,89,2,19,3,3,19,20,20,19,20,2,3,4,2,2,3,2,2,3,4,20,2,3,4,4,3,4,20,107,108,124,3,4,2,2,3,4,19,20,2,2,18,19,20,4,18,19,20,4,4,4,20,22,2,3,4,2,2,23,7,23,24,24,3,4,4,3,4,19,3,3,3,4,23,23,24,4,19,20,3,4,4,20,23,24,24,20,4,2,3,4,3,2,2,39,81, +81,38,8,7,89,3,19,19,19,3,19,20,4,2,3,4,20,18,2,3,2,2,3,4,2,2,3,4,20,4,20,4,107,108,2,3,4,18,2,3,4,19,20,2,8,8,19,20,4,18,18,19,20,20,4,2,2,3,4,20,18,18,19,23,7,23,24,8,3,4,3,4,3,19,3,3,4,20,20,19,20,19,3,4,4,20,4,7,23,24,4,20,2,3,4,2,3,4,39,81, +81,38,8,7,89,3,3,4,19,3,3,19,20,4,3,4,4,18,2,2,3,4,2,2,2,3,4,4,4,20,2,107,108,108,3,2,3,4,2,3,4,3,19,20,8,8,18,19,20,3,4,3,18,19,20,4,18,19,20,2,18,19,20,2,23,23,24,24,8,3,4,4,19,20,3,4,20,3,3,19,20,20,19,20,4,20,4,7,23,24,4,4,2,3,4,2,3,4,39,81, +81,38,8,7,89,3,19,3,4,19,3,19,20,20,3,4,20,2,2,2,3,4,2,18,2,2,2,3,4,20,2,107,108,124,4,4,4,4,2,3,4,3,19,8,23,8,8,8,20,19,20,19,20,18,19,20,4,2,2,18,19,20,2,2,18,23,23,24,24,8,3,4,5,5,3,4,19,19,3,3,19,20,3,4,4,20,2,7,23,24,4,4,2,3,4,2,3,4,39,81, +81,38,8,7,89,3,2,3,3,4,19,3,19,20,4,4,2,3,2,2,3,4,18,18,18,18,2,3,4,4,18,107,108,2,2,2,2,3,4,4,4,19,19,23,23,7,8,8,8,8,8,2,3,18,19,20,20,18,18,19,20,2,18,18,19,20,23,23,24,24,8,3,21,5,4,20,4,20,19,19,19,20,19,20,20,3,2,23,23,24,4,4,2,3,4,2,3,4,39,81, +81,38,8,8,89,4,2,19,3,4,3,19,19,20,20,4,2,3,2,3,4,2,18,19,20,20,18,19,20,20,107,108,108,18,18,18,18,2,2,2,3,4,19,23,7,7,7,7,8,8,8,8,2,18,8,8,20,19,20,2,18,18,19,20,2,2,18,23,23,24,24,8,8,21,4,4,20,4,18,19,20,20,19,20,20,3,3,23,24,7,20,20,2,3,4,2,3,4,39,81, +81,38,8,8,89,2,3,4,19,3,3,4,19,20,4,4,4,4,2,3,2,18,2,18,18,2,2,18,19,107,108,108,124,3,4,20,4,18,18,18,2,19,20,23,7,18,7,7,7,8,8,8,8,18,8,8,8,8,8,18,19,20,2,18,18,18,19,20,23,23,24,24,24,24,8,3,3,3,4,3,3,3,3,3,3,3,7,23,24,7,20,4,2,3,4,2,3,4,39,81, +81,38,8,8,89,2,3,4,3,19,3,4,20,19,20,20,4,20,4,2,18,19,2,3,2,18,18,18,107,108,108,124,18,19,20,3,4,4,3,4,19,20,2,23,7,19,20,7,7,7,7,8,8,8,7,7,7,7,7,8,8,18,18,19,20,3,4,4,20,2,23,7,23,24,24,8,8,3,3,19,19,19,19,3,4,7,23,23,24,4,3,4,2,3,4,2,3,4,39,81, +81,38,8,8,89,2,3,3,4,20,19,3,4,19,20,19,20,4,20,4,19,2,3,4,2,3,4,107,108,108,124,3,4,3,3,3,4,20,19,19,20,2,2,23,7,20,20,3,8,7,7,7,7,7,8,8,8,7,7,7,7,3,3,3,3,3,3,3,3,3,3,23,7,8,7,7,7,7,8,4,3,4,4,19,7,23,23,24,19,20,3,4,2,3,2,3,4,4,39,81, +81,38,8,8,89,8,3,3,4,19,3,19,3,4,19,20,19,20,4,20,4,3,3,3,3,107,108,108,108,124,2,3,3,3,4,4,3,4,19,20,2,2,18,23,7,20,3,19,7,8,7,7,7,7,7,7,8,8,8,7,7,19,19,3,3,3,3,3,3,3,19,19,7,8,23,23,23,7,7,7,7,7,7,7,23,23,24,20,3,4,3,4,2,3,2,2,3,4,39,81, +81,38,8,8,89,8,19,3,3,4,19,3,3,3,4,19,20,19,20,4,20,4,107,108,108,108,108,124,124,20,4,4,5,5,5,5,5,5,19,20,2,2,8,23,7,3,19,3,7,7,8,7,7,7,8,8,7,8,8,7,7,8,5,3,4,3,4,19,19,19,20,4,8,8,8,20,20,23,23,23,23,23,23,23,23,24,4,18,19,20,19,20,2,3,2,2,3,4,39,81, +81,38,8,8,89,89,19,19,19,3,3,19,19,19,3,4,20,5,5,5,5,5,107,108,124,124,124,5,5,5,5,5,5,5,5,5,5,5,3,3,3,8,23,23,7,19,3,5,7,7,7,7,7,7,8,7,8,8,8,7,7,7,19,19,20,19,3,3,4,3,4,4,7,7,8,20,3,4,4,2,18,19,20,4,2,3,4,3,4,20,2,3,2,3,18,2,3,4,39,81, +81,38,8,8,89,89,3,4,19,19,19,19,19,3,19,3,3,3,19,20,20,19,123,124,5,5,5,5,5,5,5,5,5,5,5,5,5,5,3,8,8,23,23,7,19,3,5,5,7,7,7,7,7,7,7,7,8,7,8,8,7,7,8,3,19,19,19,19,20,19,20,20,23,7,8,4,4,4,2,2,18,19,20,20,3,4,20,3,4,2,18,19,2,3,4,2,3,4,39,81, +81,38,8,8,89,89,3,4,19,3,3,3,19,19,3,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,19,23,23,23,7,4,3,19,20,19,20,20,7,8,8,7,7,7,7,8,8,8,7,7,7,19,20,20,19,19,19,19,19,19,23,7,8,20,20,20,2,3,18,19,20,4,3,4,3,4,20,2,2,3,2,3,4,2,3,4,39,81, +81,38,8,8,89,89,3,4,3,19,19,19,19,19,19,19,19,20,19,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,7,8,8,8,4,4,4,4,4,3,4,2,2,7,8,7,7,8,7,8,7,8,8,7,7,20,20,4,20,20,3,4,20,2,23,7,8,3,4,2,2,3,2,3,4,20,4,20,3,4,4,2,2,3,2,3,4,2,7,8,39,81, +81,38,8,8,89,89,3,4,3,4,5,2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,20,5,5,5,7,8,8,8,20,20,20,20,20,20,4,4,4,18,19,7,7,7,7,8,7,8,8,7,7,7,19,20,20,2,2,3,4,18,18,23,7,8,3,4,2,3,4,18,19,20,3,4,18,19,20,4,2,18,19,2,3,4,7,7,8,39,81, +81,38,8,8,7,89,3,4,3,4,5,2,3,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,7,8,8,8,8,20,20,3,4,18,19,20,20,20,20,4,18,18,18,7,7,7,7,7,7,7,7,19,20,19,20,4,3,4,20,19,20,4,7,7,8,4,2,3,2,3,4,20,3,4,2,3,4,4,2,2,3,7,8,8,23,23,24,39,81, +81,38,8,8,7,89,5,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,23,23,23,7,8,8,8,8,5,5,18,19,20,20,20,18,20,19,20,20,19,20,20,20,7,7,2,18,18,18,19,20,2,18,19,20,4,20,4,4,2,2,23,7,8,4,4,3,18,19,20,7,7,8,8,8,8,8,8,8,8,8,24,24,24,24,4,39,81, +81,38,8,8,8,89,5,5,5,5,5,5,5,5,5,5,2,2,2,2,3,2,5,5,5,5,5,23,23,23,23,8,8,8,23,8,8,19,20,20,20,20,20,20,19,20,20,19,20,20,3,4,4,2,2,18,18,18,19,20,18,18,18,18,19,19,20,20,4,20,20,3,4,23,7,8,20,20,4,3,4,4,23,23,24,24,24,24,24,24,24,24,24,3,4,2,3,4,39,81, +81,38,8,8,8,89,5,5,5,5,2,2,5,5,19,20,2,18,18,2,3,2,3,4,2,23,7,8,8,8,8,8,23,7,8,8,19,20,20,20,20,20,20,20,20,20,19,20,20,3,2,2,2,18,18,19,20,18,18,19,20,3,4,20,19,20,19,20,20,19,20,19,20,23,7,7,8,19,20,19,20,20,20,4,2,3,4,20,4,18,2,3,2,3,4,2,3,4,39,81, +81,38,8,8,8,89,5,5,3,4,2,3,4,2,3,4,2,18,19,2,3,2,3,4,23,23,7,8,23,19,19,20,2,18,18,19,20,2,20,20,20,19,20,20,20,19,20,20,3,19,18,18,18,19,20,19,20,2,2,2,3,4,4,20,20,20,20,4,3,2,3,4,19,23,23,7,8,2,18,18,19,20,20,4,2,3,4,3,4,3,18,19,2,3,4,2,3,4,39,81, +81,38,8,8,8,89,3,4,19,20,2,3,2,3,4,20,2,2,3,2,3,2,3,23,8,8,23,18,18,18,18,18,18,19,20,2,20,20,19,20,20,20,20,19,20,19,20,8,8,8,8,20,18,19,20,18,18,18,2,3,4,20,20,2,2,2,2,2,2,2,2,2,2,18,23,7,7,8,19,20,4,4,3,4,18,19,20,3,4,3,2,3,2,3,4,2,3,4,39,81, +81,38,8,8,8,89,89,4,19,20,2,3,2,3,4,18,2,18,2,3,4,8,7,89,8,23,2,3,2,19,19,20,20,19,20,20,19,20,20,20,20,20,19,20,20,19,8,8,8,8,8,8,8,8,8,8,8,8,8,4,20,18,2,2,2,2,2,2,18,18,18,18,8,8,23,23,7,8,2,2,2,2,3,4,2,3,4,3,4,3,2,3,2,3,4,2,3,4,39,81, +81,38,8,8,8,89,89,4,19,20,2,3,2,3,4,2,2,18,2,3,8,7,89,89,23,4,2,2,18,4,4,20,20,20,19,20,20,20,20,20,20,19,20,20,20,2,8,8,8,8,8,7,7,7,7,7,7,7,7,8,8,8,8,18,18,18,18,18,19,8,8,8,8,7,23,24,7,7,8,18,2,3,4,4,2,3,4,2,3,4,2,3,2,3,4,2,3,4,39,81, +81,38,8,8,8,89,89,3,4,20,2,3,18,19,20,2,18,18,8,7,89,89,89,89,23,20,2,18,19,20,20,20,19,20,20,20,20,20,20,18,20,20,20,8,8,8,8,8,7,7,7,3,4,18,19,20,20,23,7,7,7,7,7,8,8,8,8,8,8,8,7,7,7,2,3,23,23,7,8,4,4,4,4,20,2,3,4,2,3,4,2,3,2,3,4,2,3,4,39,81, +81,38,8,8,8,8,89,89,4,2,2,2,3,4,20,2,3,8,7,89,89,89,89,89,23,2,18,19,20,20,20,19,20,20,3,20,20,18,18,20,8,8,8,7,8,7,7,7,3,4,3,4,20,20,18,18,18,19,20,3,4,23,7,7,7,7,7,7,7,7,4,4,4,4,19,23,24,7,7,8,20,20,20,4,2,3,4,2,3,4,18,19,2,3,4,2,3,4,39,81, +81,38,8,8,8,8,89,89,4,2,2,2,3,4,8,7,89,89,89,89,89,89,89,23,4,2,2,3,2,20,19,20,20,20,20,20,18,18,8,8,7,7,7,7,7,7,7,20,19,20,19,20,19,20,20,18,19,20,18,19,20,20,18,19,20,2,3,4,4,19,20,20,20,20,2,2,23,23,7,8,20,4,4,4,2,3,4,2,3,4,18,19,2,3,4,2,3,4,39,81, +81,38,8,8,8,8,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,2,3,4,20,2,3,4,4,20,2,20,20,20,8,8,8,7,7,7,7,7,8,8,20,20,18,18,19,20,20,19,20,18,18,18,18,18,18,18,18,18,18,18,18,2,3,4,4,18,18,18,19,20,18,2,3,4,7,7,7,7,8,7,7,7,7,7,7,7,7,7,8,3,2,2,3,4,39,81, +81,38,8,8,89,8,8,89,89,89,89,89,89,89,89,89,89,89,89,89,2,2,3,4,20,2,3,4,4,20,2,8,8,8,8,8,7,7,7,7,8,8,7,7,18,18,19,20,2,18,18,18,18,19,20,20,19,20,19,20,18,19,20,20,18,2,3,4,19,20,3,4,2,2,18,18,19,20,23,23,23,7,8,23,23,7,23,23,23,23,23,7,8,3,18,2,3,4,39,81, +81,38,8,8,89,8,8,89,89,89,89,89,89,89,89,89,89,2,3,2,3,2,3,4,4,2,3,4,4,20,2,7,7,7,8,8,7,8,7,7,7,7,7,2,2,2,2,2,2,18,18,18,2,3,4,20,18,19,20,19,20,2,2,2,2,2,3,4,18,2,3,4,2,3,18,18,19,20,3,4,7,8,8,23,24,23,23,24,7,7,8,23,24,3,2,2,3,4,39,81, +81,38,8,8,8,89,8,2,2,2,2,18,19,20,2,18,19,2,3,2,3,2,3,4,20,2,3,4,4,20,2,7,7,7,8,8,7,7,4,4,20,2,2,2,2,2,18,18,18,2,3,4,4,19,20,2,2,2,2,2,2,2,2,2,2,3,4,4,2,2,3,4,18,19,2,18,19,20,19,7,8,8,24,2,3,4,19,2,8,8,8,20,2,3,2,2,3,4,39,81, +81,38,8,8,8,89,8,2,2,2,2,3,4,20,18,19,20,2,3,18,19,2,3,4,4,18,19,4,4,20,2,2,2,2,7,7,7,4,4,4,4,18,2,2,18,18,19,2,2,18,19,20,20,20,4,2,2,2,8,8,2,2,2,2,2,2,3,4,3,2,3,4,18,2,3,4,20,2,3,7,8,24,3,2,3,4,3,18,18,18,19,20,2,2,18,2,3,4,39,81, +81,38,8,8,8,89,8,2,2,2,18,19,20,20,18,19,20,2,2,18,19,2,3,4,2,2,3,18,4,4,18,18,18,18,2,2,2,2,4,4,18,18,18,18,19,2,2,18,18,19,20,2,3,4,20,18,18,18,8,8,8,18,18,18,2,3,4,4,2,3,4,20,19,2,3,4,18,2,7,8,24,2,2,18,19,20,3,4,4,3,2,3,2,18,19,2,3,4,39,81, +81,38,8,8,89,7,8,18,2,18,18,19,20,19,19,19,19,19,19,19,19,19,3,4,2,2,2,3,2,2,4,4,4,18,18,18,18,18,4,18,2,2,3,4,3,4,18,19,20,18,2,3,4,20,2,2,2,2,7,7,7,2,2,2,3,4,4,4,2,3,4,18,19,2,3,4,18,7,23,24,4,2,18,19,20,2,3,4,20,19,18,19,18,18,19,2,3,4,39,81, +81,38,8,8,89,7,89,19,18,19,20,20,20,20,20,19,20,20,20,20,20,20,2,3,4,2,18,19,18,18,18,19,20,19,20,20,2,2,3,4,18,18,19,20,19,20,20,18,18,2,3,4,20,2,2,2,2,8,7,7,7,2,2,3,4,4,4,4,2,3,4,18,19,2,3,4,2,7,8,20,4,4,5,5,5,18,19,20,20,2,3,4,20,19,20,2,3,4,39,81, +81,38,8,8,89,89,89,2,2,3,4,20,20,19,19,20,20,20,19,19,18,19,2,2,2,18,18,19,20,20,20,18,18,2,2,3,4,18,19,20,19,20,18,19,20,18,18,2,2,3,7,8,8,8,8,3,4,7,7,7,2,3,4,4,4,4,19,20,2,3,4,2,2,4,5,4,18,19,2,4,5,5,5,21,21,18,19,20,5,18,19,20,18,20,18,2,3,4,39,81, +81,38,8,8,89,89,89,2,89,89,4,20,20,20,20,19,19,19,19,20,18,18,18,7,8,8,8,8,8,8,8,2,2,18,18,19,20,20,2,2,2,2,3,4,7,8,8,8,8,8,8,8,8,8,8,8,8,7,7,3,4,4,4,4,4,19,20,2,2,3,4,2,2,20,21,4,18,19,2,5,5,21,21,20,3,2,3,4,21,18,19,7,7,7,7,7,8,4,39,81, +81,38,8,8,89,89,8,8,8,8,8,7,7,7,7,20,20,20,20,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,20,2,2,3,7,8,8,8,8,8,8,8,8,8,8,8,8,8,3,8,8,8,8,8,8,8,8,8,8,7,8,8,2,18,2,3,4,2,2,4,5,4,2,2,4,5,5,5,19,20,2,18,19,20,7,8,7,23,23,23,23,7,7,8,39,81, +81,38,8,8,8,8,7,7,7,7,7,7,8,8,8,8,7,8,8,8,8,8,8,8,8,4,4,4,4,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,4,4,20,20,20,18,19,20,20,19,8,8,8,8,8,8,8,8,8,8,2,2,2,3,2,2,3,4,4,4,5,5,5,5,21,21,4,4,4,4,20,3,8,8,7,7,8,8,8,8,8,8,39,81, +81,84,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,20,20,20,20,20,20,20,20,20,20,20,8,8,8,8,8,8,8,8,20,20,20,20,20,20,20,20,18,18,18,19,20,18,18,18,18,2,3,4,2,8,8,8,8,18,18,18,2,3,18,18,19,20,20,20,21,21,21,21,20,20,20,20,20,20,4,3,8,8,23,23,24,24,24,24,24,24,39,81, +81,66,34,34,35,35,34,34,34,34,34,34,34,8,8,8,8,8,34,34,34,34,34,34,34,34,34,35,34,34,34,34,34,34,34,34,34,35,34,34,34,34,34,34,34,34,34,34,34,34,34,35,34,34,34,34,34,34,34,34,34,35,34,34,34,34,34,34,34,35,34,34,34,34,34,34,34,34,34,35,34,34,34,34,34,34,35,34,34,34,34,34,34,34,35,34,34,35,67,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81 + + + + +0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,145,145,145,145,145,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,145,145,145,145,145,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0, +0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,0,0,0,145,145,0,145,145,145,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,145,145,145,145,145,0,0,145,145,145,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,145,145,145,145,145,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,0,145,145,145,0,145,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,145,0, +0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,0,145,0,0,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,145,0, +0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,145,0,145,0,0,0,0,0,0,145,145,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,145,0, +0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,145,0,145,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,145,0, +0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,145,0,145,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,145,0, +0,145,145,145,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,145,0,145,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,145,0, +0,145,145,145,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,145,0,145,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,145,0, +0,145,145,145,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,145,0,145,0,0,0,0,0,0,145,145,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,145,0,145,0,0,0,0,0,0,0,0,0,0,0,0,145,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,145,145,0,0,0,0,0,145,145,0,0,0,0,0,145,0,145,145,0,0,0,0,0,0,0,0,0,0,145,145,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,145,145,0,0,0,0,0,145,145,0,0,0,0,0,145,0,0,145,145,145,145,0,0,0,0,0,0,145,145,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0, +0,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0,0,0,145,145,145,145,145,145,0,0,0,0,0,145,145,145,0,0,0,0,145,145,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,145,145,145,145,145,0,145,145,0, +0,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,145,145,145,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,145,145,0,0,0,0,145,145,0, +0,145,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0, +0,145,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,145,0, +0,145,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,145,0, +0,145,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,0,0,0,0,145,145,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,145,145,145,145,145,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,0,0,0,0,145,145,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,145,145,0,0,0,0,0,145,145,145,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,145,145,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,145,145,0,0,0,0,145,145,0,0,0,0,0,0,145,145,0,0,0,0,0,145,0,0,0,0,145,145,145,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,145,145,145,0,0,0,0,0,145,145,0,0,0,0,0,145,145,145,0,145,145,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,145,145,145,145,0,0,0,0,145,145,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,145,145,145,145,145,0,0,0,145,145,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,145,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,145,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,145,0, +0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,145,0, +0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,145,0, +0,145,145,145,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,145,145,145,145,145,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,145,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,145,0, +0,145,145,145,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,145,145,145,145,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,145,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,145,145,145,145,0,0,0,145,145,145,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,145,145,145,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,145,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,0,0,145,0,145,0,0,145,0,0,0,145,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,145,0,0,145,0,0,0,0,0,0,0,0,0,145,145,145,145,0,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,0,0,145,0,145,0,0,145,0,0,0,145,145,145,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,145,145,0,0,145,0,0,0,0,0,0,0,145,145,145,145,145,145,0,0,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,145,145,145,145,0,0,0,0,0,145,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,145,145,0,0,0,0,145,145,0,0,0,145,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,145,145,0,145,145,145,145,0,0,0,0,0,145,145,0,0,0,145,0,0,0,0,145,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,145,145,0,145,145,0,0,0,0,145,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,145,145,145,0,0,0,0,145,145,0,0,0,0,0,145,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,145,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,0,145,145,145,145,145,145,145,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,145,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,145,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,145,145,145,145,145,145,145,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,145,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,0,0,0,0,0,145,145,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,145,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,145,145,145,145,145,145,145,0,145,145,145,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,0,0,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,0,0,0,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,0,145,0, +0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,145,145,145,145,145,0,0,0,0,0,0,145,145,145,145,0,0,0,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,0,0,0,0,145,145,145,0, +0,145,145,145,145,145,145,145,145,145,145,145,0,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,145,0, +0,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + diff --git a/DepthsBelow/DepthsBelowContentPipeline/MapProcessor.cs b/DepthsBelow/DepthsBelowContentPipeline/MapProcessor.cs index 706befd..e24f0b4 100755 --- a/DepthsBelow/DepthsBelowContentPipeline/MapProcessor.cs +++ b/DepthsBelow/DepthsBelowContentPipeline/MapProcessor.cs @@ -15,6 +15,7 @@ namespace DepthsBelowContentPipeline [ContentSerializerRuntimeType("DepthsBelow.Tile, DepthsBelow")] public class MapTileContent { + public int LocalId; public ExternalReference Texture; public Rectangle SourceRectangle; public SpriteEffects SpriteEffects; @@ -113,6 +114,7 @@ namespace DepthsBelowContentPipeline // now insert the tile into our output outLayer.Tiles[i] = new MapTileContent { + LocalId = tileIndex, Texture = textureContent, SourceRectangle = sourceRect, SpriteEffects = spriteEffects