我正在尝试使用 OOP 在 java 中创建 Othello AI。我正在使用对象“板”,在这个对象中,我试图创建一个包含所有“孩子”的 ArrayList,其中每个孩子都是板的克隆,其中一个合法的动作 - 我正在努力解决这个问题。我在 board.java 的 addChild 类中遇到的一个问题是每次调用 addChild 时都尝试创建一个新板,我不确定如何执行此操作。目前,每一个合法的动作都被应用于一个名为 child 的棋盘,这是 children ArrayList 中唯一的棋盘。任何帮助将非常感激。
另外,我想知道 Minimax 的最佳方法,我的想法是从当前棋盘遍历游戏树,进入孩子,直到我碰到一个叶子(所选棋盘没有孩子),通过对这个叶子的评估将叶子与其所有兄弟节点进行比较,然后将父节点与其所有兄弟节点进行比较,依此类推。
谢谢,斯图尔特
MiniMax.java
package com.company.Minimax;
import com.company.Main;
import com.company.othello.board;
import com.company.othello.gameHandler;
import java.util.ArrayList;
import java.util.Random;
public class MiniMax {
//tile types
public static int[][] corners = {{0, 0}, {0, 7}, {7, 0}, {7, 7}};
public static int[][] cornerBuffers = {{0, 1}, {0, 6}, {1, 0}, {1, 1},{1, 6}, {1, 7}, {6, 0},{6, 1}, {6, 6}, {6, 7}, {7, 1}, {7, 6}};
public static int[][] edges = {{2, 0},{3, 0},{4, 0},{5, 0},{0, 2},{0, 3},{0, 4},{0, 5}, {7, 2},{7, 3},{7, 4},{7, 5},{2, 7},{3, 7},{4, 7},{5, 7}};
public static int[][] edgeBuffers = {{2, 1},{3, 1},{4, 1},{5, 1}, {1, 2},{1, 3},{1, 4},{1, 5}, {6, 2},{6, 3},{6, 4},{6, 5}, {2, 6},{3, 6},{4, 6},{5, 6}};
//need to swap between user turn and AI turn. when its not user turn say "not your turn" when click
public static void Random(){
// try{
// System.out.println("sleep here");
// Thread.sleep(2000);
// }
// catch(InterruptedException ex){
// Thread.currentThread().interrupt();
// }
System.out.println("in random");
ArrayList<int[]> legalMoves;
legalMoves = gameHandler.potentialMovesList();
System.out.println("-----legal moves list-----");
for (int[] i : legalMoves) {
System.out.println(i[0] + " " + i[1]);
}
System.out.println("-------------------------");
//selects a random legal move from the list of legal moves
Random rand = new Random(); //instance of random class
int upperbound = legalMoves.size();
int int_random = rand.nextInt(upperbound);
int[] coords = legalMoves.get(int_random);
int x = coords[0];
int y = coords[1];
System.out.println("random move select");
System.out.println(x);
System.out.println(y);
System.out.println("------");
Main.grid.setMove(new int[]{x, y}, 'w'); //need to change this from 'w' hardcoded to whichever AIs turn it is (both could be ai)
Main.blackTurn = false; //set it to be white turn
gameHandler.flipDiscs('w','b',x,y, Main.grid.getBoard());
Main.blackTurn = !Main.blackTurn; //swap back to black (player) turn
}
public static void minimax(){
ArrayList<int[]> legalMoves;
legalMoves = gameHandler.potentialMovesList();
int min = -1000;
int max = 1000;
System.out.println("-----legal moves list-----");
char disc;
if (Main.blackTurn = true){
disc = 'b';
}
else {
disc = 'w';
}
int count = 0;
for (int[] i : legalMoves) {
System.out.println(i[0] + " " + i[1]);
board.addChild(Main.grid, i, disc, count);
count++;
}
System.out.println("-------------------------");
System.out.println("----------children list-----------");
for (int x = 0; x < board.getChildren().size(); x++){
System.out.println(board.getChildren().get(x));
}
System.out.println("-------------------------");
System.out.println("-----------list scores----------");
int maxIndex = 0;
int maxBoardVal = 0;
for (int i =0; i < board.getChildren().size() ; i++){
if (board.getChildren().get(i).getBoardVal() > maxBoardVal){
maxBoardVal = board.getChildren().get(i).getBoardVal();
maxIndex = i;
}
System.out.println(board.getChildren().get(i).getBoardVal()); //children only has 1 item in currently
}
System.out.println("-------------------------");
int[] coord = legalMoves.get(maxIndex);
int x = coord[0];
int y = coord[1];
System.out.println("minimax move select");
System.out.println(x);
System.out.println(y);
System.out.println("------");
Main.grid.setMove(new int[]{x, y}, 'w'); //need to change this from 'w' hardcoded to whichever AIs turn it is (both could be ai)
System.out.println("pick: " + x + " " + y);
Main.blackTurn = false; //set it to be white turn
gameHandler.flipDiscs('w','b',x,y, Main.grid.getBoard());
Main.blackTurn = !Main.blackTurn; //swap back to black (player) turn
//(this is only for one depth), for multiple depth we need to then make a list of all moves
//from each next ply (after accouting for every move that the opposite colour could make)
}
public static int evalFunction(board board, boolean blackTurn){
//number of black vs white
int[] scores = board.getScore(board);
int blackScore = scores[0];
int whiteScore = scores[1];
if (blackTurn = true){
return blackScore - whiteScore;
}
else {
return whiteScore - blackScore;
}
//do player score - opposite score, higher is better. (min will be better for min player)
//combined weight of pieces on board with weights of regions
//called priorityBoard?
// https://github.com/codelucas/OthelloAI/blob/master/src/OthelloAI27404511.java
//mobility how many legal moves there is
}
}
板子.java
package com.company.othello;
import com.company.Main;
import com.company.Minimax.MiniMax;
import java.util.ArrayList;
public class board {
private static char disc;
private static char[][] gameboard;
private static boolean blackTurn;
private static ArrayList<board> children;
private static int boardEval;
//private static board[] children;
//depth 0 = Main.grid
//depth 1 = Main.grid with a move made
//to make child boards (pass the current board, the turn and the move to make
public board(boolean blackTurnIn, char[][] board, int[][] move){
char[][] gameboard;
gameboard = board;
blackTurn = blackTurnIn;
if (blackTurn = true){
disc = 'b';
}
else {
disc = 'w';
}
gameboard[move[1][0]][move[0][1]] = disc;
//makes a new board that is the same as last gen, + the move that is made
}
//initializer to make first empty board
public board() {
gameboard = new char[8][8];
for (int i = 0; i < 8; i++){
for (int j = 0; j < 8; j++){
gameboard[i][j] = ' ';
}
}
}
public static void setGameboard(char[][] gameboard) {
board.gameboard = gameboard;
}
public static void setChildren(ArrayList<board> children) {
board.children = children;
}
public static ArrayList<board> getChildren(){
return children;
}
public char[][] getBoard(){
return gameboard;
}
public boolean getTurn(){
return blackTurn;
}
public static char getTile(int[] yo) {
char value = gameboard[yo[0]][yo[1]];
return value;
}
public static void setMove(int[] coord, char discColour){
gameboard[coord[0]][coord[1]] = discColour;
}
public static void printBoard(board grid){
//prints the logical grid in command line
for (int i =0; i< 8; i++){
for (int z =0; z< 8; z++){
System.out.print(grid.getBoard()[z][i]);
System.out.print("|");
}
System.out.println();
for (int q =0; q< 16; q++) {
System.out.print("-");
}
System.out.println();
}
System.out.println("end of grid");
}
public static void initialBoard(board grid){
for (int i = 0; i < 8; i++){
for (int j = 0; j < 8; j++){
int[] yo = {i, j};
board.setMove(yo, ' ');
}
}
board.setMove(new int[]{3, 3}, 'w');
board.setMove(new int[]{4, 3}, 'b');
board.setMove(new int[]{3, 4}, 'b');
board.setMove(new int[]{4, 4}, 'w');
}
public static int[] getScore(board board){
int blackScore = 0;
int whiteScore = 0;
for (int i = 0; i <= 7; i++){ //iterate over all tiles on board
for (int j = 0; j <= 7; j++) {
if (board.getTile(new int[]{i, j}) == 'b'){
blackScore++;
}
else if(board.getTile(new int[]{i, j}) == 'w'){
whiteScore++;
}
}
}
int score[] = {blackScore, whiteScore};
return score;
}
public static void addChild(board board, int[] move, char discColour, int count){
//public static void setMove(int[] coord, char discColour)
// ArrayList<board> childList = board.getChildren();
// board child = board; //clone current board
// child.setMove(move, discColour); //make the move on the child board
// child.setBoardVal(MiniMax.evalFunction(child, Main.blackTurn)); //set value of child
// childList.add(child); //add child to list
// board.setChildren(childList); //set global list to local list
board child = board;
ArrayList<board> children = new ArrayList<>();
child.setMove(move, discColour); //make the move on the child board
child.setBoardVal(MiniMax.evalFunction(board, Main.blackTurn)); //set value of child
child.printBoard(child);
children.add(child); //add child to list
board.setChildren(children); //set global list to local list
}
public static void setBoardVal(int boardVal){
boardEval = boardVal;
}
public static int getBoardVal(){
return boardEval;
}
}