-
Notifications
You must be signed in to change notification settings - Fork 0
/
ThinkerStrategy.java
232 lines (198 loc) · 7.84 KB
/
ThinkerStrategy.java
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
/*ThinkerStrategy is the second most complex strategy as it introduces more complex and informed
decision making. Decision making in the three overridden methods has more random elements and all the
hands the ThinkerStrategy plays are recorded and held in previousPlays to inform its future decisions
*/
import java.util.*;
public class ThinkerStrategy extends BasicStrategy
implements Strategy {
//hand that stores all previously played cards for use in callCheat
private Hand previousPlays = new Hand();
//cheats if necessary, but will also randomly cheat when unnecessary
@Override
public boolean cheat(Bid b, Hand h)
{
Card.Rank bidRank = b.getRank();
Iterator<Card> it = h.iterator();
while(it.hasNext())
{
Card curCard = it.next();
//checks if a card exists in the player's hand whose rank is required by the bid
if(curCard.getRank() == bidRank || curCard.getRank() == bidRank.next())
{
return randomDecision();
}
}
//if the player has no cards that match the bid rank, it must cheat
return true;
}
@Override
public Bid chooseBid(Bid b, Hand h, boolean cheat)
{
//Hand and Rank used to create Bid instance to be returned
Hand playHand = new Hand();
Card.Rank playRank;
if(cheat)
{
/*------determine playHand-----*/
playHand = createCheatingPlayHand(b, h);
/*-----determine playRank------*/
Card.Rank posRankLower = b.getRank();
Card.Rank posRankHigher = b.getRank().next();
playRank = getCheatRank(posRankLower, posRankHigher);
return new Bid(playHand, playRank);
}
else
{
/*-------determining playHand----------*/
//delegated to createPlayHand method so code can be reused in MyStrategy
playHand = createPlayHand(b, h);
/*------determining playRank--------*/
//set playRank to whatever rank the cards to be played are
playRank = playHand.getHand().get(0).getRank();
//adds cards to be played to previousPlays
previousPlays.addHand(playHand);
return new Bid(playHand, playRank);
}
}
//decides whether to call cheat using current hand with a random probability p to call cheat anyway
@Override
public boolean callCheat(Hand h, Bid b)
{
//get details about the played hand
int playedCount = b.getHand().size();
//combining count methods to count both
int ownCount = super.countCurHand(h, b);
ownCount += countPrevPlayed(h, b, this.previousPlays);
//resets previousPlays hand on each cheat call after it has been used
previousPlays = new Hand();
//if you have over 2 cards of that rank the previous player must be cheating
if(ownCount + playedCount > 4)
{
return true;
}
else
{
//determining small probability of calling cheat despite not being certain
double p = (ownCount + playedCount) / 20.0;
return randomWithProbability(p);
}
}
/*counting matching cards in previously played hands
embedded in seperate method for code reuse*/
protected int countPrevPlayed(Hand h, Bid b, Hand previousPlays)
{
Card.Rank playedRank = b.getRank();
int ownCount = 0;
//iterate through previously played cards and count how many cards of the played rank there are
Iterator<Card> it2 = previousPlays.iterator();
while(it2.hasNext())
{
Card curCard = it2.next();
//if a previously played card has the same rank add to running total
if(curCard.getRank().equals(playedRank))
{
ownCount++;
}
}
return ownCount;
}
//creates a hand to play when making a non-cheating bid
//expanded upon in MyStrategy to factor in number of that rank played
protected Hand createPlayHand(Bid b, Hand h)
{
Hand playHand = new Hand();
//holds the cards eligible to be played for either possible rank
ArrayList<Card> toPlayLower = super.generateToPlay(h, b, 0);
ArrayList<Card> toPlayHigher = super.generateToPlay(h, b, 1);
//random decision to play all cards or a random number of them
if(randomDecision())
{
/*---------playing all cards---------*/
//if toPlayLower is empty play toPlayHigher, else play toPlayLower
if(toPlayLower.isEmpty())
{
playHand.addCardCollection(toPlayHigher);
}
else
{
playHand.addCardCollection(toPlayLower);
}
}
else
{
/*----playing random amount of cards with preference to lower rank----*/
if(toPlayLower.isEmpty())
{
//creating random number no larger than toPlayHigher length and no less than 1
Random rand = new Random();
int numPlayed = rand.nextInt((toPlayHigher.size() - 1) + 1) + 1;
for(int i = 0; i < numPlayed; i++)
{
playHand.addSingleCard(toPlayHigher.get(i));
}
}
else
{
//creating random number no larger than toPlayLower length and no less than 1
Random rand = new Random();
int numPlayed = rand.nextInt((toPlayLower.size() - 1) + 1) + 1;
for(int i = 0; i < numPlayed; i++)
{
playHand.addSingleCard(toPlayLower.get(i));
}
}
}
return playHand;
}
//creates a play hand when making a cheating bid
protected Hand createCheatingPlayHand(Bid b, Hand h)
{
//Hand and Rank used to create Bid instance to be returned
Hand playHand = new Hand();
//creating new arraylist of cards in hand that will be cheating to play
ArrayList<Card> cheatCards = new ArrayList<>();
for(int i = 0; i < h.size(); i++)
{
Card.Rank curRank = h.getHand().get(i).getRank();
if(curRank != b.getRank() || curRank != b.getRank().next())
{
cheatCards.add(h.getHand().get(i));
}
}
//selecting a card to play from cheatCards with a bias towards higher ranks
int randIndex = randomLargeBiasInt(0, h.size() - 1);
Card selectedCard = h.getHand().get(randIndex);
playHand.addSingleCard(selectedCard);
//checking for other cards of the same rank to play
for(int i = 0; i < cheatCards.size(); i++)
{
Card.Rank curRank = cheatCards.get(i).getRank();
if(curRank == selectedCard.getRank() && i != randIndex)
{
playHand.addSingleCard(cheatCards.get(i));
}
}
return playHand;
}
//randomly makes a yes or no decision when called
protected boolean randomDecision()
{
Random rand = new Random();
return rand.nextBoolean();
}
//randomly generates a boolean value with probability p of being true
protected boolean randomWithProbability(double p)
{
return Math.random() < p;
}
//generates a random number within a given range with a bias towards the larger values
protected int randomLargeBiasInt(int min, int max)
{
Random rand = new Random();
//generate 2 different random ints within the given range
int rand1 = rand.nextInt((max - min) + 1) + min;
int rand2 = rand.nextInt((max - min) + 1) + min;
//selects the larger random number, giving a bias to larger numbers
return Math.max(rand1, rand2);
}
}