-
Notifications
You must be signed in to change notification settings - Fork 0
/
TicTacToe.java
234 lines (217 loc) · 8.81 KB
/
TicTacToe.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
import java.util.Scanner;
import java.util.Stack;
public class TicTacToe {
private static final int MAX_PLY_DEPTH = 2;
private static final boolean ENABLE_GUI = true;
public static final boolean DEBUG = true;
public static final boolean PRIORITIZE_CORNER_MOVES = true;
public static final boolean PRIORITIZE_MULTILEVEL_MOVES = true;
public static final boolean TURBO_BLOCKING = true;
public static final boolean COUNT_TURNS = true;
public static final boolean ENABLE_AB_PRUNING = true;
public static final boolean ENABLE_MOVE_ORDERING = false;
public static final boolean ENABLE_AI_TIMER = false;
public static final boolean CONSIDER_POWER_POSITIONS = true;
private static final boolean ENABLE_TEST_UTILITY = false;
static SerialManager manager;
private static final boolean PHYSICAL_BOARD = false && !ENABLE_GUI;
private static GUI gui;
public static Board board;
public static boolean isAITurn = true;
public static void main(String[] args) throws InterruptedException{
if (ENABLE_TEST_UTILITY) {
// TESTER FOR SETTING UP BOARD CONFIGS. HAS UNDO CAPABILITY
Scanner scanner = new Scanner(System.in);
Board board = new Board();
Coordinate move = null;
Stack<Coordinate> lastMoves = new Stack<>();
while (true) {
System.out.print("\nPlayer | ");
move = getMove(board, scanner, lastMoves);
board = board.move(move, 1);
lastMoves.add(move);
board.print();
System.out.println("Eval for Player: " + board.evaluationFunction(1));
System.out.println("Eval for AI: " + board.evaluationFunction(2));
System.out.print("\nAI | ");
move = getMove(board, scanner, lastMoves);
board = board.move(move, 2);
lastMoves.add(move);
board.print();
System.out.println("Eval for Player: " + board.evaluationFunction(1));
System.out.println("Eval for AI: " + board.evaluationFunction(2));
}
} else {
Scanner scanner;
if (ENABLE_GUI) {
gui = new GUI(4);
} else {
scanner = new Scanner(System.in);
manager = new SerialManager();
manager.resetBoard();
System.out.println("Welcome to 3D Tic Tac Toe.");
System.out.println("Player: input coordinates as `level <space> row <space> column` where (0,0,0) is top left corner of bottom level");
}
board = new Board();
while (board.getOpenSpots().size() > 0 && !board.isGoalState()) {
if (!ENABLE_GUI) {
// Player's turn
board.turnCount++;
board = playerMove(board, scanner, 1);
if (DEBUG) {
printDebugMsgs(1);
}
if (board.isGoalState()) {
System.out.println("Player won!");
break;
}
// AI's turn
board = AIMove(board, 2);
board.turnCount++;
if (DEBUG) {
printDebugMsgs(2);
}
if (board.isGoalState()) {
System.out.println("AI won!");
break;
}
} else { // Using the GUI
if (isAITurn) {
board = AIMove(board, 2);
isAITurn = false;
board.turnCount++;
if (DEBUG) {
printDebugMsgs(2);
}
if (board.isGoalState()) {
gui.showWinMessage("AI won!");
isAITurn = true;
break;
}
}
}
if (board.getOpenSpots().isEmpty()) {
System.out.println("Tie: No spots left");
break;
}
}
if (board.isGoalState() && !isAITurn) {
gui.showWinMessage("Player won!");
}
}
}
public static Board AIMove(Board board, int aiTile) throws InterruptedException{
AI ai = new AI();
Coordinate move = ai.nextMove(board, aiTile, MAX_PLY_DEPTH).getMove();
if (!board.isSquareBlank(move)) {
System.out.println("Square not blank");
return AIMove(board, aiTile);
}
board = board.move(move, aiTile);
if (ENABLE_GUI) {
gui.move(move);
} else {
board.print();
System.out.println("AI moved " + move);
if(PHYSICAL_BOARD){
manager.move(move, 1);
}
}
return board;
}
public static void printDebugMsgs(int currentPlayer) {
board.print();
System.out.println("Evaluation of that move: " + board.evaluationFunction(currentPlayer));
if (TURBO_BLOCKING) {
System.out.println("Blocking factor: " + board.blockingFactor(currentPlayer, Board.getNextPlayer(currentPlayer)));
}
//System.out.println("Total filled: " + board.totalFilled);
if (COUNT_TURNS) {
System.out.println("Turn count: " + board.turnCount);
}
}
// Used only for the board configuration tester
private static Coordinate getMove(Board board, Scanner scanner, Stack<Coordinate> moves) throws InterruptedException{
if(!PHYSICAL_BOARD){
System.out.print("Move: ");
String input = "";
int x = 0, y = 0, z = 0;
if (scanner.hasNextLine()) {
input = scanner.nextLine();
if (input.equals("undo")) {
Coordinate lastMove = moves.pop();
board.board[lastMove.x][lastMove.y][lastMove.z] = 0;
board.print();
System.out.println("Eval for Player: " + board.evaluationFunction(1));
System.out.println("Eval for AI: " + board.evaluationFunction(2));
getMove(board, scanner, moves);
}
String[] parsed = input.split(" ");
try {
x = Integer.parseInt(parsed[0]);
y = Integer.parseInt(parsed[1]);
z = Integer.parseInt(parsed[2]);
if ((x > 3 || x < 0) || (y > 3 || y < 0) || (z > 3 || z < 0)) {
throw new Exception();
}
} catch (Exception e) {
System.out.println("Invalid move.");
}
} else {
System.err.print("Invalid input");
}
return new Coordinate(x, y, z);
}
else{
return manager.waitForMove(0, 100);
}
}
public static Board playerMove(Board board, Scanner scanner, int playerTile) throws InterruptedException{
System.out.print("Move: ");
String input = "";
int x = 0;
int y = 0;
int z = 0;
if(!PHYSICAL_BOARD){
if (scanner.hasNextLine()) {
input = scanner.nextLine();
String[] parsed = input.split(" ");
try {
x = Integer.parseInt(parsed[0]);
y = Integer.parseInt(parsed[1]);
z = Integer.parseInt(parsed[2]);
if ((x > 3 || x < 0) || (y > 3 || y < 0) || (z > 3 || z < 0)) {
throw new Exception();
}
} catch (Exception e) {
System.out.println("Invalid move.");
return playerMove(board, scanner, playerTile);
}
} else {
System.out.println("Invalid input");
return playerMove(board, scanner, playerTile);
}
}
else{
System.out.println("Waiting for move...");
Coordinate cord = manager.waitForMove(0,100);
x = cord.x;
y = cord.y;
z = cord.z;
}
Coordinate move;
boolean success = false;
do {
move = new Coordinate(x, y, z);
success = board.isSquareBlank(move);
if (!success) {
System.out.println("Invalid move. Try again.");
return playerMove(board, scanner, playerTile);
}
} while (!success);
board = board.move(move, playerTile);
board.print();
System.out.println(playerTile + " moved " + move);
return board;
}
}