1

I am teaching myself to code again and thought I would write a card game.

I need help with my code design (I am using C#)

To start with I am building it as a console application, and later I will extend it so that it works as a web application.

The question I have is whether the Player objects are part of the Game objects ? or do Player objects (which are essentially clients) only interact with the Game Object through requests.

For example if I had a basic game where I had to deal 4 cards to 4 players and the player with the highest card wins. If two people get the same high card rank then the cards a re-dealt.

If the Players (clients) are not part of the Game (Server) then what is the design principal to trigger the event and rule to determine the highest card and then whether to redeal.

The Players themselves can only be aware of their own state.

Are the cards dealt to a player an attribute of the Player or are they an attribute of a List of Cards tied to the Game Object.

Just looking for some pointers here on design approach.

1
  • FWIW, and I won't get into details, but you really should be aware of this. "Technically" the implementation platform/user interface shouldn't matter for the design, and I am a HUGE proponent of that concept for everything but video games. When it comes to games and their design it matters a whole heck-of-a lot which engine you plan on using as it will drive your entire design.
    – Dunk
    Commented Mar 28, 2017 at 23:05

5 Answers 5

4

whether the Player objects are part of the Game objects ? or do Player objects (which are essentially clients) only interact with the Game Object through requests.

Use whatever approach leaves you with the most understandable and maintainable code. You shouldn't worry about whether a player is on the "client" or on the "server." It is common for a server to have objects that represent things that are outside the server, e.g. even a basic web app will have a User object.

Are the cards dealt to a player an attribute of the Player or are they an attribute of a List of Cards tied to the Game Object.

A player could have an attribute with a type of Hand which is a collection, e.g.

class Hand
{
    List<Card> _list;
}

class Player
{
    Hand _currentHand;
}

By keeping Hand and Player separate, you can compartmentalize the logic for, say, keeping score (which persists between hands) and tallying cards (e.g. you might have a Hand.IsStraightFlush() method).

8
  • Thanks for the response. But in my card game, the card is dealt to the player and the winner is the combination of all Players hands. In your example the calculation of the cards is based on the cards to dealt to the individual player (which from my perspective is slightly easier to design for). So if all players have a card and the winner is determined by the combination of all cards, then does it belong as an attribute of the player or does the "trick" belong to the game. Or are cards assigned to the player and then added to the game which has a list of cards ("trick"). Commented Mar 8, 2017 at 23:41
  • 1
    So it's just a game of chance? Doesn't sound very fun. As for your object model, sounds like you need a Trick class.
    – John Wu
    Commented Mar 9, 2017 at 0:36
  • No its more complicated then that, but I kept it basic for the purpose of the example, So that is the answer I think I needed. Would it work that A Player(s) has an association with a Game and a Game is comprised of Cards and a Trick, A Player is dealt a card(s) that are then thrown off into a Trick, After the cards are added to the trick then "something" <- not sure how. Will trigger to determine which player won the trick. Commented Mar 9, 2017 at 1:09
  • Well, so far you haven't mentioned a concept of workflow. You need something that tracks whose turn it is. When all turns are complete, it can also compute who won.
    – John Wu
    Commented Mar 9, 2017 at 1:18
  • Well I've programmatically worked out workflow by assigning Players to a List and sorting them by an order. Although in the future when I translate this to a web application I have no idea how I do this. I can't get my head around the idea of a restful design that can manage the state of all players. Any tips ? Do I need some type of rules table that dictates who gets dealt cards and who has the next turn? Commented Mar 9, 2017 at 3:01
1

There are two main concepts to understand

  1. When you send data over the wire, it's just data. no methods or code
  2. you can have more than object to represent the same thing

So when your Game object communicates with a Player object what happens is:

Game -> make new PlayerOnServer objects
Game -> call PlayerOnServer.DealCard(card)
PlayerOnServer -> send card data to client
PlayerOnClient -> receive card data and make a new Card object
PlayerOnClient -> call PlayerOnClient.DisplayCardOnScreen(card)

So here we have two types of Player object. One runs on the server and knows how to send cards to the client and one runs on the Client and knows how to display cards on the screen.

The Card object is just a representation of the data, and is shared between the two programs.

It might be helpful to think about this in a non-object oriented way.

Game -> write to client "5OfHearts"
Client -> listen on port Console.Write(incoming data)

wrapping up the write to client, listen on port and write to screen calls in objects doesn't change the underlying implementation. it just hides it from the higher layers of code

0

Your question is quite broad. You're eventually looking for a feasible architecture for a turn based server-client type of multiplayer game. A complete answer would require drawing a few diagrams and writing some skeletal code. I'm sure there are some detailed enough examples around somewhere.

However, there's one particular aspect about the design you should consider whether your application is going to be a local or a distributed multiplayer game or whatever.

It seems like you're about to mix the model and the control. I strongly recommend separating them. The module that holds the model for the game should not have any knowledge about servers or clients and such. The rules of a card game do not depend on whether the architecture of your game application is distributed or not. Actually, they don't even depend on whether you write an application for playing the game on computer or for simulating the game or for other purposes like tracking and keeping score of a live game.

So, I'd begin with first writing a working model for the card game itself. As long as you keep the model separated, you don't need to think about how you're going to implement some fancy distributed multiplayer game later on.

The model of a card game consists of few elements: a model for the cards and possible game tokens, a model for the game state and a model for the rules. Since we're talking about a turn based game, the rules of the game are mainly about defining legal actions and the effects actions have on the game state. I would expect the model to contain classes like

  • Card (for cards)
  • Deck (for a deck of cards)
  • GameState (aggregate for the game state; preferably serializable)
  • PlayerState (for holding the state of a player; child of GameState)
  • TableState (for holding the state of the game table if there's any; child of GameState)
  • Action (for actions a player could take)

The rule model should consist of methods and classes that control what kind of Actions are available at any state of a game and how a chosen Action would change the state of the game. The rule model should offer methods like:

  • List<Action> DetermineAvailableActions(GameState gameState)
  • GameState ResolveGameStateAfterAction(GameState initialGameState, Action action)

A simple rule model could consist of one class (GameRules) implementing above methods.

Should you choose to write a mutable GameState (which I wouldn't recommend) the latter method signature would be like

  • void ApplyAction(GameState gameState, Action action)

The model for the game should be absolutely agnostic about the rest of the application, the environment and particularly the user interface. The same model should work for a local single player game application as well as for a multiplayer server-client game application. You should be able to run simulations of whole games from the beginning to the end just using the model and a simple game loop, some logging and a minimally simple implementation of an AI or rather an artificial idiot just picking random actions.

After writing and testing the game model itself, you could continue with writing a game controller. The controller should contain the actual main loop of the game. It should be able to

  • take initial game settings (number of players, player types etc)
  • initialize the game state as per given settings
  • control the flow of the game and the communication between modules
  • send messages to players by invoking methods of some PlayerController objects
  • listen to messages sent by players

Details of the controller depend on the architecture of the game application. The controller should know about all modules involved. However, if you play your cards right, you could use the same controller for controlling a simple local game or simulation as well as a distributed multiplayer game.

A simplified game loop could look like this:

while (!currentGameState.IsFinished()) {
    activePlayerController = playerControllers.Get(currentGameState.GetActivePlayerId());
    List<Action> availableActions = rules.DetermineAvailableActions(currentGameState);
    activePlayerController.SendPleaseChooseActionMessage(currentGameState, actions);
    Action chosenAction = ReceiveChosenAction();
    currentGameState = rules.ResolveGameStateAfterAction(currentGameState, chosenAction);
    gameStateHistory.Push(currentGameState);
    for (PlayerController c: playerControllers) {
          c.SendGameStateUpdatedMessage(currentGameState, chosenAction);
    }
}

If you're not an experienced programmer, I'd suggest trying to write a simple local game first. Just keep the model, the controller and the user interface separated.

1
  • Wow.. thanks for this response. This is where I want to get to and its great to see the end state. I'm going to start but just writing the game using my own design with the basic objects required, and then I'll rewrite it using a more sophisticated pattern that you have suggested Commented Mar 10, 2017 at 2:51
0

Forget up-front design. You don't have the experience to produce a useful design, and you don't have clear requirements. If you did have the experience, you wouldn't bother because you would know that up-front design at the class level is a waste of time. Come up with a simple game and implement it in the simplest possible way starting with a single method in a single class. As the code grows, you can start extracting blocks of code into separate methods. As the number of methods grows, extract related methods into new classes. Not only will this be more fun, since you have working code almost immediately, but the resulting class structure will be better.

0

Going back to your original question; I would separate the Players from the Game mechanics completely.

The Game will deal Cards to a collection of 'Seats' at a Table. Then it will compare the Cards in each 'Seat' , deciding which 'Seat' has the best hand (or if it is a draw). This is essentially the mechanics of the Game.

Each 'Seat' can have a Player attached to it. If it has no Player attached, the Game does not deal Cards to that 'Seat' (unless your rules are otherwise).

This then allows you to have a Player leave the Game (abandon their 'Seat') and another one join it at the newly vacant 'Seat'.

Any winnings/points accrued etc. will be passed on to the applicable 'Seat' at the time it had the winning Hand.

Essentially, the Game does not care about Players (their names, chips, money, etc.) whether they are at the Table or away - it only cares about what is supplied to a 'Seat' at the Table.

If the Game is supplying points or chips to winners, it supplies them to the 'Seat'.

The attaching/detaching of a Player to a 'Seat' would entail either adding points or chips to the 'Seat' to enable play (from the Player's personal collection), or the removal (to the Player's personal collection) of anything won while at the Table when they leave.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.