-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathBoard.java
232 lines (179 loc) · 6.07 KB
/
Board.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
//Board classes by Richard Paige, 2019.
public class Board {
public static enum Mark {
X("X") { public Mark other() { return O; }},
O("O") { public Mark other() { return X; }},
BLANK(".");
private String image;
private Mark(String image) {
this.image = image;
}
public String toString() {
return image;
}
public Mark other() {
return null;
}
}
public long x; // Positions of the X's
public long o; // Positions of the O's
public Board() {
this.x = 0;
this.o = 0;
}
public Board(Board board) { // Copy constructor
this.x = board.x;
this.o = board.o;
}
public Board(String s) { // Inverse of toString()
this.x = 0;
this.o = 0;
int position = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch(c) {
case '.':
this.set(position, Mark.BLANK);
position++;
break;
case 'x':
case 'X':
this.set(position, Mark.X);
position++;
break;
case 'o':
case 'O':
this.set(position, Mark.O);
position++;
break;
case ' ': // Row divider
case '|': // Level divider
break;
default:
throw new IllegalArgumentException("Bad board marker: " + c);
}
}
}
// Selector/settor methods to determine/alter the contents of a board position.
public boolean isEmpty(int position) {
return ! Positions.contains(this.x | this.o, position);
}
public boolean isEmpty(int x, int y, int z) {
return isEmpty(Position.position(x, y, z));
}
public Mark get(int position) {
if (Positions.contains(this.x, position)) return Mark.X;
if (Positions.contains(this.o, position)) return Mark.O;
return Mark.BLANK;
}
public Mark get(int x, int y, int z) {
return get(Position.position(x, y, z));
}
public void set(int position, Mark mark) {
switch (mark) {
case X:
this.x = Positions.add(this.x, position);
this.o = Positions.remove(this.o, position);
break;
case O:
this.x = Positions.remove(this.x, position);
this.o = Positions.add(this.o, position);
break;
case BLANK:
this.x = Positions.remove(this.x, position);
this.o = Positions.remove(this.o, position);
break;
default:
throw new IllegalArgumentException(mark.toString());
}
}
public void set(int x, int y, int z, Mark mark) {
set(Position.position(x, y, z), mark);
}
public void clear(int position) {
this.x = Positions.remove(this.x, position);
this.o = Positions.remove(this.o, position);
}
public void clear(int x, int y, int z) {
clear(Position.position(x, y, z));
}
public int occupied(long positions, Mark player) {
// Returns the number of positions occupied by the specified
// player within a given set of board positions. Useful
// when combined with the Lines class to determine the
// number of markers along given line.
switch (player) {
case X: return Positions.count(this.x & positions);
case O: return Positions.count(this.o & positions);
case BLANK: return Positions.count (~(this.x | this.o) & positions);
default: throw new IllegalArgumentException(player.toString());
}
}
public boolean hasWon(Board.Mark mark) {
for (Line line : Line.lines()) {
if(occupied(line.positions(), mark) == 4) return true;
}
return false;
}
public boolean isFull() {
return ~(this.x | this.o) == 0;
}
// Matching equality and hashCode methods.
public boolean equals(Board other) {
return this.x == other.x && this.o == other.o;
}
@Override
public boolean equals(Object other) {
return other instanceof Board && equals((Board) other);
}
@Override
public int hashCode() {
return ((Long) this.x).hashCode() + ((Long) this.o).hashCode();
}
// toString produces a string that can be passed to the constructor.
@Override
public String toString() {
String result = "";
for (int position = 0; position < 64; position++) {
if (position > 0) {
if (position % 16 == 0) { // New level
result += '|';
} else if (position % 4 == 0) {
result += ' '; // New row
}
}
result += get(position);
}
return result;
}
// A more readable display of the 3D tic tac toe board.
public void print() {
System.out.println();
for (int level = 0; level < 4; level++) {
System.out.print(" Z = " + level + " ");
}
System.out.println();
for (int row = 3; row >= 0; row--) {
for (int level = 0; level < 4; level++) {
for (int column = 0; column < 4; column++) {
System.out.print(get(column, row, level));
System.out.print(" ");
}
System.out.print(" ");
}
System.out.println();
}
System.out.println();
}
//heuristic by Viansa S.
public int heuristic(Mark mark) {
Board.Mark other = mark.other();
int count = 0;
for (Line l : Line.lines()) {
if (occupied(l.positions(), other) == 0) {
count += occupied(l.positions(), mark);
}
}
return count;
}
}