Bejeweled Design Challenges

I am trying to execute a Bejeweled design. I have basically 3 classes. The Game class, which will be used by the player, the Board class, which represents the board, and the SwitchController class, which is responsible for verifying the correct selection of the desired switch on the board, by making a switch, counting the number of available switches (so I can know when the game ended, etc. .).

My current project looks something like this:

 Game: isGameOver() isSwitchValid(coord1, coord2) makeSwitch(coord1, coord2) getPieceAt(coord) getBoardLength() IBoard: getPieceAt(coord) setPieceAt(coord, piece) getLength() 

My idea would then have an ISwitchController :

 ISwitchController: isSwitchValid(coord1, coord2) makeSwitch(coord1, coord2) getAllValidSwitches() 

Here is a small diagram about how classes should be organized: alt text

I would have 2 different concrete IBoard classes available for use (and for each of them I would have to have an implementation of ISwitchController ).

Problem:

My program should have 2 IBoard implementations:

The first, ArrayBoard , will have all parts of the board stored in a 2D array. This is nothing special. I am defining an ArrayBoardSwitchController to manage this class.

The second, ListBoard , will have a List / Set for each color of the fragments, with all the coordinates of the parts of this color. I am defining a ListBoardSwitchController to manage this class.

The main problem here is that the implementation of SwitchController will be completely different on ArrayBoard and on ListBoard . For example, while the getAllValidSwitches() method is only needed to implement getAllValidSwitches() ArrayBoardSwitchController , it would not be a good idea to do with ListBoardSwitchController (in this class I use internal lists, because it’s easier to check if it is valid in this way).

From what I see, there are 2 different possible solutions:

  • I could either combine ISwitchController and IBoard interfaces. Thus, I would have two classes, a game and a council (while basically the game will be just a controller for the Council, since it will be a Council in which the game logic). It would not be so nice because the classes will not be as they could be if I had 3 different classes.

  • Let there be interfaces, as well as all the methods that I need to work with the public in specific classes. For example, if I need a getYellowPiecesList() , I would publish it on a ListBoard , so ListBoardSwitchController can use this. ListBoardSwitchController will only know about this because it knows that it only works against ListBoards .

What is your opinion on this? Here, the main attention is paid not so much to the design of the Bejeweled game, but to the solution of this problem, which is repeated when trying to implement the algorithms: on the one hand, you want to have a clear and good OOP design, and on the other hand it sometimes prevents you from having a reliable and efficient implementation of the algorithm.

+4
source share
3 answers

The main problem here is that the implementation of SwitchController will be completely different on ArrayBoard and on ListBoard.

If so, then it looks like you haven't developed the IBoard interface IBoard enough so that classes can use the IBoard implementation without knowing the implementation details. If an IBoard user IBoard to know which implementation is being used, then he almost defeats the goal of having an interface!

I would highly recommend re-exploring the methods that you post on IBoard to see if there is a way to set something like “get the part in this coordinate” in a more general way. Make sure that any methods that the controller must call in the IBoard instance have only methods in the IBoard interface.

For example, while the getPieceAt () method is only needed to implement getAllValidSwitches () ArrayBoardSwitchController, it would not be a good idea to do with ListBoardSwitchController (in this class I use internal lists, because it’s easier to check if the move is really that way).

If an operation, such as “get a piece in this coordinate”, plays a role in the IBoard interface, then the implementations must be faithful to their contract and implement it correctly. It sounds as if your ListBoard does not comply with the contract specified in IBoard .

+4
source

3: Let ArrayBoardSwitchController and ListBoardSwitchController be inner classes of ArrayBoard and ListBoard. The controller implementation is tied to the implementation of your board, so it makes sense to keep them together. Since the controller will be an inner class, you can use implementation details from the board. Then, to make it work, extend the IBoard interface to return the ISwitchController.

Note that this is slightly different from option 1. (Now ISwitchController can be used indirectly from IBoard, merging them gives direct access to ISwitchController)

+3
source

What is the purpose of ListBoard as an object that is separable from ArrayBoard? If I was going to work with a list of gems, I would save it in an object that also contained an array of what was in each position, so that replacing the position of two gems could be done quickly and efficiently. Not that I understand why you need a list of positions?

If a 6507 operating at 1.19 MHz, with 128 bytes of RAM and 20% processor availability, can process columns, finding all 3-in-a-row combinations at 6x20 in less than 100 ms, I would think that more modern machines might scanning for movements is acceptable quickly, without using a list of what gems are. I would suggest filling out your board array so that you don’t have to worry about cross cases, and for each gem, check 16 combinations of different cells within three squares (*) to see if they both match. Some movements can be reported in two directions (for example, this algorithm can detect that moving the gem to the left will create a 3-in-row, and also find that moving the gem to the left of the first to the right will result in a 3-in-a-row ), but this should not be a problem.

(*) If a gemstone can move to the left, it must coincide either with two gems to the left of the destination, or with two gems above the destination, or with two gems below, or above one and above it. Similarly for other destinations.

+1
source

Source: https://habr.com/ru/post/1315665/


All Articles