3

I am making a text adventure and whenever a player types "pick up the iron sword" or whatever, I need to be able to take the iron sword OUT of the JSON array within the room that it is kept in.

{
Rooms: [
    {
        id: "PizzaShop1",
        name: "Pizza Shop",
        description: "in a nice warm pizza shop that smells of garlic.",
        items: [
            {
                id: "HawaiianPizza1",
                name: "Hawaiian Pizza",
                description: "a pizza topped with ham and pineapple",
                strengthMod: 0,
                toughnessMod: 0
            },
            {
                id: "MeatloversPizza1",
                name: "Meatlovers Pizza",
                description: "a pizza topped with lots of meat",
                strengthMod: 0,
                toughnessMod: 0
            }
        ],
        entities: [
            {
                name: "Pizza Chef",
                description: "an italian man",
                friendly: true
            },
            {
                name: "Mouse",
                description: "a pesky mouse",
                friendly: false
            }
        ],
        northExit: "",
        southExit: "Road1",
        eastExit: "",
        westExit: ""
    },     
    {
        id: "Road1",
        name: "Road",
        description: "on a town road",
        items: [
            {
                id: "IronSword1",
                name: "Iron Sword",
                description: "a battered but usable sword",
                strengthMod: 2,
                toughnessMod: 0
            }
        ],
        entities: [],
        northExit: "PizzaShop1",
        southExit: "",
        eastExit: "",
        westExit: ""
    }
]
}

And here is my c# code:

                else if (s.Contains(" pick up "))
            {
                String newJson = "";
                s = s.Replace(" the ", " ");
                s = s.Replace(" pick ", " ");
                s = s.Replace(" up ", " ");
                String[] Words = s.Split(' ');
                foreach (String word in Words)
                {
                    if (word != Words[1])
                    {
                        Words[1] = Words[1] + " " + word;
                        Words[1] = Words[1].Replace("  ", " ");
                        Words[1] = Words[1].Trim();
                    }
                }
                using (StreamReader sr = new StreamReader("TAPResources/map.json"))
                {
                    String json = sr.ReadToEnd();
                    dynamic array = JsonConvert.DeserializeObject(json);
                    foreach (var rooms in array["Rooms"])
                    {
                        foreach (var item in rooms["items"])
                        {
                            String itm = (String)item["name"];
                            PrintMessage("Words: " + Words[1]);
                            PrintMessage("Item Name: " + itm.ToLower());
                            if (Words[1] == itm.ToLower())
                            {
                                rooms["items"].Remove(item);
                            }
                        }
                    }
                    newJson = (String)JsonConvert.SerializeObject(array);
                }
                File.WriteAllText("TAPResources/map.json", newJson);
            }

The line:

rooms["items"].Remove(item);

Gives an error, because I can't edit the array within the loop. Normally I would solve this by adding the value to another array, then iterating through that array to remove from the initial array, but I don't know how to make an array for that variable type.

Ashley
  • 449
  • 4
  • 13
  • Possible duplicate of [Read and parse a Json File in C#](http://stackoverflow.com/questions/13297563/read-and-parse-a-json-file-in-c-sharp) – Mostafiz Apr 22 '16 at 04:32
  • Not a duplicate, I have already read this and it didn't help me at all. – Ashley Apr 22 '16 at 04:38
  • You're going to have to do something with the result of `JsonConvert.SerializeObject(array);`, such as writing it back to your json file. – Bart van Nierop Apr 22 '16 at 04:43
  • 2
    First, you look up the return type of [`JsonConvert.SerializeObject`](http://www.newtonsoft.com/json/help/html/SerializingCollections.htm), which turns out to be `string`. Then you [look up](https://encrypted.google.com/search?q=c%23+write+string+to+file) how to write a `string` to a file. Finally, type in the required code. – Bart van Nierop Apr 22 '16 at 04:53

2 Answers2

2

You probably want to add classes that represent the game, rooms and items, and then keep them in memory while the game is playing. When they save the game you can serialize it back into JSON. It is easier to work with objects than to try and loop through the whole document rooms and each of the items to find one item and remove it.

I would suggest the following classes based on your Json document:

public class Item
{
    public string id { get; set; }
    public string name { get; set; }
    public string description { get; set; }
    public int strengthMod { get; set; }
    public int toughnessMod { get; set; }
}

public class Room
{
    public string id { get; set; }
    public string name { get; set; }
    public string description { get; set; }
    public List<Item> items { get; set; }
    public List<object> entities { get; set; }
    public string northExit { get; set; }
    public string southExit { get; set; }
    public string eastExit { get; set; }
    public string westExit { get; set; }
}

public class Game
{
    public List<Room> Rooms { get; set; }
}

Then you can deserialize your JSON into a Game object like this:

var game = JsonConvert.DeserializeObject<Game>(json);

Then if you want to remove the sword from the "Road1" room it's much more concise than looping through the dynamic object:

//Find room by id and remove item by id
game.Rooms.Single(room => room.id == "Road1")
    .items.RemoveAll(item => item.id == "Iron Sword");

//Turn the game object back into a Json string
var json = JsonConvert.SerializeObject(game);

//now write json string back to storage...

This gives you more flexibility during runtime. For example, it becomes really easy to add a new room on the fly:

var room = new Room
        {
            id = "new room",
            name = "very cool room",
            description = "A very cool room that was added on the fly",
            items = new List<Item> 
                        { 
                          new Item 
                               { 
                                 id = "another sword", 
                                 description = "Another battered sword"
                                 //etc...
                                } 
                          }
            //etc...
        }

game.Rooms.Add(room);

Hope this helps.

cnaegle
  • 1,125
  • 1
  • 10
  • 12
  • Thanks heaps, but I dont really understand what `game.Rooms.Single(room => room.id == "Road1") .items.RemoveAll(item => item.id == "Iron Sword");` is doing – Ashley Apr 22 '16 at 05:57
  • It's a Linq statement. Think of game as your document. It has a list of all the rooms and each room has a list of items. The first part: game.room.Single(room => room.id == "Road1") is saying find the Single room in the game that has an id of "Road1" the second part .items.RemoveAll(item => item.id =="Iron Sword") is saying find the item in the room we just looked for with the id of "Iron Sword" and remove it. Linq is a powerful syntax for working with collections. You are going to want to learn it if you code in C#. Copy and paste the code and play around with it. – cnaegle Apr 22 '16 at 06:07
  • Thanks heaps! I am still quite new to C#. – Ashley Apr 22 '16 at 06:19
  • I need to update data in the json file..And this is the way to go! – Alexander Sep 23 '18 at 20:56
2

Ok so here we go, ideally is recommended to use well defined objects (classes) case using dynamic objects is a slower processing, any how:

dynamic array = GetRooms();

    foreach (var rooms in array["Rooms"])
    {
        List<object> list = new List<object>();
        foreach (var item in rooms["items"])
        {
            string itm = (string) item["name"];
            if (!"hawaiian pizza".Equals(itm.ToLower()))
            {
                list.Add(item);
            }
        }
        //u can use this 
        //from rooms in array["Rooms"] select rooms where (true something)
        //or what I did case I'm lazy
        //Newtonsoft.Json.Linq.JToken transfor or you can use linq to dow whatever 
        rooms["items"] = JsonConvert.DeserializeObject<JToken>(JsonConvert.SerializeObject(list.ToArray()));
    }
    Console.Write(JsonConvert.SerializeObject(array));
SilentTremor
  • 4,747
  • 2
  • 21
  • 34