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