-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhuman_player.cpp
More file actions
143 lines (127 loc) · 5.32 KB
/
human_player.cpp
File metadata and controls
143 lines (127 loc) · 5.32 KB
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
/*
doko is a C++ doppelkopf program with an integrated UCT player.
Copyright (c) 2011-2016 Silvan Sievers
For questions, please write to: silvan.sievers@unibas.ch
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "human_player.h"
#include "game_type.h"
#include <cassert>
#include <iostream>
#include <string>
using namespace std;
HumanPlayer::HumanPlayer(int player_number) : Player(player_number), game_type(0) {
}
void HumanPlayer::set_cards(Cards cards_) {
Player::set_cards(cards_);
game_type = 0;
}
static unsigned int read_int_in_range(int min_value, int max_value) {
while (true) {
int value;
cin >> value;
if (cin.fail() || value < 0) {
cin.clear();
string wayne;
getline(cin, wayne);
} else if (value >= min_value && value <= max_value) {
return static_cast<unsigned int>(value);
}
cout << "invalid option, try again:" << endl;
}
}
size_t HumanPlayer::make_move(const vector<Move> &legal_moves) const {
for (size_t i = 0; i < legal_moves.size(); ++i) {
cout << i << " - ";
legal_moves[i].print_option();
if (i != legal_moves.size() - 1)
cout << ", ";
}
cout << endl;
return read_int_in_range(0, legal_moves.size());
}
size_t HumanPlayer::make_card_move(const vector<Move> &legal_moves) const {
// in order to allow a more human readable input, i.e. H9 to play hearts 9, this method needs to do some extra computation as creating a Cards object with all cards and in the end iterate over legal_moves to find the index of the card chosen by the player
Cards legal_cards;
for (size_t i = 0; i < legal_moves.size(); ++i)
legal_cards.add_card(legal_moves[i].get_card());
Card card_to_play;
while (true) { // repeated input until player choses one card of his hand
string name;
while (true) { // check for valid input, i.e. any card (not necessarily owned by the player, though)
cin >> name;
if (!is_valid_card_name(name)) {
cout << "unknown input, try again:" << endl;
} else {
break;
}
}
pair<Card, Card> card_pair = get_cards_for_name(name);
if (legal_cards.contains_card(card_pair.first)) {
card_to_play = card_pair.first;
break;
}
if (legal_cards.contains_card(card_pair.second)) {
card_to_play = card_pair.second;
break;
}
cout << "you cannot play this card!" << endl;
}
for (size_t i = 0; i < legal_moves.size(); ++i)
if (legal_moves[i].get_card() == card_to_play)
return i;
// this is the alternative to the more complicated computations above: simply ask the user for the index of the displayed card
/*cout << "please type in the appropriate index of the above output, starting from 0 for the first option" << endl;
int value = read_int_in_range(0, legal_moves.size());
return value;*/
assert(false);
return 0;
}
size_t HumanPlayer::ask_for_move(const vector<Move> &legal_moves) {
cout << "you are player " << id << ", these are your cards: " << endl;
cards.show(game_type);
// a card move
if (legal_moves[0].is_card_move()) {
cout << "please play a card (type in 'H9' or 'C1' for hearts 9 or clubs 10 e.g.)" << endl;
return make_card_move(legal_moves);
}
// not a card move
if (legal_moves[0].is_question_move()) {
question_t question_type = legal_moves[0].get_question_type();
switch (question_type) {
case IMMEDIATE_SOLO:
cout << "do you want to play an immediate solo (remaining players will not be asked for reservation)?" << endl;
break;
case HAS_RESERVATION:
cout << "do you have a reservation?" << endl;
break;
case IS_SOLO:
cout << "do you want to play a solo?" << endl;
break;
}
} else if (legal_moves[0].is_game_type_move()) {
cout << "which game type do you want to play?" << endl;
} else if (legal_moves[0].is_announcement_move()) {
cout << "do you want to make an announcement (if yes, which)?" << endl;
}
return make_move(legal_moves);
}
void HumanPlayer::inform_about_move(int player, const Move &move) {
Player::inform_about_move(player, move);
if (move.is_game_type_move()) {
assert(game_type == 0); // no other game_type has been set before
game_type = move.get_game_type();
} else if (game_type == 0 && move.is_card_move()) {
// if game_type is still not set when the first card is played, then nobody plays a solo/marriage, thus it is a regular game
game_type = ®ular;
}
}