- 新增血战计分服务,支持七对、清一色等基础番型及杠上花等特殊加番 - 扩展结算结果结构,包含番型明细与支付分数计算 - 新增PostGangContext记录杠后补摸窗口,用于判断杠上花/杠上炮 - 完善胡牌判定器,新增七对和对对胡识别方法 - 更新开发计划文档,补充注释规范要求 - 添加计分相关单元测试,确保核心逻辑正确性
128 lines
4.8 KiB
Java
128 lines
4.8 KiB
Java
package com.xuezhanmaster.game.event;
|
|
|
|
import com.xuezhanmaster.game.domain.ActionType;
|
|
import com.xuezhanmaster.game.domain.ScoreChange;
|
|
import com.xuezhanmaster.game.domain.SettlementDetail;
|
|
import com.xuezhanmaster.game.domain.SettlementFan;
|
|
import com.xuezhanmaster.game.domain.SettlementResult;
|
|
import com.xuezhanmaster.game.domain.SettlementType;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import java.util.List;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
|
|
class GameEventTest {
|
|
|
|
@Test
|
|
void shouldBuildResponseActionPayloadForFutureResponseEvents() {
|
|
GameEvent event = GameEvent.responseActionDeclared(
|
|
"game-1",
|
|
GameEventType.PENG_DECLARED,
|
|
2,
|
|
1,
|
|
"三万"
|
|
);
|
|
|
|
assertThat(event.eventType()).isEqualTo(GameEventType.PENG_DECLARED);
|
|
assertThat(event.seatNo()).isEqualTo(2);
|
|
assertThat(event.payload())
|
|
.containsEntry("actionType", "PENG")
|
|
.containsEntry("sourceSeatNo", 1)
|
|
.containsEntry("tile", "三万");
|
|
}
|
|
|
|
@Test
|
|
void shouldBuildStandardPublicTableEvents() {
|
|
GameEvent started = GameEvent.gameStarted("game-1", "room-1");
|
|
GameEvent phaseChanged = GameEvent.phaseChanged("game-1", "PLAYING");
|
|
GameEvent switched = GameEvent.turnSwitched("game-1", 3);
|
|
|
|
assertThat(started.eventType()).isEqualTo(GameEventType.GAME_STARTED);
|
|
assertThat(started.payload()).containsEntry("roomId", "room-1");
|
|
|
|
assertThat(phaseChanged.eventType()).isEqualTo(GameEventType.GAME_PHASE_CHANGED);
|
|
assertThat(phaseChanged.payload()).containsEntry("phase", "PLAYING");
|
|
|
|
assertThat(switched.eventType()).isEqualTo(GameEventType.TURN_SWITCHED);
|
|
assertThat(switched.payload()).containsEntry("currentSeatNo", 3);
|
|
}
|
|
|
|
@Test
|
|
void shouldBuildSettlementEvents() {
|
|
SettlementResult settlementResult = new SettlementResult(
|
|
SettlementType.DIAN_PAO_HU,
|
|
ActionType.HU,
|
|
2,
|
|
0,
|
|
"9筒",
|
|
new SettlementDetail(
|
|
1,
|
|
2,
|
|
4,
|
|
List.of(new SettlementFan("QING_YI_SE", "清一色", 2))
|
|
),
|
|
List.of(
|
|
new ScoreChange(2, 1, 3),
|
|
new ScoreChange(0, -1, -2)
|
|
)
|
|
);
|
|
|
|
GameEvent settlementApplied = GameEvent.settlementApplied("game-1", settlementResult);
|
|
GameEvent scoreChanged = GameEvent.scoreChanged("game-1", 2, SettlementType.DIAN_PAO_HU.name(), 1, 3);
|
|
|
|
assertThat(settlementApplied.eventType()).isEqualTo(GameEventType.SETTLEMENT_APPLIED);
|
|
assertThat(settlementApplied.payload())
|
|
.containsEntry("settlementType", "DIAN_PAO_HU")
|
|
.containsEntry("actionType", "HU")
|
|
.containsEntry("sourceSeatNo", 0)
|
|
.containsEntry("triggerTile", "9筒");
|
|
assertThat(settlementApplied.payload()).containsKey("settlementDetail");
|
|
assertThat(settlementApplied.payload()).containsKey("scoreChanges");
|
|
assertThat((java.util.Map<String, Object>) settlementApplied.payload().get("settlementDetail"))
|
|
.containsEntry("baseScore", 1)
|
|
.containsEntry("totalFan", 2)
|
|
.containsEntry("paymentScore", 4);
|
|
|
|
assertThat(scoreChanged.eventType()).isEqualTo(GameEventType.SCORE_CHANGED);
|
|
assertThat(scoreChanged.payload())
|
|
.containsEntry("settlementType", "DIAN_PAO_HU")
|
|
.containsEntry("delta", 1)
|
|
.containsEntry("score", 3);
|
|
}
|
|
|
|
@Test
|
|
void shouldAllowHuEventWithoutSourceSeatForSelfDraw() {
|
|
GameEvent selfDrawHu = GameEvent.responseActionDeclared(
|
|
"game-1",
|
|
GameEventType.HU_DECLARED,
|
|
0,
|
|
null,
|
|
null
|
|
);
|
|
|
|
assertThat(selfDrawHu.eventType()).isEqualTo(GameEventType.HU_DECLARED);
|
|
assertThat(selfDrawHu.payload())
|
|
.containsEntry("actionType", "HU")
|
|
.doesNotContainKey("sourceSeatNo")
|
|
.doesNotContainKey("tile");
|
|
}
|
|
|
|
@Test
|
|
void shouldAllowGangEventWithoutSourceSeatForConcealedGang() {
|
|
GameEvent concealedGang = GameEvent.responseActionDeclared(
|
|
"game-1",
|
|
GameEventType.GANG_DECLARED,
|
|
0,
|
|
null,
|
|
"3万"
|
|
);
|
|
|
|
assertThat(concealedGang.eventType()).isEqualTo(GameEventType.GANG_DECLARED);
|
|
assertThat(concealedGang.payload())
|
|
.containsEntry("actionType", "GANG")
|
|
.containsEntry("tile", "3万")
|
|
.doesNotContainKey("sourceSeatNo");
|
|
}
|
|
}
|