Skip to content

Commit d50a38b

Browse files
perf(gb): index ting memo by tile ordinal (#85)
Co-authored-by: Arbousier1 <elderli@foxmail.com>
1 parent db0a5e2 commit d50a38b

2 files changed

Lines changed: 27 additions & 4 deletions

File tree

src/main/java/top/ellan/mahjong/table/core/round/GbBotDecisionService.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
import top.ellan.mahjong.riichi.ReactionResponse;
1010
import top.ellan.mahjong.riichi.ReactionResponses;
1111
import java.util.ArrayList;
12-
import java.util.EnumMap;
1312
import java.util.List;
1413
import java.util.Locale;
1514
import kotlin.Pair;
1615

1716
final class GbBotDecisionService {
17+
private static final int TILE_KIND_COUNT = MahjongTile.values().length;
18+
1819
private final int minimumFan;
1920

2021
GbBotDecisionService(int minimumFan) {
@@ -188,19 +189,20 @@ private DiscardChoice bestDiscardChoice(
188189
int bestIndex = -1;
189190
long bestReadyScore = 0;
190191
int bestDiscardPreference = 0;
191-
EnumMap<MahjongTile, GbTingResponse> tingMemo = new EnumMap<>(MahjongTile.class);
192+
GbTingResponse[] tingMemo = new GbTingResponse[TILE_KIND_COUNT];
192193
MahjongTile previousDiscarded = null;
193194
int previousDiscardPreference = 0;
194195
for (int i = 0; i < hand.size(); i++) {
195196
MahjongTile discarded = hand.get(i);
196-
GbTingResponse ting = tingMemo.get(discarded);
197+
int discardedOrdinal = discarded.ordinal();
198+
GbTingResponse ting = tingMemo[discardedOrdinal];
197199
boolean tingMemoHit = ting != null;
198200
if (ting == null) {
199201
List<MahjongTile> remaining = new ArrayList<>(hand);
200202
remaining.remove(i);
201203
ting = tingEvaluator.evaluate(remaining, melds);
202204
if (ting != null) {
203-
tingMemo.put(discarded, ting);
205+
tingMemo[discardedOrdinal] = ting;
204206
}
205207
}
206208
long candidateReadyScore = readyScore(ting);

src/test/kotlin/top/ellan/mahjong/table/core/round/GbBotDecisionServiceTest.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,27 @@ class GbBotDecisionServiceTest {
123123
)
124124
}
125125

126+
@Test
127+
fun `discard suggestion keeps ordinal memo entries isolated across suits`() {
128+
val service = GbBotDecisionService(8)
129+
val hand = listOf(MahjongTile.M1, MahjongTile.P1, MahjongTile.M1, MahjongTile.P1)
130+
val ready = GbTingResponse(true, listOf(GbTingCandidate("W1", 8)), null)
131+
var evaluations = 0
132+
133+
val suggestedIndex =
134+
service.suggestedDiscardIndex(hand, emptyList()) { remaining, _ ->
135+
evaluations++
136+
if (remaining.count { it == MahjongTile.P1 } == 2) {
137+
ready
138+
} else {
139+
GbTingResponse(true, emptyList(), null)
140+
}
141+
}
142+
143+
assertEquals(0, suggestedIndex)
144+
assertEquals(2, evaluations)
145+
}
146+
126147
@Test
127148
fun `discard suggestion keeps the earliest index for equal duplicate candidates`() {
128149
val service = GbBotDecisionService(8)

0 commit comments

Comments
 (0)