I have an object which is a List within a List:
public List<List<MyObject>> Grid { get; set; }
I have noticed that sometimes when I do:
Grid[currentShape.ColumnNumber].Remove(currentShape);
It removes two objects from the array.
The way in which I populate the Grid object is if a certain condition is met, then I basically do:
Grid[newShape.ColumnNumber].Add(newShape);
currentShape = newShape;
currentShape is a class variable which I use to move around the object on the screen. Is it because of a Reference Type that when I sometimes do .Remove(), it deletes more than one object from the array? Do I need to extend the .Remove() somehow?
Any help is highly appreciated.
Update - The entire method:
public void MoveIfPossible(MoveDirection direction)
{
List<Shape> neighbouringShapes = new List<Shape>();
switch (direction)
{
case MoveDirection.Right:
if (currentShape.ColumnNumber == utilities.columns.Count - 1)
return;
neighbouringShapes = GetNeighbouringShapes(currentShape.ColumnNumber);
foreach (var s in neighbouringShapes)
{
if (currentShape.Position.X + 1 < s.Position.X && currentShape.Position.Y + currentShape.Texture.Height >= s.Position.Y)
{
return;
}
}
world.Grid[currentShape.ColumnNumber].Remove(currentShape);
world.Grid[currentShape.ColumnNumber + 1].Add(currentShape);
currentShape.Position.X = utilities.columns[currentShape.ColumnNumber + 1].X;
currentShape.ColumnNumber++;
currentShape.Coordinate.X = currentShape.ColumnNumber;
currentShape.Coordinate.Y = world.Grid[currentShape.ColumnNumber].Count - 1;
break;
case MoveDirection.Left:
if (currentShape.ColumnNumber == 0)
return;
neighbouringShapes = GetNeighbouringShapes(currentShape.ColumnNumber - 1);
foreach (var s in neighbouringShapes)
{
if (currentShape.Position.X - 1 > s.Position.X && currentShape.Position.Y + currentShape.Texture.Height >= s.Position.Y)
{
return;
}
}
world.Grid[currentShape.ColumnNumber].Remove(currentShape);
world.Grid[currentShape.ColumnNumber - 1].Add(currentShape);
currentShape.Position.X = utilities.columns[currentShape.ColumnNumber - 1].X;
currentShape.ColumnNumber--;
currentShape.Coordinate.X = currentShape.ColumnNumber;
currentShape.Coordinate.Y = world.Grid[currentShape.ColumnNumber].Count;
break;
}
}
Related
I am trying to write a markup editor in c#, part of is is to detect which tags are affecting where the caret currently is.
Examples:
<b>Tes|ting</b><u><i>Testing</i>Testing</u> (caret '|' at index 6)
Answer: [b]
<b>Testing<u><i>Test|ing</i>Tes</b>ting</u> (caret '|' at index 20)
Answer: [b, u, i]
Here is the code I have currently, inside "GetTags()" I split the string into 2 queues representing what tags are in front and behind where the caret is. I played around with ways to pop the elements from both queues to try to solve the problem but I keep getting wrong results. I think im on the right track creating 2 data structures but I don't know if Queue<> is what I need.
public class Tag
{
public enum TagType
{
bold,
italic,
underline,
}
public TagType type;
public bool opening;
public Tag(TagType type, bool opening)
{
this.type = type;
this.opening = opening;
}
public static Tag GetTagFromString(string str)
{
switch (str)
{
case "<b>": return new Tag(TagType.bold, true);
case "</b>": return new Tag(TagType.bold, false);
case "<i>": return new Tag(TagType.italic, true);
case "</i>": return new Tag(TagType.italic, false);
case "<u>": return new Tag(TagType.underline, true);
case "</u>": return new Tag(TagType.underline, false);
}
return null;
}
public static List<TagType> GetTags(string str, int index)
{
Queue<Tag> backQueue = new Queue<Tag>();
Queue<Tag> forwardQueue = new Queue<Tag>();
// populate the back queue
int i = index;
while (true)
{
int lastOpening = str.LastIndexOf('<', i);
int lastClosing = str.LastIndexOf('>', i);
if (lastOpening != -1 && lastClosing != -1)
{
string tagStr = str.Substring(lastOpening, lastClosing - lastOpening + 1);
Tag tag = GetTagFromString(tagStr);
backQueue.Enqueue(tag);
i = lastOpening - 1;
if (i < 0)
break;
}
else
break;
}
// populate the front stack
i = index;
while (true)
{
int nextOpening = str.IndexOf('<', i);
int nextClosing = str.IndexOf('>', i);
if (nextOpening != -1 && nextClosing != -1)
{
string tagStr = str.Substring(nextOpening, nextClosing - nextOpening + 1);
Tag tag = GetTagFromString(tagStr);
forwardQueue.Enqueue(tag);
i = nextClosing + 1;
}
else
break;
}
List<TagType> tags = new List<TagType>();
// populate 'tags' list with the tags affecting the index here
return tags;
}
public override string ToString()
{
string str = "<";
if (!opening)
str += "/";
switch (type)
{
case TagType.bold:
str += "b";
break;
case TagType.italic:
str += "i";
break;
case TagType.underline:
str += "u";
break;
}
str += ">";
return str;
}
}
Would love any input on how I could solve this and would greatly appreciate any issues anyone has with the code that I've provided.
I’ve written an implementation of A* that relies on sorting nodes by their F score in a sortedSet.
The sorting, in some cases, seems to insert a Node object at the 'Min' value when its compared 'F' value is actually the second lowest rather than the Min, as described. I'm completely baffled as to why this is happening. I believe it's causing the knock-on effect of causing nodeTree.Remove and nodeTree.RemoveWhere to fail, but that might be the actual cause of the issue, I'm honestly not sure - though I wouldn't know how to fix it if it is.
This is the comparer used. I assume it's relatively obvious that I'm not exactly sure how to implement these, but I think this should work as I intend.
public class FValueFirst : Comparer<PathfindingAgent.Node>
{
public override int Compare(PathfindingAgent.Node x, PathfindingAgent.Node y)
{
int result = x.F.CompareTo(y.F);
if (result == 0)
{
result = y.G.CompareTo(x.G);
}
if(x == y)
{
result = 0;
}
return result;
}
}
This is the Node object, for reference.
public class Node
{
public Cell cell;
public float G;
public float H;
public bool Opened;
public bool Closed;
public Node Previous;
public float F { get => G + H; }
}
This is the function it all occurs in. The result is deterministic, thankfully. Depending on the current destID and the particular layout of the grid's obstacles it will always get out of sort on the same iteration.
public void PathTo(Vector3Int destID)
{
SortedSet<Node> nodeTree = new SortedSet<Node>(new FValueFirst());
Vector3Int radius = PathfindingGrid.Instance.GridRadius;
NodeGrid = new Node[radius.x * 2 + 1, radius.y * 2 + 1, radius.z * 2 + 1];
Node startNode = new Node()
{
cell = PathfindingGrid.Cells[CurrentID.x, CurrentID.y, CurrentID.z],
G = 0,
H = 0
};
Node endNode = new Node()
{
cell = PathfindingGrid.Cells[destID.x, destID.y, destID.z],
G = 0,
H = 0
};
Vector3Int sID = startNode.cell.ID;
Vector3Int eID = endNode.cell.ID;
NodeGrid[sID.x, sID.y, sID.z] = startNode;
NodeGrid[eID.x, eID.y, eID.z] = endNode;
if (endNode.cell.IsOccupied) return;
nodeTree.Add(startNode);
int iterations = 0;
while(true)
{
Node node;
node = nodeTree.Min;
node.Closed = true;
nodeTree.RemoveWhere(n => n == node);
if(node == nodeTree.Min)
{
throw new Exception($"Incorrect node was removed from the tree");
}
if (node == endNode)
{
List<Node> chain = BacktraceChain(node);
Debug.Log($"Path found from {CurrentID} to {destID} with score {endNode.G} traversing {chain.Count} cells in {iterations} iterations");
DrawLine(chain, Color.white);
break;
}
List<Node> neighbours = GetNeighbours(node);
foreach(Node neighbour in neighbours)
{
if (neighbour == startNode || neighbour.Closed) continue;
float newg = Vector3Int.Distance(node.cell.ID, neighbour.cell.ID) + node.G;
if (!neighbour.Opened || newg < neighbour.G)
{
neighbour.G = newg;
neighbour.H = ManhattanHeuristic(neighbour, endNode);
neighbour.Previous = node;
if(!neighbour.Opened)
{
nodeTree.Add(neighbour);
neighbour.Opened = true;
}
else
{
nodeTree.RemoveWhere(n => n == neighbour);
nodeTree.Add(neighbour);
}
}
}
iterations++;
}
}
For posterity, I solved the issue - it was due to my inexperience with the SortedList type.
This code, found near the end of the function was to blame
if (!neighbour.Opened || newg < neighbour.G)
{
neighbour.G = newg;
neighbour.H = ManhattanHeuristic(neighbour, endNode);
neighbour.Previous = node;
if(!neighbour.Opened)
{
nodeTree.Add(neighbour);
neighbour.Opened = true;
}
else
{
nodeTree.RemoveWhere(n => n == neighbour);
nodeTree.Add(neighbour);
}
Specifically, an item in a tree cannot have its compared values modified to the point where it no longer compares correctly in that index. The item must first be removed from the list, modified, and readded.
My guess in hindsight is that, though removed immediately after modification, the tree is unable to be sufficiently traversed to access the target item due to the modification.
Thus my solution was to simply re-arrange the block so that the removal and addition occured on either side of the modification respectively, like so:
if (!neighbour.Opened || newg < neighbour.G)
{
if (neighbour.Opened)
{
if (!nodeTree.Remove(neighbour)) throw new Exception($"{neighbour} was not removed from tree");
}
else
{
neighbour.Opened = true;
}
neighbour.G = newg;
neighbour.H = ManhattanHeuristic(neighbour, endNode);
neighbour.Previous = node;
nodeTree.Add(neighbour);
}
I'm working on a multi-joystick setup where I need to build custom button mappings. And even map across devices. For example, if there is a separate joystick and throttle quadrant I need to map 'Z' or whatever, over to the throttle input. I also need to be able to check and see if there is a slider(s) available on each stick as I build the mapping profiles, etc. I cannot figure out how to just say something like:
if (joystick.HasSliders)
So far I've tried different variations of
PropertyInfo rxprop = typeof(SharpDX.DirectInput.JoystickState).GetProperty("Sliders");
However, if the joystick does not have sliders, this of course will throw an exception. If it only has a single slider, I will always get back an Int array of Sliders[] with two values, no matter if the stick only has a single slider or not. So it is not a guaranteed way to know if sliders exist, or even how many exist. If there is no second actual slider, the value Sliders[1] is always 0, but if there is a second slider it could still be in the 0 position.
Currently this is what I've been messing with:
usbjoysticks[k].Poll();
JoystickState currentState = null;
try
{
currentState = usbjoysticks[k].GetCurrentState();
//joystickmap.axisRangeMax = usbjoysticks[k].GetObjectInfoById(1);
PropertyInfo rxprop = typeof(SharpDX.DirectInput.JoystickState).GetProperty("Sliders");
var rzvalue = (int[])rxprop.GetValue(currentState, null);
var mySlider1 = rzvalue[0];
var datas = usbjoysticks[k].GetBufferedData();
foreach (var state in datas)
{
Console.WriteLine(state);
if (state.Offset == JoystickOffset.X)
{
Console.WriteLine(state.Value);
}
}
//DeviceObjectInstance my = usbjoysticks[k].GetObjectInfoByName("Sliders1");
var stuff = usbjoysticks[k].GetObjectPropertiesByName("Sliders0");
//=================
joystickmap.jX = "X";
joystickmap.axisRangeMax = usbjoysticks[k].GetObjectPropertiesByName("Y").Range.Maximum; //65535
joystickmap.jY = "Y";
if (currentState.Z != 0)
{
joystickmap.jZ = "Z";
var maxZrange = usbjoysticks[k].GetObjectPropertiesByName("Z").Range.Maximum;
joystickmap.axisRangeMax = usbjoysticks[k].GetObjectPropertiesByName("Z").Range.Maximum;
}
if (currentState.Sliders[0] != 0 || currentState.Sliders[1] != 0) //TODO possible change to Joystick State value in class object instead of text.
{
joystickmap.SLD1 = "Slider1";
//joystickmap.jZ = "Sliders";
joystickmap.jsSliders = currentState.Sliders;
var maxSld1range = usbjoysticks[k].GetObjectPropertiesByName("Sliders0").Range.Maximum;
joystickmap.sld1 = joystickmap.jsSliders[0];
joystickmap.sld2 = joystickmap.jsSliders[1];
}
if (currentState.Sliders[1] != 0)
{
joystickmap.SLD2 = "Slider2";
}
if (currentState.RotationX != 0)
{
joystickmap.rX = "RotationX";
}
if (currentState.RotationY != 0)
{
joystickmap.rY = "RotationY";
}
if (currentState.RotationZ != 0)
{
joystickmap.rZ = "RotationZ";
//joystickmap.jZ = "RotationZ";
}
joystickmap.axisdivider = 2;
for (var b = 0; b < 20; b++)
{
//joystickmap.joybuttons.Add(currentState.Buttons[b]);
joystickmap.joybuttons[b] = (b + 1);
}
joystickmappings.Add(joystickmap);
if (!File.Exists(filename))
{
File.WriteAllText(filename, JsonConvert.SerializeObject(joystickmap));
// serialize JSON directly to a file
using (StreamWriter file = File.CreateText(filename))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(file, joystickmap);
}
}
}
catch (Exception e)
{
MessageBox.Show("USB joystick map creation failure!\n" + e.Message);
break;
}
Here, Space is a class with (xposition, yposition, zposition, length, depth, height) as its elements and there is a list of type space.
I need to check with in the list whether it follows some conditions which are in if condition.
If it satisfies, then I merge the two spaces into single space. After that, I remove both the spaces which I have used. It actually means merging of two spaces into single space.
The new List is created. Again I treat it as new list and do the same procedure until it does not satisfies the conditions.
My problem is, it is going into infinite loop. I want to resolve this.
public class MergeSpace
{
public List<Space> Mergespace(List<Space> Listofspaces)
{
foreach (Space space1 in Listofspaces)
{
foreach (Space space2 in Listofspaces)
{
//int count = 0;
if ((space1.sheight == space2.sheight)
&& (space1.sdepth == space2.sdepth)
&& (space2.xposition == space1.xposition + space1.slength)
&& (space2.yposition == space1.yposition)
&& (space2.zposition == space1.zposition)
&& (space1.semptyspace == true)
&& (space2.semptyspace == true))
{
Space space = new Space();
space.xposition = space1.xposition;
space.yposition = space1.yposition;
space.zposition = space1.zposition;
space1.slength = space1.slength + space2.slength;
space.sheight = space1.sheight;
space.sdepth = space1.sdepth;
space.semptyspace = true;
Listofspaces.Add(space);
Listofspaces.Remove(space1);
Listofspaces.Remove(space2);
Mergespace(Listofspaces);
}
public class MergeSpace
{
public List<Space> Mergespace(List<Space> Listofspaces)
{
List<Space> mergedspacelist = new List<Space>();
int count=0;
foreach (Space space1 in Listofspaces)
{
foreach (Space space2 in Listofspaces)
{
//int count = 0;
if ((space1.sheight == space2.sheight)
&& (space1.sdepth == space2.sdepth)
&& (space2.xposition == space1.xposition + space1.slength)
&& (space2.yposition == space1.yposition)
&& (space2.zposition == space1.zposition)
&& (space1.semptyspace == true)
&& (space2.semptyspace == true))
{
Space space = new Space();
space.xposition = space1.xposition;
space.yposition = space1.yposition;
space.zposition = space1.zposition;
space1.slength = space1.slength + space2.slength;
space.sheight = space1.sheight;
space.sdepth = space1.sdepth;
space.semptyspace = true;
mergedspacelist .Add(space);
count++;
}
}
}
if(count>0)
{
Mergespace(mergedspacelist );
}
}
i dont know what your actual need is, i think this will avoid the infinite loop
Your conditions always will satisfy for same instance of Space. The instance will merge with itself.
if (!space1.Equals(space2))
{
if ((space1.sheight == space2.sheight)
...
}
I have a class thats receive all crystal report req to open the form of the report(a switch and a lot of cases).
and i need to copy and paste every time this code
if (sender.GetType() == typeof(CheckBox))
{
foreach (CheckBox elemento in flowLayoutPanel1.Controls.OfType<CheckBox>())
{
if (elemento.Checked)
{
foreach (string elemento2 in ListaTodos)
{
string Name = elemento.Tag.ToString();
if (Name.Substring(Name.Length - 1, 1) == elemento2.Substring(elemento2.Length - 1, 1))
{
crParceiro.ReportDefinition.ReportObjects[Name].ObjectFormat.EnableSuppress = false;
crParceiro.ReportDefinition.ReportObjects[elemento2].ObjectFormat.EnableSuppress = false;
}
}
}
else
{
foreach (string elemento2 in ListaTodos)
{
string Name = elemento.Tag.ToString();
if (Name.Substring(Name.Length - 1, 1) == elemento2.Substring(elemento2.Length - 1, 1))
{
crParceiro.ReportDefinition.ReportObjects[Name].ObjectFormat.EnableSuppress = true;
crParceiro.ReportDefinition.ReportObjects[elemento2].ObjectFormat.EnableSuppress = true;
}
}
}
}
}
Problem: i created a function and triend to paste this part of code there... and i passed the crParceiro.ReportDefinition, and also crParceiro.ReportDefinition.ReportsObject
but it doesnt have the set property and i cant set it out and return on REF our OUT...
I tried to Return the value and Linq Expressions(it says..."object doesnt have set property") no success
**Reference of Linq Exp and Return Value: **Link here
A good example of the problem are:
ReportDefinition teste = new ReportDefinition();
teste.ReportObjects = null;
//Error: Property or idexer ...cannot be assigned to -- its read only.
what can i do? im very lost..
In the code that you posted you are NOT setting the ReportObjects to null or any other value. You are accesing items of the ReportObjects by index and changing properties of these items but not direcctly on the ReportObjects
So this should work.
private void YourMethod(ReportObjects repObjs, List<string> ListaTodos)
{
foreach (CheckBox elemento in flowLayoutPanel1.Controls.OfType<CheckBox>())
{
bool enableSuppress ;
//enableSuppress changes based on the the "elemento" being checked or not
enableSuppress = !elemento.Checked ;
foreach (string elemento2 in ListaTodos)
{
string Name = elemento.Tag.ToString();
if (Name.Substring(Name.Length - 1, 1) == elemento2.Substring(elemento2.Length - 1, 1))
{
repObjs[Name].ObjectFormat.EnableSuppress = enableSuppress;
repObjs[elemento2].ObjectFormat.EnableSuppress = enableSuppress;
}
}
}
}
Then in your current call you use it like this
if (sender.GetType() == typeof(CheckBox))
{
YourMethod(crParceiro.ReportDefinition.ReportObjects, ListaTodos) ;
}