/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 |