AI 驱动的井字棋(Java 代码)





5.00/5 (14投票s)
Java 井字棋(AI 驱动)。
引言
此项目最初由 Mohd Akram 开发。它简单地演示了人工智能的力量。通俗易懂的语言将帮助您轻松理解代码。希望阅读完这篇文章后,您会对人工智能产生比以前更大的兴趣,并开发出更好的应用程序。
Using the Code
文件: TicTacToe.java
类: TicTacToe
全局变量
winComb - int[][]
:所有获胜情况state - int[][]
:当前游戏状态pl1 - Player
:玩家 1 对象(计算机 / 人类)pl2 - Player
:玩家 2 对象(计算机 / 人类)butClicked - int
:用户最近单击的按钮w1 - int
:Player1(X)
赢的局数w2 - int
:Player1(O)
赢的局数dr - int
:平局数
方法
public TicTacToe()
public void start()
public void refreshGrid()
public static int checkWin(int turn,int[][] st)
public static int checkWin2(String x,String o)
public void print(String s)
public void gameInit()
private void initComponents()
文件: Player.java
类: Player
(abstract
)
全局变量:无
方法
void playTurn(int pl,int turn)
void playerInit()
void notifyWin(int pl)
void notifyLose(int pl)
文件: Human.java
类: Human (extends Player)
全局变量:无
方法
void playTurn(int pl,int turn) // 覆盖
文件: Computer.java
类: Computer (extends Player)
全局变量
t - int
- 回合数begin - Node
- 状态树的顶部元素current - Node
- 状态树的当前节点layerFiles - File[]
- 从 layer1 到 layer 9 的层文件layers - ArrayList<Layer>
- 内存树的层
方法
public Computer(String l)
public void evaluate()
public void loadMind()
public void saveMind()
public void makeNewMind()
public void playTurn(int p,int turn) // 覆盖
void notifyWin(int pl) // 覆盖
void notifyLose(int pl) // 覆盖
文件: Node.java
类: Node
全局变量
sub_nodes - ArrayList<Node>
- 此节点与其subNodes
的连接subNodes - String
- 临时存储由“,
”分隔的subNodes
的 IDid - String
- 当前节点的id
pref - int
- 当前节点的偏好值n - int
- 此节点被玩过的次数lNum - int
- 此节点在内存树中所在的层号comp - Computer
- 此节点所属的 Computer 对象nodeType - int
- 存储此节点是否为结束节点
方法
public Node(String i,int l,Computer c)
public void setAsState()
public void playNext1()
public void playNext2()
public void playNextn()
public void extractNodes()
文件: Layer.java
类: Layer
全局变量
nodes - ArrayList<Node>
- 存储该层中 Nodes 的引用layerNum - int
- 存储层号(1-9)
方法
public void refreshLayer()
public Node searchByState(int[][] state)
public Node searchById(String id)
描述……
游戏模型可以总结如下……
游戏采用非常简单的方法来获得最可能的回合……寻找有利状态的方法稍后解释。
游戏的 GUI 是使用 netbeans Form maker 制作的。
主类(井字棋)
Tic Tac Toe 是主类。
类型为 int[][]
的 state 变量存储游戏的状态。它是一个 3x3 的数组,最初填充为 0。
1 代表“x”,2 代表“o”。有两个类型为 Player
的对象,名为“pl1
”和“pl2
”。游戏依次调用每个玩家的 playTurn
方法,从玩家 1 开始,更新显示,并在出现获胜情况时中断游戏。“checkWin()
”方法检查获胜情况。下一个回合的所有内部处理均由 Player
对象完成。
Human
和 Computer
类继承自 Player
类,因此任一类的对象都可以存储在 pl1
和 pl2
对象中。
显示
显示部分包含一个 9x9 的 jButtons
网格。顶部的文本显示了棋盘状态。jFrame
的底部还有一个通知栏。jFrame
的右侧边栏显示三个状态:每个玩家赢的局数和总平局数。
Player 类
这是一个 abstract
类,由玩家类型继承。它包含玩家应有的某些必要函数,如 playTurn()
、notifyWin()
、notifyLose()
等。
Human 类
这是人类与游戏之间的接口。当调用 playTurn()
方法时,它会等待用户按下 9x9 网格中的一个按钮。static
变量 butPressed
存储最近按下的按钮,此信息用于 Human
玩家类根据玩家回合 Number
用“x
”或“o
”填充单元格。如果回合数为偶数,对象在所需单元格中填充“o
”,否则通过设置 Main
类的 state 变量来填充“a
”,该变量在收到新状态后更新显示。
notifyWin()
和 notifyLose()
与 Human
类无关,因此为空。
人类玩家填充格子的方法是……
COMPUTER 类
这里是人工智能的主要部分。Computer
类使用树方法来存储可能的棋局、当前棋局及其偏好。游戏的可能棋局存储在名为 Node
的对象中。每个 Node
包含有关其棋局的信息。每个 Node
都有一个 ID,代表 Node
的棋局。
ID 是一个 9 个字符的 String
。每个字符代表一个单元格。0 代表空白单元格,1 代表“x”,2 代表“o”。例如 ID:“220211001
”,它代表页面顶部显示的棋局。
Node
还包含指向当前节点之后可以播放的节点的引用。在每次调用 PlayTurn()
时,计算机通过查看当前节点的子节点来找到当前节点之后最可能的棋局。最可能的棋局是通过比较子节点的偏好值获得的,具有最大值的子节点被设置为当前棋局以及当前节点。有两种方法可以找到和更新偏好值。
初始化计算机
for(int i=0;i<9;i++)
{
layerFiles[i] = new File(l+(i+1)+".nodes");
if(!layerFiles[i].exists())
{
try{
layerFiles[i].createNewFile();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
//loadMind();
makeNewMind();evaluate();saveMind();
begin.subNodes="100000000,010000000,001000000,000100000,
000010000,000001000,000000100,000000010,000000001,";
begin.extractNodes();
计算机对象会获得一个指向包含所有节点列表的层文件的文件路径。共有九个层文件。如果层文件不存在,计算机将创建新的层文件。然后是创建计算机内存的部分。makeNewMind()
方法创建新的节点或游戏的所有可能棋局(不使用层文件),并将它们存储在层对象中。然后它通过评估获胜和失败的情况来更新它们的偏好值,分别为 100
和 -100
。saveMind()
方法将层数据(即节点数据)保存到层文件中。这些层文件可用于在游戏结束后保留游戏的记忆。可以通过 loadMind()
方法加载现有的 Mind 文件。
计算机对象会获得一个指向包含所有节点列表的层文件的文件路径。共有九个层文件。如果层文件不存在,计算机将创建新的层文件。然后是创建计算机内存的部分。makeNewMind()
方法创建新的节点或 Game
的所有可能棋局(不使用层文件),并将它们存储在层对象中。然后它通过评估获胜和失败的情况来更新它们的偏好值,分别为 100
和 -100
。saveMind()
方法将层数据(即节点数据)保存到层文件中。这些层文件可用于在游戏结束后保留游戏的记忆。可以通过 loadMind()
方法加载现有的 Mind 文件。
Game
的第一个节点(即空白节点)是“begin
”节点。然后通过设置 subNodes
变量并调用 extractNodes()
手动将其连接到其可能的 subNodes
。
回合进行
计算机通过上述过程进行 nextTurn
。有两种方法:PlayNext1()
/PlayNext2()
(取决于玩家编号)和 PlayNextn()
。
public void playNext1(){
ArrayList<Node> temp = new ArrayList<Node>();
//System.out.println(id+" : "+sub_nodes.size());
long max = sub_nodes.get(0).pref;
for(int i=0;i<sub_nodes.size();i++)
{
if(sub_nodes.get(i).pref > max)
{
temp.clear();
temp.add(sub_nodes.get(i));
max = sub_nodes.get(i).pref;
}
else if(sub_nodes.get(i).pref == max)
{
temp.add(sub_nodes.get(i));
}
}
int choice = (int) (Math.random()*temp.size());
temp.get(choice).n++;
temp.get(choice).setAsState();
}
public void playNext2(){
ArrayList<Node> temp = new ArrayList<Node>();
//System.out.println(id+" : "+sub_nodes.size());
long min = sub_nodes.get(0).pref;
for(int i=0;i<sub_nodes.size();i++)
{
if(sub_nodes.get(i).pref < min)
{
temp.clear();
temp.add(sub_nodes.get(i));
min = sub_nodes.get(i).pref;
}
else if(sub_nodes.get(i).pref == min)
{
temp.add(sub_nodes.get(i));
}
}
int choice = (int) (Math.random()*temp.size());
temp.get(choice).n++;
temp.get(choice).setAsState();
}
public void playNextn(){
ArrayList<Node> temp = new ArrayList<Node>();
//System.out.println(id+" : "+sub_nodes.size());
int choice = 0;
long min = sub_nodes.get(0).n;
for(int i=0;i<sub_nodes.size();i++)
{
if(sub_nodes.get(i).n < min)
{
min = sub_nodes.get(i).n;
choice = i;
}
}
sub_nodes.get(choice).n++;
sub_nodes.get(choice).setAsState();
}
playnext1()
方法会准备一个包含所有具有最大偏好值的节点的列表,然后播放其中一个。PlayNextn()
方法播放次数最少的回合,从而做到面面俱到。此方法在进行评估过程时很有用。
确定偏好的方法
计算机通过将所有子节点的偏好值相加来确定节点的偏好值。这样,没有机会在 nextTurn
中获胜的节点,其子节点没有正值,其自身值将非常低。这样,计算机就会避开这个节点,从而走向获胜的局面。
Computer
类负责确定除起始节点(即空白节点)之外所有节点的偏好值。
在获得获胜或失败的局面时,计算机会被通知,因此如果收到的是失败通知,计算机会将当前节点的偏好值减去 10;如果是获胜通知,计算机会将当前节点的值增加 10。这样,通过 playNextn()
方法多次玩之后,我们将清楚地了解偏好和不受欢迎的局面,以及如何选择路径以达到高度偏好的获胜局面。与人类对战时,最好使用 PlayNext1()
方法进行回合,因为它能充分利用从之前的游戏中学习到的知识。
文件
import java.util.logging.Level;
import java.util.logging.Logger;
public class TicTacToe extends javax.swing.JFrame {
static int winComb[][] = {{1,2,3},{4,5,6},{7,8,9},{1,4,7},{2,5,8},{3,6,9},{1,5,9},{3,5,7}};
public static int[][] state = {{0,0,0},{0,0,0},{0,0,0}};
Player pl1 = new Human();
Player pl2 = new Computer("mind\\layer");
public static int butClicked = 0;
int w1=0 , w2 = 0 , dr = 0;
public TicTacToe() {
initComponents();
}
public void start(){
if(w1==500)System.exit(0);
int current = 1 , turn = 1;
int w=0;
while((w=checkWin(turn,state))==0)
{
if(current == 1)
{
pl1.playTurn(1,turn);
refreshGrid();
current = 2;
}
else if(current == 2 )
{
pl2.playTurn(2,turn);
refreshGrid();
current = 1;
}
turn++;
try {Thread.sleep(0);} catch (InterruptedException ex)
{Logger.getLogger(TicTacToe.class.getName()).log(Level.SEVERE, null, ex);}
}
if(w==1)
{
pl1.notifyWin(1);
pl2.notifyLose(2);
print("Player 1 Won The Game !");
w1++;
}
else if(w==2)
{
pl2.notifyWin(1);
pl1.notifyLose(2);
print("Player 2 Won The Game !");
w2++;
}
else if(w==-1)
{
print("Game DRAW !");
dr++;
}
try {Thread.sleep(0);} catch (InterruptedException ex)
{Logger.getLogger(TicTacToe.class.getName()).log(Level.SEVERE, null, ex);}
}
public void refreshGrid(){
b11.setText(state[0][0]==1?"X":(state[0][0]==2?"O":""));
b12.setText(state[0][1]==1?"X":(state[0][1]==2?"O":""));
b13.setText(state[0][2]==1?"X":(state[0][2]==2?"O":""));
b21.setText(state[1][0]==1?"X":(state[1][0]==2?"O":""));
b22.setText(state[1][1]==1?"X":(state[1][1]==2?"O":""));
b23.setText(state[1][2]==1?"X":(state[1][2]==2?"O":""));
b31.setText(state[2][0]==1?"X":(state[2][0]==2?"O":""));
b32.setText(state[2][1]==1?"X":(state[2][1]==2?"O":""));
b33.setText(state[2][2]==1?"X":(state[2][2]==2?"O":""));
jLabel1.setText(" X wins : "+w1);
jLabel2.setText(" O wins : "+w2);
jLabel3.setText(" Draws : "+dr);
}
public static int checkWin(int turn,int[][] st){
int ret = 0;
String x ="";
String o ="";
int i=0 , j=0 , c=0 , p , q;
for(p=0;p<3;p++)
{
for(q=0;q<3;q++)
{
c++;
if(st[p][q]==1)
{
x+=c;
}
else if(st[p][q]==2)
{
o+=c;
}
}
}
//print(x+" : "+o);
ret = checkWin2(x,o);
if(turn==10 && ret==0)
{
ret = -1;
}
return ret;
}
public static int checkWin2(String x,String o){
int ret = 0;
int p;
for(p=0;p<8;p++)
{
if(x.indexOf((char)winComb[p][0]+'0')>-1 &&
x.indexOf((char)winComb[p][1]+'0')>-1 && x.indexOf((char)winComb[p][2]+'0')>-1)
{
ret = 1;
break;
}
if(o.indexOf((char)winComb[p][0]+'0')>-1 &&
o.indexOf((char)winComb[p][1]+'0')>-1 && o.indexOf((char)winComb[p][2]+'0')>-1)
{
ret = 2;
break;
}
}
return ret;
}
public void print(String s){
Notification.setText("\t"+s);
}
public void gameInit(){
state[0][0] = 0;
state[0][1] = 0;
state[0][2] = 0;
state[1][0] = 0;
state[1][1] = 0;
state[1][2] = 0;
state[2][0] = 0;
state[2][1] = 0;
state[2][2] = 0;
refreshGrid();
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
try {
jPanel1 =(javax.swing.JPanel)java.beans.Beans.instantiate
(getClass().getClassLoader(), "TicTacToe_jPanel1");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (java.io.IOException e) {
e.printStackTrace();
}
b21 = new javax.swing.JButton();
b11 = new javax.swing.JButton();
b22 = new javax.swing.JButton();
b12 = new javax.swing.JButton();
b13 = new javax.swing.JButton();
b23 = new javax.swing.JButton();
b31 = new javax.swing.JButton();
b32 = new javax.swing.JButton();
b33 = new javax.swing.JButton();
Notification = new javax.swing.JLabel();
jPanel2 = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
jLabel3 = new javax.swing.JLabel();
jLabel4 = new javax.swing.JLabel();
jLabel5 = new javax.swing.JLabel();
jLabel6 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setAlwaysOnTop(true);
setPreferredSize(new java.awt.Dimension(600, 400));
b21.setBackground(new java.awt.Color(255, 255, 255));
b21.setFont(new java.awt.Font("Arial", 1, 48)); // NOI18N
b21.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
b21.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
b21ActionPerformed(evt);
}
});
b11.setBackground(new java.awt.Color(255, 255, 255));
b11.setFont(new java.awt.Font("Arial", 1, 48)); // NOI18N
b11.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
b11.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
b11ActionPerformed(evt);
}
});
b22.setBackground(new java.awt.Color(255, 255, 255));
b22.setFont(new java.awt.Font("Arial", 1, 48)); // NOI18N
b22.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
b22.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
b22ActionPerformed(evt);
}
});
b12.setBackground(new java.awt.Color(255, 255, 255));
b12.setFont(new java.awt.Font("Arial", 1, 48)); // NOI18N
b12.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
b12.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
b12ActionPerformed(evt);
}
});
b13.setBackground(new java.awt.Color(255, 255, 255));
b13.setFont(new java.awt.Font("Arial", 1, 48)); // NOI18N
b13.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
b13.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
b13ActionPerformed(evt);
}
});
b23.setBackground(new java.awt.Color(255, 255, 255));
b23.setFont(new java.awt.Font("Arial", 1, 48)); // NOI18N
b23.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
b23.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
b23ActionPerformed(evt);
}
});
b31.setBackground(new java.awt.Color(255, 255, 255));
b31.setFont(new java.awt.Font("Arial", 1, 48)); // NOI18N
b31.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
b31.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
b31ActionPerformed(evt);
}
});
b32.setBackground(new java.awt.Color(255, 255, 255));
b32.setFont(new java.awt.Font("Arial", 1, 48)); // NOI18N
b32.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
b32.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
b32ActionPerformed(evt);
}
});
b33.setBackground(new java.awt.Color(255, 255, 255));
b33.setFont(new java.awt.Font("Arial", 1, 48)); // NOI18N
b33.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
b33.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
b33ActionPerformed(evt);
}
});
Notification.setBackground(new java.awt.Color(255, 255, 0));
Notification.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
Notification.setForeground(new java.awt.Color(0, 0, 102));
Notification.setText("Tic - Tac - Toe");
Notification.setBorder(new javax.swing.border.MatteBorder(null));
jLabel1.setFont(new java.awt.Font("Arial", 0, 18)); // NOI18N
jLabel1.setBorder(javax.swing.BorderFactory.createLineBorder
(new java.awt.Color(0, 0, 0)));
jLabel2.setFont(new java.awt.Font("Arial", 0, 18)); // NOI18N
jLabel2.setBorder(javax.swing.BorderFactory.createLineBorder
(new java.awt.Color(0, 0, 0)));
jLabel3.setFont(new java.awt.Font("Arial", 0, 18)); // NOI18N
jLabel3.setBorder(javax.swing.BorderFactory.createLineBorder
(new java.awt.Color(0, 0, 0)));
jLabel4.setFont(new java.awt.Font("Arial", 0, 18)); // NOI18N
jLabel4.setBorder(javax.swing.BorderFactory.createLineBorder
(new java.awt.Color(0, 0, 0)));
jLabel5.setFont(new java.awt.Font("Arial", 0, 18)); // NOI18N
jLabel5.setBorder(javax.swing.BorderFactory.createLineBorder
(new java.awt.Color(0, 0, 0)));
jLabel6.setFont(new java.awt.Font("Arial", 0, 18)); // NOI18N
jLabel6.setBorder(javax.swing.BorderFactory.createLineBorder
(new java.awt.Color(0, 0, 0)));
javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
jPanel2.setLayout(jPanel2Layout);
jPanel2Layout.setHorizontalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel2Layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 203,
Short.MAX_VALUE)
.addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jLabel5, javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jLabel6, javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
jPanel2Layout.setVerticalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 40,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 40,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 40,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 40,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel5, javax.swing.GroupLayout.PREFERRED_SIZE, 40,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 40,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
jLabel1.getAccessibleContext().setAccessibleName("l1");
jLabel1.getAccessibleContext().setAccessibleDescription("");
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(Notification, javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(b21, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(b11, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.
ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(b22,
javax.swing.GroupLayout.PREFERRED_SIZE, 100,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.
ComponentPlacement.RELATED)
.addComponent(b23,
javax.swing.GroupLayout.PREFERRED_SIZE, 100,
javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(b12,
javax.swing.GroupLayout.PREFERRED_SIZE, 100,
javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap
(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(b13,
javax.swing.GroupLayout.PREFERRED_SIZE, 100,
javax.swing.GroupLayout.PREFERRED_SIZE))))
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(b31, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.
ComponentPlacement.RELATED)
.addComponent(b32, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.
ComponentPlacement.RELATED)
.addComponent(b33, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addContainerGap())
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(b12, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(b13, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(b11, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(b22, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(b21, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(b23, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup
(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(b32, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(b31, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(b33, javax.swing.GroupLayout.PREFERRED_SIZE,
100, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(Notification, javax.swing.GroupLayout.DEFAULT_SIZE,
40, Short.MAX_VALUE)
.addContainerGap())
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE,
561, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 385, Short.MAX_VALUE)
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void b33ActionPerformed
(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_b33ActionPerformed
if(state[2][2]==0)
butClicked = 9;
}//GEN-LAST:event_b33ActionPerformed
private void b32ActionPerformed
(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_b32ActionPerformed
if(state[2][1]==0)
butClicked = 8;
}//GEN-LAST:event_b32ActionPerformed
private void b31ActionPerformed
(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_b31ActionPerformed
if(state[2][0]==0)
butClicked = 7;
}//GEN-LAST:event_b31ActionPerformed
private void b23ActionPerformed
(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_b23ActionPerformed
if(state[1][2]==0)
butClicked = 6;
}//GEN-LAST:event_b23ActionPerformed
private void b13ActionPerformed
(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_b13ActionPerformed
if(state[0][2]==0)
butClicked = 3;
}//GEN-LAST:event_b13ActionPerformed
private void b12ActionPerformed
(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_b12ActionPerformed
if(state[0][1]==0)
butClicked = 2;
}//GEN-LAST:event_b12ActionPerformed
private void b22ActionPerformed
(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_b22ActionPerformed
if(state[1][1]==0)
butClicked = 5;
}//GEN-LAST:event_b22ActionPerformed
private void b11ActionPerformed
(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_b11ActionPerformed
if(state[0][0]==0)
butClicked = 1;
}//GEN-LAST:event_b11ActionPerformed
private void b21ActionPerformed
(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_b21ActionPerformed
if(state[1][0]==0)
butClicked = 4;
}//GEN-LAST:event_b21ActionPerformed
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed"
//desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available,
* stay with the default look and feel.
* For details, see
* http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info :
javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(TicTacToe.class.getName()).log
(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(TicTacToe.class.getName()).log
(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(TicTacToe.class.getName()).log
(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(TicTacToe.class.getName()).log
(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
TicTacToe t = new TicTacToe();
t.setVisible(true);
while(true)
{
t.start();
t.gameInit();
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel Notification;
public static javax.swing.JButton b11;
public static javax.swing.JButton b12;
public static javax.swing.JButton b13;
public static javax.swing.JButton b21;
public static javax.swing.JButton b22;
public static javax.swing.JButton b23;
public static javax.swing.JButton b31;
public static javax.swing.JButton b32;
public static javax.swing.JButton b33;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JLabel jLabel5;
private javax.swing.JLabel jLabel6;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
// End of variables declaration//GEN-END:variables
}
public abstract class Player {
void playTurn(int pl,int turn){}
void playerInit(){}
void notifyWin(int pl){}
void notifyLose(int pl){}
}
public class Human extends Player {
@Override
void playTurn(int pl,int turn){
while(TicTacToe.butClicked == 0);
switch(TicTacToe.butClicked)
{
case 1 : TicTacToe.state[0][0]=pl;break;
case 2 : TicTacToe.state[0][1]=pl;break;
case 3 : TicTacToe.state[0][2]=pl;break;
case 4 : TicTacToe.state[1][0]=pl;break;
case 5 : TicTacToe.state[1][1]=pl;break;
case 6 : TicTacToe.state[1][2]=pl;break;
case 7 : TicTacToe.state[2][0]=pl;break;
case 8 : TicTacToe.state[2][1]=pl;break;
case 9 : TicTacToe.state[2][2]=pl;break;
}
TicTacToe.butClicked = 0;
}
}
import java.io.*;
import java.util.ArrayList;
public class Computer extends Player {
int t=0;
Node begin = new Node("000000000",0,this);
Node current = begin;
double lr = 0;
File[] layerFiles = new File[9];
ArrayList<Layer> layers = new ArrayList<Layer>();
public Computer(String l){
for(int i=0;i<9;i++)
{
layerFiles[i] = new File(l+(i+1)+".nodes");
if(!layerFiles[i].exists())
{
try{
layerFiles[i].createNewFile();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
//loadMind();
makeNewMind();evaluate();saveMind();
begin.subNodes="100000000,010000000,001000000,000100000,000010000,
000001000,000000100,000000010,000000001,";
begin.extractNodes();
}
public void evaluate(){
for(int i=0;i<9;i++)
{
Layer l = layers.get(i);
for(int j=0;j<l.nodes.size();j++)
{
String x="" , o="" , s = l.nodes.get(j).id;
for(int k=0;k<9;k++)
{
char ch = s.charAt(k);
if(ch=='1')
{
x+=(k+1);
}
else if(ch=='2')
{
o+=(k+1);
}
}
int r = TicTacToe.checkWin2(x,o);
switch(r)
{
case 1 : l.nodes.get(j).pref=50;
l.nodes.get(j).nodeType=1;
break;
case 2 : l.nodes.get(j).pref=-50;
l.nodes.get(j).nodeType=1;
break;
case -1 :
l.nodes.get(j).nodeType=1;
break;
}
}
}
}
public void loadMind(){
FileReader f;
BufferedReader r;
int i=0;
try{
for(int l=0;l<9;l++)
{
layers.add(new Layer(l+1));
f = new FileReader(layerFiles[l]);
r = new BufferedReader(f);
String line;
while((line=r.readLine())!=null)
{
Node temp = new Node(r.readLine(),l+1,this);
temp.subNodes = r.readLine();
String no = r.readLine();
//System.out.println(no);
temp.pref = Integer.parseInt(no);
temp.n = Integer.parseInt(r.readLine());
temp.nodeType = Integer.parseInt(r.readLine());
layers.get(l).nodes.add(temp);
}
}
for(int l=0;l<9;l++)
{
for(int j=0;j<layers.get(l).nodes.size();j++)
{
layers.get(l).nodes.get(j).extractNodes();
}
}
}
catch(Exception e){
e.printStackTrace(System.out);
}
}
public void saveMind(){
for(int i=7;i>=0;i--)
{
layers.get(i).refreshLayer();
}
try{
for(int i=0;i<9;i++)
{
Layer l = layers.get(i);
PrintWriter p = new PrintWriter(new BufferedWriter
(new FileWriter(layerFiles[i])));
for(int j=0;j<l.nodes.size();j++)
{
Node temp = l.nodes.get(j);
p.println("***********************************************");
p.println(temp.id);
//System.out.println(temp.id);
String s="";
for(int k=0;k<temp.sub_nodes.size();k++)
{
s+=temp.sub_nodes.get(k).id+",";
}
p.println(s);
p.println(temp.pref);
p.println(temp.n);
p.println(temp.nodeType);
}
p.close();
//System.out.println("layer "+i+" : "+l.nodes.size());
}
}
catch(Exception e)
{
e.printStackTrace(System.out);
}
}
public void makeNewMind(){
layers.add(new Layer(1));layers.add(new Layer(2));layers.add(new Layer(3));
layers.add(new Layer(4));layers.add(new Layer(5));layers.add(new Layer(6));
layers.add(new Layer(7));layers.add(new Layer(8));layers.add(new Layer(9));
for(int i1=0;i1<=2;i1++){
for(int i2=0;i2<=2;i2++){
for(int i3=0;i3<=2;i3++){
for(int i4=0;i4<=2;i4++){
for(int i5=0;i5<=2;i5++){
for(int i6=0;i6<=2;i6++){
for(int i7=0;i7<=2;i7++){
for(int i8=0;i8<=2;i8++){
for(int i9=0;i9<=2;i9++){
int l=9;
if(i1==0)l--;
if(i2==0)l--;
if(i3==0)l--;
if(i4==0)l--;
if(i5==0)l--;
if(i6==0)l--;
if(i7==0)l--;
if(i8==0)l--;
if(i9==0)l--;
int x=0;
if(i1==1)x++;
if(i2==1)x++;
if(i3==1)x++;
if(i4==1)x++;
if(i5==1)x++;
if(i6==1)x++;
if(i7==1)x++;
if(i8==1)x++;
if(i9==1)x++;
int o = l-x;
if((x-o==0 || x-o==1) && l!=0 )
{
String id = ""+i1+i2+i3+i4+i5+i6+i7+i8+i9;
layers.get(l-1).nodes.add(new Node(id,l,this));
}
}}}}}}}}}
for(int l=1;l<9;l++)
{
for(int j=0;j<layers.get(l).nodes.size();j++)
{
Node node = layers.get(l).nodes.get(j);
for(int i=0;i<9;i++)
{
String newId="";
for(int k=0;k<9;k++)
{
char ch = node.id.charAt(k);
if(k==i)ch='0';
newId+=ch;
}
if(!newId.equals(node.id))
{
try{
layers.get(l-1).searchById(newId).sub_nodes.add(node);
//System.out.println(node.id+" : "+newId+" : "+l);
}
catch(NullPointerException e){}
}
}
}
}
begin.extractNodes();
}
@Override
public void playTurn(int p,int turn){
t = turn;
if(turn != 1)
{
current = layers.get(turn-2).searchByState(TicTacToe.state);
}
if(turn == 1)
{
current = begin;
}
if(p==1)current.playNextn();
if(p==2)current.playNext2();
}
@Override
void notifyWin(int pl){
if(pl==1)current.pref+=10;
if(pl==2)current.pref-=10;
current.nodeType=1;
//System.out.println("*******"+current.id+":"+current.pref+" :
//"+layers.get(current.lNum-1).searchById(current.id).pref);
saveMind();
}
@Override
void notifyLose(int pl){
if(pl==1)current.pref-=10;
if(pl==2)current.pref+=10;
current.nodeType=1;
//System.out.println("*******"+current.id+":"+current.pref+" :
//"+layers.get(current.lNum-1).searchById(current.id).pref);
saveMind();
}
}
import java.util.ArrayList;
public class Node {
ArrayList<Node> sub_nodes = new ArrayList<Node>();
String subNodes="";
String id="";
int pref = 0;
int n=0;
int lNum;
Computer comp;
int nodeType=0;
public Node(String i,int l,Computer c){
id=i;
lNum = l;
comp = c;
}
public void setAsState(){
for(int i=0;i<id.length();i++)
{
int val = (int)(id.charAt(i)-'0');
int t = i/3;
TicTacToe.state[t][i-(t*3)] = val;
}
}
public void playNext1(){
ArrayList<Node> temp = new ArrayList<Node>();
//System.out.println(id+" : "+sub_nodes.size());
long max = sub_nodes.get(0).pref;
for(int i=0;i<sub_nodes.size();i++)
{
if(sub_nodes.get(i).pref > max)
{
temp.clear();
temp.add(sub_nodes.get(i));
max = sub_nodes.get(i).pref;
}
else if(sub_nodes.get(i).pref == max)
{
temp.add(sub_nodes.get(i));
}
}
int choice = (int) (Math.random()*temp.size());
temp.get(choice).n++;
temp.get(choice).setAsState();
}
public void playNext2(){
ArrayList<Node> temp = new ArrayList<Node>();
//System.out.println(id+" : "+sub_nodes.size());
long min = sub_nodes.get(0).pref;
for(int i=0;i<sub_nodes.size();i++)
{
if(sub_nodes.get(i).pref < min)
{
temp.clear();
temp.add(sub_nodes.get(i));
min = sub_nodes.get(i).pref;
}
else if(sub_nodes.get(i).pref == min)
{
temp.add(sub_nodes.get(i));
}
}
int choice = (int) (Math.random()*temp.size());
temp.get(choice).n++;
temp.get(choice).setAsState();
}
public void playNextn(){
ArrayList<Node> temp = new ArrayList<Node>();
//System.out.println(id+" : "+sub_nodes.size());
int choice = 0;
long min = sub_nodes.get(0).n;
for(int i=0;i<sub_nodes.size();i++)
{
if(sub_nodes.get(i).n < min)
{
min = sub_nodes.get(i).n;
choice = i;
}
}
sub_nodes.get(choice).n++;
sub_nodes.get(choice).setAsState();
}
public void extractNodes(){
if(lNum!=9)
{
int l = subNodes.length();
String w="";
for(int i=0;i<l;i++)
{
char ch = subNodes.charAt(i);
if(ch!=',')
{
w+=ch;
}
else
{
sub_nodes.add(comp.layers.get(lNum).searchById(w));
w="";
}
}
}
}
}
import java.util.ArrayList;
public class Layer {
ArrayList<Node> nodes = new ArrayList<Node>();
int layerNum = 0;
public Layer(int Num){
layerNum = Num;
}
public void refreshLayer(){
for(int i=0;i<nodes.size();i++)
{
Node temp = nodes.get(i);
if(temp.nodeType!=0)continue;
temp.pref=0;
for(int j=0;j<temp.sub_nodes.size();j++)
{
temp.pref += (int)(temp.sub_nodes.get(j).pref)/2;
}
//System.out.print(temp.pref!=0?temp.pref+"\n":"");
}
}
public Node searchByState(int[][] state){
String temp = ""+state[0][0]+state[0][1]+state[0][2]+state[1][0]+
state[1][1]+state[1][2]+state[2][0]+state[2][1]+state[2][2];
//System.out.print(temp.!=0?temp:"");
Node ret = searchById(temp);
return ret;
}
public Node searchById(String id){
Node ret = null;
for(int i=0;i<nodes.size();i++)
{
//System.out.println("*********"+nodes.get(i).id);
if(nodes.get(i).id.equals(id))
{
ret = nodes.get(i);
break;
}
}
return ret;
}
}
结论
希望您喜欢阅读我的帖子,并对这个主题进一步感兴趣。此方法可用于开发其他机器学习程序。我将非常乐意看到它在其他程序中得到应用 :)。
致谢
此项目由来自印度的在读中学生 Mohd Akram 开发。我是一名 16 岁的印度人,脑海中有许多想法,希望您能帮助我实现它们。非常感谢您阅读我的作品。
历史
- 2014年5月27日:初始版本