-
Notifications
You must be signed in to change notification settings - Fork 2
/
player.cpp
248 lines (216 loc) · 8.4 KB
/
player.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#include "player.hpp"
#include "scrabble_config.hpp"
using namespace std;
////////////////////////////////////////////////////////////////////////////////
Player::Player(const std::string& name, Scrabble_Game* the_game) :
m_name(name), m_score(0), m_the_game(the_game)
////////////////////////////////////////////////////////////////////////////////
{
//fill player's tray with NULL pieces
m_pieces.resize(the_game->get_config().NUM_PLAYER_PIECES());
for (unsigned i = 0; i < m_pieces.size(); i++) {
m_pieces[i] = NULL;
}
}
////////////////////////////////////////////////////////////////////////////////
void Player::add_piece(const Scrabble_Piece* new_piece)
////////////////////////////////////////////////////////////////////////////////
{
my_assert(m_char_piece_map.size() == get_num_pieces(),
std::string("Piece-map and tray sizes are out of sync: ") +
" piece-map-size=" + obj_to_str(m_char_piece_map.size()) +
" tray-size=" + obj_to_str(get_num_pieces()));
//loop over tray-indeces. When we find a NULL value, insert there
for (unsigned i = 0; i < m_pieces.size(); i++) {
if (!m_pieces[i]) {
m_pieces[i] = new_piece;
m_char_piece_map.insert(pair<char, const Scrabble_Piece*>(new_piece->get_letter(), new_piece));
my_assert(!(new_piece->is_wildcard() && new_piece->get_letter() != '-'),
std::string("wild-card piece should have had letter '-'") +
", instead found: " + obj_to_str(new_piece->get_letter()));
return;
}
}
//should never give a player too many pieces
my_assert(false, "Tried to give player too many pieces.");
}
////////////////////////////////////////////////////////////////////////////////
void Player::remove_piece(const Scrabble_Piece* piece)
////////////////////////////////////////////////////////////////////////////////
{
my_assert(m_char_piece_map.size() == get_num_pieces(),
std::string("Piece-map and tray sizes are out of sync: ") +
" piece-map-size=" + obj_to_str(m_char_piece_map.size()) +
" tray-size=" + obj_to_str(get_num_pieces()));
//loop over tray until we find the exact same piece (matching addrs), then
//remove the piece.
for (unsigned i = 0; i < m_pieces.size(); i++) {
if (m_pieces[i] == piece) {
m_pieces[i] = NULL;
remap(); //inefficient, but that's OK
return;
}
}
//this operation should never fail
my_assert(false, "Tried to remove a piece that the player did not have.");
}
////////////////////////////////////////////////////////////////////////////////
const Indv_Play& Player::play()
////////////////////////////////////////////////////////////////////////////////
{
m_current_play.clear();
//leave this part to children
make_play();
remap();
return m_current_play;
}
////////////////////////////////////////////////////////////////////////////////
void Player::game_over()
////////////////////////////////////////////////////////////////////////////////
{
//The game has notified us that the game has been completed, we must deduct
//the value of our "stash" from our total
for (unsigned i = 0; i < m_pieces.size(); i++) {
if (m_pieces[i] != NULL) {
if (m_pieces[i]->get_point_val() > m_score) {
//we cannot go negative
m_score = 0;
break;
}
else {
m_score -= m_pieces[i]->get_point_val();
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
const Scrabble_Piece* Player::observe_piece(unsigned idx) const
////////////////////////////////////////////////////////////////////////////////
{
my_assert(idx < get_num_pieces(), "Observed out of bounds");
unsigned count = 0;
for (unsigned i = 0; i < m_pieces.size(); i++) {
if (count == idx && m_pieces[i] != nullptr) {
return m_pieces[i];
}
count += (m_pieces[i] != NULL);
}
my_assert(false, "Should never make it here");
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
unsigned Player::get_num_pieces() const
////////////////////////////////////////////////////////////////////////////////
{
unsigned count = 0;
for (unsigned i = 0; i < m_pieces.size(); i++) {
count += (m_pieces[i] != NULL);
}
return count;
}
////////////////////////////////////////////////////////////////////////////////
void Player::remap() const
////////////////////////////////////////////////////////////////////////////////
{
m_char_piece_map.clear();
for (unsigned i = 0; i < m_pieces.size(); i++) {
if (m_pieces[i]) {
//my_assert(!m_pieces[i]->is_played(), "Piece was already played");
char letter = m_pieces[i]->is_wildcard() ? '-' : m_pieces[i]->get_letter();
m_char_piece_map.insert(pair<char, const Scrabble_Piece*>(letter,m_pieces[i]));
}
}
}
////////////////////////////////////////////////////////////////////////////////
const Scrabble_Piece* Player::get_piece(char c) const
////////////////////////////////////////////////////////////////////////////////
{
multimap<char, const Scrabble_Piece*>::iterator itr;
#ifndef NDEBUG
//check the invariant that every piece in the map is also in the std::vector
for (itr = m_char_piece_map.begin(); itr != m_char_piece_map.end(); itr++) {
my_assert (has_piece(itr->second), "map and tray are out of sync");
}
#endif
//check that the player is attempting to play a real letter
my_require(Scrabble_Piece::is_valid_letter(c), std::string("'") + obj_to_str(c) + "' is not a valid letter.");
//look up the letter in the map, NOT the tray
itr = m_char_piece_map.find(c);
if (itr == m_char_piece_map.end()) {
//we don't have the exact piece, but we can use a wildcard piece instead
itr = m_char_piece_map.find('-');
my_require(itr != m_char_piece_map.end(), "Player tried to play, but does not have '" + obj_to_str(c) + "'");
//a wild-card is required to meet this request, change it's wildcard value
itr->second->set_wildcard_value(c);
}
//remove the piece from the map, NOT the tray, and return it
const Scrabble_Piece* rv = itr->second;
m_char_piece_map.erase(itr);
return rv;
}
////////////////////////////////////////////////////////////////////////////////
bool Player::has_piece(const Scrabble_Piece* piece) const
////////////////////////////////////////////////////////////////////////////////
{
for (unsigned i = 0; i < m_pieces.size(); i++) {
if (m_pieces[i] == piece) {
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
ostream& Player::operator<<(ostream& out) const
////////////////////////////////////////////////////////////////////////////////
{
out << "Player " << m_name << " has score " << m_score << endl;
out << " current pieces: ";
for (unsigned i = 0; i < m_pieces.size(); i++) {
if (m_pieces[i]) {
out << *(m_pieces[i]) << " ";
}
}
out << endl;
out << " current piece-map: ";
for (multimap<char, const Scrabble_Piece*>::const_iterator itr = m_char_piece_map.begin();
itr != m_char_piece_map.end(); itr++) {
out << "(" << itr->first << "," << *(itr->second) << ") ";
}
return out;
}
////////////////////////////////////////////////////////////////////////////////
istream& Player::operator>>(istream& in)
////////////////////////////////////////////////////////////////////////////////
{
std::string line;
char buf[64];
auto& piece_source = m_the_game->get_piece_source();
getline(in, line);
int rv = sscanf(line.c_str(), "Player %s has score %d", buf, &m_score);
my_require(rv == 2, "Bad player score format");
getline(in, line);
std::string prefix = " current pieces:";
std::string real_pref = line.substr(0, prefix.size());
my_require(real_pref == prefix, "Bad player tray");
line = line.substr(prefix.size());
for (char c : line) {
if (c != ' ') {
add_piece(piece_source.get_piece(c));
}
}
// skip piece map
getline(in, line);
return in;
}
////////////////////////////////////////////////////////////////////////////////
ostream& operator<<(ostream& out, const Player& player)
////////////////////////////////////////////////////////////////////////////////
{
return player.operator<<(out);
}
////////////////////////////////////////////////////////////////////////////////
istream& operator>>(istream& in, Player& player)
////////////////////////////////////////////////////////////////////////////////
{
return player.operator>>(in);
}