generated from Game-as-a-Service/Gaas-repo-template
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #35 from Game-as-a-Service/feature/16/backend-flow…
…-game-start Feature/16/backend flow game start
- Loading branch information
Showing
40 changed files
with
1,391 additions
and
131 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 5 additions & 16 deletions
21
backend/src/main/java/tw/waterballsa/gaas/unoflip/controller/GameController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,23 @@ | ||
package tw.waterballsa.gaas.unoflip.controller; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import tw.waterballsa.gaas.unoflip.presenter.GameJoinPresenter; | ||
import tw.waterballsa.gaas.unoflip.service.SseService; | ||
import tw.waterballsa.gaas.unoflip.usecase.GameJoinUseCase; | ||
import tw.waterballsa.gaas.unoflip.vo.GameJoinResult; | ||
import tw.waterballsa.gaas.unoflip.vo.JoinRequest; | ||
import tw.waterballsa.gaas.unoflip.vo.JoinResult; | ||
import tw.waterballsa.gaas.unoflip.vo.Response; | ||
import tw.waterballsa.gaas.unoflip.response.JoinResult; | ||
import tw.waterballsa.gaas.unoflip.response.Response; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
public class GameController { | ||
|
||
private final GameJoinUseCase gameJoinUseCase; | ||
private final GameJoinPresenter gameJoinPresenter; | ||
private final SseService sseService; | ||
|
||
public GameController(GameJoinUseCase gameJoinUseCase, GameJoinPresenter gameJoinPresenter, SseService sseService) { | ||
this.gameJoinUseCase = gameJoinUseCase; | ||
this.gameJoinPresenter = gameJoinPresenter; | ||
this.sseService = sseService; | ||
} | ||
|
||
@PostMapping("join/{playerId}") | ||
public Response<JoinResult> join(@PathVariable String playerId, @RequestBody JoinRequest joinRequest) { | ||
GameJoinResult gameJoinResult = gameJoinUseCase.join(playerId, joinRequest.playerName()); | ||
sseService.sendMessage(gameJoinPresenter.broadcastEvent(playerId, gameJoinResult)); | ||
return gameJoinPresenter.response(playerId, gameJoinResult); | ||
return gameJoinUseCase.join(playerId, joinRequest.playerName()); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
backend/src/main/java/tw/waterballsa/gaas/unoflip/domain/DealResult.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package tw.waterballsa.gaas.unoflip.domain; | ||
|
||
import tw.waterballsa.gaas.unoflip.domain.eumns.Card; | ||
|
||
import java.util.List; | ||
|
||
record DealResult(List<HandCard> playersHandCard, Card discardCard, List<Card> drawPileCards) { | ||
} |
36 changes: 36 additions & 0 deletions
36
backend/src/main/java/tw/waterballsa/gaas/unoflip/domain/Dealer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package tw.waterballsa.gaas.unoflip.domain; | ||
|
||
import tw.waterballsa.gaas.unoflip.domain.eumns.Card; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.stream.IntStream; | ||
|
||
class Dealer { | ||
public static DealResult deal() { | ||
List<Integer> cardNumbers = Card.getAllIds(); | ||
Collections.shuffle(cardNumbers); | ||
|
||
List<HandCard> playersHandCards = new ArrayList<>(); | ||
|
||
playersHandCards.add(createHandCard(0, 7, cardNumbers)); | ||
playersHandCards.add(createHandCard(7, 14, cardNumbers)); | ||
playersHandCards.add(createHandCard(14, 21, cardNumbers)); | ||
playersHandCards.add(createHandCard(21, 28, cardNumbers)); | ||
|
||
Card discardCard = Card.getLightInstance(cardNumbers.get(28)); | ||
|
||
List<Card> drawPileCards = getRandomCardList(29, 112, cardNumbers); | ||
|
||
return new DealResult(playersHandCards, discardCard, drawPileCards); | ||
} | ||
|
||
private static HandCard createHandCard(int startInclusive, int endExclusive, List<Integer> cardNumbers) { | ||
return new HandCard(getRandomCardList(startInclusive, endExclusive, cardNumbers)); | ||
} | ||
|
||
private static List<Card> getRandomCardList(int startInclusive, int endExclusive, List<Integer> cardNumbers) { | ||
return IntStream.range(startInclusive, endExclusive).mapToObj(i -> Card.getLightInstance(cardNumbers.get(i))).toList(); | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
backend/src/main/java/tw/waterballsa/gaas/unoflip/domain/HandCard.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package tw.waterballsa.gaas.unoflip.domain; | ||
|
||
import tw.waterballsa.gaas.unoflip.domain.eumns.Card; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
public class HandCard { | ||
private final List<Card> cards; | ||
|
||
public HandCard(List<Card> cards) { | ||
this.cards = cards; | ||
} | ||
|
||
public List<Integer> toCardIds() { | ||
return cards.stream().map(Card::getId).toList(); | ||
} | ||
|
||
int size() { | ||
return cards.size(); | ||
} | ||
|
||
List<Card> getCards() { | ||
return Collections.unmodifiableList(cards); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
backend/src/main/java/tw/waterballsa/gaas/unoflip/domain/Player.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package tw.waterballsa.gaas.unoflip.domain; | ||
|
||
import lombok.Getter; | ||
import lombok.Setter; | ||
|
||
@Getter | ||
public class Player { | ||
|
||
private final PlayerInfo playerInfo; | ||
@Setter | ||
private HandCard handCard; | ||
|
||
public Player(PlayerInfo playerInfo) { | ||
this.playerInfo = playerInfo; | ||
} | ||
|
||
public int getPosition() { | ||
return playerInfo.position(); | ||
} | ||
|
||
public String getId() { | ||
return playerInfo.id(); | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
backend/src/main/java/tw/waterballsa/gaas/unoflip/domain/PlayerInfo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package tw.waterballsa.gaas.unoflip.domain; | ||
|
||
public record PlayerInfo(String id, String name, Integer position) { | ||
} |
49 changes: 49 additions & 0 deletions
49
backend/src/main/java/tw/waterballsa/gaas/unoflip/domain/Players.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package tw.waterballsa.gaas.unoflip.domain; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
|
||
public class Players { | ||
private final Map<String, Player> playerMap = new HashMap<>(); | ||
|
||
public boolean exists(String playerId) { | ||
return playerMap.get(playerId) != null; | ||
} | ||
|
||
public void add(PlayerInfo playerInfo) { | ||
playerMap.put(playerInfo.id(), new Player(playerInfo)); | ||
} | ||
|
||
public List<PlayerInfo> toInfoList() { | ||
return playerMap.values().stream().map(Player::getPlayerInfo).toList(); | ||
} | ||
|
||
public HandCard getPlayerHandCard(String playerId) { | ||
return Optional.ofNullable(playerMap.get(playerId)) | ||
.map(Player::getHandCard) | ||
.orElseThrow(() -> new IllegalArgumentException("player %s not exists".formatted(playerId))); | ||
} | ||
|
||
public void setHandCard(String playerId, HandCard handCard) { | ||
Player player = Optional.ofNullable(playerMap.get(playerId)).orElseThrow(() -> new IllegalArgumentException("player %s not exists".formatted(playerId))); | ||
player.setHandCard(handCard); | ||
} | ||
|
||
public int size() { | ||
return playerMap.size(); | ||
} | ||
|
||
public List<String> getIds() { | ||
return playerMap.values().stream().map(Player::getId).toList(); | ||
} | ||
|
||
public String getPlayerId(int position) { | ||
return playerMap.values().stream() | ||
.filter(player -> position == player.getPosition()) | ||
.findFirst() | ||
.map(Player::getId) | ||
.orElseThrow(() -> new IllegalArgumentException("position %d not exists".formatted(position))); | ||
} | ||
} |
79 changes: 63 additions & 16 deletions
79
backend/src/main/java/tw/waterballsa/gaas/unoflip/domain/UnoFlipGame.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,96 @@ | ||
package tw.waterballsa.gaas.unoflip.domain; | ||
|
||
import tw.waterballsa.gaas.unoflip.vo.PlayerInfo; | ||
import lombok.Getter; | ||
import tw.waterballsa.gaas.unoflip.domain.eumns.Card; | ||
import tw.waterballsa.gaas.unoflip.domain.eumns.Direction; | ||
import tw.waterballsa.gaas.unoflip.domain.eumns.GameMode; | ||
import tw.waterballsa.gaas.unoflip.domain.eumns.GameStatus; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
public class UnoFlipGame { | ||
private static final int MAX_PLAYER_NUMBER = 4; | ||
private final List<Card> drawPileList = new ArrayList<>(); | ||
private final List<Card> discardPileList = new ArrayList<>(); | ||
|
||
@Getter | ||
private final Players players = new Players(); | ||
@Getter | ||
private final int tableId; | ||
private final List<PlayerInfo> playerInfoList = new ArrayList<>(); | ||
@Getter | ||
private String actionPlayerId; | ||
@Getter | ||
private GameStatus status; | ||
@Getter | ||
private Direction direction; | ||
@Getter | ||
private GameMode mode; | ||
|
||
public UnoFlipGame(int tableId) { | ||
this.tableId = tableId; | ||
this.status = GameStatus.WAITING; | ||
this.direction = Direction.RIGHT; | ||
this.mode = GameMode.LIGHT; | ||
} | ||
|
||
public int getTableId() { | ||
return tableId; | ||
public boolean isFull() { | ||
return players.size() >= MAX_PLAYER_NUMBER; | ||
} | ||
|
||
public void join(String playerId, String playerName) { | ||
if (isPlayerAlreadyInGame(playerId)) { | ||
throw new RuntimeException("player already in game"); | ||
} | ||
public List<PlayerInfo> getPlayerInfoList() { | ||
return players.toInfoList(); | ||
} | ||
|
||
playerInfoList.add(new PlayerInfo(playerId, playerName, getAvailablePosition())); | ||
public List<Card> getDrawPile() { | ||
return Collections.unmodifiableList(drawPileList); | ||
} | ||
|
||
public List<PlayerInfo> getPlayerInfoList() { | ||
return Collections.unmodifiableList(playerInfoList); | ||
public List<Card> getDiscardPile() { | ||
return Collections.unmodifiableList(discardPileList); | ||
} | ||
|
||
public boolean isFull() { | ||
return playerInfoList.size() >= MAX_PLAYER_NUMBER; | ||
public void join(String playerId, String playerName) { | ||
if (isPlayerAlreadyInGame(playerId)) { | ||
throw new RuntimeException("player already in game"); | ||
} | ||
|
||
players.add(new PlayerInfo(playerId, playerName, getAvailablePosition())); | ||
} | ||
|
||
private boolean isPlayerAlreadyInGame(String playerId) { | ||
return playerInfoList.stream().anyMatch(playerInfo -> playerId.equals(playerInfo.playerId())); | ||
return players.exists(playerId); | ||
} | ||
|
||
private int getAvailablePosition() { | ||
if (isFull()) { | ||
throw new RuntimeException("game is full"); | ||
throw new IllegalStateException("game is full"); | ||
} | ||
|
||
return playerInfoList.size() + 1; | ||
return players.size() + 1; | ||
} | ||
|
||
public void start() { | ||
status = GameStatus.STARTED; | ||
actionPlayerId = players.getPlayerId(getInitPosition()); | ||
|
||
DealResult dealResult = Dealer.deal(); | ||
|
||
setPlayersHandCard(dealResult); | ||
discardPileList.add(dealResult.discardCard()); | ||
drawPileList.addAll(dealResult.drawPileCards()); | ||
} | ||
|
||
private int getInitPosition() { | ||
return (int) (Math.random() * MAX_PLAYER_NUMBER) + 1; | ||
} | ||
|
||
private void setPlayersHandCard(DealResult dealResult) { | ||
int handCardListIdx = 0; | ||
for (String playerId : players.getIds()) { | ||
players.setHandCard(playerId, dealResult.playersHandCard().get(handCardListIdx++)); | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.