views:

86

answers:

4

I have a text file that should initialize my objects, which are built around a component based model, it is my first time trying to use a data driven approach and i'm not sure if i am heading in the right direction here.

The file i have currently in mind looks like this

EliteGoblin.txt

@Goblin.txt


[general]
hp += 20
strength = 12
description = "A big menacing goblin"
tacticModifier +=  1.3

[skills]
fireball

Where the @ symbol says which other files to parse at at that point The names in [] correspond with component classes in the code And below them is how to configure them

For example the hp += 20 would increase the value taken from goblin.txt and increase it by 20 etc.

My question is how i should go about parsing this file, is there some sort of parser built in C#?

Could i change the format of my document to match already defined format that already has support in .net?

How do i go about understanding what type is each value? int/float/string

Does this seem a viable solution at all?

Thanks in advance, Xtapodi.

+11  A: 

Drop the flat file and pick up XML. Definately look into XML Serialization. You can simply create all of your objects in C# as classes, serialize them into XML, and reload them into your application without having to worry about parsing a flat file out. Because your objects will act as the schema for your XML, you won't have to worry about casting objects and writing a huge parsing routine, .NET will handle it for you. You will save many moons of headache.

For instance, you could rewrite your class to look like this:

public class Monster
{
     public GeneralInfo General {get; set;}
     public SkillsInfo  Skills {get; set;}
}
public class GeneralInfo
{
  public int Hp {get; set;}
  public string Description {get; set;}
  public double TacticModifier {get; set;}
}
public class SkillsInfo
{
  public string[] SkillTypes {get; set;}
}

...and your XML would get deserialized to something like...

<Monster>
   <General>
       <Hp>20</Hp>
       <Description>A big menacing goblin</Description>
       <TacticModifier>1.3</TacticModifier>
   </General>
   <SkillTypes>
        <SkillType>Fireball</SkillType>
        <SkillType>Water</SkillType>
   </SkillTypes>
</Monster>

..Some of my class names, hierarchy, etc. may be wrong, as I punched this in real quick, but you get the general gist of how serialization will work.

George
Took the words right out of my mouth.
Steven Sudit
Since these files are used as my input in the program and are written by a human and not a program i was thinking that XML would actually make it harder to get in fast and make a change or add something. Do you suggest that even so i should go with XML?
Xtapodi
@George Ah i see that you refined your answer, truth is i haven't looked into serialization, i will try and read about it now. One thing that maybe i should mention is that in some cases it is not known what the members actually are, but a dictionary is being used instead, sort of a blackboard
Xtapodi
It all depends on your user base. If you are concerned about the user writing out XML, create a simple editor to handle it for you. You'll actually save time in the end.
George
Serialization is very simple, you should be up and running in no time. ;)
George
@George Thank you for the example code, i will try to make a small project to experiment with these and get back to you. I am getting a bit confused with the component model i am trying to build at the same time. Ah time to experiment.
Xtapodi
@George By the way, how would you tackle the inheritance of data displayed in my initial example?
Xtapodi
The simplest way would be to have a base monster, which you already have, load the new monster modifier from the XML, and essentially pass it into a function that would go through the monster modifier properties and add them together with the base monster properties.
George
I honestly don't consider XML hard to edit. However, if you want something that's perhaps simpler, but is also well-supported as a serialization format, try JSON.
Steven Sudit
A: 

What you want to do isn't going to be easy. The statistic inheritance in particular.

So, unless you can find some existing code to leverage, I suggest you start with simpler requirements with a view to adding the more involved functionality later and build up the functionality incrementally.

Phil
I was thinking that if i could make it read one file, it shouldn't be that much harder to make hierarchies for my data so that i don't duplicate them, but i've never done it before so it might well be trickier than i think.
Xtapodi
Things are always trickier than we think. Over confidence is a trait common in programmers. :) Anyway, I think it's quite possible to do what you want but it might not be neccessary. If you do everything in the most simple way to begin with you can test your ideas out. You'll quickly see where optimisations will be most beneficial. Of course this is your project so don't let me talk you out of doing something you really want to.
Phil
+1  A: 

You might want to check out Sprache, a .net library that can create DSL' s by Autofac creator Nicholas Blumhardt. From the google site:

Sprache is a small library for constructing parsers directly in C# code.

It isn't an "industrial strength" framework - it fits somewhere in between regular expressions and a full-blown toolset like ANTLR.

Usage Unlike most parser-building frameworks, you use Sprache directly from your program code, and don't need to set up any build-time code generation tasks. Sprache itself is a single tiny assembly.

A simple parser might parse a sequence of characters:

// Parse any number of capital 'A's in a row var parseA = Parse.Char('A').AtLeastOnce(); Sprache provides a number of built-in functions that can make bigger parsers from smaller ones, often callable via Linq query comprehensions:

Parser identifier = from leading in Parse.Whitespace.Many() from first in Parse.Letter.Once() from rest in Parse.LetterOrDigit.Many() from trailing in Parse.Whitespace.Many() select new string(first.Concat(rest).ToArray());

var id = identifier.Parse(" abc123 ");

Assert.AreEqual("abc123", id);

The link to the article builds a questionaire that is driven by a simple text file with the following format:

identification  "Personal Details"
[
    name        "Full Name"
    department  "Department"
]

employment      "Current Employer"
[
    name        "Your Employer"
    contact     "Contact Number"
    #months     "Total Months Employed"
]
David Robbins
Thank you very much David Robbins. Long gone the times i used flex and bison in the university. i will check more into it to see how i could apply it.
Xtapodi
+1  A: 

There is no builtin function to do exactly what you want to do, but you can easily write it.

    void ParseLine(string charClass, string line) {
        // your code to parse line here...
        Console.WriteLine("{0} : {1}", charClass, line);
    }
    void ParseFile(string fileName) {
        string currentClass = "";
        using (StringReader sr = new StringReader(fileName)) {
            string line = sr.ReadLine();
            if (line[0] == '@') {
                string embeddedFile = line.Substring(1);
                ParseFile(embeddedFile);
            }
            else if (line[0] == '[') {
                currentClass = line.Substring(2, line.Length - 2);
            }
            else ParseLine(currentClass, line);
        }
    }
KalEl