-1

So now i have a really concrete example; its highly related to that question here: Tell one, but ask the others?

the important statements there are:


In the comment section https://softwareengineering.stackexchange.com/a/418453/347781 :

But what you would say if both sides pull out the data?, ok i put the behaviour to the Chatroom, but the Chatroom pulls then out the data from the user, because it needs to fullfill its algorithm data from both,....... maybe then we have a third party, fourth and so on, The Chatroom would pull out data from all of the others. What kind of benefit i have to put then the behaviour to the Chatroom. On which metric i can decide to put it to the Chatroom, because you said placing the bevahiour to that location, which dont pull out data, but if each one of them pull out data?^^ – Robin Kreuzer

@RobinKreuzer You have to come up with a design in which no objects pull data out of other objects (some rare exceptions apply). That is what object-orientation is at its core. Objects are there to contribute behavior. It is the key factor that makes oo more maintainable than procedural programming. – Robert Bräutigam

and my abstract example here:

if(
something from user &&
something from ChatRoom &&
something from something deep in the user, maybe the color of the users fingernail? &&
something merged from user and Chatroom (the niceLevels for example) &&
something from clock &&
something ....
)

then

{
change some state in the user
change some state in the ChatRoom
change some state in the niceLevels of user and ChatRoom
change maybe the clock?
change something in a third-party-object, which was not in the if-checks (maybe sending a notification/email or something else)
change some state in ....
}

the quote and the abstract code example are both from the Tell one, but ask the others topic the abstract example should show how complex interacting/collaborations of objects could be; that it is not that easy like Robert Bräutigam claim in his quote.


Now i want to give a concrete example/question:

Let's take a chess game, if a client/user wants to move the tower five spaces forward, then there must be a few constraints full-filled.

  • The tower is not allowed to cross an own figure or a other figure (a horse is allowed to do so)
  • The tower can throw hostile a figure from the game if it is on field five spaces forward from him.
  • And so on

Now i want to add some game-rules:

  • If the a hostile figure is threw away, all fields the tower touched are colored red, if no figure is threw from the game, all fields the tower touched are colored grey. The horse color its field in all cases green.
  • If a tower and only the figure tower reaches the other side, the game-mode is changed, so all figure should now act in a other way. Maybe game-change could be that no more figures are allowed to be thrown from game the next 10 turns, and all figures are now only allowed to move in maximum 2 spaces
  • if a farmer reaches the other side, it is morphed to a queen and all towers a player left should morphe to horses
  • All figures can be named by the user and its movement action are counted, if a figure is morphed it keep that informations
  • a runner is only allowed to throw a hostile figure from the game, if itself moved at least 15 times and only 17 figures (sum of all figures from both teams) are left

And now we have there still a few more (more technically) requirements:

  • The client is only then allowed to move one of its figures, if when it is his turn^^
  • the game is controlled cli-based/text-based, so the user sends text-command to select one figure and signalize its movement (how you would dispatch this?)

So i think i have now a great NOT abstract examples, what was wished by so many of you. Im interested now, how you would model this to full fill Robert Bräutigams constraints, which is more or less the same as Demeter had too.

A few thoughts from me

  • Maybe we can add the whole behaviour into the figures?, but then it have to pull out the state of the world around it?! -> a more or less procedural approach, because one code-actor/procedur acting on the other state?
  • Maybe we should try to divide the behavior into the figures and the world around, but i can't see that the get there the wanted transactional-style. Also we get into trouble if we want to change the game-mode, we have to change it in all objects? And i think its not possible alone doing it that way, because we need merged-state ("runner is only allowed to throw [...] are left") -> the hoped OO-approach from Robert Bräutigam?

.

Ok now i stop here with my thoughts^^, i don't want to suggest that there is no solution on that i am interested in, that hopefully exists

Edit:

ok i thought it it was clear what the focus of my question is, because it linked and related that question here to the abstract one Tell one, but ask the others?

Anyway, my question is how you would model my real-world Robins magic chess game in that way that it full fills the constraint given by Robert Bräutigam (see the quote at the beginning) being then a object oriented model that doesn't pull out data from others and what the benefits are doing it like that way.

I hope the focus is clear now.

So i also don't look at a generic chess-game model-solution (as Doc Brown thought, because he linked to a search of chess-game solution, but on a special kind of modeling, like i described beginning at "Anyway, my ques....")

8
  • 3
    Side note: Instead of inventing new terms for chess pieces by translating german terms to english literally, please have a look into Wikipeda for the correct names. – Doc Brown Apr 5 at 7:46
  • And to your question: I would recommend to go through the questions on chess design and OOP which were asked on this site beforehand, you can try this search, for example. You will find the topic was discussed several times. – Doc Brown Apr 5 at 8:00
  • German is the official language of chess – Ewan Apr 5 at 11:36
  • @Ewan: so you think we should all now call pawns "farmers", rooks "towers" and bishops "runners"? First of april was four days ago, you know ;-) – Doc Brown Apr 5 at 14:37
  • 1
    @Ewan: "well they are the official names?" - did you look into the Wikipedia article I linked above? I can only guess how using german terms for chess pieces must appear to english native speakers, but if someone would use the english terms for those pieces when asking me a question in german, I would be pretty confused and irritated. – Doc Brown Apr 5 at 18:35
3

A game of chess is fully described by the list of moves that have taken place and the rules of the game. (8x8 board, starting positions etc)

If you want to program it in a OOP style your objects are not Piece, Board etc they are things like Turn, Move, Game, NotiationParser, BoardDrawer and the like

When learning OOP all the examples focus on real world objects, "a Car has four Wheels", "a Cat is an Animal" etc but in actual programming your objects are abstract collections of data and functions that operate on that data.

With real world objects we can see real connections between them, we know a Car is not an Animal. But with games or business rules there are no outside constraints.

We say "a Pawn is a Piece" because we are used to the physical game pieces, but in terms of the game rules it's completely different from the other pieces. It has crazy rules which depend on the position of other pieces and their move history! It can change into a different piece!, It knows about the board orientation!

struct Move
{
   position From
   position To
}

class Rule
{
     public Rule(list<move> movesSoFar) {...}
}
class PawnMoving : Rule
{
    bool IsValidMove(Move m);
    {
       //is there a pawn on the from square?
       //is is there a piece on the to square?
       ...etc
    }
}
class WhosTurnIsIt : Rule
{
    bool IsValidMove(Move m)
    {
        //what colour piece is on the From square
        //what colour moved last?
        //are we castling?
    }
}
class CanOpponentTakeKingAfterThisMove: Rule
{
    bool IsValidMove(Move m)
    {
       ...
    }
}
5
  • i think your solution differes basically from that what @RobertBräutigam does?, Turn, Move, BoardDrawer are "verbs", so you would write serivces/controller to change the domain-state?, you separate data and behavior?, The point is, that thislike you program it fits better to SOLID and similar rules, as Flater wrote in his answer in my Tell one, but ask the others topic; What kind of benefits we got coding like this and why you would not code like RobertBräutigam do? – Robin Kreuzer Apr 5 at 14:32
  • The benefit of my way is it is SOLID. If you have the pieces as domain objects then you have to pass the move list in to all of them and they are highly coupled, you cant change the rules without altering many classes, you cant extend the classes. If your domain objects are Rule and Move, your objects encapsulate the logic and data. you can iterate the Rules to determine if a move is valid, add new and extend rules as required, Move is a generic struct which can cover new peices, different board geometries etc – Ewan Apr 5 at 16:01
  • also a interesting solution (your code-example), but where live for example the PawnMoving, isnt it bound to pawn-pieces? Or are the loose coupled and the command-dispatcher search unrelated for the peace and for the Rule? But yeah this style of prorgramming i like too (i started my carrer that way^^), and now i want to understand the other side, @RobertBräutigam s side (so i will accept his answer, i hope that this is ok for you) Maybe i will soon ask a question which side is better, or how we can get the benefits from both sides – Robin Kreuzer Apr 10 at 15:00
  • yeah for that rule-changing i had the constraint if the tower reaches the other chess-side the game-mode is changed; i asked in the comment-section Robert how he would do that hisway, but i think its how you said, not easy. One more question i have still for you: that way you program is procedurlal because of separating domain-objects from its domain-behaviour, would you agree with me in that point? (That point says but nothing if that way of programming is bad^^, so why not programming procedural, if it is the better way?^^) – Robin Kreuzer Apr 10 at 15:05
  • my point is that they are both OOP style programs. The only question is what objects do you choose? Don't just pick the 'obvious' a "Player Moves a Piece" and stick with it no matter what. Because you wont know what you domain objects are until you start to actually write code. – Ewan Apr 10 at 19:17
2

Of course you can have the pieces holding the necessary logic. The only problem you have, as you mentioned, is that you need all the information about the board and positions too.

There's a couple of possible options how to deal with that:

  1. You can pass all that information into the piece when necessary. For example on each invocation. of move or similar.
  2. You can pass updates to all pieces and let the pieces manage their view of the current board as they see fit. This enables some optimizations for specific movements for example.
  3. You can invert the above, and let the "board" manage most of this, and have the pieces manage only movement patterns. This is usable if the most of the rules apply to most of the pieces. I'm not sure they do, you have some strange rules there.
  4. You could control pieces or let them control themselves. For example you could either tell them to "morph" or tell them what happened and let them morph if they want to. There's a trade-off, but both are "oo compatible".

What I'm trying to describe is that even if you need to have lots of data at some point in the code to make a decision, you can manage that without pulling it from others. An alternative is to just pass it in, or let the object manage it, or even duplicate it. As I've said before it all depends on the exact requirements.

Also, here is an OO Tic-Tac-Toe game that has no getters at all, that demonstrates how to deal with some of the same problems you mentioned. This game was designed to be extensible with GUI and network players without changes to existing code.

Update: There were a lot of questions, so let's dive in:

  1. What would I pass in? Certainly not a Board object. Since the Piece would like data for its function and not an object.

Here, again, there is a distinction between data structures and objects. It is always tempting to just "group" certain data elements into a structure and pass the structure. You have to resist this urge.

While it may simplify some signatures in the short-term, you now create a structure which has no abstraction capabilities and likely tied to the consume or producer or both. It can never change independently. Which is bad.

So I would pass in exactly the data the Piece needs, a list of pieces or even an array of pieces, or an array of "cells" with the pieces in it. The Piece defines the contract (by having a public method), and others can choose to call it.

One other benefit of passing "data" along instead of pulling it out, in addition to the contract being defined by the consumer, is that the object managing that data can still retain control. It can decide how/whether/what to pass along.

  1. Have a look at the Tic-Tac-Toe example, this is actually done there.

  2. The Board does not have to micro-manage the Pieces. Have a look at the Game and Board classes in the Tic-Tac-Toe example. They don't manage the cells.

  3. A method morphToKnigth() is not a setter. Although there is a gray area at some point, where it is difficult to say. In this case it feels strange because this is a made up rule and has no "business"-related name.

"Morphing" a pawn to a queen is called promotion, so that would be a good, business-related method name that is clearly not a setter.

  1. What I mean by "duplicate" is just that. Pieces could hold onto their view of the current state on the board. This would enable pieces to hold highly optimized representations for example. Bitmasks of fields, whatever.

Object-orientation does not have the need to "normalize" data in the database sense. The same piece of data can be present in multiple representations, with differing or even same semantics.

I would have no problems (barring requirements to the contrary) having the state of the board held redundantly in all the pieces, if it would help/simplify/optimize my design in some way.

7
  • "OO Tic-Tac-Toe game that has no getters at all" - nice! – Filip Milovanović Apr 5 at 11:51
  • to 1) what would you pass in? and from where you would get it?, if you pass the board into the piece, then the piece have still to ask the board for its state. And what benefit i have passing the board into a piece if the piece could get the board itself with a reference to it? passing only certain board details to the pieace; then the invocation-method have to grab that informations out of the board that it can pass it to the pieces (also here we have asking).... to 2) maybe you can go there more into detail, i not really understand that – Robin Kreuzer Apr 5 at 14:18
  • to 3) in that case we have still one big procedur sitting in the board asking the pieces?.... to 4) what is the difference to 1)? and what you mean with the trade-off, morphing means, i have a wrapper object, changing in that the concreate piece object, right?, tell them to morph is more or less a setter, tell them what happend, what exactly would you tell there? so i have to tell each event which could occurs? and the wrapper-object decide then if the right event occurs if it should morph? – Robin Kreuzer Apr 5 at 14:22
  • you wrote at the end: "An alternative [...] duplicate it" maybe you can go there more into detail what you would just pass it in, what the object should manage itself, if the collaborating state is relevant, and what you mean with duplicate it....... Maybe you can go for each of your 4 points in your answer a little bit more into detail (maybe with a small example), but i think now its really going into the right direction, thank you^^ this time you got already my +1, @Robert Bräutigam (but it would be really nice to get a few more details on that so interesting topic^^) – Robin Kreuzer Apr 5 at 14:27
  • @RobinKreuzer See update. – Robert Bräutigam Apr 5 at 18:20

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