Coverage Report

Created: 2025-09-03 03:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/nix/store/i1aar97n7b4yf8rk94p66if25brfvvdx-gqvzl8a5pvrg3xj44q0msrndcripi8dk-source/src/api/gamestate.cc
Line
Count
Source
1
#include "api/gamestate.h"
2
3
#include <algorithm>
4
#include <memory>
5
#include <new>
6
#include <vector>
7
#include "api/types.h"
8
#include "controllers/controllermanager.h"
9
#include "statefunctions/statecontroller.h"
10
#include "types/gamestate.h"
11
#include "types/settings.h"
12
#include "types/statefunction.h"
13
14
namespace api {
15
16
namespace {
17
18
15
CStateFunctionType ConvertStateFunctionType(mahjong::StateFunctionType func) {
19
15
  switch (func) {
20
6
    case mahjong::StateFunctionType::kError:
21
6
      return kError;
22
5
    case mahjong::StateFunctionType::kGameStart:
23
5
      return kGameStart;
24
3
    case mahjong::StateFunctionType::kRoundStart:
25
3
      return kRoundStart;
26
1
    case mahjong::StateFunctionType::kDraw:
27
1
      return kDraw;
28
0
    case mahjong::StateFunctionType::kPlayerHand:
29
0
      return kPlayerHand;
30
0
    case mahjong::StateFunctionType::kPon:
31
0
      return kPon;
32
0
    case mahjong::StateFunctionType::kChi:
33
0
      return kChi;
34
0
    case mahjong::StateFunctionType::kKan:
35
0
      return kKan;
36
0
    case mahjong::StateFunctionType::kConcealedKan:
37
0
      return kConcealedKan;
38
0
    case mahjong::StateFunctionType::kConvertedKan:
39
0
      return kConvertedKan;
40
0
    case mahjong::StateFunctionType::kKanDiscard:
41
0
      return kKanDiscard;
42
0
    case mahjong::StateFunctionType::kReplacement:
43
0
      return kReplacement;
44
0
    case mahjong::StateFunctionType::kRiichi:
45
0
      return kRiichi;
46
0
    case mahjong::StateFunctionType::kDiscard:
47
0
      return kDiscard;
48
0
    case mahjong::StateFunctionType::kExhaust:
49
0
      return kExhaust;
50
0
    case mahjong::StateFunctionType::kRon:
51
0
      return kRon;
52
0
    case mahjong::StateFunctionType::kTsumo:
53
0
      return kTsumo;
54
0
    case mahjong::StateFunctionType::kRoundEnd:
55
0
      return kRoundEnd;
56
0
    case mahjong::StateFunctionType::kGameEnd:
57
0
      return kGameEnd;
58
15
  }
59
60
  // This should never be reached (unless we forget to add a new state function)
61
0
  return kError;
62
15
}
63
64
8
mahjong::GameSettings convertGameSettings(const CGameSettings* settings) {
65
8
  mahjong::GameSettings cpp_settings;
66
67
8
  cpp_settings.seed = settings->seed;
68
69
  // Char arrays to vector
70
40
  for (int i = 0; i < settings->num_controllers; i++) {
71
32
    if (settings->seat_controllers[i]) {
72
32
      cpp_settings.seatControllers.emplace_back(settings->seat_controllers[i]);
73
32
    }
74
32
  }
75
76
8
  return cpp_settings;
77
8
}
78
}  // namespace
79
80
extern "C" {
81
82
0
int StartGame(const CGameSettings* settings, bool async) {
83
0
  const mahjong::GameSettings cpp_settings = convertGameSettings(settings);
84
0
  return mahjong::StartGame(cpp_settings, async);
85
0
}
86
87
0
void ExitGame(int game) {
88
0
  mahjong::ExitGame(game);
89
0
}
90
91
34
bool IsValidGameController(const char* controller) {
92
34
  return mahjong::ControllerManager::Instance()
93
34
      .GetAvailableControllersMap()
94
34
      .contains(controller);
95
34
}
96
97
8
mahjong::GameState* InitGameState(const CGameSettings* settings) {
98
8
  const mahjong::GameSettings cpp_settings = convertGameSettings(settings);
99
  // Check controllers ahead of time as C++ throws will not be handled correctly by
100
  // all library consumers (rust)
101
29
  for (const auto& controller : cpp_settings.seatControllers) {
102
29
    if (!IsValidGameController(controller.c_str())) {
103
1
      return nullptr;
104
1
    }
105
29
  }
106
107
7
  std::unique_ptr<mahjong::GameState> state =
108
7
      mahjong::InitGameState(cpp_settings);
109
7
  return state.release();
110
8
}
111
112
5
mahjong::GameState* AdvanceGameState(mahjong::GameState* state) {
113
5
  std::unique_ptr<mahjong::GameState> new_state =
114
5
      mahjong::AdvanceGameState(std::unique_ptr<mahjong::GameState>(state));
115
5
  return new_state.release();
116
5
}
117
118
5
CObservedGameState ObserveGameState(mahjong::GameState* state) {
119
5
  CObservedGameState observed = {};
120
121
5
  if (!state) {
122
0
    return observed;
123
0
  }
124
125
  // Straightforward copies
126
5
  observed.currentPlayer = state->currentPlayer;
127
5
  observed.turnNum = state->turnNum;
128
5
  observed.roundNum = state->roundNum;
129
5
  observed.riichiSticks = state->riichiSticks;
130
5
  observed.counters = state->counters;
131
5
  observed.lastCall = state->lastCall;
132
5
  observed.lastCaller = state->lastCaller;
133
5
  observed.concealedKan = state->concealedKan;
134
5
  observed.seed = state->seed;
135
5
  observed.pendingPiece = static_cast<CPiece>(state->pendingPiece.toUint8_t());
136
137
  // State function enums
138
5
  observed.prevState = ConvertStateFunctionType(state->prevState);
139
5
  observed.currState = ConvertStateFunctionType(state->currState);
140
5
  observed.nextState = ConvertStateFunctionType(state->nextState);
141
142
  // Player data
143
25
  for (int i = 0; i < 4; i++) {
144
20
    observed.scores[i] = state->scores[i];
145
20
    observed.points[i] = state->players[i].points;
146
20
    observed.hasRonned[i] = state->hasRonned[i];
147
148
    // Convert Hand to CHand
149
20
    const auto& cpp_hand = state->hands[i];
150
20
    CHand& c_hand = observed.hands[i];
151
152
    // Live pieces
153
20
    const int live_piece_count = static_cast<int>(cpp_hand.live.size());
154
20
    c_hand.livePieceCount = std::min(live_piece_count, kMaxLiveHandSize);
155
72
    for (int j = 0; j < c_hand.livePieceCount; j++) {
156
52
      c_hand.livePieces[j] = static_cast<CPiece>(cpp_hand.live[j].toUint8_t());
157
52
    }
158
159
    // Melds
160
20
    const int meld_count = static_cast<int>(cpp_hand.melds.size());
161
20
    c_hand.meldCount = std::min(meld_count, kMaxMeldsPerHand);
162
20
    for (int j = 0; j < c_hand.meldCount; j++) {
163
0
      c_hand.melds[j].type = static_cast<CMeldType>(cpp_hand.melds[j].type);
164
0
      c_hand.melds[j].start =
165
0
          static_cast<CPiece>(cpp_hand.melds[j].start.toUint8_t());
166
0
    }
167
168
    // Discards
169
20
    const auto& discards = cpp_hand.discards;
170
20
    const int discards_size = static_cast<int>(discards.size());
171
20
    c_hand.discardCount = std::min(discards_size, kMaxDiscardsPerPlayer);
172
20
    for (auto j = 0; j < c_hand.discardCount; j++) {
173
0
      c_hand.discards[j] = static_cast<CPiece>(discards[j].toUint8_t());
174
0
    }
175
176
    // Hand properties
177
20
    c_hand.open = cpp_hand.open;
178
20
    c_hand.riichi = cpp_hand.riichi;
179
20
    c_hand.riichiPieceDiscard = static_cast<int>(cpp_hand.riichiPieceDiscard);
180
20
    c_hand.riichiRound = cpp_hand.riichiRound;
181
20
  }
182
183
5
  return observed;
184
5
}
185
186
4
void FreeGameState(mahjong::GameState* state) {
187
4
  delete state;
188
4
}
189
}
190
}  // namespace api