-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathAI.java
executable file
·167 lines (131 loc) · 4.04 KB
/
AI.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
// CS171 Fall 2012 Final Project
//
// Nealon Young
// ID #81396982
import java.util.ArrayList;
import javax.swing.*;
public class AI implements Runnable {
private static final int TIME_LIMIT_MILLIS = 5000;
private static final int EVALS_PER_SECOND = 100;
private static final int emptyPosition = 0;
private static final int aiPosition = 1;
private static final int humanPosition = 2;
private static final int winCutoff = 500000;
private static boolean searchCutoff = false;
public AI() {
}
//
// run() executes a search of the game state, and makes a move for the AI player
//
public void run() {
AIGameState state = new AIGameState();
AIGameMove move = chooseMove(state);
AIGame.buttons[move.getRow()][move.getColumn()].setText(AIGame.aiButtonText);
}
//
// chooseMove() scores each of the possible moves that can be made from the given AIGameState, and returns the move with the highest eval score
//
private AIGameMove chooseMove(AIGameState state) {
long startTime = System.currentTimeMillis();
boolean aiMove = state.aiMove();
int maxScore = Integer.MIN_VALUE;
AIGameMove bestMove = null;
ArrayList<AIGameMove> moves = state.validMoves();
for (AIGameMove move : moves) {
//
// Copy the current game state
//
AIGameState newState = state.clone();
newState.makeMove(move);
//
// Compute how long to spend looking at each move
//
long searchTimeLimit = ((TIME_LIMIT_MILLIS - 1000) / (moves.size()));
int score = iterativeDeepeningSearch(newState, searchTimeLimit);
//
// If the search finds a winning move
//
if (score >= winCutoff) {
return move;
}
if (score > maxScore) {
maxScore = score;
bestMove = move;
}
}
return bestMove;
}
//
// Run an iterative deepening search on a game state, taking no longrer than the given time limit
//
private int iterativeDeepeningSearch(AIGameState state, long timeLimit) {
long startTime = System.currentTimeMillis();
long endTime = startTime + timeLimit;
int depth = 1;
int score = 0;
searchCutoff = false;
while (true) {
long currentTime = System.currentTimeMillis();
if (currentTime >= endTime) {
break;
}
int searchResult = search(state, depth, Integer.MIN_VALUE, Integer.MAX_VALUE, currentTime, endTime - currentTime);
//
// If the search finds a winning move, stop searching
//
if (searchResult >= winCutoff) {
return searchResult;
}
if (!searchCutoff) {
score = searchResult;
}
depth++;
}
return score;
}
//
// search() will perform minimax search with alpha-beta pruning on a game state, and will cut off if the given time
// limit has elapsed since the beginning of the search
//
private int search(AIGameState state, int depth, int alpha, int beta, long startTime, long timeLimit) {
ArrayList<AIGameMove> moves = state.validMoves();
boolean myMove = state.aiMove();
int savedScore = (myMove) ? Integer.MIN_VALUE : Integer.MAX_VALUE;
int score = Evaluator.eval(state);
long currentTime = System.currentTimeMillis();
long elapsedTime = (currentTime - startTime);
if (elapsedTime >= timeLimit) {
searchCutoff = true;
}
//
// If this is a terminal node or a win for either player, abort the search
//
if (searchCutoff || (depth == 0) || (moves.size() == 0) || (score >= winCutoff) || (score <= -winCutoff)) {
return score;
}
if (state.aiMove) {
for (AIGameMove move : moves) {
AIGameState childState = state.clone();
childState.makeMove(move);
alpha = Math.max(alpha, search(childState, depth - 1, alpha, beta, startTime, timeLimit));
if (beta <= alpha) {
break;
}
}
return alpha;
} else {
for (AIGameMove move : moves) {
AIGameState childState = state.clone();
childState.makeMove(move);
beta = Math.min(beta, search(childState, depth - 1, alpha, beta, startTime, timeLimit));
if (beta <= alpha) {
break;
}
}
return beta;
}
}
public void Reset() {
//clear sequential-AI based data here:
}
}