Stanley Aloh
Stanley Aloh

Reputation: 437

What pattern do I use for interdependent class

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

Answers (2)

BionicCode
BionicCode

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

libik
libik

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

Related Questions