C# / Unity3D - One constructor for all subclasses? - c#

I'm a noob, and a rusty one at that, so bear with me here. I want to make a digital implementation of an old, obscure card game. I have a Card type with properties such as name, rarity, classification, etc. Then there's more specific stuff that not all cards have, such as attack power, resource cost, etc. A fate card doesn't have a power stat, a planet card doesn't have an influence stat, and so forth.
I want to subclass Card out into these various kinds of cards with the appropriate properties that only they have, but I don't want to give up having a single "new Card(string name)" constructor. My idea was to have the Card constructor call a subclass's constructor with arguments for the general properties, but I read that you can't return anything from a constructor other than the type being constructed. Any way to do this cleanly?

If I understand well, what you want to have in the end would be something like this:
Card planetCard = new Card("Planet");
Card fateCard = new Card("Fate");
Your plan of using inheritance won't work this way, as a base class cannot call a constructor of the inherited class from its own costructor. It can only happen the other way around. The two simpler options to solve this would be:
1- Instantiate the propper class as you need it.
Given two classes like this:
public class PlanetCard : Card
{
///--- Attributes of planet here
public PlanetCard() : base("Planet"){}
}
public class FateCard : Card
{
///--- Attributes of fate here
public FateCard() : base("Fate"){}
}
You can now create the cards as follows (which is kind of similar to what you wanted to achieve in the first place):
Card planetCard = new PlanetCard();
Card fateCard = new FateCard();
2- Using Components instead of inheritance.
The use of components instead of inheritance is very common nowadays when it comes to games. The idea is having only one Card class, but each card, depending on what it really is, would have different components to use:
interface IComponent{}
public class PlanetComponent : IComponent
{
///--- Attributes of Planet
}
public class FateComponent : IComponent
{
///--- Attributes of Fate
}
public class Card
{
List<IComponent> components;
public Card(string cardName)
{
///--- Fill components according to the name
}
public T GetComponent<T>()
{
///--- return the component of the type T in the list, or null
}
}
And now you can create cards like in the first place (although the use later will be a bit different):
Card planetCard = new Card("Planet");
Card fateCard = new Card("Fate");
///--- Using the planet card
PlanetComponent planetComp=planetCard.GetComponent<PlanetComponent>();
if (planetComp!=null)
{
///--- you can use here the planet attributes
}
This solution is much more flexible, as it allows you to combine the components at will (you clud have a "FatePlanet" card with both components if you wanted). You will need though, some way of matching the name of the card with the components you want it to have.
Hope it helps!

Related

How do I organize nested classes to be references in Unity?

So I'm working on a game and I'd like some recommendations for how to sort items for easy, legible, coding reference in Unity. I know my current method is flawed, and really I'd just like some guidance.
So what I'm doing is using classes to separate item categories and their items.
For example, here's an idea of a setup for a script :
public class Items {
public class Equipment {
public class Weapons {
public Item Sword = new Item();
Sword.name = "Sword";
Sword.cost = 1;
}
}
}
then a basic Item class for example
public class Item {
public string name;
public int cost;
}
I can tell this is terrible practice, especially based on the problems I've been having, but I like the idea of using a reference like Items.Equipment.Weapons.Sword and I've grown accustomed to using that from an API I previously used.
I'm open to completely changing everything, I just want some tips. Thanks.
I guess my main question is (was), what's the best way to organize nested classes so they can be references from other scripts easily?
The answer I found was that instead of nesting classes, in my case, it's better to use namespaces to separate items into categories. Thanks a million.
I recommend using ScriptableObjects to create your items, armor, and weapons. You'll have to spend an hour or two learning them, but I think you'll be much happier with your design if you go that route.
Think of a ScriptableObject as a set of properties (item name, cost, attack power, defense power, etc.). For each item you have in your game, you create an instance of a ScriptableObject. Those ScriptableObject instances then become assets in your Unity project, just like a prefab or a sprite. That means you can drag them around in your project, and assign them to the fields on your MonoBehaviours. That'll result in you being able to assign equipment to a character by dragging it from your Project view into the Inspector.
Here's an example of how it'll look
Item.cs
public class Item : ScriptableObject
{
public string name;
public int cost;
public Sprite image;
}
Equipment.cs
public class Equipment : Item
{
public Slots slot;
}
public enum Slots
{
Body,
DoubleHanded,
Hands,
Head,
Feet,
Legs,
LeftHand,
RightHand
}
Weapon.cs
// CreateAssetMenu is what lets you create an instance of a Weapon in your Project
// view. Make a folder for your weapons, then right click inside that folder (in the
// Unity project view) and there should be a menu option for Equipment -> Create Weapon
[CreateAssetMenu(menuName = "Equipment/Create Weapon")]
public class Weapon : Equipment
{
public int attackPower;
public int attackSpeed;
public WeaponTypes weaponType;
}
public enum WeaponTypes
{
Axe,
Bow,
Sword
}
Armor.cs
[CreateAssetMenu(menuName = "Equipment/Create Armor")]
public class Armor : Equipment
{
public int defensePower;
}
Now create a bunch of weapons and armor in your project.
One thing that makes ScriptableObjects nice is you can edit them in your Inspector, rather than having to do it through code (although you can do that too).
Now on your "character" MonoBehaviour, add some properties for that character's equipment.
public class Character : MonoBehaviour
{
public Armor bodyArmor;
public Armor headArmor;
public Weapon weapon;
}
Now you can assign your weapons and armor to your character in the Inspector
You'll probably want something more customized to your needs than my example, but those are the basics. I recommend spending some time looking at ScriptableObjects. Read the Unity docs I linked earlier, or watch some videos on YouTube.
One of Unity's strengths is that it lets you do a lot of design and configuration through the editor rather than through code, and ScriptableObjects reinforce that.

Can I use an abstract base class as a Unity Editor element?

I'm trying to create a component for a Unity GameObject, let's call it MediaController. I want it to be able to manage timing (play/pause/etc) for different media (audio/video). I created an abstract class PlayableMedia with basic properties/fields/methods and created 2 classes, PlayableVideo and PlayableAudio, that inherit and implement according to our needs.
The intent was to have a singular list of PlayableMedia that could be audio/video agnostic, allowing an easy (i.e.) media.Play() call regardless of type at specific app times... but my field public List<PlayableMedia> MediaList; is not appearing in the editor and there is no error.
So ultimately my question is as the title states: is it possible to use the PlayableMedia class as the type of a field?
I'm suspecting "no" based on my experiences with this, but I've found links that say "yes" or "yes, sort of" that seem to point to custom editors/inspectors/drawers, but I have 0 experience with those and haven't been able to get it implemented (see below).
[System.Serializable]
public class RegisteredMedia
{
public float StartTime;
public PlayableMedia Media;
}
[CustomPropertyDrawer(typeof(RegisteredMedia))]
class RegisteredMediaDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), new GUIContent("Playable Media"));
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
Rect rectStartTime = new Rect(position.x, position.y, 30, position.height);
Rect rectMedia = new Rect(position.x + 35, position.y, 50, position.height);
EditorGUI.PropertyField(rectStartTime, property.FindPropertyRelative("StartTime"), GUIContent.none);
EditorGUI.PropertyField(rectMedia, property.FindPropertyRelative("Media"), GUIContent.none);
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
}
public class MediaController : MonoBehaviour
{
public List<RegisteredMedia> MediaList = new List<RegisteredMedia>();
\\[...] rest of implementation
}
Can anyone help me out? Either confirm that it isn't possible, or help me with an implementation if it is?
Also, if it can be done with custom editors/inspectors/drawers, can someone help me get a single item in the List<RegisteredMedia> to display as Start Time ____ Playable Media [=====] (where PlayableMedia will be a GameObject with the proper component attached)?
Be careful of your use of the word "property". In C# it means something very specific.
is it possible to use the PlayableMedia class as the type of a property?
I think you are asking the wrong question here. Rather than coming up with a new implementation, consider why your current implementation might not be working?
Firstly, I'll give you the following example:
public abstract class Car : MonoBehaviour { }
public class Jeep : Car { }
public class Ferrari : Car { }
public class CarHolder : MonoBehaviour
{
public List<Car> Cars;
}
In this example, I could create a GameObject with the CarHolder component, and was able to attach both Jeep and Ferrari Objects. It is important to note that each monoBehavior class I defined sits in its own file and the file name matches the class name. This is just how Unity works.
So to answer the question I think you are asking (assuming we replace "property" with "field"), it is indeed possible to use abstract class types and have them show up in the inspector. I suspect that you need to separate your classes into separate files.
It's possible natively since 2019.3 release via [SerializeReference] attribute https://docs.unity3d.com/ScriptReference/SerializeReference.html
e.g.
using System.Collections.Generic;
using UnityEngine;
using System;
[Serializable]
public abstract class AbstractExample {
public int foo;
}
// [Serializable] not needed here
public class ConcreteExample : AbstractExample {
}
public class Consumer : MonoBehaviour {
[SerializeReference]
public List<AbstractExample> examples = new() { new ConcreteExample() };
// both the list and the concrete instance visible in the editor
// and editable without any additional editor extensions
// note that you can't effectively add new items to the list via editor
// since that way you create a faulty abstract-ish instances instead
// (no actual way for the editor to know what subtype do you want)
// if you're OK with having the base class being not explicitly abstract
// and can provide a sensible constructor for it, just drop the abstract
// you'll still have full polymorphism support etc. with SerializeReference
}

I want to spawn two types of enemies in rows (think Galaga), how should I set up my classes inheritance wise?

I want to make a game similar to galaga in xna using C#. I have two types of enemies (behavior and sprite are different, as well as sound effects), and I want each to have their own rows. I was earlier using arrays to generate enemies on screen, but apparently this isn't a good approach and was told I should use lists instead. Now, I was thinking there could be a few of ways of creating the enemy classes themselves. One was using inheritance, with a base class of Enemy, and then two other classes that inherit from Enemy but have their own behavior and sprite. Another way of doing this would be to create an enemy interface. And one other way of setting this up would be to use structs. I think using interface would be more time consuming compared to the other two, but I could be wrong (if I am, let me know). The other two I am not sure about though. Technically, I believe they both use classes, just one uses structs. What would be the better way of doing this, inheriting from an enemy class, or using an enemy struct?
Considering a simple scenario, creating the Enemy class and then using inheritance is the way to go.
If you need a more complex logical tree to add specific methods to entities that don't belong to the same tree then start using Interfaces. For example, if there is an "Enemy" tree and an "Ally" tree and you want some kind of same behaviour for enemy Type1 (inherits from Enemy) and ally Type2 (inherits from Ally) when they die, then consider using an interface for that.
Anyway and just as an example, the use of an Interface could be justified when you need to manage Lists of objects that are tagged with that interface to call specific methods (entities that for example "ExplodeWhenDying"). If you don't need to manage those kind of lists, then just use methods on a common parent class (for example "Entity" (Enemy and Ally inherit from Entity) and overwrite those methods (Explode()).
Interfaces are better suited to situations in which your program requires many possibly unrelated object types to provide certain functionality which i guess is not the case here.
The longer I code up solutions the more I like the concept of "Favor Composition over inheritance". It doesn't mean reject inheritance but many times in my past I over-used inheritance. The advantages to composition are that the lowest object in the hierarchy is always expandable, there is NEVER any name confusion and it leads to better unit testing.
But what is composition? It's simply the ability to contain some other object within your parent object. I typically use property getters and setters to expose the object like example below. All cars have wheels and engines and color and could be inherted, but they are NOT a type of any of those, so it's better to compose them or "inject" the traits... This is composition and shows concrete classes (not interfaces). Interfaces are better but you don't have to do them.
public class ComposeACar
{
public ComposeACar(Wheels theWheels, Engine theEngine, Color theColor)
{
MyWheels = theWheels;
MyEngine = theEngine;
MyColor = theColor;
}
public Wheels MyWheels { get; set; }
public Engine MyEngine { get; set; }
public Color MyColor { get; set; }
}
public class Wheels {
public string size { get; set; }
public decimal price { get; set; }
public string Manufacturer { get; set; }
}
/// <summary>
/// Same here for the next two class examples
/// </summary>
public class Engine {}
public class Color {};
public class BuildACar {
public BuildACar()
{
var wheels = new Wheels { Manufacturer = "GoodYear", size = "17", price = 195.00M };
var engien = new Engine();
var color = new Color();
var newCar = new ComposeACar(wheels,engien,color);
}
}

Appropriate design/design pattern for this problem?

I previously posted this, but I guess it was too verbose and irrelevant. My question is also like this. One poster in the second link said the answer (of why you can't do the code below) was a problem of design, specifically "bad use of inheritance". So I'd like to check this issue again with the experts at StackOverflow and see if this is really an issue of "bad inheritance" - but more importantly, how to fix the design.
Like the poster, I'm also confused about the Factory method and how I can apply it. It seems the factory method is for multiple concrete classes that have the exact same implementation as the abstract base class and do not add their own properties. But, as you will see below, my concrete classes build upon the abstract base class and add extra properties.
The Base Class We Build Upon:
public abstract class FlatScreenTV
{
public string Size { get; set; }
public string ScreenType { get; set; }
}
Extension Class Examples:
public class PhillipsFlatScreenTV : FlatScreenTV
{
// Specific to Phillips TVs. Controls the backlight intensity of the LCD screen.
public double BackLightIntensity { get; set; }
}
public class SamsungFlatScreenTV : FlatScreenTV
{
// Specific to Samsung TVs. Controls the time until the TV automatically turns off.
public int AutoShutdownTime { get; set; }
}
Let's say there are more extension classes for more brands of flat screen TVs. And then, let's say we stick them all into a generic List:
public static void Main()
{
List<FlatScreenTV> tvList = new List<FlatScreenTV>();
tvList.Add(new PhillipsFlatScreenTV());
tvList.Add(new SamsungFlatScreenTV());
tvList.Add(new SharpFlatScreenTV());
tvList.Add(new VizioFlatScreenTV());
FlatScreenTV tv = tvList[9]; // Randomly get one TV out of our huge list
}
The Problem:
I want to access the specific properties of whatever 'original' brand TV this variable belongs to. I know the brand because if I call tv.GetType(), it returns the correct 'original' type - not FlatScreenTV. But I need to be able to cast tv from FlatScreenTV back to its original type to be able to access the specific properties of each brand of flat-screen TVs.
Question #1: How can I dynamically cast that, properly - without makeshift hacks and huge if-else chains to brute-guess the 'original' type?
After browsing around similar design issues, most answers are: you can't. Some people say to look at the Factory Pattern, and others say to revise the design using interfaces, but I don't know how to use either to solve this problem.
Question #2: So, how should I design these classes so that I can access the original type's specific properties in the context above?
Question #3: Is this really bad inheritance?
Your design violates the "Liskov Substitution Principle". In other words, the code that deals with items from your list of FlatScreenTV shouldn't know or care what derived type is.
Say your code needs to create a custom remote control GUI. It might be enough to simply know the names and types of the properties of each TV to auto-generate the UI. In which case you could do something like this to expose the custom properties from the base class:
public abstract class FlatScreenTV
{
public FlatScreenTV()
{
CustomProperties = new Dictionary<string,object>();
}
public Dictionary<string,object> CustomProperties { get; private set; }
public string Size { get; set; }
public string ScreenType { get; set; }
}
public class PhillipsFlatScreenTV : FlatScreenTV
{
public PhillipsFlatScreenTV()
{
BackLightIntensity = 0;
}
// Specific to Phillips TVs. Controls the backlight intensity of the LCD screen.
public double BackLightIntensity
{
get { return (double)CustomProperties["BackLightIntensity"]; }
set { CustomProperties["BackLightIntensity"] = value; }
}
}
public class SamsungFlatScreenTV : FlatScreenTV
{
public SamsungFlatScreenTV()
{
AutoShutdownTime = 0;
}
// Specific to Samsung TVs. Controls the time until the TV automatically turns off.
public int AutoShutdownTime
{
get { return (int)CustomProperties["AutoShutdownTime"]; }
set { CustomProperties["AutoShutdownTime"] = value; }
}
}
If you really do need to be working directly with the derived types, then you should instead consider moving to a plugin based architecture. For example, you might have a factory method like this:
IRemoteControlGUI GetRemoteControlGUIFor(FlatScreenTV tv)
which would scan your plugins and find the one that knew how to build the UI for the particular type of FlatScreenTV you passed in. This means that for every new FlatScreenTV you add, you also need to create a plugin that knows how to make its remote control GUI.
Factory Pattern would be the best way to go
I can offer a partial answer:
Firstly read up on Liskov's Substitution Principle.
Secondly you are creating objects that inherit from FlatScreenTV, but apparently for no purpose as you want to refer to them by their SubType (SpecificTVType) and not their SuperType (FlatScreenTV) - This is bad use of Inheritance as it is NOT using inheritance lol.
If your code wants to access properties particular to a given type, then you really want this code encapsulated within that type. Otherwise everytime you add a new TV type, all the code that handles the TV list would need to be updated to reflect that.
So you should include a method on FlatScreenTV that does x, and override this in TV's as required.
So basically in your Main method above, instead of thinking I want to be dealing with TVTypeX, you should always refer to the basetype, and let inheritance and method overriding handle the specific behaviour for the subtype you are actually dealing with.
Code eg.
public abstract class FlatScreenTV
{
public virtual void SetOptimumDisplay()
{
//do nothing - base class has no implementation here
}
}
public class PhilipsWD20TV
{
public int BackLightIntensity {get;set;}
public override void SetOptimumDisplay()
{
//Do Something that uses BackLightIntensity
}
}
"the factory method is for multiple concrete classes that have the exact same implementation as the abstract base class [interface] and do not add their own properties."
No, speaking more practical, than theorical, the factory method can provide you with objects of concrete classes, in which the concrete classes, must have some common methods and interfaces, but, also some additional specific attributes.
Sometimes I use a method that creates the same class object every time I called, and I need to call it several times, and sometimes I use a method that create several different class objects, and that maybe be confusing, maybe another question.
And, your further comment about a switch sentence, with many options, when using the factory pattern, you usually provide an identifier for the concrete class / concrete object. This can be a string, an integer, an special type id, or an enumerated type.
You could use an integer / enum ID instead, and use a collection to lookup for the concrete class.
You can still leverage a factory. The point of a factory IMO is to put all the heavy lifting of constructing your various TVs in one place. To say categorically "a factory is for multiple concrete classes that have the exact same implementation as the abstract base class" is forgetting about polymorphism.
There is no law that says you cannot use a factory pattern because the sub classes declare unique properties and methods. But the more you can make use of polymorphism, the more a factory pattern makes sense. Also as a general guideline, IMHO, the more complexity that must go into constructing from the base the better off you are in the long run using a factory because you are "encapsulating change" - that is, constructing concrete classes is likely to change due to differing requirements and inherent construction complexity (a design analysis decision, to be sure) . And that change is in a single class - the factory.
Try this: Define everything in the abstract class and then for a given TV subclass either write concrete-specific code, and for those that don't apply write some standard "I don't do that" code.
Think about all the things your TVs do in generic terms: turn on, turn off, etc. Write a virtual method shell in the base class for all the generic things a TV does - this is a simple example of the template method pattern by the way. Then override these in the concrete classes as appropriate.
There are other things you can do in the base class to make it more fundgeable (that's a technical term meaning "reference subclasses as the base class, but do sub-classy things").
Define delegate methods (very powerful yet under-utilized)
use params[] for dynamic method parameter lists
Make Property delegates
Static methods
Declare Properties and methods "abstract" - forces sub-class implementation, vis-a-vis "virtual"
Hide inherited stuff in the sub class (generally using "new" keyword to communicate that it's on purpose)
If construction parameters are numerous or complex, create a class specifically designed to pass configuration to the factory's build method.
public class TVFactory {
public TV BuildTV(Brands thisKind) {
TV newSet;
switch (thisKind) {
case Brands.Samsung :
Samsung aSamsungTV = new Samsung();
aSamsungTV.BacklightIntensity = double.MinVal;
aSamsungTV.AutoShutdownTime = 45; //oops! I made a magic number. My bad
aSamsungTV.SetAutoShutDownTime = new delegate (newSet.SetASDT);
newSet = aSamsungTV;
break;
. . .
} // switch
}
//more build methods for setting specific parameters
public TV BuildTV (Brands thisKind, string Size) { ... }
// maybe you can pass in a set of properties to exactly control the construction.
// returning a concrete class reference violates the spirit of object oriented programming
public Sony BuildSonyTV (...) {}
public TV BuildTV (Brands thisKind, Dictionary buildParameters) { ... }
}
public class TV {
public string Size { get; set; }
public string ScreenType { get; set; }
public double BackLightIntensity { get; set; }
public int AutoShutdownTime { get; set; }
//define delegates to get/set properties
public delegate int GetAutoShutDownTime ();
public delegate void SetAutoShutDownTime (object obj);
public virtual TurnOn ();
public virtural TurnOff();
// this method implemented by more than one concrete class, so I use that
// as an excuse to declare it in my base.
public virtual SomeSonyPhillipsOnlything () { throw new NotImplementedException("I don't do SonyPhillips stuff"); }
}
public class Samsung : TV {
public Samsung() {
// set the properties, delegates, etc. in the factory
// that way if we ever get new properties we don't open umpteen TV concrete classes
// to add it. We're only altering the TVFactory.
// This demonstrates how a factory isolates code changes for object construction.
}
public override void TurnOn() { // do stuff }
public override void TurnOn() { // do stuff }
public void SamsungUniqueThing () { // do samsung unique stuff }
internal void SetASDT (int i) {
AutoShutDownTime = i;
}
}
// I like enumerations.
// No worries about string gotchas
// we get intellense in Visual Studio
// has a documentation-y quality
enum Brands {
Sony
,Samsung
,Phillips
}

Object representation of betting rounds at poker

I'm writing a HandConverter of a poker hand. This is my first project and I'm trying to do it right from the beginning.
I got already the most parts, like lists of players, their position, stack sizes, cards for different boards, what game is being played and so on, but I struggle with the representation of the betting, especially the different raises, bets and multiple calls from the same player.
I found some cases where my naive case based solution does not work, and it's really complicated and I dislike it. As it currently works for NL Hold'em I think I'll have more workarounds to do if I want to implement games like Stud, Razz and so on altough the betting structure is likely the same.
For now I use this representation and I would like to improve especially the Round and Action classes. Do you have some suggestions for me?
public class HandHistory
{
public GameInfo GameInfo;
public TableInfo TableInfo;
public List<Player> Players;
public List<Round> Rounds;
public string rawtext;
public bool withHero;
}
public Round
{
public List<Action> Action;
public string Name;
public decimal Potsize;
public ulong Cards; //usually would have used a custom class,
//but I need them in a ulong mask for some library I use
}
public class Action
{
public Player Player;
public string Type;
public decimal Amount;
}
P.S. I'm also using a List to store the different rounds, is there better way like inheriting the round class for Flop, Turn and River e.g?
Instead of a string for your Action.Type, you could use an enum:
enum BettingAction
{
Check,
Bet,
Call,
Raise,
Fold
}
When you say first project what do you mean? I am guessing you are a student or new to programming.
Under that assumption I would suggest picking something simpler and than a poker hand history. As in game programming it is unreasonable to think on your first shot of programming a game you create the latest Call of Duty. You start with breakout and move up from there.
If you do not wish to start smaller than I suggest never jump into coding. When you do that you will spend more time just spinning your wheels rather than getting something done.
For instance you should first spend time designing what your program will do and what it will not do. Try to be as complete as possible. This can be done from something as complicated using a UML program or as simple as pen and paper.
I would flow out how you want a hand to progress. Information you want to track. Once you really understand this your data structures will start to come to life.
Since you are new to programming, I would start to write proof of concept code. Then move it to your final project. What I mean by proof of concept is code that you are just testing an idea to see how it works. For example, how would hand history work? Can you create some 'mock' history and set them up? Ideally you would unit test, but lets start a little smaller.
It is important to know that you are constructing a program, just like a house. You need to know what you want it to do and not do (blue prints). What each step is. And you build upon other pieces slowly. It is a process that takes time, but in the end is well worth it.
Cards could have a better name, but I am assuming you mean the community cards. I would make it a list of Cards, then the turn and river subclasses would just only ever have one card in the list. I would also suggest representing the cards in a way that makes sense to you and then doing a conversion when you need to interface with the library.
Not really a programming related answer; but the betting styles for Razz or Stud is different from Hold 'em in several ways.
1.) There are no blinds; rather antes
2.) The person opening can either bring-in or complete the bet
3.) There are more rounds of betting
You have a pretty good start. You'd probably want to create a List<Hands> which has List<Rounds> inside it. Otherwise you'll have a huge list of rounds without being able to tell when one hand started/ended and another one began.
I think you probably need to define out your action types, and then things will probably start to fall into place. Here's what I would have for types:
Check
Bet
Fold
Call
Raise (essentially a call and bet)
Might also want to think about implementing something like "Prior Action" on your action class; as each player is reacting to the action before them.
You'd also want to address some nuances of the game; where player a bets 500 and player b goes all in for 250; since except in this instance, the call needs to match the prior bet.
The term Round is a little ambiguous. BettingRound makes it more obvious.
I don't see the need to have cards, name and potsize here. Potsize is a function of the actions and changes throughout the betting round.
Seats represent the game a little better than a list of players does as this allows you to represent the game state (stack sizes etc.) a little more obviously.
I don't see the need to make the flop, river cards explicitly assigned to rounds - just use a list of cards and some conventions. e.g. first three cards = flop... first betting round = flop. Use some extension methods for convenience of referring to the flop for holdem.
Use the ulong version of cards via conversion when you need to use it rather than cluttering your domain model.
This is how I see the model of a particular individual Game (i.e. 1 flop, river, turn etc.). There's still a bunch of work to do to model all games (e.g. limit games use small bet / big bet instead of blinds to define the stakes).
public class Card
{
public Suit Suit;
public Rank Rank;
public ulong ToCardMask();
}
public enum Suit
{
Clubs,
Diamonds,
Hearts,
Spades
}
public enum Rank
{
Ace,
Deuce,
Trey,
//...
Jack,
Queen,
King
}
public class Game
{
public GameInfo GameInfo;
public TableInfo TableInfo;
public List<BettingRound> BettingRounds;
public List<Card> CommunityCards;
public string Rawtext;
public bool WithHero; //??
}
public static class GameExtensions
{
public static BettingRound Flop(this Game game)
{
return game.BettingRounds[0];
}
public static List<Card> FlopCards(this Game game)
{
return game.CommunityCards.Take(3).ToList();
}
}
public class GameInfo
{
public GameType GameType;
public GameBettingStructure BettingStructure; // Limit, PotLimit, NoLimit
public Stakes Stakes; // e.g. { $1, $2 }
public long Id;
public List<Seat> Seats;
}
enum GameType // prob change to a class for extensibility
{
HoldEm,
Razz,
StudHi,
StudHiLo,
OmahaHi,
OmahaHiLo
}
enum GameBettingStructure
{
Limit,
PotLimit,
NoLimit
}
class Stakes // probably needs some tweeking for stud games (e.g. bring-in ...)
{
public Money Ante;
public List<Money> Blinds;
}
public class Seat
{
public Player Player;
public Money InitialStackAmount;
public Money FinalStackAmount; // convienience field can be calculated
public List<Card> Hand;
}
class Money
{
public decimal Amount;
public Unit Unit;
}
enum Unit
{
USD,
EUR,
AUD,
TournamentDollars
}
public class Player
{
public string Name;
}
public class TableInfo
{
public string Name;
}
public class BettingRound
{
public List<BettingAction> BettingActions;
}
public class BettingAction
{
public abstract Money PotSizeAfter();
public byte SeatNumber;
}
public class Fold : BettingAction { }
public class Call : BettingAction { }
public class BringIn : BettingAction { }
public class Complete : BettingAction { }
public class Bet : BettingAction
{
public Money Amount;
}
public class Raise : Bet { }
instead of SubClassing Round into FlopRound TurnRound etc, I would use a Street attribute within round, and within Action as well.
static public enum Street {PREFLOP, FLOP, TURN, RIVER};
...

Categories