express+vue 在线五子棋(一)

示例

在这里插入图片描述

在线体验地址五子棋,记得一定要再拉个人才能对战

本期难点

1、完成了五子棋的布局,判断游戏结束
2、基本的在线对战,掉线暂停对局,重连继续对局
3、游戏配套im(这个im的实现,请移步在线im)

后续安排

1、黑白棋分配由玩家自选黑白棋与定义下棋间隔,以及具体的倒计时实现
2、新增旁观者,可以观棋与发送im信息
3、悔棋
4、玩家可以主动让出棋手身份,其他观战者可以接力玩
5、接入ai对战
6、使用canvas绘制棋盘对战

感兴趣的铁子,还请点个免费的收藏与关注,后续会一直跟进这个系列

前端部分五子棋布局与游戏输赢判断

<template>
    <div class="flex-wrap flex-justify-between">
        <div class="gobang-main">
            <!-- {{ userdata._id }}
            {{ gameBase }} -->
            步数: {{ currentStep }} 我方:{{ getQi }}
            <el-button v-if="isAdmin" @click="clearGame"> 清空游戏 </el-button>
            <!-- 下棋区 -->
            <game :list="gobangList" :config="config" @clickHandle="clickHandle"></game>

            <!-- <el-button v-if="isGameOver && isAdmin" @click="reloadGame"> 重新开始 </el-button> -->
        </div>
        <!-- im区 -->
        <Im
            ref="imRef"
            v-if="game_im_id"
            :style="{ width: '440px' }"
            :isShowLeft="false"
            :gobang_id="gobang_id"
            :game_im_id="game_im_id"
            @room_baseinfo="room_baseinfo"
            @get_game_content="get_game_content"
            @get_gb_info="get_gb_info"
            @del_gobang="del_gobang"
        ></Im>
    </div>
</template>

<script>
import Im from '@/views/blog/im/index.vue'
import { baseURL } from '@/plugins/config.js'
import { get_gobang_list, post_gobang, get_gobang, del_gobang } from '@/api/data.js'
import game from './game.vue'
export default {
    components: {
        Im,
        game,
    },
    data() {
        return {
            isGameOver: false,
            page: 'list',
            gameBase: {
                _id:'',
                status: '',
                max: 10,
                max_move_time: 0,
                all_time: 0,
                hei_user_id: '',
                bai_user_id: '',
                im_romm_id:''
            },
            gobangMembers: [], // 五子棋游戏成员列表

            room_id: '',
            gobangList: [],
            config: {
                type: 1, // 1为白棋 2为黑棋
                line: 15, // 棋盘线条数
                width: 36,
            },
            first: true,
        }
    },
    computed: {
        ...Vuex.mapState(['userdata']),
        ...Vuex.mapGetters(['isAdmin']),
        gobang_id() {
            return this.gameBase._id
        },
        game_im_id() {
            return this.gameBase.im_romm_id
        },

        // 当前步数
        currentStep() {
            let result = 0
            this.gobangList.forEach((item) => {
                item.forEach((itey) => {
                    if (itey.step_number > 0) {
                        result += 1
                    }
                })
            })
            return result
        },
        getQi() {
            // 自己是黑棋还是白棋
            let { _id } = this.userdata
            if (_id == this.gameBase.bai_user_id) {
                return '白棋'
            }

            if (_id == this.gameBase.hei_user_id) {
                return '黑棋'
            }

            return '观众'
        },
        step_content() {
            // 具体下的内容 1白字 2黑子
            const obj = {
                白棋: 1,
                黑棋: 2,
            }

            return obj[this.getQi] || 0
        },
    },
    created() {
        this.init()
    },

    methods: {
        del_gobang() {
            // 清空数据
            // this.gobangList = []
            // this.isGameOver = false
            // this.gameBase = {
            //     status: '',
            //     max: 10,
            //     max_move_time: 0,
            //     all_time: 0,
            //     hei_user_id: '',
            //     bai_user_id: '',
            // }

            location.reload()
        },
        clearGame() {
            this.$confirm('确定要清空游戏吗?')
                .then((res) => {
                    this.$refs.imRef.send_msg({
                        room_id: this.room_id,
                        specialType: 3,
                        gobang_id: this.gobang_id,
                    })
                })
                .catch(() => {})
        },
        // 黑棋先行,一人一只下
        isShould() {
            let { currentStep, gobangList, step_content } = this
            // 黑棋个数
            let heiNumber = 0

            // 白棋个数
            let baiNumber = 0

            // 遍历棋盘
            gobangList.forEach((aaa) => {
                aaa.forEach((item) => {
                    if (item.step_content == 1) {
                        baiNumber += 1
                    }

                    if (item.step_content == 2) {
                        heiNumber += 1
                    }
                })
            })

            // 判断现在下的步数的奇数还是偶数
            let isOdd = currentStep % 2

            if (step_content === 1) {
                // 白棋
                return isOdd === 1
            }

            if (step_content === 2) {
                // 黑棋
                return isOdd === 0
            }
        },

        clickHandle({ x, y }) {
            let {
                step_content,
                room_id,
                gobang_id,
                userdata: { _id: author_id },
                currentStep,
                isGameOver,
            } = this

            if (isGameOver) {
                return this.$message.warning('游戏已结束')
            }

            // 只有棋手才能下棋
            if (![1, 2].includes(+step_content)) return

            // 判断是否该下子
            if (!this.isShould()) {
                return this.$message.warning('请等待对方落子')
            }

            let obj = {
                room_id,
                specialType: 2,
                gobang_id,
                gobang_member_id: author_id,
                step_number: currentStep + 1,
                step_content,
                x,
                y,
                author_id,
            }
            this.$refs.imRef.send_msg(obj, () => {})
        },
        room_baseinfo({ gobangMembers, room_id }) {
            this.gobangMembers = Array.isArray(gobangMembers) ? gobangMembers : []
            this.room_id = room_id || ''
        },
        initConfigList() {
            // 生成一个二维数组
            let { line } = this.config
            for (let i = 0; i < line; i++) {
                this.gobangList.push([])
                for (let j = 0; j < line; j++) {
                    this.gobangList[i].push({
                        x: i,
                        y: j,
                        step_content: 0, // 0: 空 1: 白 2: 黑
                    })
                }
            }
        },
        async init() {
            this.initConfigList()
            let res = null
            try {
                res = await get_gobang_list()
            } catch (err) {
                return
            }
            if (res.data || this.isArray(res.data.data)) {
                if (res.data.data.length === 0) {
                    let res = await post_gobang({
                        game_name: '五子棋',
                    }).catch(() => {
                        return {}
                    })

                    if (!res.data || !this.isObject(res.data.data)) return
                    Object.assign(this.gameBase,res.data.data)
                }
                if (res.data.data.length) {
                    Object.assign(this.gameBase,res.data.data[0])
                }
            }

            // 获取现有的对局信息
            get_gobang({ gobang_id: this.gobang_id })
                .then((res) => {
                    if (res.data && this.isArrayLength(res.data.data)) {
                        let arr = res.data.data
                        this.gobangList = this.gobangList.map((aaa) => {
                            aaa = aaa.map((item) => {
                                let { x, y } = item
                                arr.find((itey) => {
                                    let { step_content, step_number, gobang_member_id } = itey
                                    if (itey.x == x + 1 && itey.y == y + 1 && step_content) {
                                        Object.assign(item, {
                                            step_content,
                                            step_number,
                                            gobang_member_id,
                                        })

                                        return true
                                    }
                                })

                                return item
                            })

                            return aaa
                        })

                        console.log(this.gobangList)
                    }
                })
                .catch(() => {})
        },

        get_game_content(row) {
            this.gobangList = this.gobangList.map((aaa) => {
                aaa = aaa.map((item) => {
                    let { x, y } = item
                    let { step_content, step_number, gobang_member_id } = row
                    if (row.x == x + 1 && row.y == y + 1 && step_content) {
                        Object.assign(item, {
                            step_content,
                            step_number,
                            gobang_member_id,
                        })
                    }

                    return item
                })

                return aaa
            })

            this.checkWin()
        },

        get_gb_info(row) {
            this.gameBase = Object.assign(this.gameBase, row)
            console.log('get_gb_info',this.gameBase)
        },
        // 判断是否胜利 需要知道哪种棋子胜利
        checkWin() {
            // if(this.first) return
            this.first = false
            // 判断当前棋盘是否有五子连珠
            let { line } = this.config
            let { gobangList: list } = this
            let type = 0 // 0: 没有胜利 1: 白棋胜利 2: 黑棋胜利 3: 平局
            // 判断横向
            for (let i = 0; i < line; i++) {
                for (let j = 0; j < line - 4; j++) {
                    if (
                        list[i][j].step_content !== 0 &&
                        list[i][j].step_content === list[i][j + 1].step_content &&
                        list[i][j].step_content === list[i][j + 2].step_content &&
                        list[i][j].step_content === list[i][j + 3].step_content &&
                        list[i][j].step_content === list[i][j + 4].step_content
                    ) {
                        type = list[i][j].step_content
                        break
                    }
                }
            }
            // 判断纵向
            for (let i = 0; i < line; i++) {
                for (let j = 0; j < line - 4; j++) {
                    if (
                        list[j][i].step_content !== 0 &&
                        list[j][i].step_content === list[j + 1][i].step_content &&
                        list[j][i].step_content === list[j + 2][i].step_content &&
                        list[j][i].step_content === list[j + 3][i].step_content &&
                        list[j][i].step_content === list[j + 4][i].step_content
                    ) {
                        type = list[j][i].step_content

                        break
                    }
                }
            }
            // 判断左斜
            for (let i = 0; i < line - 4; i++) {
                for (let j = 0; j < line - 4; j++) {
                    if (
                        list[i][j].step_content !== 0 &&
                        list[i][j].step_content === list[i + 1][j + 1].step_content &&
                        list[i][j].step_content === list[i + 2][j + 2].step_content &&
                        list[i][j].step_content === list[i + 3][j + 3].step_content &&
                        list[i][j].step_content === list[i + 4][j + 4].step_content
                    ) {
                        type = list[i][j].step_content
                        break
                    }
                }
            }

            // 判断右斜
            for (let i = 0; i < line - 4; i++) {
                for (let j = 4; j < line; j++) {
                    if (
                        list[i][j].step_content !== 0 &&
                        list[i][j].step_content === list[i + 1][j - 1].step_content &&
                        list[i][j].step_content === list[i + 2][j - 2].step_content &&
                        list[i][j].step_content === list[i + 3][j - 3].step_content &&
                        list[i][j].step_content === list[i + 4][j - 4].step_content
                    ) {
                        type = list[i][j].step_content
                        break
                    }
                }
            }

            // 判断是否平局
            let flag = true
            for (let i = 0; i < line; i++) {
                for (let j = 0; j < line; j++) {
                    if (list[i][j].step_content == 0) {
                        flag = false
                        break
                    }
                }
            }

            // 如果是平局
            if (flag) {
                type = 3
            }

            const obj = {
                1: '白棋胜利',
                2: '黑棋胜利',
                3: '平局',
            }

            if (obj[type]) {
                this.$message.success(obj[type])
                this.isGameOver = true
            }
        },
    },
}
</script>

<style lang="scss" scoped></style>

express代码

Gobang 为五子棋基本设置表
GobangMember 五子棋对战与观战人表
GobangItem 每一步的对战信息表

const { io } = require("../../tool/socket.js");
const { AuthorInfo } = require("../../mod/author/author_info");
const { ImRoom } = require("../../mod/game/im_room.js");
const { ImRoomSys } = require("../../mod/game/im_room_sys.js");
const { ImRoomMember } = require("../../mod/game/im_room_member.js");
const { Game } = require("../../mod/game/game.js");
const { GameList } = require("../../mod/game/game_list.js");
const { Gobang } = require("../../mod/game/gobang.js");
const { GobangMember } = require("../../mod/game/gobang_member.js");
const { GobangItem } = require("../../mod/game/gobang_item.js");

let allSocket = {};

// 监听客户端的连接
io.on("connection", function (socket) {
  allSocket[socket.id] = socket;
  // 监听用户掉线
  socket.on("disconnect", async () => {
    // 更新用户状态
    let user = await ImRoomMember.findOneAndUpdate(
      { socket_id: socket.id },
      { status: "2" }
    );
    if (user) {
      delete allSocket[user.im_room_id];
      // 这是触发的方法数组,默认只有im的人员信息变化
      const funStatus = ["members_change"];
      // 对于五子棋游戏相关退出房间操作
      try {
        let res = await GobangMember.findOneAndUpdate(
          { socket_id: socket.id },
          { status: "2" }
        );
        // TODO: 这儿存在性能问题

        if (res.n == 1) {
          funStatus.push("gobang_members_change");
        }
      } catch (err) {
        console.log(err);
      }

      // 向房间的用户同步信息
      sendMsgToRoom(user.im_room_id, null, funStatus);
    }
  });

  // 监听加入房间
  socket.on("join_room", async (data) => {
    if (!global.isObject(data)) {
      resMsg("加入房间参数错误", 400);
      return;
    }
    // game_id 是游戏id,只有游戏才需要传入
    let { user_id, room_id, gobang_id } = data;
    if (!user_id) {
      resMsg("用户id不能为空", 400);
      return;
    }
    let user = await AuthorInfo.findOne({ _id: user_id });
    if (!user) {
      resMsg("用户不存在", 400);
      return;
    }

    if (!room_id) {
      resMsg("房间id不能为空", 400);
      return;
    }
    let room = await ImRoom.findOne({ _id: room_id, status: "1" });
    if (!room) {
      resMsg("房间不存在", 400);
      return;
    }

    let { max, status } = room;
    if (+status !== 1) {
      resMsg("房间未开放", 300);
      return;
    }

    // 查找所有加入该房间,并且状态为在线的用户
    let members = await ImRoomMember.find({
      im_room_id: room_id,
      status: 1,
    }).countDocuments();

    if (members >= max) {
      resMsg("房间已满", 300);
      return;
    }

    // 查找用户是否已经加入过该房间
    let oldUser = await ImRoomMember.findOne({
      im_room_id: room_id,
      author_id: user_id,
    });
    if (!oldUser) {
      let res = await new ImRoomMember({
        im_room_id: room_id,
        author_id: user_id,
        author_type: 2,
        created_time: getCurrentTimer(),
        updated_time: getCurrentTimer(),
        status: 1,
        socket_id: socket.id,
      }).save();

      if (!res) {
        resMsg("加入房间失败", 400);
        return;
      }
    } else {
      await ImRoomMember.updateOne(
        { im_room_id: room_id, author_id: user_id },
        { socket_id: socket.id, status: 1 }
      );
    }

    // 这是触发的方法数组,默认只有im的人员信息变化
    const funStatus = ["members_change"];

    // 对于五子棋游戏相关加入房间操作
    if (gobang_id) {
      let game = await Gobang.findOne({ _id: gobang_id });
      if (!game) {
        resMsg("游戏不存在", 400);
        return;
      }

      // 查找用户是否已经加入过该游戏
      let oldUser = await GobangMember.findOne({
        gobang_id,
        author_id: user_id,
      });

      if (!oldUser) {
        let res = await new GobangMember({
          gobang_id,
          author_id: user_id,
          created_time: getCurrentTimer(),
          updated_time: getCurrentTimer(),
          status: 1,
          socket_id: socket.id,
          user_type: "3",
        }).save();

        if (!res) {
          resMsg("加入游戏失败", 400);
          return;
        }
      } else {
        try {
          await GobangMember.updateOne(
            { gobang_id, author_id: user_id },
            { socket_id: socket.id, status: 1 }
          );
        } catch (error) {
          console.log("err", err);
        }
      }

      // 查看是否需要更新游戏基本信息-黑棋与白棋
      let gameInfo = await Gobang.findOne({ _id: gobang_id });
      if (gameInfo) {
        let { bai_user_id, hei_user_id } = gameInfo;
        // 查看用户是否在线
        let baiUser = await GobangMember.findOne({
          author_id: bai_user_id,
          gobang_id,
        });
        let heiUser = await GobangMember.findOne({
          author_id: hei_user_id,
          gobang_id,
        });
        console.log(111,heiUser,baiUser)
        if (!heiUser) {
          await Gobang.updateOne({ _id: gobang_id }, { hei_user_id: user_id });
        } else if (!baiUser) {
          await Gobang.updateOne({ _id: gobang_id }, { bai_user_id: user_id });
        }
        
      }
      funStatus.push("get_gb");
      funStatus.push("gobang_members_change");
    }

    // 房间信息改变,向房间内所有在线用户推送房间信息
    sendMsgToRoom(room_id, null, funStatus, gobang_id);
  });

  // 主动推出登录
  socket.on("live_room", async (data) => {
    let { room_id, user_id, gobang_id } = data;

    // 更新用户状态
    let user = await ImRoomMember.findOneAndUpdate(
      { im_room_id: room_id, author_id: user_id },
      { status: "2" }
    );
    if (user) {
      delete allSocket[user.socket_id];

      // 这是触发的方法数组,默认只有im的人员信息变化
      const funStatus = ["members_change"];
      if (gobang_id) {
        // 对于五子棋游戏相关退出房间操作
        try {
          await GobangMember.findOneAndUpdate(
            { gobang_id, author_id: user_id },
            { status: "2" }
          );
        } catch (err) {
          console.log(err);
        }

        funStatus.push("gobang_members_change");
      }

      // 向房间的用户同步信息
      sendMsgToRoom(room_id, null, funStatus, gobang_id);
    }
  });

  // 发送消息
  socket.on("send_msg", async (data) => {
    if (!global.isObject(data)) return;
    // time是时长
    // specialType 默认1 im的发送消息;2 五子棋的发送下棋消息 3 五子棋发送清空数据消息
    let {
      room_id,
      author_id,
      content,
      msg_type = "1",
      time = 0,
      poster = "",
      video_width = "",
      video_height = "",
      specialType = 1,
      gobang_id,
      gobang_member_id,
      step_number,
      step_content = 0,
      x,
      y,
    } = data;
    if (specialType == 3) {
      // 有关五子棋的消息
      if (!gobang_id || !room_id) {
        resMsg("清空数据消息有字段缺失", 400, "err", socket);
        return;
      }
      let gobang = await Gobang.findOneAndDelete({ _id: gobang_id });
      if (!gobang) {
        resMsg("删除失败", 400, "err", socket);
        return;
      }

      let { im_romm_id } = gobang;

      // 删除人员
      await ImRoomMember.deleteMany({ gobang_id: gobang_id });

      // 删除对局信息
      await GobangItem.deleteMany({ gobang_id: gobang_id });

      // 删除聊天室
      await ImRoom.deleteOne({ _id: im_romm_id });

      // 删除聊天记录
      await ImRoomSys.deleteMany({ im_romm_id });
      // 删除聊天成员信息
      await ImRoomMember.deleteMany({ im_romm_id });

      console.log(111)
      sendMsgToRoom(room_id, null, ["del_gobang"], gobang_id);
      return
    }

    if (specialType == 2) {
      // 有关五子棋的消息
      console.log(data);
      if (
        !room_id ||
        !gobang_id ||
        !gobang_member_id ||
        !gobang_member_id ||
        !step_number ||
        !x ||
        !y ||
        !author_id
      ) {
        resMsg("下棋消息有字段缺失", 400, "err", socket);
        return;
      }

      if (![1, 2].includes(+step_content)) {
        resMsg("观众不能下棋", 400, "err", socket);
        return;
      }
      let oldGb = await GobangItem.findOne({
        gobang_id,
        step_number,
      });

      if (oldGb) {
        resMsg("您已经下过棋了", 400);
        return;
      }

      try {
        let newGb = await new GobangItem({
          gobang_id,
          gobang_member_id: author_id,
          step_number,
          created_time: getCurrentTimer(),
          updated_time: getCurrentTimer(),
          step_content,
          x,
          y,
        }).save();

        sendMsgToRoom(room_id, newGb, [], gobang_id);
      } catch (err) {
        console.log(err);
        resMsg("保存步数失败", 400);
        return;
      }

      return;
    }
    if (!content) {
      resMsg("请输入内容", 400);
      return;
    }
    // 判断用户是否存在
    if (!author_id) {
      resMsg("用户id不能为空", 400);
      return;
    }

    let user = await AuthorInfo.findOne({ _id: author_id });
    if (!user) {
      resMsg("用户id不能为空", 400);
      return;
    }

    // 判断房间是否存在
    if (!room_id) {
      resMsg("房间id不能为空", 400);
      return;
    }

    let room = await ImRoom({ _id: room_id, status: "1" });
    if (!room) {
      resMsg("房间未开放", 400);
      return;
    }

    if (!content) {
      resMsg("消息内容不能为空", 400);
      return;
    }

    // 保存消息
    let params = {
      im_room_id: room_id,
      author_id: author_id,
      content: content,
      msg_type,
      created_time: getCurrentTimer(),
      updated_time: getCurrentTimer(),
    };

    if (time) {
      params.time = time;
    }

    if (msg_type == 4) {
      if (poster) {
        params.poster = poster;
      }
      if (video_width) {
        params.video_width = video_width;
      }
      if (video_height) {
        params.video_height = video_height;
      }
    }

    let room_sys = await new ImRoomSys(params).save();
    if (!room_sys) {
      resMsg("保存消息失败", 400);
      return;
    }
    // 找出对应的成员信息
    let userinfo = await AuthorInfo.findOne(
      { _id: author_id },
      {
        username: 1,
        header_img: 1,
      }
    );
    if (!userinfo) {
      resMsg("用户信息不存在", 400);
      return;
    }
    room_sys.author_id = userinfo;
    sendMsgToRoom(room_id, room_sys);
  });

  /**
   * 向一个房间内的所有在线用户推送房间的基本信息
   * row 本次聊天信息
   * name 触发事件的小别名
   * **/
  async function sendMsgToRoom(room_id, row = null, names = [], game_id = "") {
    if (!room_id) return;

    // 找出全部在线的成员
    let members = await ImRoomMember.find(
      {
        im_room_id: room_id,
        status: 1,
      },
      { socket_id: 1 }
    );

    if (!members || members.length === 0) return;
    let sockets = members.map((item) => item.socket_id);

    // 找出房间信息
    let room = (await ImRoom.findOne({ _id: room_id, status: "1" })) || {};

    // 查找出当前房间的总消息数
    let roomSysCount = await ImRoomSys.find({
      im_room_id: room_id,
    }).countDocuments();

    let res = {
      data: room,
      roomSysCount,
      msg: "房间信息已更新",
    };

    if (names.length > 0) {
      // 去重
      names = [...new Set(names)];
      for (let i = 0; i < names.length; i++) {
        const item = names[i];
        switch (item) {
          case "members_change":
            // 人员状态有变化
            let roomMembers = await ImRoomMember.find(
              { im_room_id: room_id },
              { author_id: 1, status: 1, room_username: 1 }
            )
              .populate("author_id", "username header_img")
              .exec();
            res.roomMembers = roomMembers;
            break;

          case "gobang_members_change":
            // 五子棋人员状态有变化
            let gobangMembers = await GobangMember.find({ gobang_id: game_id })
              .populate("author_id", "username header_img")
              .exec();
            Object.assign(res, {
              gobangMembers,
            });
            break;

          case "get_gb":
            // 获取游戏的基本信息
            let gameInfo = await Gobang.findOne({ _id: game_id });
            if (gameInfo) {
              res.gb_info = gameInfo;
            }
            break;

          case "del_gobang":
            res.is_del_gobang = true;
            break;
        }
      }
    }

    if (global.isObject(row)) {
      if (game_id) {
        // 五子棋消息
        res.game_content = row;
      } else {
        // im有新消息
        res.content = row;
      }
    }

    sockets.forEach((item) => {
      let socket = allSocket[item];

      if (socket) {
        resMsg(res, 200, "room_baseinfo", socket);
      }
    });
  }

  // 获取当前时间戳
  function getCurrentTimer() {
    return Date.now();
  }

  // 统一返回消息
  function resMsg(msg, code = 400, name = "err", _socket) {
    let obj = {
      code,
    };
    if (code === 200) {
      obj.msg = "操作成功";
      obj.data = msg;
    } else {
      obj.msg = msg;
    }

    socket = _socket ? _socket : socket;
    socket.emit(name, obj);
  }
});

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络物理隔离后 可以用保密U盘进行数据安全交换吗?

企业用的保密U盘通常被设计用于存储和传输敏感信息&#xff0c;以确保数据的安全和保密性。 在网络之间实现了物理隔离后&#xff0c;使用保密U盘进行数据安全交换是一种常见的做法。物理隔离确保了两个网络之间的完全分离&#xff0c;因此使用保密U盘可以作为一种安全的手段来…

format()函数

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法介绍 format()可以对数据进行格式化处理操作&#xff0c;语法如下&#xff1a; format(value, format_spec) format_spec为格式化解释。当参数…

ZSWatch 开源项目介绍

前言 因为时不时逛 GitHub 会发现一些比较不错的开源项目&#xff0c;突发奇想想做一个专题&#xff0c;专门记录开源项目&#xff0c;内容不限于组件、框架以及 DIY 作品&#xff0c;希望能坚持下去&#xff0c;与此同时&#xff0c;也会选取其中的开源项目做专题分析。希望这…

MySQL高级-索引-设计原则小结

文章目录 1、设计原则2、索引小结2.1、索引概述2.2、索引结构2.3、索引分类2.4、索引语法2.5、SQL性能分析2.6、索引使用2.7、索引设计原则 1、设计原则 针对于数据量较大&#xff0c;且查询比较频繁的表建立索引。针对于常作为查询条件&#xff08;where&#xff09;、排序&am…

SpringCloud Alibaba Sentinel规则持久化实践总结

默认情况下&#xff0c;一旦我们重启应用&#xff0c;sentinel规则将消失&#xff0c;生产环境需要将配置规则进行持久化。这里我们实践将Sentinel持久化到Nacos中。 ① pom依赖 我们引入sentinel-datasource-nacos&#xff1a; <dependency><groupId>com.aliba…

【机器学习300问】134、什么是主成分分析(PCA)?

假设你的房间堆满了各种各样的物品&#xff0c;书籍、衣服、玩具等等&#xff0c;它们杂乱无章地散落各处。现在&#xff0c;你想要清理房间&#xff0c;但又不想扔掉任何东西&#xff0c;只是希望让房间看起来更整洁&#xff0c;更容易管理。 你开始思考&#xff0c;能否将物品…

十三、Maven(1)

&#x1f33b;&#x1f33b;目录 一、maven价绍二、maven的功能1、项目自动化构建2、管理jar、war包3、实现项目结构设计 三、maven安装1、maven的安装环境需要jdk2、Maven的安装路径中不能出现中文和空格3、压缩包解压即可4、配置环境变量 四、maven的仓库1. Maven仓库配置2. …

矩阵新玩法,云微客AI矩阵系统开启新营销大门

在激烈的市场竞争中&#xff0c;商家企业们都在追求更加高效的营销方式&#xff0c;在如今流量至上的时代&#xff0c;短视频凭借其魅力&#xff0c;成为了众多企业吸引流量、获客引流的核心营销途径。而想要挤进短视频流量圈的你&#xff0c;是否经常听到矩阵这个词呢&#xf…

PY32F003系列单片机,超值国产32位单片机,资料齐全 易于开发

PY32F003 系列微控制器是采用高性能的 32 位 ARM Cortex-M0 内核&#xff0c;宽电压工作范围的 MCU。嵌入高达 64 Kbytes flash 和 8 Kbytes SRAM 存储器&#xff0c;最高工作频率 32 MHz。包含多种不同封装类型多款产品。 PY32F003 系列微控制器的工作温度范围为 -40 ~ 85 ℃…

oceanbase数据库安装和连接实战(阿里云服务器操作)

本文主要是安装oceanbase的单机版进行数据库的基础使用&#xff0c;oceanbase的数据库是兼容mysql数据库的&#xff0c;实际的兼容程度需要更深度的测试&#xff0c;本文主要是安装oceanbase并使用SQLynx的mysql驱动连接使用oceanbase数据库。 目录 1. 基础介绍 2. 安装说明 …

gdb用法

创建文件 // main.cpp文件 // 稳态误差 void pid_test_wentaiwucha() {float p 1.5;int t 1; // t 1s;int target 5; // 5m/sfloat output 0;float radis 3; // 稳态误差std::cout << "output: " << std::endl;fo…

PT100(RTD)是什么?2线,3线,4线原理

RTDs - or Resistance Temperature Detectors- (电阻式温度探测器)&#xff0c;是温度型传感器&#xff0c;包含一个电阻&#xff0c;这个阻值可以随温度的变化而变化。在工业的进程中和实验室里已经使用了很多年&#xff0c;以精确&#xff0c;可靠和稳定的特性。 2线制 2线制…

.net core接入nacos注册服务并使用配置中心

1、安装依赖 Nuget包&#xff1a;nacos-sdk-csharp.Extensions.Configuration和nacos-sdk-csharp.AspNetCore 2、在appsettings.json中配置 "nacos": {"ServerAddresses": ["http://localhost:8848/"],"DefaultTimeOut": 15000,"…

前端vue-cli相关知识与搭建过程(项目创建,组件路由)very 详细

一.关于vue-cli 1.什么是vue Vue (读音 /vju ː /&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式框架。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第三方库或既有项目整合。 Vue.js 是前端的主流框架之一&#xff0c;和 Angular.js…

【财经研究】并购重组的“不可能三角”

伴随着沪深IPO景气度下滑后&#xff0c;并购重组正受到市场的关注。 近期监管层正频频为并购重组发声 6月20日&#xff0c;证监会主席吴清在陆家嘴论坛上指出&#xff1a;“支持上市公司运用各种资本市场工具增强核心竞争力&#xff0c;特别是要发挥好资本市场并购重组主渠道作…

python 识别图片点击,设置坐标,离设置坐标越近的优先识别点击

import pyautogui import cv2 import numpy as np import mathdef find_and_click(template_path, target_x, target_y, match_threshold0.8):"""在屏幕上查找目标图片并点击。Args:template_path: 目标图片的路径。target_x: 预设的坐标 x 轴值。target_y: 预设…

使用 Google Gemini 和 SwiftUI 构建 AI 图像识别应用程序

在本教程中,我们将演示如何使用 Google Gemini API 进行图像识别。这个简单的应用程序允许用户从他们的照片库中选择一张图片,并使用 Gemini 描述照片的内容。 在继续本教程之前,请访问Google AI Studio并创建您自己的 API 密钥(如果您还没有这样做)。 在 Xcode 项目中添…

AcWing算法基础课笔记——最短Hamilton路径

最短Hamilton路径 题目 给定一张 n 个点的带权无向图&#xff0c;点从 0~n-1 标号&#xff0c;求起点 0 到终点 n-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次。 输入格式 第一行输入整数n。 接下来 n 行每行n个整数&#xff0c…

CCSP自考攻略+经验总结

备考攻略 备考攻略准备阶段通读阶段精度阶段总复习阶段刷题阶段命运审判 写到最后 备考攻略 趁着对ssp知识点的理解还在&#xff0c;开始ccsp的考证之路&#xff0c;文章结构还是按照cissp备考篇的结构梳理。本次备考和cissp的离职在家备考不同&#xff0c;ccsp是在职利用非工…

通过命令行配置调整KVM的虚拟网络

正文共&#xff1a;1234 字 20 图&#xff0c;预估阅读时间&#xff1a;2 分钟 在上篇文章中&#xff08;最小化安装的CentOS7部署KVM虚拟机&#xff09;&#xff0c;我们介绍了如何在最小化安装的CentOS 7系统中部署KVM组件和相关软件包。因为没有GUI图形界面&#xff0c;我们…