views:

71

answers:

3

Hey folks,

I'm currently teaching myself objective C. I've gone through the tutorials, but I find I learn best when slogging through a project of my own, so I've embarked on making a backgammon app.

Now that I'm partway in, I'm realizing there's some overall architecture things I just don't understand.

I've established a "player" class, a "piece" class, and a "board" class. A piece theoretically belongs to both a player and the board. For instance, a player has a color, and every turn makes a move; so the player owns his pieces. At the same time, when moving a piece, it has to check whether it's a valid move, whether there are pieces on the board, etc.

From my reading it seems like it's frowned upon to reach across classes. For instance, when a player makes a move, where should the function live that moves the piece? Should it exist on board? This would be my instinct, as the board should decide whether a move is valid or not; but the piece needs to initialize that query, as its the one being moved, no?

Any info to help a noob would be super appreciated. Thanks guys!

+2  A: 

When you're modeling something based on the real world, it's tempting to have one class for each real world object. This is often a good start, but inevitably, you'll drift away from what those objects are in the real world, based on the requirements of the program you're writing.

What's most important is not that each class has an internally-consistent set of data and operations. So, it might make sense to have the "board" able to answer the question "is this a valid move", but have the gamepiece have the logic to move itself from one location to another. Alternatively, you might have a "game" object that keeps track of all of the state of the game, and have a "rules" object that allows you to play the game under different rules.

Something like CRC cards might be helpful in getting the design nailed down. If you're a visual thinker, you might find it easier to figure out what each class should do by having a more-abstract diagrammatic representation of the program structure.

Mark Bessey
A: 

First of all, you should separate conceptually things that have to do with graphical representation and animation from the underlying logic of the game. My answer to this question is probably relevant to your situation.

In backgammon and other board games, the pieces are passive and have no state except position, and should be very simple. In chess for example, it might be appropriate to put the validation code (checking whether a move is valid) in the various piece classes (king, pawn...). The logic in backgammon is much simpler, so probably could be done in one central method.

My first take would be: a game manager object is keeping track of the movement as the user drags a piece around. When the piece enters a particular triangle, the manager calls a method (on itself) to check whether the move is valid and display a red or green frame for example. When the user releases the piece on a valid triangle, the manager tells the board to update itself. The board object might not have to be more than an array.

Note that there is constant interaction between the logic code and the graphical code here. When a piece is being dragged, you have to graphically check whether it's inside a triangle, or an area surrounding the triangle. Then you have to find out which object (or merely index into an array) in the game logic this corresponds to in order to do the validation.

It's great to do a relatively simple project like this to learn how to slice up the code and how not to mix logic with representation.

Felixyz
+1  A: 

I think you're probably over engineering your class hierarchy. A good rule of thumb is to start with a handful of classes whose functionality do not overlap, and then refactor your overall design, on demand, as you expand on your program.

A class to model each player may not be necessary at all. I would start by just having a board class manage the "state" of the backgammon game -- namely whose turn it is, if the dice have been rolled, the dice roll if necessary, the state of all 24 points + bar + "off" for each player, the state of the doubling cube, the current match length and the current score for each player. (I wrote my MSc thesis on backgammon, including a command line shell program to play games, so I understand the domain here fairly well.)

@Mark Bessey I would certainly not have a design where the piece (checker) knows how to move itself.

@Felixyz Determining a legal move is actually a little more difficult in backgammon than it is in chess. This is especially true if you want to generate the complete list of legal moves on any given turn.

Shaggy Frog
I only said that you *could* do it that way. Whether or not you'd want to depends on the overall design.
Mark Bessey