开源项目 —— 原生JS实现斗地主游戏 ——代码极少、功能都有、直接粘贴即用

news2024/12/23 3:55:04

目录

效果如下

 目录结构

 GameEntity.js

 GrawGame.js

konva.min.js

PlayGame.js

veriable.js

index.html

结语:


前期回顾

卡通形象人物2 写代码-睡觉 丝滑如德芙_0.活在风浪里的博客-CSDN博客本文实现了包含形象的卡通小人吃、睡、电脑工作的网页动画https://blog.csdn.net/m0_57904695/article/details/128981376?spm=1001.2014.3001.5501

本文实现了包含形象斗地主网页游戏,js循环动画,简单生动的画面设计。非常丝滑有意思,欢迎对此代码感兴趣的朋友前来下载参考。

如果大家非常好奇该段代码所带来的网页游戏效果的话,那就直接拷贝到自己电脑上,不上传了资源了,方便大家直接玩乐,如果对你有些微帮助还请收藏以备下次及时找到!

  本文直接复制可以用,

效果如下

 目录结构

 GameEntity.js


/**
 * 实体类;有些实体其中的行为,
 * 可能没有严格符合面向对象规范,
 * 原因在于对象与过程之间的界限难以区分
 */

// 玩家
class Player{
    constructor(BoardList, name, color){
        this.Color = color
        // Board对象
        this.BoardList = BoardList
        this.name = name
        this.GroupBoard = null
    }
    // 通过ID获取牌
    GetBoardOfID(id){
        if(this.BoardList.length>0){
            for(let i=0;i<this.BoardList.length;i++){
                if(this.BoardList[i].id == id)
                    return i
            }
        }
        return -1
    }
    // 根据ID删除节点
    DeleteIDOfBoard(id){
        if(this.BoardList.length<1) return
        let index_ = this.GetBoardOfID(id)
        this.BoardList.splice(index_, 1)
    }
    // 将手中的牌按照顺序排列
    BoardListSort(){
        BoardSort(this.BoardList)
    }
    // 提示出牌
    AutoSendBoard(){
        // 提示出牌需要满足几个条件,
        // 首先上家没有出牌时,那么按照最大的类型出牌(炸弹除外),如Y2>Y1
        // 如果上家有出牌,那么需要判断当前牌组之中是否有相对应类型的牌
        // 玩家需要自己维护自己所有的牌总量(机器人由程序维护),如一手牌组当中有几个飞机几个顺子
        
    }

    // 将当前的牌聚类为一个个的牌组合;返回牌组合数组
    // 如:987654333 return: Y5,Y3,Y2
    ClusterType(){

    }
}

// 牌对象
// type ♥,♠,♦,♣
class Board{
    constructor(surface, type, id){
        this.surface = surface
        this.type = type
        this.id = type + id
        this.DrawBoardFront = CreateBorad(width/2-30, height/2-45, this)
        this.DrawBoardFront._id = id
        // id必须是要唯一的
        this.DrawBoardBack = BoardBack(width/2-30, height/2-45, this)
        this.DrawBoardBack._id = '0'+id
    }

}

// 组合牌
class BoardCombin{
    constructor(BoardList, Type, Value, length){
        this.BoardList = BoardList
        this.Type = Type
        this.Value = Value
        this.Length = length
    }
}

// 这里可以优化,使用有限状态机会更好,逻辑更清晰
// 判定出牌边界,类型一致,牌的数量一致,不小于桌面价值量
// 单:    1;     Y1
// 对:    2;     Y2  *
// 三带:  3~5;   Y3 
// 顺:    5~12;  Y4
// 连对:   6~16;  Y5  *
// 飞机:   6~16;  Y6
// 四带二: 6~8;   Y7  *
// 炸弹:   4      Y8  *
// 王炸:   2      Y8  *
// 牌组分类器
class BoardType{
    constructor(BoardList, Boards){
        this.Boards = BoardList
        this.BoardList = new Array()
        if(Boards!=null) 
            this.BoardList = Boards
        // 将牌对象划为简单的字面量
        this.BoardListValue = new Array();
        for(let i=0;i<BoardList.length;i++){
            this.BoardList.push( BoardList[i].surface )
            this.BoardListValue.push(BoardMarkMap.get(BoardList[i].surface))
        }
    }
    // 获取出牌的类型,判定牌是否严格属于哪一类型
    GetType(){
        var length = this.BoardList.length;
        // 单牌
        if(length === 1){
            return this.FiltrateSign(this.BoardList)
        }
        // 对子,王炸
        if(length === 2){
            return this.FiltrateTow(this.BoardList)
        }
        // 三带,炸弹
        if(length>=3 && length<=5){
            return this.FiltrateThree(this.BoardList)
        }
        // 飞机,连对,顺子,四带二
        if(length>=5 && length<=16){
            return this.FiltrateLine(this.BoardList)
        }
        
    }
    // 单牌过滤
    FiltrateSign(BoardList_){
        var value_ = BoardMarkMap.get(BoardList_[0])
        return new BoardCombin(this.Boards, "Y1", value_, 1)
    }
    // 双牌过滤=》王炸
    FiltrateTow(BoardList_){
        if(BoardList_[0]===BoardList_[1]){
            var value_ = BoardMarkMap.get(BoardList_[0])
            return new BoardCombin(this.Boards, "Y2", value_, 2)
        } else{
            return this.FiltrateKingMax(BoardList_)
        }
    }
    // 三带过滤=》顺子=》炸弹
    FiltrateThree(BoardList_){
        var temp = BoardList_.join('')
        // 其中任一一张牌出现三次以上
        var reg = /(\d|J|Q|K|A)\1{2}/
        var index = temp.search(reg)
        if(!reg.test(temp)) {
            // 如果没有匹配到三带,那么有可能是顺子
            if(temp.length===5) 
                return this.FiltrateLine(BoardList_)
            return null
        };
        
        var value_ = BoardMarkMap.get(BoardList_[index])
        // 判断是三不带|三带一|三带对
        temp = temp.replace(reg, '')
        if(temp.length==0)
            return new BoardCombin(this.Boards, "Y3", value_, 3)
        if(temp.length==1 && temp!=BoardList_[index])
            return new BoardCombin(this.Boards, "Y3", value_, 4)
        else if(temp.length==1){
            return this.FiltrateBomb(BoardList_);
        }
        if(temp.length==2 && temp[0] == temp[1])
            return new BoardCombin(this.Boards, "Y3", value_, 5)
        return null
    }
    // 顺子过滤=》连对=》飞机=》四带二
    FiltrateLine(BoardList_){
        var temp = BoardList_.join('')
        // 如果牌组数量大于5,那么更有可能是连对或者飞机,四带二
        if(temp.length>5){
            var tempData = null;
            // 过滤连对,过滤四带二,只有偶数才可
            if(temp.length%2===0)
            {
                tempData = this.FiltrateLineTwo(BoardList_)
                if(tempData != null) return tempData
                var tempData = this.FiltrateFour(BoardList_)
                if(tempData != null) return tempData
            }
            // 飞机过滤
            tempData = this.FiltrateAir(BoardList_)
            if(tempData != null) return tempData
        }
        // 如果出现2,小鬼,大鬼那么就不是顺子
        var reg = /(2|C|G)/
        if(reg.test(temp)) return null;
        var value_ = this.BoardListValue[0]
        for(var i=1; i<BoardList_.length; i++){
            // 顺子必须是连续的,即每个数之间相差要等于1
            if(this.BoardListValue[i-1]-this.BoardListValue[i]!=1)
                return null;
        }
        return new BoardCombin(this.Boards,'Y4', value_, BoardList_.length)
    }
    // 飞机过滤
    // 飞机可带两张单牌,或者两个对子,亦或者不带
    FiltrateAir(BoardList_){
        var temp = BoardList_.join('')
        // 其中任多张牌出现三次
        var reg = /(0|[3-9]|J|Q|K|A)\1{2}/g // 三带
        var tempList_1 = temp.match(reg)
        if(tempList_1==null) return null
        var recode = 0
        // 飞机至少要是两个连起来的三带
        for(var i=1; i<tempList_1.length; i++){
            var i1 = BoardMarkMap.get(tempList_1[i][0])
            var i2 = BoardMarkMap.get(tempList_1[i-1][0])
            if(i2-i1==1){
                temp = temp.replace(tempList_1[i],'')
                temp = temp.replace(tempList_1[i-1],'')
            }else
                recode++
        }
        var len = tempList_1.length-recode
        if(len<2) return null
        // 返回牌组对象
        var value_ = BoardMarkMap.get(tempList_1[0][0])
        // 三不带
        if(temp.length===0)
            return new BoardCombin(this.Boards, 'Y6', value_, BoardList_.length)
        // 判断剩余的牌,剩余的牌有可能是单牌也可能是对子
        var reg_Two = /(\d|J|Q|K|A|2)\1{1}/g // 对子
        var tempList_2 = temp.match(reg_Two)
        // 飞机带对子,每个飞机可以带一个对子所以必须数量一致
        if(tempList_2!=null && tempList_2.length!=len && temp.length!=len)
            return null
        if(tempList_2==null && temp.length!=len)
            return null
        return new BoardCombin(this.Boards, 'Y6', value_, BoardList_.length)
    }
    // 四带二,四可带两张or两对
    FiltrateFour(BoardList_){
        if(BoardList_.length>8) return null
        // 因为四带二是由炸弹组成,匹配四张牌
        var temp = BoardList_.join('')
        // 其中任一一张牌出现四次
        var reg = /(\d|J|Q|K|A)\1{3}/
        var index = temp.search(reg)
        if(index==-1) return null
        // 将四张一样的牌剔除掉
        temp = temp.replace(reg,'')
        var reg_Two = /(\d|J|Q|K|A|C|G)\1{1}/g
        // 匹配剩余的牌;
        var temp_list2 = temp.match(reg_Two)
        if(temp.length==4 && temp_list2.length!=2) 
            return null 
        if(temp.length==2 && temp_list2.length==0)
            return null
        // 获取四带二的价值面
        var value_ = BoardMarkMap.get(BoardList_[index])
        return new BoardCombin(this.Boards, 'Y7', value_, BoardList_.length)
    }
    // 连对
    FiltrateLineTwo(BoardList_){
        var temp = BoardList_.join('')
        // 连对边缘判断,包含2,小鬼,大鬼就不是连对,且连对为偶数
        if((/(2|C|G)/).test(temp) || temp.length%2!=0) 
            return null;
        var reg = /(\d|J|Q|K)\1{1}/g
        if(temp.replace(reg,'')!=='')
            return null;
        var tempList = temp.match(reg)
        if(tempList.length>=3){
            // 判断连续的对子是否为顺序的
            for(let j=1; j<tempList.length; j++){
                var tempData_1 = BoardMarkMap.get(tempList[j][0])
                var tempData_2 = BoardMarkMap.get(tempList[j-1][0])
                if(tempData_2-tempData_1!==1)
                    return null;
            }
        }
        var value_ = BoardMarkMap.get(tempList[0][0])
        return new BoardCombin(this.Boards, 'Y5', value_, BoardList_.length)
    }
    // 炸弹
    FiltrateBomb(BoardList_){
        var temp = BoardList_.join('')
        // 其中任一一张牌出现四次
        var reg = /(\d|J|Q|K)\1{3}/
        if(!reg.test(temp)) return null
        var value_1 = BoardMarkMap.get(BoardList_[0])
        return new BoardCombin(this.Boards, 'Y8', value_1, 4)
    }
    // 王炸
    FiltrateKingMax(BoardList_){
        if(BoardList_[0]==="G" && BoardList_[1]==="C"){
            var value_1 = BoardMarkMap.get(BoardList_[0])
            var value_2 = BoardMarkMap.get(BoardList_[1])
            return new BoardCombin(this.Boards, "Y8", value_1+value_2, 2)
        }
        return null
    }

    // 将牌变为所有该类型
    GetAllType(type, value_){
        switch(type){
            case 'Y1':
                return this.FiltrateSign_All(value_)
        }
    }

    // 返回最小的一张单牌
    FiltrateSign_All(value_){
        for(let i=this.BoardListValue.length; i>0; i--){
            if(this.BoardListValue[i-1]>value_)
                return [this.Boards[i-1]]
        }
        return null
    }

}

// 玩家出牌记录器
class BoardPlayer{
    constructor(BoardList, PlayerIndex){
        if(BoardList instanceof Map)
            BoardList = Array.from(BoardList.values())
        // 先将牌面进行排序
        BoardSort(BoardList)
        let Boards = new BoardType(BoardList)
        // 再将牌变为合法的规则牌
        this.CurrentBoardCombin = Boards.GetType()
        this.CurrentBoards = Boards.Boards
        this.PlayerIndex = PlayerIndex
    }
    Show(){
        let typeShow = this.CurrentBoardCombin
        if(typeShow==null) 
        {
            TxtInfo.innerText = '无效牌'
            return null
        }
        TxtInfo.innerText = BoardTypeMap.get(typeShow.Type)+'-'+typeShow.Value
        return typeShow
    }
}

// 已出牌池
class BoardPond{
    constructor(){
        this.CurrentBoardPond = new Array()
    }
    // 出牌,将牌置入出牌池
    SetAddBoard(BoardPlayer){
        this.CurrentBoardPond.unshift(BoardPlayer)
    }
    // 获取牌顶的类型
    GetCurrentBoard(){
        return this.CurrentBoardPond[0].CurrentBoardCombin
    }
}

 GrawGame.js

/**
 * 游戏的画面及动作绘制
 */

//------------------- 绘制各种图形和动作

// 绘制牌
function CreateBorad(x, y, Board){
    var group = new Konva.Group()
    var text = Board.surface
    var color = 'black'
    var width_ = 25
    var x_ = x+5
    if(text=='G'){
        color = 'red'
    }
    if(text=='C'||text=='G') {
        width_ = 14
        text='Joke'
    }
    if(text=='0') {
        text = '10' 
        x_ = x+8
    }
    var type = Board.type
    var rect = new Konva.Rect({
      x: x,
      y: y,
      stroke: '#555',
      fill: 'white',
      strokeWidth: 1,
      shadowColor: 'black',
      shadowBlur: 0,
      shadowOffset: { x: 5, y: 5 },
      shadowOpacity: 0.3,
      width: BoardWidth,
      height: BoardHight,
    });
    group.add(rect)
    if(type=='♠' || type=='♣') 
        color = 'black'
    else if(type=='♥' || type=='♦') 
        color = 'red'
    var BoardTxt = new Konva.Text({
      x: x+5,
      y: y+5,
      text: text,
      fontSize: 18,
      width: width_,
      fill: color
    });
    group.add(BoardTxt)
    if(text!='Joke')
    {
        group.add(new Konva.Text({
            x: x_,
            y: y+20,
            text: type,
            fontSize: 20,
            fill: color
          }))
        group.add(new Konva.Text({
            x: x+BoardWidth*0.33,
            y: y+25,
            text: type,
            fontSize: BoardWidth*0.666+5,
            fill: color
        }))
    }else{
        // 绘制大符号
        group.add(new Konva.Text({
            x: x+BoardWidth*0.266,
            y: y+30,
            text: type,
            fontSize: 25,
            fill: color
        }))
    }
    
    return group;
}

// 选中牌动画绘制;IsPass:是否绕过该判断,直接对牌进行操作,一般用于牌的初始化
function GoOrOut(node, Board, IsPass=false){
    // console.log(node)
    if(!IsLockClick && !IsPass) return
    let id = 0
    let BoardNode = null
    // 有可能是直接操作的对象
    if(node.target){
        id = node.target.parent._id
        BoardNode = node.target.parent
    }else{
        id = node._id
        BoardNode = node
    }
    
    let tempI = 20
    if(!TempBorad.has(id)){
        TempBorad.set(id, Board)
    }else{
        tempI = -20
        TempBorad.delete(id)
    }
    var tween = new Konva.Tween({
        node: BoardNode,
        duration: 0.005,
        y: BoardNode.attrs.y-tempI,
    });
    tween.play();
}

// 取消选中的牌,将牌归位
function RestoreBoard(){
    return new Promise((a, b)=>{
        IsLockClick = true
        let TempBorad_ = Array.from(TempBorad)
        for(let i=0;i<TempBorad_.length;i++){
            // console.log(TempBorad_[i])
            GoOrOut(TempBorad_[i][1].DrawBoardFront, TempBorad_[i][1], true)
        }
        IsLockClick = false
        a()
    })
    
}

// 绘制牌的反面
function BoardBack(x, y){
    var group = new Konva.Group()
    var rect = new Konva.Rect({
        x: x,
        y: y,
        stroke: '#555',
        fill: 'white',
        strokeWidth: 1,
        shadowColor: 'black',
        shadowBlur: 0,
        shadowOffset: { x: 5, y: 5 },
        shadowOpacity: 0.3,
        width: BoardWidth,
        height: BoardHight,
    })
    group.add(rect)
    
    for(var i=0; i<10; i++){
        let tempPoints = new Array()
        for(var j=0; j<10; j++){
            if(j%2==0){
                tempPoints.push(x+ i*BoardWidth/10+BoardWidth/10)
            }else{
                tempPoints.push(x+ i*BoardWidth/10)
            }
            tempPoints.push(y+BoardHight/9*j)
        }
        var redLine = new Konva.Line({
            points: tempPoints,
            stroke: 'block',
            strokeWidth: 1,
            lineCap: 'round',
            lineJoin: 'round'
          });
        group.add(redLine)
    }
    
    return group
}

// 旋转牌并移动角度并移动位置
// 动画执行到百分之多少就开始停止阻塞
function RotateBoard(node, rotation, duration, x, y, stopblock){
    return new Promise((a, b)=>{
        if(stopblock==null||stopblock==undefined||stopblock>1) 
            stopblock = 1
        if(stopblock<0) 
            stopblock = 0
        var temp = CalcXAndY(x, y, node.children[0].attrs.x, node.children[0].attrs.y)
        let oldX = temp.x
        let oldY = temp.y
        var tween = new Konva.Tween({
            node: node,
            duration: duration,
            x: oldX,
            y: oldY,
            rotation: rotation
        });
        tween.play();
        setTimeout(() => {
            a()
        }, duration*1000*stopblock);
    })
}

// 绘制倒计时的秒表
function DrawTime(){
    var simpleText = new Konva.Text({
        x: width / 2 - 40,
        y: height / 2 - 50,
        id: 'Time',
        text: EveryTime,
        fontSize: 40,
        fontFamily: 'Calibri',
        stroke: 'black',
        fill: 'white',
        padding: 5,
        align: 'center'
    });
    return simpleText
}

// 绘制地主和农民的标签
function ClassTitle(){
    let x1 = width*0.05+3
    let y1 = 5
    let x2 = width*0.95 - BoardWidth +3
    let y2 = 5
    let myx = (width)/2 - 18 
    let myy = height-20
    BoardLayer.add(
        Draw(x1, y1, 
            Loandlords_Paly_==1?'地主':'农民', 
            Loandlords_Paly_==1?'blue':'black',  'white'))
    BoardLayer.add(
        Draw(x2, y2, 
            Loandlords_Paly_==2?'地主':'农民', 
            Loandlords_Paly_==2?'blue':'black', 'white'))
    BoardLayer.add(
        Draw(myx, myy, 
            Loandlords_Paly_==0?'地主':'农民', 
            Loandlords_Paly_==0?'blue':'black', 'white'))

    function Draw( x, y, text, bgcolor, txtcolor){
        var tooltip = new Konva.Label({
            x: x,
            y: y,
            opacity: 0.75
          });
          tooltip.add(
            new Konva.Tag({
              fill: bgcolor,
              lineJoin: 'round',
              shadowColor: 'black',
              shadowBlur: 10,
              shadowOffsetX: 10,
              shadowOffsetY: 10,
              shadowOpacity: 0.5
            })
          );
      
          tooltip.add(
            new Konva.Text({
              text: text,
              fontFamily: 'Calibri',
              fontSize: 15,
              padding: 3,
              fill: txtcolor
            })
          );
          return tooltip
    }
}

// 绘制桌子
function DrawTable(){
    var play0Rect = new Konva.Rect({
        x: (width/2)-(((20-1)*25+BoardWidth)/2)-10,
        y: (height)-height*0.05-BoardHight - 10,
        width: ((20-1)*25+BoardWidth)+20,
        height: BoardHight + 20,
        cornerRadius: [10, 10, 10, 10],
        fill: PlayerList[0].Color,
    });
    var play1Rect = new Konva.Rect({
        x: 30,
        y: 20,
        width: BoardWidth+30,
        height: 18*17,
        cornerRadius: [10, 10, 10, 10],
        fill: PlayerList[1].Color
    });
    var play2Rect = new Konva.Rect({
        x: width - (BoardWidth+60),
        y: 20,
        width: BoardWidth+30,
        height: 18*17,
        cornerRadius: [10, 10, 10, 10],
        fill: PlayerList[2].Color,
    });
    Tab_ = new Konva.Rect({
        x: ((width/2) - 600/2),
        y: ((height/2) - 200/2 - 40),
        width: 600,
        height: 200,
        cornerRadius: [10, 10, 10, 10],
        fill: 'DarkGreen',
    });
    BoardLayer.add(play0Rect);
    BoardLayer.add(play1Rect);
    BoardLayer.add(play2Rect);
    BoardLayer.add(Tab_);
}

// 绘制桌子颜色
function DrawTabColor(pIndex){
    var tween = new Konva.Tween({
        node: Tab_,
        duration: 1,
        fill: PlayerList[pIndex].Color
    });
    tween.play()
}

//-------------------


// 计算X和目标X,Y和目标Y相距多少
function CalcXAndY(x1, y1, x2, y2){
    let tempX = x1-x2
    let tempY = y1-y2
    return { x: tempX, y: tempY }
}

// 发牌动画
function DrawSendBoard(){
    return new Promise(async (a, b)=>{
        // 发牌给玩家
        var GroupWidth = (width/2)-((16*25+BoardWidth)/2)
        var BaseY = (height)-height*0.05-BoardHight

        // 发牌给上家
        var BaseX_1 = width*0.05
        var BaseY_1 = BoardHight*0.3

        // 发牌给下家
        var BaseX_2 = width*0.95 - BoardWidth
        var BaseY_2 = BoardHight*0.3

        var i = 0
        for(let i=0; i<17; i++){
            await RotateBoard(PlayerList[1].BoardList[i].DrawBoardBack, 0, 0.25, BaseX_1, BaseY_1+i*10, 0.05)
            RotateBoard(PlayerList[1].BoardList[i].DrawBoardFront, 0, 0.25, BaseX_1, BaseY_1+i*10, 0)
            RotateBoard(PlayerList[2].BoardList[i].DrawBoardBack, 0, 0.25, BaseX_2, BaseY_2+i*10, 0.05) 
            RotateBoard(PlayerList[2].BoardList[i].DrawBoardFront, 0, 0.25, BaseX_2, BaseY_2+i*10, 0) 
            RotateBoard(PlayerList[0].BoardList[i].DrawBoardFront, 0, 0.25, i*25+GroupWidth, BaseY, 0.05)
        }
        a()
    })
}

// 将牌整理到合适位置
function InitLocationBoard(player){
    return new Promise(async (a,b)=>{
        if(player.name=='玩家一'){
            player.BoardListSort()
            IsLockClick = false
            let len = player.BoardList.length
            let width_ = (width/2)-(((len-1)*25+BoardWidth)/2)
            var BaseY = (height)-height*0.05-BoardHight
            for(let i=0; i<player.BoardList.length; i++){
                player.BoardList[i].DrawBoardFront.remove()
                let tempDraw = player.BoardList[i].DrawBoardFront
                MyBoardGroup.add(tempDraw)
                if(tempDraw)
                    await RotateBoard(tempDraw, 0, 0.1, i*25+width_, BaseY, 0.2)
            }
        }
        a()
    })
    
}

// 玩家出牌信息绘制区
function PlayerMessage(player, BoardCombin){
    let Group_ = player.Group
    let Boards = BoardCombin.CurrentBoards
    let len = Boards.length
    let x, y;
    // 玩家一出牌动画
    function PalyerMySend(){
        return new Promise(async (result, reject)=>{
            Group_.destroyChildren()
            x = (width/2)-(((len-1)*25+BoardWidth)/2)
            y = 270-BoardHight
            for(let i = 0; i<len; i++){
                let node = Boards[i].DrawBoardFront
                // 注销事件
                node.off('mouseenter.select')
                node.off('mousedown.click')
                node.remove()
                Group_.add(node)
                await RotateBoard(node, 0, 0.2, i*25+x, y, 0)
                player.DeleteIDOfBoard(Boards[i].id)
            }
            result()
        })
    }
    // 玩家二或三出牌动画
    function PalyerTwoOrThreeSend(player, BoardCombin){
        return new Promise(async (result, reject)=>{
            Group_.destroyChildren()
            if(player.name=='玩家二')
                x = ((width/2) - 600/2)
            else
                x = ((width/2) + 600/2 - BoardWidth)

            y = ((height/2) - 200/2 - 40)
            for(let i = 0; i<len; i++){
                let node1 = Boards[i].DrawBoardFront
                let node2 = Boards[i].DrawBoardBack
                node1.remove()
                node2.remove()
                Group_.add(node1)
                Group_.add(node2)
                RotateBoard(node1, 0, 0.2, i*25+x, y, 0)
                await RotateBoard(node2, 0, 0.2, i*25+x, y, 0)
                player.DeleteIDOfBoard(Boards[i].id)
                node1.show()
                node2.hide()
            }
            BoardLayer.draw()
            result()
        })
    }
    return new Promise(async (result, reject)=>{
        if(BoardCombin==null){
            // 画不要
            result()
            return
        }
        if(player.name=='玩家一'){
            await PalyerMySend(player, BoardCombin)
        }else{
            await PalyerTwoOrThreeSend(player, BoardCombin)
        }
        await InitLocationBoard(player)
        result()
    })
}




konva.min.js

这里代码比较长,已上传主页资源,也可以评论区找我要~

PlayGame.js

/**
 * 游戏主体逻辑,包括开始游戏,结束游戏等
 * 主要是开始游戏到循环游戏直到游戏结束的状态变化
 * 也包括初始化整个游戏
 */

// 牌面初始化
function InitBoard(){
    // 将牌打乱
    for(let i=53;i>0;i--){
        BoardListGameInit[i].DrawBoardFront.hide()
        BoardListGameInit[i].DrawBoardBack.hide()
        let randomIndex = Math.floor( Math.random()*i+1)
        BoardListGameInit.push(BoardListGameInit[randomIndex])
        BoardListGameInit.splice(randomIndex,1)
    }
    // 地主牌
    for(let i=0; i<6; i++){
        let temp = 3
        if(i==0) temp-=1
        PlayerList[0].BoardList.push(...BoardListGameInit.splice(0, temp))
        PlayerList[1].BoardList.push(...BoardListGameInit.splice(0, temp))
        PlayerList[2].BoardList.push(...BoardListGameInit.splice(0, temp))
    }
    // 将牌排列整齐
    BoardSort(BoardListGameInit)
    PlayerList[0].BoardListSort()
    PlayerList[1].BoardListSort()
    PlayerList[2].BoardListSort()

}

// 按钮闭包
var Button_ = (function(){
    // 注册事件
    let EventListener = new Array()
    // 显示按钮且添加事件
    function ShowButtonAndEvent(text1, text2, buttonLeftEvent, buttonRightEvent){
        // 添加事件之前需要先注销掉之前的事件
        HideButtonAndDeEvent()
        ShowAndHide(true)
        ButtonOne1.innerText = text1
        ButtonOne2.innerText = text2
        ButtonOne1.addEventListener('click',buttonLeftEvent)
        ButtonOne2.addEventListener('click',buttonRightEvent)
        EventListener[0] = buttonLeftEvent
        EventListener[1] = buttonRightEvent
    }
    // 隐藏按钮且删除事件
    function HideButtonAndDeEvent(){
        ShowAndHide(false)
        // 移除事件
        if(EventListener.length>0){
            ButtonOne1.removeEventListener('click',EventListener[0])
            ButtonOne2.removeEventListener('click',EventListener[1])
            EventListener.splice(0,1)
            EventListener.splice(0,1)
        }
    }
    // 隐藏或显示
    function ShowAndHide(IsShow){
        ButtonDiv.style.display = IsShow? 'block':'none'
    }
    return {
        ShowButtonAndEvent: ShowButtonAndEvent,
        HideButtonAndDeEvent: HideButtonAndDeEvent,
        ShowAndHide: ShowAndHide
    }
})()

// 倒计时闭包
var TimeSecond = (function(){
    let i = EveryTime
    // 绘制秒表
    let timeControl = null
    // 是否暂停
    let IsPause = false
    // 动画ID
    let RAFId = null
    function Show(){
        if(!timeControl)
        {
            timeControl = DrawTime()
            BoardLayer.add(timeControl)
        }
        timeControl.show()
        DrawStart()
    }

    let oldTime = new Date()
    let newDate = 0

    // 开始倒计时
    function DrawStart(){
        newDate = new Date()
        if(newDate-oldTime > 1000 && !IsPause){
            // console.log()
            timeControl.text(i<10?'0'+i:i)
            BoardLayer.draw()
            i--
            oldTime = new Date()
        }
        if(i<0){
            Close()
            // 默认当该倒计时结束,那么触发第一个按钮的点击事件
            ButtonOne1.click()
            return
        } 
        RAFId = window.requestAnimationFrame(DrawStart)
    }

    // 关闭且初始化
    function Close(){
        if(RAFId)
            window.cancelAnimationFrame(RAFId)
        i = 20
        IsPause = false
        timeControl.hide()
        BoardLayer.draw()
        RAFId = null
    }
    return {
        timeControl: timeControl,
        Show: Show,
        Close: Close,
        IsPause: IsPause
    }
})()

// 发牌
async function SendBorad(){

    // 玩家牌组
    // 在玩家牌组上面注册一个组合,如果在该组合上面点击,那么将开启选牌
    // 离开该组合将注销
    let IsSelect = false // 是否可以选中牌
    MyBoardGroup = new Konva.Group()
    NotMeBoard_Group = new Konva.Group()
    
    MyBoardGroup.on('mousedown', ()=> { IsSelect=true })
    MyBoardGroup.on('mouseup mouseleave', ()=> { 
        IsSelect=false;
        if(TempBorad!=null)
            new BoardPlayer(TempBorad, 0).Show()
    })


    // 给地主牌注册事件,因为该地主牌有可能是玩家的手牌
    for(let i=0;i<3; i++){
        BoardListGameInit[i].DrawBoardFront.show()
        BoardListGameInit[i].DrawBoardBack.hide()
        // 注册事件
        BoardListGameInit[i].DrawBoardFront.on('mouseenter.select', (node)=>{
            if (IsSelect && Loandlords_Paly_==0)
                GoOrOut(node, BoardListGameInit[i])
        })
        BoardListGameInit[i].DrawBoardFront.on('mousedown.click', (node)=>{
            if(Loandlords_Paly_==0)
                GoOrOut(node, BoardListGameInit[i])
        })
    }

    // 生成具体的牌对象
    for(let i = 0;i<3; i++){
        for(let j=0; j<PlayerList[i].BoardList.length;j++){
            let Board = PlayerList[i].BoardList[j]
            let group = null
            if(i==0){
                group = Board.DrawBoardFront
                group.on('mouseenter.select', (node)=>{
                    if (IsSelect)
                        GoOrOut(node, Board)
                })
                group.on('mousedown.click', (node)=>{
                    GoOrOut(node, Board)
                })
                // console.log(group)
                MyBoardGroup.add(group)
            }else{
                group = Board.DrawBoardBack
                let DrawBoardFront = Board.DrawBoardFront
                DrawBoardFront.hide()
                NotMeBoard_Group.add(group)
                NotMeBoard_Group.add(DrawBoardFront)
            }
            group.show()
        }
    }
    BoardLayer.add(MyBoardGroup)
    BoardLayer.add(NotMeBoard_Group)
    
    // 开始发牌动画
    await DrawSendBoard(BoardLayer)
    StartGame()
}

// 开始玩地主
async function StartGame(){

    // 将地主牌放到左上角
    for(let i = 0;i<3;i++){
        BoardLayer.add(BoardListGameInit[i].DrawBoardFront)
        BoardLayer.add(BoardListGameInit[i].DrawBoardBack)
        RotateBoard(BoardListGameInit[i].DrawBoardFront, 0, 0.2, width*0.15+i*BoardWidth, 0)
        RotateBoard(BoardListGameInit[i].DrawBoardBack, 0, 0.2, width*0.15+i*BoardWidth, 0.2)
    }

    // 叫地主
    setTimeout(() => {
        TimeSecond.Show()
        Loandlords_Paly()
    }, 500);

    // 将决定一个地主出来
    function Loandlords_Paly(){
        // 显示按钮且绑定事件
        Button_.ShowButtonAndEvent('不叫','叫地主', async ()=>{
            Loandlords_Paly_ = Math.floor( Math.random()*2+1)
            // 将倒计时关闭
            TimeSecond.Close()
            Button_.HideButtonAndDeEvent(true)

            // 必须等待动画完成
            await new Promise(async (a,b)=>{
                for(let i = 0; i<3; i++){
                    BoardListGameInit[i].DrawBoardBack.show()
                    PlayerList[Loandlords_Paly_].BoardList.push(BoardListGameInit[i])
                    NotMeBoard_Group.add(BoardListGameInit[i].DrawBoardBack)
                    if(Loandlords_Paly_==1)
                        await RotateBoard(BoardListGameInit[i].DrawBoardBack, 0, 0.2, width*0.05, (BoardHight*0.3)+(17*10)+i*10)
                    else
                        await RotateBoard(BoardListGameInit[i].DrawBoardBack, 0, 0.2, (width*0.95 - BoardWidth), (BoardHight*0.3)+(17*10)+i*10)

                    PlayerList[Loandlords_Paly_].BoardListSort()
                    a()
                }
            })
            StartFunGame()
        }, async ()=>{
            // 将倒计时关闭
            TimeSecond.Close()
            Button_.HideButtonAndDeEvent(true)
            Loandlords_Paly_ = 0
            // 叫地主;那么将地主牌添加到玩家手牌中
            PlayerList[0].BoardList.push(...BoardListGameInit)
            // 整理牌
            await InitLocationBoard(PlayerList[0])
            StartFunGame()
        })
    }
}

// 开始游戏循环
function StartFunGame(){
    // 实例化一个已经出了的牌池
    BoardPond_ = new BoardPond()
    // 绘制地主和农民
    ClassTitle()
    PlayerGroupCreate()
    BoardLayer.draw()
    // 玩家出牌的下标
    let CurrentIndex = Loandlords_Paly_
    // 周期回合数;用以记录当前是否已走完一个周期(即三名玩家)
    let Bout = 0
    // 绑定出牌不出牌事件
    Button_.ShowButtonAndEvent('不出','出牌', async ()=>{
        // 如果当前的回合是玩家,且第一张出牌的也是玩家,
        // 如果玩家还没出牌,那么需要随机出一张牌
        if(!CurrentBorad && CurrentIndex==0){
            console.log('玩家随机出牌')
            // 将牌复原的合适的位置
            await RestoreBoard()
        }
        // 当前已过完一整个周期;那么牌堆处设置为空
        if(Bout==1){
            Bout = 0
            CurrentBorad = null
        }else
            Bout++
        // 将倒计时关闭
        TimeSecond.Close()
        // 下一个回合
        NextGame()
    }, async ()=>{
        let Current_index = NextIndex(CurrentIndex, -1)
        let myBoard
        if(Current_index == 0)
        {
            myBoard = new BoardPlayer(TempBorad, 0)
            TempBorad.clear()
        }
        else // 机器人
        {
            myBoard = new BoardPlayer(RobotBoards, Current_index)
            RobotBoards = null
        }
        
        // 判定是否可以出牌
        if(JudgeBoard(myBoard)){
            // 将倒计时关闭
            TimeSecond.Close()
            Button_.ShowAndHide(false)

            // 将牌顶换为当前牌
            CurrentBorad = myBoard
            // console.log(myBoard)
            BoardPond_.SetAddBoard(myBoard)
            
            await PlayerMessage(PlayerList[Current_index], myBoard)
        }else 
        {
            console.log('不能出牌')
            return
        }
        // 新回合的开始重新设置
        Bout = 0
        NextGame()
    })
    // 游戏回合
    function NextGame(){
        if(PlayEnd()) return
        let CurrentIndex_ = CurrentIndex
        TimeSecond.Show()
        DrawTabColor(CurrentIndex)
        let isRobat = false
        if(CurrentIndex==0){
            IsLockClick = true
            Button_.ShowAndHide(true)
        }else{
            IsLockClick = false
            Button_.ShowAndHide(false)
            isRobat = true
        }
        PlayerList[CurrentIndex].Group.removeChildren()
        CurrentIndex = NextIndex(CurrentIndex)
        if(isRobat){
            setTimeout(() => {
                let _value = 0
                if(CurrentBorad!=null)
                    _value = CurrentBorad.CurrentBoardCombin.Value
                // 机器人出牌
                RobotBoards = new BoardType(PlayerList[CurrentIndex_].BoardList)
                    .GetAllType('Y1', _value)
                if(RobotBoards==null)
                    ButtonOne1.click()
                else
                    ButtonOne2.click()
            }, 1000);
        }
    }
    NextGame()
}

// 游戏结束
function PlayEnd(){
    let isEnd = false
    if(PlayerList[0].BoardList.length==0)
    {
        alert('游戏结束;你赢了')
        isEnd = true
    }
    if(PlayerList[1].BoardList.length==0)
    {
        alert('游戏结束;你上家赢了')
        isEnd = true
    }
    if(PlayerList[2].BoardList.length==0)
    {
        alert('游戏结束;你下家赢了')
        isEnd = true
    }
    if(isEnd){
        IsLockClick = false
        TimeSecond.Close()
        Button_.HideButtonAndDeEvent()
    }
    return isEnd
}

// 下一个玩家
function NextIndex(CurrentIndex_, Line=1){
    CurrentIndex_-=Line
    if(CurrentIndex_<0)
        CurrentIndex_=2
    else if(CurrentIndex_>2)
        CurrentIndex_=0
    return CurrentIndex_
}

// 判定系统,判定是否可以出牌
// 当牌顶为空,且牌顶数量与牌顶的真实价值小于当前出牌真实价值
// 且类型一致
function JudgeBoard(CurrentBoard_){
    if(CurrentBoard_.CurrentBoardCombin==null) return false
    if(CurrentBorad==null) return true
    
    if(CurrentBorad.CurrentBoardCombin.Value < CurrentBoard_.CurrentBoardCombin.Value)
    if(CurrentBorad.CurrentBoardCombin.Type == CurrentBoard_.CurrentBoardCombin.Type)
    if(CurrentBorad.CurrentBoardCombin.Length < CurrentBoard_.CurrentBoardCombin.Length || 
        CurrentBoard_.CurrentBoardCombin.Type != 'Y8')
        return true
    
    return false
}

// 玩家们的手牌绘制区
function PlayerGroupCreate(){
    PlayerList[0].Group = new Konva.Group()
    PlayerList[1].Group = new Konva.Group()
    PlayerList[2].Group = new Konva.Group()
    BoardLayer.add(PlayerList[0].Group)
    BoardLayer.add(PlayerList[1].Group)
    BoardLayer.add(PlayerList[2].Group)
}

// 将牌按照大小进行排序
function BoardSort(BoardList){
    // 先将牌面进行排序
    let len = BoardList.length
    for (var i = 0; i < len - 1; i++) {
        for (var j = 0; j < len - 1 - i; j++) {
            let value_1 = BoardMarkMap.get(BoardList[j].surface)
            let value_2 = BoardMarkMap.get(BoardList[j+1].surface)
            if (value_1 < value_2) {        // 相邻元素两两对比
                var temp = BoardList[j+1];        // 元素交换
                BoardList[j+1] = BoardList[j];
                BoardList[j] = temp;
            }
        }
    }
}

// 开始加载游戏
window.onload = function(){
    ButtonDiv = document.getElementById('ButtonDiv')
    ButtonOne1 = document.getElementById('CallLandLord')
    ButtonOne2 = document.getElementById('RobLandLord')
    TxtInfo = document.getElementById('txtInfo')
    // 首先必须添加一个场景
    Stage = new Konva.Stage({
        container: '#bodyPlayer',   // id of container <div>
        width: width,
        height: height
    });
    BoardLayer = new Konva.Layer()
    Stage.add(BoardLayer)
    DrawTable()
    InitBoard()
    SendBorad()
    
}

// 执行动画,第一个参数,动画执行函数
function RAF(){
    
}

veriable.js

/**
 * 作者:0.活在风浪里 v1.5.0
 * 变量初始化,记录有关游戏的所有全局变量
 */

//---------------------------------------游戏基本变量

// 牌面映射,字面量=》价值量
var BoardMarkMap = new Map();
BoardMarkMap.set('3', 3)
BoardMarkMap.set('4', 4)
BoardMarkMap.set('5', 5)
BoardMarkMap.set('6', 6)
BoardMarkMap.set('7', 7)
BoardMarkMap.set('8', 8)
BoardMarkMap.set('9', 9)
BoardMarkMap.set('0', 10) // 10
BoardMarkMap.set('J', 11)
BoardMarkMap.set('Q', 12)
BoardMarkMap.set('K', 13)
BoardMarkMap.set('A', 14)
BoardMarkMap.set('2', 15)
BoardMarkMap.set('C', 50) // 小鬼
BoardMarkMap.set('G', 100) // 大鬼

// 牌组合类型映射
var BoardTypeMap = new Map()
BoardTypeMap.set('Y1', '单牌')
BoardTypeMap.set('Y2', '对子')
BoardTypeMap.set('Y3', '三带')
BoardTypeMap.set('Y4', '顺子')
BoardTypeMap.set('Y5', '连对')
BoardTypeMap.set('Y6', '飞机')
BoardTypeMap.set('Y7', '四带二')
BoardTypeMap.set('Y8', '炸弹')
// BoardTypeMap.set('Y9', '王炸')

// 牌的绘制容器管理,可以通过该容器索引到任何一张牌的绘制内容
var BoardDrawMap = new Map()

// keys集合;获取牌的字面量如K,J,Q....
var BoardMarkMapKes = Array.from(BoardMarkMap.keys())

//---------------------------------------游戏结构性逻辑变量(包括绘制的逻辑变量)

// 画布的大小
const width = 844
const height = 390

// 牌有关的全局变量
const BoardWidth = 45
const BoardHight = 80

// 按钮的大小
const ButtonWidth = 120
const ButtonPadding = 20

// 每个回合等待的时间
const EveryTime = 20
// 按钮的容器:控制整体是否显示与否
var ButtonDiv = document.getElementById('ButtonDiv')
// 初始:叫地主=》过牌
var ButtonOne1 = document.getElementById('CallLandLord')
// 初始:不叫=》出牌
var ButtonOne2 = document.getElementById('RobLandLord')
// 头顶信息框
var TxtInfo = document.getElementById('txtInfo')

// 玩家手牌图层
var MyBoardGroup = null
// 机器人手牌图层
var NotMeBoard_Group = null

//---------------------------------------游戏内容逻辑变量
// 牌面绘制映射
var GrawBoard = new Map()
// 牌面选中集合
var TempBorad = new Map()
// 是否锁住点击事件
var IsLockClick = false
// 有几个玩家发完牌
var SendBoard = 0 
// 机器人牌面
var RobotBoards

// 玩家
var PlayerList = new Array()
// 自己,
PlayerList[0] = new Player([],'玩家一', 'SaddleBrown')
// 左边上家
PlayerList[1] = new Player([],'玩家二', 'DarkOliveGreen')
// 右边下家
PlayerList[2] = new Player([],'玩家三', 'MediumSlateBlue')

// 场景
var Stage = null
// 是否已出牌或者叫了地主
var isSelect = false
// 地主索引=》对应的是玩家的下标
var Loandlords_Paly_ = -1

// 图层
var BoardLayer = null
// 当前桌面牌堆;如果为null,则表明当前可以随意出牌
// 不然下一家必须接牌;类型:BoardPond
var CurrentBorad = null
// 牌池
var BoardPond_ = null
// 中间的桌子
var Tab_ = null

// 生成各种牌
var BoardListGameInit = new Array();
for(var i=0;i<15;i++){
    var key = BoardMarkMapKes[i]
    if(key=='C'){
        BoardListGameInit.push(new Board(key, '🧛', i*4))
        continue
    }else if(key=='G'){
        BoardListGameInit.push(new Board(key, '🧙‍♂️', 53))
        continue
    }
    BoardListGameInit.push(new Board(key, '♠', i*4))
    BoardListGameInit.push(new Board(key, '♥', i*4+1))
    BoardListGameInit.push(new Board(key, '♣', i*4+2))
    BoardListGameInit.push(new Board(key, '♦', i*4+3))
}

index.html

<!DOCTYPE html>
<head>
    <meta http-equiv="Content-Type" content="text/html" charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" >
    <title></title>
    <script src="script/konva.min.js"></script>
    <script src="script/GrawGame.js" ></script>
    <script src="script/GameEntity.js" ></script>
    <script src="script/veriable.js" ></script>
    <script src="script/PlayGame.js" ></script>
    <style>
        body {
            position: fixed;
            width: 100%;
            height: 390px;
            padding: 0;
            margin: 0;
            overflow: hidden;
        }
        .ButtonDiv{
            width: 90px;
            height: 20px;
            text-align: center;
            border-radius: 5px;
            padding: 5px;
            cursor: pointer;
            position:absolute;
        }
        #CallLandLord{
            top: 230px;
            left: calc(50% - 120px);
            background-color: aqua;
        }
        #RobLandLord{
            top: 230px;
            left: calc(50%);
            background-color: rgb(244, 158, 11);
        }
        #ButtonDiv{
            display: none;
        }
        @media screen and (orientation: portrait) {
            body {
                position: absolute;
                width: 100vh;
                height: 390px;
                top: 0;
                left: 100vw;
                -webkit-transform: rotate(90deg);
                -moz-transform: rotate(90deg);
                -ms-transform: rotate(90deg);
                transform: rotate(90deg);
                transform-origin: 0% 0%;
            }
        }
        @media screen and (orientation: landscape) {
            body {
                position: absolute;
                top: 0;
                left: 0;
                width: 100vw;
                height: 390px;
            }
        }
</style>
</head>
<body >
    <div id="bodyPlayer" style="margin: 0 auto; max-width: 844px; width: 100%; height: 390px; border: solid 1px;"></div>
    <div style="width: 300px; text-align: center;
    position: absolute; top: 3%; 
    left: calc(50% - 150px);" id="txtInfo"> 信息 </div>
    <div id="ButtonDiv">
        <div id="CallLandLord" class="ButtonDiv" > 不叫 </div>
        <div id="RobLandLord" class="ButtonDiv" > 叫地主 </div>
    </div>
    <script>

    </script>
</body>

</html>

以上则是全部代码,复制项目直接运行index.html,

结语:

本文到这也要搁笔了,感谢你们阅读至此!感谢阅读,多多提供意见参考,评论区随意放肆评论,我会一 一读,真诚参考,

 

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

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

相关文章

【Pytorch项目实战】之语义分割:U-Net、UNet++、U2Net

文章目录博主精品专栏导航一、前言1.1、什么是图像分割&#xff1f;1.2、语义分割与实例分割的区别1.3、语义分割的上下文信息1.4、语义分割的网络架构二、网络 数据集2.1、经典网络的发展史&#xff08;模型详解&#xff09;2.2、分割数据集下载三、算法详解3.1、U-Net3.1.1、…

oceanbase部署--使用OBD自动化部署三节点集群

准备步骤&#xff1a; 先将192.168.152.30 现有单节点集群stop&#xff0c;然后克隆两台虚拟机并在workstations重置网卡MAC&#xff0c;配置新主机IP [adminoceanbase ~]$ obd cluster list ---------------------------------------------------------------------- | …

【C语言学习笔记】:函数和对象

一、本篇要学习的内容和知识结构概览 二、知识点逐条分析 1. 混合型语言 C源文件的文件扩展名为.cpp, 也就是c plus plus的简写, 在该文件里有且只能有一个名为main的主函数, 它作为程序的入口. 因为这个主函数的存在, 所以C被称为混合型语言. 2. C语言当中的注释 第一种: …

[单片机框架][调试功能] 回溯案发现场

程序莫名死机跑飞&#xff0c;不知道问题&#xff0c;那么下面教你回溯错误源 回溯案发现场一、修改HardFault_Handler1. xx.s 在启动文件&#xff0c;找到HardFault_Handler。并修改。2. 定义HardFault_Handler_C函数。&#xff08;主要是打印信息并存储Flash&#xff09;3. 根…

javascript测试题

一、填空题 1. JavaScript 有两种引用数据类型 &#xff1a;___数组__、_____对象_ __。2. Javascript 通过___setTimeout______延迟指定时间后&#xff0c;去执行某程序。 3. Javascript 里 String 对象通过____indexOf____方法取第一次出现子字符 串的字符位置。4. Javascrip…

动态规划-背包问题

文章目录一、背包问题1. 背包问题简介2. 背包问题解决方法二、01 背包问题1. 实现思路2. 实现代码三、完全背包问题1. 实现思路2. 实现代码四、多重背包问题&#xff08;一&#xff09;1. 实现思路2. 实现代码五、多重背包问题&#xff08;二&#xff09;1. 实现思路2. 实现代码…

【C++之容器篇】精华:vector常见函数的接口的熟悉与使用

目录前言一、认识vector1. 介绍2. 成员类型二、默认成员函数&#xff08;Member functions&#xff09;1. 构造函数2. 拷贝构造函数vector (const vector& x);3. 析构函数4. 赋值运算符重载函数三、迭代器&#xff08;Iterators&#xff09;1. 普通对象的迭代器2. const对象…

4.5.3 ArrayList

文章目录1.特点2. 练习:ArrayList测试3.ArrayList扩容1.特点 存在java.util包中内部是用数组结构存放数据,封装数组的操作,每个对象都有下标内部数组默认的初始容量是10,如果不够会以1.5倍的容量增长查询快,增删数据效率会低 2. 练习:ArrayList测试 package partThree;import…

ROS2机器人编程简述humble-第四章-COMPUTATION GRAPH .2

下图所示&#xff0c;机器人和障碍物直接距离&#xff1a;可以看到如果是单线雷达&#xff0c;这种测距和传感器安装的位置密切相关。chatgpt&#xff1a;ROS2机器人的COMPUTATION GRAPH概念是指&#xff0c;通过构建一个图形结构&#xff0c;将机器人的计算任务分解成一系列的…

蓝桥杯-最长公共子序列(线性dp)

没有白走的路&#xff0c;每一步都算数&#x1f388;&#x1f388;&#x1f388; 题目描述&#xff1a; 已知有两个数组a,b。已知每个数组的长度。要求求出两个数组的最长公共子序列 序列 1 2 3 4 5 序列 2 3 2 1 4 5 子序列&#xff1a;从其中抽掉某个或多个元素而产生的新…

libVLC 视频裁剪

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 裁剪是指去除图像的外部部分,也就是从图像的左,右,顶部和/或底部移除一些东西。通常在视频中,裁剪是一种通过剪切不需要的部分来改变宽高比的特殊方式。 尤其是在做视频墙时,往往需要处理多个 vlc 实例…

【排序算法】归并排序(Merge Sort)

将两个的有序数列合并成一个有序数列&#xff0c;我们称之为"归并"。归并排序(Merge Sort)就是利用归并思想对数列进行排序。归并排序介绍根据具体的实现&#xff0c;归并排序包括"从上往下"和"从下往上"2种方式。从下往上的归并排序将待排序的数…

Java常见的六种线程池、线程池-四种拒绝策略总结

点个关注&#xff0c;必回关 一、线程池的四种拒绝策略&#xff1a; CallerRunsPolicy - 当触发拒绝策略&#xff0c;只要线程池没有关闭的话&#xff0c;则使用调用线程直接运行任务。 一般并发比较小&#xff0c;性能要求不高&#xff0c;不允许失败。 但是&#xff0c;由于…

SpringCloud(20):Sentinel原理

1.Sentinel主要功能设计理念 1.1 流量控制 流量控制在网络传输中是一个常用的概念&#xff0c;它用于调整网络包的发送数据。然而&#xff0c;从系统稳定性角度考虑&#xff0c;在处理请求的速度上&#xff0c;也有非常多的讲究。任意时间到来的请求往往是随机不可控的&#…

排序:归并排序

一、归并 li[2,4,5,7,//1,3,6,8]#归并的前提是必须两部分排好序 def merge(li,low,mid,high):ilowjmid1ltmp[]while i<mid and j<high: #只要左右两边都有数if li[i]<li[j]:ltmp.append(li[i])i1else:ltmp.append(li[j])j1#while执行完&#xff0c;肯定有一部分没数…

MDB 5 UI-KIT Bootstrap 5 最新版放送

顶级开源 UI 套件&#xff0c;Bootstrap v5 和 v4 的材料设计&#xff0c;jQuery 版本&#xff0c;数百个优质组件和模板&#xff0c;所有一致的&#xff0c;有据可查的&#xff0c;可靠的超级简单&#xff0c;1分钟安装简单的主题和定制 受到超过 3,000,000 名开发人员和设计师…

工业互联网时代,VR工厂如何实现多媒体营销?

2023开年以来&#xff0c;国内消费复苏脚步逐渐加快&#xff0c;无论是餐饮、旅游还是电影市场人气逐渐旺盛&#xff0c;可以看到消费市场逐渐暖起来。而工业互联网将会是产业数字化的主要抓手&#xff0c;VR工厂是新时期、新形势下&#xff0c;运用“互联网”思维&#xff0c;…

ChatGPT简要解读(三) - ChatGPT发展历程及模型训练机制

&#x1f482; 个人主页: 同学来啦&#x1f91f; 版权: 本文由【同学来啦】原创、在CSDN首发、需要转载请联系博主 &#x1f4ac; 如果文章对你有帮助&#xff0c;欢迎关注、点赞、收藏和订阅专栏哦 文章目录&#x1f423; 一、发展历程&#x1f534; 1、基本概念&#x1f7e0…

Android图形显示流程简介

注&#xff1a;本文缩写说明本文代码都是基于Android S一、概述本文将对从App画出一帧画面到这帧画面是如何到达屏幕并最终被人眼看到的这一过程进行简要分析&#xff0c;并将这其中涉及到的各个流程与其在systrace上的体现对应起来&#xff0c;期望最终能够让读者对Android系统…

Geek Uninstaller:向流氓软件火力全开,超良心的软件彻底卸载工具

写在前面 我们在电脑上安装软件&#xff0c;以及在使用软件的过程中&#xff0c;会产生一些程序文件、注册表项和临时文件等&#xff0c;用来支持软件的正常使用&#xff0c;都是正常现象。 但是&#xff0c;在卸载软件时&#xff0c;很多软件自身的卸载程序很不负责任&#…