https://github.com/eduardocruzpalacios/goose-game-java
Goose Game built with JDK 11.0.12
https://github.com/eduardocruzpalacios/goose-game-java
goose-game goose-game-java goosegame goosegamejava
Last synced: 7 months ago
JSON representation
Goose Game built with JDK 11.0.12
- Host: GitHub
- URL: https://github.com/eduardocruzpalacios/goose-game-java
- Owner: eduardocruzpalacios
- License: gpl-3.0
- Created: 2023-06-16T18:55:46.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-01-14T10:13:32.000Z (over 1 year ago)
- Last Synced: 2025-01-17T19:12:56.005Z (9 months ago)
- Topics: goose-game, goose-game-java, goosegame, goosegamejava
- Language: Java
- Homepage:
- Size: 596 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Goose Game
Goose Game Logic built with JDK 11.0.12.## Domain problem
The logic of this game is the same than the original goose board game, with the exception that when users play their first turn and the value of their dice thrown is 9, being the thrown values of dice 3 and 6, they move to square 23 instead of 26.Rules were extracted from [Spanish Goose Game Wikipedia page](https://es.wikipedia.org/wiki/Juego_de_la_oca), consulted between June and July of 2023.
## Architecture Design
### Polymorphism with Square
As the game has different kind of Square whose behavior defers depending on their specific kind, it was decided to create an abstract Square class whose abstract method *landedOn* is implemented in their children:
- BridgeSquare
- BronzeSquare
- DiceSquare
- GooseSquare
- InnSquare
- LabyrinthSquare
- JailSquare
- RegularSquare
- SkullSquareTradeoffs of this decision:
- Implementing new children of Square does not break existing children and they can reuse existing functionality already built in BoardUML class diagram:

### Board and Mediator pattern where Square acts as participant
Board is the information expert of squares. It is responsible of:
- knowing how many squares there are,
- knowing in which squares players are located, and
- performing the corresponding operations during the gameSo, though squares own a different behavior depending on its kind, this behavior is performed by Board, actually. Board acts here as a mediator while squares are participants.
Tradeoffs of this decision:
- Too much functionality in Board class can lead to the so-called God class antipattern.### Dice: model, service and Singleton pattern
DiceModel is a simple class providing methods for rolling and getting value.DiceService provides methods for:
- get the value of 1 dice rolled
- get the value of 2 dice rolled
- get the value of 2 dice rolled with a different return values in these cases:
- dice values are 3 and 6
- dice values are 4 and 5DiceServiceSingleton gives the only instance of DiceService needed in execution time.
Tradeoffs of this decision:
- If new functionality is needed as for dice, it is only necessary to implement in DiceService not breaking existing uses of itUML class diagram:

### Player and State pattern
As players' behavior varies depending on its state, the behavior is delegated to its state.So, what players do during their turn depends on:
- It is player's 1st turn
- It is a regular turn with 2 dice
- Player is in a square from which (s)he must use 1 dice
- Player cannot play in x number of turnsTradeoffs of this decision:
- 1 new state needs change in various places, but it protects existing player use from being brokenUML class diagram:

### Board and State pattern
System is designed so that once game is over, no more actions are allowed unless a new game is initiated.So, Board object acts differently when game is running from when is over. State pattern was implemented to avoid checking if the game is over before every single turn (*Tell-Don't-Ask*).
Tradeoffs of this decision:
- 1 additionally class that does nothing: GameOverState
- 1 less computational step in every single turn playedUML class diagram:

### Handler pattern for Player and Board states
This decision might be an example of over-engineering. Anyway, the reasoning of its implementation is to hide complex code by providing methods with more intuitive names.For instance,
`PlayerStateHandler.setNoTurnsState(player, turnsNumber);`
is more intuitive than:
`player.setPlayerState(new PlayerNoTurnsState(player, turnsNumber));`
Tradeoffs of this decision:
- Adds an additional layer that:
- reduce performance, and
- reduce complexity### GooseGameLogic and Facade pattern
This is the way to enclose all the game logic in a simple class that provides a few methods to run all the game:
- *initGame(playersNumber)*
- *playNextTurn*Tradeoffs of this decision:
- Clients using it are protected from changes in it, as if something changes in game logic, clients using it do not need to be modifiedUML class diagram:

## Client
This class is out of the game logic. It is just an example of console application acting as client that consume GooseGameLogicFacade.## Testing
- Unit tests are made with JUnit 5
- Only Dice-related classes are tested