[javascript]js的五子棋让红蓝双方自己跟自己下棋

news2024/11/20 18:46:00

运行效果(这是未分出胜负):

 

 这是分出胜负:

 

 源代码,把下边的代码放到1.html,然后用浏览器打开,就可以,然后刷新网页:

<!DOCTYPE html>
<html>
    <body>
        <h3>AI五子棋游戏,这个程序有个非常大的Bug,你找到了吗?doge</h3>
        <canvas id="chess" width="450px" height="450px"></canvas>
        <script>
            var chressBord = []; //棋盘当前落子后的记录,是否已经落子,是哪方落子		
            var wins = [];  //存放所有5个棋子在一条线上所有可能性,第一维存放y, 第二维存放x,第三维存放当前的可能性编号
            var count = 0; //赢法总数量
            var blueWin = []; //我们赢法的统计数组
            var redWin = []; //计算机赢法的统计数组
            var chess = document.getElementById("chess");
            var context = chess.getContext('2d');
			var x = 0;
			var y = 0;
 
            for(var i = 0; i < 15; i++)
			{
                chressBord[i] = [];
                wins[i] = [];
                for(var j = 0; j < 15; j++)
				{
                    chressBord[i][j] = 0;
                    wins[i][j] = [];
                }
            }
			
            //横线赢法
            for(var i = 0; i < 15; i++)
                for(var j = 0; j < 11; j++,count++)
                    for(var k = 0; k < 5; k++)
                        wins[i][j+k][count] = true;
			
            //竖线赢法
            for(var i = 0; i < 15; i++)
                for(var j = 0; j < 11; j++,count++)
                    for(var k = 0; k < 5; k++)
                        wins[j+k][i][count] = true;
			
            //正斜线赢法
            for(var i = 0; i < 11; i++)
                for(var j = 0; j < 11; j++,count++)
                    for(var k = 0; k < 5; k++)
                        wins[i+k][j+k][count] = true;
			
            //反斜线赢法
            for(var i = 0; i < 11; i++)  
                for(var j = 14; j > 3; j--,count++)
                    for(var k = 0; k < 5; k++)
                        wins[i+k][j-k][count] = true;
			
            for(var i = 0; i < count; i++)
			{
                blueWin[i] = 0; //这个数组很精髓,记录下棋后每一个位置在每种赢法的得分
                redWin[i] = 0;
            }
						
			//程序运行入口
			function main() 
			{				
				var role = "red";//两个下棋的角色不断切换
				x = Math.floor(Math.random() * 15);	//第一步随机x,y				
				y = Math.floor(Math.random() * 15);	
										
				for (i = 0; i < 225; i++)
				{					
					if(chressBord[x][y] == 0) //computerAI计算后的x,y坐标还没有落子
					{	
						if (role == "red")
						{
							Move(x,y,role); //落子
							chressBord[x][y] = 1; //red玩家棋盘位置占位
							CheckWin(x,y,role, redWin);  //计算落子后是否获胜,这里也很精髓,递归思想
						}
						else
						{
							Move(x,y,role); //落子
							chressBord[x][y] = 2; //blue玩家棋盘位置占位
							CheckWin(x,y,role, blueWin);  //计算落子后是否获胜,这里也很精髓,递归思想
						}
						
						role = (role == "blue") ? "red" : "blue"; //落子后切换角色
					}
					computerAI(); //计算下一步落子的x,y坐标
				}
			}
			
            // 计算机下棋,找玩家最容易赢的位置或者电脑最容易赢的位置
            function computerAI()
			{
                var palyer1Score = []; //这两个数组存放的内容会不断变化,随着计算双方相互切换
                var palyer2Score = [];
                var max = 0;
                var u = 0, v = 0;
                for(var i = 0; i < 15; i++)
				{
                    palyer1Score[i] = [];
                    palyer2Score[i] = [];
                    for(var j = 0; j < 15; j++)
					{
                        palyer1Score[i][j] = 0;
                        palyer2Score[i][j] = 0;
                    }
                }
				
				//找落子赢的概率最大坐标
                for(var i = 0; i < 15; i++)
				{
                    for(var j = 0; j < 15; j++)
					{						
						for(var k = 0; k < count; k++) //遍历到i,j这个坐标时,计算谁的得分更高
						{
							if(chressBord[i][j] != 0 || !wins[i][j][k]) //当前i,j坐标还没落子
								continue;
							
							switch(blueWin[k])
							{
								case 1: palyer1Score[i][j] += 200; break;
								case 2: palyer1Score[i][j] += 400; break;
								case 3: palyer1Score[i][j] += 2000; break;
								case 4: palyer1Score[i][j] += 10000; break;
							}
							
							switch(redWin[k])
							{
								case 1: palyer2Score[i][j] += 220; break;
								case 2: palyer2Score[i][j] += 420; break;
								case 3: palyer2Score[i][j] += 2100; break;
								case 4: palyer2Score[i][j] += 20000; break;
							}
						}
						
						if(palyer1Score[i][j] > max) //如果玩家落子的分数多,就替换
						{
							max  = palyer1Score[i][j];
							u = i;
							v = j;
						}
						else if(palyer1Score[i][j] == max)  //如果玩家落子的分数跟原来最多分数一样多
						{
							if(palyer2Score[i][j] > palyer2Score[u][v]) //如果电脑在i,j落子的分数比u,v的分数多,就替换
							{
								u = i;
								v = j;    
							}
						}
						
						if(palyer2Score[i][j] > max) //如果电脑下棋新位置分数比原来的多,就替换
						{
							max  = palyer2Score[i][j];
							u = i;
							v = j;
						}
						else if(palyer2Score[i][j] == max) //如果电脑下棋新位置分数跟原来的一样多
						{
							if(palyer1Score[i][j] > palyer1Score[u][v]) //如果玩家落子的分数多,就准备把玩家最好的位置占掉
							{
								u = i;
								v = j;    
							}
						}
                    }
                }
				x = u;
				y = v;
            }
			            
            function Move(i,j,Role) //落子
			{
                context.beginPath();
                context.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI);// 画圆
                context.closePath();    
                context.fillStyle = Role;
                context.fill(); //填充颜色				
            }
			
			function CheckWin(i, j, Role, WinArray)
			{			
				for(var k = 0; k < count; k++)
					if(wins[i][j][k]) // 将可能赢的情况都加1
					{
						WinArray[k]++; //第k这个位置要注意,每一个k代表一种赢的可能性,并且前边的x,y代表第K种赢法x,y的坐标对,这个对于理解算法是否赢很重要
						if(WinArray[k] >= 5)
						{
							alert(Role + ': 恭喜,你赢了!')
							throw new Error(Role + " player win!!");;
						}
					}
			}			
            
            function drawChessBoard()
			{
                for(var i = 0; i < 15; i++)
				{
                    context.moveTo(15 + i * 30 , 15);
                    context.lineTo(15 + i * 30 , 435);
                    context.moveTo(15 , 15 + i * 30);
                    context.lineTo(435 , 15 + i * 30);
                    context.stroke();
                }
            }
			
            drawChessBoard(); // 画棋盘
			main();
        </script>
    </body>
</html>

 

import javax.swing.*;
import java.awt.*;

public class FiveInOne extends JFrame {
    static Graphics graphics;
    private final Image buffer;  // 双缓冲图像
    private final Graphics bufferGraphics;  // 双缓冲图像的绘图上下文
    int player;
    int[][] chessBoard;
    int[][][] wins;
    int count;
    int[] blueWin;
    int[] redWin;
    int x, y;
    Color c;

    FiveInOne()
    {
        setLayout(null);
        setSize(700, 900);
        setLocationRelativeTo(null);
        setVisible(true);
        graphics = getContentPane().getGraphics();
        buffer = createImage(700, 900);
        bufferGraphics = buffer.getGraphics();
        chessBoard = new int[15][15];
        wins = new int[15][15][573];
        blueWin = new int[573];
        redWin = new int[573];

        player = 1;
        c = new Color(255,0,0);
        bufferGraphics.setColor(new Color(0,0,0));

        drawchessBoard();

        System.out.println("count: " +String.valueOf(count));
        generateWinArray();
        main2();
    }

    void generateWinArray()
    {
        //横线赢法
        for(int i = 0; i < 15; i++)
            for(int j = 0; j < 11; j++,count++)
                for(int k = 0; k < 5; k++)
                    wins[i][j+k][count] = 1;

        //竖线赢法
        for(int i = 0; i < 15; i++)
            for(int j = 0; j < 11; j++,count++)
                for(int k = 0; k < 5; k++)
                    wins[j+k][i][count] = 1;

        //正斜线赢法
        for(int i = 0; i < 11; i++)
            for(int j = 0; j < 11; j++,count++)
                for(int k = 0; k < 5; k++)
                    wins[i+k][j+k][count] = 1;

        //反斜线赢法
        for(int i = 0; i < 11; i++)
            for(int j = 14; j > 3; j--,count++)
                for(int k = 0; k < 5; k++)
                    wins[i+k][j-k][count] = 1;
    }

    void main2()
    {
        String role = "red";//两个下棋的角色不断切换
        x = (int) Math.floor(Math.random() * 15);	//第一步随机x,y
        y = (int) Math.floor(Math.random() * 15);

        for (int i = 0; i < 225; i++)
        {
            if(chessBoard[x][y] == 0) //computerAI计算后的x,y坐标还没有落子
            {
                if (role.equals("red"))
                {
                    drawChess(x,y); //落子
                    chessBoard[x][y] = 1; //red玩家棋盘位置占位
                    CheckWin(x,y,role, redWin);  //计算落子后是否获胜,这里也很精髓,递归思想
                }
                else
                {
                    drawChess(x,y); //落子
                    chessBoard[x][y] = 2; //blue玩家棋盘位置占位
                    CheckWin(x,y,role, blueWin);  //计算落子后是否获胜,这里也很精髓,递归思想
                }

                role = (role == "blue") ? "red" : "blue"; //落子后切换角色
            }

            computerAI(); //计算下一步落子的x,y坐标
            System.out.println("x: " + x + ", y: " + y);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    void computerAI()
    {
        int[][] palyer1Score = new int[15][15]; //这两个数组存放的内容会不断变化,随着计算双方相互切换
        int[][] palyer2Score = new int[15][15];
        int max = 0;
        int u = 0, v = 0;

        //找落子赢的概率最大坐标
        for(int i = 0; i < 15; i++)
        {
            for(int j = 0; j < 15; j++)
            {
                for(int k = 0; k < count; k++) //遍历到i,j这个坐标时,计算谁的得分更高
                {
                    if(chessBoard[i][j] != 0 || 0 == wins[i][j][k]) //当前i,j坐标还没落子
                        continue;

                    switch(blueWin[k])
                    {
                        case 1: palyer1Score[i][j] += 200; break;
                        case 2: palyer1Score[i][j] += 400; break;
                        case 3: palyer1Score[i][j] += 2000; break;
                        case 4: palyer1Score[i][j] += 10000; break;
                    }

                    switch(redWin[k])
                    {
                        case 1: palyer2Score[i][j] += 220; break;
                        case 2: palyer2Score[i][j] += 420; break;
                        case 3: palyer2Score[i][j] += 2100; break;
                        case 4: palyer2Score[i][j] += 20000; break;
                    }
                }

                if(palyer1Score[i][j] > max) //如果玩家落子的分数多,就替换
                {
                    max  = palyer1Score[i][j];
                    u = i;
                    v = j;
                }
                else if(palyer1Score[i][j] == max)  //如果玩家落子的分数跟原来最多分数一样多
                {
                    if(palyer2Score[i][j] > palyer2Score[u][v]) //如果电脑在i,j落子的分数比u,v的分数多,就替换
                    {
                        u = i;
                        v = j;
                    }
                }

                if(palyer2Score[i][j] > max) //如果电脑下棋新位置分数比原来的多,就替换
                {
                    max  = palyer2Score[i][j];
                    u = i;
                    v = j;
                }
                else if(palyer2Score[i][j] == max) //如果电脑下棋新位置分数跟原来的一样多
                {
                    if(palyer1Score[i][j] > palyer1Score[u][v]) //如果玩家落子的分数多,就准备把玩家最好的位置占掉
                    {
                        u = i;
                        v = j;
                    }
                }
            }
        }
        x = u;
        y = v;
    }

    void CheckWin(int i, int j, String Role, int[] WinArray)
    {
        for(int  k = 0; k < count; k++)
            if(wins[i][j][k] == 1) // 将可能赢的情况都加1
            {
                WinArray[k]++; //第k这个位置要注意,每一个k代表一种赢的可能性,并且前边的x,y代表第K种赢法x,y的坐标对,这个对于理解算法是否赢很重要
                if(WinArray[k] >= 5)
                {
                    //alert(Role + ': 恭喜,你赢了!')
                    System.out.println(Role + " player win!!");
                    break;
                }
            }
    }

    void drawChess(int mouse_x, int mouse_y)
    {
        mouse_x = 15 + mouse_x * 30; //把一个区域的点击放到一个点
        mouse_y = 15 + mouse_y * 30;

        if (player == 1)
        {
            c = new Color(255,0,0);
            player = 2;
        }
        else
        {
            c = new Color(0,0,255);
            player = 1;
        }

        bufferGraphics.setColor(c);
        bufferGraphics.fillArc(mouse_x - 12, mouse_y - 38, 20, 20, 0, 360);

        graphics.drawImage(buffer, 0, 0, null);
    }

    void drawchessBoard()
    {
        for (int i = 0; i < 15; i++)
        {
            bufferGraphics.drawLine(15 + i * 30, 15, 15 + i * 30, 435);
            bufferGraphics.drawLine(15, 15 + i * 30, 435, 15 + i * 30);
        }
    }

    //这个程序有个非常大的Bug,你找到了吗?
    public static void main(String[] args) {
        new FiveInOne();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2244192.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go语言中AES加密算法的实现与应用

一、前言 在当今的软件开发领域&#xff0c;数据安全至关重要。加密技术作为保护数据机密性的关键手段&#xff0c;被广泛应用于各个方面。AES&#xff08;高级加密标准&#xff09;作为一种对称加密算法&#xff0c;以其高效性和安全性在众多加密场景中占据重要地位。本文将详…

单片机GPIO中断+定时器 实现模拟串口接收

单片机GPIO中断定时器 实现模拟串口接收 解决思路代码示例 解决思路 串口波特率9600bps,每个bit约为1000000us/9600104.16us&#xff1b; 定时器第一次定时时间设为52us即半个bit的时间&#xff0c;其目的是偏移半个bit时间&#xff0c;之后的每104us采样并读取1bit数据。使得…

近几年新笔记本重装系统方法及一些注意事项

新笔记本怎么重装系统&#xff1f; 近几年的新笔记本默认开启了raid on模式或vmd选项&#xff0c;安装过程中会遇到问题&#xff0c;新笔记本电脑重装自带的系统建议采用u盘方式安装&#xff0c;默认新笔记本有bitlocker加密机制&#xff0c;如果采用一键重装系统或硬盘方式安装…

【支持向量机(SVM)】:算法原理及核函数

文章目录 1 SVM算法原理1.1 目标函数确定1.2 约束条件优化问题转换1.3 对偶问题转换1.4 确定超平面1.5 计算举例1.6 SVM原理小节 2 SVM核函数2.1 核函数的作用2.2 核函数分类2.3 高斯核函数2.3 高斯核函数API2.4 超参数 γ \gamma γ 1 SVM算法原理 1.1 目标函数确定 SVM思想…

自动驾驶系列—告别眩光烦恼:智能大灯如何守护夜间行车安全

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

无插件H5播放器EasyPlayer.js RTSP播放器chrome/edge等浏览器如何使用独立显卡

随着互联网的快速发展和视频内容的日益丰富&#xff0c;HTML5视频播放器已成为网页视频播放的主流技术。EasyPlayer.js播放器视频播放技术不仅支持多种浏览器和设备&#xff0c;还提供了丰富的功能和更好的用户体验。 那么chrome/edge等浏览器如何使用独立显卡&#xff1f; 在…

@Autowired 和 @Resource思考(注入redisTemplate时发现一些奇怪的现象)

1. 前置知识 Configuration public class RedisConfig {Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template new RedisTemplate<>();template.setConnectionFactory(facto…

STM32低功耗设计NFC与无线距离感应智能钥匙扣-分享

目录 目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 智能钥匙扣作为一种小巧而实用的智能设备&#xff0c;凭借其便携性…

微服务day09

DSL查询 快速入门 GET /items/_search {"query": {"match_all": {}} } 叶子查询 GET /items/_search {"query": {"match_all": {}} }GET /items/_search {"query": {"multi_match": {"query": "脱…

Golang语言整合jwt+gin框架实现token

1.下载jwt go get -u github.com/dgrijalva/jwt-go2.新建生成token和解析token文件 2.1 新建common文件夹和jwtConfig文件夹 新建jwtconfig.go文件 2.2 jwtconfig.go文件代码 /* Time : 2021/8/2 下午3:03 Author : mrxuexi File : main Software: GoLand */ package jwtC…

Orcad 输出有链接属性的PDF

安装adobe pdf安装Ghostscript修改C:\Cadence\SPB_16.6\tools\capture\tclscripts\capUtils\capPdfUtil.tcl ​ 设置默认打印机为 Adobe PDF ​ 将Ghostscript的路径修改正确 打开cadence Orcad &#xff0c;accessories->candece Tcl/Tk Utilities-> Utilities->PD…

Java读取WPS excel.xlsx嵌入图片

1. 背景&原因 经常有读取Excel文件的需求&#xff0c;开发者大多使用apache poi或者基于此的工具进行excel内容读取&#xff0c;前不久遇到了一个需求&#xff0c;读取每一行内容&#xff0c;但每一行都包含图片文件&#xff0c;发现无法通过已封装的工具读取excel的图片内…

Elasticsearch 查询时 term、match、match_phrase、match_phrase_prefix 的区别

Elasticsearch 查询时 term、match、match_phrase、match_phrase_prefix 的区别 keyword 与 text 区别term 查询match 查询match_phrase 查询match_phrase_prefix 查询写在最后 在讲述 es 查询时 term、match、match_phrase、match_phrase_prefix 的区别之前&#xff0c;先来了…

ERROR TypeError: AutoImport is not a function

TypeError: AutoImport is not a function 原因&#xff1a;unplugin-auto-import 插件版本问题 Vue3基于Webpack&#xff0c;在vue.config.js中配置 当unplugin-vue-components版本小于0.26.0时&#xff0c;使用以下写法 const { defineConfig } require("vue/cli-se…

iOS 18 导航栏插入动画会导致背景短暂变白的解决

问题现象 在最新的 iOS 18 系统中,如果我们执行导航栏的插入动画,可能会造成导航栏背景短暂地变为白色: 如上图所示:我们分别向主视图和 Sheet 弹出视图的导航栏插入了消息,并应用了动画效果。可以看到,前者的导航栏背景会在消息插入那一霎那“变白”,而后者则没有任何…

PHP屏蔽海外IP的访问页面(源代码实例)

PHP屏蔽海外IP的访问页面&#xff08;源代码实例&#xff09;&#xff0c;页面禁用境外IP地址访问 <?php/*** 屏蔽海外ip访问* 使用ip2long函数得到ip转为整数的值&#xff0c;判断值是否在任一一个区间中* 以下是所有国内ip段* 调用方法&#xff1a;IschinaIp($ALLIPS)* …

SpringBoot 增量部署发布(第2版)

一、背景介绍 书接上一篇《SpringBoot 增量部署发布_springboot增量部署-CSDN博客》&#xff0c;上一篇内容实现了将静态资源与jar分离&#xff0c;但是即使是打包成**-exec.jar&#xff0c;解压jar文件&#xff0c;可以看到里面包含了static&#xff0c;resource目录&#xf…

单片机智能家居火灾环境安全检测-分享

目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 电路图采用Altium Designer进行设计&#xff1a; 三、实物设计图 四、程序源代码设计 五、获取资料内容 前言 传统的火灾报警系统大多依赖于简单的烟雾探测器或温度传感器&#xff0c;…

C++:指针和引用

指针的基础 数据在内存当中是怎么样被存储的 数据在内存中的存储方式取决于数据的类型和计算机的体系结构 基本数据类型 整数类型&#xff1a;整数在内存中以二进制补码的形式存储。对于有符号整数&#xff0c;最高位为符号位&#xff0c;0 表示正数&#xff0c;1 表示负数。…

MySQL更换瀚高语法更换

MySQL更换瀚高语法更换 一、前言二、语句 一、前言 水一篇,mysql更换瀚高之后&#xff0c;一些需要更换的语法介绍 > 二、语句 MySQL瀚高MySQL用法瀚高用法说明ifnull(x,y)coalesce(x,y)相同相同用于检查两个表达式并返回第一个非空表达式。如果第一个表达式不是 NULL&…