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/controllers/gentlemanbot.cc
Line
Count
Source
1
#include "controllers/gentlemanbot.h"
2
3
#include <array>
4
#include <cstddef>
5
#include <cstdint>
6
#include <memory>
7
#include <vector>
8
9
#include "analysis/analysis.h"
10
#include "analysis/handnode.h"
11
#include "controllers/controllermanager.h"
12
#include "types/event.h"
13
#include "types/pieces.h"
14
#include "types/piecetype.h"
15
#include "types/sets.h"
16
#include "types/winds.h"
17
18
namespace mahjong {
19
REGISTER_PLAYER_CONTROLLER(GentlemanBot);
20
21
namespace {
22
void CountPieces(std::array<int8_t, Piece::kPiecesize> counts,
23
0
                 const std::vector<Piece>& pieces) {
24
0
  for (const auto& p : pieces) {
25
0
    counts.at(p.toUint8_t())++;
26
0
  }
27
0
}
28
29
}  // namespace
30
31
void GentlemanBot::RoundStart(std::vector<Piece> hand, Wind /*seatWind*/,
32
0
                              Wind /*prevalentWind*/) {
33
0
  hand_ = hand;
34
0
  lastEvent_.type = Event::kDiscard;
35
0
  riichi_ = false;
36
0
}
37
38
0
void GentlemanBot::ReceiveEvent(Event e) {
39
0
  if (e.decision) {
40
0
    if (e.type <= lastEvent_.type) {
41
0
      lastEvent_ = e;
42
0
    }
43
44
0
    if (e.type == Event::kDiscard) {
45
0
      if (!riichi_) {
46
0
        hand_.emplace_back(e.piece);
47
0
        lastEvent_.piece = getDiscard().toUint8_t();
48
0
      }
49
0
    } else {
50
0
    }
51
0
  }
52
0
}
53
54
0
Event GentlemanBot::RetrieveDecision() {
55
0
  if (lastEvent_.type == Event::kRiichi) {
56
0
    lastEvent_.type = Event::kRiichi;
57
0
    riichi_ = true;
58
0
  } else if (lastEvent_.type != Event::kDiscard) {
59
0
    lastEvent_.type = Event::kDecline;
60
0
  }
61
62
0
  Event e = lastEvent_;
63
0
  lastEvent_.type = Event::kDiscard;  // lowest """priority""" event type
64
0
  return e;
65
0
}
66
67
0
Piece GentlemanBot::getDiscard() {
68
0
  std::vector<Piece> free_pieces;
69
0
  std::vector<Piece> prefered_discards;
70
0
  std::vector<Piece> second_tier_discards;
71
0
  std::vector<Piece> third_tier_discards;
72
73
0
  std::array<int8_t, Piece::kPiecesize> counts = {};
74
0
  const std::unique_ptr<Node> symbolic_hand = breakdownHand(hand_);
75
76
0
  for (const auto& leaf : *symbolic_hand) {
77
0
    if (leaf.type() == SetType::kSingle) {
78
0
      free_pieces.push_back(leaf.start());
79
0
    }
80
0
  }
81
82
0
  CountPieces(counts, free_pieces);
83
84
0
  for (const auto& p : free_pieces) {
85
0
    if (counts.at((p + 1).toUint8_t()) > 0 ||
86
0
        counts.at((p - 1).toUint8_t()) > 0) {
87
0
      second_tier_discards.push_back(p);
88
0
    } else if (counts.at(p.toUint8_t()) == 2 ||
89
0
               counts.at((p + 2).toUint8_t()) > 0 ||
90
0
               counts.at((p - 2).toUint8_t()) > 0) {
91
0
      third_tier_discards.push_back(p);
92
0
    } else {
93
0
      prefered_discards.push_back(p);
94
0
    }
95
0
  }
96
97
0
  for (const auto& p : prefered_discards) {
98
0
    if (p.isHonor()) {
99
0
      for (size_t i = 0; i < hand_.size(); i++) {
100
0
        if (hand_.at(i).toUint8_t() == p.toUint8_t()) {
101
0
          hand_.erase(hand_.begin() + i);
102
0
        }
103
0
      }
104
0
      return p;
105
0
    }
106
0
  }
107
0
  for (const auto& p : prefered_discards) {
108
0
    for (size_t i = 0; i < hand_.size(); i++) {
109
0
      if (hand_.at(i).toUint8_t() == p.toUint8_t()) {
110
0
        hand_.erase(hand_.begin() + i);
111
0
      }
112
0
    }
113
0
    return p;
114
0
  }
115
0
  for (const auto& p : second_tier_discards) {
116
0
    for (size_t i = 0; i < hand_.size(); i++) {
117
0
      if (hand_.at(i).toUint8_t() == p.toUint8_t()) {
118
0
        hand_.erase(hand_.begin() + i);
119
0
      }
120
0
    }
121
0
    return p;
122
0
  }
123
0
  for (const auto& p : third_tier_discards) {
124
0
    for (size_t i = 0; i < hand_.size(); i++) {
125
0
      if (hand_.at(i).toUint8_t() == p.toUint8_t()) {
126
0
        hand_.erase(hand_.begin() + i);
127
0
      }
128
0
    }
129
0
    return p;
130
0
  }
131
0
  return Piece(kError);
132
0
}
133
134
}  // namespace mahjong