-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTeamRational.java
executable file
·247 lines (206 loc) · 9.53 KB
/
TeamRational.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
import java.util.*;
public class TeamRational extends Player {
// A BoardPosition includes the piece positions, the number of moves played, and myColour.
// We attach to each one a Node: bestMove, scoreWhite, scoreBlack (assuming perfect play.)
public byte[] bestMoveBytes, scoreWhiteBytes, scoreBlackBytes;
int maxNumMoves; // Called GameLimit in the project specs; game cannot have more than this many moves.
private Random rand; // For choosing random moves
public int payoff1WW, payoff1WL, payoff1LW, payoff1LL, payoff2WW, payoff2WL, payoff2LW, payoff2LL;
/*These give the payoff table, according to this player's beliefs:
*
* P1\P2 | W | L |
* ---------------------------------------------------
* W | payoff1WW,payoff2WW | payoff1WL,payoff2WL |
* ---------------------------------------------------
* L | payoff1LW,payoff2LW | payoff1LL,payoff2LL |
* ---------------------------------------------------*/
public TeamRational(int maxNumMoves,
int payoff1WW, int payoff1WL,
int payoff1LW, int payoff1LL,
int payoff2WW, int payoff2WL,
int payoff2LW, int payoff2LL) {
this.maxNumMoves = maxNumMoves;
this.payoff1WW=payoff1WW; this.payoff1WL=payoff1WL;
this.payoff1LW=payoff1LW; this.payoff1LL=payoff1LL;
this.payoff2WW=payoff2WW; this.payoff2WL=payoff2WL;
this.payoff2LW=payoff2LW; this.payoff2LL=payoff2LL;
this.rand = new Random(System.currentTimeMillis());
this.bestMoveBytes = new byte[BoardPosition.MAX_INT];
for (int i=0; i<BoardPosition.MAX_INT; i++) {
this.bestMoveBytes[i]=Node.UNINITIALIZED;
}
this.scoreWhiteBytes = new byte[BoardPosition.MAX_INT];
this.scoreBlackBytes = new byte[BoardPosition.MAX_INT];
LinkedList<BoardPosition> allInitialBoardPositions = BoardPosition.getAllInitialBoardPositions();
for (BoardPosition boardPosition : allInitialBoardPositions) {
computeBestMove(boardPosition);
}
}
public TeamRational(int maxNumMoves) {
//Default's to the TeamRealist payoff table:
this(maxNumMoves, 2, 3, 0, 1, 2, 0, 3, 1);
}
public void prepareForSeries() {
}
public void prepareForMatch() {
}
public void receiveMatchOutcome(int matchOutcome) {
}
public MoveDescription chooseMove() {
BoardPosition boardPosition = toBoardPosition();
return new MoveDescription((int) bestMoveBytes[boardPosition.toInt()]);
}
//We attach a Node (bestMove,scoreWhite,scoreBlack) to a BoardPosition (piece locations, numMovesPlayed, myColour)
//which indicates that at perfect play, bestMove is allowed, and the scores will be as indicated.
private byte[] computeBestMove(BoardPosition boardPosition) {
int currentPositionInt = boardPosition.toInt();
if (this.bestMoveBytes[currentPositionInt] != Node.UNINITIALIZED) {
return new byte[] {this.bestMoveBytes[currentPositionInt],
this.scoreWhiteBytes[currentPositionInt],this.scoreBlackBytes[currentPositionInt]};
}
int currentPlayerColour = (boardPosition.numMovesPlayed % 2 == 0) ? WHITE : BLACK;
//Now setup the payoff table:
int[] payoffsWhiteWins, payoffsBlackWins, payoffsTie, payoffsDraw;
if (boardPosition.myColour==WHITE) { //If player 1 is white:
payoffsWhiteWins = new int[] {payoff1WL,payoff2WL};
payoffsBlackWins = new int[] {payoff1LW,payoff2LW};
payoffsTie = new int[] {payoff1WW,payoff2WW};
payoffsDraw = new int[] {payoff1LL,payoff2LL};
} else { //If player 1 is black:
payoffsWhiteWins = new int[] {payoff2LW,payoff1LW};
payoffsBlackWins = new int[] {payoff2WL,payoff1WL};
payoffsTie = new int[] {payoff2WW,payoff1WW};
payoffsDraw = new int[] {payoff2LL,payoff1LL};
}
Node returnNode = null; // Node to be returned by this function.
// ---> First we go through the cases where the game has ended:
if (boardPosition.whiteKingPosition == 0 && boardPosition.blackKingPosition == 0) {
// if both kings have been captured, the game has ended
returnNode = new Node(null, payoffsTie);
} else if (boardPosition.whiteKingPosition == 0 && currentPlayerColour == BLACK) {
// if white king has been captured and it's black player's turn, the
// game has ended black won
returnNode = new Node(null, payoffsBlackWins);
} else if (boardPosition.blackKingPosition == 0 && currentPlayerColour == WHITE) {
// if black king has been captured and it's white player's turn, the
// game has ended white won
returnNode = new Node(null, payoffsWhiteWins);
} else if (currentPlayerColour == WHITE && boardPosition.whiteKingPosition == 0
&& boardPosition.whiteRookPosition == 0) {
// if it's white player's turn but he has no pieces left, the game
// has ended black won
returnNode = new Node(null, payoffsBlackWins);
} else if (currentPlayerColour == BLACK && boardPosition.blackKingPosition == 0
&& boardPosition.blackRookPosition == 0) {
// if it's black player's turn but he has no pieces left, the game
// has ended white won
returnNode = new Node(null, payoffsWhiteWins);
} else if (boardPosition.numMovesPlayed >= maxNumMoves) {
// if we have reached the maximum number of moves, the game is over
if (boardPosition.whiteKingPosition != 0 && boardPosition.blackKingPosition != 0) {
// draw
returnNode = new Node(null, payoffsDraw);
} else if (boardPosition.blackKingPosition == 0) {
// white won
returnNode = new Node(null, payoffsWhiteWins);
} else {
// !whiteKingRemains
// black won
returnNode = new Node(null, payoffsBlackWins);
}
} else {
// ---> Otherwise, the game has not ended and we explore all possible moves:
ArrayList<MoveDescription> allPossibleMoves = boardPosition.getAllPossibleMoves();
// Explore the moves one by one, keeping track of best achievable score:
int bestScore = 0;
// As well as all Nodes that achieve that score:
ArrayList<Node> allBestNodes = new ArrayList<Node>();
for (MoveDescription moveDescription : allPossibleMoves) {
BoardPosition newBoardPosition = boardPosition.doMove(moveDescription);
Node node = new Node(computeBestMove(newBoardPosition)); // Recursion!
if (allBestNodes.size() == 0) {
// First move is always the best so far:
bestScore = node.getScore(currentPlayerColour);
allBestNodes.add(new Node(moveDescription, node.getScore(WHITE), node.getScore(BLACK)));
} else if (node.getScore(currentPlayerColour) == bestScore) {
// If current move is as good as our best so far, add it to the list:
allBestNodes.add(new Node(moveDescription, node.getScore(WHITE), node.getScore(BLACK)));
} else if (node.getScore(currentPlayerColour) > bestScore) {
// If current move is better than our best so far, wipe the list and add current move:
bestScore = node.getScore(currentPlayerColour);
allBestNodes = new ArrayList<Node>();
allBestNodes.add(new Node(moveDescription, node.getScore(WHITE), node.getScore(BLACK)));
}
}
// Choose a random move among the best available options:
returnNode = allBestNodes.get(rand.nextInt(allBestNodes.size()));
}
// Add results to our byte arrays:
byte [] nodeBytes = returnNode.toBytes();
bestMoveBytes[currentPositionInt] = nodeBytes[0];
scoreWhiteBytes[currentPositionInt] = nodeBytes[1];
scoreBlackBytes[currentPositionInt] = nodeBytes[2];
return nodeBytes;
}
public static class Node {
public static final int UNINITIALIZED = -2;
public static final int NULL = -1;
public MoveDescription bestMove;
public int scoreWhite, scoreBlack;
public Node(MoveDescription bestMove_, int scoreWhite_, int scoreBlack_) {
bestMove = bestMove_;
scoreWhite = scoreWhite_;
scoreBlack = scoreBlack_;
}
public Node(MoveDescription bestMove_, int[] score_) {
this(bestMove_, score_[WHITE], score_[BLACK]);
}
public int getScore(int colour) {
return (colour == WHITE) ? scoreWhite : scoreBlack;
}
public byte[] toBytes() {//encode a node as three bytes.
if (bestMove != null) {
return new byte[] {(byte) bestMove.toInt(), (byte) scoreWhite, (byte) scoreBlack};
} else {
return new byte[] {(byte) Node.NULL, (byte) scoreWhite, (byte) scoreBlack};
}
}
public Node(byte[] nodeBytes) {// decode array with three bytes into a node.
this(nodeBytes[0],nodeBytes[1],nodeBytes[2]);
}
public Node(byte bestMoveByte, byte scoreWhiteByte, byte scoreBlackByte) {
// decode three bytes into a node.
if (bestMoveByte==Node.NULL || bestMoveByte==Node.UNINITIALIZED) {
bestMove = null;
} else {
bestMove = new MoveDescription((int) bestMoveByte);
}
scoreWhite = (int) scoreWhiteByte;
scoreBlack = (int) scoreBlackByte;
}
}
public static TeamRational createOptimist(Integer maxNumMoves) {
return new TeamRational(maxNumMoves, 2, 3, 0, 1, 2, 3, 0, 1);
}
public static TeamRational createPessimist(Integer maxNumMoves) {
return new TeamRational(maxNumMoves, 2, 3, 0, 1, -2, -3, 0, -1);
}
public static TeamRational createQueller(Integer maxNumMoves) {
return new TeamRational(maxNumMoves, -2, 0, -3, -1, 2, 0, 3, 1);
}
public static TeamRational createRealist(Integer maxNumMoves) {
return new TeamRational(maxNumMoves, 2, 3, 0, 1, 2, 0, 3, 1);
}
public static TeamRational createScrapper(Integer maxNumMoves) {
return new TeamRational(maxNumMoves, -2, 0, -3, -1, -2, -3, 0, -1);
}
public static TeamRational createTruster(Integer maxNumMoves) {
return new TeamRational(maxNumMoves, 10, 9, 6, 5, 10, 6, 9, 5);
}
public static TeamRational createUtilitarian(Integer maxNumMoves) {
return new TeamRational(maxNumMoves, 4, 3, 3, 2, 4, 3, 3, 2);
}
public static TeamRational createCooperative(Integer maxNumMoves) {
return new TeamRational(maxNumMoves, 3, 2, 0, 1, 3, 0, 2, 1); //3 means WW
}
}