-
Notifications
You must be signed in to change notification settings - Fork 0
/
TreeNode.java
293 lines (241 loc) · 10 KB
/
TreeNode.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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
import org.omg.Messaging.SYNC_WITH_TRANSPORT;
import javax.annotation.processing.SupportedSourceVersion;
import java.util.*;
class BestMove{
Board boardState;
int index;
BestMove(){
boardState = new Board();
}
}
public class TreeNode extends Thread{
private Board state;
//this is used for level deepening
private int MAX_DEPTH = 3;
private int AI;
private int opponent;
TreeNode(){
}
//constructor sets the board and the player number and opponent number
TreeNode(Board board, int AI ,int opponent){
state = new Board(board);
this.AI = AI;
this.opponent = opponent;
}
//minimax function that takes in the current board, whether its a max level or not, and the depth as input
public int miniMax(Board currentBoard, boolean maxLevel, int depth){
int score = checkWinner(currentBoard);
Board boardCopy = new Board(currentBoard);
//exits when the desired depth has been reached
if(depth == 0){
return score;
}
//ends if the AI has won
if(score == 100){
return score;
}
//ends if the opponent has won
if (score == -100){
return score;
}
//this is the AI's turns and is the max level
int goAgainCount = 0;
if(maxLevel){
int bestMove = -1000;
for(int i = state.getNumPits()-1; i >= 0;i--){
//makes the move
if(currentBoard.getSeedsInPit(AI, i) > 0){
//outputs a value of the player goes again
int goAgain = makeMoveOnBoard(currentBoard, AI,i);
//if it goes again we are at the same level
if(goAgain == 1) {
bestMove = Math.max(bestMove, miniMax(currentBoard, maxLevel,depth) + goAgain);
}
//otherwise continue to the next level
else{
bestMove = Math.max(bestMove, miniMax(currentBoard, !maxLevel,depth-1));
}
currentBoard = new Board(boardCopy);
}
}
}
//this is the opponents turns and is the min level
else{
int minMove = 1000;
for(int i = state.getNumPits()-1; i >= 0;i--) {
if(currentBoard.getSeedsInPit(opponent, i) > 0) {
//outputs a value of the player goes again
int goAgain = makeMoveOnBoard(currentBoard, opponent, i);
//if it goes again we are at the same level
if (goAgain == 1) {
minMove = Math.min(minMove, miniMax(currentBoard, maxLevel,depth) - goAgain);
}
//otherwise go the next level
else {
minMove = Math.min(minMove, miniMax(currentBoard, !maxLevel,depth-1));
}
//return back to the original state
currentBoard = new Board(boardCopy);
}
}
}
return score;
}
//this will get the best move to make
public BestMove bestMove(Board state,int AI,int opponent){
this.AI = AI;
this.opponent = opponent;
//this will return index of the best move
BestMove move = new BestMove();
//we will be doing a max node first
int nodeValue = -1000;
Board copyState = new Board(state);
for(int i = state.getNumPits()-1; i > 0;i--){
//if the pocket has seeds in it, make a move
if(copyState.getSeedsInPit(AI,i) > 0) {
//return 1, if you get another turn
//return 0 if you dont go again
int goAgain = makeMoveOnBoard(copyState,AI,i);
int valueOfMove;
//if the player goes again we remain at a max node
if(goAgain == 1){
valueOfMove = miniMax(copyState,true,MAX_DEPTH) + goAgain;
}
//otherise we go to a min node
else{
valueOfMove = miniMax(copyState,false,MAX_DEPTH) + goAgain;
}
//return back to the original board state
copyState = new Board(state);
//sets the current best move
if(valueOfMove > nodeValue){
nodeValue = valueOfMove;
move.index = i;
move.boardState=copyState;
}
}
}
return move;
}
//makes the move,
//returns 1 if the player will go again, return 0 otherwise
public int makeMoveOnBoard(Board state, int currentlyPlaying, int move){
//wipe the seeds from index specified by user (set num of seeds in pit to 0)
int numSeeds = state.getSeedsInPit(currentlyPlaying,move);
state.wipeSeeds(currentlyPlaying,move);
//add one to every pit and store crossed, not including other player's store
int index = move + 1;
//will hold the ending pit by the end of the while loop
int lastPit = 0;
//holds the side of the board we are distributing on: 1 or 2
int boardSide = currentlyPlaying;
while (numSeeds > 0) {
lastPit = index;
//if player is at the end and at own store, add to store, switch to other side of the board and continue on
if ((index == state.getNumPits()) && (boardSide == currentlyPlaying)) {
//add to store
state.addStore(currentlyPlaying);
numSeeds--;
//switch board sides
boardSide = state.otherPlayerSide(boardSide);
index = 0;
//if player ends in their store, they do another turn
if (numSeeds == 0) {
return 1;
}
}
//if we're at the end and not at our own store then do not add to store, switch to other side and continue on
else if (index == state.getNumPits()) {
//switch board sides
boardSide = state.otherPlayerSide(boardSide);
index = 0;
}
//just add a seed and move on
else {
state.addSeed(boardSide,index);
numSeeds--;
index++;
}
}
if (lastPit == state.getNumPits()) {
return 0;
}
//if the user ends their turn in a pit on their own side in an empty pit and the pit directly
// across from it (on the other player's side) has seeds, all seeds in both pits
// go to the store of the user who just finished moving seeds
int otherSide = state.otherPlayerSide(currentlyPlaying);
if ((boardSide == currentlyPlaying) &&
(state.getSeedsInPit(currentlyPlaying, lastPit) == 1) &&
(state.getSeedsInPit(otherSide, state.getNumPits() - lastPit - 1) != 0)) {
int pitSeeds1 = state.getSeedsInPit(currentlyPlaying, lastPit);
int pitSeeds2 = state.getSeedsInPit(otherSide, state.getNumPits() - lastPit - 1);
//wipe seeds from both pits
state.wipeSeeds(currentlyPlaying, lastPit);
state.wipeSeeds(otherSide, state.getNumPits() - lastPit - 1);
//put seeds in p's store
state.addStoreByValue(currentlyPlaying, pitSeeds1 + pitSeeds2);
}
return 0;
}
//given a board object it returns who won using an integer
//100 if the AI won, -100 if the opponent won, 0 otherwise
public int checkWinner(Board state){
if(gameOver()) {
//add up all of the remaining seeds on the stores
for(int i = 0 ; i < state.getNumPits();i++){
//adds seeds on AI side to the store
int countSeeds = state.accessStore(AI);
state.addStoreByValue(AI,countSeeds);
//adds seeds on opponent side to their store
countSeeds = state.accessStore(opponent);
state.addStoreByValue(opponent,countSeeds);
}
//the AI wins
if (state.accessStore(AI) > state.accessStore(opponent)) {
return 100;
}
//the opponent wins
else if (state.accessStore(AI) < state.accessStore(opponent)) {
return -100;
}
//there is a tie in the game
else {
return 0;
}
}
//setruns the difference in seeds as the score
else{
int score1 = 0;
int score2 = 0;
for(int i = 0; i < state.getNumPits();i++){
score1 += state.getSeedsInPit(AI,i);
score2 += state.getSeedsInPit(opponent,i);
}
int difference = (state.accessStore(AI)+score1) - (state.accessStore(opponent) + score2);
return difference;
}
}
/**
* This checks if the game is over
* Checks if there are any more moves available to make
*/
public boolean gameOver(){
int counterPlayer1 = 0;
int counterPlayer2 = 0;
for(int i = 0; i < state.getNumPits();i++){
int player1PocketValue = state.getSeedsInPit(AI,i);
int player2PocketValue = state.getSeedsInPit(opponent,i);
if(player1PocketValue > 0) {
counterPlayer1++;
}
if(player2PocketValue > 0) {
counterPlayer2++;
}
}
// if one of the players sides has no more seeds in it then the game has ended
if(counterPlayer1 == 0 || counterPlayer2 == 0){
return true;
}
return false;
}
}