QT-五子棋游戏

QT-五子棋游戏

  • 一、演示效果
  • 二、核心代码
  • 三、下载链接


一、演示效果

请添加图片描述

二、核心代码

#include "GameModel.h"
#include <time.h>
#include <stdlib.h>GameModel::GameModel(){}void GameModel::startGame(GameType type){gameType = type;//初始化棋盤gameMapVec.clear();for(int i=0;i<BOARD_GRAD_SIZE;i++){std::vector<int> lineBoard;for(int j=0;j<BOARD_GRAD_SIZE;j++){lineBoard.push_back(0);}gameMapVec.push_back(lineBoard);}//如果是AI模式,需要初始化評分數組if(gameType == AI){scoreMapVec.clear();for(int i=0;i<BOARD_GRAD_SIZE;i++){std::vector<int> lineScores;for(int j=0;j<BOARD_GRAD_SIZE;j++){lineScores.push_back(0);}scoreMapVec.push_back(lineScores);}}//輪到黑方下棋為true,反之playerFlag = true;
}void GameModel::actionByPerson(int row, int col){updateGameMap(row,col);
}
void GameModel::updateGameMap(int row, int col){if(playerFlag){gameMapVec[row][col] = 1;}else{gameMapVec[row][col] = -1;}//換手playerFlag = !playerFlag;
}bool GameModel::isWin(int row,int col){/*判斷下棋點的水平、垂直、左斜、右斜方中* 有沒有5子相連的情況,如有則贏*/for(int i=0;i<5;i++){//先判斷水平方向是否有5子相連if(row>0 && row<BOARD_GRAD_SIZE &&col-i>0 && col-i+4<BOARD_GRAD_SIZE &&gameMapVec[row][col-i] == gameMapVec[row][col-i+1] &&gameMapVec[row][col-i] == gameMapVec[row][col-i+2] &&gameMapVec[row][col-i] == gameMapVec[row][col-i+3] &&gameMapVec[row][col-i] == gameMapVec[row][col-i+4]){return true;}//先判斷垂直方向是否有5子相連if(row-i>0 && row-i+4<BOARD_GRAD_SIZE &&col>0 && col<BOARD_GRAD_SIZE &&gameMapVec[row-i][col] == gameMapVec[row-i+1][col] &&gameMapVec[row-i][col] == gameMapVec[row-i+2][col] &&gameMapVec[row-i][col] == gameMapVec[row-i+3][col] &&gameMapVec[row-i][col] == gameMapVec[row-i+4][col]){return true;}//先判斷"/"方向是否有5子相連,左下->右上if(row-i>0 && row-i+4<BOARD_GRAD_SIZE &&col+i-4>0 && col+i<BOARD_GRAD_SIZE &&gameMapVec[row-i][col+i] == gameMapVec[row-i+1][col+i-1] &&gameMapVec[row-i][col+i] == gameMapVec[row-i+2][col+i-2] &&gameMapVec[row-i][col+i] == gameMapVec[row-i+3][col+i-3] &&gameMapVec[row-i][col+i] == gameMapVec[row-i+4][col+i-4]){return true;}//先判斷"\"方向是否有5子相連,右下->左上if(row-i>0 && row-i+4<BOARD_GRAD_SIZE &&col-i>0 && col-i+4<BOARD_GRAD_SIZE &&gameMapVec[row-i][col-i] == gameMapVec[row-i+1][col-i+1] &&gameMapVec[row-i][col-i] == gameMapVec[row-i+2][col-i+2] &&gameMapVec[row-i][col-i] == gameMapVec[row-i+3][col-i+3] &&gameMapVec[row-i][col-i] == gameMapVec[row-i+4][col-i+4]){return true;}}return false;
}//計算每格分數函數
void GameModel::calculateScore(){//統計玩家或者電腦連成的子int personNum = 0; //玩家連成子的個數int botNum = 0;   //AI連成子的個數int emptyNum = 0;   //各方向空白位的個數//清空評分數組scoreMapVec.clear();for(int i=0;i<BOARD_GRAD_SIZE;i++){std::vector<int> lineScores;for(int j=0;j<BOARD_GRAD_SIZE;j++){lineScores.push_back(0);}scoreMapVec.push_back(lineScores);}//計分/*計分個人理解:* 遍歷每一個格子,判斷哪些是空白的點(即為0的點),以該點為中心,判斷周圍的八個點向外延伸的四格裡,* 有多少個是黑子、白子、空白,以此作為依據來評分。下方算法是以守為主,所以守的分數>攻的分數*/for(int row=0;row<BOARD_GRAD_SIZE;row++){for(int col=0;col<BOARD_GRAD_SIZE;col++){//空白點才算if(row>0 && col>0 && gameMapVec[row][col]==0){//遍歷周圍8個方向for(int y=-1;y<=1;y++){for(int x=-1;x<=1;x++){//重置personNum = 0;botNum = 0;emptyNum = 0;//原坐標不算if(!(y==0 && x==0)){//每個方向延伸4個子//對玩家黑子評分(正反兩個方向)for(int i=1;i<=4;i++){if(row+i*y>0 && row+i*y<BOARD_GRAD_SIZE &&col+i*x>0 && col+i*x<BOARD_GRAD_SIZE &&gameMapVec[row+i*y][col+i*x]==1){ //真人玩家的子personNum++;}else if(row+i*y>0 && row+i*y<BOARD_GRAD_SIZE &&col+i*x>0 && col+i*x<BOARD_GRAD_SIZE &&gameMapVec[row+i*y][col+i*x]==0){ //空白位emptyNum++;break;}else{ //出邊界,或有白子break;}}for(int i=1;i<=4;i++){if(row-i*y>0 && row-i*y<BOARD_GRAD_SIZE &&col-i*x>0 && col-i*x<BOARD_GRAD_SIZE &&gameMapVec[row-i*y][col-i*x]==1){ //真人玩家的子personNum++;}else if(row-i*y>0 && row-i*y<BOARD_GRAD_SIZE &&col-i*x>0 && col-i*x<BOARD_GRAD_SIZE &&gameMapVec[row-i*y][col-i*x]==0){ //空白位emptyNum++;break;}else{ //出邊界,或有白子break;}}if(personNum == 1){                 //殺2scoreMapVec[row][col]+=10;}else if(personNum == 2){           //殺3if(emptyNum == 1)scoreMapVec[row][col]+=30;else if(emptyNum == 2)scoreMapVec[row][col]+=40;}else if(personNum == 3){           //殺4//量變空位不一樣,優先級不一樣if(emptyNum == 1)scoreMapVec[row][col]+=60;else if(emptyNum == 2)scoreMapVec[row][col]+=110;}else if(personNum == 4){           //殺5scoreMapVec[row][col]+=10100;}//進行一次清空emptyNum = 0;//對AI白子評分for(int i=1;i<=4;i++){if(row+i*y>0 && row+i*y<BOARD_GRAD_SIZE &&col+i*x>0 && col+i*x<BOARD_GRAD_SIZE &&gameMapVec[row+i*y][col+i*x]==-1){ //AI的子botNum++;}else if(row+i*y>0 && row+i*y<BOARD_GRAD_SIZE &&col+i*x>0 && col+i*x<BOARD_GRAD_SIZE &&gameMapVec[row+i*y][col+i*x]==0){ //空白位emptyNum++;break;}else{ //出邊界break;}}for(int i=1;i<=4;i++){if(row-i*y>0 && row-i*y<BOARD_GRAD_SIZE &&col-i*x>0 && col-i*x<BOARD_GRAD_SIZE &&gameMapVec[row-i*y][col-i*x]==-1){ //AI的子botNum++;}else if(row-i*y>0 && row-i*y<BOARD_GRAD_SIZE &&col-i*x>0 && col-i*x<BOARD_GRAD_SIZE &&gameMapVec[row-i*y][col-i*x]==0){ //空白位emptyNum++;break;}else{ //出邊界break;}}if(botNum == 0){scoreMapVec[row][col]+=5;  //活1}else if(botNum == 1){scoreMapVec[row][col]+=10; //活2}else if(botNum == 2){         //活3if(emptyNum == 1)scoreMapVec[row][col]+=25;else if(emptyNum == 2)scoreMapVec[row][col]+=50;}else if(botNum == 3){         //活4if(emptyNum == 1)scoreMapVec[row][col]+=55;else if(emptyNum == 2)scoreMapVec[row][col]+=100;}else if(botNum >= 4){         //活5scoreMapVec[row][col]+=20000;}}}}}}}}
//AI執行下棋
void GameModel::actionByAI(int &clickRow,int &clickCol){//計算評分calculateScore();//從評分中找出最大分數的位置int maxScore = 0;std::vector<std::pair<int,int>> maxPoints;for(int row = 1;row<BOARD_GRAD_SIZE;row++){for(int col = 1;col<BOARD_GRAD_SIZE;col++){//前提是這個坐標是空的if(gameMapVec[row][col] == 0){if(scoreMapVec[row][col]>maxScore){     //找最大數和坐標maxPoints.clear();maxScore = scoreMapVec[row][col];maxPoints.push_back(std::make_pair(row,col));}else if(scoreMapVec[row][col] == maxScore){   //如果有多個最大值就將他們存儲起來,在後面的代碼隨機抽1個maxPoints.push_back(std::make_pair(row,col));}}}}//隨機落子,如果有多個點的話srand((unsigned)time(0));int index = rand()%maxPoints.size();std::pair<int,int> pointPair = maxPoints.at(index);clickRow = pointPair.first;clickCol = pointPair.second;updateGameMap(clickRow,clickCol);
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPainter>
#include <QMouseEvent>
#include <math.h>
#include <QMessageBox>
#include <QTimer>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);this->setFixedSize(MARGIN*2+BLOCK_SIZE*BOARD_GRAD_SIZE,MARGIN*2+BLOCK_SIZE*BOARD_GRAD_SIZE);initGame();}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::paintEvent(QPaintEvent* event){QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing); //設置抗鋸齒for(int i=0;i<BOARD_GRAD_SIZE+1;i++){//從左到右,第(i+1)條豎線painter.drawLine(MARGIN+BLOCK_SIZE*i,MARGIN,MARGIN+BLOCK_SIZE*i,this->height()-MARGIN);//從上到下,第(i+1)條橫線painter.drawLine(MARGIN,MARGIN+BLOCK_SIZE*i,this->width()-MARGIN,MARGIN+BLOCK_SIZE*i);}//繪製選中點QBrush brush;brush.setStyle(Qt::SolidPattern);//繪製落子標記(防止鼠標出框越界)if(clickPosRow>0 && clickPosRow<BOARD_GRAD_SIZE &&clickPosCol>0 && clickPosCol<BOARD_GRAD_SIZE &&game->gameMapVec[clickPosRow][clickPosCol]==0){if(game->playerFlag){brush.setColor(Qt::black);}else{brush.setColor(Qt::white);}painter.setBrush(brush);painter.drawRect(MARGIN+BLOCK_SIZE*clickPosCol-MARK_SIZE/2,MARGIN+BLOCK_SIZE*clickPosRow-MARK_SIZE/2,MARK_SIZE,MARK_SIZE);}for(int i=0;i<BOARD_GRAD_SIZE;i++){for(int j=0;j<BOARD_GRAD_SIZE;j++){if(game->gameMapVec[i][j]==1){brush.setColor(Qt::black);painter.setBrush(brush);painter.drawEllipse(MARGIN+BLOCK_SIZE*j-CHESS_RADIUS,MARGIN+BLOCK_SIZE*i-CHESS_RADIUS,CHESS_RADIUS*2,CHESS_RADIUS*2);}else if(game->gameMapVec[i][j]==-1){brush.setColor(Qt::white);painter.setBrush(brush);painter.drawEllipse(MARGIN+BLOCK_SIZE*j-CHESS_RADIUS,MARGIN+BLOCK_SIZE*i-CHESS_RADIUS,CHESS_RADIUS*2,CHESS_RADIUS*2);}}}//判斷輸嬴if(clickPosCol>0 && clickPosCol<BOARD_GRAD_SIZE &&clickPosRow>0 && clickPosRow<BOARD_GRAD_SIZE &&(game->gameMapVec[clickPosRow][clickPosCol]==1||game->gameMapVec[clickPosRow][clickPosCol]==-1)){  //代碼解析:game->gameMapVec[clickPosRow][clickPosCol]==1||game->gameMapVec[clickPosRow][clickPosCol]==-1,防止因為5個0(空白)相連也被判勝利if(game->isWin(clickPosRow,clickPosCol) && game->gameStatus == PLAYING){game->gameStatus = WIN;QString str;str = game->gameMapVec[clickPosRow][clickPosCol]==1?u8"黑棋":u8"白棋";QMessageBox::StandardButton btnValue = QMessageBox::information(this,u8"五子棋嬴家",str+u8"勝利");if(btnValue == QMessageBox::Ok){game->startGame(game_type);game->gameStatus = PLAYING;}}}
}
//初始化遊戲
void MainWindow::initGame(){game = new GameModel();QMessageBox::StandardButton select = QMessageBox::question(this,u8"選擇遊戲模式",u8"YES[玩家VS電腦]  NO[玩家VS玩家]");if(select == QMessageBox::Yes){game_type = AI;}else {game_type = MAN;}game->gameStatus = PLAYING;game->startGame(game_type);update();
}void MainWindow::mouseMoveEvent(QMouseEvent* event){//通過鼠標的hover確定落子的標記int x = event->x();int y = event->y();//棋盤邊緣不能落子if(x>=MARGIN+BLOCK_SIZE/2&&x<this->width()-MARGIN-BLOCK_SIZE/2&&y>=MARGIN+BLOCK_SIZE/2&&y<this->height()-MARGIN-BLOCK_SIZE/2){//獲取最近的左上角的點int col = (x-MARGIN)/BLOCK_SIZE;int row = (y-MARGIN)/BLOCK_SIZE;int leftTopPosX = MARGIN+BLOCK_SIZE*col;int leftTopPosY = MARGIN+BLOCK_SIZE*row;//根據距離算出合適的點擊位置,一共四個點,根據半徑距離選最近的clickPosRow = -1; //初始化最終值clickPosCol = -1;int len = 0;  //計算完後取整就可以了selectPos = false;//確定一個誤差在範圍內的點,且只可能確定一個出來//len:與左上角的點的距離len = sqrt((x-leftTopPosX)*(x-leftTopPosX)+(y-leftTopPosY)*(y-leftTopPosY));if(len<POS_OFFSET){clickPosRow = row;clickPosCol = col;if(game->gameMapVec[clickPosRow][clickPosCol]==0){selectPos = true;}}//len:與右上角的點的距離len = sqrt((x-leftTopPosX-BLOCK_SIZE)*(x-leftTopPosX-BLOCK_SIZE)+(y-leftTopPosY)*(y-leftTopPosY));if(len<POS_OFFSET){clickPosRow = row;clickPosCol = col+1;if(game->gameMapVec[clickPosRow][clickPosCol]==0){selectPos = true;}}//len:與左下角的點的距離len = sqrt((x-leftTopPosX)*(x-leftTopPosX)+(y-leftTopPosY-BLOCK_SIZE)*(y-leftTopPosY-BLOCK_SIZE));if(len<POS_OFFSET){clickPosRow = row+1;clickPosCol = col;if(game->gameMapVec[clickPosRow][clickPosCol]==0){selectPos = true;}}//len:與右下角的點的距離len = sqrt((x-leftTopPosX-BLOCK_SIZE)*(x-leftTopPosX-BLOCK_SIZE)+(y-leftTopPosY-BLOCK_SIZE)*(y-leftTopPosY-BLOCK_SIZE));if(len<POS_OFFSET){clickPosRow = row+1;clickPosCol = col+1;if(game->gameMapVec[clickPosRow][clickPosCol]==0){selectPos = true;}}}//存了坐標後也要重繪update();
}void MainWindow::mouseReleaseEvent(QMouseEvent* event){if(selectPos == false){return;}else{selectPos = false;}//由人來下棋chessOneByPerson();if(game_type == AI){ //人機模式//AI 下棋QTimer::singleShot(AI_THINK_TIME,this,SLOT(chessOneByAI()));}
}void MainWindow::chessOneByPerson(){if(clickPosRow!=-1 && clickPosCol!=-1 && game->gameMapVec[clickPosRow][clickPosCol]==0){//在遊戲的數據模型中落子game->actionByPerson(clickPosRow,clickPosCol);//播放落子音效//重繪update();}
}void MainWindow::chessOneByAI(){game->actionByAI(clickPosRow,clickPosCol);update();
}

三、下载链接

https://download.csdn.net/download/u013083044/89656663

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

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

相关文章

uniapp/vue如何实现一个子表单及子表单作用

子表单是一个辅助表单或一个表&#xff0c;它允许在主表单中添加多个行式项目&#xff0c;以处理与主记录相关联的多个辅助项目或数据。子表单在多种应用场景中发挥着重要作用&#xff0c;特别是在需要处理一对多关系的数据时。 以下是对子表单的详细解析&#xff1a; 定义与特…

90%的设计师都不知道的免抠图素材插件,水花免抠png素材轻松搞定!附保姆教程

你是否曾在设计中为绘制那些晶莹剔透的水花而苦恼&#xff1f;用PS太麻烦&#xff0c;细节根本抠不清楚&#xff1b;去素材网找&#xff0c;不是付费太高就是图案不满意&#xff01;可以试试千鹿设计助手的“AI免抠生成”插件&#xff0c;接下来我来分享一下我的一些使用过程和…

ardupilot开发 --- C嘎嘎 篇

长生不老&#xff1f;三界六道不就毁在这4个字上&#xff1f; 溜撒点一起上吧 cout和cin的使用&#xff0c;标准输入输出<< 和 >> 的使用数据类型&#xff08;函数&#xff09;模板的使用&#xff1a;命名空间的使用&#xff0c;std命名空间语句块new 的使用引用 &…

fiddler在软件测试中的使用(详细版)

1.抓包&#xff0c;辅助定位bug&#xff08;web中类似谷歌浏览器F12开发调试工具&#xff09; 合格的软件测试工程师&#xff0c;不仅仅需要能够发现bug&#xff0c;还需要能透过bug表象&#xff0c;分析出问题根本原因&#xff0c;从而提升bug的解决效率&#xff0c;通过fidd…

手机使用技巧:如何恢复Android手机不见的短信

在您的 Android 手机上丢失短信可能是一种令人沮丧的经历&#xff0c;尤其是在文本包含重要信息的情况下。幸运的是&#xff0c;有一些方法可以在Android上恢复已删除的短信。在这篇博文中&#xff0c;我们将讨论几种在Android手机上恢复已删除短信的方法。 为什么需要恢复Andr…

vue2版本空目录下创建新项目的方法2024

vue2版本空目录下创建新项目的方法2024 node -v npm -v vue -V 安装vue-cli 2.9版本的命令 npm install vue-cli -g 卸载vue2.x方法&#xff1a; npm uninstall vue-cli -g 设置 NPM 镜像 npm config set registry https://registry.npmmirror.com vue -V 报错时需设置环…

JVM的内存模型和垃圾回收

JVM内存区域 内存模型图&#xff1a; 堆 线程共享。所有的对象实例以及数组都要在堆上分配。回收器主要管理的对象。 它的目的是存放对象实例。同时它也是GC所管理的主要区域&#xff0c;因此常被称为GC堆&#xff0c;又由于现在收集器常使用分代算法&#xff0c;Java堆中还…

【Spring Cloud】Consul

官网介绍: Spring Cloud Consul该项目为Spring Boot应用程序提供了与Consul的集成,通过自动配置和绑定到Spring环境以及其他Spring编程模型习语。通过几个简单的注解,您可以在应用程序内部快速启用和配置常见模式,并使用基于Consul的组件构建大型分布式系统。提供的模式包括…

【网络编程】第十一章 数据链路层 - 以太网(MAC+MTU+ARP+MSS+RARP)

文章目录 重点链路层以太网MAC帧格式碰撞域MAC地址MAC地址和IP地址 MTU-最大传输单元MTU 对 IP 的影响MTU 对 UDP 的影响MTU 对 TCP 的影响-MSS ARP协议ARP协议的工作流程ARP请求的过程ARP应答的过程 ARP 缓存中间人攻击 RARP协议 重点 数据链路层的作用&#xff1a;两个设备 …

虚幻5|AI视力系统,听力系统,预测系统(2)听力系统

虚幻5|AI视力系统&#xff0c;听力系统&#xff0c;预测系统&#xff08;1&#xff09;视力系统-CSDN博客 一&#xff0c;把之前的听力系统&#xff0c;折叠成函数&#xff0c;复制粘贴一份改名为听力系统 1.小个体修改如下&#xff0c;把之前的视力系统改成听力系统 2.整体修…

解决Jasper Studio预览无数据源的问题:在Dataset and Query里面预览数据为空,但是浏览器访问接口,是存在数据的。

目录 1.1、错误描述 1.2、解决方案 1.1、错误描述 最近接触Jasper Studio报表开发比较多一些&#xff0c;遇到了很多的问题&#xff0c;其中有一个问题就是&#xff1a;在Jasper Studio中的Dataset and query里面预览数据&#xff0c;发现是空的&#xff0c;如下图所示&…

数据仓库ETL开发

在企业数字化转型的过程中&#xff0c;数据仓库已经成为了企业管理和决策的重要工具。数据仓库ETL开发是构建数据仓库的关键步骤之一&#xff0c;它可以帮助企业从源系统中抽取、清洗、转换和整合数据&#xff0c;方便企业进行管理和分析。本文将介绍如何高效实现数据仓库ETL开…

Spring底层机制环境搭建

文章目录 1.模块创建和依赖引入1.聚合模块&#xff0c;下面有一个myspring2.查看父模块是否管理了子模块3.myspring模块引入基本包 2.进行环境搭建1.目录概览2.UserController.java3.UserService.java4.UserDao.java5.AppMain.java6.beans.xml7.测试8.配置UserController.java为…

掌握电子邮件的艺术:使用 Mailbird 统一管理您的数字生活

在数字时代&#xff0c;电子邮件已成为我们沟通的骨干。无论是商务交流、家庭联络&#xff0c;还是订阅更新&#xff0c;我们几乎每天都在使用电子邮件。但随着账户数量的增加&#xff0c;管理这些账户变得日益复杂。如何有效地整合和优化您的电子邮件体验&#xff1f;Mailbird…

【PaperInFive-时间序列预测】TSMixer:用于时间序列预测的全MLP架构(谷歌)

全文总结&#xff1a;本文研究了线性模型用于时间序列预测的能力&#xff0c;提出了时间序列混合器(TSMixer)&#xff0c;一种通过堆叠多层感知器(mlp)设计的新架构。TSMixer在时间和特征维度上交替应用mlp&#xff0c;在概念上对应于时间混合和特征混合操作&#xff0c;有效地…

AI开发者大赛 | 6道算法赛题上新

2024 AI开发者大赛正在如火如荼地进行着&#xff0c;本届比赛吸引了全球范围内的众多优秀开发者参与其中&#xff0c;用代码书写未来&#xff0c;用算法改变世界。 如今&#xff0c;算法赛新一批赛题上线&#xff0c;无论是初学者还是资深开发者&#xff0c;你都可以在2024 AI…

ClickHouse集群的安装

目录 1.clickhouse中文文档地址 2.centos安装部署 2.1采用tgz的方式安装 2.2修改配置文件 2.3修改数据目录 2.4创建角色和目录 3 集群安装 3.1配置文件修改 3.2启动zookeeper 3.3启动clickhouse-server 3.4任意节点连接clickhouse 3.5查看集群 3.6建库 3.7查看数…

了解住宅代理和移动代理的工作原理:从基础到高级应用

在当今时代&#xff0c;代理技术已经成为了优化网络连接、提升数据安全和增强用户体验的重要工具。特别是住宅代理和移动代理&#xff0c;这两种代理类型在网络服务中扮演着越来越重要的角色。本文将从详细的为您介绍这两种代理服务的工作原理&#xff0c;帮助你更好地理解并应…

如何对 GitLab 中文版进行升级?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门面向中国程序员和企业提供企业级一体化 DevOps 平台&#xff0c;用来帮助用户实现需求管理、源代码托管、CI/CD、安全合规&#xff0c;而且所有的操作都是在一个平台上进行&#xff0c;省事省心省钱。可以一键安装极狐GitL…

ArcGIS空间自相关 (Global Moran‘s I)——探究人口空间格局的20年变迁

先了解什么是莫兰指数&#xff1f; 莫兰指数&#xff08;Morans I&#xff09;是一种用于衡量空间自相关性的统计量&#xff0c;即它可以帮助我们了解一个地理区域内的观测值是否彼此相关以及这种相关性的强度和方向。 白话版&#xff1a;一句话就是判断数据在空间上有没有自…