feat: implement dice game api
This commit is contained in:
parent
46c9d2b7c1
commit
9175c82f98
4 changed files with 176 additions and 0 deletions
|
@ -0,0 +1,44 @@
|
||||||
|
package de.szut.casino.dice;
|
||||||
|
|
||||||
|
import de.szut.casino.exceptionHandling.exceptions.InsufficientFundsException;
|
||||||
|
import de.szut.casino.exceptionHandling.exceptions.UserNotFoundException;
|
||||||
|
import de.szut.casino.shared.service.BalanceService;
|
||||||
|
import de.szut.casino.user.UserEntity;
|
||||||
|
import de.szut.casino.user.UserService;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class DiceController {
|
||||||
|
private final UserService userService;
|
||||||
|
private final BalanceService balanceService;
|
||||||
|
private final DiceService diceService;
|
||||||
|
|
||||||
|
public DiceController(UserService userService, BalanceService balanceService, DiceService diceService) {
|
||||||
|
this.userService = userService;
|
||||||
|
this.balanceService = balanceService;
|
||||||
|
this.diceService = diceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/dice")
|
||||||
|
public ResponseEntity<Object> rollDice(@RequestBody @Valid DiceDto diceDto) {
|
||||||
|
Optional<UserEntity> optionalUser = userService.getCurrentUser();
|
||||||
|
|
||||||
|
if (optionalUser.isEmpty()) {
|
||||||
|
throw new UserNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
UserEntity user = optionalUser.get();
|
||||||
|
|
||||||
|
if (!this.balanceService.hasFunds(user, diceDto)) {
|
||||||
|
throw new InsufficientFundsException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok(diceService.play(user, diceDto));
|
||||||
|
}
|
||||||
|
}
|
25
backend/src/main/java/de/szut/casino/dice/DiceDto.java
Normal file
25
backend/src/main/java/de/szut/casino/dice/DiceDto.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package de.szut.casino.dice;
|
||||||
|
|
||||||
|
import de.szut.casino.shared.dto.BetDto;
|
||||||
|
import jakarta.validation.constraints.DecimalMin;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DiceDto extends BetDto {
|
||||||
|
private boolean rollOver;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@DecimalMin(value = "1.00")
|
||||||
|
private BigDecimal targetValue;
|
||||||
|
|
||||||
|
public DiceDto(BigDecimal betAmount, boolean rollOver, BigDecimal targetValue) {
|
||||||
|
super(betAmount);
|
||||||
|
this.rollOver = rollOver;
|
||||||
|
this.targetValue = targetValue;
|
||||||
|
}
|
||||||
|
}
|
39
backend/src/main/java/de/szut/casino/dice/DiceResult.java
Normal file
39
backend/src/main/java/de/szut/casino/dice/DiceResult.java
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package de.szut.casino.dice;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
public class DiceResult {
|
||||||
|
private boolean win;
|
||||||
|
private BigDecimal payout;
|
||||||
|
private BigDecimal rolledValue;
|
||||||
|
|
||||||
|
public DiceResult(boolean win, BigDecimal payout, BigDecimal rolledValue) {
|
||||||
|
this.win = win;
|
||||||
|
this.payout = payout;
|
||||||
|
this.rolledValue = rolledValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWin() {
|
||||||
|
return win;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWin(boolean win) {
|
||||||
|
this.win = win;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getPayout() {
|
||||||
|
return payout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayout(BigDecimal payout) {
|
||||||
|
this.payout = payout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getRolledValue() {
|
||||||
|
return rolledValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRolledValue(BigDecimal rolledValue) {
|
||||||
|
this.rolledValue = rolledValue;
|
||||||
|
}
|
||||||
|
}
|
68
backend/src/main/java/de/szut/casino/dice/DiceService.java
Normal file
68
backend/src/main/java/de/szut/casino/dice/DiceService.java
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
package de.szut.casino.dice;
|
||||||
|
|
||||||
|
import de.szut.casino.shared.service.BalanceService;
|
||||||
|
import de.szut.casino.user.UserEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class DiceService {
|
||||||
|
private static final int MAX_DICE_VALUE = 100;
|
||||||
|
private final Random random = new Random();
|
||||||
|
private final BalanceService balanceService;
|
||||||
|
|
||||||
|
public DiceService(BalanceService balanceService) {
|
||||||
|
this.balanceService = balanceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiceResult play(UserEntity user, DiceDto diceDto) {
|
||||||
|
balanceService.subtractFunds(user, diceDto.getBetAmount());
|
||||||
|
|
||||||
|
int rolledValue = random.nextInt(MAX_DICE_VALUE) + 1;
|
||||||
|
BigDecimal rolledValueDecimal = BigDecimal.valueOf(rolledValue);
|
||||||
|
|
||||||
|
BigDecimal targetValue = diceDto.getTargetValue();
|
||||||
|
boolean isRollOver = diceDto.isRollOver();
|
||||||
|
|
||||||
|
boolean winConditionMet = isWinConditionMet(rolledValueDecimal, targetValue, isRollOver);
|
||||||
|
|
||||||
|
if (!winConditionMet) {
|
||||||
|
return new DiceResult(false, BigDecimal.ZERO, rolledValueDecimal);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal winChance = calculateWinChance(targetValue, isRollOver);
|
||||||
|
BigDecimal multiplier = calculateMultiplier(winChance);
|
||||||
|
|
||||||
|
BigDecimal payout = diceDto.getBetAmount().multiply(multiplier);
|
||||||
|
balanceService.addFunds(user, payout);
|
||||||
|
|
||||||
|
return new DiceResult(true, payout, rolledValueDecimal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isWinConditionMet(BigDecimal rolledValue, BigDecimal targetValue, boolean isRollOver) {
|
||||||
|
if (isRollOver) {
|
||||||
|
return rolledValue.compareTo(targetValue) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rolledValue.compareTo(targetValue) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal calculateWinChance(BigDecimal targetValue, boolean isRollOver) {
|
||||||
|
if (isRollOver) {
|
||||||
|
return BigDecimal.valueOf(MAX_DICE_VALUE).subtract(targetValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetValue.subtract(BigDecimal.ONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal calculateMultiplier(BigDecimal winChance) {
|
||||||
|
if (winChance.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
return BigDecimal.valueOf(MAX_DICE_VALUE - 1).divide(winChance, 4, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue