0

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.

zlatkovnik
  • 23
  • 5
  • What exception is being thrown? – nkr Nov 14 '19 at 13:46
  • I have edited the post with the exception thrown – zlatkovnik Nov 14 '19 at 14:11
  • Wouldn't use an array[,] here myself. especially when needing serialisation. I'd have gone for a simple List then calculated the reguired Index e.g IndexOfTile = Game.Height * row + column. – Tony Hopkinson Nov 14 '19 at 14:11
  • I was thinking of rewriting everything because of that, but I wanted a more elegant solution. – zlatkovnik Nov 14 '19 at 14:13
  • Tip from an old hand, go for get it working first. – Tony Hopkinson Nov 14 '19 at 14:37
  • @zlatkovnik Can you post your serialization code that saves the game to xml? – BryanJ Nov 14 '19 at 14:53
  • When I get back home I'll post it in edit – zlatkovnik Nov 14 '19 at 15:24
  • @BryanJ I have added the code in EDIT2 – zlatkovnik Nov 14 '19 at 18:39
  • @zlatkovnik note sure if this related, but it looks like you are ignoring Grid during serialization, however, based on your code, I don't see where Grid is ever created. I assume it will be null when your game gets deserialized, and that could be the issue. Also, perhaps posting the resulting xml (if it's not too large) may help. – BryanJ Nov 14 '19 at 19:08
  • @BryanJ I have posted the xml. I am ignoring grid because xml can't serialize a matrix, even initializing the matrix in the property "ListFromMatrix" doesn't work. With that property I thought I can convert the list into a matrix in deserialization. – zlatkovnik Nov 14 '19 at 19:20
  • @zlatkovnik I think it's failing because it is trying to deserialize the property ListFromMatrix but can't. It may be better if ListFromMatrix is also implemented with {get; set} and before you serialize, you call a method to populate the list (so it gets set), and then when you deserialize, it will be set by the serializer. – BryanJ Nov 14 '19 at 19:35
  • Do you still need an answer for this? The easiest way to do it is to use a surrogate jagged 2d array property as shown here: https://dotnetfiddle.net/vm6Nfv – dbc Nov 15 '19 at 18:20
  • check once here https://stackoverflow.com/a/11448270/7300644 – Sandeep Jadhav Feb 16 '21 at 14:44

2 Answers2

0

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;
}
Robert McKee
  • 21,305
  • 1
  • 43
  • 57
0

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;
}
BryanJ
  • 8,485
  • 1
  • 42
  • 61