新增局终处理逻辑,当牌墙耗尽且有多家未胡时: 1. 退税:未听牌玩家需退还此前杠分收入 2. 查叫:未听牌玩家向听牌玩家赔付最大理论点炮值 新增 SettlementType.TUI_SHUI 和 SettlementType.CHA_JIAO 结算类型 新增 ReadyHandOption 记录最优听牌选项 支持一炮多响裁决,新增 ResponseActionResolutionBatch 承载多赢家结果 在 GameSession 中新增 settlementHistory 保留结算记录供复用 更新开发文档要求加强关键区域的中文注释
68 lines
2.7 KiB
Java
68 lines
2.7 KiB
Java
package com.xuezhanmaster.game.service;
|
|
|
|
import com.xuezhanmaster.game.domain.ActionType;
|
|
import com.xuezhanmaster.game.domain.ResponseActionResolution;
|
|
import com.xuezhanmaster.game.domain.ResponseActionResolutionBatch;
|
|
import com.xuezhanmaster.game.domain.ResponseActionWindow;
|
|
import org.springframework.stereotype.Component;
|
|
|
|
import java.util.Comparator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
|
|
@Component
|
|
public class ResponseActionResolver {
|
|
|
|
public Optional<ResponseActionResolutionBatch> resolve(
|
|
ResponseActionWindow window,
|
|
Map<Integer, ActionType> selections,
|
|
int seatCount
|
|
) {
|
|
// 只要有胡牌声明,就按一炮多响返回全部胡牌赢家,其它动作全部失效。
|
|
List<ResponseActionResolution> huResolutions = selections.entrySet().stream()
|
|
.filter(entry -> entry.getValue() == ActionType.HU)
|
|
.sorted(Comparator.comparingInt(entry -> seatDistance(window.sourceSeatNo(), entry.getKey(), seatCount)))
|
|
.map(entry -> new ResponseActionResolution(
|
|
entry.getValue(),
|
|
entry.getKey(),
|
|
window.sourceSeatNo(),
|
|
window.triggerTile()
|
|
))
|
|
.toList();
|
|
if (!huResolutions.isEmpty()) {
|
|
// 一炮多响时保留所有胡牌赢家,后续由执行层逐个结算。
|
|
return Optional.of(new ResponseActionResolutionBatch(ActionType.HU, huResolutions));
|
|
}
|
|
|
|
return selections.entrySet().stream()
|
|
.filter(entry -> entry.getValue() != ActionType.PASS)
|
|
.min(Comparator
|
|
.comparingInt((Map.Entry<Integer, ActionType> entry) -> priority(entry.getValue()))
|
|
.thenComparingInt(entry -> seatDistance(window.sourceSeatNo(), entry.getKey(), seatCount)))
|
|
.map(entry -> new ResponseActionResolutionBatch(
|
|
entry.getValue(),
|
|
List.of(new ResponseActionResolution(
|
|
entry.getValue(),
|
|
entry.getKey(),
|
|
window.sourceSeatNo(),
|
|
window.triggerTile()
|
|
))
|
|
));
|
|
}
|
|
|
|
private int priority(ActionType actionType) {
|
|
return switch (actionType) {
|
|
case HU -> 0;
|
|
case GANG -> 1;
|
|
case PENG -> 2;
|
|
case PASS -> 3;
|
|
default -> 99;
|
|
};
|
|
}
|
|
|
|
private int seatDistance(int sourceSeatNo, int targetSeatNo, int seatCount) {
|
|
return (targetSeatNo - sourceSeatNo + seatCount) % seatCount;
|
|
}
|
|
}
|