/nix/store/i1aar97n7b4yf8rk94p66if25brfvvdx-gqvzl8a5pvrg3xj44q0msrndcripi8dk-source/src/analysis/possiblesets.cc
Line | Count | Source |
1 | | #include <algorithm> |
2 | | #include <cstdint> |
3 | | #include <iterator> |
4 | | #include <map> |
5 | | #include <memory> |
6 | | #include <random> |
7 | | // #include <ext/alloc_traits.h> |
8 | | #include <array> |
9 | | #include <vector> |
10 | | |
11 | | #include "analysis/analysis.h" |
12 | | #include "analysis/handnode.h" |
13 | | #include "types/pieces.h" |
14 | | #include "types/piecetype.h" |
15 | | #include "types/sets.h" |
16 | | |
17 | | namespace mahjong { |
18 | | namespace { |
19 | | const std::vector<std::vector<Piece>> kTriplets = { |
20 | | {kOneBamboo, kTwoBamboo, kThreeBamboo}, |
21 | | {kTwoBamboo, kThreeBamboo, kFourBamboo}, |
22 | | {kThreeBamboo, kFourBamboo, kFiveBamboo}, |
23 | | {kFourBamboo, kFiveBamboo, kSixBamboo}, |
24 | | {kFiveBamboo, kSixBamboo, kSevenBamboo}, |
25 | | {kSixBamboo, kSevenBamboo, kEightBamboo}, |
26 | | {kSevenBamboo, kEightBamboo, kNineBamboo}, |
27 | | {kOneCharacter, kTwoCharacter, kThreeCharacter}, |
28 | | {kTwoCharacter, kThreeCharacter, kFourCharacter}, |
29 | | {kThreeCharacter, kFourCharacter, kFiveCharacter}, |
30 | | {kFourCharacter, kFiveCharacter, kSixCharacter}, |
31 | | {kFiveCharacter, kSixCharacter, kSevenCharacter}, |
32 | | {kSixCharacter, kSevenCharacter, kEightCharacter}, |
33 | | {kSevenCharacter, kEightCharacter, kNineCharacter}, |
34 | | {kOnePin, kTwoPin, kThreePin}, |
35 | | {kTwoPin, kThreePin, kFourPin}, |
36 | | {kThreePin, kFourPin, kFivePin}, |
37 | | {kFourPin, kFivePin, kSixPin}, |
38 | | {kFivePin, kSixPin, kSevenPin}, |
39 | | {kSixPin, kSevenPin, kEightPin}, |
40 | | {kSevenPin, kEightPin, kNinePin}, |
41 | | {kOneBamboo, kOneBamboo, kOneBamboo}, |
42 | | {kTwoBamboo, kTwoBamboo, kTwoBamboo}, |
43 | | {kThreeBamboo, kThreeBamboo, kThreeBamboo}, |
44 | | {kFourBamboo, kFourBamboo, kFourBamboo}, |
45 | | {kFiveBamboo, kFiveBamboo, kFiveBamboo}, |
46 | | {kSixBamboo, kSixBamboo, kSixBamboo}, |
47 | | {kSevenBamboo, kSevenBamboo, kSevenBamboo}, |
48 | | {kEightBamboo, kEightBamboo, kEightBamboo}, |
49 | | {kNineBamboo, kNineBamboo, kNineBamboo}, |
50 | | {kOneCharacter, kOneCharacter, kOneCharacter}, |
51 | | {kTwoCharacter, kTwoCharacter, kTwoCharacter}, |
52 | | {kThreeCharacter, kThreeCharacter, kThreeCharacter}, |
53 | | {kFourCharacter, kFourCharacter, kFourCharacter}, |
54 | | {kFiveCharacter, kFiveCharacter, kFiveCharacter}, |
55 | | {kSixCharacter, kSixCharacter, kSixCharacter}, |
56 | | {kSevenCharacter, kSevenCharacter, kSevenCharacter}, |
57 | | {kEightCharacter, kEightCharacter, kEightCharacter}, |
58 | | {kNineCharacter, kNineCharacter, kNineCharacter}, |
59 | | {kOnePin, kOnePin, kOnePin}, |
60 | | {kTwoPin, kTwoPin, kTwoPin}, |
61 | | {kThreePin, kThreePin, kThreePin}, |
62 | | {kFourPin, kFourPin, kFourPin}, |
63 | | {kFivePin, kFivePin, kFivePin}, |
64 | | {kSixPin, kSixPin, kSixPin}, |
65 | | {kSevenPin, kSevenPin, kSevenPin}, |
66 | | {kEightPin, kEightPin, kEightPin}, |
67 | | {kNinePin, kNinePin, kNinePin}, |
68 | | {kWestWind, kWestWind, kWestWind}, |
69 | | {kEastWind, kEastWind, kEastWind}, |
70 | | {kSouthWind, kSouthWind, kSouthWind}, |
71 | | {kNorthWind, kNorthWind, kNorthWind}, |
72 | | {kRedDragon, kRedDragon, kRedDragon}, |
73 | | {kWhiteDragon, kWhiteDragon, kWhiteDragon}, |
74 | | {kGreenDragon, kGreenDragon, kGreenDragon}}; |
75 | | |
76 | | const std::vector<std::vector<Piece>> kPairs = { |
77 | | {kOneBamboo, kOneBamboo}, |
78 | | {kTwoBamboo, kTwoBamboo}, |
79 | | {kThreeBamboo, kThreeBamboo}, |
80 | | {kFourBamboo, kFourBamboo}, |
81 | | {kFiveBamboo, kFiveBamboo}, |
82 | | {kSixBamboo, kSixBamboo}, |
83 | | {kSevenBamboo, kSevenBamboo}, |
84 | | {kEightBamboo, kEightBamboo}, |
85 | | {kNineBamboo, kNineBamboo}, |
86 | | {kOnePin, kOnePin}, |
87 | | {kTwoPin, kTwoPin}, |
88 | | {kThreePin, kThreePin}, |
89 | | {kFourPin, kFourPin}, |
90 | | {kFivePin, kFivePin}, |
91 | | {kSixPin, kSixPin}, |
92 | | {kSevenPin, kSevenPin}, |
93 | | {kEightPin, kEightPin}, |
94 | | {kNinePin, kNinePin}, |
95 | | {kOneCharacter, kOneCharacter}, |
96 | | {kTwoCharacter, kTwoCharacter}, |
97 | | {kThreeCharacter, kThreeCharacter}, |
98 | | {kFourCharacter, kFourCharacter}, |
99 | | {kFiveCharacter, kFiveCharacter}, |
100 | | {kSixCharacter, kSixCharacter}, |
101 | | {kSevenCharacter, kSevenCharacter}, |
102 | | {kEightCharacter, kEightCharacter}, |
103 | | {kNineCharacter, kNineCharacter}, |
104 | | {kEastWind, kEastWind}, |
105 | | {kSouthWind, kSouthWind}, |
106 | | {kWestWind, kWestWind}, |
107 | | {kNorthWind, kNorthWind}, |
108 | | {kRedDragon, kRedDragon}, |
109 | | {kWhiteDragon, kWhiteDragon}, |
110 | | {kGreenDragon, kGreenDragon}}; |
111 | | |
112 | | const std::vector<Piece> kPieceSet{ |
113 | | kOneBamboo, kTwoBamboo, kThreeBamboo, kFourBamboo, |
114 | | kFiveBamboo, kSixBamboo, kSevenBamboo, kEightBamboo, |
115 | | kNineBamboo, kOnePin, kTwoPin, kThreePin, |
116 | | kFourPin, kFivePin, kSixPin, kSevenPin, |
117 | | kEightPin, kNinePin, kOneCharacter, kNineCharacter, |
118 | | kTwoCharacter, kThreeCharacter, kFourCharacter, kFiveCharacter, |
119 | | kSixCharacter, kSevenCharacter, kEightCharacter, kWhiteDragon, |
120 | | kGreenDragon, kRedDragon, kEastWind, kSouthWind, |
121 | | kNorthWind, kWestWind}; |
122 | | |
123 | 0 | bool TestValid(const std::vector<Piece>& hand) { |
124 | 0 | std::map<Piece, bool> pieces; |
125 | 0 | for (const auto& piece : hand) { |
126 | 0 | if (pieces.contains(piece)) { |
127 | 0 | return false; |
128 | 0 | } |
129 | 0 | pieces[piece] = true; |
130 | 0 | } |
131 | 0 | return true; |
132 | 0 | } |
133 | | } // namespace |
134 | | |
135 | 0 | std::vector<Piece> GetPossibleStdFormHand() { |
136 | 0 | std::vector<Piece> living_walls; |
137 | 0 | std::vector<Piece> dead_wall; |
138 | 0 | for (int i = 0; i < 4; i++) { |
139 | 0 | living_walls.insert(living_walls.end(), kPieceSet.begin(), kPieceSet.end()); |
140 | 0 | } |
141 | |
|
142 | 0 | std::random_device rd; |
143 | 0 | std::mt19937_64 g(rd()); |
144 | 0 | std::shuffle(living_walls.begin(), living_walls.end(), g); |
145 | 0 | std::move(living_walls.begin(), living_walls.begin() + 14, |
146 | 0 | std::back_inserter(dead_wall)); |
147 | |
|
148 | 0 | std::array<uint8_t, Piece::kPiecesize> piece_count = {}; |
149 | 0 | for (const auto& piece : living_walls) { |
150 | 0 | piece_count.at(piece.toUint8_t())++; |
151 | 0 | } |
152 | |
|
153 | 0 | std::vector<bool> choose_pair = {false, false, false, false, true}; |
154 | 0 | std::shuffle(choose_pair.begin(), choose_pair.end(), g); |
155 | 0 | const std::uniform_int_distribution<> pair_chance(0, 3); |
156 | 0 | std::uniform_int_distribution<> triplet_selection(0, kTriplets.size()); |
157 | 0 | std::uniform_int_distribution<> pair_selection(0, kPairs.size()); |
158 | |
|
159 | 0 | std::vector<Piece> hand; |
160 | 0 | for (const bool choice : choose_pair) { |
161 | 0 | if (choice) { |
162 | 0 | int pair = pair_selection(g); |
163 | 0 | while (piece_count.at(kPairs.at(pair)[0].toUint8_t()) < 2) { |
164 | 0 | pair = pair_selection(g); |
165 | 0 | } |
166 | 0 | hand.push_back(kPairs.at(pair)[0]); |
167 | 0 | hand.push_back(kPairs.at(pair)[1]); |
168 | 0 | piece_count.at(kPairs.at(pair)[0].toUint8_t()) -= 2; |
169 | 0 | } else { |
170 | 0 | int triplet = triplet_selection(g); |
171 | 0 | while ((triplet <= 20 && |
172 | 0 | (piece_count.at(kTriplets.at(triplet)[0].toUint8_t()) < 1 || |
173 | 0 | piece_count.at(kTriplets.at(triplet)[1].toUint8_t()) < 1 || |
174 | 0 | piece_count.at(kTriplets.at(triplet)[2].toUint8_t()) < 1)) || |
175 | 0 | (triplet > 20 && |
176 | 0 | piece_count.at(kTriplets.at(triplet)[0].toUint8_t()) < 3)) { |
177 | 0 | triplet = triplet_selection(g); |
178 | 0 | } |
179 | 0 | if (triplet <= 20) { |
180 | 0 | piece_count.at(kTriplets.at(triplet)[0].toUint8_t())--; |
181 | 0 | piece_count.at(kTriplets.at(triplet)[1].toUint8_t())--; |
182 | 0 | piece_count.at(kTriplets.at(triplet)[2].toUint8_t())--; |
183 | 0 | } else { |
184 | 0 | piece_count.at(kTriplets.at(triplet)[0].toUint8_t()) -= 3; |
185 | 0 | } |
186 | 0 | hand.push_back(kTriplets.at(triplet)[0]); |
187 | 0 | hand.push_back(kTriplets.at(triplet)[1]); |
188 | 0 | hand.push_back(kTriplets.at(triplet)[2]); |
189 | 0 | } |
190 | 0 | } |
191 | 0 | return hand; |
192 | 0 | } |
193 | | |
194 | 0 | bool TestStdForm(const std::vector<Piece>& hand) { |
195 | 0 | auto root = breakdownHand(hand); |
196 | 0 | for (const auto& branch : Node::AsBranchVectors(root.get())) { |
197 | 0 | bool complete = true; |
198 | 0 | const std::vector<const Node*> singles; |
199 | 0 | for (const auto* node : branch) { |
200 | 0 | if (node->type() == SetType::kSingle) { |
201 | 0 | complete = false; |
202 | 0 | break; |
203 | 0 | } |
204 | 0 | } |
205 | 0 | if (complete) { |
206 | 0 | return true; |
207 | 0 | } |
208 | 0 | } |
209 | | |
210 | 0 | return false; |
211 | 0 | } |
212 | | |
213 | 0 | std::vector<Piece> GetPossibleTenpaiHand(bool replacement) { |
214 | 0 | std::vector<Piece> tenpaihand = GetPossibleStdFormHand(); |
215 | 0 | std::random_device rd; |
216 | 0 | std::mt19937_64 g(rd()); |
217 | 0 | std::shuffle(tenpaihand.begin(), tenpaihand.end(), g); |
218 | 0 | std::uniform_int_distribution<> piece_index(0, 13); |
219 | 0 | std::uniform_int_distribution<> piece_select(0, 33); |
220 | 0 | const int ind = piece_index(g); |
221 | 0 | if (!replacement) { |
222 | 0 | tenpaihand.erase(tenpaihand.begin() + ind); |
223 | 0 | return tenpaihand; |
224 | 0 | } |
225 | 0 | tenpaihand[ind] = kPieceSet[piece_select(g)]; |
226 | 0 | while (TestStdForm(tenpaihand) && !TestValid(tenpaihand)) { |
227 | 0 | tenpaihand[ind] = kPieceSet[piece_select(g)]; |
228 | 0 | } |
229 | 0 | return tenpaihand; |
230 | 0 | } |
231 | | |
232 | | } // namespace mahjong |