when i starting my game on the game scene,everything is fine,but when i load from menu,first time is ok,then there is saving data to json,and when i come back to main menu,and then again press play it's " Object reference not set to an instance of an object " for my saveScript which is attached to empty gameObject on game scene.
loading just
SceneManager.LoadSceneAsync("game");
SAVE SCRIPT
public void PopulateSaveData(SaveData sd)
{
//character
sd.s_XP = XP;
respawnScript.instance.PopulateSaveData(sd);
sd.s_x = gameObject.transform.position.x;
sd.s_y = gameObject.transform.position.y;
sd.s_z = gameObject.transform.position.z;
playerHealth.instance.PopulateSaveData(sd);
//sword
playerSword.instance.PopulateSaveData(sd);
//inventory
Inventory.instance.PopulateSaveData(sd);
//sd.s_allItemsPositions = allItemsPositions;
//sd.s_allPotionInteractions = GameObject.FindObjectsOfType<potionInteraction>().ToList();
if (allPotionInteractionO.Count > 0)
{
Debug.Log("ALL POTIONS COUNT " + allPotionInteractionO[0]);
sd.s_allPotionInteractions = allPotionInteractionO;
}
sd.s_allWeaponInteractions = all_swords;
sd.s_allWeaponInteractionsGO = all_swordsGO;
for (int i = 0; i < all_swordsGO.Count; i++)
{
sd.s_allSwordsRotation.Add(all_swordsGO[i].transform.rotation);
}
for (int i = 0; i < all_swordsGO.Count; i++)
{
//because some objects can be destroyed thats why im initializing list again
//allInteractableGameObjects = GameObject.FindGameObjectsWithTag("interactable object").ToList();
// sd.s_allItemsPositions.Add(allInteractableGameObjects[i].transform.position);
sd.s_allSwordsPositions.Add(all_swordsGO[i].transform.position);
}
for (int i = 0; i < allPotionInteractionO.Count; i++)
{
sd.s_allPotionsPositions.Add(allPotionInteractionO[i].transform.position);
}
///going through list and check if there is used item,then saving its bool to another list at same position
for (int i = 0; i < allPotionInteractionO.Count; i++)
{
if (allPotionInteractionO[i].isUsed)
{
allPotionsIsUsed[i] = true;
}
}
sd.s_allPotionsIsUsed = allPotionsIsUsed;
//quest part
for (int i = 0; i < allNPCS.Count; i++)
{
if (allNPCS[i].quest == null)
{
allNpcQuests[i] = null;
}
}
sd.s_allQuests = allNpcQuests;
if(MarieleQuest.instance.currentMarieleQuest!=null)
{
sd.s_currentQuest = MarieleQuest.instance.currentMarieleQuest;
}
foreach (Slot slot in slotsToSave)
{
slot.PopulateSaveData(sd);
}
//enemies
foreach (EnemyStats enemy in all_enemies)
{
enemy.PopulateSaveData(sd);
}
//procedural enemies
foreach (ProceduralStats enemy in all_procedural_enemies)
{
enemy.PopulateSaveData(sd);
}
}
LOAD
public void LoadFromSaveData(SaveData sd)
{
if (SceneManager.GetActiveScene().name == "game")
{
//character
XP = sd.s_XP;
if (sd.s_HP > 0)
{
playerHealth.instance.LoadFromSaveData(sd);
}
else if (sd.s_HP == 0)
{
playerHealth.instance.currentHealth = 100;
}
if (sd.s_respawnObject != null)
{
respawnScript.instance.LoadFromSaveData(sd);
}
if (sd.s_x != 0 && sd.s_y != 0 && sd.s_z != 0)
{
gameObject.transform.position = new Vector3(sd.s_x, sd.s_y, sd.s_z);
}
//sword
if (sd.s_sword != null && sd.s_temp != null && sd.s_currentSword != null && sd.s_currentSwordGO != null)
{
playerSword.instance.LoadFromSaveData(sd);
}
else
{
playerSword.instance.currentSwordGameObject = GameObject.Find("character/mixamorig:Hips/mixamorig:Spine/mixamorig:Spine1/" + playerSword.instance.currentSwordGameObject.name);
playerSword.instance.temp = playerSword.instance.currentSwordGameObject;
}
//potions
if (sd.s_allPotionsIsUsed.Count > 0)
{
allPotionsIsUsed = sd.s_allPotionsIsUsed;
}
//quest
if (sd.s_allQuests.Count > 0)
{
Debug.Log("SD ALL QUESTS" + sd.s_allQuests);
allNpcQuests = sd.s_allQuests;
}
if (sd.s_allQuests.Count > 0)
{
for (int i = 0; i < allNPCS.Count; i++)
{
allNPCS[i].quest = allNpcQuests[i];
}
}
if (sd.s_currentQuest != null)
{
MarieleQuest.instance.currentMarieleQuest = sd.s_currentQuest;
}
if (sd.s_allPotionInteractions.Count > 0)//second pattern in if is changed(FOR REMEMBER)
{
Debug.Log("SD ALL POTIONS > 0");
if (sd.s_allPotionInteractions[0] != null)
{
allPotionInteractionO = sd.s_allPotionInteractions;
}
else
{
allPotionInteractionO = GameObject.FindObjectsOfType<potionInteraction>().ToList();
}
for (int b = 0; b < allPotionInteractionO.Count; b++)
{
allPotionInteractionO[b].isUsed = allPotionsIsUsed[b];
}
for (int i = 0; i < allPotionInteractionO.Count; i++)
{
if (allPotionInteractionO[i].isUsed)
{
allPotionInteractionO[i].gameObject.SetActive(false);
}
}
}
Inventory.instance.LoadFromSaveData(sd);
if (sd.s_allWeaponInteractions.Count > 0)
{
//all_swords = sd.s_allWeaponInteractions;
// all_swordsGO = sd.s_allWeaponInteractionsGO;
for (int i = 0; i < all_swordsGO.Count; i++)
{
if (!Inventory.instance.itemsGameObjects.Contains(all_swordsGO[i])
&& all_swordsGO[i] != playerSword.instance.currentSwordGameObject)
{
all_swordsGO[i].SetActive(true);
all_swordsGO[i].transform.rotation = sd.s_allSwordsRotation[i];
}
}
for (int j = 0; j < sd.s_allSwordsPositions.Count; j++)
{
//Debug.Log(sd.s_allItemsPositions[j] + " " + allInteractableGameObjects[j].name);
all_swordsGO[j].transform.position = sd.s_allSwordsPositions[j];
allPotionInteractionO[j].transform.position = sd.s_allPotionsPositions[j];
}
}
foreach (Slot slot in slotsToSave)
{
slot.LoadFromSaveData(sd);
}
//enemies
foreach (EnemyStats enemy in all_enemies)
{
enemy.LoadFromSaveData(sd);
}
foreach (string id in dead_enemies_ids)
{
SaveData.EnemyData enemyData = new SaveData.EnemyData();
enemyData.e_Health = 0;
enemyData.e_id = id;
sd.enemyData.Add(enemyData);
}
//procedural enemies
foreach (ProceduralStats enemy in all_procedural_enemies)
{
enemy.LoadFromSaveData(sd);
}
foreach (string id in all_procedural_ids)
{
SaveData.ProceduralEnemyData enemyData = new SaveData.ProceduralEnemyData();
enemyData.e_ProcHealth = 0;
enemyData.e_ProcId = id;
sd.proceduralEnemyData.Add(enemyData);
}
}
}
these two scripts just writing data to lists,and reading it from saved file,
saving is called once OnApplicationQuit()
load called at the end of Start()
when i open scene game just from itself and close and load again,everything work fine,because its destroying objects and load them again,but
once i start from main menu,from there do LoadScene("game") i'm getting error that some fields are not exist anymore,but it's like unreal
SaveData script which have all info and store it to file,then read
public class SaveData : MonoBehaviour
{
private void Awake()
{
}
private void Start()
{
s_inventoryGO = new List<GameObject>();
Debug.Log("s_inventoryGO" + s_inventoryGO.Count);
}
//character saving
public int s_XP;
public GameObject s_respawnObject;
public float s_x;
public float s_y;
public float s_z;
//inventory
public List<Item> s_inventory = new List<Item>();
public List<GameObject> s_inventoryGO = new List<GameObject>();
public List<GameObject> s_allGameObjectInventory = new List<GameObject>();
public List<GameObject> s_allInteractableObjects = new List<GameObject>();
public List<potionInteraction> s_allPotionInteractions = new List<potionInteraction>();
public List<weaponInteract> s_allWeaponInteractions = new List<weaponInteract>();
public List<GameObject> s_allWeaponInteractionsGO = new List<GameObject>();
public List<Quaternion> s_allSwordsRotation = new List<Quaternion>();
public List<Vector3> s_allSwordsPositions = new List<Vector3>();
public List<Vector3> s_allPotionsPositions = new List<Vector3>();
public List<bool> s_allPotionsIsUsed = new List<bool>();
public List<Quest> s_allQuests = new List<Quest>();
public Quest s_currentQuest;
public int s_HP;
[System.Serializable]
public struct SlotsData
{
public Item s_slotItem;
public string s_id;
//public Sprite s_icon ;
}
public List<SlotsData> s_slots = new List<SlotsData>();
//sword
public Transform s_sword;
public GameObject s_currentSwordGO;
public GameObject s_temp;
public swordEquipping s_currentSword;
//enemy saving
[System.Serializable]
public struct EnemyData
{
public int e_Health;
public string e_id;
}
public List<EnemyData> enemyData = new List<EnemyData>();
//procedural enemy saving
[System.Serializable]
public struct ProceduralEnemyData
{
public int e_ProcHealth;
public string e_ProcId;
}
public List<ProceduralEnemyData> proceduralEnemyData = new List<ProceduralEnemyData>();
public string toJson()
{
return JsonUtility.ToJson(this);
}
public void LoadFromJson(string json)
{
JsonUtility.FromJsonOverwrite(json, this);
}
}
When using DontDestroyOnLoad wherever you want this object to exist, make a copy of it in your scene if you want the data stored to persist between your game session.
Here is a snippet from the docs
void Awake()
{
GameObject[] objs = GameObject.FindGameObjectsWithTag("music");
if (objs.Length > 1)
{
Destroy(this.gameObject);
}
DontDestroyOnLoad(this.gameObject);
}
It will search for other objects in the scene with the same tag. If it finds it, it will destroy itself. What you can do here is have a public Init() function on your script. When a new scene is loaded with the object and your object already finds an instance of itself, it can pass the local references to the existing object. Something like...
public GameObject objRef1;
public GameObject objRef2;
public void Init(GameObject obj1, GameObject obj2)
{
objRef1 = obj1;
objRef2 = obj2;
...
etc.
}
Inside of the Awake() of the new object, you would call the existing objects Init with the local references it has, which work as it loaded with your scene.
void Awake()
{
// make the tag unique so you only grab objects of this save type
GameObject[] objs = GameObject.FindGameObjectsWithTag("yourObjectsTag");
if (objs.Length > 1)
{
objs[0].GetComponent<YourScriptName>().Init(obj1, obj2, ..., etc.);
Destroy(this.gameObject);
}
DontDestroyOnLoad(this.gameObject);
}
In this approach it means you have a local copy of your DontDestroyOnLoad object in every scene so when the existing one loads in, it can just grab the references from it.
I'm working on a radix sort algorithm with linked list. I have in mind how I'm going to solve it, but I need to be able to delete the whole linked list (deleting node one by one when looping through linked list). The problem which I encountered is my current (node) pointer doesn't get the value first. I have tried many different things, but I guess I don't grasp how to reset the pointers 'first', 'current', 'left', 'right' when deleting a node
Radixsort.cs:
public static void Counting_sort(LinkedList<int> list, int exp)
{
LinkedList<int> D = new LinkedList<int>();
LinkedList<int>[] lists = new LinkedList<int>[10];
for (int i = 0; i < lists.Length; i++)
{
lists[i] = new LinkedList<int>();
}
// Skaiciu daznumas
int number = 0;
for (list.Beginning(); list.Exists(); list.Next())
{
number = (list.Take() / exp % 10);
lists[number].Add(list.Take());
list.Remove(list.TakeNode()); <---------- Removing node one by one till it's empty
}
for (int i = 0; i < lists.Length; i++)
{
for (list.Beginning(); list.Exists(); list.Next())
{
//list.Add(lists)
}
}
}
public static void Radix_sort(LinkedList<NumberPlate> list)
{
LinkedList<int> intList = new LinkedList<int>();
AddIntToLinkedList(list, intList);
for (int exp = 1; exp < Math.Pow(10, 9); exp *= 10)
{
Counting_sort(intList, exp);
}
}
LinkedList.cs
public class LinkedList<T> : IEnumerable<T> where T : IComparable<T>, IEquatable<T>
{
public sealed class Node<T>
{
public Node<T> Right;
public Node<T> Left;
public T data;
public Node(T value, Node<T> left, Node<T> right)
{
Left = left;
Right = right;
data = value;
}
}
private Node<T> first;
private Node<T> last;
private Node<T> current;
public int size;
public LinkedList()
{
first = null;
last = null;
current = null;
size = 0;
}
public void Add(T element)
{
var node = new Node<T>(element, last, null);
if (first != null)
{
last.Right = node;
last = node;
}
else
{
first = node;
last = node;
}
current = node;
size++;
}
public void Remove(Node<T> node)
{
if (node == first)
{
first = first.Right;
}
else if (node == last)
{
last = last.Left;
}
else if (node.Left != null)
{
node.Left.Right = node.Right;
}
else if (node.Right != null)
{
node.Right.Left = node.Left;
}
size--;
}
public void Beginning()
{
current = first;
}
public void End()
{
current = last;
}
public void Next()
{
current = current.Right;
}
public void Previous()
{
current = current.Left;
}
public bool Exists()
{
return current != null;
}
public T Take()
{
return current.data;
}
public Node<T> TakeNode()
{
return current;
}
I think you should be able to do this to clear a list:
foreach (var node in list)
{
list.Remove(node);
}
The Remove method is already implemented for you on the LinkedList class, so you should make use of it.
Because the LinkedList implements IEnumerable, you can iterate over it using foreach.
I'm trying to do a Radix sort in a Linked list class. I found radix sort algorithm for array and am trying to change it to work with my linked list. However, I'm a bit struggling. The code I'm trying to change is taken from http://www.w3resource.com/csharp-exercises/searching-and-sorting-algorithm/searching-and-sorting-algorithm-exercise-10.php I tested the code with an array and it worked. Does anybody have any ideas how to make radix sort work in a linked list?
//abstract class
abstract class DataList
{
protected int length;
public int Length { get { return length; } }
public abstract double Head();
public abstract double Next();
public abstract void Swap(int a, int b);
public void Print(int n)
{
Console.Write("{0} ", Head());
for (int i = 1; i < n; i++)
Console.Write("{0} ", Next());
Console.WriteLine();
}
}
//linked list class
class LinkedList : DataList
{
class MyLinkedListNode
{
public MyLinkedListNode nextNode { get; set; }
public int data { get; set; }
public MyLinkedListNode(int data)
{
this.data = data;
}
public MyLinkedListNode()
{
this.data = 0;
}
}
MyLinkedListNode headNode;
MyLinkedListNode prevNode;
MyLinkedListNode currentNode;
public LinkedList(int n, int min, int max)
{
length = n;
Random rand = new Random();
headNode = new MyLinkedListNode(rand.Next(min, max));
currentNode = headNode;
for (int i = 1; i < length; i++)
{
prevNode = currentNode;
currentNode.nextNode = new MyLinkedListNode(rand.Next(min, max));
currentNode = currentNode.nextNode;
}
currentNode.nextNode = null;
}
public LinkedList()
{
headNode = new MyLinkedListNode();
currentNode = headNode;
}
public override double Head()
{
currentNode = headNode;
prevNode = null;
return currentNode.data;
}
public override double Next()
{
prevNode = currentNode;
currentNode = currentNode.nextNode;
return currentNode.data;
}
public override void Swap(int a, int b)
{
prevNode.data = a;
currentNode.data = b;
}
//my radix sort
public void radixSort()
{
int j = 0;
LinkedList tmp = new LinkedList();
for (int shift = 31; shift > -1; --shift)
{
//I try to go trough old list
MyLinkedListNode current = headNode;
while (current != null)
{
bool move = (current.data << shift) >= 0;
//I found this expression somewhere and I'm trying to use it to form a new Linked list (tmp)
if (shift == 0 ? !move : move)
;
else
{
if (tmp.headNode == null)
tmp.headNode = currentNode;
else
{
tmp.currentNode.nextNode = current;
//infinite loop happens on the commented line
//tmp.currentNode = tmp.currentNode.nextNode;
j++;
}
current = current.nextNode;
}
}
}
}
Following the C# radix sort example, you need an array of ten lists. Move nodes from the original list into the ten lists, appending a node with least signfificant digit == '0' into array_of_lists[0], '1' into array_of_list[1], and so on. After the original list is emptied, then concatenate the array of lists back into the original list and repeat for the next to least significant digit. Repeat the process until all the digits are handled.
You could use a larger base, such as base 16, where you would use an array of 16 lists. You can then select each "digit" using a shift and an and .
I'm having trouble effectively implementing this generic method featured by Eric Lippert. His blog outlines a very simple and effective means of creating an A Star algorithm (found here). Here's the quick run down.
The code for the actual path finding:
class Path<Node> : IEnumerable<Node>
{
public Node LastStep { get; private set; }
public Path<Node> PreviousSteps { get; private set; }
public double TotalCost { get; private set; }
private Path(Node lastStep, Path<Node> previousSteps, double totalCost)
{
LastStep = lastStep;
PreviousSteps = previousSteps;
TotalCost = totalCost;
}
public Path(Node start) : this(start, null, 0) { }
public Path<Node> AddStep(Node step, double stepCost)
{
return new Path<Node>(step, this, TotalCost + stepCost);
}
public IEnumerator<Node> GetEnumerator()
{
for (Path<Node> p = this; p != null; p = p.PreviousSteps)
yield return p.LastStep;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
class AStar
{
static public Path<Node> FindPath<Node>(
Node start,
Node destination,
Func<Node, Node, double> distance,
Func<Node, double> estimate)
where Node : IHasNeighbours<Node>
{
var closed = new HashSet<Node>();
var queue = new PriorityQueue<double, Path<Node>>();
queue.Enqueue(0, new Path<Node>(start));
while (!queue.IsEmpty)
{
var path = queue.Dequeue();
if (closed.Contains(path.LastStep))
continue;
if (path.LastStep.Equals(destination))
return path;
closed.Add(path.LastStep);
foreach (Node n in path.LastStep.Neighbours)
{
double d = distance(path.LastStep, n);
if (n.Equals(destination))
d = 0;
var newPath = path.AddStep(n, d);
queue.Enqueue(newPath.TotalCost + estimate(n), newPath);
}
}
return null;
}
/// <summary>
/// Finds the distance between two points on a 2D surface.
/// </summary>
/// <param name="x1">The IntPoint on the x-axis of the first IntPoint</param>
/// <param name="x2">The IntPoint on the x-axis of the second IntPoint</param>
/// <param name="y1">The IntPoint on the y-axis of the first IntPoint</param>
/// <param name="y2">The IntPoint on the y-axis of the second IntPoint</param>
/// <returns></returns>
public static long Distance2D(long x1, long y1, long x2, long y2)
{
// ______________________
//d = √ (x2-x1)^2 + (y2-y1)^2
//
//Our end result
long result = 0;
//Take x2-x1, then square it
double part1 = Math.Pow((x2 - x1), 2);
//Take y2-y1, then sqaure it
double part2 = Math.Pow((y2 - y1), 2);
//Add both of the parts together
double underRadical = part1 + part2;
//Get the square root of the parts
result = (long)Math.Sqrt(underRadical);
//Return our result
return result;
}
/// <summary>
/// Finds the distance between two points on a 2D surface.
/// </summary>
/// <param name="x1">The IntPoint on the x-axis of the first IntPoint</param>
/// <param name="x2">The IntPoint on the x-axis of the second IntPoint</param>
/// <param name="y1">The IntPoint on the y-axis of the first IntPoint</param>
/// <param name="y2">The IntPoint on the y-axis of the second IntPoint</param>
/// <returns></returns>
public static int Distance2D(int x1, int y1, int x2, int y2)
{
// ______________________
//d = √ (x2-x1)^2 + (y2-y1)^2
//
//Our end result
int result = 0;
//Take x2-x1, then square it
double part1 = Math.Pow((x2 - x1), 2);
//Take y2-y1, then sqaure it
double part2 = Math.Pow((y2 - y1), 2);
//Add both of the parts together
double underRadical = part1 + part2;
//Get the square root of the parts
result = (int)Math.Sqrt(underRadical);
//Return our result
return result;
}
public static long Distance2D(Point one, Point two)
{
return AStar.Distance2D(one.X, one.Y, two.X, two.Y);
}
}
The PriorityQueue code:
class PriorityQueue<P, V>
{
private SortedDictionary<P, Queue<V>> list = new SortedDictionary<P, Queue<V>>();
public void Enqueue(P priority, V value)
{
Queue<V> q;
if (!list.TryGetValue(priority, out q))
{
q = new Queue<V>();
list.Add(priority, q);
}
q.Enqueue(value);
}
public V Dequeue()
{
// will throw if there isn’t any first element!
var pair = list.First();
var v = pair.Value.Dequeue();
if (pair.Value.Count == 0) // nothing left of the top priority.
list.Remove(pair.Key);
return v;
}
public bool IsEmpty
{
get { return !list.Any(); }
}
}
And the interface that gets nearby nodes:
interface IHasNeighbours<N>
{
IEnumerable<N> Neighbours { get; }
}
This is the part I'm having trouble effectively implementing. I can create a class capable of being used by the path finding, but finding the nearby nodes is becoming a pain. Essentially what I end up doing is creating a class that, in this case, counts as a single tile. However, in order to get all the nearby nodes, I have to pass a value into that tile that includes a list of all other tiles. This is very cumbersome and leads me to believe there must be an easier method.
Here is my implementation using a wrapper for System.Drawing.Point:
class TDGrid : IHasNeighbours<TDGrid>, IEquatable<TDGrid>
{
public Point GridPoint;
public List<Point> _InvalidPoints = new List<Point>();
public Size _GridSize = new Size();
public int _GridTileSize = 50;
public TDGrid(Point p, List<Point> invalidPoints, Size gridSize)
{
GridPoint = p;
_InvalidPoints = invalidPoints;
_GridSize = gridSize;
}
public TDGrid Up(int gridSize)
{
return new TDGrid(new Point(GridPoint.X, GridPoint.Y - gridSize));
}
public TDGrid Down(int gridSize)
{
return new TDGrid(new Point(GridPoint.X, GridPoint.Y + gridSize));
}
public TDGrid Left(int gridSize)
{
return new TDGrid(new Point(GridPoint.X - gridSize, GridPoint.Y));
}
public TDGrid Right(int gridSize)
{
return new TDGrid(new Point(GridPoint.X + gridSize, GridPoint.Y));
}
public IEnumerable<TDGrid> IHasNeighbours<TDGrid>.Neighbours
{
get { return GetNeighbours(this); }
}
private List<TDGrid> GetNeighbours(TDGrid gridPoint)
{
List<TDGrid> retList = new List<TDGrid>();
if (IsGridSpotAvailable(gridPoint.Up(_GridTileSize)))
retList.Add(gridPoint.Up(_GridTileSize)); ;
if (IsGridSpotAvailable(gridPoint.Down(_GridTileSize)))
retList.Add(gridPoint.Down(_GridTileSize));
if (IsGridSpotAvailable(gridPoint.Left(_GridTileSize)))
retList.Add(gridPoint.Left(_GridTileSize));
if (IsGridSpotAvailable(gridPoint.Right(_GridTileSize)))
retList.Add(gridPoint.Right(_GridTileSize));
return retList;
}
public bool IsGridSpotAvailable(TDGrid gridPoint)
{
if (_InvalidPoints.Contains(gridPoint.GridPoint))
return false;
if (gridPoint.GridPoint.X < 0 || gridPoint.GridPoint.X > _GridSize.Width)
return false;
if (gridPoint.GridPoint.Y < 0 || gridPoint.GridPoint.Y > _GridSize.Height)
return false;
return true;
}
public override int GetHashCode()
{
return GridPoint.GetHashCode();
}
public override bool Equals(object obj)
{
return this.GridPoint == (obj as TDGrid).GridPoint;
}
public bool Equals(TDGrid other)
{
return this.GridPoint == other.GridPoint;
}
}
The List _InvalidPoints is where I'm falling flat. I can pass this in to every TDGrid that is created but that seems like a massive waste of resources considering how simple all the rest of the code is. I know this is a lack of knowledge on my part but I haven't been able to search it down.
There must be another way to implement:
interface IHasNeighbours<N>
{
IEnumerable<N> Neighbours { get; }
}
Anyone have any ideas on this?
Edit --
Here's the path finding code:
public void FindPath(TDGrid start, TDGrid end)
{
AStar.FindPath<TDGrid>(start, end, (p1, p2) => { return AStar.Distance2D(p1.GridPoint, p2.GridPoint); }, (p1) => { return AStar.Distance2D(p1.GridPoint, end.GridPoint); });
}
It sounds like you have two separate concerns here. You need to represent the pathways between nodes and the nodes themselves. You may find it easiest to represent these two concepts separately.
For example, in the code below, the Grid class keeps track of how nodes are connected. This could be as simple as storing an hash set of the tiles that are walls (ie. obstructed). To determine if a node is reachable, check if it is in the hash set. This is just a simple example. There are many other ways you could represent a graph, see Wikipedia.
An individual Node can be represented as two coordinates on the Grid, requiring only three values: the row, the column, and the Grid itself. This allows each individual Node to be created on the fly (Flyweight pattern).
Hope that helps!
class Grid
{
readonly int _rowCount;
readonly int _columnCount;
// Insert data for master list of obstructed cells
// or master list of unobstructed cells
public Node GetNode(int row, int column)
{
if (IsOnGrid(row, column) && !IsObstructed(row, column))
{
return new Node(this, row, column);
}
return null;
}
private bool IsOnGrid(int row, int column)
{
return row >= 0 && row < _rowCount && column >= 0 && column < _columnCount;
}
private bool IsObstructed(int row, int column)
{
// Insert code to check whether specified row and column is obstructed
}
}
class Node : IHasNeighbours<Node>
{
readonly Grid _grid;
readonly int _row;
readonly int _column;
public Node(Grid grid, int row, int column)
{
_grid = grid;
_row = row;
_column = column;
}
public Node Up
{
get
{
return _grid.GetNode(_row - 1, _column);
}
}
public Node Down
{
get
{
return _grid.GetNode(_row + 1,_column);
}
}
public Node Left
{
get
{
return _grid.GetNode(_row, _column - 1);
}
}
public Node Right
{
get
{
return _grid.GetNode(_row, _column + 1);
}
}
public IEnumerable<Node> Neighbours
{
get
{
Node[] neighbors = new Node[] {Up, Down, Left, Right};
foreach (Node neighbor in neighbors)
{
if (neighbor != null)
{
yield return neighbor;
}
}
}
}
}
This was the implementation I ended up using, very similar to Special Touch's solution. SpacialObject is a Point.
public class Tile : SpacialObject, IHasNeighbours<Tile>
{
public Tile(int x, int y)
: base(x, y)
{
CanPass = true;
}
public bool CanPass { get; set; }
public Point GetLocation(int gridSize)
{
return new Point(this.X * gridSize, this.Y * gridSize);
}
public IEnumerable<Tile> AllNeighbours { get; set; }
public IEnumerable<Tile> Neighbours { get { return AllNeighbours.Where(o => o.CanPass); } }
public void FindNeighbours(Tile[,] gameBoard)
{
var neighbours = new List<Tile>();
var possibleExits = X % 2 == 0 ? EvenNeighbours : OddNeighbours;
possibleExits = GetNeighbours;
foreach (var vector in possibleExits)
{
var neighbourX = X + vector.X;
var neighbourY = Y + vector.Y;
if (neighbourX >= 0 && neighbourX < gameBoard.GetLength(0) && neighbourY >= 0 && neighbourY < gameBoard.GetLength(1))
neighbours.Add(gameBoard[neighbourX, neighbourY]);
}
AllNeighbours = neighbours;
}
public static List<Point> GetNeighbours
{
get
{
return new List<Point>
{
new Point(0, 1),
new Point(1, 0),
new Point(0, -1),
new Point(-1, 0),
};
}
}
public static List<Point> EvenNeighbours
{
get
{
return new List<Point>
{
new Point(0, 1),
new Point(1, 1),
new Point(1, 0),
new Point(0, -1),
new Point(-1, 0),
new Point(-1, 1),
};
}
}
public static List<Point> OddNeighbours
{
get
{
return new List<Point>
{
new Point(0, 1),
new Point(1, 0),
new Point(1, -1),
new Point(0, -1),
new Point(-1, 0),
new Point(-1, -1),
};
}
}
}
Then in the main program I used:
private void InitialiseGameBoard()
{
GameBoard = new Tile[_Width, _Height];
for (var x = 0; x < _Width; x++)
{
for (var y = 0; y < _Height; y++)
{
GameBoard[x, y] = new Tile(x, y);
}
}
AllTiles.ToList().ForEach(o => o.FindNeighbours(GameBoard));
int startX = 0, endX = GameBoard.GetLength(0) - 1;
int startEndY = GameBoard.GetLength(1) / 2;
_StartGridPoint = new Point(startX, startEndY);
_EndGridPoint = new Point(endX, startEndY);
//GameBoard[startX, startEndY].CanPass = false;
//GameBoard[endX, startEndY].CanPass = false;
}
private void BlockOutTiles()
{
GameBoard[2, 5].CanPass = false;
GameBoard[2, 4].CanPass = false;
GameBoard[2, 2].CanPass = false;
GameBoard[3, 2].CanPass = false;
GameBoard[4, 5].CanPass = false;
GameBoard[5, 5].CanPass = false;
GameBoard[5, 3].CanPass = false;
GameBoard[5, 2].CanPass = false;
}
public IEnumerable<Tile> AllTiles
{
get
{
for (var x = 0; x < _Width; x++)
for (var y = 0; y < _Height; y++)
yield return GameBoard[x, y];
}
}
I wrote this code
I have these errors
Cannot implicitly convert type x.Program.TreeNode' to 'int' // on findmin
Cannot implicitly convert type x.Program.TreeNode' to 'int' // on findmax
and is my main correct or missing somethin?
and how i can count the nodes,leaves and get the hight (need only hints)
class Program
{
static void Main(string[] args)
{
BinarySearchTree t = new BinarySearchTree();
t.insert(ref t.root, 10);
t.insert(ref t.root, 5);
t.insert(ref t.root, 6);
t.insert(ref t.root, 17);
t.insert(ref t.root, 2);
t.insert(ref t.root, 3);
BinarySearchTree.print(t.root);
}
public class TreeNode
{
public int n;
public TreeNode _left;
public TreeNode _right;
public TreeNode(int n, TreeNode _left, TreeNode _right)
{
this.n = n;
this._left = _left;
this._right = _right;
}
public void DisplayNode()
{
Console.Write(n);
}
}
public class BinarySearchTree
{
public TreeNode root;
public BinarySearchTree()
{
root = null;
}
public void insert(ref TreeNode root, int x)
{
if (root == null)
{
root = new TreeNode(x, null, null);
}
else
if (x < root.n)
insert(ref root._left, x);
else
insert(ref root._right, x);
}
public int FindMin()
{
TreeNode current = root;
while (current._left != null)
current = current._left;
return current;
}
public int FindMax()
{
TreeNode current = root;
while (current._right != null)
current = current._right;
return current;
}
public TreeNode Find(int key)
{
TreeNode current = root;
while (current.n != key)
{
if (key < current.n)
current = current._left;
else
current = current._right;
if (current == null)
return null;
}
return current;
}
public void InOrder(ref TreeNode root)
{
if (root != null)
{
InOrder(ref root._left);
root.DisplayNode();
InOrder(ref root._right);
}
}
public static void print(TreeNode root)
{
if (root != null)
{
print(root._left);
Console.WriteLine(root.n.ToString());
print(root._right);
}
}
Since you need (FindMin/FindMax) to return an int, do you mean current.n?
Updated: for counting leaves and nodes, how about (as instance methods of TreeNode):
public int CountNodes()
{
int count = 1; // me!
if (_left != null) count += _left.CountNodes();
if (_right != null) count += _right.CountNodes();
return count;
}
public int CountLeaves()
{
int count = (_left == null && _right == null) ? 1 : 0;
if (_left != null) count += _left.CountLeaves();
if (_right != null) count += _right.CountLeaves();
return count;
}
If I've missed the point, let me know...
Your FindMin() and FindMax() methods are trying to return TreeNode objects but the signature says they returns ints. As it doesn't appear that the methods are used in the program, prehaps you could remove them?