-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPlayer20220808025.java
133 lines (110 loc) · 4.44 KB
/
Player20220808025.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
package players;
import game.*;
import java.util.List;
import java.util.Random;
public class Player20220808025 extends Player {
private final int boardSize;
private final Random random;
// Parameters for Monte Carlo simulation
private static final int SIMULATION_COUNT = 5000;
// Parameters for Minimax algorithm
private final int SEARCH_DEPTH = 7;
private final int TIME_LIMIT_MS = 950; // 950ms time limit
public Player20220808025(Board board) {
super(board);
this.boardSize = board.getSize();
this.random = new Random();
}
@Override
public Move nextMove() {
if (boardSize <= 10) {
return monteCarloNextMove();
} else {
return minimaxNextMove();
}
}
private Move monteCarloNextMove() {
List<Move> possibleMoves = board.getPossibleMoves();
if (possibleMoves.isEmpty()) return null;
Move bestMove = null;
double bestScore = -1;
for (Move move : possibleMoves) {
double averageScore = simulateMove(move);
if (averageScore > bestScore) {
bestScore = averageScore;
bestMove = move;
}
}
return bestMove;
}
private double simulateMove(Move move) {
double totalScore = 0;
for (int i = 0; i < SIMULATION_COUNT; i++) {
Board simulationBoard = new Board(board);
simulationBoard.applyMove(move);
totalScore += simulateGame(simulationBoard);
}
return totalScore / SIMULATION_COUNT;
}
private double simulateGame(Board simulationBoard) {
while (!simulationBoard.isGameOver()) {
List<Move> possibleMoves = simulationBoard.getPossibleMoves();
if (possibleMoves.isEmpty()) break;
Move randomMove = possibleMoves.get(random.nextInt(possibleMoves.size()));
simulationBoard.applyMove(randomMove);
}
return simulationBoard.getScore();
}
private Move minimaxNextMove() {
long startTime = System.currentTimeMillis();
List<Move> possibleMoves = board.getPossibleMoves();
if (possibleMoves.isEmpty()) return null;
Move bestMove = null;
int bestValue = Integer.MIN_VALUE;
for (Move move : possibleMoves) {
if (System.currentTimeMillis() - startTime >= TIME_LIMIT_MS) {
break; // If time limit is exceeded, return the best move found so far
}
// Create a copy of the board state and apply the move
Board simulatedBoard = new Board(board);
if (!simulatedBoard.applyMove(move)) continue;
int val = minimax(simulatedBoard, SEARCH_DEPTH, move, startTime);
// Penalize moves that are close to the board edge
int newRow = board.getPlayerRow() + move.getDRow();
int newCol = board.getPlayerCol() + move.getDCol();
int boardSize = board.getSize();
if (newRow < 2 || newRow > boardSize - 3 || newCol < 2 || newCol > boardSize - 3) {
val -= 5;
}
if (val > bestValue) {
bestValue = val;
bestMove = move;
}
}
return bestMove;
}
private int minimax(Board boardState, int depth, Move previousMove, long startTime) {
if (depth == 0 || boardState.isGameOver() || System.currentTimeMillis() - startTime >= TIME_LIMIT_MS) {
return evaluateBoard(boardState);
}
int best = Integer.MIN_VALUE;
List<Move> moves = boardState.getPossibleMoves();
for (Move move : moves) {
Board newBoard = new Board(boardState);
if (!newBoard.applyMove(move)) continue;
int score = minimax(newBoard, depth - 1, move, startTime);
if (previousMove != null && isReverse(previousMove, move)) {
score -= 10;
}
best = Math.max(best, score);
}
best += boardState.getPossibleMoves().size();
return best;
}
private int evaluateBoard(Board boardState) {
return boardState.getScore() + 2 * boardState.getPossibleMoves().size();
}
private boolean isReverse(Move m1, Move m2) {
return m1.getDRow() == -m2.getDRow() && m1.getDCol() == -m2.getDCol();
}
}