Unity复刻骑砍中的帝国象棋(一)

news2025/4/9 23:32:14

Unity复刻骑砍中的帝国象棋(一)

起因和简介

这两天从一款游戏中发现了这么个棋类小游戏,觉得挺有意思,没错,就是下面这个:
帝国象棋
作为程序员的我,一下就想到复刻它一下。这个棋类小游戏,我并不知道它确切的名字,好像叫帝国象棋??好吧,这个不重要,重要的是我要实现它,顺便说一下,这个应该不会侵权吧,我可是真的只是为了学习,毕竟就算100%实现了,也不是以赚钱为目的的。先来说说它的规则吧,其实这个游戏我并没有玩,规则是我从其他人的攻略文章里搜来的:

  1. 双方分为攻击方和防守方,中间摆成十字的棋子,是防守方,四周的4组品字形棋子为攻击方。防守方中有一个棋子是王,就是正中间那个头上有皇冠图标的那个棋子。
  2. 所有的棋子,全部走直线,类似中国象棋里的“车”的走法。但是棋盘正中间的那个位置,任何棋子都不可以进入,也不可以越过,即便是“王”,离开之后就不能再回到中间去。
  3. 两个己方棋子,如果能“夹住”一个敌方棋子,那么就可以把它吃掉。水平或者垂直方向均可。棋盘中间的位置可以视作任何一方的己方棋子。一方棋子如果主动走到两边具有敌对棋子的位置,并不会“自杀”,对方如果想要杀死该棋子,只能从另一个方向夹击,或原夹击形式的棋子离开后重新回到原位置,重新形成夹击才能杀死该棋子。
  4. 防守方的“王”,如果能行走到任意方向上的棋盘的边缘,则防守方胜利。攻击方如果能杀死“王”,则攻击方胜利。

规则描述虽然文字挺多,但是实际上很简单。

开发计划和实现

目前写这篇文章之时,已经实现了走棋规则的判断、胜负的判断,就是说可以实现人和人的对战了。下一步,如果有时间的话,将会再完善一下这个小工程,主要是:①完善UI,实现开始、退出的对话框,以及胜利、失败的提示等。②如果还有时间,打算再实现一个AI功能,思路跟我之前写过的一片棋类游戏AI相差不多。有兴趣的可以一观:四字连珠。
目前的演示视频如下:

Unity复刻骑砍游戏中的帝国象棋(一)

具体实现

数据描述

首先是棋盘的数据描述,这是整个游戏最重要的数据结构,这个游戏的棋盘是个9*9的方格,很显然,最适合的就是用数组描述,比较直观的就是2维数组,但是二维数组在访问频率较高的场合,会稍稍影响性能,如果你用的Rider,它会给你提示:
二维数组性能

上图的意思是,使用多维数组效率很低,建议使用一维数组代替。

基于Rider给予的忠告,这里我使用的是一维数组。但是为了方便,还是以2维的形式去访问,然后写一个2维转1维的索引转换函数:

private static int CoordToIndex(int x, int y)
{
    return Mathf.Clamp(x * 9 + y, 0, 80);
}

也许这样的转换在实质上跟使用2维数组是性能等价的,但Rider不提示性能问题了,作为有点强迫症的可以心安理得,当然,如果你用的是VS,那就无所谓了,就算2维数组性能不如一维,这种性能的差异也可以忽略不计。

那么问题来了,数组里面放什么呢?如果想搞的稍微复杂一些,可以专门写一个棋子类,然后用数组作为容器,去盛放这些棋子。但是我并没有这么做,主要是感觉没大有必要,于是我用了2个数组,来描述这个棋盘。

private enum ChessType
{
    None,		// 表示该位置没有棋子
    Offensive,	// 表示该位置是攻击方的棋子
    Defense,	// 表示该位置是防守方的棋子
    King		// 表示该位置是防守方的王
}

private readonly ChessType[] boardMap = new ChessType [81];
private readonly GameObject[] chesses = new GameObject[81];

上面代码,定义了一个ChessType,其实就是这个棋盘上每个方格的状态。然后用一个9*9=81长度的数组来表示整个棋盘,还有一个一样的数组,用来盛放棋子的GameObject,方便进行位置调整和被杀后的剔除。

然后就是棋盘的初始化:
private void PutChess(int x, int y, ChessType ct)
{
    GameObject obj;
    switch (ct)
    {
        case ChessType.Defense:
            obj = Instantiate(defenseChessPrefab, transform);
            break;
        case ChessType.King:
            obj = Instantiate(kingChessPrefab, transform);
            break;
        case ChessType.Offensive:
            obj = Instantiate(offensiveChessPrefab, transform);
            break;
        default:
            return;
    }

    obj.transform.localPosition = CoordToLocal(x, y);
    int index = CoordToIndex(x, y);
    boardMap[index] = ct;
    chesses[index] = obj;
}
private void ResetChessBoard()
{
    for (int i = 0; i < 81; ++i)
    {
        boardMap[i] = ChessType.None;
        if (chesses[i] != null)
        {
            Destroy(chesses[i]);
            chesses[i] = null;
        }
    }

    PutChess(3, 0, ChessType.Offensive);
    PutChess(4, 0, ChessType.Offensive);
    PutChess(5, 0, ChessType.Offensive);
    PutChess(4, 1, ChessType.Offensive);

    PutChess(0, 3, ChessType.Offensive);
    PutChess(0, 4, ChessType.Offensive);
    PutChess(0, 5, ChessType.Offensive);
    PutChess(1, 4, ChessType.Offensive);

    PutChess(8, 3, ChessType.Offensive);
    PutChess(8, 4, ChessType.Offensive);
    PutChess(8, 5, ChessType.Offensive);
    PutChess(7, 4, ChessType.Offensive);

    PutChess(3, 8, ChessType.Offensive);
    PutChess(4, 8, ChessType.Offensive);
    PutChess(5, 8, ChessType.Offensive);
    PutChess(4, 7, ChessType.Offensive);

    PutChess(2, 4, ChessType.Defense);
    PutChess(3, 4, ChessType.Defense);
    PutChess(4, 2, ChessType.Defense);
    PutChess(4, 3, ChessType.Defense);
    PutChess(4, 5, ChessType.Defense);
    PutChess(4, 6, ChessType.Defense);
    PutChess(5, 4, ChessType.Defense);
    PutChess(6, 4, ChessType.Defense);
    PutChess(4, 4, ChessType.King);
}
棋盘坐标转换

只要在游戏开始的时候,调用ResetChessBoard方法,就可以重新摆一盘棋了。这里面有个函数CoordToLocal,用于根据棋盘坐标来计算棋子的局部坐标:

private static Vector3 CoordToLocal(int x, int y)
{
    return new Vector3(x * deltaCellSize - 0.47f + 0.0522222f, (8 - y) * deltaCellSize - 0.47f + 0.0522222f, 0.05f);
}

实际上,这个函数写的并不太优雅,原因是它跟模型的尺寸和棋盘的纹理位置是相关的,这就意味着如果你更换一个棋盘模型,这个函数就得重写。当然,能够通用的方法也有很多,为了简单,同时也为了性能,这里就这么写死了。

同时,对应的,也要有鼠标棋盘后,把点击位置转换为棋盘坐标的方法:

if (Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition), out RaycastHit hit, 500f))
{
    int x = Mathf.FloorToInt((hit.point.x + 0.47f) / deltaCellSize);
    int y = Mathf.FloorToInt((hit.point.z + 0.47f) / deltaCellSize);

	// x, y就是棋盘坐标
}
游戏逻辑

整个游戏过程,可以用状态机来描述不同的状态,代码和意义如下:

private enum PlayState
{
    GameOver,				// 游戏结束状态,或者游戏尚未开始状态
    ComputerThink,			// 计算机正在思考
    PlayerThink,			// 玩家正在思考
    PlayerTakeChess,		// 玩家举起了一枚棋子(选定某棋子,但尚未决定如何行走)
    PlayerPutChess			// 玩家将举起的棋子放到了指定位置(决定了如何行走)
}

针对不同的状态,就可以写不同的逻辑,然后在各个状态中进行切换:

思考状态 PlayerThink
case PlayState.PlayerThink:
    if (Input.GetMouseButtonDown(0))
    {
        if (Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition), out RaycastHit hit, 500f))
        {
            int x = Mathf.FloorToInt((hit.point.x + 0.47f) / deltaCellSize);
            int y = Mathf.FloorToInt((hit.point.z + 0.47f) / deltaCellSize);

            if (TryGetChessByCoord(x, y, out GameObject chess) && TakeupChess(x, y))
            {
                chess.transform.localPosition += takeChessOffset;
                currentTakedChess = chess;
                takedChessCoord.x = x;
                takedChessCoord.y = y;
                state = PlayState.PlayerTakeChess;
            }
        }
    }

    break;

如上,在玩家思索状态下,如果检测到了鼠标左键被按下,那么就发射一条射线,判断是否点击了棋盘上的己方棋子,如果是己方棋子,则继续判断这个棋子是不是可以被拿起:如果棋子四周有其他棋子,也就是说这枚棋子实际上不能进行移动,那么这枚棋子就不能被拿起,比如说这一枚:
不应该能够被拿起
只有点击的是能够被拿起的棋子,那么就拿起这枚棋子,并且将状态切换到PlayState.PlayerTakeChess

另外,举起棋子要做的事情是:枚举这枚棋子所有可能的走位,然后在所有的走位上打上标记,就是生成一个小圆点,表示可以走到的位置。这里用到了一个简单的对象池,而且只要想一下就不难发现,因为棋盘大小是9*9,所以,所有可能的走位不可能超过9+9-1=17个,因此这个对象池可以实现实例化17个这样的标记预制体,然后根据实际需要来摆放。

举起棋子的状态 PlayerTakeChess
  • ① 如果玩家点了鼠标右键,那么表示玩家改变了主意,表示要放弃刚刚选择的棋子,要重新选择棋子,这时候要把已经举起的棋子放下,状态重新切换为思考状态。
  • ② 如果玩家点了鼠标左键,首先判断所点的位置是不是原棋子的位置,如果是,那就同①,表示要放弃该棋子;如果所点的是另一个棋子,并且这枚棋子可以被举起,那么同样表示玩家改变了主意,此时需要放下原来举起的棋子,然后举起新选择的棋子,状态不改变;如果玩家点击的是所举起的棋子可以到达的空位,那么就标记该位置为目标位置,并将状态切换为“放置棋子”。
case PlayState.PlayerTakeChess:
	if (Input.GetMouseButtonDown(1))
	{
	    ClearChessPoints();
	    state = PlayState.PlayerThink;
	    currentTakedChess.transform.localPosition -= takeChessOffset;
	    currentTakedChess = null;
	    break;
	}
	
	if (Input.GetMouseButtonDown(0))
	{
	    if (Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition), out RaycastHit hit, 500f))
	    {
	        int x = Mathf.FloorToInt((hit.point.x + 0.47f) / deltaCellSize);
	        int y = Mathf.FloorToInt((hit.point.z + 0.47f) / deltaCellSize);
	
	        if (takedChessCoord.x == x && takedChessCoord.y == y)
	        {
	            ClearChessPoints();
	            currentTakedChess.transform.localPosition -= takeChessOffset;
	            currentTakedChess = null;
	            state = PlayState.PlayerThink;
	            break;
	        }
	
	        if (IsPutable(x, y))
	        {
	            ClearChessPoints();
	            tickLerp = 0;
	            originChessPosition = currentTakedChess.transform.localPosition;
	            targetChessPosition = CoordToLocal(x, y);
	            int index = CoordToIndex(takedChessCoord.x, takedChessCoord.y);
	            takedChessType = boardMap[index];
	            boardMap[index] = ChessType.None;
	            chesses[index] = null;
	            takedChessCoord.x = x;
	            takedChessCoord.y = y;
	            state = PlayState.PlayerPutChess;
	            break;
	        }
	
	        if (TryGetChessByCoord(x, y, out GameObject chess))
	        {
	            int curindex = CoordToIndex(x, y);
	            if (IsFriend(curindex, boardMap[CoordToIndex(takedChessCoord.x, takedChessCoord.y)]))
	            {
	                ClearChessPoints();
	                currentTakedChess.transform.localPosition -= takeChessOffset;
	            }
	
	            if (TakeupChess(x, y))
	            {
	                chess.transform.localPosition += takeChessOffset;
	                currentTakedChess = chess;
	                takedChessCoord.x = x;
	                takedChessCoord.y = y;
	                state = PlayState.PlayerTakeChess;
	            }
	            else
	                state = PlayState.PlayerThink;
	        }
	    }
	}
	
	break;
放置棋子状态 PlayerPutChess
case PlayState.PlayerPutChess:
    if (tickLerp < 0.99f)
    {
        tickLerp += 2.5f * Time.deltaTime;
        currentTakedChess.transform.localPosition =
            Vector3.Lerp(originChessPosition, targetChessPosition, tickLerp);
    }
    else
    {
        currentTakedChess.transform.localPosition = targetChessPosition;
        int index = CoordToIndex(takedChessCoord.x, takedChessCoord.y);
        boardMap[index] = takedChessType;
        chesses[index] = currentTakedChess;
        currentTakedChess = null;
        if (IsWin() || KillChess() || NoEnemyChessCanMove())
        {
            GameOver();
            break;
        }

        isPlayerOffensive = !isPlayerOffensive;
        if (isPlayWithPlayer)
        {
            state = PlayState.PlayerThink;
        }
        else
        {
            state = PlayState.ComputerThink;
        }
    }

    break;

这个状态的逻辑就比较简单些,主要是完成棋子移动的动画,并且,移动完成后,进行是否赢了的判断、是否杀死了对方的棋子,如果是杀死的是防御方的王,也要判定赢了;还有,如果敌人虽然仍有棋子,但全部无法移动,比如被堵到角落,也需要判定胜利。如果判断一方胜利,那么就结束游戏。然后将状态切换到GameOver,否则的话,就视情况将状态切换到玩家思考或者电脑思考状态,取决于游戏模式是人机对战还是跟人人对战。
这里重要的方法有两个,判断输赢和判断吃子的方法,请参考代码注释:

// 如果王已经逃走,判定防御方胜利
private bool IsWin()
{
    // 如果操作的棋子是王,那么判断是否移动到了棋盘的任意方向的边界
    if (takedChessType == ChessType.King)
    {
        if (takedChessCoord.x is 0 or 8 || takedChessCoord.y is 0 or 8)
            return true;
    }

    return false;
}
// 判断杀死棋子,如果杀死的是王,那么返回true,表示攻击方胜利
private bool KillChess()
{
    bool result = false;
    if (takedChessCoord.x >= 2)
    {
        if (IsFriend(CoordToIndex(takedChessCoord.x - 2, takedChessCoord.y)))
        {
            int index = CoordToIndex(takedChessCoord.x - 1, takedChessCoord.y);
            if (IsEnemy(index))
            {
                result |= RemoveChess(index);
            }
        }
    }

    if (takedChessCoord.y >= 2)
    {
        if (IsFriend(CoordToIndex(takedChessCoord.x, takedChessCoord.y - 2)))
        {
            int index = CoordToIndex(takedChessCoord.x, takedChessCoord.y - 1);
            if (IsEnemy(index))
            {
                result |= RemoveChess(index);
            }
        }
    }

    if (takedChessCoord.x <= 6)
    {
        if (IsFriend(CoordToIndex(takedChessCoord.x + 2, takedChessCoord.y)))
        {
            int index = CoordToIndex(takedChessCoord.x + 1, takedChessCoord.y);
            if (IsEnemy(index))
            {
                result |= RemoveChess(index);
            }
        }
    }

    if (takedChessCoord.y <= 6)
    {
        if (IsFriend(CoordToIndex(takedChessCoord.x, takedChessCoord.y + 2)))
        {
            int index = CoordToIndex(takedChessCoord.x, takedChessCoord.y + 1);
            if (IsEnemy(index))
            {
                result |= RemoveChess(index);
            }
        }
    }

    return result;
}

// 移除被吃掉的棋子,如果是王,返回true
private bool RemoveChess(int index)
{
    Destroy(chesses[index]);
    chesses[index] = null;
    bool result = boardMap[index] == ChessType.King;
    boardMap[index] = ChessType.None;
    return result;
}

// 判断指定位置的棋子是否为tp类型棋子的友方,如果tp未指定,判断依据为当前所举棋子
private bool IsFriend(int index, ChessType tp = ChessType.None)
{
    // 棋盘正中的位置,可以视作任何方的乙方单位
	if (index == 4 * 9 + 4)
            return true;

    if (tp == ChessType.None)
        tp = takedChessType;
    return tp switch
    {
        ChessType.Offensive => boardMap[index] == ChessType.Offensive,
        ChessType.King or ChessType.Defense => boardMap[index] == ChessType.King ||
                                               boardMap[index] == ChessType.Defense,
        _ => false
    };
}

// 判断指定位置是否为当前方的敌对棋子
private bool IsEnemy(int index)
{
    return takedChessType switch
    {
        ChessType.Offensive => boardMap[index] == ChessType.King || boardMap[index] == ChessType.Defense,
        ChessType.King or ChessType.Defense => boardMap[index] == ChessType.Offensive,
        _ => false
    };
}

// 敌人是否没有任何棋子可以移动
private bool NoEnemyChessCanMove()
{
    if (isPlayerOffensive)
        return !boardMap.Where((t, i) => t is ChessType.King or ChessType.Defense && IsChessMoveable(i)).Any();
    return !boardMap.Where((t, i) => t == ChessType.Offensive && IsChessMoveable(i)).Any();
}

// 判定一个棋子是否可以移动
private bool IsChessMoveable(int index)
{
    int x = index / 9;
    int y = index % 9;

    int t = x - 1;
    if (t >= 0 && (y != 4 || t != 4) && boardMap[CoordToIndex(t, y)] == ChessType.None)
        return true;

    t = x + 1;
    if (t <= 8 && (y != 4 || t != 4) && boardMap[CoordToIndex(t, y)] == ChessType.None)
        return true;

    t = y - 1;
    if (t >= 0 && (x != 4 || t != 4) && boardMap[CoordToIndex(x, t)] == ChessType.None)
        return true;
    t = y + 1;
    return t <= 8 && (x != 4 || t != 4) && boardMap[CoordToIndex(x, t)] == ChessType.None;
}

尚未开发的功能

  • UI
  • AI

源码下载

https://download.csdn.net/download/sdhexu/87222722

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

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

相关文章

【程序人生】4年创作纪念日,不忘初心,继续前行

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

JavaScript --04. 流程控制语句介绍

文章目录流程控制1 代码块1.1 声明代码块1.2 let 和 var的作用域2 条件判断语句 -- if语句3 条件分支语句3.1 if-else语句3.2 if-else if-else语句3.3 练习4 Switch语句5 循环语句5.1 While循环5.2 do-while循环5.3 for循环5.4 嵌套循环6 break和continue6.1 break6.2 continue…

PTL智能拣货系统

一、PTL背景介绍 随着工业 4.0 理念持续扩展并被接受&#xff0c;智能制造将是中国制造业发展趋势。未来的生产企业不仅仅在生产过程中追求智能化&#xff0c;仓储、工具、设备智能化管理都会成为新的趋势。 现阶段物流仓储行业进入了一个快速的发展期&#xff0c;各种各样的…

辣椒疫霉RXLR效应子抑制植物免疫

文章信息 题目&#xff1a;A Phytophthora capsici RXLR effector targets and inhibits the central immune kinases to suppress plant immunity 刊名&#xff1a;New Phytologist 作者&#xff1a;Xiangxiu Liang&#xff0c;Daolong Dou et al. 单位&#xff1a;China …

微信无感知检测单项好友【WeTool 免费版】【微信如何检测单向好友?】

一.微信无感知检测单项好友 1.1 背景 因为最近业务的原因加了好多的陌生微信好友&#xff0c;难免有很多好友删了我&#xff0c;但是我还有他的微信&#xff0c;岂不是很占地方&#xff1f; 所以我琢磨如何检测这些单项好友【利用转账、拉群的方法太费时间】&#xff0c;我无…

[附源码]计算机毕业设计springboot拉勾教育课程管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

事件绑定(onclick,onfocus,onblur)

事件绑定(onclick,onfocus,onblur) 学习路线&#xff1a;JavaScript_DOM->事件绑定(onclick,onfocus,onblur)-> 事件绑定(onmouseout,onmouseover) ->事件绑定(onsubmit)表单提交 ->提交表单与验证表单案例 常用绑定方式 方式一&#xff1a;通过 HTML标签中的事…

Java Hash 碰撞

散列函数&#xff08;英语&#xff1a;Hash function&#xff09;又称散列算法、哈希函数&#xff0c;是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要&#xff0c;使得数据量变小&#xff0c;将数据的格式固定下来。 该函数将数据打乱混合…

获取windows硬件、软件信息的方法

1&#xff0c;方法1 systeminfo 该命令是Windows中用于显示关于计算机及其操作系统的详细配置信息&#xff0c;包括操作系统配置、安全信息、产品 ID 和硬件属性&#xff0c;如 RAM、磁盘空间和网卡和补丁信息等。 SYSTEMINFO [/S system [/U username [/P [password]]]] [/FO…

从阿里降薪百分之三十来了国企,没想到还是要加班!哭了!

从阿里进国企&#xff0c;图什么&#xff1f;图它降工资&#xff1f;图它技术强&#xff1f;当然是图它轻松不加班&#xff0c;稳定不裁员&#xff01;但如果像下面这位阿里程序员一样&#xff0c;降薪百分之三十进了国企&#xff0c;发现还是得加班&#xff0c;大概只能emo了.…

[附源码]Python计算机毕业设计Django的文成考研培训管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Ae 动态图形模板

哈喽&#xff0c;各位小伙伴&#xff01;今天我们来学习一下如何通过AePr导出和安装动态图形模板&#xff1f; 新建合成 首先&#xff0c;新建一个合成&#xff0c;然后点击文字工具&#xff0c;内容自定义&#xff08;例&#xff1a;一场彗星雨&#xff0c;隔断了时空&#…

【408篇】C语言笔记-第九章(数据结构概述)

文章目录第一节&#xff1a;逻辑结构与存储结构1. 逻辑结构2. 存储结构1. 顺序存储2. 链式存储3. 顺序存储与链式存储分析第二节&#xff1a;算法的评价&#xff08;时间复杂度与空间复杂度&#xff09;1. 算法定义2. 时间复杂度3. 空间复杂度第一节&#xff1a;逻辑结构与存储…

CentOS7安装GmSSL过程记录

近期因为项目需要上区块链&#xff0c;在集成过程中证书选择了国密SM2&#xff0c;于是开启了入坑之旅&#xff0c;由于整个过程反复多次&#xff0c;我的记录也可能存在遗漏&#xff0c;只能尽力记录&#xff0c;这也是我为什么熬夜也要写下这篇记录&#xff01; 环境说明Virt…

[附源码]Python计算机毕业设计Django的玉石交易系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…

【Pandas数据处理100例】(九十三):Pandas使用all()函数判断DataFrame中的元素是否都为True

前言 大家好,我是阿光。 本专栏整理了《Pandas数据分析处理》,内包含了各种常见的数据处理,以及Pandas内置函数的使用方法,帮助我们快速便捷的处理表格数据。 正在更新中~ ✨ 🚨 我的项目环境: 平台:Windows10语言环境:python3.7编译器:PyCharmPandas版本:1.3.5N…

数据库事务、连接与java线程之间的关系

最近在处理事务和多线程时&#xff0c;比较困扰数据库事务&#xff0c;数据库连接以及java线程之间的关系。 问题1&#xff1a;事务和连接的关系&#xff1f; 回答&#xff1a;对于数据库事务来说先有一个连接&#xff0c;才能有事务&#xff0c;一个连接里可以有一次或多次事…

[附源码]计算机毕业设计SpringBoot计算机相关专业考研资料管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

二叉树的遍历与构建问题

目录 一、二叉树遍历 二、从前序与中序遍历序列构造二叉树 三、从中序遍历与后序遍历序列构造二叉树 一、二叉树遍历 编一个程序&#xff0c;读入用户输入的一串先序遍历字符串&#xff0c;根据此字符串建立一个二叉树&#xff08;以指针方式存储&#xff09;。 例如如下的…

卡塔尔世界杯壁纸已上线,下载的壁纸清晰度不够?教你修复清晰

当我们无法走入现场感受这场体育盛宴&#xff0c;就用一张张世界杯壁纸回味世界杯的动人瞬间吧&#xff0c;在家云看球&#xff0c;换上卡塔尔世界杯壁纸&#xff0c;用上表情包一样可以过把瘾&#xff0c;一起看看如何获得卡塔尔世界杯的壁纸和表情包吧&#xff01; 如何获得…