Welcome, Guest. Please login or register.
April 26, 2024, 10:02:24 PM

Login with username, password and session length

Search:     Advanced search
we're back, baby
*
Home Help Search Login Register
f13.net  |  f13.net General Forums  |  The Gaming Graveyard  |  Game Design/Development  |  Topic: Yegolev Learns C# - was Your app's data 0 Members and 1 Guest are viewing this topic.
Pages: 1 [2] 3 4 Go Down Print
Author Topic: Yegolev Learns C# - was Your app's data  (Read 32100 times)
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #35 on: January 02, 2009, 11:16:32 AM

Alright, time has passed and I made an effort to implement something.  I may or may not have understood Tarami's directions, so I decided to KISS and see if I can just get the data structure part working for now by putting raw strings in.  I made some classes:


   class IngredientNames
   {
      List<string> myIngr = new List<string>();
         myIngr.Add("Onion");
         myIngr.Add("Water");
         myIngr.Add("Squash");
         myIngr.Add("Leaves");
         myIngr.Add("Nuts");
         myIngr.Add("Cheese");
   }
   class RecipeNames
   {
      List<string> myRecipes = new List<string>();
         myRecipes.Add("Soup");
         myRecipes.Add("Casserole");
         myRecipes.Add("Pasta");
         myRecipes.Add("Salad");
      public RecipeNames ()
      {
      Dictionary<string,string> recDic = new Dictionary<string,string>;
      foreach (string s in myRecipes)
      {
         recDic.Add(s,IngredientNames) // underpants gnomes?
      }
      }
   }


I'm reading Programming C# 3.0 as hard as I can but the whole OO business is still not quite grokked and so I'm unsure about the best way to get the values for myIngr into recDic.  I want to do something like a double-foreach like how I would poplulate a 2D array, but I am also not sure how to get that to work.  At this point I don't care if the data are paired up in any particular way, I just want to get the fill-in-recDic part working and I'll fiddle with that later.  What my insitncts tell me is that I should have the recDic bit in some third class but once again am unsure of what the best way would be to get the list from those other classes.

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
ezrast
Terracotta Army
Posts: 2125


WWW
Reply #36 on: January 02, 2009, 12:41:03 PM

You want every recipe name to be the key for a number of ingredients, right? Dictionaries are one-to-one, so recDic should probably be defined as a Dictionary<string, List<string> > or something.

recDic.Add(s,IngredientNames) is probably failing because Add is looking for strings as arguments, and IngredientNames is not a string. But at this point I should probably keep my mouth shut and let someone who knows what they're talking about answer. I do not know C#.

Anyway, more importantly, remember to post the compiler error next time.
Tarami
Terracotta Army
Posts: 1980


Reply #37 on: January 02, 2009, 04:21:17 PM

You are trying to add a string collection to a dictionary that is typed to hold single strings, which will not work... also, the myIngr list is private, meaning it can't be accessed outside of the class, which will halt the compiler even if it's fixed.

But you got it sorta right, you just need to think of objects more as... well, ordinary objects. smiley If you rearrange it a little, it'll be easier to see, I think.

OO is primarily a way to impose context on code, telling code implicitly on what data to run the logic, rather than having to pass a reference around for the thing you want modified. Therefore it helps if you simply think of objects in OO as any object you got in real life. If it can have a name, you should add a variable to the object that associates a name to the object.

In this scenario, you got ingredients and recipes, both of those making for very straight-forward classes;

Code:
class Ingredient { }
class Recipe { }

Each of these can have a name, such as "Flour" or "Sweetrolls", so add a string variable to hold that info.

Code:
class Ingredient {
    public string Name;
}
class Recipe {
    public string Name;
}

Recipes are made up by several Ingredients, which means we have to keep a list of the ingredients each recipe needs. Since each recipe has its own distinct list, we can add that info directly to the Recipe class, because no other recipe needs to access that information. It is only relevant to the recipe itself.

Code:
class Ingredient {
    public string Name;
}
class Recipe {
    public string Name;   
    public List<Ingredient> Ingredients = new List<Ingredient>(); // We need to initialize this variable, or we can't use it.
}

Now you can handle Ingredients and Recipes for what they are; self-contained objects that have all the info they need to act independently of eachother. We will do one more thing to each of the classes to ease the usage of them - add a constructor that takes a name parameter.


Code:
class Ingredient {
    public string Name;
    public Ingredient(string name) {
        Name = name;
    }
}
class Recipe {
    public string Name;   
    public List<Ingredient> Ingredients = new List<Ingredient>(); // We need to initialize this variable, or we can't use it.
    public Recipe(string name) {
        Name = name;
    }
}

Then we can initialize a recipe;

Code:
Recipe casserole = new Recipe("Italian Casserole");

Ingredient onion = new Ingredient("Onions");
Ingredient cheese = new Ingredient("Grated cheese");
Ingredient mushies = new Ingredient("Mushrooms");

casserole.Ingredients.Add(onion);
casserole.Ingredients.Add(cheese);
casserole.Ingredients.Add(mushies);

That will give you an object, with the Name "Italian Casserole" that has three Ingredients. Now you can add the Recipe to a "cookbook" of sorts, namely a dictionary. A cookbook is a collection of recipes, and each recipe has a distinct name. That makes a Dictionary<,> perfect.

Code:
Dictionary cookbook = new Dictionary<string, Recipe>(); // String, for the name of recipe, and Recipe, that holds all the relevant info.

cookbook.Add(casserole.Name, casserole);

Now you can go on and make more recipes the same way and add them to your cookbook-dictionary. To pull out a certain recipe, you only need to do;

Code:
Recipe momsCasserole = cookbook["Italian Casserole"];

foreach(Ingredient ing in momsCasserole.Ingredients) {
    Console.WriteLine(ing.Name);
}

Of course, now you got the problem that you only have the ingredients, but lack the quantities. That's a little more tricky to do in a proper way, so I'll leave that out for now.

I hope it helped anyway. Oh ho ho ho. Reallllly?

PS.
I leave no guarantees that the above actually compiles, but it should do with minimal fixing.

- I'm giving you this one for free.
- Nothing's free in the waterworld.
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #38 on: January 05, 2009, 11:02:01 AM

Please indulge some SirBrucing so we can see if I get what you are saying.

You are trying to add a string collection to a dictionary that is typed to hold single strings, which will not work...

I sort of thought I could use references for values but that is very Perly and perhaps incorrect anyway.

Quote
also, the myIngr list is private, meaning it can't be accessed outside of the class, which will halt the compiler even if it's fixed.

Later, in the car on the way home, I had the idea that I was being sloppy and should have written accessors, properties or something, for the class that just has a list, but then I wondered if I would gain anything by putting the list in a separate class.

Quote
But you got it sorta right, you just need to think of objects more as... well, ordinary objects. smiley If you rearrange it a little, it'll be easier to see, I think.

This statement seems to sum up my primary problem with C#.  In Perl I can just write everything with a global context, and it defaults to such behavior, but this just isn't how things are done in C#, or any Real OO it seems.  I was going to try to put your linked-dictionary idea into code but it seems like I'd be better served by laying out my object scopes as if I was going to write the actual program, then get into the rest of it.

Quote
Code:
class Ingredient { }
class Recipe { }

Each of these can have a name, such as "Flour" or "Sweetrolls", so add a string variable to hold that info.

Code:
class Ingredient {
    public string Name;
}
class Recipe {
    public string Name;
}

Recipes are made up by several Ingredients, which means we have to keep a list of the ingredients each recipe needs. Since each recipe has its own distinct list, we can add that info directly to the Recipe class, because no other recipe needs to access that information. It is only relevant to the recipe itself.

This stuff is always incredibly obvious in hindsight.  "Recipes are made of Ingredients" indeed.

Quote
Code:
class Recipe { 
    public string Name;   
    public List<Ingredient> Ingredients = new List<Ingredient>(); // We need to initialize this variable, or we can't use it.
}

Oh yeah.  I get it.  Makes so much sense now, list of objects in the Recipe class.  Well, it makes sense now, but we shall see what happens next time I try to do this without handholding.  The thing that seems to trip me up is illustrated here: I'm just not used to the idea of making a class just to hold a string or even a set of strings, which is what I think an Ingredient would be since it doesn't have many properties other than the name.  Really the idea of turning something dead-simple as a string into a class seems ridiculous, and I am just going to have to overcome that perspective, I think.

Quote
Now you can handle Ingredients and Recipes for what they are; self-contained objects that have all the info they need to act independently of each other.

I'll need to keep this general idea in mind or else I'll be in trouble again.

Quote
Code:
class Ingredient {
    public string Name;
    public Ingredient(string name) {
        Name = name;
    }
}

I'm positive I get this.  I know how to make a constructor.  I am trying very hard not to think of this sort of thing as "ridiculous".  I have to remind myself it's probably like how I thought calculus was ridiculous until about halfway through differential equations. awesome, for real

Quote
Then we can initialize a recipe;

Code:
Recipe casserole = new Recipe("Italian Casserole");

Ingredient onion = new Ingredient("Onions");
Ingredient cheese = new Ingredient("Grated cheese");
Ingredient mushies = new Ingredient("Mushrooms");

casserole.Ingredients.Add(onion);
casserole.Ingredients.Add(cheese);
casserole.Ingredients.Add(mushies);

I am unclear as to where this code should go.  Can I newb it and stick this in Main() in Program.cs?  Or worse yet, Form1.cs?

Quote
That will give you an object, with the Name "Italian Casserole" that has three Ingredients. Now you can add the Recipe to a "cookbook" of sorts, namely a dictionary. A cookbook is a collection of recipes, and each recipe has a distinct name. That makes a Dictionary<,> perfect.

Makes sense so far.  It's a hash except using classes instead of references for the value... which is basically the same thing.

Quote
Code:
Dictionary cookbook = new Dictionary<string, Recipe>(); // String, for the name of recipe, and Recipe, that holds all the relevant info.

cookbook.Add(casserole.Name, casserole);

You lost me, maybe.  This makes my head hurt.  Let's see, you're instantiating a Dictionary object called cookbook.  This cookbook contains pairs of string,Recipe.  Then you Add a casserole with casserole.Name as the key... but what the hell is the string under there?  Is it "Italian Casserole"?  Well, it would have to be, so why does this seem totally ass-backward to me? swamp poop

Quote
Of course, now you got the problem that you only have the ingredients, but lack the quantities. That's a little more tricky to do in a proper way, so I'll leave that out for now.

I'll take a whack at that.  If I get this example working then Encapsulation means I can't fuck it up too bad just by fiddling with Ingredient, yeah? awesome, for real

Quote
I hope it helped anyway. Oh ho ho ho. Reallllly?

It did, very much.  I'll be back.

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
Tarami
Terracotta Army
Posts: 1980


Reply #39 on: January 05, 2009, 02:01:15 PM

Properties are nice and should be used, but I didn't want to introduce them here since it would also introduce access modifiers (private, internal, public, protected etc.). Thing is, properties don't really serve much of a point from a logic standpoint, but it's nice to have since you can write-protect variables with them and wrap some bits to tidy up the vars before they get stored internally. If you already know how properties work, go for it. I chose public variables because it was a little cleaner and hopefully easier to follow.

Yes, the add operations should be stuck in a main() or Form_Load() or some such start-up method. It doesn't really matter, but you will have to keep in mind to move the declaration of the Dictionary outside the method (into the class Program or Form1, depending on what kind of application you're making) so it won't go out of scope between calls of utilarian methods (perhaps an Add event when you click a button, or some such.) Something like;
Code:
class Program {
    Dictionary<string, Recipe> cookbook = new Dictionary<string, Recipe>();

    public void main(string[] args) {
        // Your start-up stuff here
    }

    public void AddRecipe(Recipe r) {
        // And so on
    }
}

Not sure I'm getting this right, but -
The underlying value of casserole.Name is "Italian Casserole" as you say, it's just because of how Dictionary<,> behaves that you have to "double declare" the key. In theory you could be keying your stored objects by some other string that didn't exist in the object that you're storing as a value. But that would be stupid in this case. ;) It might seem more elegant to simply tell the dictionary to use the Name variable, and it would be, but that would require a little bit of unnecessary tampering, which Dictionary<,> is there to avoid.

PS;

- I'm giving you this one for free.
- Nothing's free in the waterworld.
sidereal
Contributor
Posts: 1712


Reply #40 on: January 05, 2009, 02:59:14 PM

Really the idea of turning something dead-simple as a string into a class seems ridiculous, and I am just going to have to overcome that perspective, I think.

It does seem now like excessive busywork, but one of the major benefits of OO development is separating architecture from implementation.  In non-OO perl-land, my implementation defines my architecture.  So if I store my ingredients as a list of strings, I interact with it in one way (looping the list), but if I store it as XML I interact with it another way (sax parsing), or if I store it as a bunch of constants with 'amount' fields I have to do some multidimensional hash and all of the code that uses it has to be tuned to that.  With OO you abstract that implementation away, so as far as the rest of your architecture is concerned you have an Ingredient and could give fuckall about how it's stored.  So if you want to change from a String to a reference to some global 'Nutmeg' object (and I assume that you will eventually want to do something like this), you don't have to dig through all of your code to change it.  You just change the internals of the Ingredient class, which for now is, yes, just a String.  It makes the extra 5-10 lines worth it.  Or to put it another way, right now it's 'something dead-simple as a string' but you don't want to bet 30 hours of future development time that it's going to stay that way.


THIS IS THE MOST I HAVE EVERY WANTED TO GET IN TO A BETA
Tarami
Terracotta Army
Posts: 1980


Reply #41 on: January 05, 2009, 04:07:41 PM

I want to chime in on the abstraction point there. Yes, Ingredient is important because it's conceptually very different from having it as a string. I just like metaphors too much, so I'll just use a couple bad ones to explain the point.

The thing is, a string is words. That's all it's good for storing. An ingredient is not words. You don't put words in food. You put things like carrots in food. Carrots have weight and colour and all sorts of qualifying attributes. Grated carrot or diced carrot?

Meanwhile, the string "carrot" doesn't tell you any of that. But the class Carrot, (which may inherit Ingredient, perhaps ;-), can tell you as much as you like about its properties. It *can* still be just a carrot, because it's that too, but it can also be a quarter-pound of grated carrot that was grown in Montreal. Maybe you took it so far that you made a subclass of Ingredient, Vegetable, and you have a recipe for vegetable soup that just asks for two pounds of random vegetables. Well, you have Vegetable defined, so you know exactly what a Vegetable is.

Still, you have no idea if the string "carrot" is a vegetable. It lacks meaning to your logic beyond being a six-letter word. You could expand the string to "Carrot, grated, 0.2 pounds, grown in Montreal, is a vegetable, is an ingredient", but that just doesn't seem very practical in comparison.

However, there's no ultimate truth to what should be abstracted and how far it should be abstracted, that's just up to common sense and probably one of the big things to learn in OOP.

- I'm giving you this one for free.
- Nothing's free in the waterworld.
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #42 on: January 07, 2009, 12:43:52 PM

My mom always said I didn't have any common sense.  sidereal's "architecture vs implementation" bit is my trouble, being a self-taught hacker instead of a real programmer.  It's going to take some hammering to get my mind into the right frame for this style of code, but I'll get there, and you guys are helping a great deal.  I have already run into the dreaded "what should be a class and what should a class be" question when trying to dream up something.  For my card game, I still don't know if a Hand should be a class that contains Card instances, should there be a Deck class or what.  Mind-numbing.

I know about properties (another thing which also seems sort of silly at first glance) because they are tossed in there with everything else when Jesse Liberty explains variables and why you should not make everything a global.  Ironically, I think I'd rather do something fancier here.  Quantity was mentioned, but there are two possible quantites: quantity to use in a recipe and quantity in stock.  A Recipe that calls for two cups of sugar should, I think, have "two cups" in the particular Recipe, so that should not go into Ingredient, but Ingredient should know how many eggs are available... well, later on.  Good thing Ingredient isn't just a string! awesome, for real

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
MahrinSkel
Terracotta Army
Posts: 10857

When she crossed over, she was just a ship. But when she came back... she was bullshit!


Reply #43 on: January 07, 2009, 02:01:46 PM

Being self-taught myself, I understand your frustration.  I found it works best if I just hack together something that barely works (but is ugly as sin, lots of brute force and spaghetti code), then use the understanding of the problem that gave me to plan a proper object hierarchy and do it right, usually from scratch (bits of the old code may get cut and pasted in, but I start from a new project).

--Dave

--Signature Unclear
Tarami
Terracotta Army
Posts: 1980


Reply #44 on: January 07, 2009, 02:21:49 PM

Yeppers. Coding is like most crafts; getting the bits to work together is initially much more important than doing it strictly right. I believe it goes back to the whole abstraction dilemma; it takes a very, very experienced programmer to know what systems you're going to need to make stuff work. Most likely you know because you've built something similar before. Therefore it's almost always more efficient to churn out some choppy, ugly prototype that works as a concrete blueprint for building all the clever bells and whistles the final product will need to work smoothly. Also, it's good for the soul to see it can work before you put in a ton of hours to make it fancy. Going full force first thing with something you're not familiar with, only to see it's much more complicated than you expected, is horribly demoralizing. Many are the projects that I've started that have ended up in the zombie pile.

Secondly, actually I'm going to sorta agree with you on properties. They are rather silly. The actual need of properties is none. They just reduce code clutter and the tidy up the programming interface for the class. Which is nice, of course. smiley

And having a Hand object, if you want one, made up by a collection of Card objects is a good idea, because that's what it really is. A (random) set of predefined cards. You can then add hand manipulation methods to the Hand class, since they only need to tamper with the cards actually on hand. And so on. Maybe a method to draw a number of cards in the Deck class?

- I'm giving you this one for free.
- Nothing's free in the waterworld.
sidereal
Contributor
Posts: 1712


Reply #45 on: January 07, 2009, 03:31:56 PM

For my card game, I still don't know if a Hand should be a class that contains Card instances, should there be a Deck class or what.  Mind-numbing.

To pile on the sidetrack, when I do card games I usually share a class between a deck and a hand.  I just call it a CardPile, which is a thin wrapper around a native collection (a List or whatever).  I try to distinguish between what something is (a pile of cards) and what it's used for.  Decks and hands are used for different things, but they are essentially the same thing, so they can share the same functionality.  OO purists would disagree with me, because some of my functions are useless depending on what this pile is used for (for example, I support shuffling your hand which doesn't amount to much [or does it?]) but I think the simplicity of the architecture makes up for excessive functionality.

THIS IS THE MOST I HAVE EVERY WANTED TO GET IN TO A BETA
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #46 on: January 12, 2009, 11:30:17 AM

It's not much of a sidetrack since my initial drive into C# was due to wanting to write a better MTGO than WoTC.  I'm still pretty sure I can do it.  A RecipeBook is possibly more complicated than a card game so maybe I should revisit the original idea.

I had the same problem with a Hand made of Cards.  I mean, that's obvious to me, but then I was looking at making a Deck object.  The problem was oddly similar to the one I worried about with RecipeBook: keeping track of which Card instances were where.  Did I need some other object, or should I use global vars (these seem anathema to C#)?  Abstracting it to PileofCards does seem like a great way to simplify it while I pound out a prototype.  Hell, if I can instantiate a few cards and "move" them between Piles, that will be a major breakthrough.

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
sidereal
Contributor
Posts: 1712


Reply #47 on: January 12, 2009, 12:04:58 PM

Do that.  Also, the Graveyard is a CardPile.  The OutOfPlay area is a CardPile.  The InPlay area is a CardPile, etc.  Or you could just call it a CardCollection since they're starting to look less like piles.  But if your CardWhatever class supports shuffling, drawing from one to the other off the top, moving a card from one to the other, then you're 80% of the way there.

Quote
write a better MTGO than WoTC

Ouch.  I appreciate the sentiment, but ouch.  There are two ways to go about this.  One is to implement a blank card table that supports moving cards around and displaying them.  It is up to the players to understand the rules of Magic.  So, for example, a player decides to play a card they manually dock their own mana, click the card to play it, click on the table, etc.  The other player keeps them honest.  In this case the software is just replacing the physical cards, the shuffling algorithm, and the table display.  This can also be just a step towards option 2, which is..

actually implement the rules of magic.  This is not for the faint of heart.  I made a run myself back in 98ish.  Just getting through basic creatures, direct damage, and other non-mindbending cards is tricky.  Once you get into the real juice like Time Vault that breaks the game's own rules, you are in super-expert data modeling land.  You need to be very careful about how you implement the engine to make sure a card can go in there and completely fuck it up and then back out when the card goes away.  Just read the Lich effect and try to come up with an architecture that supports that.  To be fair, if you limit yourself to tournament-legal cards you get rid of most of the ridiculously complicated, game-breaking stuff.  But it's still a real challenge.

THIS IS THE MOST I HAVE EVERY WANTED TO GET IN TO A BETA
schild
Administrator
Posts: 60345


WWW
Reply #48 on: January 12, 2009, 12:58:53 PM

The problem with MTGO isn't "the cards don't work." This is, in fact, the one thing it does right. No, the problem is the "constructed" type of play - not in the Magic sense - but in games with rules like "Drafts" and "leagues." Also, client stability and the GUI.

God.

The fucking GUI.
Margalis
Terracotta Army
Posts: 12335


Reply #49 on: January 12, 2009, 08:47:00 PM

Write code that makes logical sense. That's my number one tip. 95% of tough coding problems are caused when someone writes a bunch of code and they don't understand how it works or how it is *supposed* to work, they just throw more and more stuff together until it collapses.

If you have a clear idea of what peice is supposed to do then smushing them together is trivial.

vampirehipi23: I would enjoy a book written by a monkey and turned into a movie rather than this.
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #50 on: January 13, 2009, 10:57:37 AM

actually implement the rules of magic.

I don't want to do this, actually.  I started playing tournament Magic in 1994-5 and I am very impressed that anyone created a successful computer version, online or not.  No, my intent isn't to duplicate the cards or rules but rather to create a similar game that does not look like the programming team was intentionally trying to sabotage their own project.  I have my own idea for a card game, anyway.

Steps on the card game are pretty much as you outlined.  Set up a system where I can move Cards from one CardCollection to another, then set up a simple display using simple Form elements or maybe WPF, then whip up a GUI in three hours.

Yes, I am kidding about the three-hour GUI.

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
Morat20
Terracotta Army
Posts: 18529


Reply #51 on: January 13, 2009, 12:21:04 PM

I want to chime in on the abstraction point there.
Damn skippy. For the longest time I avoided real abstraction, having been raised on C where you had structures and you LIKED them, goddammit!

After wasting countless hours rewriting code simply because I hadn't bothered to do it properly (abstractly!) in the first place, I stopped fucking around. Yeah, it takes forever to write a properly abstracted "hello world" program. It's not for that.

It's so I can have MyObject.Clone(AnotherObject) and written right there in main or on_load or whatever, and know that no matter what I do to how MyObject works, that bit will ALWAYS work. (Assuming I changed the Clone method, of course).

Abstraction saves you days or weeks of work down the line, at fairly minimal cost up front. I created a genetic program -- top level ran it (Initialize, rank for fitness, crossover, mutate, repeat), middle level was the tree-structures of the chromosome, next level down was the "Rule" level (nodes and leaves) and below that was the final layer of actual data.

I rewrote the entire bottom layer -- completely changed the data it was running on, how it compared them how it stored them, EVERYTHING -- without having to do more than cosmetic changes anywhere else. Even though that bottom layer was where everything actually happened, the absolute core of the project.

All because I'd written it properly in the first place. If I'd done it in a language without OO support, I'd have had to pretty much rewrite half of it.

OO, done properly, allows for extensibility, adaptation, evolution, and all the other bits that happen naturally with any good piece of code.
Tarami
Terracotta Army
Posts: 1980


Reply #52 on: January 13, 2009, 04:41:54 PM

I want to chime in on the abstraction point there.
Damn skippy. For the longest time I avoided real abstraction, having been raised on C where you had structures and you LIKED them, goddammit!
I don't know if this is aimed at me and if it is, what it means. awesome, for real

- I'm giving you this one for free.
- Nothing's free in the waterworld.
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #53 on: January 14, 2009, 05:46:31 AM

For the longest time I avoided real abstraction, having been raised on C where you had structures and you LIKED them, goddammit!

After wasting countless hours rewriting code simply because I hadn't bothered to do it properly (abstractly!) in the first place, I stopped fucking around. Yeah, it takes forever to write a properly abstracted "hello world" program. It's not for that.

It is very strange that you post this on the same day that I run into a real-world issue with this very thing.  I was scratching my head (in between constant interruptions) over why I was not seeing some notifications come out of a Korn script I have been working on for a few months, and while I was waiting for my haircut it occurred to me that it was probably due to restrictions on recursive POSIX function calls in Korn.  Basically you can't recurse POSIX functions so you have to use Korn functions for that purpose... trouble is that the scoping is different.  I inherited the script, so it's not 100% my fault in this case, but the reason I stuck with POSIX functions is because I was lazy: variable scoping is global by default.  Switching to Korn functions means that I have to rewrite a bunch of shit.  Goddammit.  If I had done it the "right" way the first time then I would not be in this situation... although when you are talking about ksh the definition of "right" is very loose.

The above is why I really want to learn C# the right way.

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #54 on: January 14, 2009, 06:43:14 AM

it occurred to me that it was probably due to restrictions on recursive POSIX function calls in Korn.


"Yeah, I was WAY off about that."

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
Morat20
Terracotta Army
Posts: 18529


Reply #55 on: January 14, 2009, 08:44:22 AM

I want to chime in on the abstraction point there.
Damn skippy. For the longest time I avoided real abstraction, having been raised on C where you had structures and you LIKED them, goddammit!
I don't know if this is aimed at me and if it is, what it means. awesome, for real
Not really aimed at you, so much as that when I learned to code I learned prior to object-oriented design really hitting the scene. It was out there, IIRC, but not really used.

Instead you used custom data structures and a lot of referencing and function pointers to do many of the same things as OO code does, but it was five times more complex, buggy as shit, and easy to break.

But I learned that way, so I stuck with it (my C++ code was a lot more "C" than "C++") until I got tired of shooting myself in the foot. I don't bother with objects or the like if I'm doing something simple, but anything complex -- especially if I plan to revise/evolve down the line -- I start with an OO framework.

I'll be a happy man if I never have to see -- or fix -- someone's bastard version of polymorphism using function pointers. Fucking function pointers.
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #56 on: January 15, 2009, 11:43:27 AM

Again I will agree with Morat with my example.  I made a few small changes to my script, since as far as I could tell the code was fine and the meat was wrong, however I had to search variable names in the whole script and had to check each function that I impacted with my changes.  Basically, I had to make sure that my various code bits were correctly handling the data they were working on since I could not guarantee any of the inputs or outputs.

I blame BASIC.

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
CadetUmfer
Terracotta Army
Posts: 69


WWW
Reply #57 on: January 16, 2009, 06:38:42 AM

I'm waiting for next year's thread where you learn F#, hehe.  "What, you mean I can write this with 20% of the code and have it more abstract, more strongly typed and more succinct?  Explain this closure thing again??"

;)

Anthony Umfer
Developer, LiftOff Studios
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #58 on: January 16, 2009, 06:50:26 AM

Is that MS Fortran?  Jesus help me. Ohhhhh, I see.

Edit to say that if I decide to pick up any other language that has tenuous relations to my work, it will likely be Haskell.

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
Bokonon
Terracotta Army
Posts: 302


Reply #59 on: January 16, 2009, 07:08:43 AM

One useful thinking pattern for OO (it may or may not be useful for you) is to think about is-a and has-a. Things that fall under is-a should be defined as classes, while things that fall under has-a should be defined as a property/field of a class. An Ingredient has-a name, has-a freezing point, has-a burning point, etc.

One other thing I've noticed you do Yeg, is use "object" and "class" sorta interchangeably. This can lead to all sorts of confusion. To simplify (to the point of being not 100% accurate, but useful for a new/medium developer), think of a class as a data and behavior definition. Classes are templates of a sort. Objects are concrete instances of the classes you instantiate them as. Or rather, they are references to these instances. So Ingredient is a class. Paprika is an object that is an instance of an Ingredient.

Objects can be thought of as programmatic copy-and-pastes of your class definitions (with exceptions), that you then use within the context of your running program. These copy-and-pastes are independent of each other (so changing your paprika instance's name to "awesome sauce" won't change your horseradish instance's name as well).

Hope I didn't confuse.
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #60 on: January 16, 2009, 07:33:21 AM

One other thing I've noticed you do Yeg, is use "object" and "class" sorta interchangeably. This can lead to all sorts of confusion. To simplify (to the point of being not 100% accurate, but useful for a new/medium developer), think of a class as a data and behavior definition. Classes are templates of a sort. Objects are concrete instances of the classes you instantiate them as. Or rather, they are references to these instances. So Ingredient is a class. Paprika is an object that is an instance of an Ingredient.

Ah, yes, good catch.  I will have to watch that.  Many times I use the word "instance" to mean that, but I can see how I am confusing classes and objects somewhat.  I suppose the right thing is to only use the words Class and Object so I and others do not get confused.  Also your post was helpful and not at all confusing.

I think it's sort of funny that this thread is turning into a miniblog of me learning C#, and now I somehow find myself this morning reading Extreme Programming Adventures in C#, which is apparently a running account of Ron Jeffries learning C# and attempting to apply XP principles to it.  I think I will know by the end of chapter one if XP is more my thing, but right now it sounds awesome.  Maybe too awesome.

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
sidereal
Contributor
Posts: 1712


Reply #61 on: January 16, 2009, 09:23:04 AM

Is that MS Fortran?  Jesus help me. Ohhhhh, I see.

Edit to say that if I decide to pick up any other language that has tenuous relations to my work, it will likely be Haskell.

More like MS OCaml.  I'm a fan of the implicit strong typing, but it's not going to kick Ruby off the perch of the closure-philes.

THIS IS THE MOST I HAVE EVERY WANTED TO GET IN TO A BETA
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #62 on: January 16, 2009, 09:50:39 AM

I made some code.  Have a question, not sure I can do what I am thinking I want to do.  Pertinent lines are red.

Card class, obviously:

   class Card
   {// private member variables
      private int fire;
      private int water;
      private int air;
      private int dirt;
      private string name;

      // constructor
      public Card(string n)
      {
         name = n;

         fire = 1;
         water = 2;
         air = 3;
         dirt = 4;
      }


Pertinent bit of CardPile, the general form of any set of cards:

      private Dictionary<string, Card> containedCards;
      
      public CardPile(params string[] cardNames)
      {
         containedCards = new Dictionary<string, Card>();
         foreach (string s in cardNames)
         {
            containedCards.Add(s, Card(s));
         }
      }


If it is not obvious, I want to initialize a CardPile with a set of Cards which I pass to a foreach as a string array.  I am not really sure I want to do this but it would be nice to see it work.  I would be using the Add() method to put cards into the dictionary with the intent of having a card's name be the key (string) and the Card object that gets instantiated based on what string (card name) I give it (real code for that comes later).  Nevermind the stubbiness of Card, I'm just worrying about the Add() part and whether it can do what I want.

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
Tarami
Terracotta Army
Posts: 1980


Reply #63 on: January 16, 2009, 10:07:51 AM

1) That looks good enough. Say, what are the fire/water/air/dirt vars? I get the feeling you're trying to do something that can be done a better way. Manage suite?

2) Typically it'd be better to use "params Card[] cards" as argument to the constructor, because then you don't have to rewrite the constructor (possibly jerking upp ALOT of references elsewhere in the code) if you decide to change the identifier of Card (right now, a string, next, maybe a string and a suite?) When passed around, you'll want to use Card rather than the string key, so most of the time you'll be adding and removing Card instances from the collection.

3) You don't need to declare variables in classes as private. They're private by implication. So "private int x" is identical to "int x" when declared as a class member. Same goes for all class members (methods, enums, nested classes... etc.)

Edit:

4) I forgot to mention. Dictionary is a key-unique collection, it can't store multiple objects with the same key. For a normal deck of cards this won't be a problem, but for something more akin Magic, it would be. Are the cards going to be unique, or will there be duplicates?
« Last Edit: January 16, 2009, 10:25:50 AM by Tarami »

- I'm giving you this one for free.
- Nothing's free in the waterworld.
sidereal
Contributor
Posts: 1712


Reply #64 on: January 16, 2009, 10:09:15 AM

Caveat:  I'm coming from Java-land, so I'll probably say something dumb and/or inaccurate about C# syntax.

Minor issues: you're missing the 'new' operator in your Add call

Larger issues: A dictionary allows a single value per key.  Java behavior is to replace it if you try to add a new value with the same key, but I think C# actually tosses an exception.  In your case, this'd mean that you could only have one instance of each card name, otherwise your dictionary would bitch.  You probably want a List instead of a Dictionary.  Also, this isn't part of your particular question, but if your fire/water/air/dirt values are supposed to be enum-type attributes of the card, standard practice is to make them static, initialize the values in the declaration, and capitalize the names.  But C# actually natively supports enums these days, and that's an ever better way to go:

http://www.csharp-station.com/Tutorials/Lesson17.aspx

THIS IS THE MOST I HAVE EVERY WANTED TO GET IN TO A BETA
Tarami
Terracotta Army
Posts: 1980


Reply #65 on: January 16, 2009, 10:29:38 AM

Java behavior is to replace it if you try to add a new value with the same key, but I think C# actually tosses an exception.
Depends on how you set it. This would throw an exception;
    dicCards.Add("a", myCard);
while this will overwrite the value;
    dicCards["a"] = myCard;

Basically, you're almost always better off using the indexer ([]) to set or add values, because it does all the key-checking for you.

- I'm giving you this one for free.
- Nothing's free in the waterworld.
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #66 on: January 16, 2009, 11:20:44 AM

I am going to have to do more thinking on what goes where.

1) That looks good enough. Say, what are the fire/water/air/dirt vars? I get the feeling you're trying to do something that can be done a better way. Manage suite?

Mmm, well I was hoping to ignore this bit until later.  Then again, I failed to consider that I would have multiple identical card objects when I picked a Dictionary to hold them, so I might as well scratch it now and use a List.  Actually I sketched out this code with an Array and decided I didn't want to try to deal with "holes" in the array.  For example, removing a Card from a CardPile would possibly mean that containedCards[23] would be empty/null/whatever.  I won't be able to dodge writing a real ShowAllCards() with a sparse array.  I will need to think about this.

As for how I plan to implement Card itself, the end goal is to have a Card that can have any number of arbitrary properties.  There are likely to be several standard ones but I don't want to limit myself to a set of 52 cards with a couple of properties, for example.  I'm thinking of Magic here in that I might have a card called Butt with properties like string Title = "Butt", int Fire = 3; string FreeText = "This card has a picture of a butt with a butt-shaped tattoo on it."; string Arbitrary1="Odiferous"; int Pimples=9; and so on.  Simply put, I'd like to give someone free reign to make cards as if this were a paper game.  At the moment the actual properties are not important to me.

2) Typically it'd be better to use "params Card[] cards" as argument to the constructor, because then you don't have to rewrite the constructor (possibly jerking upp ALOT of references elsewhere in the code) if you decide to change the identifier of Card (right now, a string, next, maybe a string and a suite?)

You seem to be saying I should use classes for both key and value (if I use a Dictionary).  Is that correct?

New idea: on startup I instantiate a CardPile named deck that initializes with all of the cards it contains.  After that I can make new CardPiles of various types that simply get a particular object from the master deck object.

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
Yegolev
Moderator
Posts: 24440

2/10 WOULD NOT INGEST


WWW
Reply #67 on: January 16, 2009, 11:44:31 AM

Rewrite.

   class CardPile
   {
      List<Card> containedCards = new List<Card>;
      public CardPile(params Card[] cards)
      {
         foreach (Card c in cards)
         {
            containedCards.Add(c);
         }
      }
      // show number of cards in pile
      public int GetNumCards()
      {
         return containedCards.Count;
      }
   }
}


I think I'm done for today.  Next time I will work on setting up the CardPile derivatives such as Hand and Deck.

Why am I homeless?  Why do all you motherfuckers need homes is the real question.
They called it The Prayer, its answer was law
Mommy come back 'cause the water's all gone
Azaroth
Terracotta Army
Posts: 1959


Reply #68 on: January 17, 2009, 09:22:58 AM

So, how many of you guys can I exploit into working for free?

F  is inviting you to start Quarto. Do you want to Accept (Alt+C) or Decline (Alt+D) the invitation?
 
  You have accepted the invitation to start Quarto.
 
F  says:
don't know what this is
Az  says:
I think it's like
Az  says:
where we pour milk on the stomach alien from total recall
Margalis
Terracotta Army
Posts: 12335


Reply #69 on: January 17, 2009, 05:25:45 PM

I strongly suggest you develop a notation to distinguish between instance variables and local variables/parameters.

The one I use is underscore.

vampirehipi23: I would enjoy a book written by a monkey and turned into a movie rather than this.
Pages: 1 [2] 3 4 Go Up Print 
f13.net  |  f13.net General Forums  |  The Gaming Graveyard  |  Game Design/Development  |  Topic: Yegolev Learns C# - was Your app's data  
Jump to:  

Powered by SMF 1.1.10 | SMF © 2006-2009, Simple Machines LLC