How to serialize/deserialize an object matrix to/from xml in C#? - c#

I have an assignment to save and load a Minesweeper board. I'm having issues saving the board matrix. These are my Minesweeper properties:
[XmlIgnore]
public Tile[,] Grid { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public int NumberOfMines { get; set; }
Tile properties:
public int X { get; set; }
public int Y { get; set; }
public int NeighbourMines { get; set; }
public bool IsMine { get; set; }
public bool IsRevealed { get; set; }
public bool IsFlagged { get; set; }
I tried something like this:
public List<Tile> ListFromMatrix
{
get
{
List<Tile> temp = new List<Tile>(Height * Width);
for (int i = 0; i < Height; i++)
for (int j = 0; j < Width; j++)
temp.Add(Grid[i, j]);
return temp;
}
set
{
//Grid = new Tile[Height, Width];
int it = 0;
for (int i = 0; i < Height; i++)
for (int j = 0; j < Width; j++)
Grid[i, j] = value[it++];
}
}
Saving into the file works fine, but loading from it causes an exception. And I really don't know how to debug it since the exception is thrown at:
//this.Game is the Minesweeper reference in the main form
this.Game = (Game)xs.Deserialize(fileStream);
Any help is appreciated!
EDIT: This is the exception
System.InvalidOperationException: 'There is an error in XML document (7, 4).
Inner Exception 1: NullReferenceException: Object reference not set to an instance of an object.
EDIT2: Save code
SaveFileDialog sfd = new SaveFileDialog();
if (sfd.ShowDialog() == DialogResult.OK)
{
using (FileStream fs = new FileStream(sfd.FileName, FileMode.Create))
{
XmlSerializer xs = new XmlSerializer(typeof(Game));
xs.Serialize(fs, this.Game);
}
}
EDIT3: Here are the xml contents https://pastebin.com/0vkxQC5A
EDIT4: Thank you for trying but nothing works with this so I will just rewrite the code to use a list instead of the matrix.

You might try changing your set like so:
set
{
var height = value.Max(t=>t.Y);
var width = value.Max(t=>t.X);
Grid = new Tile[height, width];
foreach(var tile in value)
{
Grid[tile.Y,tile.X]=tile;
}
}
You probably don't want to use the height and width properties from the game object, because then you would need to assume those get set prior to this property. Might as well just calculate them yourself. And while you are at it, might as well just change get as well, and then throw away Height/Width, or change them to actually pull the current width/height of the Grid:
get
{
var temp = new List<Tile>(Grid.Length);
for (int i = 0; i < Grid.GetLength(0); i++)
for (int j = 0; j < Grid.GetLength(1); j++)
temp.Add(Grid[i, j]);
return temp;
}

It appears the error is in deserializing your property ListFromMatrix.
public List<Tile> ListFromMatrix {get; set;}
// when it comes time to serialize
ListFromMatrix = CreateList();
using (FileStream fs = new FileStream(sfd.FileName, FileMode.Create))
{
XmlSerializer xs = new XmlSerializer(typeof(Game));
xs.Serialize(fs, this.Game);
}
private List<Tile> CreateList()
{
var temp = new List<Tile>(Height * Width);
for (int i = 0; i < Height; i++)
for (int j = 0; j < Width; j++)
temp.Add(Grid[i, j]);
return temp;
}

Related

Reading string from a file to 2d array

i'm trying to convert a string from file to 2d array. Is it possible to make the array dynamic? And how can i return the array, so i can work with it? I'm really confused.
public interface IMazeLoader
{
Maze LoadMaze(string src);
}
class MazeLoader : IMazeLoader
{
public Maze LoadMaze(string filepath)
{
var width = 5;
var height = 5;
var map = new char[width, height];
var file = new StreamReader(filepath);
string line;
var lineCount = 0;
while ((line = file.ReadLine()) != null)
{
if (lineCount < height)
{
for (int i = 0; i < width && i < line.Length; i++)
{
map[i, lineCount] = line[i];
}
}
lineCount++;
}
file.Close();
return;
}
}
Here is my Maze class :
public class Maze
{
public static readonly char CHAR_WALL = '#';
public static readonly char CHAR_START = 'S';
public static readonly char CHAR_FINISH = 'F';
public int Width { get; internal set; }
public int Height { get; internal set; }
public int StartX { get; private set;}
public int StartY { get; private set; }
public int StartAngle { get; private set; }
private char[,] _plan;
public char[,] Plan { get { return _plan; } }
public Maze(char[,] plan)
{
}
Thanks for any reply, happy Eastern btw. :)
Something like this should allow you to load any rectangular dimension map:
public class MazeLoader : IMazeLoader
{
public Maze LoadMaze(string filepath)
{
char[][] loaded =
File
.ReadLines(filepath)
.Select(x => x.ToCharArray())
.ToArray();
int[] widths =
loaded
.Select(x => x.Length)
.Distinct()
.ToArray();
if (widths.Length != 1)
{
throw new InvalidDataException("Map Data Not Rectangular");
}
else
{
var width = widths[0];
var height = loaded.Length;
var map = new char[height, width];
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
map[i, j] = loaded[i][j];
return new Maze(map);
}
}
}
Now I tested this on this input:
aaaa
aaaa
bbbb
bbbb
bbbb
And got this map:
Please note that the file orientation and the map orientation are the same. I had to flip around how you were building our your map to get that to work.
Here's my alterations to Maze itself:
public class Maze
{
public int Width => this.Plan.GetUpperBound(1) - this.Plan.GetLowerBound(1) + 1;
public int Height => this.Plan.GetUpperBound(0) - this.Plan.GetLowerBound(0) + 1;
public char[,] Plan { get; private set; }
public Maze(char[,] plan)
{
this.Plan = plan;
}
}

c# array of objects System.ArrayTypeMismatchException: 'Attempted to access an element as a type incompatible with the array.'

i'm trying to store objects in array, but i recive error - System.ArrayTypeMismatchException: 'Attempted to access an element as a type incompatible with the array.' I was looking for answer but still can't figure it out. It seemed to me that if i use arrays of object type i can update array with any type of data...
my code:
{//cass.cs
public class Map
{
private int Rows { get; set; }
private int Cols { get; set; }
private string[,] Grid { get; set; }
private Object[,] BoardTiles { get; set; }
public Map(int rows, int cols)
{
this.Rows = rows;
this.Cols = cols;
this.BoardTiles = new string[rows, cols];
}
public void printBoard(int playerPositionRowIndex, int playerPositionColumnIndex)
{
Floor floor = new Floor("floor", 1);
for (int r = 0; r < Rows; r++)
{
for (int c = 0; c < Cols; c++)
{
if (r == playerPositionRowIndex && c == playerPositionColumnIndex)
{
BoardTiles[r, c] = floor; //this place will be changed
Console.Write("#");
}
else
{
BoardTiles[r, c] = floor;
Console.Write("*");
}
}
Console.WriteLine();
}
}
}
{//floor.cs
public class Floor
{
private string Type { get; set; }
private int Num{ get; set; }
public Floor(string type, int num)
{
this.Type = type;
this.Num = num;
}
}
}
Map map = new Map(5, 10);
map.printBoard(4, 3);

Is there a way to get the object located in the coordinates retrieved from a 2d array to compare it?

I am trying to print the coordinates if my object is found in the 2D array. Am using .Equals but it seems to be ignoring it.
private void PrintCarInfo(Car car, object[,] matrix)
{
int xCoordinate = 0;
int yCoordinate = 0;
int w = matrix.GetLength(0);
int h = matrix.GetLength(1);
for (int x = 0; x < w; ++x)
{
for (int y = 0; y < h; ++y)
{
if (matrix[x, y].Equals(car))
{
xCoordinate = x;
yCoordinate = y;
}
}
}
}
This is the Car class:
public class Car
{
public int Index { get; set; }
public string Name { get; set; }
public bool Manual { get; set; }
public bool Diesel { get; set; }
public Car()
{
}
public Car(Car car)
{
Index = car.Index;
Name = car.Name;
Manual = car.Manual;
Diesel = car.Diesel;
}
}
This is what I get when debug from the 2D array:
[1,1] {Toyota (15)}
Am using .Equals but it seems to be ignoring it.
Yes,
if (matrix[x, y].Equals(car))
will only work
When car is a reference to an instance in the matrix, or
When you override Car.Equals
The default comparison for classes is Reference Equality. That will only work when the search element car is the exact same object as is in the matrix.
When you want to compare to a different object but with the same property values, you will have to implement Equality by yourself.

C# enter value into multidimensional array

I am build a program with c#, and have included dataGridView on it. I do math operation on that dataGridView data, then insert the result into multidimensional array. But i got error message that say "Object reference not set to an instance of an object".
here my code:
frm_clustering.cs
public void hitungMatriksJarak()
{
clusteringModel cm = new clusteringModel();
int i = 0;
int j = 0;
for (i = 0; i < this.dgv_clustering.Rows.Count; i++)
{
for (j = 0; j < this.dgv_clustering.Rows.Count; j++)
{
cm.matriks[j,i] = Math.Sqrt(Math.Pow(Convert.ToDouble(this.dgv_clustering[1, i].Value), 2) +
Math.Pow(Convert.ToDouble(this.dgv_clustering[2, i].Value), 2) +
Math.Pow(Convert.ToDouble(this.dgv_clustering[3, i].Value), 2) +
Math.Pow(Convert.ToDouble(this.dgv_clustering[4, i].Value), 2));
}
}
}
clusteringModel.cs:
class clusteringModel
{
private int _jmlKel;
public int jmlKel
{
get { return _jmlKel; }
set { _jmlKel = value; }
}
private double[,] _matriks = new double[500,500];
public double[,] matriks
{
get { return _matriks; }
set { _matriks = value; }
}
}

Fast save\load big data

I have the following class:
public class HPChartGraphPoint
{
public int Keyword { get; set; }
public List<long> Points { get; set; }
public HPChartGraphPoint()
{
Points = new List<long>();
}
public string SerializeToString()
{
var sb = new StringBuilder();
sb.Append(Keyword);
sb.Append(":");
for (int i = 0; i < Points.Count; i++)
{
sb.Append(Points[i]);
sb.Append(":");
}
return sb.ToString();
}
public static HPChartGraphPoint DesirializeFromString(string str)
{
var splitter = str.Split(new[]{":"},StringSplitOptions.RemoveEmptyEntries)
.Select(x => int.Parse(x)).ToArray();
var retPoint = new HPChartGraphPoint();
retPoint.Keyword = splitter[0];
for (int i = 1; i < splitter.Length; i++)
{
retPoint.Points.Add(splitter[i]);
}
return retPoint;
}
}
i need to store and load a collection List with millions elements. How to do it fast and memory efficient?
EDIT:
Here is code for storing
using (var sw = new StreamWriter(filePath))
{
for (int i = 0; i < HPChartGraphPointCollection.Count; i++)
{
sw.WriteLine(HPChartGraphPointCollection[i].SerializeToString());
}
}
Binary format could be more compact and easier to read/parse than text.
You could use light-weight stream wrappers: BinaryReader and BinaryWriter.

Categories

Resources