package com.jn.rz.实验三;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* @author 江南大学1033190417
* @date 2022/5/5 10:42
*/
public class Status {
public char[][] status;
public Status(char[][] status) {
this.status = status;
}
//估价函数
public int f() {
//计算MAX所有赢线
int M = 0;
for (int i = 0; i < 3; i++) {
if (status[i][0] != 'O' && status[i][1] != 'O' && status[i][2] != 'O') {
++M;
}
if (status[0][i] != 'O' && status[1][i] != 'O' && status[2][i] != 'O') {
++M;
}
}
if (status[0][0] != 'O' && status[1][1] != 'O' && status[2][2] != 'O') {
++M;
}
if (status[0][2] != 'O' && status[1][1] != 'O' && status[2][0] != 'O') {
++M;
}
//计算MIN所有赢线
int O = 0;
for (int i = 0; i < 3; i++) {
if (status[i][0] != 'X' && status[i][1] != 'X' && status[i][2] != 'X') {
++O;
}
if (status[0][i] != 'X' && status[1][i] != 'X' && status[2][i] != 'X') {
++O;
}
}
if (status[0][0] != 'X' && status[1][1] != 'X' && status[2][2] != 'X') {
++O;
}
if (status[0][2] != 'X' && status[1][1] != 'X' && status[2][0] != 'X') {
++O;
}
return M - O;
}
//判断胜负
public boolean isWin(char temp) {
return ((status[0][0] == temp && status[0][1] == temp && status[0][2] == temp) ||
(status[1][0] == temp && status[1][1] == temp && status[1][2] == temp) ||
(status[2][0] == temp && status[2][1] == temp && status[2][2] == temp) ||
(status[0][0] == temp && status[1][0] == temp && status[2][0] == temp) ||
(status[0][1] == temp && status[1][1] == temp && status[2][1] == temp) ||
(status[0][2] == temp && status[1][2] == temp && status[2][2] == temp) ||
(status[0][0] == temp && status[1][1] == temp && status[2][2] == temp) ||
(status[0][2] == temp && status[1][1] == temp && status[2][0] == temp));
}
//判断赢家
public int winner() {
/*
当玩家先手时,max为玩家,所以返回1表示玩家赢,返回-1表示电脑赢,返回0表示平局或者还没结束;
当电脑先手时,max为电脑,所以返回1表示电脑赢,返回-1表示玩家赢,返回0表示平局或者还没结束。
*/
if ((isWin('O') && first == 1) || (isWin('X') && first == -1)) {
return 1;
} else if ((isWin('X') && first == 1) || (isWin('O') && first == -1)) {
return -1;
} else {
return 0;
}
}
//判断棋牌是否下满
public boolean isFull() {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (status[i][j] == '.')
return false;
}
}
return true;
}
/**
* 极小极大算法
* 通过递归,从叶子节点,推出父子节点(即往上推出)的值,该树的取值只有三种要么1,要么-1,要么0。
*
* @param player 当前玩家
* @param nextPlayer 下一个玩家
* @return
*/
public int maxMinSearch(char player, char nextPlayer) {
int maxVal = 2, minVal = 2;
int win = winner();
if (win != 0) {//如果是叶子结点
return win;
}
if (isFull()) {//如果下满没有赢家是平局
return 0;
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (status[i][j] == '.') {
status[i][j] = player;
int val = maxMinSearch(nextPlayer, player);
status[i][j] = '.';
if ((player == 'O' && first == 1) || (player == 'X' && first == -1)) {
if (maxVal < val)
maxVal = val;
} else if ((player == 'X' && first == 1) || (player == 'O' && first == -1)) {
if (minVal > val)
minVal = val;
}
}
}
}
int reval = 0;
if ((player == 'O' && first == 1) || (player == 'X' && first == -1)) {
reval = maxVal;
} else if ((player == 'X' && first == 1) || (player == 'O' && first == -1)) {
reval = minVal;
}
return reval;
}
/**
* alpha-beta算法
* @param player
* @param nextPlayer
* @param alpha -2
* @param beta 2
* @return
*/
public int alphaBetaSearch(char player,char nextPlayer,int alpha,int beta){
int win = winner();
if (win != 0) {//如果是叶子结点
return win;
}
if (isFull()) {//如果下满没有赢家是平局
return 0;
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (status[i][j] == '.') {
status[i][j] = player;
int val = alphaBetaSearch(nextPlayer, player,alpha,beta);
status[i][j] = '.';
if ((player == 'O' && first == 1) || (player == 'X' && first == -1)) {
if (alpha<val)
alpha=val;
else
return beta;
} else if ((player == 'X' && first == 1) || (player == 'O' && first == -1)) {
if (beta>val)
beta=val;
else
return alpha;
}
}
}
}
int reval = 0;
if ((player == 'O' && first == 1) || (player == 'X' && first == -1)) {
reval = alpha;
} else if ((player == 'X' && first == 1) || (player == 'O' && first == -1)) {
reval = beta;
}
return reval;
}
//玩家下棋
public void player() {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("输入要下的位置(0-8):");
int pos = scanner.nextInt();
int x = pos / 3;
int y = pos % 3;
if (status[x][y] == '.') {
status[x][y] = piece;
break;
} else {
System.out.println("该位置有棋子了,请重新输入!");
}
}
}
//电脑下棋,根据极小极大算法
public int computer() {
int bestVal = 2;//用来记录先手为玩家时,电脑取min时,能取的最小值
int bestVal2 = -2;//用来记录先手为电脑时,电脑取max时,能取的最大值
List<Integer> myMoves = new ArrayList<>();//记录电脑能做的位置
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (status[i][j] == '.') {
status[i][j] = comPiece;
int val = maxMinSearch(piece, comPiece);
status[i][j] = '.';
if (first == 1) {
if (val < bestVal) {
bestVal = val;
myMoves = new ArrayList<>();
myMoves.add(3 * i + j);
} else if (val == bestVal) {
myMoves.add(3 * i + j);
}
} else if (first == -1) {
if (val > bestVal2) {
bestVal2 = val;
myMoves = new ArrayList<>();
myMoves.add(3 * i + j);
} else if (val == bestVal2) {
myMoves.add(3 * i + j);
}
}
}
}
}
return myMoves.get((int) (Math.random() * (myMoves.size()) - 1));
}
//电脑下棋,根据alpha-beta算法
public int computer2() {
int bestVal = 2;//用来记录先手为玩家时,电脑取min时,能取的最小值
int bestVal2 = -2;//用来记录先手为电脑时,电脑取max时,能取的最大值
List<Integer> myMoves = new ArrayList<>();//记录电脑能做的位置
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (status[i][j] == '.') {
status[i][j] = comPiece;
int val = alphaBetaSearch(piece, comPiece,-2,2);
status[i][j] = '.';
if (first == 1) {
if (val < bestVal) {
bestVal = val;
myMoves = new ArrayList<>();
myMoves.add(3 * i + j);
} else if (val == bestVal) {
myMoves.add(3 * i + j);
}
} else if (first == -1) {
if (val > bestVal2) {
bestVal2 = val;
myMoves = new ArrayList<>();
myMoves.add(3 * i + j);
} else if (val == bestVal2) {
myMoves.add(3 * i + j);
}
}
}
}
}
return myMoves.get((int) (Math.random() * (myMoves.size()) - 1));
}
public void main(){
int nextMove = first;
while (!isFull() && winner() == 0) {
if (nextMove == 1 && !isFull()) {//玩家下
player();
print(status);
nextMove = -1;
}
if (nextMove == -1 && !isFull()) {//电脑下
int computer = computer2();
status[computer / 3][computer % 3] = comPiece;
System.out.println("电脑下的棋子");
print(status);
nextMove = 1;
}
}
printResult();
}
//答应输赢结果
public void printResult(){
if (first==1){
if (piece=='O'){
System.out.println(new String[]{"电脑赢了", "平局", "你赢了"}[winner() + 1]);
}else {
System.out.println(new String[]{"你赢了", "平局", "电脑赢了"}[winner() + 1]);
}
}else if (first==-1){
if (piece=='X'){
System.out.println(new String[]{"电脑赢了", "平局", "你赢了"}[winner() + 1]);
}else {
System.out.println(new String[]{"你赢了", "平局", "电脑赢了"}[winner() + 1]);
}
}
}
//玩家优先是1
public static int first;
//玩家选择的棋子
public static char piece;
//电脑的棋子
public static char comPiece;
public static void print(char[][] status) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(status[i][j] + "\t");
}
System.out.println();
}
}
public static void main(String[] args) {
char[][] begin = new char[][]{
{'.', '.', '.'},
{'.', '.', '.'},
{'.', '.', '.'},
};
Status status = new Status(begin);
Scanner scanner = new Scanner(System.in);
System.out.print("Human first[y/n]:");
String flag = scanner.nextLine();
first = flag.equals("y") ? 1 : -1;
System.out.print("Human select X/O[X/O]:");
piece = scanner.nextLine().charAt(0);
comPiece = piece == 'O' ? 'X' : 'O';
print(begin);//打印初始棋盘
status.main();
}
}
极小极大算法和alpha-beta算法
最新推荐文章于 2024-07-29 18:00:00 发布