# Gomoku

local Api           = {}
local AIGame        = {}
local BattleGame    = {}
local Config        = {}
local GobangEvent   = {}
local GobangMgr     = {}
local GobangData    = {}
local LogicEvent    = {}
local SwitchCtrl    = {}
local SettingRule   = {}
local TimerManager  = {}

function listenevents_gobang()

    ScriptSupportEvent:registerEvent([=[Block.PlaceBy]=],GobangEvent.block_placedby)
    ScriptSupportEvent:registerEvent([=[Block.Trigger]=],GobangEvent.block_trigger)
    ScriptSupportEvent:registerEvent([=[Game.AnyPlayer.LeaveGame]=],GobangEvent.playerLeaveGame)
    ScriptSupportEvent:registerEvent([=[Game.Start]=],GobangEvent.gamestart)
    ScriptSupportEvent:registerEvent([=[Game.Run]=],GobangEvent.gamerun)
    ScriptSupportEvent:registerEvent([=[Player.AreaIn]=],GobangEvent.playerAreaIn)
    ScriptSupportEvent:registerEvent([=[Player.AreaOut]=],GobangEvent.playerAreaOut)

end


Api = {
    Chat        = class.Chat.new(),
    Block       = class.Block.new(),
    Player      = class.Player.new(),
    Actor       = class.Actor.new(),
    Backpack    = class.Backpack.new(),
    Team        = class.Team.new(),
    MiniTimer   = class.MiniTimer.new(),
    Area        = class.Area.new(),
}


LogicEvent = {
    SwitchTriggerEvent = 1,
    ChangeThreeModeEvent = 2,
    ChangeCampEvent = 3,
    SelectedStartThreeModeEvent= 4,
    AIStartThreeModeEvent = 5,
    StartRoundEvent = 6,
    StartBeginGameEvent = 7,

    PlaceChessBlockEvent = 8,
    ChangeCurPlaceChessTypeEvent = 9,
    AIModeWinEvent = 10,
    AbstainEvent = 11,
    BattleModeWinEvent = 12,
    PlayerLeaveGame = 13,
    GameStartEvent = 14,
    PlayerAreaInEvent = 15,
    PlayerAreaOutEvent = 16,
}


GobangMgr = {


    HandleEvent = function(event,param)
        if event == LogicEvent.SwitchTriggerEvent then
            if param.blockid ~= 724 then return end

            SwitchCtrl.SwitchTrigger(param.x,param.y,param.z,param.eventobjid,param.blockid)

        elseif event == LogicEvent.ChangeThreeModeEvent then
            SettingRule.ChangeStartThreeChessPos(param.roomId)

        elseif event == LogicEvent.ChangeCampEvent then
            SettingRule.ChangePlayerPos(param.roomId)

        elseif event == LogicEvent.AIStartThreeModeEvent then
            AIGame.SetAIRoundBeforeData(param.roomId)

        elseif event == LogicEvent.StartBeginGameEvent then
            AIGame.ResetData(param.roomId)
            BattleGame.ResetData(param.roomId)
            SettingRule.SetDefaultThreeChess(param.roomId)
            AIGame.InitWinsList(param.roomId)
            SettingRule.SetPlayerPos(param.roomId)
            BattleGame.SetStartGameData(param.roomId)

        elseif event == LogicEvent.StartRoundEvent then
            SettingRule.GainItemChessToPlayer(param.roomId)
            AIGame.SetPlaceThreeChess(param.roomId)
            AIGame.StartRound(param.roomId)
            BattleGame.SetPlaceThreeChess(param.roomId)
            BattleGame.StartRound(param.roomId);

        elseif event == LogicEvent.PlaceChessBlockEvent then
            GobangMgr.PlaceChessBlock(param)

        elseif event == LogicEvent.ChangeCurPlaceChessTypeEvent then
            GobangMgr.ChangeCurPlaceChessType(param)

        elseif event == LogicEvent.AIModeWinEvent then
            GobangMgr.AIModeWin(param)

        elseif  event == LogicEvent.BattleModeWinEvent then
            GobangMgr.BattleModeWin(param)

        elseif event == LogicEvent.PlayerLeaveGame then
            GobangMgr.PlayerLeaveGame(param.eventobjid)
        elseif event == LogicEvent.GameStartEvent then
            GobangMgr.InitRoomArea()

        elseif event == LogicEvent.PlayerAreaInEvent then
            SettingRule.PlayerAreaIn(param.areaid,param.eventobjid)
        elseif event == LogicEvent.PlayerAreaOutEvent then
            SettingRule.PlayerAreaOut(param.areaid,param.eventobjid)
        end

    end,


    JudgeChessInChessboard = function(roomId,x,y,z)
        if x == nil and y == nil and z == nil then return false end


        local CheckerboardPos = Config.Checkerboard[roomId]
        if CheckerboardPos == nil then return false end
        print(CheckerboardPos)
        local rangeBeginPos = CheckerboardPos.beginPos;
        local rangeEndPos = CheckerboardPos.endPos;

        if rangeBeginPos.y ~= y or rangeEndPos.y ~= y then
            return false;
        end

        local maxCoord = 0;
        local minCoord = 0;


        maxCoord = math.max(rangeEndPos.x, rangeBeginPos.x)
        minCoord = math.min(rangeEndPos.x, rangeBeginPos.x)
        if x > maxCoord or x <minCoord then
            return false;
        end

        maxCoord = math.max(rangeEndPos.z, rangeBeginPos.z)
        minCoord = math.min(rangeEndPos.z, rangeBeginPos.z)
        if z > maxCoord or z <minCoord then
            return false;
        end

        return true;

    end,


    PlaceChessBlock = function (param)
        if param == nil then return end

        local curRoomId = GobangMgr.GetRoomidByPos(param.x,param.y,param.z)
        if param.eventobjid == nil then return end


        if curRoomId == nil then print("Fail to get the board ID")
            Api.Block:destroyBlock(param.x,param.y,param.z,false)
            return
        end


        local isRight = SettingRule.GetChessPlaceIsRight(curRoomId,param.eventobjid,param.x,param.y,param.z,param.blockid)
        if isRight == false then
            return
        end


        local data = GobangData[curRoomId]
        if data.IsAI and data.IsWin ==false then

            AIGame.ChessBlockPlaceTrigger(param)
        else

            if GobangData[curRoomId].IsBeginRound == false or data.IsWin then return end
            BattleGame.BlockPlacedBy(param.x,param.y,param.z,param.blockid,param.eventobjid)
        end

    end,


    ChangeCurPlaceChessType = function(param)
        if GobangData[param.roomId].IsAI and GobangData[param.roomId].CurChessType == GobangData[param.roomId].AIChess then
            if GobangData[param.roomId].IsBeginRound == false then return end
            TimerManager.CreateTimer(1,function()
                AIGame.ComputerAI(param.roomId)
            end)
        end
    end,


    AIModeWin = function(param)
        local data = GobangData[param.roomId]


        if data.BlackChess.uin ~= nil then
            --Api.Player:teleportHome(data.BlackChess.uin)
           --Api.Backpack:clearAllPack(data.BlackChess.uin)
            Api.Player:notifyGameInfo2Self(data.BlackChess.uin,"Winner has appeared.Game ends. ")
            SettingRule.SetTipLightState(param.roomId,Config.ChessType.BlackChess,false)
            Api.Backpack:removeGridItemByItemID(data.BlackChess.uin, Config.BlockIdEnum[Config.ChessType.BlackChess],1000);
        end

        if data.WhiteChess.uin ~= nil then
            --Api.Player:teleportHome(data.WhiteChess.uin)
            --Api.Backpack:clearAllPack(data.WhiteChess.uin)
            Api.Player:notifyGameInfo2Self(data.WhiteChess.uin,"Winner has appeared.Game ends. ")
            SettingRule.SetTipLightState(param.roomId,Config.ChessType.WhiteChess,false)
            Api.Backpack:removeGridItemByItemID(data.WhiteChess.uin, Config.BlockIdEnum[Config.ChessType.WhiteChess],1000);
        end


        SettingRule.ClearAreaPlayerBuff(param.roomId)
        GobangData.ResetRoomState(param.roomId)
        TimerManager.ClearRoundTimer(param.roomId)
        
    end,


    BattleModeWin = function(param)
        local data = GobangData[param.roomId]


        if data.BlackChess.uin ~= nil then
            --Api.Player:teleportHome(data.BlackChess.uin)
            --Api.Backpack:clearAllPack(data.BlackChess.uin)
            Api.Player:notifyGameInfo2Self(data.BlackChess.uin,"Winner has appeared.Game ends. ")
            SettingRule.SetTipLightState(param.roomId,Config.ChessType.BlackChess,false)
            Api.Backpack:removeGridItemByItemID(data.BlackChess.uin, Config.BlockIdEnum[Config.ChessType.BlackChess],1000);
        end

        if data.WhiteChess.uin ~= nil then
            Api.Player:notifyGameInfo2Self(data.WhiteChess.uin,"Winner has appeared.Game ends. ")
            SettingRule.SetTipLightState(param.roomId,Config.ChessType.WhiteChess,false)
            Api.Backpack:removeGridItemByItemID(data.WhiteChess.uin, Config.BlockIdEnum[Config.ChessType.WhiteChess],1000);
        end

        SettingRule.ClearAreaPlayerBuff(param.roomId)
        GobangData.ResetRoomState(param.roomId)
        TimerManager.ClearRoundTimer(param.roomId)
       

    end,


    AbstainCurRound = function(param)
        if param == nil then return end

    end,


    GetRoomidByPos = function(x,y,z)
        if x == nil or y == nil or z == nil then return end

        local data = Config.Checkerboard;
        if data == nil then return nil end

        for k,v in pairs(data) do
            local maxX = math.max(v.beginPos.x,v.endPos.x);
            local minX = math.min(v.beginPos.x,v.endPos.x);
            local maxZ = math.max(v.beginPos.z,v.endPos.z)
            local minZ = math.min(v.beginPos.z,v.endPos.z)

            if x<=maxX and x >= minX and z <=maxZ and z >= minZ then

                return k
            end
        end

        return nil

    end,


    GetRoomIdByUin = function(uin)
        if uin == nil then return end

        local roomId = nil

        for i=1,4 do
            print(GobangData[i])
            print(uin)
            if GobangData[i].IsBegin then
                if GobangData[i].BlackChess.uin ~= nil and uin == GobangData[i].BlackChess.uin then
                    return i
                end

                if GobangData[i].WhiteChess.uin ~= nil and uin == GobangData[i].WhiteChess.uin then
                    return  i
                end
            end
        end

        return roomId

    end,


    PlayerLeaveGame = function(eventobjid)
        if eventobjid == nil then return end


        local roomId = SettingRule.GetRoomIdByUin(eventobjid);
        if roomId == nil then return end

        local data = GobangData[roomId];
        local winChessType;
        if data.BlackChess.uin == eventobjid then
            winChessType = Config.ChessType.WhiteChess
        elseif data.WhiteChess.uin == eventobjid then
            winChessType = Config.ChessType.BlackChess
        end

        Api.Chat:sendSystemMsg("Room "..roomId..":Player leaves the room and give up the game. ")
        GobangData.SetWin(roomId,true,winChessType)

    end,


    InitRoomArea = function()


        for k,v in pairs(Config.CheckerboardCenterPos) do
            local ret,areaid = Api.Area:createAreaRect(v, {x=10,y=6,z=10})
            if ret == ErrorCode.OK then
                GobangData[k].AreaId = areaid
            end

        end
    end,

}


GobangEvent = {


    playerAreaIn = function(param)

        GobangMgr.HandleEvent(LogicEvent.PlayerAreaInEvent,param)
    end,


    playerAreaOut = function(param)

        GobangMgr.HandleEvent(LogicEvent.PlayerAreaOutEvent,param)
    end,


    block_placedby = function(param)

        GobangMgr.HandleEvent(LogicEvent.PlaceChessBlockEvent,param);
    end,


    block_trigger = function(param)

        GobangMgr.HandleEvent(LogicEvent.SwitchTriggerEvent,param);
    end,


    gamestart = function()

        Api.Chat:sendSystemMsg("Game starts. ")
        GobangMgr.HandleEvent(LogicEvent.GameStartEvent)
    end,

    gamerun = function()
        TimerManager.Update()
    end,


    playerLeaveGame = function(param)

        GobangMgr.HandleEvent(LogicEvent.PlayerLeaveGame,param)
    end,



}


Config = {

    SwitchType = {
        RandomSelect    = 1,
        StartGame       = 2,
        BlackChess      = 3,
        WhiteChess      = 4,

        ChangeThreeMode = 5,
        BlackStartRound = 6,
        WhiteStartRound = 7,
        Abstain         = 8,
        ChangeChessType = 9,
        DesignatedStartType = 10,
        AdmitDefeatType = 11,
    },


    SwitchMapping = {

        { x = 275, y = 8, z = 97, roomId=4, type = 1 },
        { x = 271, y = 8, z = 97, roomId=4, type = 1 },
        { x = 273, y = 7, z = 99, roomId=4, type = 2 },
        { x = 269, y = 8, z = 97, roomId=4, type = 3 },
        { x = 277, y = 8, z = 97, roomId=4, type = 4 },

        { x = 271, y = 8, z = 75, roomId=3, type = 1 },
        { x = 275, y = 8, z = 75, roomId=3, type = 1 },
        { x = 273, y = 7, z = 73, roomId=3, type = 2 },
        { x = 277, y = 8, z = 75, roomId=3, type = 3 },
        { x = 269, y = 8, z = 75, roomId=3, type = 4 },

        { x = 314, y = 8, z = 75, roomId=1, type = 1 },
        { x = 318, y = 8, z = 75, roomId=1, type = 1 },
        { x = 316, y = 7, z = 73, roomId=1, type = 2 },
        { x = 320, y = 8, z = 75, roomId=1, type = 3 },
        { x = 312, y = 8, z = 75, roomId=1, type = 4 },

        { x = 318, y = 8, z = 97, roomId=2, type = 1 },
        { x = 314, y = 8, z = 97, roomId=2, type = 1 },
        { x = 316, y = 7, z = 99, roomId=2, type = 2 },
        { x = 312, y = 8, z = 97, roomId=2, type = 3 },
        { x = 320, y = 8, z = 97, roomId=2, type = 4 },


        { x = 325, y = 9, z = 67, roomId=1, type = 5 },
        { x = 327, y = 9, z = 67, roomId=1, type = 6 },
        { x = 326, y = 9, z = 63, roomId=1, type = 8 },
        { x = 307, y = 9, z = 63, roomId=1, type = 9 },
        { x = 305, y = 9, z = 63, roomId=1, type = 7 },
        { x = 306, y = 9, z = 67, roomId=1, type = 8 },

        { x = 306, y = 9, z = 109, roomId=2, type = 8 },
        { x = 307, y = 9, z = 105, roomId=2, type = 5 },
        { x = 305, y = 9, z = 105, roomId=2, type = 6 },
        { x = 325, y = 9, z = 109, roomId=2, type = 9 },
        { x = 327, y = 9, z = 109, roomId=2, type = 7 },
        { x = 326, y = 9, z = 105, roomId=2, type = 8 },

        { x = 283, y = 9, z = 63, roomId=3, type = 8 },
        { x = 282, y = 9, z = 67, roomId=3, type = 5 },
        { x = 284, y = 9, z = 67, roomId=3, type = 6 },
        { x = 264, y = 9, z = 63, roomId=3, type = 9 },
        { x = 262, y = 9, z = 63, roomId=3, type = 7 },
        { x = 263, y = 9, z = 67, roomId=3, type = 8 },

        { x = 263, y = 9, z = 109, roomId=4, type = 8 },
        { x = 264, y = 9, z = 105, roomId=4, type = 5 },
        { x = 262, y = 9, z = 105, roomId=4, type = 6 },
        { x = 282, y = 9, z = 109, roomId=4, type = 9 },
        { x = 284, y = 9, z = 109, roomId=4, type = 7 },
        { x = 283, y = 9, z = 105, roomId=4, type = 8 },


        { x = 294, y = 9, z = 84, roomId=-1, type = 10 },

        { x = 326, y = 7 , z = 60 , roomId=1, type = 11 },
        { x = 306, y = 7 , z = 60 , roomId=1, type = 11 },
        { x = 306, y = 7 , z = 112, roomId=2, type = 11 },
        { x = 326, y = 7 , z = 112, roomId=2, type = 11 },
        { x = 283, y = 7 , z = 60 , roomId=3, type = 11 },
        { x = 263, y = 7 , z = 60 , roomId=3, type = 11 },
        { x = 263, y = 7 , z = 112, roomId=4, type = 11 },
        { x = 283, y = 7 , z = 112, roomId=4, type = 11 },

    },


    ChessType = {
        None        = -1,
        BlackChess  = 1,
        WhiteChess  = 2,
    },


    RoomType = {
        None        = -1,
        RoomOne     = 1,
        RoomTwo     = 2,
        RoomThree   = 3,
        RoomFour    = 4,
    },


    ChoseMode = {
        None = -1,
        Random = 1,
        Default = 2,
    },


    ThreeChessRelativePos = {
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 0,   y = 0,   z = 2,  type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 1,   y = 0,   z = 2,  type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 2,   y = 0,   z = 2,  type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 1,   y = 0,   z = 1,  type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 2,   y = 0,   z = 1,  type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 1,   y = 0,   z = 0,  type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 2,   y = 0,   z = 0,  type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 0,   y = 0,   z = -1, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 1,   y = 0,   z = -1, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 2,   y = 0,   z = -1, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 0,   y = 0,   z = -2, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 1,   y = 0,   z = -2, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 0, z = 1, y = 0, type = 2 }, { x = 2,   y = 0,   z = -2, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = 2,   y = 0,   z = 2,  type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = 2,   y = 0,   z = 1,  type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = 2,   y = 0,   z = 0,  type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = 2,   y = 0,   z = -1, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = 2,   y = 0,   z = -2, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = 1,   y = 0,   z = 0,  type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = -1,  y = 0,   z = -1, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = -1,  y = 0,   z = -2, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = 0,   y = 0,   z = -1, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = 0,   y = 0,   z = -2, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = -1,  y = 0,   z = -1, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = -1,  y = 0,   z = -2, type = 1 },    },
        {   { x = 0, y = 0, z = 0, type = 1 }, { x = 1, z = 1, y = 0, type = 2 }, { x = -2,  y = 0,   z = -2, type = 1 },    },
    },


    CheckerboardCenterPos = {
        { x = 316, y = 7, z = 65,   roomId=1 },
        { x = 316, y = 7, z = 107,  roomId=2 },
        { x = 273, y = 7, z = 65,   roomId=3 },
        { x = 273, y = 7, z = 107,  roomId=4 },
    },


    BlockIdEnum = {
        [1] = 3994,
        [2] = 3997,
    },


    InitPlayerPos = {
        [1] ={{ x=326, y=9 , z=65    }, { x=306, y=9, z=65 }   },
        [2] ={{ x=306, y=9 , z=107   }, { x=326, y=9, z=107 }  },
        [3] ={{ x=283, y=9 , z=65    }, { x=263, y=9, z=65 }   },
        [4] ={{ x=263, y=9 , z=107   }, { x=283, y=9, z=107 }  },
    },


    Checkerboard = {
        { beginPos = {x = 309, y = 7, z = 72} , endPos = {x = 323, y = 7, z = 58}   },
        { beginPos = {x = 323, y = 7, z = 100} , endPos = {x = 309, y = 7, z = 114}  },
        { beginPos = {x = 280, y = 7, z = 72} , endPos = {x = 266, y = 7, z = 58}   },
        { beginPos = {x = 266, y = 7, z = 100}, endPos = {x = 280, y = 7, z = 114}  },
    },



    TipLightPos = {

        [1] ={{ x=323, y=9 , z=76   }, { x=309, y=9, z=76 }  },
        [2] ={{ x=309, y=9 , z=96   }, { x=323, y=9, z=96 }  },
        [3] ={{ x=280, y=9 , z=76   }, { x=266, y=9, z=76 }  },
        [4] ={{ x=266, y=9 , z=96   }, { x=280, y=9, z=96 }  },
    },


    RuleTipLightPos = {
        { x=294, y=7 , z=83 }
    },


    TipLightBlockIdEnum = {
        Registered = 949,
        Unregistered = 707,
    },


}


GobangData = {


    [Config.RoomType.RoomOne] = {
        IsBegin = false,
        IsAI    = false,
        AIChess = Config.ChessType.None,
        CurChessType = Config.ChessType.None,
        CanStartGame = false;
        ChoseMode = Config.ChoseMode.None,
        MyChessType = Config.ChessType.None,
        BlackChess = { uin = nil},
        WhiteChess = { uin = nil},

        CurStartModeIndex = 1,
        IsStartModeFinish = false,
        IsBeginRound = false,

        IsWin = false,
        WinUin = nil,
        AreaId = 0,

    },

    [Config.RoomType.RoomTwo] = {
        IsBegin = false,
        IsAI    = false,
        AIChess = Config.ChessType.None,
        CurChessType = Config.ChessType.None,
        CanStartGame = false;
        ChoseMode = Config.ChoseMode.None,
        MyChessType = Config.ChessType.None,
        BlackChess = { uin = nil},
        WhiteChess = { uin = nil},

        CurStartModeIndex = 1,
        IsStartModeFinish = false,
        IsBeginRound = false,

        IsWin = false,
        WinUin = nil,
        AreaId = 0,
    },

    [Config.RoomType.RoomThree] = {
        IsBegin = false,
        IsAI    = false,
        AIChess = Config.ChessType.None,
        CurChessType = Config.ChessType.None,
        CanStartGame = false;
        ChoseMode = Config.ChoseMode.None,
        MyChessType = Config.ChessType.None,
        BlackChess = { uin = nil},
        WhiteChess = { uin = nil},

        CurStartModeIndex = 1,
        IsStartModeFinish = false,
        IsBeginRound = false,

        IsWin = false,
        WinUin = nil,
        AreaId = 0,
    },

    [Config.RoomType.RoomFour] = {
        IsBegin = false,
        IsAI    = false,
        AIChess = Config.ChessType.None,
        CurChessType = Config.ChessType.None,
        CanStartGame = false;
        ChoseMode = Config.ChoseMode.None,
        MyChessType = Config.ChessType.None,
        BlackChess = { uin = nil},
        WhiteChess = { uin = nil},

        CurStartModeIndex = 1,
        IsStartModeFinish = false,
        IsBeginRound = false,

        IsWin = false,
        WinUin = nil,
        AreaId = 0,
    },

    IsDesignatedStart = false,


    SetWin = function(roomId,isWin,chessType)
        if isWin == nil or roomId == nil then return end
        local this = GobangData;

        this[roomId].IsWin = isWin;
        if chessType == nil then
            this[roomId].WinUin = this[roomId].CurChessType
        else
            this[roomId].WinUin = chessType
        end

        TimerManager.CreateTimer(1,function()

            if this[roomId].IsAI then
                GobangMgr.HandleEvent(LogicEvent.AIModeWinEvent,{roomId = roomId})
            else
                GobangMgr.HandleEvent(LogicEvent.BattleModeWinEvent,{roomId = roomId})
            end
        end)

    end,


    SetMyChessType = function(roomId,type)
        if type == nil or roomId == nil then return end
        local this = GobangData;

        this[roomId].MyChessType = type;
    end,


    SetGameBegin = function(roomId,uin,isBegin)
        if isBegin == nil or roomId == nil then return end
        local this = GobangData;



        this[roomId].IsBegin = isBegin;
        GobangMgr.HandleEvent(LogicEvent.StartBeginGameEvent,{roomId = roomId})

    end,


    SetAIState = function(roomId,isAI,aiChess)
        if isAI == nil or roomId == nil then return end
        if isAI and aiChess == nil then return end
        local this = GobangData;


        this[roomId].IsAI = isAI;
        print(this[roomId].IsAI)
        this[roomId].AIChess = aiChess;
    end,


    SetCurChess = function(roomId,chessType)
        if chessType == nil or roomId == nil then return end
        local this = GobangData;

        this[roomId].CurChessType = chessType;
        GobangMgr.HandleEvent(LogicEvent.ChangeCurPlaceChessTypeEvent,{roomId = roomId})
    end,


    SetUinToChess = function(roomId,chessType,uin)

        if roomId == nil or chessType == nil or uin == nil then return end
        local this = GobangData



        if chessType == Config.ChessType.WhiteChess then
            if this[roomId].WhiteChess.uin == nil then
                this[roomId].WhiteChess.uin = uin
                this[roomId].CanStartGame = true
            end
        elseif  chessType == Config.ChessType.BlackChess then
            if this[roomId].BlackChess.uin == nil then
                this[roomId].BlackChess.uin = uin
                this[roomId].CanStartGame = true
            end
        end
    end,


    SetChoseMode = function(roomId,mode)
        if roomId == nil or mode == nil then return end
        local this = GobangData

        this[roomId].ChoseMode = mode;

    end,


    SetBeginRound = function(roomId,mode)
        if roomId == nil or mode == nil then return end
        local this = GobangData

        Api.Chat:sendSystemMsg("room "..roomId.."Set start round ")


        this[roomId].CurChessType=Config.ChessType.WhiteChess ;
        if this.IsDesignatedStart == false and this[roomId].IsAI then
            this[roomId].CurChessType=Config.ChessType.BlackChess

        end
        this[roomId].IsBeginRound = mode;
        GobangMgr.HandleEvent(LogicEvent.StartRoundEvent,{roomId = roomId})

    end,

    SetStartMode = function(roomId,mode)
        if roomId == nil or mode == nil then return end
        local this = GobangData

        this[roomId].IsStartModeFinish = mode;

        if this[roomId].IsAI then
            GobangMgr.HandleEvent(LogicEvent.AIStartThreeModeEvent,{roomId=roomId})
        else
            GobangMgr.HandleEvent(LogicEvent.SelectedStartThreeModeEvent,{roomId=roomId})
        end

    end,


    SetCurStartModeIndex = function(roomId,index)
        if roomId == nil or index == nil then return end
        local this = GobangData;

        this[roomId].CurStartModeIndex = index;

        GobangMgr.HandleEvent(LogicEvent.ChangeThreeModeEvent,{roomId = roomId})
    end,


    ChangeCamp = function(roomId)
        if roomId == nil then return end

        local this = GobangData;
        if this[roomId] == nil then return end

        if this[roomId].IsAI then
            if this[roomId].AIChess ~= Config.ChessType.WhiteChess then
                this[roomId].AIChess = Config.ChessType.WhiteChess
                this[roomId].MyChessType = Config.ChessType.BlackChess
                this[roomId].BlackChess.uin = this[roomId].WhiteChess.uin
                this[roomId].WhiteChess.uin = nil

                Api.Chat:sendSystemMsg("Man-machine alternate ")
                GobangMgr.HandleEvent(LogicEvent.ChangeCampEvent,{roomId = roomId})
            end
        else
            if this[roomId].BlackChess.uin and this[roomId].WhiteChess.uin then
                local uin = this[roomId].BlackChess.uin
                this[roomId].BlackChess.uin = this[roomId].WhiteChess.uin
                this[roomId].WhiteChess.uin = uin;

                Api.Chat:sendSystemMsg("alternate ")
                GobangMgr.HandleEvent(LogicEvent.ChangeCampEvent,{roomId = roomId})
            else

            end
        end

    end,


    SetAbstain = function(roomId,uin)
        if roomId == nil then return end
        local this = GobangData

        if this[roomId].CurChessType == Config.ChessType.WhiteChess then
            this.SetCurChess(roomId,Config.ChessType.BlackChess)
        elseif this[roomId].CurChessType == Config.ChessType.BlackChess then
            this.SetCurChess(roomId,Config.ChessType.WhiteChess)
        end

        Api.Chat:sendSystemMsg("Set a waiver ")
        GobangMgr.HandleEvent(LogicEvent.AbstainEvent,{roomId = roomId,uin=uin})
    end,


    CancelSelectChess = function(roomId,chessType,uin)
        if roomId == nil or chessType == nil or uin == nil then return end
        local this = GobangData

        if chessType == Config.ChessType.BlackChess and this[roomId].BlackChess.uin == uin then
            this[roomId].BlackChess.uin = nil
            this[roomId].MyChessType = Config.ChessType.None

        elseif chessType == Config.ChessType.WhiteChess then
            this[roomId].WhiteChess.uin = nil
            this[roomId].MyChessType = Config.ChessType.None
        end

        if  this[roomId].BlackChess.uin == nil and  this[roomId].WhiteChess.uin == nil then
            this[roomId].ChoseMode = Config.ChoseMode.None
            this[roomId].AIChess = Config.ChessType.None
        end

    end,


    SetDesignatedStart = function()
        local this = GobangData

        if this.IsDesignatedStart then
            this.IsDesignatedStart = false

        else
            this.IsDesignatedStart = true

        end

    end,

    ResetRoomState = function(roomId)
        if roomId == nil then return end


        GobangData[roomId] = {
            IsBegin = false,
            IsAI    = false,
            AIChess = Config.ChessType.None,
            CurChessType = Config.ChessType.None,
            CanStartGame = false;
            ChoseMode = Config.ChoseMode.None,
            MyChessType = Config.ChessType.None,
            BlackChess = { uin = nil},
            WhiteChess = { uin = nil},

            CurStartModeIndex = 1,
            IsStartModeFinish = false,
            IsBeginRound = false,

            IsWin = false,
            WinUin = nil,
        }



    end,

}

SwitchCtrl= {


    SwitchTrigger =function(x,y,z,uin,blockid)
        if Config == nil or Config.SwitchMapping == nil then return end
        if x == nil or y == nil or z == nil then return end

        local this = SwitchCtrl
        local ret,data = Api.Block:getBlockData(x, y, z)
        Api.Block:setBlockAll(x, y, z, blockid,data-8)

        for k,v in pairs(Config.SwitchMapping) do
            if v.x ==x and v.y == y and v.z == z then
                if v.type == Config.SwitchType.RandomSelect then
                    this.RandomSelectChess(v.roomId,uin)
                elseif v.type == Config.SwitchType.StartGame then
                    this.GameStart(v.roomId,uin)
                elseif v.type == Config.SwitchType.BlackChess then
                    this.SelectBlackChess(v.roomId,uin)
                elseif v.type == Config.SwitchType.WhiteChess then
                    this.SelectWhiteChess(v.roomId,uin)
                elseif v.type == Config.SwitchType.ChangeThreeMode then
                    this.ChangeThreeChessMode(v.roomId,uin)
                elseif v.type == Config.SwitchType.BlackStartRound then
                    this.StartGameMode(v.roomId,uin)
                elseif v.type == Config.SwitchType.WhiteStartRound then
                    this.StartRound(v.roomId,uin)
                elseif v.type == Config.SwitchType.Abstain then
                    this.Abstain(v.roomId,uin)
                elseif v.type == Config.SwitchType.ChangeChessType then
                    this.ChangeChessCamp(v.roomId,uin)
                elseif v.type == Config.SwitchType.DesignatedStartType then
                    this.DesignatedStart(v.roomId,uin)
                elseif v.type == Config.SwitchType.AdmitDefeatType then
                    this.AdmitDefeat(v.roomId,uin)
                end
            end
        end

    end,


    RandomSelectChess = function(roomId,uin)
        if roomId ==  nil or  uin == nil then return end

        local data = GobangData[roomId];
        if data.IsBegin or data.ChoseMode == Config.ChoseMode.Default then return end

        if data.BlackChess.uin ~= nil and data.WhiteChess.uin ~= nil then return end
        if data.BlackChess.uin == uin or data.WhiteChess.uin == uin then return end

        local selectType;


        if data.BlackChess.uin ~= nil then
            selectType = Config.ChessType.WhiteChess
            Api.Player:notifyGameInfo2Self(uin,"Randomly assigned as white ")
        elseif data.WhiteChess.uin ~=nil then
            selectType = Config.ChessType.BlackChess
            Api.Player:notifyGameInfo2Self(uin,"Randomly assigned as black ")
        end


        if data.BlackChess.uin == nil and data.WhiteChess.uin == nil then
            local randomNum = math.random(1,100)
            local generateChess = randomNum%2 +1

            if Config.ChessType.WhiteChess == generateChess then
                selectType=Config.ChessType.WhiteChess
                Api.Player:notifyGameInfo2Self(uin,"Randomly assigned as white ")
            elseif Config.ChessType.BlackChess == generateChess then
                selectType=Config.ChessType.BlackChess
                Api.Player:notifyGameInfo2Self(uin,"Randomly assigned as black ")
            end
        end

        GobangData.SetUinToChess(roomId,selectType,uin)
        SettingRule.SetTipLightState(roomId,selectType,true)
        GobangData.SetChoseMode(roomId,Config.ChoseMode.Random)


        GobangData.SetMyChessType(roomId,selectType)


    end,

    DesignatedStart= function(roomId,uin)

        local hasGameStart = false

        local ret, hostUin = Api.Player:getHostUin()
        if hostUin ~= uin then return end

        for k,v in pairs(Config.RoomType) do
            local data = GobangData[v]
            if data ~= nil and data.IsBegin then
                hasGameStart = true
            end
        end

        if hasGameStart == false then
            GobangData.SetDesignatedStart()
            SettingRule.SetRuleTipLightSate(GobangData.IsDesignatedStart)
            if GobangData.IsDesignatedStart then
                Api.Chat:sendSystemMsg("The host adds advanced rules ")
            else
                Api.Chat:sendSystemMsg("The host removes advanced rules ")
            end


        else
            Api.Player:notifyGameInfo2Self(uin,"There is an ongoing game in the room and the rule modification failed. ")
        end

    end,

    GameStart = function(roomId,uin)
        if roomId ==  nil or  uin == nil then return end
        local data = GobangData[roomId];
        if data.IsBegin then return end

        if data.IsBegin then return end
        if data.CanStartGame == false then return end


        if data.BlackChess.uin ~= uin and data.WhiteChess.uin ~= uin then return end


        if (data.BlackChess.uin == uin and data.WhiteChess.uin == nil ) then
            GobangData.SetAIState(roomId,true,Config.ChessType.WhiteChess)
            Api.Player:notifyGameInfo2Self(uin,"Game starts in 3 seconds ")
        elseif  (data.WhiteChess.uin == uin and data.BlackChess.uin == nil ) then
            GobangData.SetAIState(roomId,true,Config.ChessType.BlackChess)
            Api.Player:notifyGameInfo2Self(uin,"Game starts in 3 seconds ")
        else
            GobangData.SetAIState(roomId,false)
            Api.Player:notifyGameInfo2Self(uin,"Game starts in 3 seconds ")
        end

        TimerManager.CreateCountdownTimer(3,uin,function ()
            GobangData.SetGameBegin(roomId,uin,true);
            SettingRule.PlayerInSelfChess(roomId)
        end)

    end,


    SelectBlackChess = function(roomId,uin)
        if roomId ==  nil or  uin == nil then return end

        local data = GobangData[roomId];
        if data.IsBegin  then return end

        if data.WhiteChess.uin == uin then return end
        print(GobangData[roomId])

        if data.BlackChess.uin == uin then
            Api.Player:notifyGameInfo2Self(uin,"Cancel application ")
            GobangData.CancelSelectChess(roomId,Config.ChessType.BlackChess,uin)
            SettingRule.SetTipLightState(roomId,Config.ChessType.BlackChess,false)
        elseif data.BlackChess.uin == nil then
            if data.ChoseMode == Config.ChoseMode.Random then return end

            GobangData.SetUinToChess(roomId,Config.ChessType.BlackChess,uin)
            SettingRule.SetTipLightState(roomId,Config.ChessType.BlackChess,true)
            Api.Player:notifyGameInfo2Self(uin,"Apply for black ")

            GobangData.SetChoseMode(roomId,Config.ChoseMode.Default)

            GobangData.SetMyChessType(roomId,Config.ChessType.BlackChess)

        end

    end,


    SelectWhiteChess = function(roomId,uin)
        if roomId ==  nil or  uin == nil then return end

        local data = GobangData[roomId];
        if data.IsBegin  then return end

        if data.BlackChess.uin == uin then return end

        if data.WhiteChess.uin == uin then
            Api.Player:notifyGameInfo2Self(uin,"Cancel application ")
            GobangData.CancelSelectChess(roomId,Config.ChessType.WhiteChess,uin)
            SettingRule.SetTipLightState(roomId,Config.ChessType.WhiteChess,false)
        elseif data.WhiteChess.uin == nil then
            GobangData.SetUinToChess(roomId,Config.ChessType.WhiteChess,uin)
            SettingRule.SetTipLightState(roomId,Config.ChessType.WhiteChess,true)
            Api.Player:notifyGameInfo2Self(uin,"Apply for white ")

            GobangData.SetChoseMode(roomId,Config.ChoseMode.Default)
            GobangData.SetMyChessType(roomId,Config.ChessType.WhiteChess)


        end

    end,


    ChangeThreeChessMode = function(roomId,uin)
        if roomId ==  nil or  uin == nil then return end
        if GobangData.IsDesignatedStart == false then return end
        local data = GobangData[roomId];

        if data.IsStartModeFinish then return end
        if data.BlackChess.uin ~= uin then return end

        local maxNum = 26;
        local index = data.CurStartModeIndex;

        index = index +1
        if index > maxNum then index = 1 end

        GobangData.SetCurStartModeIndex(roomId,index);
        --Api.Player:notifyGameInfo2Self(uin,"")
        Api.Chat.sendSystemMsg("Room "..roomId..":Game starts, Black start ")

    end,


    StartGameMode = function(roomId,uin)
        if roomId ==  nil or  uin == nil then return end
        if GobangData.IsDesignatedStart == false then return end
        local data = GobangData[roomId];


        if data.IsStartModeFinish then return end
        if data.BlackChess.uin ~= uin then return end

        GobangData.SetStartMode(roomId,true);
        Api.Player:notifyGameInfo2Self(uin,"Black selecte the opening mode ")


    end,


    Abstain = function(roomId,uin)
        if roomId ==  nil or  uin == nil then return end
        local data = GobangData[roomId];

        if data.IsBeginRound == false then return end

        if (data.CurChessType == Config.ChessType.BlackChess and data.BlackChess.uin ~= uin) or
                ( data.CurChessType == Config.ChessType.WhiteChess and data.WhiteChess.uin ~= uin) then
            return
        else
            GobangData.SetAbstain(roomId,uin);
            Api.Player:notifyGameInfo2Self(uin,"Retire. Player alternates.  ")
            Api.Chat.sendSystemMsg("Retire. Player alternates.")
        end

    end,


    ChangeChessCamp = function(roomId,uin)
        if roomId ==  nil or  uin == nil then return end
        if GobangData.IsDesignatedStart == false then return end
        local data = GobangData[roomId];

        if data.IsBeginRound then return end
        if data.WhiteChess.uin ~= uin then return end

        Api.Chat:sendSystemMsg("Alternate ",roomId,": You are white")
        TimerManager.CreateCountdownTimer(5,uin,function ()
            GobangData.ChangeCamp(roomId)
        end)

    end,


    StartRound = function(roomId,uin)
        print("White starts the round switch trigger ")

        if roomId ==  nil or  uin == nil then return end
        local data = GobangData[roomId];

        if data.IsBeginRound then return end
        if data.WhiteChess.uin ~= uin then return end

        GobangData.SetBeginRound(roomId,true);
        Api.Player:notifyGameInfo2Self(uin,"First start game round ")

    end,
}


SettingRule = {


    ChangePlayerPos = function(roomId)

        if roomId == nil then return end

        print(GobangData[roomId].IsStartModeFinish)
        if GobangData[roomId].IsBegin == false or GobangData[roomId].IsStartModeFinish == false or
                GobangData[roomId].IsBeginRound == true then return end

        local initPos = Config.InitPlayerPos[roomId];
        print(initPos)

        if GobangData[roomId].BlackChess.uin ~= nil then
            Api.Player:setPosition(GobangData[roomId].BlackChess.uin,initPos[1].x+1,initPos[1].y,initPos[1].z)
            Api.Player:notifyGameInfo2Self(GobangData[roomId].BlackChess.uin,"Alternate: You are black ")
        end

        if GobangData[roomId].WhiteChess.uin ~= nil then
           Api.Player:setPosition(GobangData[roomId].WhiteChess.uin,initPos[2].x+1,initPos[2].y,initPos[2].z)
            Api.Player:notifyGameInfo2Self(GobangData[roomId].WhiteChess.uin,"Alternate: You are white ")
        end

        GobangData.SetBeginRound(roomId,true)



    end,


    SetPlayerPos = function(roomId)
        if roomId == nil then return end

        local initPos = Config.InitPlayerPos[roomId];
        if GobangData[roomId].BlackChess.uin ~= nil  then
            --Api.Player:setPosition(GobangData[roomId].BlackChess.uin,initPos[1].x,initPos[1].y,initPos[1].z)
        end

        if GobangData[roomId].WhiteChess.uin ~= nil then
            --Api.Player:setPosition(GobangData[roomId].WhiteChess.uin,initPos[2].x,initPos[2].y,initPos[2].z)
        end

        if GobangData.IsDesignatedStart then
            Api.Chat:sendSystemMsg("Game starts, Black start ")
        else
            Api.Chat:sendSystemMsg("Game starts. Black goes first ")
        end

    end,


    ChangeStartThreeChessPos = function(roomId)
        if roomId == nil or GobangData == nil or GobangData[roomId] == nil then return end
        if GobangData[roomId].IsBegin == false or GobangData[roomId].IsStartModeFinish == true then return end

        local data = GobangData[roomId]
        local checkerboardCenterPos;
        local lastRelativePos
        local curRelativePos
        local lastIndex

        checkerboardCenterPos = Config.CheckerboardCenterPos[roomId]
        curRelativePos = Config.ThreeChessRelativePos[data.CurStartModeIndex]
        lastIndex = data.CurStartModeIndex -1;
        if lastIndex <1 then lastIndex = 26 end
        lastRelativePos = Config.ThreeChessRelativePos[lastIndex];


        for k,v in pairs(lastRelativePos) do
            local x,y,z
            x = v.x +checkerboardCenterPos.x
            y = v.y +checkerboardCenterPos.y
            z = v.z +checkerboardCenterPos.z
            Api.Block:destroyBlock(x,y,z,false)
        end


        for k,v in pairs(curRelativePos) do
            local x,y,z
            local blockid

            x = v.x +checkerboardCenterPos.x
            y = v.y +checkerboardCenterPos.y
            z = v.z +checkerboardCenterPos.z
            blockid = Config.BlockIdEnum[v.type]

            Api.Block:placeBlock(blockid,x,y,z,3)
        end

    end,


    SetDefaultThreeChess = function(roomId)
        if roomId == nil or GobangData == nil or GobangData[roomId] == nil then return end
        if GobangData.IsDesignatedStart == false then return end
        if GobangData[roomId].IsBegin == false or GobangData[roomId].IsStartModeFinish == true then return end

        local data = GobangData[roomId]
        local checkerboardCenterPos;
        local curRelativePos

        checkerboardCenterPos = Config.CheckerboardCenterPos[roomId]
        curRelativePos = Config.ThreeChessRelativePos[data.CurStartModeIndex]


        for k,v in pairs(curRelativePos) do
        local x,y,z
        local blockid

        x = v.x +checkerboardCenterPos.x
        y = v.y +checkerboardCenterPos.y
        z = v.z +checkerboardCenterPos.z
        blockid = Config.BlockIdEnum[v.type]

        Api.Block:placeBlock(blockid,x,y,z,3)
        end

    end,


    GainItemChessToPlayer = function(roomId)
        if roomId == nil then return end

        local data = GobangData[roomId]

        if data.BlackChess.uin ~= nil then
            Api.Player:gainItems(data.BlackChess.uin,Config.BlockIdEnum[1],300,1)
        end

        if data.WhiteChess.uin ~= nil then
            Api.Player:gainItems(data.WhiteChess.uin,Config.BlockIdEnum[2],300,1)
        end

    end,


    GetChessPlaceIsRight = function(roomId,uin,x,y,z,blockid)
        if uin == nil or x == nil or y == nil or blockid == nil then return false end


        print(GobangMgr.JudgeChessInChessboard(roomId,x,y,z))
        if GobangMgr.JudgeChessInChessboard(roomId,x,y,z) == false then
            Api.Block:destroyBlock(x,y,z,false)
            return false
        end


        if Config.BlockIdEnum[1] ~= blockid and Config.BlockIdEnum[2] ~= blockid then
            Api.Block:destroyBlock(x,y,z,false)
        end



        if (GobangData[roomId].IsWin and GobangData[roomId].CurChessType ~= GobangData[roomId].AIChess )
                or GobangData[roomId].IsBegin == false then
            Api.Block:destroyBlock(x,y,z,false)
        end


        if GobangData[roomId].CurChessType == Config.ChessType.None then return end
        if GobangData[roomId].IsAI then

        else
            if GobangData[roomId].BlackChess.uin ~= uin and
                    GobangData[roomId].WhiteChess.uin ~= uin then

                Api.Block:destroyBlock(x,y,z,false)
                return
            end
        end




        local data = GobangData[roomId]
        if data == nil then return false end
        print(data)

        if data.CurChessType == Config.ChessType.BlackChess and Config.BlockIdEnum[1] ~= blockid then

            Api.Block:destroyBlock(x,y,z,false)
            return false
        elseif data.CurChessType == Config.ChessType.WhiteChess and Config.BlockIdEnum[2] ~= blockid then

            Api.Block:destroyBlock(x,y,z,false)
            return false
        elseif data.CurChessType == Config.ChessType.None then

            Api.Block:destroyBlock(x,y,z,false)
            return false
        end

        return true

    end,


    GetRoomIdByUin = function(uin)
        if uin == nil then return end

        local roomNum  = 4

        for i =1, roomNum do
            local data = GobangData[i]
            if data ~= nil then
                if data.BlackChess.uin == uin then
                    return i
                end

                if data.WhiteChess.uin == uin then
                    return i
                end
            end

        end

        return nil

    end,


    SetTipLightState = function(roomId,chessType,state)
        if roomId == nil or chessType == nil or state == nil then return end


        local blockid
        local posTable = Config.TipLightPos[roomId]
        local pos = posTable[chessType]

        if state  then
            blockid = Config.TipLightBlockIdEnum.Registered
        else
            blockid = Config.TipLightBlockIdEnum.Unregistered
        end


        if blockid  == nil or pos == nil then return end
        Api.Block:setBlockAll(pos.x, pos.y, pos.z, blockid)

    end,


    SetRuleTipLightSate = function(state)
        if state == nil then return end

        local blockid
        local pos = Config.RuleTipLightPos[1]

        if state  then
            blockid = Config.TipLightBlockIdEnum.Registered
        else
            blockid = Config.TipLightBlockIdEnum.Unregistered
        end

        if blockid  == nil or pos == nil then return end
        Api.Block:setBlockAll(pos.x, pos.y, pos.z, blockid)

    end,


    ChangeCurPlaceChessType = function(roomId)
        if roomId == nil then return end
        local curChessType = GobangData[roomId].CurChessType

        if curChessType == Config.ChessType.BlackChess then
            GobangData.SetCurChess(roomId,Config.ChessType.WhiteChess);
        elseif curChessType == Config.ChessType.WhiteChess then
            GobangData.SetCurChess(roomId,Config.ChessType.BlackChess);
        end
        SettingRule.RoundTimeLimited(roomId)
        Api.Chat.sendSystemMsg("Countdown ends. Player alternates. ")
    end,


    RoundTimeLimited = function(roomId)

        if GobangData[roomId].IsAI and GobangData[roomId].AIChess == GobangData[roomId].CurChessType then
            return
        elseif GobangData[roomId].CurChessType ~= Config.ChessType.None then
            local uins = {}
            if GobangData[roomId].BlackChess.uin ~= nil then
                table.insert(uins,GobangData[roomId].BlackChess.uin)
            end
            if GobangData[roomId].WhiteChess.uin ~= nil then
                table.insert(uins,GobangData[roomId].WhiteChess.uin)
            end

            TimerManager.StartRoundTimer(roomId,uins,60,function()
                if GobangData[roomId].IsBeginRound == false then return end
                for k1,v1 in pairs(uins) do
                    Api.Player:notifyGameInfo2Self(v1,"Countdown ends. Player alternates. ")
                end
                SettingRule.ChangeCurPlaceChessType(roomId)
            end)
        end
    end,

    PlayerAreaIn = function(areaid,uin)
        if areaid ==nil or uin == nil then return end

        for i = 1,4 do
            if GobangData[i].AreaId == areaid then
                if GobangData[i].IsBegin == false then return end
                local isCurChess = false
                if GobangData[i].BlackChess.uin ~= nil and GobangData[i].BlackChess.uin == uin then
                    isCurChess = true
                end

                if GobangData[i].BlackChess.uin ~= nil and GobangData[i].BlackChess.uin == uin then
                    isCurChess = true
                end

                if isCurChess == false then
                    Api.Actor:addBuff(uin,1008,1,50000000)
                    return
                end
            end
        end

    end,

    PlayerAreaOut = function(areaid,uin)
        if areaid ==nil or uin == nil then return end
        Api.Actor:removeBuff(uin,1008)
    end,


    PlayerInSelfChess = function(roomId)
        if roomId == nil then return end

        local data  = GobangData[roomId]
        if data == nil or data.IsBegin == false then return end


        local ret,playerList = Api.Area:getAreaPlayers(data.AreaId)
        if ret == ErrorCode.OK then
            for k,v in pairs(playerList) do
                local isCurChessPlayer = false
                if data.BlackChess.uin ~= nil and data.BlackChess.uin == v then
                    isCurChessPlayer = true
                end

                if data.WhiteChess.uin ~= nil and data.WhiteChess.uin == v then
                    isCurChessPlayer = true
                end

                if isCurChessPlayer == false then
                    Api.Actor:addBuff(v,1008,1,50000000)
                end
            end
        end
    end,

    ClearAreaPlayerBuff = function(roomId)
        if roomId == nil then return end
        local data  = GobangData[roomId]
        if data == nil or data.IsWin == false then return end

        local ret,playerList = Api.Area:getAreaPlayers(data.AreaId)

        if ret == ErrorCode.OK then
            for k,v in pairs(playerList) do
                Api.Actor:removeBuff(v,1008)
            end
        end
    end,

    AdmitDefeat = function(roomId,uin)
        if roomId == nil or uin ==  nil then return end
        local data = GobangData[roomId]
        if data == nil then return end

        local isPlayerOp = false
        local winChessType = nil
        local text = " "

        if data.IsBegin == false or data.IsWin then return end

        if data.BlackChess.uin ~= nil and data.BlackChess.uin == uin then
            isPlayerOp = true
            winChessType = Config.ChessType.BlackChess
            text = "Room "..roomId..":Game ends. White wins. "
        end

        if data.WhiteChess.uin ~= nil and data.WhiteChess.uin == uin then
            isPlayerOp =true
            winChessType = Config.ChessType.WhiteChess
            text = "Room "..roomId..":Game ends. Black wins. "
        end

        if isPlayerOp == false or winChessType == nil then return end

        GobangData.SetWin(roomId,true,winChessType)
        Api.Chat:sendSystemMsg(text)
        Api.Player:notifyGameInfo2Self(uin,"You have retired from this competition and the game is over. ")


    end,

}


AIGame = {
    AIData = {
        [Config.RoomType.RoomOne] = {
            successTypeCount = 0,
            wins = {},
            myWin = {},
            computerWin = {},
            chessBoard = {},
            placedBlockPos = {},
            isAIPlace = false,
        },
        [Config.RoomType.RoomTwo] = {
            successTypeCount = 0,
            wins = {},
            myWin = {},
            computerWin = {},
            chessBoard = {},
            placedBlockPos = {},
            isAIPlace = false,
        },
        [Config.RoomType.RoomThree] = {
            successTypeCount = 0,
            wins = {},
            myWin = {},
            computerWin = {},
            chessBoard = {},
            placedBlockPos = {},
            isAIPlace = false,
        },
        [Config.RoomType.RoomFour] = {
            successTypeCount = 0,
            wins = {},
            myWin = {},
            computerWin = {},
            chessBoard = {},
            placedBlockPos = {},
            isAIPlace = false,
        },
    },

    GetNormalizedCoord = function(roomId,x,y,z)
        if roomId == nil then return end
        if x ==nil or y == nil or z == nil then return end
        if type(x) ~= "number" or type(y) ~= "number" or type(z) ~= "number" then

            return
        end

        local normalizedX = 0;
        local normalizedZ = 0;

        local CheckerboardPos = Config.Checkerboard[roomId]
        if CheckerboardPos == nil then return end

        if CheckerboardPos.beginPos ==nil or CheckerboardPos.endPos == nil  then return end

        if GobangMgr.JudgeChessInChessboard(roomId,x,y,z) ==false then return end

        if CheckerboardPos.beginPos.x < CheckerboardPos.endPos.x then
            normalizedX = x - CheckerboardPos.beginPos.x ;
        else
            normalizedX = x - CheckerboardPos.endPos.x ;
        end

        if CheckerboardPos.beginPos.z < CheckerboardPos.endPos.z then
            normalizedZ = z - CheckerboardPos.beginPos.z;
        else
            normalizedZ = z - CheckerboardPos.endPos.z;
        end

        local text =  normalizedX..","..normalizedZ;
        --Api.Chat:sendSystemMsg(text);
        return normalizedX,normalizedZ;

    end,

    GetRealCoord = function(roomId,u,v)
        if u ==nil or v == nil then return end
        if type(u) ~= "number" or type(v) ~= "number" then

            return
        end

        local realX = 0;
        local realZ = 0;

        local CheckerboardPos = Config.Checkerboard[roomId]
        if CheckerboardPos == nil then return end

        if CheckerboardPos.beginPos ==nil or CheckerboardPos.endPos == nil  then return end

        if CheckerboardPos.beginPos.x < CheckerboardPos.endPos.x then
            realX = u + CheckerboardPos.beginPos.x ;
        else
            realX = u + CheckerboardPos.endPos.x ;
        end

        if CheckerboardPos.beginPos.z < CheckerboardPos.endPos.z then
            realZ = v + CheckerboardPos.beginPos.z;
        else
            realZ = v + CheckerboardPos.endPos.z;
        end

        if GobangMgr.JudgeChessInChessboard(roomId,realX,CheckerboardPos.beginPos.y,realZ) ==false then return end
        return realX,CheckerboardPos.beginPos.y,realZ;

    end,


    InitWinsList = function(roomId)
        if GobangData[roomId].IsAI == false then return end
        local this = AIGame;
        local data = AIGame.AIData[roomId]
        for i = 0, 14 do
            for j =0,10 do
                for k = 0,4 do
                    if data.wins[i] == nil then  data.wins[i] = {}; end
                    if data.wins[i][j+k] == nil then data.wins[i][j+k]= {}; end
                    data.wins[i][j+k][data.successTypeCount] = true;
                end
                data.successTypeCount = data.successTypeCount +1;
            end

            for j =0,10 do
                for k = 0,4 do
                    if data.wins[j+k] == nil then data.wins[j+k] = {}; end
                    if data.wins[j+k][i] == nil then data.wins[j+k][i] = {}; end
                    data.wins[j+k][i][data.successTypeCount] = true;
                end
                data.successTypeCount = data.successTypeCount +1;
            end
        end

        for i = 0, 10 do
            for j =0,10 do
                for k = 0,4 do
                    if  data.wins[j+k] == nil then data.wins[j+k] = {} end
                    if data.wins[j+k][i+k] == nil then data.wins[j+k][i+k] ={} end
                    data.wins[j+k][i+k][data.successTypeCount] = true;
                end
                data.successTypeCount = data.successTypeCount +1;
            end

            for j =4,14 do
                for k = 0,4 do
                    if data.wins[i+k] == nil then data.wins[i+k] ={} end
                    if  data.wins[i+k][j-k] ==nil then  data.wins[i+k][j-k]= {}; end
                    data.wins[i+k][j-k][data.successTypeCount] = true;
                end
                data.successTypeCount = data.successTypeCount +1;
            end
        end

        for i = 0,data.successTypeCount-1 do
            data.myWin[i] = 0;
            data.computerWin[i] = 0;
        end

        for i = 0,14 do
            for j = 0, 14 do
                if data.chessBoard[i] == nil then data.chessBoard[i] ={} end
                data.chessBoard[i][j] = 0

            end
        end

    end,


    BlockPlacedBy = function(roomId,x,y,z)
        local this = AIGame;
        local data = AIGame.AIData[roomId]
        local normalx = -1;
        local normalz = -1;

        if GobangData[roomId].IsAI == false then return end

        normalx, normalz = this.GetNormalizedCoord(roomId,x,y,z);
        if GobangData[roomId].CurChessType == GobangData[roomId].AIChess then return end

        if normalx == -1 or normalz == -1 then return end

        if data.chessBoard[normalx][normalz] ~= 0 then return end

        data.chessBoard[normalx][normalz] = GobangData[roomId].MyChessType;


        for i = 0, data.successTypeCount-1 do
            if data.wins[normalx][normalz][i] then
                data.myWin[i] = data.myWin[i]+1;
                data.computerWin[i] = 7;
                if data.myWin[i] == 5 then
                    local ret,score;
                    if GobangData[roomId].AIChess ==Config.ChessType.BlackChess then
                        ret,score = Api.Player:getGameScore(GobangData[roomId].WhiteChess.uin)
                        Api.Player:setGameScore(GobangData[roomId].WhiteChess.uin,score+1)
                        Api.Player:notifyGameInfo2Self(GobangData[roomId].WhiteChess.uin,"Room "..roomId..": Game ends. White wins. ")
                    elseif GobangData[roomId].AIChess ==Config.ChessType.WhiteChess  then
                        ret,score = Api.Player:getGameScore(GobangData[roomId].BlackChess.uin)
                        Api.Player:setGameScore(GobangData[roomId].BlackChess.uin,score+1)
                        Api.Player:notifyGameInfo2Self(GobangData[roomId].BlackChess.uin,"Room "..roomId..": Game ends. Black wins. ")
                    end

                    GobangData.SetWin(roomId,true);
                    break
                end
            end
        end

        table.insert(data.placedBlockPos,{x =x,y=y,z=z})


        GobangData.SetCurChess(roomId,GobangData[roomId].AIChess);
        --SettingRule.RoundTimeLimited(roomId)
        if GobangData[roomId].AIChess == Config.ChessType.BlackChess then
            Api.Chat.sendSystemMsg("Black round, please place the stone ")
        elseif GobangData[roomId].AIChess == Config.ChessType.WhiteChess then
            Api.Chat.sendSystemMsg("White round, please place the stone ")
        end


    end,


    StartRound = function(roomId)
        if roomId == nil then return end
        if GobangData[roomId].IsAI == false then return end

        SettingRule.RoundTimeLimited(roomId)
        if GobangData[roomId].CurChessType == Config.ChessType.WhiteChess then
            Api.Chat:sendSystemMsg("White round, please place the stone ")
        elseif GobangData[roomId].CurChessType == Config.ChessType.BlackChess then
            Api.Chat:sendSystemMsg("Black round, please place the stone ")
        end
        AIGame.ComputerAI(roomId)
    end,


    ComputerAI = function(roomId)
        if roomId == nil or  GobangData[roomId] == nil then return end
        if GobangData[roomId].IsAI == false then return end
        if GobangData[roomId].AIChess ~= GobangData[roomId].CurChessType then return end


        local this = AIGame;
        local data = AIGame.AIData[roomId]


        if data.isAIPlace then
            data.isAIPlace = false

            GobangData.SetCurChess(roomId,GobangData[roomId].MyChessType);
            SettingRule.RoundTimeLimited(roomId)
            if GobangData[roomId].CurChessType == Config.ChessType.WhiteChess then
                Api.Chat:sendSystemMsg("White round, please place the stone ")
            elseif GobangData[roomId].CurChessType == Config.ChessType.BlackChess then
                Api.Chat:sendSystemMsg("Black round, please place the stone ")
            end
            return
        end

        Api.Chat:sendSystemMsg("Room "..roomId.."Robot Starts ")
        local u,v = this.GetAIBestPos(roomId)
        local blockid = 0;
        local x,y,z ;
        x,y,z = this.GetRealCoord(roomId,u,v);
        data.chessBoard[u][v] = 2;

        blockid = Config.BlockIdEnum[GobangData[roomId].AIChess];
        Api.Block:placeBlock(blockid,x,y,z,3)
        data.isAIPlace = true
        table.insert(data.placedBlockPos,{x =x,y=y,z=z})


        for i = 0, data.successTypeCount-1 do
            if data.wins[u][v][i] then
                data.computerWin[i] = data.computerWin[i]+1;
                data.myWin[i] = 7;
                if data.computerWin[i] == 5 then
                    Api.Chat:sendSystemMsg("Room "..roomId.."Robot wins ")
                    GobangData.SetWin(roomId,true);
                    return
                end
            end
        end

    end,


    GetAIBestPos = function(roomId)
        local this = AIGame;
        local data = AIGame.AIData[roomId]
        local myScore = {};
        local computerScore = {};

        local max = 0;
        local u =7;
        local v =7;

        for i = 0 ,14 do
            myScore[i] = {};
            computerScore[i] = {};
            for j =0 ,14 do
                myScore[i][j] = 0;
                computerScore[i][j] = 0;
            end
        end

        for i =0,14 do
            for j =0,14 do
                if data.chessBoard[i][j] == 0 then
                    for k = 0,data.successTypeCount-1  do
                        if data.wins[i][j][k] then
                            if data.myWin[k] ==1 then
                                myScore[i][j] =  myScore[i][j] + 200
                            elseif data.myWin[k] ==2 then
                                myScore[i][j] =  myScore[i][j] + 400
                            elseif data.myWin[k] ==3 then
                                myScore[i][j] =  myScore[i][j] + 2000
                            elseif data.myWin[k] ==4 then
                                myScore[i][j] =  myScore[i][j] + 10000
                            end

                            if data.computerWin[k] ==1 then
                                computerScore[i][j] =  computerScore[i][j] + 220
                            elseif data.computerWin[k] ==2 then
                                computerScore[i][j] =  computerScore[i][j] + 420
                            elseif data.computerWin[k] ==3 then
                                computerScore[i][j] =  computerScore[i][j] + 2100
                            elseif data.computerWin[k] ==4 then
                                computerScore[i][j] =  computerScore[i][j] + 20000
                            end
                            if myScore[i][j] > max then
                                max = myScore[i][j];
                                u=i;
                                v=j;
                            elseif myScore[i][j] == max then
                                if computerScore[i][j] >computerScore[u][v] then
                                    u=i;
                                    v=j;
                                end
                            end
                            if computerScore[i][j] > max then
                                max = computerScore[i][j];
                                u=i;
                                v=j;
                            elseif computerScore[i][j] == max then
                                if myScore[i][j] >myScore[u][v] then
                                    u=i;
                                    v=j;
                                end
                            end
                        end
                    end
                end
            end
        end

        return u,v
    end,


    SetPlaceThreeChess = function(roomId)

        local this = AIGame;
        local data = AIGame.AIData[roomId]
        if roomId == nil or GobangData == nil or GobangData[roomId] == nil then return end
        if GobangData.IsDesignatedStart == false then return end

        if GobangData[roomId].IsAI == false then return end
        if GobangData[roomId].IsStartModeFinish == false or GobangData[roomId].IsBeginRound ==false then return end

        local chessData = GobangData[roomId]
        local checkerboardCenterPos;
        local curRelativePos
        checkerboardCenterPos = Config.CheckerboardCenterPos[roomId]
        curRelativePos = Config.ThreeChessRelativePos[chessData.CurStartModeIndex]

        for k,v in pairs(curRelativePos) do
            local x,y,z
            local chessType;
            local normalx = -1;
            local normalz = -1;
            local mapTable = nil;
            local otherMapTable = nil;

            x = v.x +checkerboardCenterPos.x
            y = v.y +checkerboardCenterPos.y
            z = v.z +checkerboardCenterPos.z

            table.insert(data.placedBlockPos,{x =x,y=y,z=z})

            if k == 2 then
                chessType = Config.ChessType.WhiteChess
            else
                chessType = Config.ChessType.BlackChess
            end

            if chessType == GobangData[roomId].AIChess then
                mapTable = data.computerWin
                otherMapTable = data.myWin
            elseif chessType == GobangData[roomId].MyChessType then
                mapTable = data.myWin
                otherMapTable = data.computerWin
            end

            normalx, normalz = this.GetNormalizedCoord(roomId,x,y,z);
            data.chessBoard[normalx][normalz] = chessType;
            for i = 0, data.successTypeCount-1 do
                if data.wins[normalx][normalz][i] then
                    mapTable[i] = mapTable[i]+1;
                    otherMapTable[i] = 7;
                end
            end
        end
    end,


    SetAIRoundBeforeData = function(roomId)
        if roomId == nil then return end
        local data = GobangData[roomId];

        if data.IsAI == false then return end


        if GobangData.IsDesignatedStart then
            if data.AIChess == Config.ChessType.BlackChess then
                if data.IsStartModeFinish  == true then return end
                GobangData.SetStartMode(roomId,true)
            elseif data.AIChess == Config.ChessType.WhiteChess then
                if data.IsStartModeFinish  ==false or data.IsBeginRound then return end
                GobangData.SetBeginRound(roomId,true)
            end
        else

            GobangData.SetBeginRound(roomId,true)
        end

    end,


    ChessBlockPlaceTrigger = function(param)
        local curRoomId = GobangMgr.GetRoomidByPos(param.x,param.y,param.z)
        if curRoomId == nil then  return end
        local data = GobangData[curRoomId]




        local myChessType
        if data.AIChess == Config.ChessType.BlackChess then
            myChessType = Config.ChessType.WhiteChess
        elseif data.AIChess == Config.ChessType.WhiteChess then
            myChessType = Config.ChessType.BlackChess
        end

        if myChessType == data.CurChessType then

            AIGame.BlockPlacedBy(curRoomId,param.x,param.y,param.z)
        elseif data.AIChess == data.CurChessType then

            TimerManager.CreateTimer(1,function()

                AIGame.ComputerAI(curRoomId)
            end)

        end
    end,


    ResetData = function(roomId)
        if roomId == nil then

            return
        end

        local data = AIGame.AIData[roomId]

        print(data.placedBlockPos)
        for k,v in pairs(data.placedBlockPos) do
            Api.Block:destroyBlock(v.x,v.y,v.z,false)
        end

        AIGame.AIData[roomId].placedBlockPos = {}
        AIGame.AIData[roomId].successTypeCount = 0
        AIGame.AIData[roomId].wins = {}
        AIGame.AIData[roomId].myWin = {}
        AIGame.AIData[roomId].computerWin = {}
        AIGame.AIData[roomId].chessBoard = {}
        AIGame.AIData[roomId].isAIPlace = false

    end,


}


BattleGame = {
    BattleData = {
        [Config.RoomType.RoomOne] = {
            whiteChessList = { };
            blackChessList = { };
            battleData = {
                beginTime=os.time(),
                roundNum = 0,
                curNum = 0,
            }
        },
        [Config.RoomType.RoomTwo] = {
            whiteChessList = { };
            blackChessList = { };
            battleData = {
                beginTime=os.time(),
                roundNum = 0,
                curNum = 0,
            }
        },
        [Config.RoomType.RoomThree] = {
            whiteChessList = { };
            blackChessList = { };
            battleData = {
                beginTime=os.time(),
                roundNum = 0,
                curNum = 0,
            }
        },
        [Config.RoomType.RoomFour] = {
            whiteChessList = { };
            blackChessList = { };
            battleData = {
                beginTime=os.time(),
                roundNum = 0,
                curNum = 0,
            }
        },

        AllChessNum = 225
    },


    JudgeVictory = function(roomId,chessList,byactor)
        if chessList == nil then return end;
        local this = BattleGame;


        if this.checkX(chessList) or  this.checkZ(chessList) or  this.checkLeft(chessList) or this.checkRight(chessList) then
            Api.Player:notifyGameInfo2Self(byactor,"You win ")
            GobangData.SetWin(roomId,true)
            local ret,score = Api.Player:getGameScore(byactor)
            Api.Player:setGameScore(byactor,score+1)

        else
        end
    end,


    checkX = function(chessInfoList)
        if chessInfoList == nil then return false end;

        table.sort(chessInfoList,function (a,b) return a.z > b.z  end )

        local xIdenticalList = {};
        local sameNum = 0;
        local j = 0;
        local g = 0;

        for k,v in pairs(chessInfoList) do
            if  xIdenticalList[v.x] == nil then
                xIdenticalList[v.x] = {};
            end
            table.insert( xIdenticalList[v.x],v);
        end



        for k, v in  pairs(xIdenticalList) do
            sameNum = 0;
            j = 0;
            g = 0;

            for k1,v1 in pairs(v) do
                j = v1.z;
                print(math.abs(g-j))
                print(g,",",j)
                if math.abs(g-j)  == 1 then
                    sameNum = sameNum+1;
                    if sameNum>=4 then

                        return true;
                    end
                else
                    sameNum = 0
                end
                g=j;
            end
        end
        return false
    end,

    checkZ = function(chessInfoList)
        if chessInfoList == nil then return false end;

        table.sort(chessInfoList,function (a,b) return a.x > b.x  end )

        local xIdenticalList = {};
        local sameNum = 0;
        local j = 0;
        local g = 0;

        for k,v in pairs(chessInfoList) do
            if  xIdenticalList[v.z] == nil then
                xIdenticalList[v.z] = {};
            end
            table.insert( xIdenticalList[v.z],v);
        end



        for k, v in  pairs(xIdenticalList) do
            sameNum = 0;
            j = 0;
            g = 0;

            for k1,v1 in pairs(v) do
                j = v1.x;
                print(math.abs(g-j))
                print(g,",",j)
                if math.abs(g-j) == 1 then
                    sameNum = sameNum+1;
                    if sameNum>=4 then

                        return true;
                    end
                else
                    sameNum = 0
                end
                g=j;
            end
        end

        return false
    end,

    checkRight = function(chessInfoList)
        if chessInfoList == nil then return false end;

        table.sort(chessInfoList,function (a,b) return a.x > b.x  end )

        local xIdenticalList = {};
        local sameNum = 0;
        local j = 0;
        local g = 0;

        for k,v in pairs(chessInfoList) do
            if  xIdenticalList[v.Xaddy] == nil then
                xIdenticalList[v.Xaddy] = {};
            end
            table.insert( xIdenticalList[v.Xaddy],v);
        end

        for k, v in  pairs(xIdenticalList) do
            sameNum = 0;
            j = 0;
            g = 0;

            for k1,v1 in pairs(v) do
                j = v1.x;
                print(math.abs(g-j))
                if math.abs(g-j) == 1 then
                    sameNum = sameNum+1;
                    if sameNum>=4 then

                        return true;
                    end
                else
                    sameNum = 0
                end
                g=j;
            end
        end

        return false
    end,

    checkLeft = function(chessInfoList)
        if chessInfoList == nil then return false end;

        table.sort(chessInfoList,function (a,b) return a.x > b.x  end )

        local xIdenticalList = {};
        local sameNum = 0;
        local j = 0;
        local g = 0;

        for k,v in pairs(chessInfoList) do
            if  xIdenticalList[v.Xsuby] == nil then
                xIdenticalList[v.Xsuby] = {};
            end
            table.insert( xIdenticalList[v.Xsuby],v);
        end

        for k, v in  pairs(xIdenticalList) do
            sameNum = 0;
            j = 0;
            g = 0;

            for k1,v1 in pairs(v) do
                j = v1.x;
                print(math.abs(g-j))
                if math.abs(g-j) == 1 then
                    sameNum = sameNum+1;
                    if sameNum>=4 then

                        return true;
                    end
                else
                    sameNum = 0
                end
                g=j;
            end
        end

        return false
    end,


    GetChessListByBlockId = function(roomId,blockid)
        if blockid == nil then return end;
        local this = BattleGame;
        local data = BattleGame.BattleData[roomId]

        if tonumber(blockid) == Config.BlockIdEnum[2] then
            return data.whiteChessList
        elseif tonumber(blockid) == Config.BlockIdEnum[1] then
            return data.blackChessList
        else
            return nil;
        end
    end,


    SaveChessInfo = function(blockid,x,y,z)
        chessInfo = {
            x=x,
            y=y,
            z=z,
            Xsuby = x-z;
            Xaddy = x+z;
        }

        local this = BattleGame;
        local curRoomId = GobangMgr.GetRoomidByPos(x,y,z)

        local chessList = this.GetChessListByBlockId(curRoomId,blockid);
        if chessList == nil then return end;

        table.insert(chessList,chessInfo);
    end,


    SetChessRoundData = function(roomId)
        if roomId == nil or curNum ==nil or roundNum == nil then return end

        local data = BattleGame.BattleData[roomId].battleData;
        if data == nil then return end

        local num = 0
        for k,v in pairs(BattleGame.BattleData[roomId].whiteChessList) do
            num = num+1
        end

        for k,v in pairs(BattleGame.BattleData[roomId].whiteChessList) do
            num = num+1
        end

        if num >= BattleGame.BattleData.AllChessNum then

            return
        end

        if num == data.curNum and data.beginTime+20 <os.time() and data.roundNum >=4 then

            return
        end

        if num == data.curNum and data.roundNum <4 then
            data.roundNum = data.roundNum+1
        else
            data.roundNum = 1
            data.beginTime = os.time()
            data.curNum = num

        end

    end,


    SetPlaceThreeChess = function(roomId)
        if roomId == nil or GobangData == nil or GobangData[roomId] == nil then return end
        if GobangData.IsDesignatedStart == false then return end
        if GobangData[roomId].IsAI then return end
        if GobangData[roomId].IsStartModeFinish == false or GobangData[roomId].IsBeginRound ==false then return end

        local this = BattleGame;
        local data = BattleGame.BattleData[roomId]
        local ChessData = GobangData[roomId]
        local checkerboardCenterPos;
        local curRelativePos
        checkerboardCenterPos = Config.CheckerboardCenterPos[roomId]
        curRelativePos = Config.ThreeChessRelativePos[ChessData.CurStartModeIndex]

        for k,v in pairs(curRelativePos) do
            local x,y,z
            local chessType;

            x = v.x +checkerboardCenterPos.x
            y = v.y +checkerboardCenterPos.y
            z = v.z +checkerboardCenterPos.z

            if k == 2 then
                chessType = Config.ChessType.WhiteChess
            else
                chessType = Config.ChessType.BlackChess
            end

            this.SaveChessInfo(Config.BlockIdEnum[chessType],x,y,z);
        end

    end,


    StartRound = function(roomId)
        if GobangData[roomId].IsAI then return end

        if GobangData.IsDesignatedStart then
            GobangData.SetCurChess(roomId,Config.ChessType.WhiteChess)
        else
            GobangData.SetCurChess(roomId,Config.ChessType.BlackChess)
        end
        SettingRule.RoundTimeLimited(roomId)
        if GobangData[roomId].CurChessType == Config.ChessType.WhiteChess then
            Api.Chat:sendSystemMsg("White round, please place the stone ")
        elseif GobangData[roomId].CurChessType == Config.ChessType.BlackChess then
            Api.Chat:sendSystemMsg("Black round, please place the stone ")
        end
    end,


    BlockPlacedBy = function(x, y, z, blockid, byactor)
        local this = BattleGame;
        local curRoomId = GobangMgr.GetRoomidByPos(x,y,z);
        local data = GobangData[curRoomId]
        local changeState = false

        if data.IsAI or data.CurChessType == Config.ChessType.None then return end

        if data.CurChessType == Config.ChessType.BlackChess then
            if blockid == Config.BlockIdEnum[1] and byactor == data.BlackChess.uin then
                changeState = true
            end
        elseif data.CurChessType == Config.ChessType.WhiteChess then
            if blockid == Config.BlockIdEnum[2] and byactor == data.WhiteChess.uin then
                changeState = true
            end
        end

        if changeState == false then
            Api.Player:notifyGameInfo2Self(byactor,"It is other side turn ")
            Api.Block:destroyBlock(x,y,z,false);
            return
        end

        local chessList = this.GetChessListByBlockId(curRoomId,blockid);
        if chessList == nil then return end;

        this.SaveChessInfo(blockid,x,y,z)
        this.JudgeVictory(curRoomId,chessList,byactor)

        if data.CurChessType == Config.ChessType.BlackChess then

            GobangData.SetCurChess(curRoomId,Config.ChessType.WhiteChess)

        elseif data.CurChessType == Config.ChessType.WhiteChess then

            GobangData.SetCurChess(curRoomId,Config.ChessType.BlackChess)
        end

        SettingRule.RoundTimeLimited(curRoomId)
        if GobangData[roomId].CurChessType == Config.ChessType.WhiteChess then
            Api.Chat:sendSystemMsg("White round, please place the stone ")
        elseif GobangData[roomId].CurChessType == Config.ChessType.BlackChess then
            Api.Chat:sendSystemMsg("Black round, please place the stone ")
        end

    end,


    SetStartGameData = function(roomId)
        if roomId == nil then return end
        if GobangData.IsDesignatedStart ~= true then
            GobangData.SetBeginRound(roomId,true)
        end
    end,


    ResetData = function(roomId)
        local data = BattleGame.BattleData[roomId]

        for k,v in pairs(data.whiteChessList) do
            Api.Block:destroyBlock(v.x,v.y,v.z,false)
        end

        for k,v in pairs(data.blackChessList) do
            Api.Block:destroyBlock(v.x,v.y,v.z,false)
        end

        BattleGame.BattleData[roomId].whiteChessList = { };
        BattleGame.BattleData[roomId].blackChessList = { };
        BattleGame.BattleData[roomId].battleData = {
            beginTime=os.time(),
            roundNum = 0,
            curNum = 0,
        }

    end,


}


TimerManager = {

    TaskList = {},
    CountdownTaskList = {},
    Tick = 0,
    CountdownTick = 0,

    RoundTimer = {},

    CreateTimer = function(timeInterval,func)
        if timeInterval == nil then return end
        local this = TimerManager
        local timeList = {
            beginTime = os.time(),
            timeInterval = timeInterval,
            func = func,
        }
        table.insert(this.TaskList,timeList)
    end,


    CreateCountdownTimer = function(timeInterval,uin,func)
        if timeInterval == nil or timeInterval <=0 then return end
        local this = TimerManager

        local timeList = {
            beginTime = os.time(),
            timeInterval = timeInterval,
            uin = uin,
            func = func,
        }

        table.insert(this.CountdownTaskList,timeList)
    end,


    StartRoundTimer = function(roomId,uins,timeInterval,func)
        if func == nil or roomId == nil then return end
        local timer = TimerManager.RoundTimer[roomId]
        if timer == nil or timer.timerid == nil then
            local ret,timerid = Api.MiniTimer:createTimer("Countdown")
            if ret == ErrorCode.OK then
                local round = {
                    RoundInterval = 60,
                    RoundFunc = func,
                    BeginTime = -1,
                    Uins = uins,
                    timerid = timerid,
                }

                if timeInterval ~= nil and timeInterval >= 0 then
                    round.RoundInterval = timeInterval;
                end
                TimerManager.RoundTimer[roomId] = round
                timer = round
            end
        end

        local ret = Api.MiniTimer:startBackwardTimer(timer.timerid,timer.RoundInterval,false)
        if ret ~= ErrorCode.OK then return end

        local text = ""
        if GobangData[roomId].CurChessType == Config.ChessType.BlackChess then
            text = "Black round countdown: "
        elseif GobangData[roomId].CurChessType == Config.ChessType.WhiteChess then
            text = "White round countdown: "
        end

        local ret = Api.MiniTimer:showTimerTips(timer.Uins,timer.timerid,text,true);
        if ret ~= ErrorCode.OK then return end
        timer.BeginTime = os.time()
    end,

    ClearRoundTimer = function(roomId)
        if roomId == nil then return end

        local this = TimerManager
        local timer = this.RoundTimer[roomId]
        if timer == nil then return end

        Api.MiniTimer:showTimerTips(timer.Uins,timer.timerid,"",false);
        Api.MiniTimer:deleteTimer(timer.timerid)
        this.RoundTimer[roomId] = nil
    end,

    Update = function()
        local this = TimerManager
        this.Tick = this.Tick + 1
        this.CountdownTick = this.CountdownTick + 1

        if this.Tick >=10 then
            this.Tick = 0
            for k,v in pairs(this.TaskList) do
                if v == nil then break end
                if os.time() >=v.beginTime+v.timeInterval and v.func ~= nil then
                    v.func()

                    table.remove(this.TaskList,k)
                end
            end
        end

        if this.CountdownTick >=20 then
            this.CountdownTick = 0

            for k,v in pairs(this.CountdownTaskList) do
                if v == nil then break end
                local num = v.beginTime+v.timeInterval - os.time()
                if num > 0 and v.uin ~= nil then
                    Api.Player:notifyGameInfo2Self(v.uin,"countdown "..num.."seconds ")
                end
                if os.time() >=v.beginTime+v.timeInterval and v.func ~= nil then
                    v.func()
                    table.remove(this.CountdownTaskList,k)
                end
            end


        end

        for k,v in pairs(this.RoundTimer) do
            if GobangData[k].IsBeginRound == false then break end
            if v == nil then break end
            if v.BeginTime == -1 then break end

            local ret,time = Api.MiniTimer:getTimerTime(v.timerid)
            if ret == ErrorCode.OK and time ==  1 then
                v.BeginTime = -1
                Api.MiniTimer:showTimerTips(v.Uins,v.timerid,"countdown: ",false);
                if v.RoundFunc ~= nil then
                    local func = v.RoundFunc
                    func()
                end
                this.RoundTimer[k] = nil
            end
        end
    end,
}

listenevents_gobang()

Last Update: 9/9/2019, 5:57:21 PM