JavaScript写的一个带AI的井字棋

最近有一门课结束了,需要做一个井字棋的游戏,我用JavaScript写了一个。首先界面应该问题不大,用html稍微写一下就可以。主要是人机对弈时的ai算法,如何使电脑方聪明起来,是值得思考一下的。开始游戏后,由玩家先行。那么站在计算机的角度,可以对多种情况进行分析,并按照重要程度赋予权值。
情况如下:

1、同一排(行。列。对角线)有且只有两个棋子,并且都是自己的,只要再进一步就能获胜,那么剩下的那个位置权值最高,优先级最大。赋予一级权值。

2、同一排(行。列。对角线)有且只有两个棋子,并且都是对方的(也就是玩家的),只要再进一步,玩家就会成功,所以“我”要堵住,剩下的那个位置赋予二级权值。

3、因为电脑方后行,如果聪明点,需要一直堵玩家方,所以当一排只有一个棋,且是玩家的棋子,那么该排其他位置的权值设为三级。

4、四级权值:一排只有己方(电脑方)的棋子。

5、五级权限:同排没有棋子,包括对方和己方。

实现的时候,每个位置的棋子,可以用二维数组full表示,每个位置的权值大小也用一个二维数组val来表示。玩家方下完后,调用AI方的函数,AI方行棋前,先更新一下权值,然后选出权值最大的位置落子(最优解)。无论是ai还是玩家方,每次落子后都要判断有没有产生输赢。用alert()函数输出结果。

为了表示权值的大小,规定按照一级到五级顺序,依次加  10000、1000、10、5、3

注:由于可能要提交源码,我没有分离出css样式和js文件,不过最好还是分开写更规范。如有不足之处,欢迎批评指正。

源码如下:

<html>
<head>
<meta charset="utf-8">
<title>井字棋</title>
<script>
//定义全局变量
var full=[[0,0,0],[0,0,0],[0,0,0]];//0表示null,1表示我下的,2表示电脑下的
var val=[[1,1,1],[1,1,1],[1,1,1]];//表示每个位置的权值
function judge(){
      //检测是否有人赢
      //行
      for(var i=0;i<3;i++){
          if(full[i][0]==full[i][1]&&full[i][1]==full[i][2]&&full[i][0]!=0){
                          if(full[i][0]==1){
                               window.alert("you win!");
                                return true;
                          }
                          else {
                                window.alert("you lose");
                                return true;
                          }
          }
      }
      //列
      for(var i=0;i<3;i++){
          if(full[0][i]==full[1][i]&&full[1][i]==full[2][i]&&full[0][i]!=0){
                          if(full[0][i]==1){
                               window.alert("you win!");
                               return true;
                          }
                          else {
                               window.alert("you lose");
                               return true;
                          }
          }
      }
      //主对角线
      if(full[0][0]==full[1][1]&&full[1][1]==full[2][2]&&full[0][0]!=0){
                          if(full[0][0]==1){
                               window.alert("you win!");
                               return true;
                        }
                          else {
                               window.alert("you lose");
                               return true;
                        }
      }
      if(full[0][2]==full[1][1]&&full[2][0]==full[1][1]&&full[0][2]!=0){
                          if(full[0][2]==1){
                               window.alert("you win!");
                               return true;
                        }
                          else {
                              window.alert("you lose");
                              return true;
                        }
      }
      for(var i=0;i<3;i++){
         for(var j=0;j<3;j++){
            if(full[i][j]==0)
               return false;//说明还没结束
             if(i==2&&j==2)
               {window.alert("平局!");
                return true;
               }
         }
      }
      return false;//无结果
}
function bn(i,j){
     //如果已经下过,则无效
      if(full[i][j]!=0){
           return 0;
      }else{
           //没下过
           full[i][j]=1;
           num1=(i*3+j+1)+"";
           document.getElementById(num1).value="X";
           if(judge()==true){
               return;
           }
           ai();//切换
      }
}
//重置权值:
function resetValue(){

      for(var i=0;i<3;i++){
           for(var j=0;j<3;j++){
               if(full[i][j]!=0)
                   val[i][j]=0;
               else{
            //看行和列:
                  //最高权值
                  if(((full[0][j]+full[1][j]+full[2][j])==4)&&(full[0][j]*full[1][j]*full[2][j])==0
                  &&((full[0][j]-1)*(full[1][j]-1)*(full[2][j]-1))==-1)
                        val[i][j]=val[i][j]+10000;
                  if(((full[i][0]+full[i][1]+full[i][2])==4)&&(full[i][0]*full[i][1]*full[i][2])==0
                  &&((full[i][0]-1)*(full[i][1]-1)*(full[i][2]-1))==-1)
                        val[i][j]=val[i][j]+10000;
                  //次级权值
                  if(((full[0][j]+full[1][j]+full[2][j])==2)&&(full[0][j]*full[1][j]*full[2][j])==0
                  &&((full[0][j]-1)*(full[1][j]-1)*(full[2][j]-1))==0)
                        val[i][j]=val[i][j]+1000;
                  if(((full[i][0]+full[i][1]+full[i][2])==2)&&(full[i][0]*full[i][1]*full[i][2])==0
                  &&((full[i][0]-1)*(full[i][1]-1)*(full[i][2]-1))==0)
                        val[i][j]=val[i][j]+1000;
                  //三级权值(一排只有一个X)
                  if(((full[0][j]+full[1][j]+full[2][j])==1)&&(full[0][j]*full[1][j]*full[2][j])==0
                  &&((full[0][j]-1)*(full[1][j]-1)*(full[2][j]-1))==0)
                        val[i][j]=val[i][j]+10;
                  if(((full[i][0]+full[i][1]+full[i][2])==1)&&(full[i][0]*full[i][1]*full[i][2])==0
                  &&((full[i][0]-1)*(full[i][1]-1)*(full[i][2]-1))==0)
                        val[i][j]=val[i][j]+10;
                  //四级权值(一排只有一个O)
                  if(((full[0][j]+full[1][j]+full[2][j])==2)&&(full[0][j]*full[1][j]*full[2][j])==0
                  &&((full[0][j]-1)*(full[1][j]-1)*(full[2][j]-1))==1)
                        val[i][j]=val[i][j]+5;
                  if(((full[i][0]+full[i][1]+full[i][2])==2)&&(full[i][0]*full[i][1]*full[i][2])==0
                  &&((full[i][0]-1)*(full[i][1]-1)*(full[i][2]-1))==1)
                        val[i][j]=val[i][j]+5;
                  //五级权限(该行没有X或O)
                  if(((full[0][j]+full[1][j]+full[2][j])==0)&&(full[0][j]*full[1][j]*full[2][j])==0
                  &&((full[0][j]-1)*(full[1][j]-1)*(full[2][j]-1))==-1)
                        val[i][j]=val[i][j]+2;
                  if(((full[i][0]+full[i][1]+full[i][2])==0)&&(full[i][0]*full[i][1]*full[i][2])==0
                  &&((full[i][0]-1)*(full[i][1]-1)*(full[i][2]-1))==-1)
                        val[i][j]=val[i][j]+2;

        //主对角线:同上
                   if((i==0&&j==0)||(i==2&&j==2)||(i==1&&j==1)){
                        if(((full[0][0]+full[1][1]+full[2][2])==4)&&(full[0][0]*full[1][1]*full[2][2])==0
                        &&((full[0][0]-1)*(full[1][1]-1)*(full[2][2]-1))==-1)
                        val[i][j]=val[i][j]+10000;

                  //次级权值
                  if(((full[0][0]+full[1][1]+full[2][2])==2)&&(full[0][0]*full[1][1]*full[2][2])==0
                  &&((full[0][0]-1)*(full[1][1]-1)*(full[2][2]-1))==0)
                        val[i][j]=val[i][j]+1000;

                  //三级权值(一排只有一个X)
                  if(((full[0][0]+full[1][1]+full[2][2])==1)&&(full[0][0]*full[1][1]*full[2][2])==0
                  &&((full[0][0]-1)*(full[1][1]-1)*(full[2][2]-1))==0)
                        val[i][j]=val[i][j]+10;

                  //四级权值(一排只有一个O)
                  if(((full[0][0]+full[1][1]+full[2][2])==2)&&(full[0][0]*full[1][1]*full[2][2])==0
                  &&((full[0][0]-1)*(full[1][1]-1)*(full[2][2]-1))==1)
                        val[i][j]=val[i][j]+5;

                  //五级权值(该行没有X或O)
                  if(((full[0][0]+full[1][1]+full[2][2])==0)&&(full[0][0]*full[1][1]*full[2][2])==0
                  &&((full[0][0]-1)*(full[1][1]-1)*(full[2][2]-1))==-1)
                        val[i][j]=val[i][j]+2;
               }
         //副对角线(同上)
                if((i==0&&j==2)||(i==2&&j==0)||(i==1&&j==1)){
                       //一级
                      if(((full[0][2]+full[1][1]+full[2][0])==4)&&(full[0][2]*full[1][1]*full[2][0])==0
                      &&((full[0][2]-1)*(full[1][1]-1)*(full[2][0]-1))==-1)
                       val[i][j]=val[i][j]+10000;
                       //二级
                       if(((full[0][2]+full[1][1]+full[2][0])==2)&&(full[0][2]*full[1][1]*full[2][0])==0
                       &&((full[0][2]-1)*(full[1][1]-1)*(full[2][0]-1))==0)
                       val[i][j]=val[i][j]+1000;
                       //三级权值(一排只有一个X)
                       if(((full[0][2]+full[1][1]+full[2][0])==1)&&(full[0][2]*full[1][1]*full[2][0])==0
                       &&((full[0][2]-1)*(full[1][1]-1)*(full[2][0]-1))==0)
                       val[i][j]=val[i][j]+10;
                       //四级权值(一排只有一个O)
                       if(((full[0][2]+full[1][1]+full[2][0])==2)&&(full[0][2]*full[1][1]*full[2][0])==0
                       &&((full[0][2]-1)*(full[1][1]-1)*(full[2][0]-1))==1)
                       val[i][j]=val[i][j]+5;
                       //五级权值(该行没有X或O)
                       if(((full[0][2]+full[1][1]+full[2][0])==0)&&(full[0][2]*full[1][1]*full[2][0])==0
                       &&((full[0][2]-1)*(full[1][1]-1)*(full[2][0]-1))==-1)
                       val[i][j]=val[i][j]+2;
                      }
                   }
           }
      }
}
function ai(){
      if(judge()==true){
          return;
      }
      //挑选权值最大的
      resetValue();
      var mi=0,mj=0,temp=0;
      for(var i=0;i<3;i++)
         for(var j=0;j<3;j++){
             if(val[i][j]>temp){
                  temp=val[i][j];
                  mi=i;
                  mj=j;
             }
         }
         full[mi][mj]=2;
         num1=(mi*3+mj+1)+"";
         document.getElementById(num1).value="O";
         if(judge()==true){
          return;
      }
}
function lose(){
window.alert("you lose");
location.reload();
}
</script>
</head>
<body>
<h1 align=center> 井字棋</h1>
<table border=2px bordercolor="blue"width="300"height="300" style="font-size:50 " align=center>
<tr>
<td><input type="button" id="1" Style="width:100px;height:100px;" value="  " onclick="bn(0,0)"/></td>
<td><input type="button" id="2" Style="width:100px;height:100px;" value="  " onclick="bn(0,1)"/></td>
<td><input type="button" id="3" Style="width:100px;height:100px;" value="  " onclick="bn(0,2)"/></td>
</tr>
<tr>
<td><input type="button" id="4" Style="width:100px;height:100px;" value="  " onclick="bn(1,0)"/></td>
<td><input type="button" id="5" Style="width:100px;height:100px;" value="  " onclick="bn(1,1)"/></td>
<td><input type="button" id="6" Style="width:100px;height:100px;" value="  " onclick="bn(1,2)"/></td>
</tr>
<tr >
<td><input type="button" id="7" Style="width:100px;height:100px;" value="  " onclick="bn(2,0)"/></td>
<td><input type="button" id="8" Style="width:100px;height:100px;" value="  " onclick="bn(2,1)"/></td>
<td><input type="button" id="9" Style="width:100px;height:100px;" value="  " onclick="bn(2,2)"/></td>
</tr>
</table>
<div ><input type="button" style="position:relative;left:500px;top:5px;width:100px;height:50px;" value="重新开始" onclick="location.reload() "/>
      <input type="button" style="position:relative;left:550px;top:5px;width:100px;height:50px;" value="认    输" onclick="lose()"/>
</div>
<body>
</html>

原文地址:https://www.cnblogs.com/phdeblog/p/9062432.html

时间: 2024-11-08 15:58:35

JavaScript写的一个带AI的井字棋的相关文章

井字棋的最优策略竟是先占角!

http://www.guokr.com/article/4754/ 井字棋可能是最简单的棋类游戏了,它简单到了成年人之间玩几乎总是平局的地步.因此,这个游戏貌似最多只能哄哄小孩子.不过,对井字棋游戏中所有可能的情况进行一番细致的分析,你会发现一个你或许不会料到的惊人结论——先手的最优策略不是稳坐正中央,而是先占一个角! 几年前,果壳网小编曾经自己动手写过一个和人下井字棋的电脑程序,运行之后却发现电脑先走时总爱把第一步棋下在角上:检查程序代码许久后才意识到,电脑程序可能并没有问题.人们往往有一个

Pascal小游戏 井字棋

一个很经典的井字棋游戏 Pascal源码Chaobs奉上 注意:1.有的FP版本不支持汉语,将会出现乱码.2.别想赢电脑了,平手不错了. 井字过三关: program TicTacToe; uses crt; var a:Array [1..3] of Array [1..3] of char; b:Array [1..3] of Array [1..3] of integer; i,n,g,e,p:integer; t:text; c:char; o:integer; r:integer; s

[游戏学习22] MFC 井字棋 双人对战

>_<:太多啦,感觉用英语说的太慢啦,没想到一年做的东西竟然这么多.....接下来要加速啦! >_<:注意这里必须用MFC和前面的Win32不一样啦! >_<:这也是第一次出现MFC游戏,其框架和逻辑的写法和Win32有很大的区别,建议先看一下MFC的基础再理解代码: >_<:TicTac.h 1 #define EX 1 //该点左鼠标 2 #define OH 2 //该点右鼠标 3 4 class CMyApp : public CWinApp 5 {

C++井字棋游戏,DOS界面版

据说有一个能保证不败的算法.明天看看先再写个PVC版的. 正题.今天无聊写了个井字棋游戏,顺便逐渐让自己习惯良好的代码风格,放上来给新手学习学习. jzq2.cpp /* N字棋游戏PVP版,DOS版 本棋盘可扩充,仅仅需调整检測条件就可以,其它接口不需改变. 非人机对战型.PVP类型; @author:天下无双 @date:2014-5-25 @version:1.0 */ #include <iostream> #include <string> #define INVALID

井字棋游戏升级版 - TopTicTacToe项目 简介

一.游戏简介 井字棋是一款世界闻名的游戏,不用我说,你一定知道它的游戏规则. 这款游戏简单易学,玩起来很有意思,不过已经证明出这款游戏如果两个玩家都足够聪明的话, 是很容易无法分出胜负的,即我们得到的结果是平局. 我们的项目,就是井字棋游戏的升级版!游戏有九个小棋盘,每个棋盘构成了整体布局的一部分,要想获得游戏的胜利,你要把握整个局势才行! 二.亮点 创新 传统的井字棋只有九个格,玩法简单,但是变化也相当有限.初玩者很容易被这新颖的游戏吸引住,但是玩了一段时间后,很容易摸出规律,很轻松达到不败的

『HTML5实现人工智能』小游戏《井字棋》发布,据说IQ上200才能赢【算法&amp;代码讲解+资源打包下载】

一,什么是TicTacToe(井字棋) 本游戏为在下用lufylegend开发的第二款小游戏.此游戏是大家想必大家小时候都玩过,因为玩它很简单,只需要一张草稿纸和一只笔就能开始游戏,所以广受儿童欢迎.可能我说了半天,对它名字不熟悉的朋友也不懂我在说神马.那没关系,我就引用Wiki(维基百科)的介绍作为大家对它名字的认识,顺便也勾起我们儿时的回忆: 井字棋,大陆.台湾又称为井字游戏.圈圈叉叉:另外也有打井游戏.OX棋的称呼,香港多称井字过三关.过三关,是种纸笔游戏.两个玩家,一个打圈(O),一个打

人工智能博弈树算法做的井字棋游戏

不会输,超碉!井字棋这个游戏真是太无聊啦! 算法大概就是,有一个给状况进行估价的函数,深搜每种状况,假设每个人都按对自己最有利的方式走(假设玩家也是不傻),最后让电脑走出最有利的一步. 代码: 1 //#pragma comment(linker, "/STACK:102400000,102400000") 2 #include<cstdio> 3 #include<cmath> 4 #include<iostream> 5 #include<

井字棋

题目描述 对于一个给定的井字棋棋盘,请设计一个高效算法判断当前玩家是否获胜. 给定一个二维数组board,代表当前棋盘,其中元素为1的代表是当前玩家的棋子,为0表示没有棋子,为-1代表是对方玩家的棋子. 测试样例: [[1,0,1],[1,-1,-1],[1,-1,0]] 返回:true //判断每行每列每个对角线上的值是否都为1 class Board { public: bool checkWon(vector<vector<int> > board) { int len =

程序设计入门—Java语言 第五周编程题 2井字棋(5分)

2 井字棋(5分) 题目内容: 嗯,就是视频里说的那个井字棋.视频里说了它的基本思路,现在,需要你把它全部实现出来啦. 你的程序先要读入一个整数n,范围是[3,100],这表示井字棋棋盘的边长.比如n=3就表示是一个3x3的棋盘.然后,要读入n行,每行n个数字,每个数字是1或0,依次表示[0,0]到[n-1,n-1]位置上的棋子.1表示X,0表示O(大写字母O). 你的程序要判断其中是否存在某一方获胜,获胜的条件是存在整行或整列或整条对角线或整条反对角线上是相同的棋子.如果存在,则输出代表获胜一