package com.first.gobang.ai;
import com.first.gobang.interAndEnum.GobangAI;
import com.first.gobang.tools.BoardEvaluator;
public class EasyAI implements GobangAI {
private static final int BOARD_SIZE = 15;
private static final int EMPTY = 0;
private static final int BLACK = 1;
private static final int WHITE = 2;
@Override
public int[] makeMove(int[][] board, int currentPlayer) {
// 检查是否是游戏开始的第一步(玩家先手,电脑后手)
if (isBoardEmpty(board)) {
// 如果棋盘为空,玩家先手,电脑暂未落子,此时不需要电脑落子
return null;
}
// 检查是否是电脑的第一回合出手(玩家先手,电脑后手)
boolean isComputerFirstMove = checkComputerFirstMove(board, currentPlayer);
if (isComputerFirstMove) {
// 电脑的第一回合出手,根据玩家的第一步位置选择一个相对中心的位置
int[] playerFirstMove = findPlayerFirstMove(board, currentPlayer);
if (playerFirstMove != null) {
int playerX = playerFirstMove[0];
int playerY = playerFirstMove[1];
// 根据玩家的第一步位置选择一个相对中心的位置
int centerX = BOARD_SIZE / 2;
int centerY = BOARD_SIZE / 2;
int computerX = centerX;
int computerY = centerY;
// 如果玩家的第一步在中心附近,电脑选择一个相邻的空位
if (Math.abs(playerX - centerX) <= 1 && Math.abs(playerY - centerY) <= 1) {
int[][] directions = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
for (int[] dir : directions) {
int newX = centerX + dir[0];
int newY = centerY + dir[1];
if (newX >= 0 && newX < BOARD_SIZE && newY >= 0 && newY < BOARD_SIZE && board[newX][newY] == EMPTY) {
computerX = newX;
computerY = newY;
break;
}
}
}
System.out.println("AI选择相对中心的位置作为第一步: (" + computerX + ", " + computerY + ")");
return new int[]{computerX, computerY};
}
}
// 检查是否能直接获胜
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] != EMPTY) continue;
board[i][j] = currentPlayer;
if (BoardEvaluator.checkWin(board, i, j)) {
board[i][j] = EMPTY;
System.out.println("AI检测到可以获胜,选择位置: (" + i + ", " + j + ")");
return new int[]{i, j};
}
board[i][j] = EMPTY;
}
}
// 检查是否需要阻止对手获胜
int opponent = currentPlayer == BLACK ? WHITE : BLACK;
int[] defensiveMove = BoardEvaluator.findBestDefensiveMove(board, opponent);
if (defensiveMove != null) {
System.out.println("AI检测到需要防守,选择位置: (" + defensiveMove[0] + ", " + defensiveMove[1] + ")");
return defensiveMove;
}
// 使用 evaluateBoard 方法评估棋盘并选择最佳位置
return selectBalancedMove(board, currentPlayer);
}
private boolean checkComputerFirstMove(int[][] board, int currentPlayer) {
int count = 0;
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] != EMPTY) count++;
}
}
// 检查是否是电脑的第一回合出手(玩家先手,棋盘上有一个玩家的棋子)
return count == 1;
}
private int[] findPlayerFirstMove(int[][] board, int currentPlayer) {
int opponent = currentPlayer == BLACK ? WHITE : BLACK;
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] == opponent) {
return new int[]{i, j};
}
}
}
return null;
}
private boolean isBoardEmpty(int[][] board) {
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] != EMPTY) {
return false;
}
}
}
return true;
}
private int[] selectBalancedMove(int[][] board, int currentPlayer) {
int highestScore = Integer.MIN_VALUE;
int[] bestMove = null;
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] == EMPTY) {
board[i][j] = currentPlayer;
int offensiveScore = evaluateOffensivePotential(board, i, j, currentPlayer);
int defensiveScore = evaluateDefensivePotential(board, i, j, currentPlayer);
int totalScore = offensiveScore + defensiveScore;
board[i][j] = EMPTY;
if (totalScore > highestScore) {
highestScore = totalScore;
bestMove = new int[]{i, j};
}
}
}
}
if (bestMove != null) {
System.out.println("AI选择进攻和防守平衡的位置: (" + bestMove[0] + ", " + bestMove[1] + ")");
} else {
System.out.println("AI未找到合适位置,返回中心点");
}
return bestMove != null ? bestMove : new int[]{BOARD_SIZE / 2, BOARD_SIZE / 2};
}
private int evaluateOffensivePotential(int[][] board, int x, int y, int player) {
return BoardEvaluator.evaluateBoard(board);
}
private int evaluateDefensivePotential(int[][] board, int x, int y, int player) {
int opponent = player == BLACK ? WHITE : BLACK;
board[x][y] = opponent;
int score = BoardEvaluator.evaluateBoard(board);
board[x][y] = EMPTY;
return score;
}
}package com.first.gobang.ai;
import com.first.gobang.interAndEnum.GobangAI;
import com.first.gobang.tools.BoardEvaluator;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.PriorityQueue;
public class HardAI implements GobangAI {
private static final int BOARD_SIZE = 15;
private static final int EMPTY = 0;
private static final int SEARCH_DEPTH = 3;
private final Random random = new Random();
private static final int[][][] DIRECTION_OFFSETS = {{{0, 1}, {0, -1}}, {{1, 0}, {-1, 0}}, {{1, 1}, {-1, -1}}, {{1, -1}, {-1, 1}}};
@Override
public int[] makeMove(int[][] board, int currentPlayer) {
long startTime = System.currentTimeMillis();
int[] instantMove = checkInstantWinOrBlock(board, currentPlayer);
if (instantMove != null) return instantMove;
List<int[]> candidates = getSmartCandidates(board, 2);
PriorityQueue<ScoredMove> moveQueue = new PriorityQueue<>((a, b) -> b.score - a.score);
for (int[] move : candidates) {
int x = move[0], y = move[1];
board[x][y] = currentPlayer;
int score = fastEvaluate(board, currentPlayer, x, y);
board[x][y] = EMPTY;
moveQueue.add(new ScoredMove(move, score));
}
int[] bestMove = candidates.get(0);
int maxScore = Integer.MIN_VALUE;
int topN = Math.min(3, moveQueue.size());
for (int i = 0; i < topN; i++) {
ScoredMove sm = moveQueue.poll();
int[] move = sm.move;
board[move[0]][move[1]] = currentPlayer;
int score = minimax(board, SEARCH_DEPTH, Integer.MIN_VALUE, Integer.MAX_VALUE, false, currentPlayer);
board[move[0]][move[1]] = EMPTY;
if (score > maxScore) {
maxScore = score;
bestMove = move;
}
}
System.out.println("AI思考时间: " + (System.currentTimeMillis() - startTime) + "ms");
return bestMove;
}
private int[] checkInstantWinOrBlock(int[][] board, int player) {
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] != EMPTY) continue;
board[i][j] = player;
if (BoardEvaluator.checkWin(board, i, j)) {
board[i][j] = EMPTY;
return new int[]{i, j};
}
board[i][j] = EMPTY;
}
}
int[] defensiveMove = BoardEvaluator.findBestDefensiveMove(board, player == 1 ? 2 : 1);
if (defensiveMove != null) {
return defensiveMove;
}
return null;
}
private List<int[]> getSmartCandidates(int[][] board, int radius) {
List<int[]> candidates = new ArrayList<>();
boolean[][] visited = new boolean[BOARD_SIZE][BOARD_SIZE];
if (isBoardEmpty(board)) {
candidates.add(new int[]{7, 7});
return candidates;
}
for (int x = 0; x < BOARD_SIZE; x++) {
for (int y = 0; y < BOARD_SIZE; y++) {
if (board[x][y] != EMPTY) {
for (int i = Math.max(0, x - radius); i <= Math.min(BOARD_SIZE - 1, x + radius); i++) {
for (int j = Math.max(0, y - radius); j <= Math.min(BOARD_SIZE - 1, y + radius); j++) {
if (board[i][j] == EMPTY && !visited[i][j]) {
visited[i][j] = true;
candidates.add(new int[]{i, j});
}
}
}
}
}
}
return candidates;
}
private int fastEvaluate(int[][] board, int player, int x, int y) {
int score = 0;
int opponent = player == 1 ? 2 : 1;
for (int[][] directions : DIRECTION_OFFSETS) {
int playerCount = 1;
boolean playerBlocked = false;
for (int[] dir : directions) {
for (int i = 1; i <= 4; i++) {
int nx = x + dir[0] * i;
int ny = y + dir[1] * i;
if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) {
playerBlocked = true;
break;
}
if (board[nx][ny] == player) playerCount++;
else if (board[nx][ny] == opponent) {
playerBlocked = true;
break;
}
}
}
if (playerCount >= 5) score += 100000;
else if (playerCount == 4) score += playerBlocked ? 500 : 2000;
else if (playerCount == 3) score += playerBlocked ? 30 : 200;
}
return score + (10 - Math.abs(x - 7) - Math.abs(y - 7));
}
private int minimax(int[][] board, int depth, int alpha, int beta, boolean isMax, int player) {
if (depth == 0) {
return BoardEvaluator.evaluateBoard(board);
}
List<int[]> candidates = getSmartCandidates(board, 2);
int bestValue = isMax ? Integer.MIN_VALUE : Integer.MAX_VALUE;
for (int[] move : candidates) {
int x = move[0], y = move[1];
board[x][y] = isMax ? player : (player == 1 ? 2 : 1);
int value = minimax(board, depth - 1, alpha, beta, !isMax, player);
board[x][y] = EMPTY;
if (isMax) {
bestValue = Math.max(bestValue, value);
alpha = Math.max(alpha, bestValue);
} else {
bestValue = Math.min(bestValue, value);
beta = Math.min(beta, bestValue);
}
if (beta <= alpha) break;
}
return bestValue;
}
private boolean isBoardEmpty(int[][] board) {
for (int[] row : board) {
for (int cell : row) {
if (cell != EMPTY) return false;
}
}
return true;
}
private static class ScoredMove {
int[] move;
int score;
ScoredMove(int[] move, int score) {
this.move = move;
this.score = score;
}
}
}package com.first.gobang.ai;
import com.first.gobang.interAndEnum.GobangAI;
import com.first.gobang.interAndEnum.ThreatType;
import com.first.gobang.tools.BoardEvaluator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MediumAI implements GobangAI {
private static final int BOARD_SIZE = 15;
private static final int EMPTY = 0;
private static final int BLACK = 1;
private static final int WHITE = 2;
@Override
public int[] makeMove(int[][] board, int currentPlayer) {
// 检查是否是游戏开始的第一步(玩家先手,电脑后手)
if (isBoardEmpty(board)) {
// 如果棋盘为空,玩家先手,电脑暂未落子,此时不需要电脑落子
return null;
}
// 检查是否是电脑的第一回合出手(玩家先手,电脑后手)
boolean isComputerFirstMove = checkComputerFirstMove(board, currentPlayer);
if (isComputerFirstMove) {
// 电脑的第一回合出手,根据玩家的第一步位置选择一个相对中心的位置
int[] playerFirstMove = findPlayerFirstMove(board, currentPlayer);
if (playerFirstMove != null) {
int playerX = playerFirstMove[0];
int playerY = playerFirstMove[1];
// 根据玩家的第一步位置选择一个相对中心的位置
int centerX = BOARD_SIZE / 2;
int centerY = BOARD_SIZE / 2;
int computerX = centerX;
int computerY = centerY;
// 如果玩家的第一步在中心附近,电脑选择一个相邻的空位
if (Math.abs(playerX - centerX) <= 1 && Math.abs(playerY - centerY) <= 1) {
int[][] directions = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
for (int[] dir : directions) {
int newX = centerX + dir[0];
int newY = centerY + dir[1];
if (newX >= 0 && newX < BOARD_SIZE && newY >= 0 && newY < BOARD_SIZE && board[newX][newY] == EMPTY) {
computerX = newX;
computerY = newY;
break;
}
}
}
System.out.println("AI选择相对中心的位置作为第一步: (" + computerX + ", " + computerY + ")");
return new int[]{computerX, computerY};
}
}
// 检查是否能直接获胜
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] != EMPTY) continue;
board[i][j] = currentPlayer;
if (BoardEvaluator.checkWin(board, i, j)) {
board[i][j] = EMPTY;
System.out.println("AI检测到可以获胜,选择位置: (" + i + ", " + j + ")");
return new int[]{i, j};
}
board[i][j] = EMPTY;
}
}
// 检查是否需要阻止对手获胜
int opponent = currentPlayer == BLACK ? WHITE : BLACK;
int[] defensiveMove = BoardEvaluator.findBestDefensiveMove(board, opponent);
if (defensiveMove != null) {
System.out.println("AI检测到需要防守,选择位置: (" + defensiveMove[0] + ", " + defensiveMove[1] + ")");
return defensiveMove;
}
// 使用 evaluateBoard 方法评估棋盘并选择最佳位置
return selectBalancedMove(board, currentPlayer);
}
private boolean checkComputerFirstMove(int[][] board, int currentPlayer) {
int count = 0;
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] != EMPTY) count++;
}
}
// 检查是否是电脑的第一回合出手(玩家先手,棋盘上有一个玩家的棋子)
return count == 1;
}
private int[] findPlayerFirstMove(int[][] board, int currentPlayer) {
int opponent = currentPlayer == BLACK ? WHITE : BLACK;
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] == opponent) {
return new int[]{i, j};
}
}
}
return null;
}
private boolean isBoardEmpty(int[][] board) {
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] != EMPTY) {
return false;
}
}
}
return true;
}
private int[] selectBalancedMove(int[][] board, int currentPlayer) {
int highestScore = Integer.MIN_VALUE;
int[] bestMove = null;
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] == EMPTY) {
board[i][j] = currentPlayer;
int offensiveScore = evaluateOffensivePotential(board, i, j, currentPlayer);
int defensiveScore = evaluateDefensivePotential(board, i, j, currentPlayer);
int totalScore = offensiveScore + defensiveScore;
board[i][j] = EMPTY;
if (totalScore > highestScore) {
highestScore = totalScore;
bestMove = new int[]{i, j};
}
}
}
}
if (bestMove != null) {
System.out.println("AI选择进攻和防守平衡的位置: (" + bestMove[0] + ", " + bestMove[1] + ")");
} else {
System.out.println("AI未找到合适位置,返回中心点");
}
return bestMove != null ? bestMove : new int[]{BOARD_SIZE / 2, BOARD_SIZE / 2};
}
private int evaluateOffensivePotential(int[][] board, int x, int y, int player) {
return BoardEvaluator.evaluateBoard(board);
}
private int evaluateDefensivePotential(int[][] board, int x, int y, int player) {
int opponent = player == BLACK ? WHITE : BLACK;
board[x][y] = opponent;
int score = BoardEvaluator.evaluateBoard(board);
board[x][y] = EMPTY;
return score;
}
private int[] findThreatMove(int[][] board, int player) {
Map<ThreatType, List<int[]>> threatMoves = new HashMap<>();
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] != EMPTY) continue;
board[i][j] = player;
ThreatType threat = BoardEvaluator.evaluateThreat(board, i, j, player);
board[i][j] = EMPTY;
if (threat != ThreatType.NONE) {
threatMoves.computeIfAbsent(threat, k -> new ArrayList<>()).add(new int[]{i, j});
}
}
}
if (threatMoves.containsKey(ThreatType.WIN)) {
return threatMoves.get(ThreatType.WIN).get(0);
}
if (threatMoves.containsKey(ThreatType.OPEN_FOUR)) {
return threatMoves.get(ThreatType.OPEN_FOUR).get(0);
}
if (threatMoves.containsKey(ThreatType.OPEN_THREE)) {
return threatMoves.get(ThreatType.OPEN_THREE).get(0);
}
return null;
}
}package com.first.gobang.tools;
import com.first.gobang.interAndEnum.ThreatType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BoardEvaluator {
private static final int BOARD_SIZE = 15;
private static final int EMPTY = 0;
private static final int BLACK = 1;
private static final int WHITE = 2;
public static int evaluateBoard(int[][] board) {
int score = 0;
int centerBonus = 7; // 中心位置加成
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] == EMPTY) continue;
int player = board[i][j];
int[][] dirs = {{1, 0}, {0, 1}, {1, 1}, {1, -1}};
for (int[] dir : dirs) {
int count = 1;
boolean blocked = false;
for (int k = 1; k < 5; k++) {
int ni = i + dir[0] * k;
int nj = j + dir[1] * k;
if (ni < 0 || ni >= BOARD_SIZE || nj < 0 || nj >= BOARD_SIZE) {
blocked = true;
break;
}
if (board[ni][nj] == player) {
count++;
} else if (board[ni][nj] != EMPTY) {
blocked = true;
break;
}
}
if (count >= 5) {
return player == WHITE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
int value = 0;
if (count == 4) {
value = blocked ? 100 : 1000;
} else if (count == 3) {
value = blocked ? 10 : 100;
} else if (count == 2) {
value = blocked ? 1 : 10;
}
// 添加中心位置加成
value += 10 - Math.abs(i - centerBonus) - Math.abs(j - centerBonus);
score += player == WHITE ? value : -value;
}
}
}
return score;
}
public static boolean checkWin(int[][] board, int x, int y) {
if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE || board[x][y] == EMPTY) {
return false;
}
int player = board[x][y];
int[][][] dirPatterns = {{{-1, 0}, {1, 0}}, {{0, -1}, {0, 1}}, {{-1, -1}, {1, 1}}, {{-1, 1}, {1, -1}}};
for (int[][] pattern : dirPatterns) {
int count = 1;
for (int[] dir : pattern) {
int nx = x + dir[0];
int ny = y + dir[1];
while (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE && board[nx][ny] == player) {
count++;
if (count >= 5) {
return true;
}
nx += dir[0];
ny += dir[1];
}
}
}
return false;
}
public static int[] findBestDefensiveMove(int[][] board, int opponent) {
Map<ThreatType, List<int[]>> threatMoves = new HashMap<>();
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j] != EMPTY) continue;
board[i][j] = opponent;
ThreatType threat = evaluateThreat(board, i, j, opponent);
board[i][j] = EMPTY;
if (threat != ThreatType.NONE) {
threatMoves.computeIfAbsent(threat, k -> new ArrayList<>()).add(new int[]{i, j});
}
}
}
if (threatMoves.containsKey(ThreatType.WIN)) {
return threatMoves.get(ThreatType.WIN).get(0);
}
if (threatMoves.containsKey(ThreatType.OPEN_FOUR)) {
return threatMoves.get(ThreatType.OPEN_FOUR).get(0);
}
if (threatMoves.containsKey(ThreatType.CLOSED_FOUR)) {
return threatMoves.get(ThreatType.CLOSED_FOUR).get(0);
}
if (threatMoves.containsKey(ThreatType.OPEN_THREE)) {
return threatMoves.get(ThreatType.OPEN_THREE).get(0);
}
return null;
}
public static ThreatType evaluateThreat(int[][] board, int x, int y, int player) {
int[][] directions = {{1, 0}, {0, 1}, {1, 1}, {1, -1}};
int[] threatCount = new int[6];
int openThreats = 0;
for (int[] dir : directions) {
int len = getLineLength(board, x, y, dir, player);
int leftSpace = checkSpace(board, x, y, new int[]{-dir[0], -dir[1]}, player);
int rightSpace = checkSpace(board, x, y, dir, player);
int totalSpace = leftSpace + rightSpace + 1;
if (totalSpace < 5) continue;
if (len >= 5) {
return ThreatType.WIN;
} else if (len == 4) {
if (leftSpace > 0 && rightSpace > 0) {
openThreats++;
} else {
threatCount[4]++;
}
} else if (len == 3) {
if (leftSpace > 0 && rightSpace > 0) {
threatCount[3]++;
} else {
threatCount[3]++;
}
}
}
if (openThreats > 0) {
return ThreatType.OPEN_FOUR;
} else if (threatCount[4] > 0) {
return ThreatType.CLOSED_FOUR;
} else if (threatCount[3] >= 2) {
return ThreatType.OPEN_THREE;
}
return ThreatType.NONE;
}
private static int getLineLength(int[][] board, int x, int y, int[] dir, int player) {
int count = 1;
for (int step = 1; step <= 4; step++) {
int nx = x + dir[0] * step;
int ny = y + dir[1] * step;
if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) break;
if (board[nx][ny] == player) count++;
else break;
}
for (int step = 1; step <= 4; step++) {
int nx = x - dir[0] * step;
int ny = y - dir[1] * step;
if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) break;
if (board[nx][ny] == player) count++;
else break;
}
return count;
}
private static int checkSpace(int[][] board, int x, int y, int[] dir, int player) {
int space = 0;
for (int step = 1; step <= 4; step++) {
int nx = x + dir[0] * step;
int ny = y + dir[1] * step;
if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) break;
if (board[nx][ny] == EMPTY) {
space++;
} else if (board[nx][ny] == player) {
continue;
} else {
break;
}
}
return space;
}
}帮助我根据实际的开发和经验为我重构和优化这三个五子棋ai算法