Reputation: 437
I have read from other sources that it isn't a good idea for objects to know about each other especially the ones on same level. It should be more like hierarchy.
My problem is quite unique as I haven't figured out a way around it. Also I have been unlucky to come across any topic that addresses my issue specifically.
The problem
I am building a chess app and I am constructing the model of the app. Right now I have an abstract objects like for example Piece
which other pieces like Queen
, Knight
and the rest would inherit from.
I also have a Board
class which handles all board model and state of a game. Now each of my piece has a generateMove()
method to calculate possible moves from their position and to do this they need to know the state of the board. Also the Pieces are been instantiated by Board at startup.
Question Do I go ahead and instantiate Pieces by e.g
public class ChessBoard{
Boardbit = 64bit
Knight = new Knight(start_position, this)
//calculate
}
and then in Knight class method
public long generateMove(ChessBoard);
If no, what other ways can I go about it?
Upvotes: 0
Views: 168
Reputation: 29028
Making Chessboard
to know the Knight
and vise versa is not elegant. I agree with you in this point. Kind of sticking with the 'Tell don't ask' rule forces the 'higher level' element, in this case the chessboard, to tell the piece to move while providing all the required information. The Chessboard
itself doesn't know which piece is moving (in this case of predicting possible moves for all pieces), but for sure never knows any details about how a piece can move or is allowed to move. This is just one possible solution using sort of Strategy Pattern. (The Visitor or some similar pattern could also be used here):
Main() {
chessboard = new Chessboard()
PiecesCollection = new PiecesCollection(new Knight(KnightStrategy, Color.Black))
chessboard.AddPieces(PiecesCollection)
CollectionOfAllPossibleMoveCollections = chessBoard.CallculateAllPossibleMoves()
Move selectedMove = ShowOrSelectMove(CollectionOfAllPossibleMoveCollections)
chessboard.ExecuteMove(selectedMove)
}
public class Chessboard{
// fields
PiecesCollectionWhite
// where 'PiecesCollectionWhite' is a collection of `Piece`
PiecesCollectionBlack
// where 'PiecesCollectionBlack' is a collection of `Piece`
CurrentlyVisitedPositionsCollection
// where 'CurrentlyVisitedPositionsCollection' is a collection of `Position`
// methods
AddPieces(PiecesCollection, Color)
CallculateAllPossibleMoves(Color) {
CollectionOfPossibleMoveCollections =
FOREACH Piece IN PiecesCollection OF Color
DO Piece.CalculateMoves(this.CurrentlyVisitedPositionsCollection)
return CollectionOfAllPossibleMoveCollections // where 'CollectionOfAllPossibleMoveCollections ' is a collection that holds a collection of `Move` of which each nested collection represents the possible moves of a chess piece.
}
ExecuteMove(Move) {
RemovePieceFromBoardIfNecessary(Move.ToPosition)
}
}
public class Piece
{
// fields
Strategy
Position
Color
// methods
CallculateMoves(CurrentlyVisitedPositionsCollection) {
PossibleMovesCollection = this.Strategy.Execute(CurrentlyVisitedPositionsCollection, this.Position)
return PossibleMovesCollection where `PossibleMovesCollection` is a collection of `Move`
}
}
public class Knight extends Piece
{
ctor(Strategy, Color)
}
public class Stragtegy
{
abstract Execute(currentPosition, allPiecesPositions) : PossibleMovesCollection
}
public class KnightStrategy extends Strategy
{
Execute(currentPosition, allPiecesPositions) {
PossibleMovesCollection = ApplyKnightMoveAlgorithm()
return PossibleMovesCollection
}
private ApplyKnightMoveAlgorithm() : PossibleMovesCollection
}
public class Move
{
Position fromPosition
Position toPosition
}
public class Color
{
Black
White
}
public class Position
{
Color
xCoordinate
yCoordinate
}
This is just a sketch and not a complete example. There is some state information or operations missing. E.g. maybe you would have to store the Color
that was moved last on the chessboard.
Since the Chessboard
returns all possible moves (information about all currently visited coordinates) you can easily enhance the algorithm by implementing some intelligence to predict the best possible moves from this information. So before the controller or in this case the Main()
will call Chessboard.ExecuteMove(Move)
it could make a call to PredictionEngine.PredictBestMove(CollectionOfAllPossibleMoveCollections)
.
Upvotes: 1
Reputation: 23049
Much better is to have method generateMove(boardState)
, so your Board should call whatever piece you have and pass them the necessary information for such task. It can be used even for some optimization as board can pregenerate some good-to-use structure each round only once and then pass it to all the pieces (like some 2d array).
Upvotes: 1