Skip to main content
Tweeted twitter.com/StackSoftEng/status/1000507142514888704
edited tags
Link
Deduplicator
  • 9.3k
  • 5
  • 33
  • 53
added 4 characters in body
Source Link
Jansky
  • 181
  • 4

I frequently come across this problem when developing games and simulations. As an example, I'm currently writing an implementation of chess. I'm using it as a vehicle to experiment with entity-component systems and responsibility chains, inspired by Brian Bucklew's talk on Roguelike architecture (https://www.youtube.com/watch?v=U03XXzcThGU). Ultimately I'd like to be able to express each behavioural component of Chess as a small, encapsulated component of a chess piece and swap these out at a whim to quickly create pieces with new behaviours.

So I have a Game which has a Board, and the Board may have a number of Pieces each of which may have a number of Components. I don't have a notion of what type a Piece is, rather I encode their behaviour through their Components; you can send a "IsOwnedByPlayerOne" message to determine which side the Piece is on, for example:

IComponent.cs:

public interface IComponent
{
    void Handle(ref Message message);
}

Piece.cs:

public bool IsOwnedByPlayerOne()
{
    var isOwnedByPlayerOneMessage = new Message(MessageType.IsOwnedByPlayerOne);
    Handle(ref isOwnedByPlayerOneMessage);

    return isOwnedByPlayerOneMessage.GetParameter<bool>(MessageParameter.IsOwnedByPlayerOne);
}

The issue I've come to is this: a Component is very much a low-level type, but they need awareness of the world around them which can only be achieved through access to higher-level types. For example, say I send a "IsLegalMove" message to a Rook Piece, asking whether it can legally move from a1 to a6. It would need to check whether there are any other Pieces between a1 and a6, which requires access to the Board. But the Board itself contains the Piece which in turn contains the Component, so conceptually the design is getting a bit loopy.

I could give either Piece or Component access to Board as a field. Or I could add Board as a parameter to IComponent``'s Handle() method. I don't feel great about either of these solutions but can't put my finger on why. Which one would be better aligned with quality software principles? Or are there others you'd recommend?

I frequently come across this problem when developing games and simulations. As an example, I'm currently writing an implementation of chess. I'm using it as a vehicle to experiment with entity-component systems and responsibility chains, inspired by Brian Bucklew's talk on Roguelike architecture (https://www.youtube.com/watch?v=U03XXzcThGU). Ultimately I'd like to be able to express each behavioural component of Chess as a small, encapsulated component of a chess piece and swap these out at a whim to quickly create pieces with new behaviours.

So I have a Game which has a Board, and the Board may have a number of Pieces each of which may have a number of Components. I don't have a notion of what type a Piece is, rather I encode their behaviour through their Components; you can send a "IsOwnedByPlayerOne" message to determine which side the Piece is on, for example:

IComponent.cs:

public interface IComponent
{
    void Handle(ref Message message);
}

Piece.cs:

public bool IsOwnedByPlayerOne()
{
    var isOwnedByPlayerOneMessage = new Message(MessageType.IsOwnedByPlayerOne);
    Handle(ref isOwnedByPlayerOneMessage);

    return isOwnedByPlayerOneMessage.GetParameter<bool>(MessageParameter.IsOwnedByPlayerOne);
}

The issue I've come to is this: Component is very much low-level type, but they need awareness of the world around them which can only be achieved through access to higher-level types. For example, say I send a "IsLegalMove" message to a Rook Piece, asking whether it can legally move from a1 to a6. It would need to check whether there are any other Pieces between a1 and a6, which requires access to the Board. But the Board itself contains the Piece which in turn contains the Component, so conceptually the design is getting a bit loopy.

I could give either Piece or Component access to Board as a field. Or I could add Board as a parameter to IComponent``'s Handle() method. I don't feel great about either of these solutions but can't put my finger on why. Which one would be better aligned with quality software principles? Or are there others you'd recommend?

I frequently come across this problem when developing games and simulations. As an example, I'm currently writing an implementation of chess. I'm using it as a vehicle to experiment with entity-component systems and responsibility chains, inspired by Brian Bucklew's talk on Roguelike architecture (https://www.youtube.com/watch?v=U03XXzcThGU). Ultimately I'd like to be able to express each behavioural component of Chess as a small, encapsulated component of a chess piece and swap these out at a whim to quickly create pieces with new behaviours.

So I have a Game which has a Board, and the Board may have a number of Pieces each of which may have a number of Components. I don't have a notion of what type a Piece is, rather I encode their behaviour through their Components; you can send a "IsOwnedByPlayerOne" message to determine which side the Piece is on, for example:

IComponent.cs:

public interface IComponent
{
    void Handle(ref Message message);
}

Piece.cs:

public bool IsOwnedByPlayerOne()
{
    var isOwnedByPlayerOneMessage = new Message(MessageType.IsOwnedByPlayerOne);
    Handle(ref isOwnedByPlayerOneMessage);

    return isOwnedByPlayerOneMessage.GetParameter<bool>(MessageParameter.IsOwnedByPlayerOne);
}

The issue I've come to is this: a Component is very much a low-level type, but they need awareness of the world around them which can only be achieved through access to higher-level types. For example, say I send a "IsLegalMove" message to a Rook Piece, asking whether it can legally move from a1 to a6. It would need to check whether there are any other Pieces between a1 and a6, which requires access to the Board. But the Board itself contains the Piece which in turn contains the Component, so conceptually the design is getting a bit loopy.

I could give either Piece or Component access to Board as a field. Or I could add Board as a parameter to IComponent``'s Handle() method. I don't feel great about either of these solutions but can't put my finger on why. Which one would be better aligned with quality software principles? Or are there others you'd recommend?

Source Link
Jansky
  • 181
  • 4

How does one resolve low level types dependent on high level types?

I frequently come across this problem when developing games and simulations. As an example, I'm currently writing an implementation of chess. I'm using it as a vehicle to experiment with entity-component systems and responsibility chains, inspired by Brian Bucklew's talk on Roguelike architecture (https://www.youtube.com/watch?v=U03XXzcThGU). Ultimately I'd like to be able to express each behavioural component of Chess as a small, encapsulated component of a chess piece and swap these out at a whim to quickly create pieces with new behaviours.

So I have a Game which has a Board, and the Board may have a number of Pieces each of which may have a number of Components. I don't have a notion of what type a Piece is, rather I encode their behaviour through their Components; you can send a "IsOwnedByPlayerOne" message to determine which side the Piece is on, for example:

IComponent.cs:

public interface IComponent
{
    void Handle(ref Message message);
}

Piece.cs:

public bool IsOwnedByPlayerOne()
{
    var isOwnedByPlayerOneMessage = new Message(MessageType.IsOwnedByPlayerOne);
    Handle(ref isOwnedByPlayerOneMessage);

    return isOwnedByPlayerOneMessage.GetParameter<bool>(MessageParameter.IsOwnedByPlayerOne);
}

The issue I've come to is this: Component is very much low-level type, but they need awareness of the world around them which can only be achieved through access to higher-level types. For example, say I send a "IsLegalMove" message to a Rook Piece, asking whether it can legally move from a1 to a6. It would need to check whether there are any other Pieces between a1 and a6, which requires access to the Board. But the Board itself contains the Piece which in turn contains the Component, so conceptually the design is getting a bit loopy.

I could give either Piece or Component access to Board as a field. Or I could add Board as a parameter to IComponent``'s Handle() method. I don't feel great about either of these solutions but can't put my finger on why. Which one would be better aligned with quality software principles? Or are there others you'd recommend?