commit de90ad79ea6caa488a7354019628974e14367cbd Author: ytc1012 <18001193130@163.com> Date: Tue Nov 18 18:08:48 2025 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..585f569 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +.vscode/ +bin/ \ No newline at end of file diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..1ccebc9 --- /dev/null +++ b/config/config.go @@ -0,0 +1,233 @@ +package config + +import ( + "fmt" + "log/slog" + "os" + "path/filepath" + "strings" + + "github.com/spf13/viper" + "gopkg.in/ini.v1" +) + +var ( + V *viper.Viper + ROOT string +) + +const mainIniPath = "bin/conf/env.ini" + +func init() { + root, err := findConfigRoot() + if err != nil { + slog.Warn("can't find config root", "error", err) + ROOT, _ = os.Getwd() + } else { + ROOT = root + } + + configPath := filepath.Join(ROOT, mainIniPath) + + V = viper.New() + + // 使用 ini 包解析配置文件 + cfg, err := ini.Load(configPath) + if err != nil { + slog.Error("load config file error", "error", err) + // 创建一个空的配置 + cfg = ini.Empty() + } + + // 将 ini 配置加载到 viper 中 + loadIniToViper(cfg, V) + + if err = loadIncludeFiles(); err != nil { + panic("load include files error:" + err.Error()) + } + + go signalReload() +} + +func ReloadConfigFile() { + configPath := filepath.Join(ROOT, mainIniPath) + + // 使用 ini 包重新加载配置文件 + cfg, err := ini.Load(configPath) + if err != nil { + slog.Error("reload config file error", "error", err) + return + } + + // 清空现有配置并重新加载 + V = viper.New() + loadIniToViper(cfg, V) + + if err := loadIncludeFiles(); err != nil { + slog.Error("reload include files error", "error", err) + return + } + slog.Info("reload config file successfully") +} + +func SaveConfigFile() error { + configPath := filepath.Join(ROOT, mainIniPath) + if err := V.WriteConfigAs(configPath); err != nil { + slog.Error("save config file error", "error", err) + return err + } + + slog.Info("save config file successfully") + return nil +} + +func loadIncludeFiles() error { + includeFile := GetString("include_files.path", "") + if includeFile != "" { + includeFiles := strings.Split(includeFile, ",") + for _, file := range includeFiles { + file = strings.TrimSpace(file) + if file != "" { + // 使用绝对路径或相对路径 + if !filepath.IsAbs(file) { + file = filepath.Join(ROOT, file) + } + // 使用 ini 包加载包含的配置文件 + cfg, err := ini.Load(file) + if err != nil { + return fmt.Errorf("failed to read config file %s: %w", file, err) + } + // 合并配置到主 viper 实例 + loadIniToViper(cfg, V) + } + } + } + + return nil +} + +// GetString 获取字符串配置值,支持 section.key 格式 +func GetString(key string, defaultValue string) string { + if V.IsSet(key) { + return V.GetString(key) + } + return defaultValue +} + +// GetInt 获取整数配置值,支持 section.key 格式 +func GetInt(key string, defaultValue int) int { + if V.IsSet(key) { + return V.GetInt(key) + } + return defaultValue +} + +// GetBool 获取布尔配置值,支持 section.key 格式 +func GetBool(key string, defaultValue bool) bool { + if V.IsSet(key) { + return V.GetBool(key) + } + return defaultValue +} + +// GetSection 获取整个 section 的配置,返回 map[string]string +func GetSection(section string) (map[string]string, error) { + // 从 viper 中获取 section,格式为 section.key + sectionMap := make(map[string]string) + + // 遍历所有配置键,查找属于该 section 的配置 + allKeys := V.AllKeys() + found := false + for _, key := range allKeys { + if strings.HasPrefix(key, section+".") { + found = true + subKey := strings.TrimPrefix(key, section+".") + sectionMap[subKey] = V.GetString(key) + } + } + + if !found { + return nil, fmt.Errorf("section %s not found", section) + } + return sectionMap, nil +} + +// GetPath 获取路径配置值,如果是相对路径则基于 ROOT 解析为绝对路径 +func GetPath(key string, defaultValue string) string { + pathValue := GetString(key, defaultValue) + if pathValue == "" { + return defaultValue + } + // 如果是绝对路径,直接返回 + if filepath.IsAbs(pathValue) { + return pathValue + } + // 相对路径基于 ROOT 解析 + return filepath.Join(ROOT, pathValue) +} + +// loadIniToViper 将 ini 配置加载到 viper 中 +func loadIniToViper(cfg *ini.File, v *viper.Viper) { + for _, section := range cfg.Sections() { + sectionName := section.Name() + // 跳过默认 section (DEFAULT) + if sectionName == ini.DEFAULT_SECTION { + sectionName = "" + } + + for _, key := range section.Keys() { + keyName := key.Name() + value := key.Value() + + // 构建 viper 键名:section.key 或 key (如果 section 为空) + var viperKey string + if sectionName != "" { + viperKey = sectionName + "." + keyName + } else { + viperKey = keyName + } + + v.Set(viperKey, value) + } + } +} + +// fileExist 检查文件或目录是否存在 +// 如果由 filename 指定的文件或目录存在则返回 true,否则返回 false +func fileExist(filename string) bool { + _, err := os.Stat(filename) + return err == nil || os.IsExist(err) +} + +func findConfigRoot() (string, error) { + if execPath, err := os.Executable(); err == nil { + if root := searchConfig(filepath.Dir(execPath)); root != "" { + return root, nil + } + } + + if wd, err := os.Getwd(); err == nil { + if root := searchConfig(wd); root != "" { + return root, nil + } + } + + return "", fmt.Errorf("unable to locate %s", mainIniPath) +} + +func searchConfig(start string) string { + dir := start + for { + configPath := filepath.Join(dir, mainIniPath) + if fileExist(configPath) { + return dir + } + + parent := filepath.Dir(dir) + if parent == dir { + break + } + dir = parent + } + return "" +} diff --git a/config/reload_unix.go b/config/reload_unix.go new file mode 100644 index 0000000..e7a5624 --- /dev/null +++ b/config/reload_unix.go @@ -0,0 +1,22 @@ +// +build !windows,!plan9 + +package config + +import ( + "os" + "os/signal" + "syscall" +) + +func signalReload() { + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGUSR1) + + for { + sig := <-ch + switch sig { + case syscall.SIGUSR1: + ReloadConfigFile() + } + } +} diff --git a/config/reload_windows.go b/config/reload_windows.go new file mode 100644 index 0000000..0e07fc7 --- /dev/null +++ b/config/reload_windows.go @@ -0,0 +1,4 @@ +package config + +func signalReload() { +} diff --git a/constant/code.go b/constant/code.go new file mode 100644 index 0000000..277f2b7 --- /dev/null +++ b/constant/code.go @@ -0,0 +1,73 @@ +package constant + +const ProxyConnectError = -4 //代理连接失败 +const ProxyNotInConnect = -3 //代理错误 +const UserNotInConnect = -2 //链接没有找到用户 +const RoleNotInConnect = -1 //链接没有找到角色 +const OK = 0 +const InvalidParam = 1 //参数有误 +const DBError = 2 //数据库异常 +const UserExist = 3 //用户已存在 +const PwdIncorrect = 4 //密码不正确 +const UserNotExist = 5 //用户不存在 +const SessionInvalid = 6 //session无效 +const HardwareIncorrect = 7 //Hardware错误 +const RoleAlreadyCreate = 8 //已经创建过角色了 +const RoleNotExist = 9 //角色不存在 +const CityNotExist = 10 //城市不存在 +const CityNotMe = 11 //城市不是自己的 +const UpError = 12 //升级失败 +const GeneralNotFound = 13 //武将不存在 +const GeneralNotMe = 14 //武将不是自己的 +const ArmyNotFound = 15 //军队不存在 +const ArmyNotMe = 16 //军队不是自己的 +const ResNotEnough = 17 //资源不足 +const OutArmyLimit = 18 //超过带兵限制 +const ArmyBusy = 19 //军队再忙 +const GeneralBusy = 20 //将领再忙 +const CannotGiveUp = 21 //不能放弃 +const BuildNotMe = 22 //领地不是自己的 +const ArmyNotMain = 23 //军队没有主将 +const UnReachable = 24 //不可到达 +const PhysicalPowerNotEnough = 25 //体力不足 +const DecreeNotEnough = 26 //政令不足 +const GoldNotEnough = 27 //金币不足 +const GeneralRepeat = 28 //重复上阵 +const CostNotEnough = 29 //cost不足 +const GeneralNoHas = 30 //没有该合成武将 +const GeneralNoSame = 31 //合成武将非同名 +const ArmyNotEnough = 32 //队伍数不足 +const TongShuaiNotEnough = 33 //统帅不足 +const GeneralStarMax = 34 //升级到最大星级 +const UnionCreateError = 35 //联盟创建失败 +const UnionNotFound = 36 //联盟不存在 +const PermissionDenied = 37 //权限不足 +const UnionAlreadyHas = 38 //已经有联盟 +const UnionNotAllowExit = 39 //不允许退出 +const ContentTooLong = 40 //内容太长 +const NotBelongUnion = 41 //不属于该联盟 +const PeopleIsFull = 42 //用户已满 +const HasApply = 43 //已经申请过了 +const BuildCanNotDefend = 44 //不能驻守 +const BuildCanNotAttack = 45 //不能占领 +const BuildMBSNotFound = 46 //没有军营 +const BuildWarFree = 47 //免战中 +const ArmyConscript = 48 //征兵中 +const BuildGiveUpAlready = 49 //领地已经在放弃了 +const CanNotBuildNew = 50 //不能再新建建筑在领地上 +const CanNotTransfer = 51 //不能调兵 +const HoldIsFull = 52 //坑位已满 +const ArmyIsOutside = 53 //队伍在城外 +const CanNotUpBuild = 54 //不能升级建筑 +const CanNotDestroy = 55 //不能拆除建筑 +const OutCollectTimesLimit = 56 //超过征收次数 +const InCdCanNotOperate = 57 //cd内不能操作 +const OutGeneralLimit = 58 //武将超过上限了 +const NotHasJiShi = 59 //没有集市 +const OutPosTagLimit = 60 //超过了收藏上限 +const OutSkillLimit = 61 //超过了技能上限 +const UpSkillError = 62 //装备技能失败 +const DownSkillError = 63 //取下技能失败 +const OutArmNotMatch = 64 //兵种不符 +const PosNotSkill = 65 //该位置没有技能 +const SkillLevelFull = 66 //技能等级已满 diff --git a/data/conf/db.sql b/data/conf/db.sql new file mode 100644 index 0000000..a99c084 --- /dev/null +++ b/data/conf/db.sql @@ -0,0 +1,233 @@ + +CREATE TABLE IF NOT EXISTS `tb_user_info` ( + `uid` int unsigned NOT NULL AUTO_INCREMENT, + `username` varchar(20) NOT NULL COMMENT '用户名', + `passcode` char(12) NOT NULL DEFAULT '' COMMENT '加密随机数', + `passwd` char(64) NOT NULL DEFAULT '' COMMENT 'md5密码', + `status` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '用户账号状态。0-默认;1-冻结;2-停号', + `hardware` varchar(64) NOT NULL DEFAULT '' COMMENT 'hardware', + `ctime` timestamp NOT NULL DEFAULT '2013-03-15 14:38:09', + `mtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`uid`), + UNIQUE KEY (`username`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '用户信息表'; + +CREATE TABLE IF NOT EXISTS `tb_login_history` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `uid` int unsigned NOT NULL DEFAULT 0 COMMENT '用户UID', + `state` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '登录状态,0登录,1登出', + `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '登录时间', + `ip` varchar(31) NOT NULL DEFAULT '' COMMENT 'ip', + `hardware` varchar(64) NOT NULL DEFAULT '' COMMENT 'hardware', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '用户登录表'; + +CREATE TABLE IF NOT EXISTS `tb_login_last` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `uid` int unsigned NOT NULL DEFAULT 0 COMMENT '用户UID', + `login_time` timestamp COMMENT '登录时间', + `logout_time` timestamp COMMENT '登出时间', + `ip` varchar(31) NOT NULL DEFAULT '' COMMENT 'ip', + `is_logout` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '是否logout,1:logout,0:login', + `session` varchar(100) COMMENT '会话', + `hardware` varchar(64) NOT NULL DEFAULT '' COMMENT 'hardware', + UNIQUE KEY (`uid`), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '最后一次用户登录表'; + +CREATE TABLE IF NOT EXISTS `tb_role_1` ( + `rid` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'roleId', + `uid` int unsigned NOT NULL COMMENT '用户UID', + `headId` int unsigned NOT NULL DEFAULT 0 COMMENT '头像Id', + `sex` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '性别,0:女 1男', + `nick_name` varchar(100) COMMENT 'nick_name', + `balance` int unsigned NOT NULL DEFAULT 0 COMMENT '余额', + `login_time` timestamp COMMENT '登录时间', + `logout_time` timestamp COMMENT '登出时间', + `profile` varchar(500) COMMENT '个人简介', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + UNIQUE KEY (`uid`), + PRIMARY KEY (`rid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '玩家表'; + +CREATE TABLE IF NOT EXISTS `tb_map_role_city_1` ( + `cityId` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'cityId', + `rid` int unsigned NOT NULL COMMENT 'roleId', + `x` int unsigned NOT NULL COMMENT 'x坐标', + `y` int unsigned NOT NULL COMMENT 'y坐标', + `name` varchar(100) NOT NULL DEFAULT '城池' COMMENT '城池名称', + `is_main` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '是否是主城', + `cur_durable` int unsigned NOT NULL COMMENT '当前耐久', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `occupy_time` timestamp DEFAULT '2013-03-15 14:38:09' COMMENT '占领时间', + PRIMARY KEY (`cityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '玩家城池'; + + + +CREATE TABLE IF NOT EXISTS `tb_map_role_build_1` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `rid` int unsigned NOT NULL, + `type` int unsigned NOT NULL COMMENT '建筑类型', + `level` tinyint unsigned NOT NULL COMMENT '建筑等级', + `op_level` tinyint unsigned COMMENT '建筑操作等级', + `x` int unsigned NOT NULL COMMENT 'x坐标', + `y` int unsigned NOT NULL COMMENT 'y坐标', + `name` varchar(100) NOT NULL COMMENT '名称', + `max_durable` int unsigned NOT NULL COMMENT '最大耐久', + `cur_durable` int unsigned NOT NULL COMMENT '当前耐久', + `end_time` timestamp DEFAULT '2013-03-15 14:38:09' COMMENT '建造、升级、拆除结束时间', + `occupy_time` timestamp DEFAULT '2013-03-15 14:38:09' COMMENT '占领时间', + `giveUp_time` int unsigned DEFAULT '0' COMMENT '放弃时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '角色建筑'; + +CREATE TABLE IF NOT EXISTS `tb_city_facility_1` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `cityId` int unsigned NOT NULL COMMENT '城市id', + `rid` int unsigned NOT NULL, + `facilities` varchar(4096) NOT NULL COMMENT '设施列表,格式为json结构', + UNIQUE KEY (`cityId`), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '城池设施'; + +CREATE TABLE IF NOT EXISTS `tb_role_res_1` ( + `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `rid` int unsigned NOT NULL COMMENT 'rid', + `wood` int unsigned NOT NULL COMMENT '木', + `iron` int unsigned NOT NULL COMMENT '铁', + `stone` int unsigned NOT NULL COMMENT '石头', + `grain` int unsigned NOT NULL COMMENT '粮食', + `gold` int unsigned NOT NULL COMMENT '金币', + `decree` int unsigned NOT NULL COMMENT '令牌', + UNIQUE KEY (`rid`), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '角色资源表'; + +CREATE TABLE IF NOT EXISTS `tb_general_1` ( + `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `rid` int unsigned NOT NULL COMMENT 'rid', + `cfgId` int unsigned NOT NULL COMMENT '配置id', + `physical_power` int unsigned NOT NULL COMMENT '体力', + `exp` int unsigned NOT NULL COMMENT '经验', + `order` tinyint NOT NULL COMMENT '第几队', + `level` tinyint unsigned NOT NULL DEFAULT 1 COMMENT 'level', + `cityId` int NOT NULL DEFAULT 0 COMMENT '城市id', + `star` int NOT NULL DEFAULT 0 COMMENT '稀有度(星级)', + `star_lv` int NOT NULL DEFAULT 0 COMMENT '稀有度(星级)进阶等级级', + `arms` int NOT NULL DEFAULT 0 COMMENT '兵种', + `has_pr_point` int NOT NULL DEFAULT 0 COMMENT '总属性点', + `use_pr_point` int NOT NULL DEFAULT 0 COMMENT '已用属性点', + `attack_distance` int NOT NULL DEFAULT 0 COMMENT '攻击距离', + `force_added` int NOT NULL DEFAULT 0 COMMENT '已加攻击属性', + `strategy_added` int NOT NULL DEFAULT 0 COMMENT '已加战略属性', + `defense_added` int NOT NULL DEFAULT 0 COMMENT '已加防御属性', + `speed_added` int NOT NULL DEFAULT 0 COMMENT '已加速度属性', + `destroy_added` int NOT NULL DEFAULT 0 COMMENT '已加破坏属性', + `parentId` int NOT NULL DEFAULT 0 COMMENT '已合成到武将的id', + `compose_type` int NOT NULL DEFAULT 0 COMMENT '合成类型', + `skills` varchar(64) NOT NULL DEFAULT '[0, 0, 0]' COMMENT '携带的技能', + `state` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '0:正常,1:转换掉了', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '将领表'; + +CREATE TABLE IF NOT EXISTS `tb_army_1` ( + `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `rid` int unsigned NOT NULL COMMENT 'rid', + `cityId` int unsigned NOT NULL COMMENT '城市id', + `order` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '第几队 1-5队', + `generals` varchar(256) NOT NULL DEFAULT '[0, 0, 0]' COMMENT '将领', + `soldiers` varchar(256) NOT NULL DEFAULT '[0, 0, 0]' COMMENT '士兵', + `conscript_times` varchar(256) NOT NULL DEFAULT '[0, 0, 0]' COMMENT '征兵结束时间', + `conscript_cnts` varchar(256) NOT NULL DEFAULT '[0, 0, 0]' COMMENT '征兵数量', + `cmd` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '命令 0:空闲 1:攻击 2:驻军 3:返回', + `from_x` int unsigned NOT NULL COMMENT '来自x坐标', + `from_y` int unsigned NOT NULL COMMENT '来自y坐标', + `to_x` int unsigned COMMENT '去往x坐标', + `to_y` int unsigned COMMENT '去往y坐标', + `start` timestamp COMMENT '出发时间', + `end` timestamp COMMENT '到达时间', + UNIQUE KEY (`rid`, `cityId`, `order`), + PRIMARY KEY (`id`) +)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '军队表'; + +CREATE TABLE IF NOT EXISTS `tb_war_report_1` ( + `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `a_rid` int unsigned NOT NULL COMMENT '攻击方id', + `d_rid` int unsigned NOT NULL DEFAULT 0 COMMENT '防守方id,0为系统npc', + `b_a_army` varchar(512) NOT NULL COMMENT '开始攻击方军队', + `b_d_army` varchar(512) NOT NULL COMMENT '开始防守方军队', + `e_a_army` varchar(512) NOT NULL COMMENT '开始攻击方军队', + `e_d_army` varchar(512) NOT NULL COMMENT '开始防守方军队', + `b_a_general` varchar(512) NOT NULL COMMENT '开始攻击方武将', + `b_d_general` varchar(512) NOT NULL COMMENT '开始防守方武将', + `e_a_general` varchar(512) NOT NULL COMMENT '结束攻击方武将', + `e_d_general` varchar(512) NOT NULL COMMENT '结束防守方武将', + `rounds` varchar(1024) NOT NULL COMMENT '回合战报数据', + `result` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '0失败,1打平,2胜利', + `a_is_read` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '攻击方战报是否已阅 0:未阅 1:已阅', + `d_is_read` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '攻击方战报是否已阅 0:未阅 1:已阅', + `destroy` int unsigned COMMENT '破坏了多少耐久', + `occupy` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '是否攻占 0:否 1:是', + `x` int unsigned COMMENT 'x坐标', + `y` int unsigned COMMENT 'y坐标', + `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '战报表'; + +CREATE TABLE IF NOT EXISTS `tb_coalition_1` ( + `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `name` varchar(20) NOT NULL COMMENT '联盟名字', + `members` varchar(2048) NOT NULL COMMENT '成员', + `create_id` int unsigned NOT NULL COMMENT '创建者id', + `chairman` int unsigned NOT NULL COMMENT '盟主', + `vice_chairman` int unsigned NOT NULL COMMENT '副盟主', + `notice` varchar(256) COMMENT '公告', + `state` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '0解散,1运行中', + `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY (`name`) +)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '联盟'; + +CREATE TABLE IF NOT EXISTS `tb_coalition_apply_1` ( + `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `union_id` int unsigned NOT NULL COMMENT '联盟id', + `rid` int unsigned NOT NULL COMMENT '申请者的rid', + `state` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '申请状态,0未处理,1拒绝,2通过', + `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '联盟申请表'; + +CREATE TABLE IF NOT EXISTS `tb_role_attribute_1` ( + `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `rid` int unsigned NOT NULL COMMENT 'rid', + `parent_id` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '上级联盟id', + `collect_times` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '征收次数', + `last_collect_time` timestamp DEFAULT '2013-03-15 14:38:09' COMMENT '最后征收时间', + `pos_tags` varchar(512) COMMENT '收藏的位置', + PRIMARY KEY (`id`) +)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '玩家属性表'; + +CREATE TABLE IF NOT EXISTS `tb_coalition_log_1` ( + `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `union_id` int unsigned NOT NULL COMMENT '联盟id', + `op_rid` int unsigned NOT NULL COMMENT '操作者id', + `target_id` int unsigned COMMENT '被操作的对象', + `des` varchar(256) NOT NULL COMMENT '描述', + `state` tinyint unsigned NOT NULL COMMENT '0:创建,1:解散,2:加入,3:退出,4:踢出,5:任命,6:禅让,7:修改公告', + `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '发生时间', + PRIMARY KEY (`id`) +)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '联盟日志表'; + +CREATE TABLE IF NOT EXISTS `tb_skill_1` ( + `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `rid` int unsigned NOT NULL COMMENT 'rid', + `cfgId` int unsigned NOT NULL COMMENT '技能id', + `belong_generals` varchar(256) NOT NULL Default '[]' COMMENT '归属武将数组', + `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '获得技能时间', + PRIMARY KEY (`id`) +)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT '技能表'; + + + diff --git a/data/conf/env.ini b/data/conf/env.ini new file mode 100644 index 0000000..79b9444 --- /dev/null +++ b/data/conf/env.ini @@ -0,0 +1,56 @@ +[mysql] +host = 127.0.0.1 +port = 3306 +user = root +password = root +dbname = slgdb +charset = utf8 +; 最大空闲连接数 +max_idle = 2 +; 最大打开连接数 +max_conn = 10 + +[httpserver] +host = +port = 8088 + + +[gateserver] +host = +port = 8004 +need_secret = true +slg_proxy = ws://127.0.0.1:8001 +chat_proxy = ws://127.0.0.1:8002 +login_proxy = ws://127.0.0.1:8003 + +[slgserver] +host = +port = 8001 +need_secret = false + +[chatserver] +host = +port = 8002 +need_secret = false + +[loginserver] +host = +port = 8003 +need_secret = false + + +[xorm] +show_sql = true +log_file = ../logs/sql.log + +[log] +file_dir = ../logs/ +max_size = 120 +max_backups = 100 +max_age = 10 +compress = true + +[logic] +map_data = data/conf/mapRes_0.json +json_data = data/conf/json/ +server_id = 1 \ No newline at end of file diff --git a/data/conf/json/basic.json b/data/conf/json/basic.json new file mode 100644 index 0000000..42b54b9 --- /dev/null +++ b/data/conf/json/basic.json @@ -0,0 +1,96 @@ +{ + "conscript": { + "des": "每征一个兵需要消耗的资源", + "cost_wood":10, + "cost_iron":10, + "cost_stone":0, + "cost_grain":10, + "cost_gold":1, + "cost_time":1 + }, + "general": { + "des": "武将的一些配置", + "physical_power_limit": 100, + "cost_physical_power": 1, + "recovery_physical_power": 10, + "reclamation_time": 30, + "reclamation_cost": 1, + "draw_general_cost": 30, + "pr_point": 1000, + "limit": 500 + }, + "role": { + "des": "角色的一些配置", + "wood": 1000000, + "iron": 1000000, + "stone": 1000000, + "grain": 1000000, + "gold": 1000000, + "decree": 20, + "wood_yield": 1000000, + "iron_yield": 1000000, + "stone_yield": 1000000, + "grain_yield": 1000000, + "gold_yield": 1000000, + "depot_capacity": 100000000000, + "build_limit": 20, + "recovery_time": 20, + "decree_limit": 20, + "collect_times_limit": 3, + "collect_interval": 30, + "pos_tag_limit": 10 + }, + "city": { + "des": "城池的一些配置", + "cost": 75, + "durable": 100000, + "transform_rate": 50, + "recovery_time": 600 + }, + "build": { + "des": "建筑的一些配置", + "war_free": 20, + "giveUp_time": 30, + "fortress_limit": 10 + }, + "npc": { + "des": "npc一些配置", + "levels": [ + { + "soilders": 100 + }, + { + "soilders": 200 + }, + { + "soilders": 300 + }, + { + "soilders": 400 + }, + { + "soilders": 500 + }, + { + "soilders": 600 + }, + { + "soilders": 700 + }, + { + "soilders": 800 + }, + { + "soilders": 900 + }, + { + "soilders": 1000 + } + ] + }, + "union": { + "des": "联盟的一些配置", + "member_limit": 100 + } + +} \ No newline at end of file diff --git a/data/conf/json/facility/facility.json b/data/conf/json/facility/facility.json new file mode 100644 index 0000000..ebb2ea1 --- /dev/null +++ b/data/conf/json/facility/facility.json @@ -0,0 +1,109 @@ +{ + "title": "城内设施类型", + "list": [ + { + "type": 0, + "name": "主城" + }, + { + "type": 1, + "name": "疾风营" + }, + { + "type": 2, + "name": "铁壁营" + }, + { + "type": 3, + "name": "军机营" + }, + { + "type": 4, + "name": "尚武营" + }, + { + "type": 5, + "name": "军营" + }, + { + "type": 6, + "name": "预备役所" + }, + { + "type": 7, + "name": "汉点将台" + }, + { + "type": 8, + "name": "魏点将台" + }, + { + "type": 9, + "name": "蜀点将台" + }, + { + "type": 10, + "name": "吴点将台" + }, + { + "type": 11, + "name": "群点将台" + }, + { + "type": 12, + "name": "封禅台" + }, + { + "type": 13, + "name": "校场" + }, + { + "type": 14, + "name": "统帅厅" + }, + { + "type": 15, + "name": "集市" + }, + { + "type": 16, + "name": "募兵所" + }, + { + "type": 17, + "name": "伐木场" + }, + { + "type": 18, + "name": "炼铁场" + }, + { + "type": 19, + "name": "磨坊" + }, + { + "type": 20, + "name": "采石场" + }, + { + "type": 21, + "name": "民居" + }, + { + "type": 22, + "name": "社稷坛" + }, + { + "type": 23, + "name": "城墙" + }, + { + "type": 24, + "name": "女墙" + }, + { + "type": 25, + "name": "仓库" + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_addition.json b/data/conf/json/facility/facility_addition.json new file mode 100644 index 0000000..6e1a208 --- /dev/null +++ b/data/conf/json/facility/facility_addition.json @@ -0,0 +1,131 @@ +{ + "title": "城池设施加成类别", + "list": [ + { + "type": 1, + "des": "耐久度上限", + "value": "+%n%" + }, + { + "type": 2, + "des": "部队统帅上限", + "value": "+%n%" + }, + { + "type": 3, + "des": "可配置队伍数", + "value": "%n%" + }, + { + "type": 4, + "des": "部队速度", + "value": "+%n%" + }, + { + "type": 5, + "des": "部队防御", + "value": "+%n%" + }, + { + "type": 6, + "des": "部队谋略", + "value": "+%n%" + }, + { + "type": 7, + "des": "部队攻击", + "value": "+%n%" + }, + { + "type": 8, + "des": "征兵时间", + "value": "-%n%%" + }, + { + "type": 9, + "des": "预备役上限", + "value": "+%n%" + }, + { + "type": 10, + "des": "金币", + "value": "-%n%%" + }, + { + "type": 11, + "des": "汉阵营加成", + "value": "+%n%" + }, + { + "type": 12, + "des": "群阵营加成", + "value": "+%n%" + }, + { + "type": 13, + "des": "魏阵营加成", + "value": "+%n%" + }, + { + "type": 14, + "des": "蜀阵营加成", + "value": "+%n%" + }, + { + "type": 15, + "des": "吴阵营加成", + "value": "+%n%" + }, + + { + "type": 16, + "des": "交易兑换率", + "value": "+%n%%" + }, + { + "type": 17, + "des": "木材产量", + "value": "+%n%/小时" + }, + { + "type": 18, + "des": "铁矿产量", + "value": "+%n%/小时" + }, + { + "type": 19, + "des": "粮食产量", + "value": "+%n%/小时" + }, + { + "type": 20, + "des": "石矿产量", + "value": "+%n%/小时" + }, + { + "type": 21, + "des": "税收", + "value": "+%n%" + }, + { + "type": 22, + "des": "扩建次数", + "value": "+%n%" + }, + { + "type": 23, + "des": "仓库容量", + "value": "+%n%" + }, + { + "type": 24, + "des": "带兵数量", + "value": "+%n%" + }, + { + "type": 25, + "des": "可配置前锋部队数量", + "value": "%n%" + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_army_jfy.json b/data/conf/json/facility/facility_army_jfy.json new file mode 100644 index 0000000..b4d5360 --- /dev/null +++ b/data/conf/json/facility/facility_army_jfy.json @@ -0,0 +1,87 @@ +{ + "title": "城内设施-疾风营配置表", + "name": "疾风营", + "type": 1, + "des": "提高本城部队速度", + "additions": [ + 4 + ], + "conditions": [ + { + "type": 0, + "level": 2 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_army_jjy.json b/data/conf/json/facility/facility_army_jjy.json new file mode 100644 index 0000000..82be1fa --- /dev/null +++ b/data/conf/json/facility/facility_army_jjy.json @@ -0,0 +1,87 @@ +{ + "title": "城内设施-军机营配置表", + "name": "军机营", + "type": 3, + "des": "提高本城部队谋略", + "additions": [ + 6 + ], + "conditions": [ + { + "type": 0, + "level": 3 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_army_swy.json b/data/conf/json/facility/facility_army_swy.json new file mode 100644 index 0000000..d22b37e --- /dev/null +++ b/data/conf/json/facility/facility_army_swy.json @@ -0,0 +1,87 @@ +{ + "title": "城内设施-尚武营配置表", + "name": "尚武营", + "type": 4, + "des": "提高本城部队攻击", + "additions": [ + 7 + ], + "conditions": [ + { + "type": 0, + "level": 3 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_army_tby.json b/data/conf/json/facility/facility_army_tby.json new file mode 100644 index 0000000..7e5800e --- /dev/null +++ b/data/conf/json/facility/facility_army_tby.json @@ -0,0 +1,87 @@ +{ + "title": "城内设施-铁壁营配置表", + "name": "铁壁营", + "type": 2, + "des": "提高本城部队防御", + "additions": [ + 5 + ], + "conditions": [ + { + "type": 0, + "level": 2 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_barrack_by.json b/data/conf/json/facility/facility_barrack_by.json new file mode 100644 index 0000000..e7b9f9e --- /dev/null +++ b/data/conf/json/facility/facility_barrack_by.json @@ -0,0 +1,87 @@ +{ + "title": "城内设施-兵营配置表", + "name": "兵营", + "type": 5, + "des": "提高本城部队武将带兵数量", + "additions": [ + 24 + ], + "conditions": [ + { + "type": 0, + "level": 7 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 100 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 200 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 300 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 400 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 500 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_barrack_yby.json b/data/conf/json/facility/facility_barrack_yby.json new file mode 100644 index 0000000..b3bf81d --- /dev/null +++ b/data/conf/json/facility/facility_barrack_yby.json @@ -0,0 +1,91 @@ +{ + "title": "城内设施-预备役配置表", + "name": "预备役所", + "type": 6, + "des": "提高本城预备役上限", + "additions": [ + 9 + ], + "conditions": [ + { + "type": 0, + "level": 6 + }, + { + "type": 13, + "level": 2 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 1000 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 2000 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 3000 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 4000 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 5000 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_camp_han.json b/data/conf/json/facility/facility_camp_han.json new file mode 100644 index 0000000..65c1ae1 --- /dev/null +++ b/data/conf/json/facility/facility_camp_han.json @@ -0,0 +1,87 @@ +{ + "title": "城内设施-汉点将台配置表", + "name": "汉点将台", + "type": 7, + "des": "提高汉阵营加成效果", + "additions": [ + 11 + ], + "conditions": [ + { + "type": 0, + "level": 4 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 10 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_camp_qun.json b/data/conf/json/facility/facility_camp_qun.json new file mode 100644 index 0000000..5e9a1b5 --- /dev/null +++ b/data/conf/json/facility/facility_camp_qun.json @@ -0,0 +1,99 @@ +{ + "title": "城内设施-群点将台配置表", + "name": "群点将台", + "type": 11, + "des": "提高群阵营加成效果", + "additions": [ + 12 + ], + "conditions": [ + { + "type": 0, + "level": 6 + }, + { + "type": 8, + "level": 1 + }, + { + "type": 9, + "level": 1 + }, + { + "type": 10, + "level": 1 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_camp_shu.json b/data/conf/json/facility/facility_camp_shu.json new file mode 100644 index 0000000..2e49cbe --- /dev/null +++ b/data/conf/json/facility/facility_camp_shu.json @@ -0,0 +1,91 @@ +{ + "title": "城内设施-蜀点将台配置表", + "name": "蜀点将台", + "type": 9, + "des": "提高蜀阵营加成效果", + "additions": [ + 14 + ], + "conditions": [ + { + "type": 0, + "level": 5 + }, + { + "type": 7, + "level": 1 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_camp_wei.json b/data/conf/json/facility/facility_camp_wei.json new file mode 100644 index 0000000..a0d06fb --- /dev/null +++ b/data/conf/json/facility/facility_camp_wei.json @@ -0,0 +1,91 @@ +{ + "title": "城内设施-魏点将台配置表", + "name": "魏点将台", + "type": 8, + "des": "提高魏阵营加成效果", + "additions": [ + 13 + ], + "conditions": [ + { + "type": 0, + "level": 5 + }, + { + "type": 7, + "level": 1 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_camp_wu.json b/data/conf/json/facility/facility_camp_wu.json new file mode 100644 index 0000000..6ace530 --- /dev/null +++ b/data/conf/json/facility/facility_camp_wu.json @@ -0,0 +1,91 @@ +{ + "title": "城内设施-吴点将台配置表", + "name": "吴点将台", + "type": 10, + "des": "提高吴阵营加成效果", + "additions": [ + 15 + ], + "conditions": [ + { + "type": 0, + "level": 5 + }, + { + "type": 7, + "level": 1 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_city.json b/data/conf/json/facility/facility_city.json new file mode 100644 index 0000000..0e2afd3 --- /dev/null +++ b/data/conf/json/facility/facility_city.json @@ -0,0 +1,163 @@ +{ + "title": "主城配置", + "name": "主城", + "type": 0, + "des": "提高本城的耐久上限部队统帅上限", + "additions": [ + 1, + 2 + ], + "conditions": [], + "levels": [ + { + "level": 1, + "values": [ + 10000, + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 20000, + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 30000, + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 40000, + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 50000, + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + }, + { + "level": 6, + "values": [ + 60000, + 30 + ], + "need": { + "decree": 0, + "grain": 6000, + "wood": 6000, + "iron": 6000, + "stone": 6000 + }, + "time": 60 + }, + { + "level": 7, + "values": [ + 70000, + 35 + ], + "need": { + "decree": 0, + "grain": 7000, + "wood": 7000, + "iron": 7000, + "stone": 7000 + }, + "time": 70 + }, + { + "level": 8, + "values": [ + 80000, + 40 + ], + "need": { + "decree": 0, + "grain": 8000, + "wood": 8000, + "iron": 8000, + "stone": 8000 + }, + "time": 80 + }, + { + "level": 9, + "values": [ + 90000, + 45 + ], + "need": { + "decree": 0, + "grain": 9000, + "wood": 9000, + "iron": 9000, + "stone": 9000 + }, + "time": 90 + }, + { + "level": 10, + "values": [ + 100000, + 50 + ], + "need": { + "decree": 0, + "grain": 10000, + "wood": 10000, + "iron": 10000, + "stone": 10000 + }, + "time": 100 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_fct.json b/data/conf/json/facility/facility_fct.json new file mode 100644 index 0000000..bf9f7f4 --- /dev/null +++ b/data/conf/json/facility/facility_fct.json @@ -0,0 +1,91 @@ +{ + "title": "城内设施-封禅台配置", + "name": "封禅台", + "type": 12, + "des": "提高本城部队的统帅上限", + "additions": [ + 2 + ], + "conditions": [ + { + "type": 0, + "level": 8 + }, + { + "type": 5, + "level": 5 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_general_jc.json b/data/conf/json/facility/facility_general_jc.json new file mode 100644 index 0000000..4bf0270 --- /dev/null +++ b/data/conf/json/facility/facility_general_jc.json @@ -0,0 +1,87 @@ +{ + "title": "城内设施-校场配置表", + "name": "校场", + "type": 13, + "des": "使本城可以配置部队,并提高本城可配置部队数量", + "additions": [ + 3 + ], + "conditions": [ + { + "type": 0, + "level": 1 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 1 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 2 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 3 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 4 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_general_tst.json b/data/conf/json/facility/facility_general_tst.json new file mode 100644 index 0000000..24a28c2 --- /dev/null +++ b/data/conf/json/facility/facility_general_tst.json @@ -0,0 +1,87 @@ +{ + "title": "城内设施-统帅厅配置表", + "name": "统帅厅", + "type": 14, + "des": "使本城可以配置前锋,并提高本城可配置前锋部队数量", + "additions": [ + 25 + ], + "conditions": [ + { + "type": 16, + "level": 1 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 1 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 2 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 3 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 4 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_market.json b/data/conf/json/facility/facility_market.json new file mode 100644 index 0000000..1422365 --- /dev/null +++ b/data/conf/json/facility/facility_market.json @@ -0,0 +1,157 @@ +{ + "title": "城内设施-集市配置表", + "des": "提高交易兑换率", + "name": "集市", + "type": 15, + "additions": [ + 16 + ], + "conditions": [ + { + "type": 0, + "level": 5 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + }, + { + "level": 6, + "values": [ + 30 + ], + "need": { + "decree": 0, + "grain": 6000, + "wood": 6000, + "iron": 6000, + "stone": 6000 + }, + "time": 60 + }, + { + "level": 7, + "values": [ + 35 + ], + "need": { + "decree": 0, + "grain": 7000, + "wood": 7000, + "iron": 7000, + "stone": 7000 + }, + "time": 70 + }, + { + "level": 8, + "values": [ + 40 + ], + "need": { + "decree": 0, + "grain": 8000, + "wood": 8000, + "iron": 8000, + "stone": 8000 + }, + "time": 80 + }, + { + "level": 9, + "values": [ + 45 + ], + "need": { + "decree": 0, + "grain": 9000, + "wood": 9000, + "iron": 9000, + "stone": 9000 + }, + "time": 90 + }, + { + "level": 10, + "values": [ + 50 + ], + "need": { + "decree": 0, + "grain": 10000, + "wood": 10000, + "iron": 10000, + "stone": 10000 + }, + "time": 100 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_mbs.json b/data/conf/json/facility/facility_mbs.json new file mode 100644 index 0000000..dbda0e3 --- /dev/null +++ b/data/conf/json/facility/facility_mbs.json @@ -0,0 +1,160 @@ +{ + "title": "募兵所配置表", + "des": "开启本城部队征兵,并缩短征兵时间", + "name": "募兵所", + "type": 16, + "additions": [ + 10 + ], + "conditions": [ + { + "type": 0, + "level": 2 + }, + { + "type": 13, + "level": 2 + } + ], + "levels": [{ + "level": 1, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 10 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 15 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 20 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 25 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + }, + { + "level": 6, + "values": [ + 30 + ], + "need": { + "decree": 0, + "grain": 6000, + "wood": 6000, + "iron": 6000, + "stone": 6000 + }, + "time": 60 + }, + { + "level": 7, + "values": [ + 35 + ], + "need": { + "decree": 0, + "grain": 7000, + "wood": 7000, + "iron": 7000, + "stone": 7000 + }, + "time": 70 + }, + { + "level": 8, + "values": [ + 40 + ], + "need": { + "decree": 0, + "grain": 8000, + "wood": 8000, + "iron": 8000, + "stone": 8000 + }, + "time": 80 + }, + { + "level": 9, + "values": [ + 45 + ], + "need": { + "decree": 0, + "grain": 9000, + "wood": 9000, + "iron": 9000, + "stone": 9000 + }, + "time": 90 + }, + { + "level": 10, + "values": [ + 50 + ], + "need": { + "decree": 0, + "grain": 10000, + "wood": 10000, + "iron": 10000, + "stone": 10000 + }, + "time": 100 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_produce_csc.json b/data/conf/json/facility/facility_produce_csc.json new file mode 100644 index 0000000..5f6d0d8 --- /dev/null +++ b/data/conf/json/facility/facility_produce_csc.json @@ -0,0 +1,157 @@ +{ + "title": "城内设施-采石场配置表", + "name": "采石场", + "des": "额外获得石矿产量", + "type": 20, + "additions": [ + 20 + ], + "conditions": [ + { + "type": 0, + "level": 3 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 1000 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 2000 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 3000 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 4000 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 5000 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + }, + { + "level": 6, + "values": [ + 6000 + ], + "need": { + "decree": 0, + "grain": 6000, + "wood": 6000, + "iron": 6000, + "stone": 6000 + }, + "time": 60 + }, + { + "level": 7, + "values": [ + 7000 + ], + "need": { + "decree": 0, + "grain": 7000, + "wood": 7000, + "iron": 7000, + "stone": 7000 + }, + "time": 70 + }, + { + "level": 8, + "values": [ + 8000 + ], + "need": { + "decree": 0, + "grain": 8000, + "wood": 8000, + "iron": 8000, + "stone": 8000 + }, + "time": 80 + }, + { + "level": 9, + "values": [ + 9000 + ], + "need": { + "decree": 0, + "grain": 9000, + "wood": 9000, + "iron": 9000, + "stone": 9000 + }, + "time": 90 + }, + { + "level": 10, + "values": [ + 10000 + ], + "need": { + "decree": 0, + "grain": 10000, + "wood": 10000, + "iron": 10000, + "stone": 10000 + }, + "time": 100 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_produce_fmc.json b/data/conf/json/facility/facility_produce_fmc.json new file mode 100644 index 0000000..d21f596 --- /dev/null +++ b/data/conf/json/facility/facility_produce_fmc.json @@ -0,0 +1,157 @@ +{ + "title": "城内设施-伐木场配置表", + "name": "伐木场", + "des": "额外获得木材产量", + "type": 17, + "additions": [ + 17 + ], + "conditions": [ + { + "type": 0, + "level": 2 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 1000 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 2000 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 3000 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 4000 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 5000 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + }, + { + "level": 6, + "values": [ + 6000 + ], + "need": { + "decree": 0, + "grain": 6000, + "wood": 6000, + "iron": 6000, + "stone": 6000 + }, + "time": 60 + }, + { + "level": 7, + "values": [ + 7000 + ], + "need": { + "decree": 0, + "grain": 7000, + "wood": 7000, + "iron": 7000, + "stone": 7000 + }, + "time": 70 + }, + { + "level": 8, + "values": [ + 8000 + ], + "need": { + "decree": 0, + "grain": 8000, + "wood": 8000, + "iron": 8000, + "stone": 8000 + }, + "time": 80 + }, + { + "level": 9, + "values": [ + 9000 + ], + "need": { + "decree": 0, + "grain": 9000, + "wood": 9000, + "iron": 9000, + "stone": 9000 + }, + "time": 90 + }, + { + "level": 10, + "values": [ + 10000 + ], + "need": { + "decree": 0, + "grain": 10000, + "wood": 10000, + "iron": 10000, + "stone": 10000 + }, + "time": 100 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_produce_ltc.json b/data/conf/json/facility/facility_produce_ltc.json new file mode 100644 index 0000000..dbef25f --- /dev/null +++ b/data/conf/json/facility/facility_produce_ltc.json @@ -0,0 +1,157 @@ +{ + "title": "城内设施-炼铁场配置表", + "name": "炼铁场", + "des": "额外获得铁矿产量", + "type": 18, + "additions": [ + 18 + ], + "conditions": [ + { + "type": 0, + "level": 2 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 1000 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 2000 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 3000 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 4000 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 5000 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + }, + { + "level": 6, + "values": [ + 6000 + ], + "need": { + "decree": 0, + "grain": 6000, + "wood": 6000, + "iron": 6000, + "stone": 6000 + }, + "time": 60 + }, + { + "level": 7, + "values": [ + 7000 + ], + "need": { + "decree": 0, + "grain": 7000, + "wood": 7000, + "iron": 7000, + "stone": 7000 + }, + "time": 70 + }, + { + "level": 8, + "values": [ + 8000 + ], + "need": { + "decree": 0, + "grain": 8000, + "wood": 8000, + "iron": 8000, + "stone": 8000 + }, + "time": 80 + }, + { + "level": 9, + "values": [ + 9000 + ], + "need": { + "decree": 0, + "grain": 9000, + "wood": 9000, + "iron": 9000, + "stone": 9000 + }, + "time": 90 + }, + { + "level": 10, + "values": [ + 10000 + ], + "need": { + "decree": 0, + "grain": 10000, + "wood": 10000, + "iron": 10000, + "stone": 10000 + }, + "time": 100 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_produce_mf.json b/data/conf/json/facility/facility_produce_mf.json new file mode 100644 index 0000000..1e01501 --- /dev/null +++ b/data/conf/json/facility/facility_produce_mf.json @@ -0,0 +1,157 @@ +{ + "title": "城内设施-磨坊配置表", + "name": "磨坊", + "des": "额外获得粮食产量", + "type": 19, + "additions": [ + 19 + ], + "conditions": [ + { + "type": 0, + "level": 3 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 1000 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 2000 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 3000 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 4000 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 5000 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + }, + { + "level": 6, + "values": [ + 6000 + ], + "need": { + "decree": 0, + "grain": 6000, + "wood": 6000, + "iron": 6000, + "stone": 6000 + }, + "time": 60 + }, + { + "level": 7, + "values": [ + 7000 + ], + "need": { + "decree": 0, + "grain": 7000, + "wood": 7000, + "iron": 7000, + "stone": 7000 + }, + "time": 70 + }, + { + "level": 8, + "values": [ + 8000 + ], + "need": { + "decree": 0, + "grain": 8000, + "wood": 8000, + "iron": 8000, + "stone": 8000 + }, + "time": 80 + }, + { + "level": 9, + "values": [ + 9000 + ], + "need": { + "decree": 0, + "grain": 9000, + "wood": 9000, + "iron": 9000, + "stone": 9000 + }, + "time": 90 + }, + { + "level": 10, + "values": [ + 10000 + ], + "need": { + "decree": 0, + "grain": 10000, + "wood": 10000, + "iron": 10000, + "stone": 10000 + }, + "time": 100 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_produce_mj.json b/data/conf/json/facility/facility_produce_mj.json new file mode 100644 index 0000000..7ae2ed6 --- /dev/null +++ b/data/conf/json/facility/facility_produce_mj.json @@ -0,0 +1,157 @@ +{ + "title": "城内设施-民居配置表", + "name": "民居", + "des": "提供税收", + "type": 21, + "additions": [ + 21 + ], + "conditions": [ + { + "type": 0, + "level": 1 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 1000 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 2000 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 3000 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 4000 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 5000 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + }, + { + "level": 6, + "values": [ + 6000 + ], + "need": { + "decree": 0, + "grain": 6000, + "wood": 6000, + "iron": 6000, + "stone": 6000 + }, + "time": 60 + }, + { + "level": 7, + "values": [ + 7000 + ], + "need": { + "decree": 0, + "grain": 7000, + "wood": 7000, + "iron": 7000, + "stone": 7000 + }, + "time": 70 + }, + { + "level": 8, + "values": [ + 8000 + ], + "need": { + "decree": 0, + "grain": 8000, + "wood": 8000, + "iron": 8000, + "stone": 8000 + }, + "time": 80 + }, + { + "level": 9, + "values": [ + 9000 + ], + "need": { + "decree": 0, + "grain": 9000, + "wood": 9000, + "iron": 9000, + "stone": 9000 + }, + "time": 90 + }, + { + "level": 10, + "values": [ + 10000 + ], + "need": { + "decree": 0, + "grain": 10000, + "wood": 10000, + "iron": 10000, + "stone": 10000 + }, + "time": 100 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_sjt.json b/data/conf/json/facility/facility_sjt.json new file mode 100644 index 0000000..1e450f5 --- /dev/null +++ b/data/conf/json/facility/facility_sjt.json @@ -0,0 +1,128 @@ +{ + "title": "城内设施-社稷坛配置", + "name": "社稷坛", + "type": 22, + "des": "每升一级可以额外扩建一次", + "additions": [ + 22 + ], + "conditions": [ + { + "type": 0, + "level": 9 + } + ], + "levels": [{ + "level": 1, + "values": [ + 1 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 2 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 3 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 4 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 5 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + }, + { + "level": 6, + "values": [ + 6 + ], + "need": { + "decree": 0, + "grain": 6000, + "wood": 6000, + "iron": 6000, + "stone": 6000 + }, + "time": 60 + }, + { + "level": 7, + "values": [ + 7 + ], + "need": { + "decree": 0, + "grain": 7000, + "wood": 7000, + "iron": 7000, + "stone": 7000 + }, + "time": 70 + }, + { + "level": 8, + "values": [ + 8 + ], + "need": { + "decree": 0, + "grain": 8000, + "wood": 8000, + "iron": 8000, + "stone": 8000 + }, + "time": 80 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_wall_cq.json b/data/conf/json/facility/facility_wall_cq.json new file mode 100644 index 0000000..e4c65fb --- /dev/null +++ b/data/conf/json/facility/facility_wall_cq.json @@ -0,0 +1,87 @@ +{ + "title": "城内设施-城墙配置", + "name": "城墙", + "type": 23, + "des": "提高本城耐久上限", + "additions": [ + 1 + ], + "conditions": [ + { + "type": 0, + "level": 7 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 10000 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 20000 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 30000 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 40000 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 50000 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_wall_nq.json b/data/conf/json/facility/facility_wall_nq.json new file mode 100644 index 0000000..2f8547a --- /dev/null +++ b/data/conf/json/facility/facility_wall_nq.json @@ -0,0 +1,87 @@ +{ + "title": "城内设施-女墙配置", + "name": "女墙", + "type": 24, + "des": "提高本城耐久上限", + "additions": [ + 1 + ], + "conditions": [ + { + "type": 23, + "level": 1 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 10000 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 20000 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 30000 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 40000 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 50000 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/facility/facility_warehouse.json b/data/conf/json/facility/facility_warehouse.json new file mode 100644 index 0000000..7a92800 --- /dev/null +++ b/data/conf/json/facility/facility_warehouse.json @@ -0,0 +1,129 @@ +{ + "title": "城内设施-仓库配置", + "name": "仓库", + "type": 25, + "des": "每升一级增加仓库容量", + "additions": [ + 23 + ], + "conditions": [ + { + "type": 0, + "level": 2 + } + ], + "levels": [ + { + "level": 1, + "values": [ + 10000 + ], + "need": { + "decree": 0, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "time": 10 + }, + { + "level": 2, + "values": [ + 20000 + ], + "need": { + "decree": 0, + "grain": 2000, + "wood": 2000, + "iron": 2000, + "stone": 2000 + }, + "time": 20 + }, + { + "level": 3, + "values": [ + 30000 + ], + "need": { + "decree": 0, + "grain": 3000, + "wood": 3000, + "iron": 3000, + "stone": 3000 + }, + "time": 30 + }, + { + "level": 4, + "values": [ + 40000 + ], + "need": { + "decree": 0, + "grain": 4000, + "wood": 4000, + "iron": 4000, + "stone": 4000 + }, + "time": 40 + }, + { + "level": 5, + "values": [ + 50000 + ], + "need": { + "decree": 0, + "grain": 5000, + "wood": 5000, + "iron": 5000, + "stone": 5000 + }, + "time": 50 + }, + { + "level": 6, + "values": [ + 60000 + ], + "need": { + "decree": 0, + "grain": 6000, + "wood": 6000, + "iron": 6000, + "stone": 6000 + }, + "time": 60 + }, + { + "level": 7, + "values": [ + 70000 + ], + "need": { + "decree": 0, + "grain": 7000, + "wood": 7000, + "iron": 7000, + "stone": 7000 + }, + "time": 70 + }, + { + "level": 8, + "values": [ + 80000 + ], + "need": { + "decree": 0, + "grain": 8000, + "wood": 8000, + "iron": 8000, + "stone": 8000 + }, + "time": 80 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/general/general.json b/data/conf/json/general/general.json new file mode 100644 index 0000000..1401cc3 --- /dev/null +++ b/data/conf/json/general/general.json @@ -0,0 +1,9205 @@ +{ + "title": "武将配置", + "list": [ + { + "name": "十常士", + "cfgId": 100002, + "force": 8400, + "strategy": 8500, + "defense": 9000, + "speed": 6200, + "destroy": 2100, + "cost": 30, + "force_grow": 30, + "strategy_grow": 40, + "defense_grow": 40, + "speed_grow": 20, + "destroy_grow": 40, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 7, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 1 + }, + { + "name": "吕布", + "cfgId": 100003, + "force": 9600, + "strategy": 5500, + "defense": 9700, + "speed": 9000, + "destroy": 1800, + "cost": 30, + "force_grow": 80, + "strategy_grow": 20, + "defense_grow": 50, + "speed_grow": 80, + "destroy_grow": 50, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 12, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "蔡文姬", + "cfgId": 100004, + "force": 8500, + "strategy": 8500, + "defense": 8100, + "speed": 8300, + "destroy": 2000, + "cost": 25, + "force_grow": 80, + "strategy_grow": 60, + "defense_grow": 55.00000000000001, + "speed_grow": 78, + "destroy_grow": 55.00000000000001, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 21, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "貂蝉", + "cfgId": 100005, + "force": 8800, + "strategy": 8400, + "defense": 8900, + "speed": 8300, + "destroy": 2000, + "cost": 30, + "force_grow": 65, + "strategy_grow": 75, + "defense_grow": 80, + "speed_grow": 67, + "destroy_grow": 80, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "袁绍", + "cfgId": 100006, + "force": 8100, + "strategy": 5000, + "defense": 7900, + "speed": 4300, + "destroy": 7000, + "cost": 30, + "force_grow": 30, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 20, + "destroy_grow": 50, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 24, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "卢植", + "cfgId": 100007, + "force": 8900, + "strategy": 8000, + "defense": 9000, + "speed": 8600, + "destroy": 1600, + "cost": 35, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 76, + "destroy_grow": 50, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 5, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "张角", + "cfgId": 100008, + "force": 9100, + "strategy": 9200, + "defense": 8900, + "speed": 9000, + "destroy": 1300, + "cost": 35, + "force_grow": 80, + "strategy_grow": 88, + "defense_grow": 84, + "speed_grow": 83, + "destroy_grow": 84, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 10, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "董卓", + "cfgId": 100009, + "force": 8800, + "strategy": 7300, + "defense": 8600, + "speed": 8900, + "destroy": 1300, + "cost": 50, + "force_grow": 80, + "strategy_grow": 55.00000000000001, + "defense_grow": 89, + "speed_grow": 87, + "destroy_grow": 89, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 18, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "吕布", + "cfgId": 100010, + "force": 10000, + "strategy": 8000, + "defense": 10000, + "speed": 9000, + "destroy": 1800, + "cost": 35, + "force_grow": 100, + "strategy_grow": 50, + "defense_grow": 80, + "speed_grow": 80, + "destroy_grow": 80, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 10, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "贾诩", + "cfgId": 100011, + "force": 8800, + "strategy": 9500, + "defense": 9100, + "speed": 6900, + "destroy": 2000, + "cost": 35, + "force_grow": 50, + "strategy_grow": 90, + "defense_grow": 80, + "speed_grow": 35, + "destroy_grow": 80, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 15, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "马超", + "cfgId": 100013, + "force": 9600, + "strategy": 6500, + "defense": 9700, + "speed": 9200, + "destroy": 1800, + "cost": 35, + "force_grow": 89, + "strategy_grow": 60, + "defense_grow": 91, + "speed_grow": 89, + "destroy_grow": 91, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 10, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "甄洛", + "cfgId": 100015, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55.00000000000001, + "destroy_grow": 50, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 20, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "刘备", + "cfgId": 100016, + "force": 8700, + "strategy": 9000, + "defense": 8500, + "speed": 4800, + "destroy": 4000, + "cost": 35, + "force_grow": 80, + "strategy_grow": 89, + "defense_grow": 82, + "speed_grow": 22, + "destroy_grow": 82, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "诸葛亮", + "cfgId": 100017, + "force": 7500, + "strategy": 10000, + "defense": 9200, + "speed": 3500, + "destroy": 5500, + "cost": 35, + "force_grow": 68, + "strategy_grow": 95, + "defense_grow": 90, + "speed_grow": 30, + "destroy_grow": 90, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "马云禄", + "cfgId": 100019, + "force": 9200, + "strategy": 7500, + "defense": 9000, + "speed": 9100, + "destroy": 2200, + "cost": 25, + "force_grow": 90, + "strategy_grow": 50, + "defense_grow": 80, + "speed_grow": 80, + "destroy_grow": 80, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 11, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "黄月英", + "cfgId": 100020, + "force": 7800, + "strategy": 9200, + "defense": 8900, + "speed": 4300, + "destroy": 4500, + "cost": 30, + "force_grow": 45, + "strategy_grow": 85, + "defense_grow": 95, + "speed_grow": 20, + "destroy_grow": 95, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 13, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "赵云", + "cfgId": 100021, + "force": 9500, + "strategy": 8200, + "defense": 9200, + "speed": 5100, + "destroy": 4200, + "cost": 30, + "force_grow": 90, + "strategy_grow": 80, + "defense_grow": 90, + "speed_grow": 40, + "destroy_grow": 90, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 11, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "张飞", + "cfgId": 100022, + "force": 9500, + "strategy": 7500, + "defense": 9900, + "speed": 8800, + "destroy": 1300, + "cost": 40, + "force_grow": 91, + "strategy_grow": 68, + "defense_grow": 88, + "speed_grow": 60, + "destroy_grow": 88, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 21, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "曹操", + "cfgId": 100023, + "force": 8300, + "strategy": 9900, + "defense": 9200, + "speed": 8800, + "destroy": 1200, + "cost": 4, + "force_grow": 80, + "strategy_grow": 92, + "defense_grow": 89, + "speed_grow": 78, + "destroy_grow": 89, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 10, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "荀彧", + "cfgId": 100024, + "force": 8900, + "strategy": 9500, + "defense": 9000, + "speed": 9100, + "destroy": 2100, + "cost": 25, + "force_grow": 80, + "strategy_grow": 92, + "defense_grow": 95, + "speed_grow": 75, + "destroy_grow": 95, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "曹丕", + "cfgId": 100025, + "force": 8100, + "strategy": 8900, + "defense": 9000, + "speed": 5200, + "destroy": 2500, + "cost": 30, + "force_grow": 70, + "strategy_grow": 79, + "defense_grow": 81, + "speed_grow": 45, + "destroy_grow": 81, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 7, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "关羽", + "cfgId": 100026, + "force": 9500, + "strategy": 8100, + "defense": 9000, + "speed": 8800, + "destroy": 1500, + "cost": 35, + "force_grow": 89, + "strategy_grow": 78, + "defense_grow": 92, + "speed_grow": 78, + "destroy_grow": 92, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 7, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "张辽", + "cfgId": 100027, + "force": 9900, + "strategy": 8500, + "defense": 9700, + "speed": 9100, + "destroy": 1600, + "cost": 40, + "force_grow": 98, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 97, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 10, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "王异", + "cfgId": 100028, + "force": 8100, + "strategy": 8700, + "defense": 8300, + "speed": 6200, + "destroy": 2100, + "cost": 25, + "force_grow": 84, + "strategy_grow": 86, + "defense_grow": 81, + "speed_grow": 51, + "destroy_grow": 81, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 24, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "张春华", + "cfgId": 100029, + "force": 8300, + "strategy": 9100, + "defense": 8700, + "speed": 6800, + "destroy": 2200, + "cost": 25, + "force_grow": 70, + "strategy_grow": 89, + "defense_grow": 81, + "speed_grow": 61, + "destroy_grow": 81, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 6, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "孙权", + "cfgId": 100030, + "force": 8100, + "strategy": 9300, + "defense": 9500, + "speed": 6900, + "destroy": 3100, + "cost": 40, + "force_grow": 65, + "strategy_grow": 88, + "defense_grow": 91, + "speed_grow": 63, + "destroy_grow": 91, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 5, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "周瑜", + "cfgId": 100031, + "force": 8400, + "strategy": 9600, + "defense": 9400, + "speed": 6700, + "destroy": 2800, + "cost": 35, + "force_grow": 72, + "strategy_grow": 89, + "defense_grow": 92, + "speed_grow": 66, + "destroy_grow": 92, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 11, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "周姬", + "cfgId": 100032, + "force": 8100, + "strategy": 8800, + "defense": 8900, + "speed": 6400, + "destroy": 2900, + "cost": 25, + "force_grow": 68, + "strategy_grow": 80, + "defense_grow": 87, + "speed_grow": 61, + "destroy_grow": 87, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 8, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "孙坚", + "cfgId": 100033, + "force": 9200, + "strategy": 7600, + "defense": 8700, + "speed": 3500, + "destroy": 3800, + "cost": 30, + "force_grow": 90, + "strategy_grow": 59, + "defense_grow": 87, + "speed_grow": 12, + "destroy_grow": 87, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 5, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 5 + }, + { + "name": "甘宁", + "cfgId": 100034, + "force": 9000, + "strategy": 7600, + "defense": 9200, + "speed": 7000, + "destroy": 3500, + "cost": 30, + "force_grow": 89, + "strategy_grow": 71, + "defense_grow": 92, + "speed_grow": 66, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 19, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "吕蒙", + "cfgId": 100035, + "force": 8300, + "strategy": 9400, + "defense": 9000, + "speed": 6900, + "destroy": 3200, + "cost": 35, + "force_grow": 77, + "strategy_grow": 89, + "defense_grow": 92, + "speed_grow": 66, + "destroy_grow": 24, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 18, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "孙尚香", + "cfgId": 100036, + "force": 8100, + "strategy": 8600, + "defense": 8400, + "speed": 6700, + "destroy": 2800, + "cost": 25, + "force_grow": 72, + "strategy_grow": 79, + "defense_grow": 82, + "speed_grow": 66, + "destroy_grow": 24, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 21, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "何太后", + "cfgId": 100037, + "force": 8100, + "strategy": 8200, + "defense": 9100, + "speed": 6500, + "destroy": 2900, + "cost": 25, + "force_grow": 72, + "strategy_grow": 78, + "defense_grow": 82, + "speed_grow": 69, + "destroy_grow": 28, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 1 + }, + { + "name": "关银屏", + "cfgId": 100072, + "force": 9100, + "strategy": 8100, + "defense": 8900, + "speed": 9200, + "destroy": 1500, + "cost": 35, + "force_grow": 86, + "strategy_grow": 80, + "defense_grow": 86, + "speed_grow": 90, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 10, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "姜维", + "cfgId": 100074, + "force": 9000, + "strategy": 8800, + "defense": 9500, + "speed": 8700, + "destroy": 1300, + "cost": 30, + "force_grow": 86, + "strategy_grow": 87, + "defense_grow": 89, + "speed_grow": 88, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 17, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "许褚", + "cfgId": 100080, + "force": 9100, + "strategy": 4800, + "defense": 9200, + "speed": 3500, + "destroy": 3800, + "cost": 30, + "force_grow": 82, + "strategy_grow": 66, + "defense_grow": 87, + "speed_grow": 41, + "destroy_grow": 25, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 19, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "张郃", + "cfgId": 100083, + "force": 9200, + "strategy": 6500, + "defense": 9000, + "speed": 4800, + "destroy": 3500, + "cost": 30, + "force_grow": 87, + "strategy_grow": 73, + "defense_grow": 90, + "speed_grow": 51, + "destroy_grow": 29, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 24, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "太史慈", + "cfgId": 100090, + "force": 8900, + "strategy": 7300, + "defense": 8800, + "speed": 6900, + "destroy": 1700, + "cost": 30, + "force_grow": 85, + "strategy_grow": 59, + "defense_grow": 91, + "speed_grow": 53, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "灵帝", + "cfgId": 100101, + "force": 8700, + "strategy": 9100, + "defense": 9100, + "speed": 6900, + "destroy": 3500, + "cost": 35, + "force_grow": 85, + "strategy_grow": 90, + "defense_grow": 91, + "speed_grow": 59, + "destroy_grow": 29, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 20, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "邓艾", + "cfgId": 100310, + "force": 9100, + "strategy": 8900, + "defense": 8100, + "speed": 4100, + "destroy": 3900, + "cost": 35, + "force_grow": 90, + "strategy_grow": 82, + "defense_grow": 80, + "speed_grow": 20, + "destroy_grow": 31, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 6, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "貂蝉", + "cfgId": 100337, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 30, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 6, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "张姬", + "cfgId": 100358, + "force": 9100, + "strategy": 8900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 18, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 4 + }, + { + "name": "袁姬", + "cfgId": 100359, + "force": 8100, + "strategy": 7900, + "defense": 7000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 19, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 1 + }, + { + "name": "华佗", + "cfgId": 100369, + "force": 2100, + "strategy": 9700, + "defense": 9500, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 13, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 1 + }, + { + "name": "苏妲己", + "cfgId": 100372, + "force": 9100, + "strategy": 8900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 6, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 4 + }, + { + "name": "骊姬", + "cfgId": 100377, + "force": 9100, + "strategy": 8900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 4 + }, + { + "name": "大乔&小乔", + "cfgId": 100424, + "force": 7900, + "strategy": 8500, + "defense": 9700, + "speed": 6100, + "destroy": 1600, + "cost": 40, + "force_grow": 98, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 66, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 16, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "夏侯渊", + "cfgId": 100435, + "force": 9300, + "strategy": 7500, + "defense": 9100, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 96, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 20, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "荀彧&荀攸", + "cfgId": 100437, + "force": 6300, + "strategy": 9500, + "defense": 9100, + "speed": 6100, + "destroy": 1100, + "cost": 35, + "force_grow": 78, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 66, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 7, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "黄忠", + "cfgId": 100442, + "force": 9300, + "strategy": 7500, + "defense": 9100, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 96, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "陈宫", + "cfgId": 100443, + "force": 6300, + "strategy": 9500, + "defense": 9100, + "speed": 6100, + "destroy": 1100, + "cost": 35, + "force_grow": 78, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 66, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 16, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "夏侯惇", + "cfgId": 100449, + "force": 9300, + "strategy": 7500, + "defense": 9100, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 96, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 12, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "孙策", + "cfgId": 100450, + "force": 9300, + "strategy": 7500, + "defense": 9100, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 96, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 10, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 5 + }, + { + "name": "关羽", + "cfgId": 100451, + "force": 9300, + "strategy": 7500, + "defense": 9100, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 96, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 9, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "木鹿大王", + "cfgId": 100452, + "force": 9000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 96, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 5, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "司马懿", + "cfgId": 100472, + "force": 7100, + "strategy": 9500, + "defense": 9300, + "speed": 5700, + "destroy": 2500, + "cost": 30, + "force_grow": 45, + "strategy_grow": 98, + "defense_grow": 95, + "speed_grow": 58, + "destroy_grow": 22, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 9, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "许褚", + "cfgId": 100473, + "force": 9100, + "strategy": 6500, + "defense": 9300, + "speed": 3700, + "destroy": 3500, + "cost": 35, + "force_grow": 95, + "strategy_grow": 58, + "defense_grow": 95, + "speed_grow": 28, + "destroy_grow": 22, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 10, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "张宁", + "cfgId": 100474, + "force": 9300, + "strategy": 7500, + "defense": 9100, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 96, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 20, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "郝昭", + "cfgId": 100475, + "force": 8800, + "strategy": 6500, + "defense": 9500, + "speed": 3700, + "destroy": 3500, + "cost": 35, + "force_grow": 85, + "strategy_grow": 58, + "defense_grow": 95, + "speed_grow": 28, + "destroy_grow": 22, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 15, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "郭嘉", + "cfgId": 100476, + "force": 7100, + "strategy": 9500, + "defense": 9300, + "speed": 8700, + "destroy": 2500, + "cost": 30, + "force_grow": 45, + "strategy_grow": 98, + "defense_grow": 75, + "speed_grow": 88, + "destroy_grow": 22, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 11, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "庞统", + "cfgId": 100477, + "force": 7100, + "strategy": 9500, + "defense": 9300, + "speed": 3700, + "destroy": 2500, + "cost": 35, + "force_grow": 45, + "strategy_grow": 98, + "defense_grow": 75, + "speed_grow": 88, + "destroy_grow": 22, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 8, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "陆逊", + "cfgId": 100478, + "force": 7100, + "strategy": 9500, + "defense": 9300, + "speed": 3700, + "destroy": 2500, + "cost": 35, + "force_grow": 45, + "strategy_grow": 98, + "defense_grow": 75, + "speed_grow": 88, + "destroy_grow": 22, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 13, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "吕布", + "cfgId": 100479, + "force": 9900, + "strategy": 6500, + "defense": 9300, + "speed": 5700, + "destroy": 2500, + "cost": 35, + "force_grow": 45, + "strategy_grow": 58, + "defense_grow": 95, + "speed_grow": 58, + "destroy_grow": 22, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 19, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "董卓", + "cfgId": 100480, + "force": 9000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 96, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 14, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "潘凤", + "cfgId": 100486, + "force": 9000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 96, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "孟获", + "cfgId": 100488, + "force": 9000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 96, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 8, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "颜良&文丑", + "cfgId": 100495, + "force": 9500, + "strategy": 6500, + "defense": 9900, + "speed": 3800, + "destroy": 1300, + "cost": 40, + "force_grow": 91, + "strategy_grow": 68, + "defense_grow": 88, + "speed_grow": 30, + "destroy_grow": 12, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 6, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 2 + }, + { + "name": "诸葛亮", + "cfgId": 100496, + "force": 5400, + "strategy": 9600, + "defense": 9400, + "speed": 5700, + "destroy": 3800, + "cost": 35, + "force_grow": 72, + "strategy_grow": 89, + "defense_grow": 92, + "speed_grow": 66, + "destroy_grow": 24, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 13, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "步皇后", + "cfgId": 100497, + "force": 5400, + "strategy": 9600, + "defense": 9400, + "speed": 5700, + "destroy": 3800, + "cost": 35, + "force_grow": 72, + "strategy_grow": 89, + "defense_grow": 92, + "speed_grow": 66, + "destroy_grow": 24, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "曹纯", + "cfgId": 100498, + "force": 9500, + "strategy": 6500, + "defense": 9900, + "speed": 3800, + "destroy": 1300, + "cost": 40, + "force_grow": 91, + "strategy_grow": 68, + "defense_grow": 88, + "speed_grow": 30, + "destroy_grow": 12, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "兀突骨", + "cfgId": 100519, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 12, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "花鬘", + "cfgId": 100520, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 25, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 18, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "公孙瓒", + "cfgId": 100521, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 30, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 15, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "诸葛恪", + "cfgId": 100522, + "force": 5800, + "strategy": 8800, + "defense": 6500, + "speed": 4700, + "destroy": 3600, + "cost": 30, + "force_grow": 56, + "strategy_grow": 86, + "defense_grow": 69, + "speed_grow": 38, + "destroy_grow": 39, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 8, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 4 + }, + { + "name": "全踪", + "cfgId": 100523, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 30, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 9, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "沙摩柯", + "cfgId": 100524, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 30, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 8, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "张机", + "cfgId": 100526, + "force": 3100, + "strategy": 9200, + "defense": 5200, + "speed": 3100, + "destroy": 300, + "cost": 35, + "force_grow": 45, + "strategy_grow": 89, + "defense_grow": 46, + "speed_grow": 35, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 19, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "吾粲", + "cfgId": 100528, + "force": 5800, + "strategy": 5800, + "defense": 6500, + "speed": 4700, + "destroy": 3600, + "cost": 30, + "force_grow": 56, + "strategy_grow": 46, + "defense_grow": 69, + "speed_grow": 38, + "destroy_grow": 39, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 12, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "徐庶", + "cfgId": 100534, + "force": 3100, + "strategy": 9200, + "defense": 5200, + "speed": 3100, + "destroy": 300, + "cost": 35, + "force_grow": 45, + "strategy_grow": 89, + "defense_grow": 46, + "speed_grow": 90, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 16, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "柯比能", + "cfgId": 100550, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 30, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 17, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "朱儁", + "cfgId": 100553, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 2900, + "cost": 35, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 89, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "皇甫嵩", + "cfgId": 100554, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 2900, + "cost": 35, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 89, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 6, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "陆抗", + "cfgId": 100574, + "force": 3100, + "strategy": 9200, + "defense": 5200, + "speed": 5100, + "destroy": 300, + "cost": 35, + "force_grow": 45, + "strategy_grow": 89, + "defense_grow": 46, + "speed_grow": 56, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 14, + "star": 5, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "典韦", + "cfgId": 100575, + "force": 9500, + "strategy": 5700, + "defense": 8700, + "speed": 3500, + "destroy": 4100, + "cost": 30, + "force_grow": 81, + "strategy_grow": 51, + "defense_grow": 87, + "speed_grow": 48, + "destroy_grow": 29, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 18, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "徐庶", + "cfgId": 100582, + "force": 3100, + "strategy": 9200, + "defense": 5200, + "speed": 3100, + "destroy": 300, + "cost": 35, + "force_grow": 45, + "strategy_grow": 89, + "defense_grow": 46, + "speed_grow": 90, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 13, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "荀攸", + "cfgId": 100583, + "force": 3100, + "strategy": 9200, + "defense": 5200, + "speed": 3100, + "destroy": 300, + "cost": 35, + "force_grow": 45, + "strategy_grow": 89, + "defense_grow": 46, + "speed_grow": 50, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 5, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "曹仁", + "cfgId": 100585, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 2900, + "cost": 35, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 89, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 10, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "庞德", + "cfgId": 100586, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 2900, + "cost": 35, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 89, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 7, + "star": 5, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "黄盖", + "cfgId": 100587, + "force": 8700, + "strategy": 4900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 35, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 59, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 13, + "star": 5, + "arms": [ + 2, + 5, + 7 + ], + "camp": 5 + }, + { + "name": "甘宁", + "cfgId": 100589, + "force": 8700, + "strategy": 4900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 35, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 59, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 18, + "star": 5, + "arms": [ + 2, + 5, + 7 + ], + "camp": 5 + }, + { + "name": "司马懿", + "cfgId": 100590, + "force": 3100, + "strategy": 9200, + "defense": 5200, + "speed": 3100, + "destroy": 300, + "cost": 35, + "force_grow": 45, + "strategy_grow": 89, + "defense_grow": 46, + "speed_grow": 50, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 15, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "钟会", + "cfgId": 100591, + "force": 3100, + "strategy": 9200, + "defense": 5200, + "speed": 3100, + "destroy": 300, + "cost": 35, + "force_grow": 45, + "strategy_grow": 89, + "defense_grow": 46, + "speed_grow": 50, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 18, + "star": 5, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "汉献帝", + "cfgId": 100001, + "force": 5500, + "strategy": 7500, + "defense": 7000, + "speed": 6000, + "destroy": 2000, + "cost": 20, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 33, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 1 + }, + { + "name": "王美人", + "cfgId": 100038, + "force": 7400, + "strategy": 8600, + "defense": 7400, + "speed": 8600, + "destroy": 1800, + "cost": 25, + "force_grow": 62, + "strategy_grow": 79, + "defense_grow": 82, + "speed_grow": 86, + "destroy_grow": 14, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 47, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "皇甫嵩", + "cfgId": 100039, + "force": 8800, + "strategy": 8600, + "defense": 8600, + "speed": 8900, + "destroy": 2100, + "cost": 25, + "force_grow": 72, + "strategy_grow": 79, + "defense_grow": 82, + "speed_grow": 96, + "destroy_grow": 24, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 30, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "朱儁", + "cfgId": 100040, + "force": 8900, + "strategy": 8700, + "defense": 9000, + "speed": 9100, + "destroy": 2600, + "cost": 25, + "force_grow": 79, + "strategy_grow": 89, + "defense_grow": 88, + "speed_grow": 91, + "destroy_grow": 18, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 40, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "张奂", + "cfgId": 100041, + "force": 8600, + "strategy": 9000, + "defense": 9100, + "speed": 5300, + "destroy": 4500, + "cost": 25, + "force_grow": 81, + "strategy_grow": 76, + "defense_grow": 89, + "speed_grow": 31, + "destroy_grow": 28, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 20, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 2 + }, + { + "name": "曹操", + "cfgId": 100042, + "force": 8100, + "strategy": 8900, + "defense": 8600, + "speed": 9300, + "destroy": 2200, + "cost": 25, + "force_grow": 79, + "strategy_grow": 90, + "defense_grow": 85, + "speed_grow": 88, + "destroy_grow": 18, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 27, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "孙坚", + "cfgId": 100043, + "force": 9100, + "strategy": 7800, + "defense": 9200, + "speed": 9300, + "destroy": 2300, + "cost": 25, + "force_grow": 83, + "strategy_grow": 59, + "defense_grow": 87, + "speed_grow": 86, + "destroy_grow": 21, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 44, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "刘备", + "cfgId": 100044, + "force": 7900, + "strategy": 8500, + "defense": 8700, + "speed": 5100, + "destroy": 4600, + "cost": 25, + "force_grow": 69, + "strategy_grow": 79, + "defense_grow": 88, + "speed_grow": 51, + "destroy_grow": 41, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 40, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 2 + }, + { + "name": "鲍信", + "cfgId": 100045, + "force": 8100, + "strategy": 6700, + "defense": 8300, + "speed": 6100, + "destroy": 1900, + "cost": 25, + "force_grow": 69, + "strategy_grow": 59, + "defense_grow": 78, + "speed_grow": 61, + "destroy_grow": 22, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 47, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "严氏", + "cfgId": 100046, + "force": 7900, + "strategy": 7700, + "defense": 8200, + "speed": 9100, + "destroy": 2100, + "cost": 25, + "force_grow": 70, + "strategy_grow": 79, + "defense_grow": 82, + "speed_grow": 92, + "destroy_grow": 17, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 45, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "董姬", + "cfgId": 100047, + "force": 7500, + "strategy": 8100, + "defense": 8300, + "speed": 8800, + "destroy": 1700, + "cost": 25, + "force_grow": 71, + "strategy_grow": 72, + "defense_grow": 86, + "speed_grow": 85, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 26, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "邹氏", + "cfgId": 100048, + "force": 7100, + "strategy": 7300, + "defense": 8100, + "speed": 4100, + "destroy": 3100, + "cost": 25, + "force_grow": 71, + "strategy_grow": 72, + "defense_grow": 84, + "speed_grow": 36, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 29, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "华雄", + "cfgId": 100049, + "force": 8300, + "strategy": 6700, + "defense": 8800, + "speed": 4600, + "destroy": 3900, + "cost": 30, + "force_grow": 78, + "strategy_grow": 56, + "defense_grow": 89, + "speed_grow": 42, + "destroy_grow": 37, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 44, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "张辽", + "cfgId": 100050, + "force": 8800, + "strategy": 7900, + "defense": 8900, + "speed": 9300, + "destroy": 1900, + "cost": 30, + "force_grow": 86, + "strategy_grow": 76, + "defense_grow": 89, + "speed_grow": 82, + "destroy_grow": 17, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 27, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "张梁", + "cfgId": 100051, + "force": 8100, + "strategy": 5900, + "defense": 7900, + "speed": 4300, + "destroy": 3500, + "cost": 25, + "force_grow": 76, + "strategy_grow": 56, + "defense_grow": 69, + "speed_grow": 42, + "destroy_grow": 25, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 46, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "管亥", + "cfgId": 100052, + "force": 7800, + "strategy": 6900, + "defense": 7900, + "speed": 9100, + "destroy": 1500, + "cost": 25, + "force_grow": 74, + "strategy_grow": 56, + "defense_grow": 79, + "speed_grow": 88, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 28, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "徐荣", + "cfgId": 100053, + "force": 8200, + "strategy": 5900, + "defense": 7900, + "speed": 5100, + "destroy": 2500, + "cost": 25, + "force_grow": 76, + "strategy_grow": 46, + "defense_grow": 79, + "speed_grow": 32, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 31, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "张曼成", + "cfgId": 100054, + "force": 8800, + "strategy": 4900, + "defense": 8700, + "speed": 2300, + "destroy": 3000, + "cost": 30, + "force_grow": 76, + "strategy_grow": 46, + "defense_grow": 79, + "speed_grow": 22, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 42, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "吕姬", + "cfgId": 100055, + "force": 8800, + "strategy": 4200, + "defense": 6700, + "speed": 2500, + "destroy": 3200, + "cost": 30, + "force_grow": 76, + "strategy_grow": 46, + "defense_grow": 79, + "speed_grow": 22, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 33, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "左慈", + "cfgId": 100056, + "force": 5800, + "strategy": 8900, + "defense": 8700, + "speed": 5500, + "destroy": 2200, + "cost": 30, + "force_grow": 56, + "strategy_grow": 76, + "defense_grow": 89, + "speed_grow": 52, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 37, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "田丰", + "cfgId": 100057, + "force": 5900, + "strategy": 9200, + "defense": 7700, + "speed": 8800, + "destroy": 1200, + "cost": 30, + "force_grow": 66, + "strategy_grow": 96, + "defense_grow": 80, + "speed_grow": 92, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 29, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "颜良", + "cfgId": 100058, + "force": 8900, + "strategy": 5200, + "defense": 8700, + "speed": 8800, + "destroy": 1300, + "cost": 30, + "force_grow": 86, + "strategy_grow": 36, + "defense_grow": 82, + "speed_grow": 85, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 36, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "文丑", + "cfgId": 100059, + "force": 8800, + "strategy": 4300, + "defense": 8700, + "speed": 8900, + "destroy": 2300, + "cost": 30, + "force_grow": 86, + "strategy_grow": 37, + "defense_grow": 85, + "speed_grow": 89, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 34, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "吕姬", + "cfgId": 100060, + "force": 8800, + "strategy": 5700, + "defense": 8700, + "speed": 9500, + "destroy": 1700, + "cost": 30, + "force_grow": 86, + "strategy_grow": 36, + "defense_grow": 82, + "speed_grow": 88, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 26, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "马腾", + "cfgId": 100062, + "force": 8800, + "strategy": 5200, + "defense": 8700, + "speed": 9500, + "destroy": 1300, + "cost": 30, + "force_grow": 76, + "strategy_grow": 42, + "defense_grow": 81, + "speed_grow": 89, + "destroy_grow": 15, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 35, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "甘皇后", + "cfgId": 100063, + "force": 3800, + "strategy": 5200, + "defense": 5700, + "speed": 3500, + "destroy": 3600, + "cost": 25, + "force_grow": 56, + "strategy_grow": 36, + "defense_grow": 59, + "speed_grow": 25, + "destroy_grow": 31, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 44, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "糜夫人", + "cfgId": 100064, + "force": 3800, + "strategy": 4900, + "defense": 5700, + "speed": 3500, + "destroy": 3500, + "cost": 25, + "force_grow": 60, + "strategy_grow": 56, + "defense_grow": 49, + "speed_grow": 29, + "destroy_grow": 28, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 29, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "关羽", + "cfgId": 100065, + "force": 9000, + "strategy": 8200, + "defense": 8700, + "speed": 4500, + "destroy": 4200, + "cost": 30, + "force_grow": 86, + "strategy_grow": 79, + "defense_grow": 89, + "speed_grow": 45, + "destroy_grow": 36, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 37, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "魏延", + "cfgId": 100066, + "force": 8900, + "strategy": 7200, + "defense": 8700, + "speed": 4500, + "destroy": 3600, + "cost": 30, + "force_grow": 86, + "strategy_grow": 56, + "defense_grow": 89, + "speed_grow": 32, + "destroy_grow": 36, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 49, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "徐庶", + "cfgId": 100067, + "force": 5800, + "strategy": 8900, + "defense": 7700, + "speed": 8500, + "destroy": 1100, + "cost": 30, + "force_grow": 56, + "strategy_grow": 89, + "defense_grow": 69, + "speed_grow": 83, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 38, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "张飞", + "cfgId": 100068, + "force": 8900, + "strategy": 6200, + "defense": 8700, + "speed": 3900, + "destroy": 3600, + "cost": 30, + "force_grow": 86, + "strategy_grow": 66, + "defense_grow": 89, + "speed_grow": 36, + "destroy_grow": 37, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 49, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "庞统", + "cfgId": 100069, + "force": 5800, + "strategy": 8800, + "defense": 6500, + "speed": 3700, + "destroy": 3600, + "cost": 30, + "force_grow": 56, + "strategy_grow": 86, + "defense_grow": 69, + "speed_grow": 38, + "destroy_grow": 39, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 46, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "穆皇后", + "cfgId": 100070, + "force": 4200, + "strategy": 5300, + "defense": 4500, + "speed": 3900, + "destroy": 3100, + "cost": 20, + "force_grow": 29, + "strategy_grow": 49, + "defense_grow": 59, + "speed_grow": 40, + "destroy_grow": 31, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "马姬", + "cfgId": 100071, + "force": 8100, + "strategy": 6800, + "defense": 7900, + "speed": 8500, + "destroy": 1600, + "cost": 25, + "force_grow": 76, + "strategy_grow": 58, + "defense_grow": 79, + "speed_grow": 82, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 27, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "马谡", + "cfgId": 100073, + "force": 5600, + "strategy": 8700, + "defense": 6900, + "speed": 4100, + "destroy": 4300, + "cost": 25, + "force_grow": 66, + "strategy_grow": 76, + "defense_grow": 59, + "speed_grow": 48, + "destroy_grow": 37, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 24, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "郭皇后", + "cfgId": 100075, + "force": 4300, + "strategy": 5800, + "defense": 4500, + "speed": 8700, + "destroy": 1300, + "cost": 20, + "force_grow": 46, + "strategy_grow": 39, + "defense_grow": 49, + "speed_grow": 78, + "destroy_grow": 9, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 49, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "卞夫人", + "cfgId": 100076, + "force": 4700, + "strategy": 5900, + "defense": 5600, + "speed": 8700, + "destroy": 1300, + "cost": 20, + "force_grow": 43, + "strategy_grow": 56, + "defense_grow": 59, + "speed_grow": 89, + "destroy_grow": 12, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 24, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "丁夫人", + "cfgId": 100077, + "force": 5400, + "strategy": 6100, + "defense": 5500, + "speed": 8700, + "destroy": 1200, + "cost": 20, + "force_grow": 66, + "strategy_grow": 56, + "defense_grow": 59, + "speed_grow": 88, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 42, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "郭嘉", + "cfgId": 100078, + "force": 7800, + "strategy": 8900, + "defense": 9000, + "speed": 9100, + "destroy": 1300, + "cost": 30, + "force_grow": 76, + "strategy_grow": 89, + "defense_grow": 90, + "speed_grow": 91, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 49, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "夏侯惇", + "cfgId": 100079, + "force": 8900, + "strategy": 7800, + "defense": 9000, + "speed": 9100, + "destroy": 1100, + "cost": 30, + "force_grow": 86, + "strategy_grow": 76, + "defense_grow": 90, + "speed_grow": 88, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 44, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "典韦", + "cfgId": 100081, + "force": 8800, + "strategy": 5700, + "defense": 8700, + "speed": 3500, + "destroy": 4100, + "cost": 30, + "force_grow": 81, + "strategy_grow": 51, + "defense_grow": 87, + "speed_grow": 48, + "destroy_grow": 29, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 20, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "庞德", + "cfgId": 100084, + "force": 8900, + "strategy": 7700, + "defense": 8700, + "speed": 8900, + "destroy": 1300, + "cost": 30, + "force_grow": 85, + "strategy_grow": 59, + "defense_grow": 87, + "speed_grow": 83, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 33, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "曹仁", + "cfgId": 100085, + "force": 8900, + "strategy": 8100, + "defense": 8900, + "speed": 9100, + "destroy": 1400, + "cost": 30, + "force_grow": 88, + "strategy_grow": 79, + "defense_grow": 89, + "speed_grow": 89, + "destroy_grow": 17, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 48, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "周泰", + "cfgId": 100086, + "force": 8700, + "strategy": 6300, + "defense": 8100, + "speed": 5900, + "destroy": 2600, + "cost": 30, + "force_grow": 80, + "strategy_grow": 58, + "defense_grow": 81, + "speed_grow": 63, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 32, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "徐盛", + "cfgId": 100087, + "force": 8400, + "strategy": 7300, + "defense": 8300, + "speed": 6100, + "destroy": 2900, + "cost": 25, + "force_grow": 81, + "strategy_grow": 68, + "defense_grow": 87, + "speed_grow": 56, + "destroy_grow": 27, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 39, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "孙坚", + "cfgId": 100088, + "force": 8700, + "strategy": 6300, + "defense": 8100, + "speed": 8900, + "destroy": 2600, + "cost": 30, + "force_grow": 80, + "strategy_grow": 58, + "defense_grow": 81, + "speed_grow": 83, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 29, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 5 + }, + { + "name": "孙策", + "cfgId": 100089, + "force": 8900, + "strategy": 7300, + "defense": 8800, + "speed": 8900, + "destroy": 2100, + "cost": 25, + "force_grow": 85, + "strategy_grow": 57, + "defense_grow": 87, + "speed_grow": 83, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 32, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "吴夫人", + "cfgId": 100091, + "force": 4700, + "strategy": 5300, + "defense": 5100, + "speed": 5000, + "destroy": 2900, + "cost": 25, + "force_grow": 47, + "strategy_grow": 51, + "defense_grow": 61, + "speed_grow": 53, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 47, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "陆逊", + "cfgId": 100092, + "force": 5700, + "strategy": 8900, + "defense": 8100, + "speed": 5900, + "destroy": 2600, + "cost": 30, + "force_grow": 59, + "strategy_grow": 88, + "defense_grow": 80, + "speed_grow": 59, + "destroy_grow": 24, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 27, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "徐夫人", + "cfgId": 100093, + "force": 4700, + "strategy": 5300, + "defense": 5100, + "speed": 5300, + "destroy": 3600, + "cost": 20, + "force_grow": 50, + "strategy_grow": 58, + "defense_grow": 61, + "speed_grow": 53, + "destroy_grow": 29, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "小乔", + "cfgId": 100094, + "force": 4700, + "strategy": 7300, + "defense": 5100, + "speed": 5000, + "destroy": 2900, + "cost": 20, + "force_grow": 60, + "strategy_grow": 68, + "defense_grow": 51, + "speed_grow": 53, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 47, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "大乔", + "cfgId": 100095, + "force": 4700, + "strategy": 6300, + "defense": 5100, + "speed": 5900, + "destroy": 3600, + "cost": 20, + "force_grow": 50, + "strategy_grow": 58, + "defense_grow": 61, + "speed_grow": 63, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 48, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "步骘", + "cfgId": 100096, + "force": 5700, + "strategy": 7300, + "defense": 7100, + "speed": 6900, + "destroy": 3600, + "cost": 25, + "force_grow": 55, + "strategy_grow": 78, + "defense_grow": 71, + "speed_grow": 49, + "destroy_grow": 36, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 39, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "蒯越", + "cfgId": 100097, + "force": 4700, + "strategy": 8900, + "defense": 5100, + "speed": 5900, + "destroy": 3700, + "cost": 25, + "force_grow": 55, + "strategy_grow": 89, + "defense_grow": 61, + "speed_grow": 59, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 34, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "何进", + "cfgId": 100098, + "force": 7700, + "strategy": 3900, + "defense": 5900, + "speed": 8900, + "destroy": 1100, + "cost": 25, + "force_grow": 55, + "strategy_grow": 49, + "defense_grow": 71, + "speed_grow": 87, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 42, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "丁原", + "cfgId": 100099, + "force": 5700, + "strategy": 3900, + "defense": 6100, + "speed": 8900, + "destroy": 1700, + "cost": 25, + "force_grow": 50, + "strategy_grow": 39, + "defense_grow": 51, + "speed_grow": 89, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 20, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "董承", + "cfgId": 100100, + "force": 3700, + "strategy": 6900, + "defense": 5000, + "speed": 8800, + "destroy": 1400, + "cost": 25, + "force_grow": 35, + "strategy_grow": 59, + "defense_grow": 51, + "speed_grow": 89, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 26, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "王烈", + "cfgId": 100102, + "force": 5700, + "strategy": 4900, + "defense": 5100, + "speed": 5800, + "destroy": 3000, + "cost": 25, + "force_grow": 50, + "strategy_grow": 69, + "defense_grow": 61, + "speed_grow": 59, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 38, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "孔融", + "cfgId": 100103, + "force": 4100, + "strategy": 7900, + "defense": 4100, + "speed": 5000, + "destroy": 3700, + "cost": 25, + "force_grow": 55, + "strategy_grow": 89, + "defense_grow": 61, + "speed_grow": 59, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 38, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "刘表", + "cfgId": 100107, + "force": 3700, + "strategy": 5900, + "defense": 4100, + "speed": 8100, + "destroy": 1100, + "cost": 20, + "force_grow": 36, + "strategy_grow": 59, + "defense_grow": 41, + "speed_grow": 79, + "destroy_grow": 6, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "李儒", + "cfgId": 100111, + "force": 6100, + "strategy": 8800, + "defense": 8100, + "speed": 6900, + "destroy": 3500, + "cost": 25, + "force_grow": 59, + "strategy_grow": 79, + "defense_grow": 71, + "speed_grow": 69, + "destroy_grow": 38, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 48, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 1 + }, + { + "name": "公孙瓒", + "cfgId": 100114, + "force": 8100, + "strategy": 5800, + "defense": 7100, + "speed": 8500, + "destroy": 1100, + "cost": 20, + "force_grow": 78, + "strategy_grow": 49, + "defense_grow": 71, + "speed_grow": 89, + "destroy_grow": 9, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 36, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "高顺", + "cfgId": 100115, + "force": 8800, + "strategy": 4700, + "defense": 7500, + "speed": 8900, + "destroy": 1300, + "cost": 20, + "force_grow": 81, + "strategy_grow": 51, + "defense_grow": 79, + "speed_grow": 86, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 47, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "袁术", + "cfgId": 100116, + "force": 6100, + "strategy": 6800, + "defense": 7100, + "speed": 5500, + "destroy": 3800, + "cost": 20, + "force_grow": 68, + "strategy_grow": 59, + "defense_grow": 61, + "speed_grow": 59, + "destroy_grow": 39, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 21, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "张勋", + "cfgId": 100117, + "force": 7800, + "strategy": 5100, + "defense": 8100, + "speed": 8700, + "destroy": 1300, + "cost": 20, + "force_grow": 81, + "strategy_grow": 59, + "defense_grow": 80, + "speed_grow": 85, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 30, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "淳于琼", + "cfgId": 100118, + "force": 7800, + "strategy": 3200, + "defense": 8100, + "speed": 4500, + "destroy": 3800, + "cost": 20, + "force_grow": 68, + "strategy_grow": 29, + "defense_grow": 81, + "speed_grow": 49, + "destroy_grow": 29, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 38, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "高览", + "cfgId": 100119, + "force": 8300, + "strategy": 3800, + "defense": 8800, + "speed": 4500, + "destroy": 3900, + "cost": 20, + "force_grow": 81, + "strategy_grow": 39, + "defense_grow": 81, + "speed_grow": 49, + "destroy_grow": 29, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 33, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "沮授", + "cfgId": 100120, + "force": 4100, + "strategy": 9100, + "defense": 7100, + "speed": 5500, + "destroy": 2100, + "cost": 20, + "force_grow": 78, + "strategy_grow": 89, + "defense_grow": 71, + "speed_grow": 59, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 1 + }, + { + "name": "逢纪", + "cfgId": 100121, + "force": 3800, + "strategy": 8500, + "defense": 6100, + "speed": 5500, + "destroy": 2100, + "cost": 20, + "force_grow": 48, + "strategy_grow": 79, + "defense_grow": 71, + "speed_grow": 45, + "destroy_grow": 19, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 36, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 1 + }, + { + "name": "麴义", + "cfgId": 100122, + "force": 8100, + "strategy": 7800, + "defense": 8800, + "speed": 8900, + "destroy": 1300, + "cost": 25, + "force_grow": 78, + "strategy_grow": 69, + "defense_grow": 71, + "speed_grow": 89, + "destroy_grow": 9, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 32, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "张郃", + "cfgId": 100123, + "force": 9000, + "strategy": 6800, + "defense": 8800, + "speed": 3900, + "destroy": 3300, + "cost": 25, + "force_grow": 85, + "strategy_grow": 69, + "defense_grow": 81, + "speed_grow": 49, + "destroy_grow": 39, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 35, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "南华老仙", + "cfgId": 100124, + "force": 3100, + "strategy": 8800, + "defense": 4800, + "speed": 3900, + "destroy": 2200, + "cost": 25, + "force_grow": 48, + "strategy_grow": 89, + "defense_grow": 61, + "speed_grow": 30, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 42, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "韩遂", + "cfgId": 100127, + "force": 7800, + "strategy": 7000, + "defense": 8500, + "speed": 8900, + "destroy": 900, + "cost": 25, + "force_grow": 80, + "strategy_grow": 70, + "defense_grow": 85, + "speed_grow": 89, + "destroy_grow": 12, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 21, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "关平", + "cfgId": 100129, + "force": 8800, + "strategy": 7500, + "defense": 8500, + "speed": 5600, + "destroy": 1000, + "cost": 30, + "force_grow": 83, + "strategy_grow": 70, + "defense_grow": 85, + "speed_grow": 49, + "destroy_grow": 12, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 4 + }, + { + "name": "黄忠", + "cfgId": 100130, + "force": 8900, + "strategy": 8300, + "defense": 8800, + "speed": 5500, + "destroy": 1200, + "cost": 35, + "force_grow": 90, + "strategy_grow": 85, + "defense_grow": 90, + "speed_grow": 50, + "destroy_grow": 8, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 35, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 4 + }, + { + "name": "赵云", + "cfgId": 100131, + "force": 8900, + "strategy": 7000, + "defense": 8300, + "speed": 8600, + "destroy": 1200, + "cost": 35, + "force_grow": 83, + "strategy_grow": 64, + "defense_grow": 80, + "speed_grow": 85, + "destroy_grow": 8, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 25, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "严颜", + "cfgId": 100134, + "force": 8900, + "strategy": 6500, + "defense": 8500, + "speed": 3600, + "destroy": 3500, + "cost": 30, + "force_grow": 84, + "strategy_grow": 60, + "defense_grow": 75, + "speed_grow": 32, + "destroy_grow": 22, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 37, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "李严", + "cfgId": 100138, + "force": 7100, + "strategy": 7500, + "defense": 6500, + "speed": 4100, + "destroy": 1200, + "cost": 20, + "force_grow": 63, + "strategy_grow": 71, + "defense_grow": 65, + "speed_grow": 39, + "destroy_grow": 12, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 33, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "马岱", + "cfgId": 100139, + "force": 8100, + "strategy": 7200, + "defense": 7500, + "speed": 8600, + "destroy": 1100, + "cost": 20, + "force_grow": 80, + "strategy_grow": 60, + "defense_grow": 75, + "speed_grow": 89, + "destroy_grow": 3, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 44, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "马超", + "cfgId": 100140, + "force": 9100, + "strategy": 4200, + "defense": 8500, + "speed": 8600, + "destroy": 600, + "cost": 30, + "force_grow": 88, + "strategy_grow": 51, + "defense_grow": 75, + "speed_grow": 89, + "destroy_grow": 7, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 49, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "沙摩柯", + "cfgId": 100141, + "force": 8500, + "strategy": 3200, + "defense": 8500, + "speed": 8800, + "destroy": 200, + "cost": 25, + "force_grow": 82, + "strategy_grow": 33, + "defense_grow": 85, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 41, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "于禁", + "cfgId": 100143, + "force": 8100, + "strategy": 5200, + "defense": 8200, + "speed": 8700, + "destroy": 800, + "cost": 25, + "force_grow": 83, + "strategy_grow": 53, + "defense_grow": 86, + "speed_grow": 88, + "destroy_grow": 3, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 49, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "乐进", + "cfgId": 100144, + "force": 7100, + "strategy": 7200, + "defense": 8200, + "speed": 3700, + "destroy": 1800, + "cost": 25, + "force_grow": 75, + "strategy_grow": 83, + "defense_grow": 76, + "speed_grow": 38, + "destroy_grow": 3, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 26, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "乐进", + "cfgId": 100145, + "force": 9100, + "strategy": 6200, + "defense": 8200, + "speed": 5700, + "destroy": 1100, + "cost": 30, + "force_grow": 85, + "strategy_grow": 73, + "defense_grow": 86, + "speed_grow": 58, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "曹彰", + "cfgId": 100148, + "force": 8400, + "strategy": 4200, + "defense": 8200, + "speed": 8700, + "destroy": 600, + "cost": 25, + "force_grow": 85, + "strategy_grow": 23, + "defense_grow": 76, + "speed_grow": 86, + "destroy_grow": 9, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 40, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "韩当", + "cfgId": 100156, + "force": 8600, + "strategy": 6300, + "defense": 8200, + "speed": 6700, + "destroy": 1500, + "cost": 25, + "force_grow": 85, + "strategy_grow": 65, + "defense_grow": 86, + "speed_grow": 58, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "甘宁", + "cfgId": 100157, + "force": 9600, + "strategy": 5200, + "defense": 9200, + "speed": 5700, + "destroy": 1500, + "cost": 25, + "force_grow": 88, + "strategy_grow": 53, + "defense_grow": 86, + "speed_grow": 51, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 44, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "蒋钦", + "cfgId": 100159, + "force": 8600, + "strategy": 7200, + "defense": 9200, + "speed": 5700, + "destroy": 1200, + "cost": 25, + "force_grow": 85, + "strategy_grow": 63, + "defense_grow": 96, + "speed_grow": 53, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 25, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "张纮", + "cfgId": 100160, + "force": 2600, + "strategy": 8800, + "defense": 5200, + "speed": 5100, + "destroy": 1200, + "cost": 20, + "force_grow": 35, + "strategy_grow": 83, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 47, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "张昭", + "cfgId": 100161, + "force": 2600, + "strategy": 9200, + "defense": 3200, + "speed": 4500, + "destroy": 200, + "cost": 25, + "force_grow": 15, + "strategy_grow": 83, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 2, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 33, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "黄盖", + "cfgId": 100162, + "force": 8900, + "strategy": 7200, + "defense": 9100, + "speed": 5100, + "destroy": 3200, + "cost": 30, + "force_grow": 85, + "strategy_grow": 73, + "defense_grow": 91, + "speed_grow": 43, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 24, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "鲁肃", + "cfgId": 100163, + "force": 3600, + "strategy": 9200, + "defense": 5200, + "speed": 4700, + "destroy": 200, + "cost": 25, + "force_grow": 35, + "strategy_grow": 93, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 6, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 24, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "诸葛瑾", + "cfgId": 100164, + "force": 5600, + "strategy": 8800, + "defense": 5900, + "speed": 4900, + "destroy": 3100, + "cost": 25, + "force_grow": 56, + "strategy_grow": 87, + "defense_grow": 56, + "speed_grow": 53, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 48, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "丁封", + "cfgId": 100165, + "force": 8600, + "strategy": 6200, + "defense": 8200, + "speed": 6300, + "destroy": 1200, + "cost": 25, + "force_grow": 85, + "strategy_grow": 63, + "defense_grow": 86, + "speed_grow": 59, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 35, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "吕蒙", + "cfgId": 100166, + "force": 6600, + "strategy": 9300, + "defense": 6200, + "speed": 6800, + "destroy": 1200, + "cost": 25, + "force_grow": 55, + "strategy_grow": 90, + "defense_grow": 66, + "speed_grow": 59, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 49, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "孙桓", + "cfgId": 100243, + "force": 3600, + "strategy": 4200, + "defense": 4200, + "speed": 4800, + "destroy": 1200, + "cost": 20, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "董袭", + "cfgId": 100245, + "force": 3600, + "strategy": 4200, + "defense": 4200, + "speed": 4800, + "destroy": 1200, + "cost": 20, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 35, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "潘璋", + "cfgId": 100246, + "force": 3600, + "strategy": 4200, + "defense": 4200, + "speed": 4800, + "destroy": 1200, + "cost": 20, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 47, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "侯成", + "cfgId": 100265, + "force": 6100, + "strategy": 3100, + "defense": 3100, + "speed": 8100, + "destroy": 1200, + "cost": 20, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 88, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 41, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "波才", + "cfgId": 100266, + "force": 6100, + "strategy": 3100, + "defense": 3100, + "speed": 8100, + "destroy": 1200, + "cost": 20, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 88, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 44, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "胡车儿", + "cfgId": 100267, + "force": 6100, + "strategy": 3100, + "defense": 3100, + "speed": 8100, + "destroy": 1200, + "cost": 20, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 88, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 28, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "张绣", + "cfgId": 100268, + "force": 6100, + "strategy": 3100, + "defense": 3100, + "speed": 8100, + "destroy": 1200, + "cost": 20, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 88, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 40, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "魏续", + "cfgId": 100269, + "force": 6100, + "strategy": 3100, + "defense": 3100, + "speed": 8100, + "destroy": 1200, + "cost": 20, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 88, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 33, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "贺齐", + "cfgId": 100321, + "force": 4100, + "strategy": 3900, + "defense": 5100, + "speed": 4100, + "destroy": 900, + "cost": 25, + "force_grow": 19, + "strategy_grow": 20, + "defense_grow": 20, + "speed_grow": 32, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 43, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "夏侯月姬", + "cfgId": 100326, + "force": 7000, + "strategy": 6500, + "defense": 6300, + "speed": 8600, + "destroy": 900, + "cost": 20, + "force_grow": 63, + "strategy_grow": 50, + "defense_grow": 65, + "speed_grow": 80, + "destroy_grow": 15, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 30, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "敬哀皇后", + "cfgId": 100329, + "force": 7000, + "strategy": 6500, + "defense": 6300, + "speed": 8600, + "destroy": 900, + "cost": 20, + "force_grow": 63, + "strategy_grow": 50, + "defense_grow": 65, + "speed_grow": 80, + "destroy_grow": 15, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 38, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "邓芝", + "cfgId": 100330, + "force": 7000, + "strategy": 6500, + "defense": 6300, + "speed": 8600, + "destroy": 900, + "cost": 20, + "force_grow": 63, + "strategy_grow": 50, + "defense_grow": 65, + "speed_grow": 80, + "destroy_grow": 15, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "霍弋", + "cfgId": 100331, + "force": 7000, + "strategy": 6500, + "defense": 6300, + "speed": 8600, + "destroy": 900, + "cost": 20, + "force_grow": 63, + "strategy_grow": 50, + "defense_grow": 65, + "speed_grow": 80, + "destroy_grow": 15, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 43, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "黄权", + "cfgId": 100334, + "force": 7000, + "strategy": 6500, + "defense": 6300, + "speed": 8600, + "destroy": 900, + "cost": 20, + "force_grow": 63, + "strategy_grow": 50, + "defense_grow": 65, + "speed_grow": 80, + "destroy_grow": 15, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 46, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "李恢", + "cfgId": 100335, + "force": 7000, + "strategy": 6500, + "defense": 6300, + "speed": 8600, + "destroy": 900, + "cost": 20, + "force_grow": 63, + "strategy_grow": 50, + "defense_grow": 65, + "speed_grow": 80, + "destroy_grow": 15, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 21, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "宋宪", + "cfgId": 100338, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 49, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "张燕", + "cfgId": 100339, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "于吉", + "cfgId": 100340, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 27, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "张横", + "cfgId": 100342, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 85, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 35, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "李堪", + "cfgId": 100343, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 85, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 34, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "马玩", + "cfgId": 100344, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 85, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 41, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "杨秋", + "cfgId": 100345, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 85, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 48, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "侯选", + "cfgId": 100346, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 85, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 48, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "程银", + "cfgId": 100347, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 85, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 21, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "成宜", + "cfgId": 100348, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 85, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 47, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "张任", + "cfgId": 100351, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 89, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 25, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "梁兴", + "cfgId": 100352, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 8800, + "destroy": 900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 85, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 31, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "纪灵", + "cfgId": 100353, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 33, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "水镜先生", + "cfgId": 100354, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "蔡夫人", + "cfgId": 100355, + "force": 8700, + "strategy": 8900, + "defense": 9000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 32, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "伏皇后", + "cfgId": 100378, + "force": 4100, + "strategy": 7900, + "defense": 8000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 25, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 4 + }, + { + "name": "杜氏", + "cfgId": 100379, + "force": 4100, + "strategy": 7900, + "defense": 8000, + "speed": 6800, + "destroy": 2900, + "cost": 25, + "force_grow": 70, + "strategy_grow": 50, + "defense_grow": 50, + "speed_grow": 55, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 48, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 4 + }, + { + "name": "法正", + "cfgId": 100396, + "force": 8800, + "strategy": 7500, + "defense": 8500, + "speed": 5600, + "destroy": 1000, + "cost": 30, + "force_grow": 83, + "strategy_grow": 70, + "defense_grow": 85, + "speed_grow": 49, + "destroy_grow": 12, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 21, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 4 + }, + { + "name": "关兴&张苞", + "cfgId": 100398, + "force": 8800, + "strategy": 7500, + "defense": 8500, + "speed": 5600, + "destroy": 1000, + "cost": 30, + "force_grow": 83, + "strategy_grow": 70, + "defense_grow": 85, + "speed_grow": 49, + "destroy_grow": 12, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 28, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 4 + }, + { + "name": "夏侯渊", + "cfgId": 100420, + "force": 4100, + "strategy": 3900, + "defense": 5100, + "speed": 4100, + "destroy": 900, + "cost": 25, + "force_grow": 19, + "strategy_grow": 20, + "defense_grow": 20, + "speed_grow": 32, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 38, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "徐晃", + "cfgId": 100421, + "force": 4100, + "strategy": 3900, + "defense": 5100, + "speed": 4100, + "destroy": 900, + "cost": 25, + "force_grow": 19, + "strategy_grow": 20, + "defense_grow": 20, + "speed_grow": 32, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 25, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "凌统", + "cfgId": 100426, + "force": 7900, + "strategy": 6500, + "defense": 8700, + "speed": 6100, + "destroy": 1600, + "cost": 30, + "force_grow": 78, + "strategy_grow": 65, + "defense_grow": 87, + "speed_grow": 66, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 43, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "张宝", + "cfgId": 100430, + "force": 7900, + "strategy": 6500, + "defense": 8700, + "speed": 6100, + "destroy": 1600, + "cost": 30, + "force_grow": 78, + "strategy_grow": 65, + "defense_grow": 87, + "speed_grow": 66, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 35, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "黄盖", + "cfgId": 100439, + "force": 7900, + "strategy": 6500, + "defense": 8700, + "speed": 6100, + "destroy": 1600, + "cost": 30, + "force_grow": 78, + "strategy_grow": 65, + "defense_grow": 87, + "speed_grow": 66, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 41, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "曹节", + "cfgId": 100471, + "force": 2100, + "strategy": 6200, + "defense": 5200, + "speed": 5700, + "destroy": 1100, + "cost": 20, + "force_grow": 85, + "strategy_grow": 73, + "defense_grow": 86, + "speed_grow": 58, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 47, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "丁封", + "cfgId": 100481, + "force": 8800, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 30, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 89, + "speed_grow": 84, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 49, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 5 + }, + { + "name": "韩遂", + "cfgId": 100482, + "force": 7800, + "strategy": 7000, + "defense": 8500, + "speed": 8900, + "destroy": 900, + "cost": 25, + "force_grow": 80, + "strategy_grow": 70, + "defense_grow": 85, + "speed_grow": 89, + "destroy_grow": 12, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 34, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "麴义", + "cfgId": 100483, + "force": 8100, + "strategy": 7800, + "defense": 8800, + "speed": 8900, + "destroy": 1300, + "cost": 25, + "force_grow": 78, + "strategy_grow": 69, + "defense_grow": 71, + "speed_grow": 89, + "destroy_grow": 9, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 41, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "公孙瓒", + "cfgId": 100484, + "force": 8100, + "strategy": 5800, + "defense": 7100, + "speed": 8500, + "destroy": 1100, + "cost": 20, + "force_grow": 78, + "strategy_grow": 49, + "defense_grow": 71, + "speed_grow": 89, + "destroy_grow": 9, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 45, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "张鲁", + "cfgId": 100487, + "force": 6800, + "strategy": 6500, + "defense": 6900, + "speed": 4100, + "destroy": 1100, + "cost": 35, + "force_grow": 48, + "strategy_grow": 65, + "defense_grow": 57, + "speed_grow": 56, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 33, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "孟优", + "cfgId": 100489, + "force": 6800, + "strategy": 6500, + "defense": 6900, + "speed": 4100, + "destroy": 1100, + "cost": 35, + "force_grow": 48, + "strategy_grow": 65, + "defense_grow": 57, + "speed_grow": 56, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 32, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "带来洞主", + "cfgId": 100490, + "force": 6800, + "strategy": 6500, + "defense": 6900, + "speed": 4100, + "destroy": 1100, + "cost": 35, + "force_grow": 48, + "strategy_grow": 65, + "defense_grow": 57, + "speed_grow": 56, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 36, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "金环三杰", + "cfgId": 100491, + "force": 6800, + "strategy": 6500, + "defense": 6900, + "speed": 4100, + "destroy": 1100, + "cost": 35, + "force_grow": 48, + "strategy_grow": 65, + "defense_grow": 57, + "speed_grow": 56, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 29, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "董荼那", + "cfgId": 100493, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 35, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "祝融夫人", + "cfgId": 100494, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 36, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "刘豹", + "cfgId": 100506, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 40, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "楼班", + "cfgId": 100507, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 22, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "严白虎", + "cfgId": 100508, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 35, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 36, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "赵统", + "cfgId": 100525, + "force": 8000, + "strategy": 7500, + "defense": 8900, + "speed": 9100, + "destroy": 1100, + "cost": 30, + "force_grow": 88, + "strategy_grow": 85, + "defense_grow": 97, + "speed_grow": 86, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 23, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "步度根", + "cfgId": 100529, + "force": 5800, + "strategy": 5800, + "defense": 6500, + "speed": 4700, + "destroy": 3600, + "cost": 25, + "force_grow": 56, + "strategy_grow": 46, + "defense_grow": 69, + "speed_grow": 38, + "destroy_grow": 39, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 32, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "蜀三相", + "cfgId": 100532, + "force": 5800, + "strategy": 8800, + "defense": 6500, + "speed": 4700, + "destroy": 3600, + "cost": 25, + "force_grow": 56, + "strategy_grow": 86, + "defense_grow": 69, + "speed_grow": 38, + "destroy_grow": 39, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 37, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "献帝", + "cfgId": 100551, + "force": 3100, + "strategy": 8200, + "defense": 5200, + "speed": 8100, + "destroy": 300, + "cost": 35, + "force_grow": 45, + "strategy_grow": 89, + "defense_grow": 46, + "speed_grow": 90, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 33, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "伏寿", + "cfgId": 100552, + "force": 3100, + "strategy": 8200, + "defense": 5200, + "speed": 8100, + "destroy": 300, + "cost": 35, + "force_grow": 45, + "strategy_grow": 89, + "defense_grow": 46, + "speed_grow": 90, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 43, + "star": 4, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "张宝", + "cfgId": 100562, + "force": 8100, + "strategy": 5900, + "defense": 7900, + "speed": 4300, + "destroy": 3500, + "cost": 25, + "force_grow": 76, + "strategy_grow": 56, + "defense_grow": 69, + "speed_grow": 42, + "destroy_grow": 25, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 31, + "star": 4, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "董白", + "cfgId": 100592, + "force": 8900, + "strategy": 7300, + "defense": 8800, + "speed": 8900, + "destroy": 2100, + "cost": 25, + "force_grow": 85, + "strategy_grow": 57, + "defense_grow": 87, + "speed_grow": 83, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 41, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "张绣", + "cfgId": 100593, + "force": 8900, + "strategy": 7300, + "defense": 8800, + "speed": 8900, + "destroy": 2100, + "cost": 25, + "force_grow": 85, + "strategy_grow": 57, + "defense_grow": 87, + "speed_grow": 83, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 38, + "star": 4, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "刘虞", + "cfgId": 100104, + "force": 7700, + "strategy": 7900, + "defense": 8100, + "speed": 5900, + "destroy": 1700, + "cost": 15, + "force_grow": 55, + "strategy_grow": 59, + "defense_grow": 61, + "speed_grow": 59, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 467, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "王允", + "cfgId": 100105, + "force": 3700, + "strategy": 8000, + "defense": 5100, + "speed": 3900, + "destroy": 3000, + "cost": 25, + "force_grow": 25, + "strategy_grow": 69, + "defense_grow": 50, + "speed_grow": 47, + "destroy_grow": 29, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 449, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 2 + }, + { + "name": "陶谦", + "cfgId": 100106, + "force": 2700, + "strategy": 5900, + "defense": 4800, + "speed": 8000, + "destroy": 1300, + "cost": 20, + "force_grow": 25, + "strategy_grow": 59, + "defense_grow": 41, + "speed_grow": 79, + "destroy_grow": 6, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 363, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "陈宫", + "cfgId": 100109, + "force": 4100, + "strategy": 7100, + "defense": 5100, + "speed": 5900, + "destroy": 3100, + "cost": 20, + "force_grow": 56, + "strategy_grow": 69, + "defense_grow": 61, + "speed_grow": 59, + "destroy_grow": 30, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 318, + "star": 3, + "arms": [ + 2, + 5, + 8 + ], + "camp": 1 + }, + { + "name": "李肃", + "cfgId": 100113, + "force": 4100, + "strategy": 6800, + "defense": 6100, + "speed": 6000, + "destroy": 3000, + "cost": 20, + "force_grow": 49, + "strategy_grow": 59, + "defense_grow": 61, + "speed_grow": 59, + "destroy_grow": 31, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 363, + "star": 3, + "arms": [ + 2, + 5, + 8 + ], + "camp": 1 + }, + { + "name": "成公英", + "cfgId": 100125, + "force": 5100, + "strategy": 3800, + "defense": 4100, + "speed": 3000, + "destroy": 1300, + "cost": 20, + "force_grow": 48, + "strategy_grow": 29, + "defense_grow": 51, + "speed_grow": 28, + "destroy_grow": 8, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 390, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "祢衡", + "cfgId": 100126, + "force": 2100, + "strategy": 7500, + "defense": 3800, + "speed": 2500, + "destroy": 1300, + "cost": 20, + "force_grow": 28, + "strategy_grow": 60, + "defense_grow": 41, + "speed_grow": 19, + "destroy_grow": 15, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 474, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "马良", + "cfgId": 100132, + "force": 2800, + "strategy": 8500, + "defense": 3500, + "speed": 2600, + "destroy": 1200, + "cost": 25, + "force_grow": 43, + "strategy_grow": 80, + "defense_grow": 35, + "speed_grow": 25, + "destroy_grow": 12, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 376, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "陈到", + "cfgId": 100133, + "force": 8500, + "strategy": 4500, + "defense": 7500, + "speed": 3600, + "destroy": 2500, + "cost": 25, + "force_grow": 80, + "strategy_grow": 38, + "defense_grow": 80, + "speed_grow": 29, + "destroy_grow": 22, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 318, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "吴兰", + "cfgId": 100136, + "force": 5800, + "strategy": 3500, + "defense": 4500, + "speed": 8600, + "destroy": 800, + "cost": 25, + "force_grow": 39, + "strategy_grow": 33, + "defense_grow": 55, + "speed_grow": 89, + "destroy_grow": 3, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 318, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "雷铜", + "cfgId": 100137, + "force": 7000, + "strategy": 6500, + "defense": 6300, + "speed": 3600, + "destroy": 1200, + "cost": 20, + "force_grow": 53, + "strategy_grow": 50, + "defense_grow": 65, + "speed_grow": 20, + "destroy_grow": 15, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 384, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "邓忠", + "cfgId": 100146, + "force": 8100, + "strategy": 3200, + "defense": 5200, + "speed": 3700, + "destroy": 1100, + "cost": 20, + "force_grow": 75, + "strategy_grow": 43, + "defense_grow": 66, + "speed_grow": 28, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 438, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "曹洪", + "cfgId": 100147, + "force": 8100, + "strategy": 7200, + "defense": 8200, + "speed": 8700, + "destroy": 900, + "cost": 20, + "force_grow": 75, + "strategy_grow": 71, + "defense_grow": 72, + "speed_grow": 80, + "destroy_grow": 5, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 376, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "荀彧", + "cfgId": 100149, + "force": 3100, + "strategy": 9200, + "defense": 5200, + "speed": 3100, + "destroy": 300, + "cost": 25, + "force_grow": 45, + "strategy_grow": 89, + "defense_grow": 46, + "speed_grow": 35, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 470, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "荀攸", + "cfgId": 100150, + "force": 3500, + "strategy": 9200, + "defense": 4200, + "speed": 3100, + "destroy": 1500, + "cost": 20, + "force_grow": 41, + "strategy_grow": 95, + "defense_grow": 38, + "speed_grow": 38, + "destroy_grow": 15, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 480, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "曹真", + "cfgId": 100151, + "force": 7100, + "strategy": 6200, + "defense": 7200, + "speed": 8700, + "destroy": 300, + "cost": 20, + "force_grow": 75, + "strategy_grow": 53, + "defense_grow": 76, + "speed_grow": 88, + "destroy_grow": 3, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 342, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "满宠", + "cfgId": 100152, + "force": 4100, + "strategy": 8200, + "defense": 5200, + "speed": 5700, + "destroy": 300, + "cost": 20, + "force_grow": 45, + "strategy_grow": 83, + "defense_grow": 56, + "speed_grow": 48, + "destroy_grow": 11, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 448, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "曹睿", + "cfgId": 100153, + "force": 5600, + "strategy": 6200, + "defense": 5200, + "speed": 4700, + "destroy": 500, + "cost": 15, + "force_grow": 55, + "strategy_grow": 63, + "defense_grow": 66, + "speed_grow": 48, + "destroy_grow": 6, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 307, + "star": 3, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "钟会", + "cfgId": 100154, + "force": 5600, + "strategy": 9200, + "defense": 6200, + "speed": 3300, + "destroy": 2500, + "cost": 15, + "force_grow": 55, + "strategy_grow": 87, + "defense_grow": 56, + "speed_grow": 38, + "destroy_grow": 26, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 455, + "star": 3, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "赵忠", + "cfgId": 100169, + "force": 2600, + "strategy": 3300, + "defense": 2200, + "speed": 8800, + "destroy": 200, + "cost": 15, + "force_grow": 15, + "strategy_grow": 20, + "defense_grow": 16, + "speed_grow": 89, + "destroy_grow": 2, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 496, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "夏恽", + "cfgId": 100170, + "force": 2600, + "strategy": 3300, + "defense": 2200, + "speed": 8800, + "destroy": 200, + "cost": 15, + "force_grow": 15, + "strategy_grow": 20, + "defense_grow": 16, + "speed_grow": 89, + "destroy_grow": 2, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 493, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "郭胜", + "cfgId": 100171, + "force": 2600, + "strategy": 3300, + "defense": 2200, + "speed": 8800, + "destroy": 200, + "cost": 15, + "force_grow": 15, + "strategy_grow": 20, + "defense_grow": 16, + "speed_grow": 89, + "destroy_grow": 2, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 313, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "毕岚", + "cfgId": 100172, + "force": 2600, + "strategy": 3300, + "defense": 2200, + "speed": 8800, + "destroy": 200, + "cost": 15, + "force_grow": 15, + "strategy_grow": 20, + "defense_grow": 16, + "speed_grow": 89, + "destroy_grow": 2, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 302, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "段珪", + "cfgId": 100173, + "force": 2600, + "strategy": 3300, + "defense": 2200, + "speed": 8800, + "destroy": 200, + "cost": 15, + "force_grow": 15, + "strategy_grow": 20, + "defense_grow": 16, + "speed_grow": 89, + "destroy_grow": 2, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 413, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "高望", + "cfgId": 100174, + "force": 2600, + "strategy": 3300, + "defense": 2200, + "speed": 8800, + "destroy": 200, + "cost": 15, + "force_grow": 15, + "strategy_grow": 20, + "defense_grow": 16, + "speed_grow": 89, + "destroy_grow": 2, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 427, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "张恭", + "cfgId": 100175, + "force": 2600, + "strategy": 3300, + "defense": 2200, + "speed": 8800, + "destroy": 200, + "cost": 15, + "force_grow": 15, + "strategy_grow": 20, + "defense_grow": 16, + "speed_grow": 89, + "destroy_grow": 2, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 330, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "韩悝", + "cfgId": 100176, + "force": 2600, + "strategy": 3300, + "defense": 2200, + "speed": 8800, + "destroy": 200, + "cost": 15, + "force_grow": 15, + "strategy_grow": 20, + "defense_grow": 16, + "speed_grow": 89, + "destroy_grow": 2, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 385, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "宋典", + "cfgId": 100177, + "force": 2600, + "strategy": 3300, + "defense": 2200, + "speed": 8800, + "destroy": 200, + "cost": 15, + "force_grow": 15, + "strategy_grow": 20, + "defense_grow": 16, + "speed_grow": 89, + "destroy_grow": 2, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 404, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "马致远", + "cfgId": 100181, + "force": 2100, + "strategy": 3100, + "defense": 3100, + "speed": 8100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 89, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 334, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "裴元绍", + "cfgId": 100182, + "force": 2100, + "strategy": 3100, + "defense": 3100, + "speed": 8100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 89, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 315, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "马元义", + "cfgId": 100183, + "force": 2100, + "strategy": 3100, + "defense": 3100, + "speed": 8100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 89, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 303, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "李傕", + "cfgId": 100184, + "force": 2100, + "strategy": 3100, + "defense": 3100, + "speed": 8100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 89, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 393, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "许攸", + "cfgId": 100185, + "force": 2100, + "strategy": 3100, + "defense": 3100, + "speed": 8100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 89, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 345, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "审配", + "cfgId": 100186, + "force": 2100, + "strategy": 3100, + "defense": 3100, + "speed": 8100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 89, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 425, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "陈琳", + "cfgId": 100187, + "force": 2100, + "strategy": 3100, + "defense": 3100, + "speed": 2100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 29, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 346, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 2 + }, + { + "name": "郭图", + "cfgId": 100188, + "force": 3100, + "strategy": 8100, + "defense": 3100, + "speed": 6100, + "destroy": 1200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 39, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 407, + "star": 3, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "朱治", + "cfgId": 100217, + "force": 5600, + "strategy": 5200, + "defense": 6200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 431, + "star": 3, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "凌操", + "cfgId": 100218, + "force": 5600, + "strategy": 5200, + "defense": 6200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 465, + "star": 3, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "阚沢", + "cfgId": 100219, + "force": 5600, + "strategy": 5200, + "defense": 6200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 481, + "star": 3, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "虞翻", + "cfgId": 100220, + "force": 5600, + "strategy": 5200, + "defense": 6200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 375, + "star": 3, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "朱桓", + "cfgId": 100221, + "force": 5600, + "strategy": 5200, + "defense": 6200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 331, + "star": 3, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "陈群", + "cfgId": 100227, + "force": 4800, + "strategy": 7500, + "defense": 4100, + "speed": 8100, + "destroy": 300, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 442, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "李通", + "cfgId": 100228, + "force": 4800, + "strategy": 7500, + "defense": 4100, + "speed": 8100, + "destroy": 300, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 495, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "朱灵", + "cfgId": 100229, + "force": 4800, + "strategy": 7500, + "defense": 4100, + "speed": 8100, + "destroy": 300, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 355, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "牛金", + "cfgId": 100230, + "force": 4800, + "strategy": 7500, + "defense": 4100, + "speed": 8100, + "destroy": 300, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 421, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "蔡瑁", + "cfgId": 100231, + "force": 4800, + "strategy": 7500, + "defense": 4100, + "speed": 8100, + "destroy": 300, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 423, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "蒋济", + "cfgId": 100232, + "force": 4800, + "strategy": 7500, + "defense": 4100, + "speed": 8100, + "destroy": 300, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 340, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "贾逵", + "cfgId": 100233, + "force": 4800, + "strategy": 7500, + "defense": 4100, + "speed": 8100, + "destroy": 300, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 364, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "王凌", + "cfgId": 100234, + "force": 4800, + "strategy": 7500, + "defense": 4100, + "speed": 8100, + "destroy": 300, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 439, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "孟达", + "cfgId": 100254, + "force": 6500, + "strategy": 3200, + "defense": 7500, + "speed": 3800, + "destroy": 200, + "cost": 25, + "force_grow": 52, + "strategy_grow": 33, + "defense_grow": 65, + "speed_grow": 36, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 416, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "刘封", + "cfgId": 100255, + "force": 6500, + "strategy": 3200, + "defense": 7500, + "speed": 3800, + "destroy": 200, + "cost": 25, + "force_grow": 52, + "strategy_grow": 33, + "defense_grow": 65, + "speed_grow": 36, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 362, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "廖化", + "cfgId": 100256, + "force": 6500, + "strategy": 3200, + "defense": 7500, + "speed": 3800, + "destroy": 200, + "cost": 25, + "force_grow": 52, + "strategy_grow": 33, + "defense_grow": 65, + "speed_grow": 36, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 310, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "蒋琬", + "cfgId": 100257, + "force": 6500, + "strategy": 3200, + "defense": 7500, + "speed": 3800, + "destroy": 200, + "cost": 25, + "force_grow": 52, + "strategy_grow": 33, + "defense_grow": 65, + "speed_grow": 36, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 483, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "费祎", + "cfgId": 100258, + "force": 6500, + "strategy": 3200, + "defense": 7500, + "speed": 3800, + "destroy": 200, + "cost": 25, + "force_grow": 52, + "strategy_grow": 33, + "defense_grow": 65, + "speed_grow": 36, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 338, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "邓茂", + "cfgId": 100270, + "force": 3100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 1200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 88, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 435, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 2 + }, + { + "name": "袁氏兄弟", + "cfgId": 100271, + "force": 3100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 1200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 88, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 412, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 2 + }, + { + "name": "审配", + "cfgId": 100272, + "force": 3100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 1200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 88, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 328, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 2 + }, + { + "name": "黄祖", + "cfgId": 100279, + "force": 3100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 1200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 38, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 384, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "汉少帝", + "cfgId": 100414, + "force": 2600, + "strategy": 3300, + "defense": 2200, + "speed": 8800, + "destroy": 200, + "cost": 15, + "force_grow": 15, + "strategy_grow": 20, + "defense_grow": 16, + "speed_grow": 89, + "destroy_grow": 2, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 363, + "star": 3, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "阿会喃", + "cfgId": 100492, + "force": 5800, + "strategy": 3500, + "defense": 2900, + "speed": 4100, + "destroy": 1100, + "cost": 35, + "force_grow": 48, + "strategy_grow": 65, + "defense_grow": 57, + "speed_grow": 56, + "destroy_grow": 13, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 481, + "star": 3, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "戏志才", + "cfgId": 100502, + "force": 3500, + "strategy": 2500, + "defense": 4900, + "speed": 3800, + "destroy": 1300, + "cost": 15, + "force_grow": 91, + "strategy_grow": 18, + "defense_grow": 28, + "speed_grow": 30, + "destroy_grow": 12, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 341, + "star": 3, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "糜竺", + "cfgId": 100198, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 2900, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 25, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 439, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "伊籍", + "cfgId": 100199, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 2900, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 25, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 574, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "孙乾", + "cfgId": 100200, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 2900, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 25, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 412, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "王平", + "cfgId": 100202, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 2900, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 25, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 470, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "吴懿", + "cfgId": 100203, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 2900, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 25, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 512, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "陈登", + "cfgId": 100204, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 2900, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 25, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 505, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "曹昂", + "cfgId": 100208, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 8500, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 570, + "star": 2, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "曹彰", + "cfgId": 100209, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 8500, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 535, + "star": 2, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "曹丕", + "cfgId": 100210, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 8500, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 556, + "star": 2, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "刘晔", + "cfgId": 100211, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 8500, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 553, + "star": 2, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "杨修", + "cfgId": 100212, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 8500, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 414, + "star": 2, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "曹休", + "cfgId": 100213, + "force": 1800, + "strategy": 3500, + "defense": 4100, + "speed": 8500, + "destroy": 200, + "cost": 15, + "force_grow": 10, + "strategy_grow": 20, + "defense_grow": 30, + "speed_grow": 85, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 588, + "star": 2, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "顾雍", + "cfgId": 100222, + "force": 5600, + "strategy": 5200, + "defense": 6200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 421, + "star": 2, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "孙静", + "cfgId": 100223, + "force": 5600, + "strategy": 5200, + "defense": 6200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 513, + "star": 2, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "军士", + "cfgId": 100239, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 428, + "star": 2, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "吕范", + "cfgId": 100240, + "force": 3600, + "strategy": 4200, + "defense": 4200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 507, + "star": 2, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "宋谦", + "cfgId": 100241, + "force": 3600, + "strategy": 4200, + "defense": 4200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 540, + "star": 2, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "祖茂", + "cfgId": 100242, + "force": 3600, + "strategy": 4200, + "defense": 4200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 540, + "star": 2, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "孙瑜", + "cfgId": 100247, + "force": 3600, + "strategy": 4200, + "defense": 4200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 424, + "star": 2, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "骆统", + "cfgId": 100248, + "force": 3600, + "strategy": 4200, + "defense": 4200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 470, + "star": 2, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "全琮", + "cfgId": 100249, + "force": 3600, + "strategy": 4200, + "defense": 4200, + "speed": 4800, + "destroy": 1200, + "cost": 15, + "force_grow": 55, + "strategy_grow": 43, + "defense_grow": 46, + "speed_grow": 43, + "destroy_grow": 16, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 516, + "star": 2, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "王子服", + "cfgId": 100280, + "force": 2100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 18, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 500, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "许劭", + "cfgId": 100281, + "force": 2100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 18, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 518, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "刘琦", + "cfgId": 100282, + "force": 2100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 18, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 449, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "曹豹", + "cfgId": 100283, + "force": 2100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 18, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 494, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "郑泰", + "cfgId": 100284, + "force": 2100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 18, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 554, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "刘焉", + "cfgId": 100285, + "force": 2100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 18, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 507, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "王朗", + "cfgId": 100286, + "force": 2100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 18, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 562, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "田豫", + "cfgId": 100287, + "force": 2100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 18, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 401, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "杨彪", + "cfgId": 100288, + "force": 2100, + "strategy": 2100, + "defense": 2100, + "speed": 3100, + "destroy": 200, + "cost": 15, + "force_grow": 30, + "strategy_grow": 22, + "defense_grow": 21, + "speed_grow": 18, + "destroy_grow": 20, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 580, + "star": 2, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "军士", + "cfgId": 100128, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 592, + "star": 1, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "军士", + "cfgId": 100142, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 547, + "star": 1, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "军士", + "cfgId": 100155, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 670, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "军士", + "cfgId": 100167, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 656, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "军士", + "cfgId": 100178, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 577, + "star": 1, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + }, + { + "name": "军士", + "cfgId": 100179, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 591, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 1 + }, + { + "name": "军士", + "cfgId": 100180, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 682, + "star": 1, + "arms": [ + 3, + 6, + 9 + ], + "camp": 1 + }, + { + "name": "军士", + "cfgId": 100189, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 534, + "star": 1, + "arms": [ + 3, + 6, + 9 + ], + "camp": 2 + }, + { + "name": "军士", + "cfgId": 100190, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 610, + "star": 1, + "arms": [ + 1, + 4, + 7 + ], + "camp": 2 + }, + { + "name": "军士", + "cfgId": 100191, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 524, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "黄巾军", + "cfgId": 100192, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 682, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "黄巾军", + "cfgId": 100193, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 564, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "黄巾军", + "cfgId": 100194, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 649, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "黄巾军", + "cfgId": 100195, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 697, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "黄巾军", + "cfgId": 100196, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 552, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "黄巾军", + "cfgId": 100197, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 600, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 2 + }, + { + "name": "军士", + "cfgId": 100205, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 663, + "star": 1, + "arms": [ + 3, + 6, + 9 + ], + "camp": 4 + }, + { + "name": "军士", + "cfgId": 100206, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 617, + "star": 1, + "arms": [ + 1, + 4, + 7 + ], + "camp": 4 + }, + { + "name": "军士", + "cfgId": 100207, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 600, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 4 + }, + { + "name": "军士", + "cfgId": 100214, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 613, + "star": 1, + "arms": [ + 3, + 6, + 9 + ], + "camp": 3 + }, + { + "name": "军士", + "cfgId": 100215, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 538, + "star": 1, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "军士", + "cfgId": 100216, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 576, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 3 + }, + { + "name": "军士", + "cfgId": 100224, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 626, + "star": 1, + "arms": [ + 3, + 6, + 9 + ], + "camp": 5 + }, + { + "name": "军士", + "cfgId": 100225, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 641, + "star": 1, + "arms": [ + 1, + 4, + 7 + ], + "camp": 5 + }, + { + "name": "军士", + "cfgId": 100226, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 604, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "军士", + "cfgId": 100253, + "force": 100, + "strategy": 100, + "defense": 100, + "speed": 100, + "destroy": 100, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 686, + "star": 1, + "arms": [ + 2, + 5, + 8 + ], + "camp": 5 + }, + { + "name": "军士", + "cfgId": 100264, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 562, + "star": 1, + "arms": [ + 1, + 4, + 7 + ], + "camp": 3 + }, + { + "name": "军士", + "cfgId": 100276, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 530, + "star": 1, + "arms": [ + 1, + 4, + 7 + ], + "camp": 2 + }, + { + "name": "山贼", + "cfgId": 100277, + "force": 1000, + "strategy": 1000, + "defense": 1000, + "speed": 1000, + "destroy": 1000, + "cost": 100, + "force_grow": 10, + "strategy_grow": 10, + "defense_grow": 10, + "speed_grow": 10, + "destroy_grow": 10, + "physical_power_limit": 100, + "cost_physical_power": 1, + "probability": 599, + "star": 1, + "arms": [ + 1, + 4, + 7 + ], + "camp": 1 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/general/general_arms.json b/data/conf/json/general/general_arms.json new file mode 100644 index 0000000..75ab61c --- /dev/null +++ b/data/conf/json/general/general_arms.json @@ -0,0 +1,117 @@ +{ + "title": "兵种配置表", + "arms":[ + { + "id": 1, + "name": "步兵", + "condition":{ + "level": 1, + "star_lv": 0 + }, + "change_cost": { + "gold": 1000 + }, + "harm_ratio": [100, 110, 90, 95, 105, 85, 90, 100, 80] + }, + { + "id": 2, + "name": "弓兵", + "condition":{ + "level": 1, + "star_lv": 0 + }, + "change_cost": { + "gold": 1000 + }, + "harm_ratio":[90, 100, 110, 85, 95, 105, 80, 90, 100] + }, + { + "id": 3, + "name": "骑兵", + "condition":{ + "level": 1, + "star_lv": 0 + }, + "change_cost": { + "gold": 1000 + }, + "harm_ratio": [110, 90, 100, 105, 85, 95, 100, 80, 90] + }, + { + "id": 4, + "name": "轻步兵", + "condition":{ + "level": 3, + "star_lv": 0 + }, + "change_cost": { + "gold": 5000 + }, + "harm_ratio": [105, 115, 95, 100, 110, 90, 95, 105, 85] + }, + { + "id": 5, + "name": "长弓兵", + "condition":{ + "level": 3, + "star_lv": 0 + }, + "change_cost": { + "gold": 6000 + }, + "harm_ratio": [95, 105, 115, 90, 100, 110, 85, 95, 105] + }, + { + "id": 6, + "name": "轻骑兵", + "condition":{ + "level": 3, + "star_lv": 0 + }, + "change_cost": { + "gold": 4000 + }, + "harm_ratio": [115, 95, 105, 110, 90, 100, 105, 85, 95] + }, + { + "id": 7, + "name": "重甲兵", + "condition":{ + "level": 7, + "star_lv": 0 + }, + "change_cost": { + "gold": 14000 + }, + "harm_ratio": [110, 120, 90, 105, 115, 95, 100, 110, 90] + }, + + { + "id": 8, + "name": "弩兵", + "condition":{ + "level": 3, + "star_lv": 0 + }, + "change_cost": { + "gold": 6000 + }, + "harm_ratio": [100, 110, 120, 95, 105, 115, 90, 100, 110] + }, + + { + "id": 9, + "name": "重骑兵", + "condition":{ + "level": 7, + "star_lv": 0 + }, + "change_cost": { + "gold": 18000 + }, + "harm_ratio": [120, 100, 110, 105, 95, 105, 110, 90, 100] + } + + + ] +} \ No newline at end of file diff --git a/data/conf/json/general/general_basic.json b/data/conf/json/general/general_basic.json new file mode 100644 index 0000000..abc8e53 --- /dev/null +++ b/data/conf/json/general/general_basic.json @@ -0,0 +1,105 @@ +{ + "title": "将领基本配置表", + "levels":[ + { + "level": 1, + "exp": 0, + "soldiers": 100 + }, + { + "level": 2, + "exp": 1000, + "soldiers": 200 + }, + { + "level": 3, + "exp": 2000, + "soldiers": 300 + }, + { + "level": 4, + "exp": 3000, + "soldiers": 400 + }, + { + "level": 5, + "exp": 4000, + "soldiers": 500 + }, + { + "level": 6, + "exp": 5000, + "soldiers": 600 + }, + { + "level": 7, + "exp": 6000, + "soldiers": 700 + }, + { + "level": 8, + "exp": 7500, + "soldiers": 800 + }, + { + "level": 9, + "exp": 9000, + "soldiers": 900 + }, + { + "level": 10, + "exp": 11000, + "soldiers": 1000 + }, + { + "level": 11, + "exp": 12500, + "soldiers": 1100 + }, + { + "level": 12, + "exp": 15000, + "soldiers": 1200 + }, + { + "level": 13, + "exp": 17000, + "soldiers": 1300 + }, + { + "level": 14, + "exp": 19000, + "soldiers": 1400 + }, + { + "level": 15, + "exp": 23000, + "soldiers": 1500 + }, { + "level": 16, + "exp": 26000, + "soldiers": 1600 + }, + { + "level": 17, + "exp": 29000, + "soldiers": 1700 + }, + { + "level": 18, + "exp": 31000, + "soldiers": 1800 + }, + { + "level": 19, + "exp": 35000, + "soldiers": 1900 + }, + { + "level": 20, + "exp": 50000, + "soldiers": 2000 + } + + ] +} \ No newline at end of file diff --git a/data/conf/json/map_build.json b/data/conf/json/map_build.json new file mode 100644 index 0000000..0c4ba2d --- /dev/null +++ b/data/conf/json/map_build.json @@ -0,0 +1,439 @@ +{ + "title": "地图资源配置", + "cfg":[ + {"type": 50, + "des": "系统要塞", + "name": "要塞", + "level": 5, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 30000, + "defender": 1 + }, + {"type": 51, + "name": "城区", + "level": 1, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 100000, + "defender": 5 + }, + {"type": 51, + "name": "城区", + "level": 2, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 200000, + "defender": 5 + }, + {"type": 51, + "name": "城区", + "level": 3, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 300000, + "defender": 5 + }, + {"type": 51, + "name": "城区", + "level": 4, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 400000, + "defender": 5 + }, + {"type": 51, + "name": "城区", + "level": 5, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 500000, + "defender": 5 + }, + {"type": 51, + "name": "城区", + "level": 6, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 600000, + "defender": 5 + }, + {"type": 51, + "name": "城区", + "level": 7, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 700000, + "defender": 5 + }, + {"type": 51, + "name": "城区", + "level": 8, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 800000, + "defender": 5 + }, + {"type": 51, + "name": "城区", + "level": 9, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 900000, + "defender": 5 + }, + {"type": 51, + "name": "城区", + "level": 10, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 1000000, + "defender": 5 + }, + {"type": 52, + "name": "土地Lv.1", + "level": 1, + "grain": 100, + "wood": 100, + "iron": 100, + "stone": 100, + "durable": 10000, + "defender": 1 + }, + {"type": 52, + "name": "土地Lv.2", + "level": 2, + "grain": 200, + "wood": 200, + "iron": 200, + "stone": 200, + "durable": 10000, + "defender": 2 + }, + {"type": 52, + "name": "土地Lv.3", + "level": 3, + "grain": 300, + "wood": 300, + "iron": 300, + "stone": 300, + "durable": 100, + "defender": 3 + }, + {"type": 52, + "name": "土地Lv.4", + "level": 4, + "grain": 0, + "wood": 4000, + "iron": 0, + "stone": 0, + "durable": 10000, + "defender": 4 + }, + {"type": 52, + "name": "土地Lv.5", + "level": 5, + "grain": 0, + "wood": 5000, + "iron": 0, + "stone": 0, + "durable": 10000, + "defender": 5 + }, + {"type": 52, + "name": "土地Lv.6", + "level": 6, + "grain": 0, + "wood": 1000, + "iron": 0, + "stone": 0, + "durable": 10000, + "defender": 6 + }, + {"type": 52, + "name": "土地Lv.7", + "level": 7, + "grain": 0, + "wood": 2000, + "iron": 0, + "stone": 0, + "durable": 10000, + "defender": 7 + }, + {"type": 52, + "name": "土地Lv.8", + "level": 8, + "grain": 0, + "wood": 3000, + "iron": 0, + "stone": 0, + "durable": 100, + "defender": 8 + }, + {"type": 53, + "name": "土地Lv.1", + "level": 1, + "grain": 100, + "wood": 100, + "iron": 100, + "stone": 100, + "durable": 10000, + "defender": 1 + }, + {"type": 53, + "name": "土地Lv.2", + "level": 2, + "grain": 200, + "wood": 200, + "iron": 200, + "stone": 200, + "durable": 10000, + "defender": 2 + }, + {"type": 53, + "name": "土地Lv.3", + "level": 3, + "grain": 300, + "wood": 300, + "iron": 300, + "stone": 300, + "durable": 100, + "defender": 3 + }, + {"type": 53, + "name": "土地Lv.4", + "level": 4, + "grain": 0, + "wood": 0, + "iron": 4000, + "stone": 0, + "durable": 10000, + "defender": 4 + }, + {"type": 53, + "name": "土地Lv.5", + "level": 5, + "grain": 0, + "wood": 0, + "iron": 5000, + "stone": 0, + "durable": 100, + "defender": 5 + }, + {"type": 53, + "name": "土地Lv.6", + "level": 6, + "grain": 0, + "wood": 0, + "iron": 6000, + "stone": 0, + "durable": 10000, + "defender": 6 + }, + {"type": 53, + "name": "土地Lv.7", + "level": 7, + "grain": 0, + "wood": 0, + "iron": 7000, + "stone": 0, + "durable": 10000, + "defender": 7 + }, + {"type": 53, + "name": "土地Lv.8", + "level": 8, + "grain": 0, + "wood": 0, + "iron": 8000, + "stone": 0, + "durable": 10000, + "defender": 8 + }, + {"type": 54, + "name": "土地Lv.1", + "level": 1, + "grain": 100, + "wood": 100, + "iron": 100, + "stone": 100, + "durable": 10000, + "defender": 1 + }, + {"type": 54, + "name": "土地Lv.2", + "level": 2, + "grain": 200, + "wood": 200, + "iron": 200, + "stone": 200, + "durable": 10000, + "defender": 2 + }, + {"type": 54, + "name": "土地Lv.3", + "level": 3, + "grain": 300, + "wood": 300, + "iron": 300, + "stone": 300, + "durable": 100, + "defender": 3 + }, + {"type": 54, + "name": "土地Lv.4", + "level": 4, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 1000, + "durable": 10000, + "defender": 1 + }, + {"type": 54, + "name": "土地Lv.5", + "level": 5, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 5000, + "durable": 10000, + "defender": 5 + }, + {"type": 54, + "name": "土地Lv.6", + "level": 6, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 6000, + "durable": 10000, + "defender": 6 + }, + {"type": 54, + "name": "土地Lv.7", + "level": 7, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 7000, + "durable": 10000, + "defender": 7 + }, + {"type": 54, + "name": "土地Lv.8", + "level": 8, + "grain": 0, + "wood": 0, + "iron": 0, + "stone": 8000, + "durable": 10000, + "defender": 8 + }, + + + + {"type": 55, + "name": "土地Lv.1", + "level": 1, + "grain": 100, + "wood": 100, + "iron": 100, + "stone": 100, + "durable": 10000, + "defender": 1 + }, + {"type": 55, + "name": "土地Lv.2", + "level": 2, + "grain": 200, + "wood": 200, + "iron": 200, + "stone": 200, + "durable": 10000, + "defender": 2 + }, + {"type": 55, + "name": "土地Lv.3", + "level": 3, + "grain": 300, + "wood": 300, + "iron": 300, + "stone": 300, + "durable": 100, + "defender": 3 + }, + {"type": 55, + "name": "土地Lv.4", + "level": 4, + "grain": 1000, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 10000, + "defender": 4 + }, + {"type": 55, + "name": "土地Lv.5", + "level": 5, + "grain": 5000, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 10000, + "defender": 5 + }, + {"type": 55, + "name": "土地Lv.6", + "level": 6, + "grain": 6000, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 10000, + "defender": 6 + }, + {"type": 55, + "name": "土地Lv.7", + "level": 7, + "grain": 7000, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 10000, + "defender": 7 + }, + {"type": 55, + "name": "土地Lv.8", + "level": 8, + "grain": 8000, + "wood": 0, + "iron": 0, + "stone": 0, + "durable": 10000, + "defender": 8 + } + ] +} \ No newline at end of file diff --git a/data/conf/json/map_build_custom.json b/data/conf/json/map_build_custom.json new file mode 100644 index 0000000..ef3997f --- /dev/null +++ b/data/conf/json/map_build_custom.json @@ -0,0 +1,43 @@ +{ + "title": "地图用户建设的建筑配置", + "cfg": [ + { + "type": 56, + "name": "要塞", + "levels": [ + { + "level": 1, + "durable": 10000, + "defender": 5, + "time": 20, + "need": { + "decree": 2, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "result": { + "army_cnt": 1 + } + }, + { + "level": 2, + "durable": 10000, + "defender": 5, + "time": 20, + "need": { + "decree": 3, + "grain": 1000, + "wood": 1000, + "iron": 1000, + "stone": 1000 + }, + "result": { + "army_cnt": 2 + } + } + ] + } + ] +} \ No newline at end of file diff --git a/data/conf/json/skill/beidong/baizhanjingbing.json b/data/conf/json/skill/beidong/baizhanjingbing.json new file mode 100644 index 0000000..cc922bc --- /dev/null +++ b/data/conf/json/skill/beidong/baizhanjingbing.json @@ -0,0 +1,75 @@ +{ + "cfgId": 201, + "name": "百战精兵", + "trigger": 2, + "target": 2, + "des": "使自身攻击属性提升%n%、防御属性提升%n%、谋略属性提升%n%、速度属性提升%n%", + "limit": 3, + "arms": [ + 1, + 4, + 7, + 2, + 5, + 8, + 3, + 6, + 9 + ], + + "include_effect": [ + 2,3,4,5 + ], + "levels": [ + { + "probability":30, + "effect_value": [50,50,50,50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50,50,50,50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50,50,50,50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50,50,50,50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50,50,50,50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50,50,50,50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50,50,50,50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50,50,50,50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50,50,50,50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50,50,50,50], + "effect_round": [0] + } + ] +} diff --git a/data/conf/json/skill/skill_outline.json b/data/conf/json/skill/skill_outline.json new file mode 100644 index 0000000..e053efe --- /dev/null +++ b/data/conf/json/skill/skill_outline.json @@ -0,0 +1,90 @@ +{ + "trigger_type": { + "des": "触发类型", + "list": [ + { + "type": 1, + "des": "主动" + }, + { + "type": 2, + "des": "被动" + }, + { + "type": 3, + "des": "追击" + }, + { + "type": 4, + "des": "指挥" + } + ] + }, + "effect_type": { + "des": "效果类型", + "list": [ + { + "type": 1, + "des": "伤害率", + "isRate": true + }, + { + "type": 2, + "des": "攻击", + "isRate": false + }, + { + "type": 3, + "des": "防御", + "isRate": false + }, + { + "type": 4, + "des": "谋略", + "isRate": false + }, + { + "type": 5, + "des": "速度", + "isRate": false + } + ] + }, + "target_type": { + "des": "作用目标类型", + "list": [ + { + "type": 1, + "des": "自己" + }, + { + "type": 2, + "des": "我军单体" + }, + { + "type": 3, + "des": "我军1-2个目标" + }, + { + "type": 4, + "des": "我军全体" + }, + { + "type": 5, + "des": "敌军单体" + }, + { + "type": 6, + "des": "敌军1-2个目标" + }, + { + "type": 7, + "des": "敌军2-3个目标" + }, + { + "type": 8, + "des": "敌军全体" + } + ] + } +} \ No newline at end of file diff --git a/data/conf/json/skill/zhihui/fengshi.json b/data/conf/json/skill/zhihui/fengshi.json new file mode 100644 index 0000000..b1efcc6 --- /dev/null +++ b/data/conf/json/skill/zhihui/fengshi.json @@ -0,0 +1,72 @@ +{ + "cfgId": 401, + "name": "锋矢", + "trigger": 4, + "target": 2, + "des": "战斗中,使我军全体进行普通攻击的伤害提升%n%", + "limit": 3, + "arms": [ + 2, + 5, + 8, + 3, + 6, + 9 + ], + + "include_effect": [ + 1 + ], + "levels": [ + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + } + ] +} diff --git a/data/conf/json/skill/zhudong/tuji.json b/data/conf/json/skill/zhudong/tuji.json new file mode 100644 index 0000000..8044fa7 --- /dev/null +++ b/data/conf/json/skill/zhudong/tuji.json @@ -0,0 +1,72 @@ +{ + "cfgId": 101, + "name": "突击", + "trigger": 1, + "target": 5, + "des": "对敌军单体发动一次攻击(伤害率`%n%%`)", + "limit": 3, + "arms": [ + 1, + 4, + 7, + 3, + 6, + 9 + ], + + "include_effect": [ + 1 + ], + "levels": [ + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + } + ] +} diff --git a/data/conf/json/skill/zhuiji/zhongzhan.json b/data/conf/json/skill/zhuiji/zhongzhan.json new file mode 100644 index 0000000..693d03c --- /dev/null +++ b/data/conf/json/skill/zhuiji/zhongzhan.json @@ -0,0 +1,72 @@ +{ + "cfgId": 301, + "name": "重斩", + "trigger": 3, + "target": 5, + "des": "普通攻击后,对攻击目标再次发动攻击(伤害率%n%%)", + "limit": 3, + "arms": [ + 1, + 4, + 7, + 3, + 6, + 9 + ], + + "include_effect": [ + 1 + ], + "levels": [ + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + }, + { + "probability":30, + "effect_value": [50], + "effect_round": [0] + } + ] +} diff --git a/data/conf/mapRes_0.json b/data/conf/mapRes_0.json new file mode 100644 index 0000000..01a54f1 --- /dev/null +++ b/data/conf/mapRes_0.json @@ -0,0 +1 @@ +{"w":200,"h":200,"list":[[53,6],[55,4],[52,7],[55,6],[54,6],[54,6],[55,7],[54,2],[53,2],[53,4],[52,6],[55,1],[52,6],[52,7],[54,6],[54,4],[55,6],[54,4],[52,4],[52,3],[54,8],[53,4],[54,4],[54,1],[52,5],[53,5],[55,4],[53,2],[55,2],[55,4],[53,2],[52,4],[54,4],[52,6],[53,1],[54,3],[55,6],[54,2],[53,7],[0,0],[0,0],[54,7],[52,2],[55,5],[53,7],[53,4],[52,6],[53,1],[52,7],[52,4],[52,5],[53,2],[55,2],[55,6],[55,3],[55,1],[53,6],[55,3],[0,0],[0,0],[0,0],[55,3],[52,6],[54,1],[52,2],[55,6],[55,1],[54,1],[55,6],[54,2],[53,6],[54,1],[53,5],[52,2],[53,6],[54,1],[53,5],[54,3],[52,1],[53,2],[53,6],[55,6],[50,5],[52,1],[53,2],[52,5],[54,1],[52,2],[53,7],[53,1],[54,1],[54,5],[53,7],[55,2],[52,1],[52,4],[52,1],[53,3],[53,3],[54,1],[55,5],[0,0],[55,2],[54,2],[53,1],[53,1],[53,1],[52,7],[52,1],[55,2],[53,1],[52,2],[52,5],[52,1],[54,2],[53,8],[55,4],[53,4],[55,7],[53,2],[52,1],[53,4],[52,6],[53,2],[52,5],[53,1],[54,1],[54,7],[55,1],[55,3],[52,4],[53,6],[52,2],[54,7],[55,3],[52,6],[53,1],[55,6],[54,2],[54,3],[52,5],[52,2],[52,7],[53,6],[55,1],[53,8],[55,5],[52,1],[55,7],[55,5],[55,1],[53,2],[54,7],[54,2],[54,1],[55,6],[55,2],[53,6],[53,2],[54,8],[54,1],[54,3],[54,4],[52,4],[52,2],[55,3],[55,4],[55,1],[55,1],[53,5],[55,1],[54,3],[54,5],[52,8],[54,2],[55,4],[54,2],[52,3],[55,2],[52,6],[55,1],[54,5],[52,3],[55,5],[55,6],[52,1],[53,2],[54,4],[53,5],[55,7],[54,6],[55,3],[55,7],[52,3],[53,2],[52,5],[53,3],[55,7],[53,2],[52,2],[52,4],[0,0],[0,0],[0,0],[54,3],[52,7],[52,5],[55,2],[52,2],[54,2],[52,3],[55,3],[53,7],[54,1],[53,4],[52,5],[52,6],[53,5],[55,2],[54,7],[55,2],[53,1],[55,5],[55,3],[55,3],[54,6],[54,6],[53,3],[52,6],[52,6],[53,7],[54,1],[55,5],[54,5],[55,8],[53,6],[54,5],[55,6],[53,4],[0,0],[0,0],[0,0],[0,0],[52,4],[55,5],[55,3],[55,1],[55,5],[53,2],[55,1],[53,2],[52,5],[54,7],[53,2],[53,2],[55,4],[55,7],[54,2],[0,0],[0,0],[0,0],[55,2],[52,3],[53,7],[52,2],[54,1],[55,2],[54,1],[53,2],[52,1],[54,8],[55,2],[54,3],[52,1],[53,4],[54,1],[52,6],[55,1],[52,7],[55,2],[55,2],[53,2],[54,6],[55,5],[53,2],[53,5],[52,6],[55,3],[55,3],[54,1],[52,1],[53,2],[53,6],[53,2],[52,4],[55,8],[55,3],[55,1],[52,2],[54,7],[52,1],[0,0],[52,5],[53,1],[54,3],[52,2],[54,1],[53,5],[53,7],[55,1],[55,2],[52,6],[55,2],[55,4],[52,7],[54,6],[53,2],[50,5],[54,1],[53,5],[55,2],[52,5],[50,5],[55,2],[52,1],[53,3],[53,1],[53,5],[55,5],[54,4],[52,3],[55,1],[52,1],[52,1],[52,4],[55,5],[53,7],[55,2],[52,1],[55,7],[54,4],[54,7],[54,6],[53,2],[54,3],[54,6],[55,2],[55,6],[52,3],[54,5],[54,5],[55,8],[52,6],[53,7],[55,4],[55,2],[53,5],[52,6],[55,1],[55,5],[53,2],[53,2],[55,5],[53,3],[54,2],[54,4],[50,5],[53,2],[52,2],[52,7],[52,3],[52,5],[55,5],[55,1],[55,1],[55,8],[54,5],[54,5],[55,1],[55,5],[53,1],[53,6],[54,1],[53,8],[54,7],[52,5],[53,1],[54,3],[53,2],[53,2],[54,7],[55,4],[53,8],[52,7],[55,3],[55,8],[52,6],[52,3],[52,7],[54,3],[52,1],[0,0],[0,0],[0,0],[53,5],[54,2],[55,2],[53,1],[54,3],[53,3],[52,2],[53,2],[55,4],[52,4],[52,7],[54,3],[52,1],[52,1],[53,6],[52,2],[52,1],[55,5],[53,8],[55,7],[55,1],[54,2],[52,1],[54,4],[52,4],[52,5],[55,7],[55,1],[55,2],[52,8],[53,5],[55,2],[53,7],[54,1],[55,6],[54,3],[0,0],[0,0],[0,0],[54,1],[52,4],[52,8],[53,1],[54,3],[53,4],[53,2],[52,2],[52,2],[55,6],[52,1],[54,1],[55,1],[53,2],[53,6],[0,0],[0,0],[0,0],[0,0],[55,2],[52,3],[53,6],[53,1],[54,1],[53,6],[52,1],[55,3],[52,1],[52,2],[53,1],[52,4],[54,5],[52,8],[55,1],[54,6],[53,2],[55,4],[53,4],[52,5],[53,4],[54,1],[52,6],[54,2],[54,1],[54,3],[52,6],[54,4],[52,3],[53,3],[53,6],[53,8],[55,8],[53,4],[52,3],[54,2],[52,1],[52,3],[54,8],[0,0],[0,0],[0,0],[53,2],[55,2],[52,1],[54,4],[52,3],[53,5],[54,1],[52,7],[52,7],[55,6],[55,5],[55,2],[54,3],[55,8],[52,1],[52,7],[53,2],[53,2],[55,2],[55,1],[52,3],[53,1],[54,5],[53,3],[54,6],[52,1],[53,2],[52,2],[54,7],[50,5],[52,2],[54,4],[52,2],[53,2],[55,2],[55,1],[52,7],[53,8],[54,2],[53,4],[53,7],[55,1],[53,1],[55,1],[55,7],[52,5],[53,5],[55,4],[55,3],[53,3],[53,5],[55,2],[53,3],[54,6],[52,1],[54,4],[54,1],[52,2],[52,7],[53,3],[55,3],[53,6],[53,1],[52,3],[54,1],[55,4],[54,4],[53,2],[55,2],[54,3],[53,7],[52,7],[54,2],[53,6],[55,6],[54,2],[54,3],[53,3],[55,1],[52,2],[54,6],[55,4],[52,1],[53,6],[53,6],[54,8],[52,8],[53,2],[55,1],[52,6],[54,2],[53,4],[54,4],[53,2],[54,2],[52,2],[55,2],[0,0],[0,0],[0,0],[55,5],[55,1],[53,1],[55,2],[52,6],[53,3],[55,7],[54,4],[54,2],[53,1],[53,2],[53,4],[54,2],[54,7],[54,5],[53,3],[52,1],[53,2],[55,2],[55,4],[54,2],[54,6],[55,1],[55,3],[52,3],[54,4],[52,1],[55,7],[54,3],[55,3],[52,5],[55,2],[54,3],[53,6],[52,7],[52,8],[0,0],[0,0],[0,0],[0,0],[54,3],[55,4],[55,4],[55,2],[52,1],[52,5],[55,2],[52,2],[53,7],[52,3],[55,6],[53,1],[53,6],[52,4],[55,2],[54,6],[55,6],[0,0],[0,0],[55,5],[50,5],[55,3],[53,2],[53,4],[54,3],[55,1],[54,4],[53,2],[53,8],[52,3],[53,3],[54,3],[55,5],[53,2],[55,6],[55,1],[53,4],[53,1],[55,5],[53,1],[52,2],[53,6],[55,6],[52,6],[53,8],[55,5],[55,1],[53,1],[53,2],[53,3],[55,2],[52,2],[55,2],[53,8],[55,2],[52,5],[53,6],[0,0],[55,3],[0,0],[52,4],[53,4],[55,1],[53,4],[54,7],[54,1],[55,2],[54,1],[55,7],[54,1],[52,2],[53,5],[55,2],[54,5],[53,2],[52,1],[55,2],[55,2],[54,1],[53,2],[55,7],[53,7],[55,5],[54,2],[55,4],[53,3],[53,2],[52,1],[52,5],[55,2],[52,3],[54,5],[55,2],[54,6],[53,5],[55,2],[55,3],[54,2],[54,2],[55,4],[55,5],[53,8],[52,3],[53,6],[55,7],[54,3],[54,7],[55,3],[53,2],[53,2],[55,1],[54,1],[52,1],[55,7],[53,1],[55,2],[53,6],[52,1],[53,3],[52,6],[54,4],[52,4],[55,1],[54,3],[52,3],[52,3],[54,3],[53,1],[54,2],[52,8],[52,2],[55,7],[53,3],[53,2],[55,4],[55,6],[54,5],[54,3],[55,2],[53,7],[54,3],[52,6],[52,6],[53,2],[54,4],[53,1],[53,1],[53,3],[55,3],[53,4],[54,1],[53,4],[54,3],[54,7],[55,5],[54,6],[52,4],[53,3],[54,6],[52,3],[0,0],[0,0],[54,2],[55,3],[55,3],[54,1],[52,5],[52,2],[55,3],[55,1],[53,6],[52,2],[52,6],[53,1],[54,1],[55,1],[55,4],[53,3],[52,2],[55,5],[54,3],[52,4],[53,3],[55,1],[53,3],[55,2],[53,6],[55,3],[54,3],[54,2],[54,1],[53,4],[55,6],[52,2],[54,1],[54,7],[52,2],[54,3],[53,5],[0,0],[0,0],[55,1],[53,7],[52,7],[53,2],[54,5],[55,3],[55,6],[55,5],[55,8],[54,5],[52,5],[55,4],[54,3],[52,4],[52,4],[55,2],[0,0],[0,0],[54,2],[52,3],[52,6],[53,2],[52,2],[55,3],[54,1],[52,3],[55,5],[53,7],[53,5],[54,2],[52,6],[52,2],[55,7],[54,2],[52,6],[52,3],[54,1],[55,2],[52,1],[54,4],[52,1],[52,5],[52,6],[52,3],[54,2],[53,6],[52,2],[52,1],[52,2],[54,6],[53,6],[54,6],[54,3],[52,4],[55,5],[52,3],[0,0],[0,0],[0,0],[0,0],[55,2],[54,1],[54,1],[55,6],[52,1],[55,5],[55,1],[52,1],[54,5],[53,1],[54,6],[54,1],[52,2],[52,6],[53,6],[54,6],[54,3],[52,2],[54,1],[52,8],[52,8],[55,1],[54,5],[52,4],[53,8],[53,7],[53,4],[52,5],[54,6],[55,4],[53,1],[53,5],[53,1],[55,6],[54,1],[55,2],[54,1],[55,8],[55,7],[54,3],[52,2],[55,3],[55,2],[53,5],[52,2],[55,1],[55,3],[55,6],[52,1],[54,2],[52,3],[52,7],[54,3],[55,4],[53,1],[54,6],[53,2],[55,7],[55,2],[54,6],[55,7],[55,6],[52,1],[52,5],[52,1],[55,3],[55,7],[53,6],[52,1],[50,5],[52,1],[52,3],[52,5],[52,3],[55,4],[52,8],[55,3],[54,4],[55,4],[55,5],[52,6],[54,5],[53,1],[53,2],[55,2],[52,4],[55,2],[53,1],[52,2],[55,4],[53,3],[53,3],[54,2],[54,6],[53,1],[55,2],[52,3],[52,1],[52,1],[0,0],[0,0],[53,2],[52,1],[53,7],[52,4],[54,1],[53,7],[52,7],[53,2],[54,1],[54,2],[53,5],[55,3],[54,7],[54,3],[52,5],[52,1],[54,6],[54,1],[55,2],[53,1],[52,2],[52,3],[52,2],[52,5],[54,5],[52,8],[54,3],[55,5],[55,3],[52,4],[53,6],[52,1],[53,7],[55,2],[52,4],[54,1],[53,2],[0,0],[0,0],[52,3],[52,4],[53,1],[53,2],[52,1],[50,5],[52,1],[53,1],[54,7],[53,7],[53,1],[52,3],[54,7],[52,1],[52,2],[54,1],[54,2],[0,0],[0,0],[53,2],[53,6],[53,8],[54,8],[0,0],[0,0],[0,0],[54,1],[53,4],[55,1],[55,6],[55,6],[53,2],[54,4],[52,1],[52,1],[54,6],[54,6],[52,1],[52,5],[55,3],[53,3],[54,1],[53,6],[53,3],[54,4],[52,5],[53,7],[53,4],[54,2],[53,4],[52,3],[55,4],[54,2],[54,3],[52,8],[54,7],[53,5],[55,7],[53,1],[0,0],[0,0],[55,7],[55,5],[52,2],[52,2],[55,8],[54,3],[54,3],[52,6],[55,2],[53,2],[55,4],[52,6],[54,1],[53,2],[54,3],[53,6],[52,3],[54,3],[55,2],[52,3],[53,5],[54,7],[52,1],[55,4],[55,2],[50,5],[55,2],[55,2],[52,3],[54,4],[53,1],[55,4],[53,4],[54,5],[52,5],[53,3],[53,7],[54,5],[54,3],[52,4],[54,3],[54,4],[53,1],[54,1],[55,1],[55,2],[55,1],[53,1],[54,7],[54,3],[52,2],[52,6],[55,5],[54,2],[54,2],[54,7],[53,6],[54,8],[54,7],[55,2],[52,6],[53,5],[52,3],[54,4],[54,7],[53,4],[52,3],[54,3],[54,5],[54,3],[53,2],[53,2],[52,2],[52,6],[55,3],[53,2],[53,1],[54,1],[53,1],[52,3],[53,7],[54,4],[54,2],[55,5],[53,6],[55,7],[52,7],[55,8],[55,6],[55,6],[55,4],[53,5],[52,4],[55,3],[54,2],[55,2],[52,8],[55,5],[55,2],[53,3],[0,0],[52,1],[55,1],[52,2],[52,2],[55,2],[54,3],[54,2],[55,2],[53,3],[53,3],[53,8],[52,1],[52,4],[55,2],[53,3],[53,7],[53,2],[55,8],[53,7],[54,7],[55,4],[52,3],[52,8],[55,7],[52,1],[54,6],[54,8],[55,6],[55,1],[55,2],[55,3],[52,6],[55,4],[54,3],[55,3],[55,1],[54,6],[0,0],[0,0],[53,1],[53,2],[54,3],[54,1],[53,1],[55,1],[55,1],[52,4],[54,1],[54,2],[52,1],[54,3],[52,1],[55,5],[52,4],[0,0],[0,0],[0,0],[53,1],[53,3],[52,1],[52,3],[0,0],[0,0],[0,0],[52,3],[54,5],[55,4],[55,3],[54,1],[55,4],[52,2],[52,3],[52,2],[54,8],[53,2],[55,6],[54,7],[54,5],[54,8],[55,1],[52,6],[52,2],[54,3],[55,3],[53,3],[52,5],[53,1],[52,5],[52,2],[55,6],[52,4],[50,5],[53,2],[55,2],[53,6],[52,1],[54,2],[0,0],[0,0],[53,8],[52,2],[54,6],[52,7],[54,3],[54,4],[53,3],[52,1],[55,2],[53,4],[54,3],[55,7],[54,2],[52,1],[55,4],[54,2],[54,3],[53,3],[54,2],[52,4],[52,3],[55,6],[52,1],[54,3],[55,7],[53,7],[53,3],[53,7],[53,4],[55,8],[52,2],[55,1],[53,2],[54,5],[53,2],[53,2],[54,3],[55,5],[55,3],[52,5],[55,3],[55,4],[54,2],[52,3],[53,1],[53,4],[53,2],[52,1],[55,4],[54,1],[53,4],[53,3],[53,2],[54,2],[52,2],[54,5],[53,5],[54,8],[55,4],[55,1],[53,2],[55,3],[52,3],[53,7],[53,4],[52,3],[54,5],[54,6],[52,4],[55,1],[54,4],[54,3],[54,3],[53,1],[53,1],[54,1],[52,6],[52,1],[55,2],[54,2],[53,2],[54,2],[54,6],[52,4],[53,2],[52,3],[55,5],[53,3],[53,2],[52,1],[54,3],[54,1],[53,4],[54,5],[52,2],[55,3],[53,7],[53,2],[55,3],[54,3],[54,5],[0,0],[0,0],[0,0],[53,4],[54,3],[54,1],[53,5],[53,7],[55,1],[53,6],[54,7],[54,6],[53,6],[54,1],[52,1],[53,4],[54,3],[55,5],[53,1],[53,2],[53,3],[54,1],[54,8],[53,1],[55,7],[54,6],[55,2],[54,1],[53,3],[52,1],[54,4],[54,8],[54,1],[53,2],[52,6],[55,6],[55,6],[52,6],[0,0],[0,0],[0,0],[0,0],[54,1],[55,1],[54,4],[55,4],[55,2],[53,2],[54,2],[55,1],[52,6],[53,6],[52,3],[52,5],[0,0],[0,0],[0,0],[54,6],[52,2],[55,7],[54,3],[0,0],[0,0],[0,0],[0,0],[55,4],[54,1],[53,1],[53,3],[53,3],[52,6],[52,5],[52,1],[55,2],[54,1],[53,6],[54,7],[53,2],[54,3],[52,3],[53,3],[53,4],[53,7],[54,2],[52,3],[52,6],[53,8],[53,7],[51,1],[54,1],[53,1],[52,3],[53,8],[54,2],[52,8],[55,2],[54,7],[54,3],[54,2],[0,0],[54,6],[55,5],[52,1],[54,7],[55,5],[55,4],[55,5],[54,2],[54,6],[54,4],[55,7],[54,4],[55,4],[53,2],[52,1],[55,1],[53,3],[55,4],[54,4],[53,1],[54,3],[54,1],[52,8],[55,7],[52,3],[55,1],[53,7],[52,1],[52,1],[53,4],[52,5],[53,4],[54,3],[53,4],[55,1],[55,5],[54,2],[52,2],[55,2],[52,3],[55,7],[55,3],[55,5],[54,3],[55,5],[54,5],[55,2],[54,7],[52,3],[52,6],[54,2],[54,4],[53,5],[53,6],[50,5],[54,5],[54,3],[52,1],[52,1],[55,1],[55,1],[54,7],[52,3],[54,1],[55,6],[50,5],[55,5],[55,5],[55,1],[52,4],[53,3],[55,3],[54,5],[52,5],[52,6],[53,4],[53,3],[55,3],[52,3],[52,3],[54,1],[55,4],[52,2],[53,1],[54,2],[52,7],[52,5],[55,3],[54,2],[54,1],[54,3],[53,1],[52,4],[54,3],[52,6],[53,4],[53,5],[52,1],[53,6],[54,3],[0,0],[0,0],[0,0],[53,5],[53,6],[55,2],[53,4],[54,4],[53,4],[55,4],[54,1],[55,4],[53,1],[52,5],[52,7],[53,2],[53,4],[55,1],[53,6],[53,1],[0,0],[0,0],[0,0],[52,7],[52,3],[55,3],[54,1],[55,1],[55,3],[55,8],[53,6],[55,2],[54,7],[53,4],[55,5],[53,7],[54,2],[52,1],[54,3],[0,0],[0,0],[0,0],[54,1],[52,3],[54,5],[55,4],[52,4],[52,3],[53,3],[53,2],[55,6],[55,5],[55,5],[55,3],[0,0],[0,0],[0,0],[0,0],[52,3],[55,1],[55,1],[52,4],[53,3],[53,7],[0,0],[0,0],[52,7],[53,4],[52,3],[55,8],[55,2],[55,5],[52,3],[52,1],[55,3],[52,3],[52,2],[54,5],[0,0],[0,0],[53,1],[54,4],[52,3],[53,7],[54,7],[55,4],[55,1],[54,6],[55,1],[54,2],[53,8],[54,8],[55,3],[54,2],[52,1],[54,4],[52,3],[54,7],[53,2],[53,1],[0,0],[0,0],[54,1],[55,2],[52,3],[52,2],[53,3],[53,1],[52,5],[52,1],[54,1],[53,6],[53,3],[54,3],[55,7],[54,5],[54,6],[54,7],[54,3],[53,1],[52,2],[55,1],[52,5],[54,6],[54,3],[53,8],[53,7],[54,2],[53,4],[54,8],[53,5],[53,5],[54,3],[53,4],[52,8],[55,4],[55,5],[53,5],[54,2],[55,2],[55,4],[54,4],[52,6],[53,1],[52,4],[54,5],[55,8],[52,2],[52,3],[55,7],[52,5],[53,5],[54,5],[55,2],[53,2],[53,2],[54,3],[52,1],[53,1],[52,2],[53,1],[55,6],[54,2],[54,2],[55,8],[55,5],[55,5],[52,4],[55,2],[53,6],[52,2],[53,7],[52,5],[54,6],[53,1],[52,1],[55,3],[52,3],[54,2],[53,3],[54,2],[54,5],[53,1],[54,5],[52,1],[52,4],[53,1],[54,4],[55,1],[50,5],[55,3],[52,5],[54,1],[53,8],[53,4],[53,2],[55,6],[54,7],[55,4],[55,6],[0,0],[0,0],[0,0],[55,2],[55,1],[53,8],[53,6],[55,1],[55,5],[55,2],[55,1],[52,2],[55,5],[52,3],[55,4],[53,2],[52,2],[52,6],[53,1],[55,7],[0,0],[0,0],[0,0],[54,2],[52,2],[52,7],[52,4],[52,6],[53,3],[55,1],[52,7],[52,1],[54,1],[54,3],[53,3],[54,7],[54,2],[55,8],[54,8],[0,0],[0,0],[0,0],[55,5],[52,2],[54,1],[52,7],[55,8],[54,6],[53,4],[53,4],[54,2],[53,7],[54,6],[54,7],[53,4],[52,8],[55,7],[0,0],[0,0],[54,2],[53,5],[55,3],[55,1],[55,1],[0,0],[0,0],[53,8],[54,2],[52,1],[53,3],[54,6],[52,6],[52,2],[54,2],[54,7],[55,1],[52,5],[55,1],[0,0],[0,0],[52,1],[52,2],[53,1],[53,6],[52,1],[53,5],[54,6],[55,5],[53,8],[53,3],[55,1],[54,1],[55,3],[55,2],[55,1],[52,7],[53,5],[55,5],[55,6],[53,3],[0,0],[0,0],[54,6],[52,3],[55,5],[54,1],[54,8],[53,1],[53,2],[55,6],[54,1],[53,1],[55,7],[52,6],[52,3],[55,2],[54,6],[55,6],[52,5],[54,2],[54,6],[53,1],[54,1],[54,7],[54,7],[54,1],[52,2],[54,7],[53,1],[53,1],[55,6],[55,4],[53,2],[53,1],[54,3],[54,1],[53,1],[53,5],[53,5],[50,5],[53,1],[54,1],[53,5],[55,3],[54,2],[54,4],[52,2],[54,4],[53,1],[53,1],[52,5],[54,4],[54,1],[55,1],[53,2],[54,3],[53,6],[53,1],[52,5],[53,6],[55,2],[54,2],[53,1],[54,4],[52,1],[53,1],[54,7],[54,5],[50,5],[53,3],[52,4],[52,4],[55,7],[55,4],[55,1],[53,2],[52,2],[53,7],[52,1],[52,2],[54,6],[54,3],[53,2],[52,4],[53,1],[52,5],[55,3],[54,2],[53,1],[55,4],[55,2],[53,2],[54,6],[53,3],[54,7],[52,1],[50,5],[54,6],[54,1],[52,5],[55,3],[54,7],[55,8],[0,0],[0,0],[53,2],[53,8],[54,2],[55,2],[52,3],[54,1],[52,2],[54,5],[55,2],[53,3],[50,5],[54,3],[55,6],[52,1],[55,5],[0,0],[0,0],[0,0],[53,7],[52,2],[52,3],[54,3],[52,1],[52,2],[52,6],[55,2],[53,7],[54,7],[54,2],[54,2],[54,3],[52,8],[52,6],[54,2],[55,7],[55,2],[0,0],[54,5],[53,3],[54,4],[52,3],[52,3],[54,2],[55,1],[54,1],[55,1],[55,3],[53,2],[54,4],[53,1],[54,2],[52,1],[0,0],[0,0],[53,5],[53,2],[54,1],[52,7],[53,2],[53,3],[0,0],[0,0],[54,7],[53,1],[55,7],[54,5],[53,1],[53,3],[54,1],[52,1],[53,6],[53,3],[0,0],[0,0],[52,2],[52,3],[0,0],[0,0],[54,6],[54,2],[55,6],[55,1],[54,1],[52,3],[52,6],[55,4],[52,4],[52,4],[54,2],[53,6],[52,6],[53,3],[52,7],[53,8],[55,6],[0,0],[0,0],[0,0],[52,1],[55,2],[53,7],[55,2],[54,1],[52,3],[54,1],[55,4],[55,3],[54,2],[55,3],[54,6],[53,3],[52,2],[55,8],[55,7],[54,3],[53,1],[53,6],[55,6],[55,3],[55,8],[53,4],[54,2],[55,4],[55,3],[55,6],[55,6],[53,3],[52,3],[54,3],[54,7],[55,1],[55,2],[54,2],[53,5],[55,2],[52,1],[54,5],[53,2],[50,5],[54,2],[54,6],[53,2],[52,1],[55,3],[55,2],[53,4],[53,3],[53,4],[55,8],[55,1],[54,1],[55,4],[53,2],[53,1],[55,5],[53,2],[55,1],[53,3],[54,4],[53,1],[0,0],[0,0],[53,2],[55,6],[53,3],[52,7],[55,8],[52,6],[52,8],[52,8],[54,5],[55,2],[50,5],[53,1],[53,3],[53,5],[54,2],[53,7],[52,8],[54,7],[53,7],[54,5],[52,2],[52,5],[55,1],[55,1],[54,3],[52,3],[53,3],[52,8],[55,5],[52,3],[54,5],[55,7],[53,6],[54,1],[54,1],[55,1],[0,0],[0,0],[55,5],[52,3],[52,3],[53,5],[52,4],[55,3],[54,7],[52,2],[54,6],[55,7],[54,1],[53,6],[55,6],[53,2],[52,6],[54,4],[53,1],[54,2],[0,0],[0,0],[54,7],[53,5],[52,1],[55,1],[55,2],[53,6],[55,2],[52,1],[55,3],[52,2],[55,3],[52,5],[54,2],[53,8],[53,4],[54,1],[53,8],[54,3],[53,3],[52,2],[55,5],[53,5],[54,4],[53,3],[54,2],[55,8],[55,2],[52,3],[53,7],[52,3],[52,4],[55,3],[52,6],[0,0],[0,0],[55,2],[55,2],[52,3],[54,3],[55,1],[54,3],[55,3],[53,5],[55,4],[55,2],[55,1],[55,1],[55,3],[53,5],[52,6],[55,1],[52,2],[53,7],[55,7],[55,3],[55,3],[0,0],[0,0],[52,6],[53,2],[54,6],[55,1],[54,7],[55,6],[52,2],[53,4],[52,1],[52,1],[53,2],[50,5],[52,1],[54,2],[54,2],[53,7],[52,4],[0,0],[0,0],[0,0],[52,8],[52,3],[53,2],[54,7],[54,2],[55,3],[55,4],[53,1],[52,1],[55,3],[53,4],[55,1],[52,1],[55,2],[54,3],[52,2],[55,2],[53,7],[52,6],[55,1],[50,5],[55,6],[55,6],[55,1],[53,1],[54,6],[54,7],[52,3],[52,4],[52,1],[53,3],[52,1],[55,3],[53,6],[53,3],[54,3],[52,4],[55,8],[52,2],[53,2],[53,4],[52,1],[55,3],[53,6],[53,1],[54,6],[53,5],[54,2],[54,2],[52,8],[52,5],[54,2],[52,6],[53,2],[52,4],[54,1],[52,2],[55,5],[53,6],[53,5],[54,6],[53,2],[0,0],[0,0],[55,3],[55,8],[54,5],[52,5],[55,3],[53,1],[53,1],[55,2],[52,1],[53,7],[54,4],[53,2],[55,3],[53,7],[53,1],[52,2],[54,1],[53,2],[52,2],[52,6],[54,1],[52,2],[54,1],[52,2],[54,8],[55,6],[52,4],[53,1],[52,2],[52,5],[53,2],[52,7],[53,2],[53,2],[52,8],[55,1],[53,3],[53,1],[0,0],[53,3],[52,8],[54,2],[52,3],[55,1],[55,6],[52,3],[55,5],[55,1],[53,2],[53,4],[54,6],[54,5],[54,7],[52,2],[53,3],[55,2],[0,0],[0,0],[52,1],[55,2],[54,6],[55,1],[53,4],[55,1],[54,4],[52,5],[53,1],[54,4],[53,5],[53,2],[54,6],[54,2],[55,2],[54,1],[52,5],[54,6],[54,7],[55,2],[55,6],[53,6],[53,7],[52,3],[52,2],[53,5],[55,1],[52,1],[52,6],[55,4],[52,1],[54,4],[0,0],[0,0],[0,0],[53,8],[53,7],[55,6],[53,4],[53,5],[53,4],[54,5],[53,4],[50,5],[55,3],[55,5],[53,1],[53,2],[55,3],[54,2],[54,8],[52,2],[53,2],[52,2],[53,2],[54,3],[53,2],[55,2],[55,1],[54,2],[52,7],[53,2],[55,1],[54,5],[52,1],[53,3],[54,5],[54,2],[52,5],[52,7],[55,3],[54,7],[53,7],[52,3],[50,5],[0,0],[55,3],[0,0],[52,4],[54,2],[52,2],[53,2],[52,1],[55,2],[52,3],[54,1],[52,3],[55,2],[53,5],[53,1],[54,5],[54,5],[52,5],[55,5],[52,7],[54,2],[54,3],[52,7],[53,2],[53,4],[50,5],[54,2],[54,2],[52,2],[55,1],[52,6],[55,6],[54,6],[53,3],[53,2],[54,2],[52,5],[53,5],[54,6],[53,5],[54,5],[52,2],[53,3],[53,4],[55,5],[54,1],[53,2],[54,3],[52,2],[53,2],[55,2],[54,2],[54,2],[52,3],[53,5],[55,6],[54,3],[52,5],[55,3],[55,1],[52,7],[52,2],[54,3],[53,3],[0,0],[0,0],[52,5],[53,1],[0,0],[0,0],[54,2],[52,6],[55,4],[55,5],[53,1],[55,4],[54,5],[54,2],[52,3],[52,2],[55,3],[55,7],[55,3],[52,6],[55,6],[54,7],[55,8],[52,3],[55,5],[53,7],[52,2],[55,7],[55,1],[52,1],[55,6],[53,2],[55,4],[55,4],[52,4],[54,6],[55,7],[53,3],[54,3],[53,3],[55,5],[54,6],[0,0],[0,0],[55,7],[55,7],[52,8],[55,2],[55,3],[53,5],[53,5],[55,3],[53,3],[54,3],[55,3],[53,1],[53,2],[55,8],[55,3],[55,6],[54,7],[0,0],[52,7],[52,6],[52,2],[55,3],[55,3],[54,6],[53,1],[53,8],[53,5],[55,1],[54,2],[53,2],[54,1],[54,7],[53,4],[55,1],[53,7],[0,0],[0,0],[0,0],[53,7],[55,3],[52,2],[52,5],[55,2],[54,1],[54,7],[55,3],[53,5],[54,2],[52,2],[0,0],[0,0],[0,0],[53,4],[53,1],[53,3],[52,7],[54,2],[53,6],[53,5],[52,5],[54,7],[53,3],[55,2],[54,6],[55,1],[55,6],[53,1],[54,6],[53,3],[54,8],[54,1],[55,4],[53,1],[55,6],[53,2],[55,7],[52,3],[52,1],[55,5],[55,1],[52,6],[54,3],[54,4],[53,3],[53,2],[52,7],[54,4],[52,1],[53,2],[54,7],[52,4],[0,0],[0,0],[54,5],[53,3],[55,5],[55,6],[55,6],[55,2],[54,6],[55,1],[53,8],[55,3],[53,3],[52,1],[52,1],[54,2],[54,3],[54,3],[52,4],[53,3],[52,5],[53,1],[52,1],[53,1],[53,3],[52,4],[52,6],[52,4],[52,4],[52,1],[54,1],[54,1],[52,1],[55,2],[55,2],[52,3],[54,6],[55,3],[53,1],[55,2],[52,8],[55,3],[55,2],[55,6],[52,6],[53,6],[53,4],[55,4],[53,3],[53,1],[52,6],[55,5],[55,7],[53,1],[52,1],[52,2],[55,1],[52,8],[54,1],[54,7],[53,1],[54,4],[53,1],[55,5],[54,1],[53,3],[54,3],[52,6],[55,2],[0,0],[0,0],[54,2],[52,3],[54,6],[54,1],[54,7],[52,1],[52,4],[53,1],[52,1],[52,3],[52,6],[53,1],[55,6],[55,6],[54,2],[53,5],[54,3],[54,4],[54,1],[52,1],[55,2],[52,2],[53,7],[53,1],[54,2],[53,2],[55,2],[52,6],[55,5],[54,2],[53,6],[52,5],[54,6],[53,1],[55,5],[55,7],[0,0],[0,0],[55,5],[52,4],[52,1],[53,2],[52,6],[55,3],[53,3],[52,2],[54,8],[52,6],[54,2],[55,1],[52,3],[52,4],[55,2],[54,2],[52,2],[53,3],[54,2],[54,3],[54,1],[52,1],[52,6],[54,7],[52,5],[53,2],[53,6],[55,8],[53,7],[53,4],[53,8],[55,5],[55,7],[54,2],[54,4],[0,0],[0,0],[0,0],[53,2],[55,3],[55,5],[52,1],[53,3],[55,3],[52,2],[55,1],[55,2],[52,7],[52,5],[0,0],[0,0],[0,0],[0,0],[53,8],[53,1],[52,7],[54,6],[53,1],[54,2],[54,4],[55,1],[53,6],[54,5],[53,7],[54,2],[52,4],[54,1],[54,6],[52,4],[54,6],[53,7],[54,2],[52,4],[53,6],[55,3],[54,4],[54,1],[55,2],[53,3],[52,3],[52,2],[53,5],[52,5],[54,2],[54,3],[55,6],[55,1],[53,6],[52,5],[53,4],[54,6],[0,0],[0,0],[54,2],[52,1],[55,2],[53,6],[55,1],[55,3],[52,2],[53,1],[52,2],[52,5],[55,6],[54,2],[52,7],[55,4],[52,3],[52,7],[53,2],[52,8],[54,2],[55,3],[52,1],[54,2],[52,7],[55,2],[55,1],[54,7],[54,7],[52,4],[52,5],[54,7],[53,7],[55,8],[55,3],[52,2],[55,3],[52,7],[55,2],[52,1],[54,8],[53,3],[53,1],[54,3],[55,7],[54,4],[54,2],[53,7],[55,1],[54,3],[55,2],[55,8],[53,7],[53,2],[52,1],[52,6],[52,1],[54,1],[53,7],[52,8],[54,5],[55,7],[54,1],[53,6],[54,2],[55,2],[52,1],[55,7],[53,2],[55,1],[54,1],[53,3],[55,1],[54,2],[54,8],[52,5],[52,3],[54,4],[52,5],[52,6],[55,4],[52,7],[53,3],[53,1],[53,1],[54,6],[54,3],[52,4],[55,1],[53,2],[53,7],[54,5],[53,1],[52,3],[55,5],[52,3],[54,1],[54,8],[54,8],[55,2],[55,2],[53,5],[55,6],[55,6],[54,1],[52,1],[54,3],[0,0],[0,0],[0,0],[52,5],[53,2],[55,7],[53,1],[53,2],[52,2],[52,1],[53,2],[53,3],[55,4],[52,7],[54,2],[54,7],[55,3],[55,1],[52,4],[54,2],[54,3],[52,2],[55,2],[53,7],[52,8],[54,7],[53,8],[55,2],[53,2],[54,4],[53,1],[55,5],[55,3],[52,7],[53,2],[52,6],[54,6],[0,0],[0,0],[0,0],[0,0],[55,6],[55,3],[54,1],[52,5],[52,1],[53,1],[52,6],[53,6],[52,2],[55,7],[55,1],[55,3],[54,2],[0,0],[0,0],[54,3],[54,3],[54,7],[55,2],[54,3],[53,6],[53,3],[53,6],[52,2],[54,3],[53,3],[55,7],[52,6],[53,5],[52,3],[55,8],[54,1],[52,3],[55,3],[53,2],[53,3],[54,7],[52,1],[52,1],[55,8],[52,3],[54,4],[53,2],[55,4],[53,7],[53,1],[55,2],[53,2],[53,1],[54,3],[55,8],[54,1],[0,0],[50,5],[55,6],[55,6],[53,3],[55,7],[55,6],[53,1],[52,4],[54,6],[55,2],[52,4],[54,4],[54,3],[54,1],[53,6],[54,8],[54,6],[0,0],[0,0],[53,6],[52,3],[52,3],[54,7],[52,1],[52,2],[52,2],[53,1],[52,1],[54,2],[54,1],[55,3],[50,5],[54,2],[52,5],[55,2],[55,7],[53,5],[55,5],[53,7],[53,2],[55,1],[52,6],[52,2],[54,6],[53,3],[54,2],[55,4],[52,8],[54,8],[53,2],[54,6],[54,2],[54,1],[52,4],[52,2],[53,4],[52,2],[52,5],[52,1],[54,2],[54,1],[54,1],[55,4],[54,2],[55,3],[54,6],[55,4],[53,1],[52,1],[54,2],[55,1],[54,1],[55,5],[55,5],[54,1],[52,6],[52,8],[52,1],[54,3],[52,1],[52,2],[53,8],[54,4],[55,2],[53,8],[54,4],[53,6],[53,6],[54,5],[53,3],[53,3],[53,2],[53,1],[54,7],[54,2],[54,1],[54,1],[52,2],[55,1],[53,8],[53,7],[54,2],[52,1],[53,4],[52,6],[53,1],[0,0],[0,0],[0,0],[54,3],[54,3],[54,3],[53,2],[53,3],[55,3],[53,6],[53,8],[53,6],[55,2],[52,4],[55,1],[55,3],[55,7],[55,5],[53,7],[54,1],[55,1],[55,6],[55,1],[52,3],[53,2],[53,5],[53,2],[54,4],[53,2],[53,3],[52,1],[53,1],[55,1],[53,3],[55,1],[55,2],[53,2],[52,6],[52,7],[52,2],[0,0],[0,0],[53,3],[54,5],[55,1],[52,2],[52,4],[52,1],[52,2],[52,7],[55,8],[53,2],[52,1],[52,1],[0,0],[0,0],[53,6],[55,1],[52,1],[55,6],[53,1],[54,7],[55,6],[53,1],[53,1],[52,5],[53,2],[54,7],[55,2],[54,4],[53,1],[54,1],[53,4],[55,6],[52,2],[54,6],[54,3],[55,4],[55,1],[52,2],[55,6],[52,5],[53,2],[52,2],[53,5],[54,3],[55,2],[54,3],[54,3],[54,4],[0,0],[55,7],[0,0],[0,0],[53,1],[53,8],[54,6],[52,1],[55,1],[54,4],[53,1],[52,8],[52,2],[52,4],[53,3],[54,8],[54,8],[53,3],[55,3],[55,7],[52,3],[0,0],[0,0],[55,4],[54,3],[52,7],[55,2],[53,2],[53,2],[52,6],[53,7],[53,5],[55,3],[53,1],[53,2],[54,6],[54,7],[54,4],[55,1],[52,6],[55,1],[52,1],[55,2],[54,3],[52,4],[53,1],[53,5],[55,1],[53,2],[54,1],[53,2],[52,2],[52,1],[55,1],[54,8],[54,3],[53,4],[55,6],[55,7],[54,6],[54,5],[52,7],[54,1],[54,3],[55,4],[53,1],[54,6],[54,6],[55,1],[52,5],[53,3],[52,2],[53,7],[53,6],[54,1],[52,2],[55,6],[53,1],[52,2],[53,1],[55,1],[54,2],[54,2],[54,2],[55,6],[52,8],[55,6],[52,2],[54,1],[54,6],[55,3],[54,1],[52,5],[55,7],[52,5],[52,3],[54,2],[52,5],[54,7],[55,2],[54,4],[53,2],[54,5],[54,7],[55,4],[52,3],[53,3],[55,1],[55,5],[55,1],[0,0],[0,0],[0,0],[55,3],[53,5],[55,3],[52,2],[53,5],[55,8],[55,3],[52,2],[52,2],[52,1],[52,6],[55,3],[52,4],[53,4],[52,2],[55,8],[52,3],[55,2],[53,1],[52,7],[55,1],[54,4],[54,7],[53,2],[54,6],[53,2],[54,6],[52,8],[53,2],[54,7],[54,5],[54,5],[54,3],[53,3],[55,5],[54,7],[53,3],[0,0],[0,0],[54,2],[52,1],[52,6],[52,6],[52,7],[52,8],[54,8],[54,1],[54,1],[52,2],[54,1],[0,0],[0,0],[0,0],[0,0],[53,8],[52,2],[54,2],[54,5],[55,4],[54,3],[55,4],[54,1],[52,3],[53,4],[54,2],[55,4],[53,8],[52,3],[54,8],[55,5],[55,6],[55,2],[55,5],[54,3],[55,3],[52,2],[55,5],[52,3],[53,6],[55,7],[54,3],[53,1],[55,2],[55,2],[52,1],[53,7],[52,8],[52,1],[54,2],[0,0],[0,0],[0,0],[54,1],[54,4],[55,4],[55,3],[53,6],[55,6],[52,3],[53,4],[53,1],[52,5],[54,4],[55,2],[54,4],[55,6],[52,5],[54,4],[0,0],[54,7],[54,1],[54,2],[55,5],[55,6],[52,3],[53,3],[54,6],[54,2],[53,1],[52,8],[52,2],[53,2],[52,4],[55,3],[52,4],[54,4],[52,4],[55,3],[55,2],[54,5],[52,2],[54,5],[53,3],[53,1],[55,3],[54,6],[54,5],[53,3],[53,6],[54,2],[54,7],[55,3],[54,8],[53,2],[55,2],[53,6],[53,1],[54,4],[53,6],[52,3],[52,4],[52,1],[55,2],[52,1],[54,3],[52,2],[52,1],[55,7],[53,1],[55,5],[53,7],[53,2],[54,3],[55,4],[52,4],[52,2],[53,1],[54,3],[53,7],[53,6],[53,1],[54,5],[52,8],[54,1],[53,3],[52,2],[55,4],[52,7],[50,5],[52,7],[54,2],[52,3],[54,3],[54,6],[53,8],[54,2],[53,2],[54,5],[53,2],[52,4],[54,1],[55,3],[53,4],[52,4],[52,4],[53,1],[0,0],[0,0],[52,2],[53,5],[54,3],[55,3],[53,3],[54,6],[53,1],[55,5],[52,1],[54,7],[54,7],[53,8],[53,3],[55,8],[53,1],[52,2],[50,5],[54,4],[52,5],[54,2],[54,1],[55,4],[55,7],[55,5],[53,2],[55,4],[53,2],[52,1],[53,1],[54,5],[55,2],[52,1],[54,1],[54,2],[55,3],[53,8],[54,3],[54,5],[53,3],[54,7],[0,0],[0,0],[52,4],[54,5],[55,2],[55,1],[52,3],[53,7],[53,3],[52,3],[53,4],[52,1],[0,0],[0,0],[0,0],[53,2],[53,1],[55,2],[52,2],[54,5],[52,6],[52,2],[53,2],[55,7],[53,2],[54,1],[54,3],[53,1],[54,6],[52,2],[55,2],[52,1],[52,7],[55,3],[55,3],[52,6],[53,7],[54,6],[52,1],[54,2],[54,6],[52,6],[53,5],[53,5],[53,2],[54,3],[53,5],[53,5],[55,1],[0,0],[52,6],[0,0],[0,0],[0,0],[53,2],[54,2],[54,2],[52,5],[52,1],[53,2],[54,1],[52,6],[54,7],[54,2],[53,2],[53,4],[54,2],[53,2],[55,1],[53,4],[52,4],[54,2],[0,0],[0,0],[54,4],[54,2],[53,1],[52,6],[53,3],[52,6],[53,1],[53,1],[54,2],[54,3],[55,6],[53,3],[55,1],[55,1],[55,3],[53,2],[52,3],[53,2],[50,5],[54,2],[54,3],[53,1],[53,2],[53,1],[54,1],[52,5],[55,2],[52,1],[54,2],[54,2],[55,7],[55,2],[52,7],[54,3],[52,3],[53,3],[55,7],[52,1],[54,3],[53,1],[53,2],[54,1],[52,5],[54,6],[55,7],[52,2],[50,5],[54,5],[52,1],[53,1],[55,2],[53,5],[52,6],[53,8],[53,6],[55,2],[55,2],[52,6],[52,7],[54,1],[53,6],[54,1],[55,1],[53,4],[54,2],[54,5],[53,2],[52,7],[52,2],[54,6],[52,5],[55,7],[54,6],[55,4],[53,1],[54,1],[54,1],[53,2],[52,7],[55,3],[53,8],[55,4],[52,2],[54,4],[0,0],[0,0],[55,4],[52,7],[52,2],[54,5],[54,4],[54,6],[55,2],[53,1],[55,3],[52,3],[54,5],[53,6],[55,5],[52,2],[55,4],[55,2],[54,5],[52,1],[54,4],[52,2],[55,1],[53,4],[53,3],[53,1],[55,1],[50,5],[53,2],[54,8],[55,2],[54,4],[52,5],[55,2],[54,1],[53,7],[54,2],[52,5],[55,1],[55,2],[52,6],[54,6],[0,0],[0,0],[0,0],[52,6],[52,5],[52,3],[54,2],[54,5],[54,7],[52,2],[53,4],[55,5],[0,0],[0,0],[0,0],[0,0],[55,2],[54,2],[55,3],[52,5],[52,1],[54,2],[52,3],[54,5],[55,5],[55,2],[52,2],[53,1],[52,3],[54,5],[53,6],[55,6],[55,4],[52,4],[53,3],[53,3],[54,1],[54,3],[52,2],[55,4],[52,2],[53,6],[55,5],[52,3],[54,6],[53,1],[53,2],[54,5],[53,5],[0,0],[55,8],[0,0],[0,0],[0,0],[53,7],[52,5],[53,2],[52,2],[54,5],[53,3],[53,1],[55,2],[54,7],[53,3],[53,1],[55,6],[54,1],[52,5],[52,1],[53,4],[0,0],[54,4],[0,0],[0,0],[53,7],[55,1],[53,1],[55,1],[55,7],[53,5],[53,1],[54,7],[55,2],[54,3],[52,2],[55,2],[54,7],[54,2],[52,4],[55,4],[54,4],[52,2],[53,5],[55,2],[53,4],[54,3],[54,2],[52,7],[52,6],[0,0],[0,0],[54,2],[53,1],[54,3],[52,5],[55,4],[53,7],[52,4],[53,4],[53,1],[55,1],[54,5],[52,3],[55,1],[53,2],[53,6],[54,1],[52,5],[54,6],[52,8],[52,1],[52,7],[55,1],[53,4],[53,1],[55,1],[52,7],[52,3],[50,5],[52,8],[53,6],[52,2],[55,5],[54,2],[52,6],[53,1],[54,8],[50,5],[53,4],[54,2],[52,5],[53,1],[55,7],[54,7],[55,8],[52,2],[54,3],[52,1],[54,3],[54,1],[53,5],[52,3],[52,3],[55,4],[54,7],[52,3],[55,6],[55,3],[0,0],[53,4],[52,3],[52,2],[52,7],[52,1],[54,7],[53,7],[55,3],[52,8],[55,1],[54,5],[54,1],[55,3],[53,4],[55,4],[55,7],[55,1],[53,2],[55,7],[55,5],[55,1],[55,4],[54,1],[53,6],[54,1],[53,1],[55,5],[53,3],[52,5],[52,1],[54,6],[52,3],[55,7],[54,5],[54,1],[53,2],[55,3],[54,6],[52,7],[55,1],[55,2],[0,0],[0,0],[0,0],[54,2],[54,4],[53,7],[52,6],[53,1],[55,4],[53,1],[55,6],[52,1],[53,5],[55,1],[54,4],[0,0],[0,0],[55,5],[54,2],[54,5],[52,3],[52,1],[55,7],[53,6],[52,1],[54,2],[55,1],[52,4],[55,4],[53,8],[52,7],[53,2],[52,6],[53,2],[52,4],[55,5],[53,5],[54,6],[52,7],[55,4],[52,5],[54,4],[53,3],[55,2],[54,1],[55,3],[53,7],[55,6],[55,7],[0,0],[0,0],[0,0],[54,5],[55,5],[52,4],[55,1],[55,6],[54,4],[52,4],[54,1],[54,7],[53,5],[54,8],[52,1],[53,3],[52,2],[55,3],[54,5],[52,2],[52,2],[54,2],[54,2],[55,4],[55,2],[52,8],[53,6],[53,7],[54,5],[54,5],[52,1],[53,1],[52,3],[52,8],[52,2],[54,2],[55,4],[53,7],[54,1],[55,3],[54,3],[55,7],[55,7],[55,2],[53,5],[54,1],[52,2],[55,7],[55,2],[52,5],[0,0],[0,0],[52,1],[55,2],[54,7],[52,3],[54,2],[52,4],[52,3],[52,5],[53,4],[55,5],[52,7],[55,1],[53,1],[52,3],[54,1],[55,1],[53,7],[52,7],[54,8],[55,4],[55,7],[55,1],[52,7],[53,1],[53,4],[54,2],[54,6],[55,5],[53,8],[53,1],[52,1],[52,1],[55,7],[54,1],[53,2],[52,2],[52,7],[52,6],[55,5],[54,4],[53,1],[54,8],[54,5],[52,2],[54,3],[53,1],[53,3],[54,7],[54,1],[54,3],[52,8],[55,4],[54,1],[54,2],[0,0],[53,4],[0,0],[0,0],[52,5],[52,6],[53,6],[55,7],[55,3],[54,3],[55,5],[53,2],[53,6],[55,2],[53,2],[53,4],[52,2],[55,4],[55,3],[55,8],[54,8],[53,8],[54,8],[54,2],[54,5],[53,5],[54,6],[53,7],[54,7],[55,2],[53,7],[55,5],[52,6],[53,3],[55,7],[54,1],[54,2],[54,7],[53,1],[55,1],[54,1],[54,2],[52,1],[55,3],[54,3],[0,0],[0,0],[0,0],[0,0],[53,6],[55,3],[55,5],[53,2],[55,2],[53,2],[52,2],[54,3],[52,6],[54,3],[54,2],[0,0],[0,0],[52,4],[53,1],[52,5],[52,6],[55,4],[55,5],[52,2],[55,2],[53,2],[53,2],[52,7],[53,1],[52,7],[54,3],[53,1],[50,5],[53,1],[53,5],[55,2],[55,1],[55,3],[52,4],[53,6],[55,2],[54,2],[53,1],[54,5],[54,5],[52,2],[53,2],[54,8],[55,3],[0,0],[0,0],[0,0],[52,1],[53,2],[54,2],[53,4],[54,4],[53,6],[52,4],[55,2],[55,1],[54,2],[53,5],[55,4],[55,3],[54,2],[54,5],[53,1],[52,8],[54,7],[53,6],[53,6],[0,0],[0,0],[52,2],[54,1],[55,5],[55,2],[52,1],[53,2],[55,5],[55,1],[52,2],[54,8],[54,1],[55,6],[54,1],[52,2],[55,2],[52,6],[54,1],[50,5],[55,5],[52,6],[53,1],[54,1],[55,4],[54,5],[52,1],[0,0],[52,2],[52,1],[54,4],[55,4],[52,3],[54,2],[52,5],[55,1],[55,1],[54,2],[54,2],[55,7],[55,6],[54,7],[52,3],[55,2],[55,7],[54,7],[53,4],[53,6],[53,5],[52,2],[54,1],[55,3],[54,4],[53,6],[54,4],[52,1],[52,1],[55,5],[53,1],[52,2],[52,4],[55,1],[55,6],[53,2],[53,3],[52,4],[54,7],[53,2],[52,4],[54,3],[52,6],[53,2],[52,6],[54,8],[55,5],[55,5],[52,3],[52,5],[53,5],[53,1],[55,6],[55,3],[52,6],[52,7],[53,2],[0,0],[0,0],[0,0],[52,1],[53,2],[52,8],[52,4],[53,1],[52,3],[55,3],[54,2],[54,2],[52,1],[52,3],[53,6],[53,3],[54,6],[52,3],[53,1],[52,6],[55,5],[52,2],[54,5],[54,3],[54,6],[53,5],[54,6],[52,1],[53,3],[54,4],[54,4],[55,2],[52,1],[52,8],[52,5],[54,1],[53,6],[53,2],[52,6],[53,3],[55,1],[52,1],[53,1],[54,2],[55,6],[53,6],[0,0],[0,0],[54,2],[52,3],[55,6],[53,3],[55,1],[54,1],[52,6],[52,4],[54,6],[55,1],[54,3],[0,0],[0,0],[54,1],[52,1],[53,7],[55,5],[54,8],[52,5],[55,1],[55,7],[54,7],[54,3],[53,3],[53,1],[55,1],[53,6],[54,5],[53,1],[52,3],[52,7],[55,2],[52,7],[52,3],[52,1],[52,2],[55,3],[52,6],[52,2],[52,4],[53,5],[53,2],[54,3],[53,3],[0,0],[0,0],[0,0],[0,0],[55,3],[55,7],[52,5],[55,5],[53,3],[53,1],[54,1],[53,2],[52,3],[54,2],[55,1],[54,6],[55,5],[55,8],[54,1],[55,1],[52,3],[54,8],[53,7],[0,0],[0,0],[53,8],[53,7],[54,6],[55,2],[54,1],[52,1],[53,7],[52,6],[52,6],[53,7],[52,8],[54,1],[55,7],[55,2],[53,1],[55,4],[53,3],[53,3],[54,2],[53,8],[54,8],[54,3],[54,6],[54,1],[52,4],[52,4],[53,4],[0,0],[0,0],[52,7],[53,2],[53,7],[53,1],[55,1],[52,1],[52,5],[53,5],[53,5],[54,2],[54,4],[54,7],[55,5],[54,1],[53,5],[55,5],[55,8],[55,1],[53,7],[54,3],[54,8],[55,2],[55,2],[54,1],[55,2],[55,5],[53,2],[55,3],[53,6],[52,7],[52,2],[53,1],[53,3],[54,6],[55,8],[52,3],[52,6],[54,2],[55,5],[54,6],[53,8],[52,8],[52,4],[55,6],[52,4],[53,3],[54,3],[53,5],[53,3],[55,6],[55,5],[54,2],[0,0],[55,4],[0,0],[0,0],[0,0],[54,1],[54,7],[52,4],[52,3],[53,3],[55,2],[52,5],[55,3],[53,3],[50,5],[52,3],[52,5],[54,5],[54,2],[53,5],[54,1],[53,5],[55,3],[54,7],[55,4],[55,2],[53,2],[55,3],[54,2],[54,5],[54,2],[53,3],[54,2],[54,7],[55,4],[53,8],[52,8],[53,6],[54,1],[54,3],[52,1],[52,1],[55,2],[53,1],[54,7],[55,3],[53,1],[52,1],[0,0],[0,0],[53,4],[54,6],[52,1],[54,7],[55,1],[52,1],[53,6],[53,4],[55,5],[52,3],[52,3],[52,2],[0,0],[0,0],[0,0],[55,1],[53,3],[54,3],[53,1],[53,2],[54,6],[54,1],[54,1],[55,5],[54,1],[55,2],[54,4],[54,7],[55,1],[52,1],[50,5],[52,3],[52,1],[55,3],[55,8],[55,1],[55,2],[54,3],[52,2],[55,1],[52,2],[54,7],[54,5],[54,4],[53,5],[55,5],[54,7],[0,0],[0,0],[52,8],[53,5],[53,3],[55,1],[52,8],[52,4],[55,3],[55,6],[53,7],[53,5],[54,1],[55,1],[54,5],[52,7],[52,3],[54,2],[54,7],[55,4],[55,6],[54,3],[0,0],[0,0],[0,0],[52,5],[55,2],[55,5],[53,7],[52,6],[53,7],[53,7],[52,3],[55,3],[55,1],[54,1],[53,4],[52,5],[53,1],[55,1],[53,6],[54,2],[52,1],[53,2],[55,2],[55,8],[54,1],[0,0],[54,4],[0,0],[0,0],[54,4],[52,3],[55,3],[53,5],[53,1],[53,1],[53,7],[53,1],[54,3],[54,5],[54,5],[55,7],[54,7],[53,1],[54,1],[55,1],[55,5],[54,2],[52,2],[55,2],[52,1],[53,1],[54,1],[54,2],[53,7],[55,2],[52,1],[52,2],[52,2],[54,1],[54,5],[53,3],[55,2],[55,2],[55,1],[55,1],[54,7],[53,1],[54,6],[55,6],[55,6],[54,2],[53,8],[54,2],[53,7],[52,5],[53,4],[53,1],[55,2],[0,0],[0,0],[0,0],[0,0],[53,6],[0,0],[0,0],[0,0],[52,5],[53,4],[54,1],[55,2],[53,1],[52,3],[52,2],[54,3],[53,4],[55,5],[53,4],[55,3],[53,7],[55,1],[52,3],[54,1],[52,1],[55,7],[53,1],[55,4],[53,4],[55,1],[52,2],[52,1],[52,1],[54,3],[54,2],[54,8],[53,1],[55,2],[55,1],[54,1],[52,6],[52,3],[54,6],[55,1],[54,4],[52,8],[53,7],[53,7],[54,4],[52,1],[55,6],[55,1],[0,0],[0,0],[54,4],[55,7],[53,8],[53,4],[52,3],[53,3],[53,3],[53,1],[52,5],[53,1],[54,8],[0,0],[0,0],[0,0],[53,2],[55,1],[52,1],[54,4],[54,7],[54,3],[52,6],[54,2],[53,7],[52,7],[55,1],[52,3],[53,2],[54,5],[54,5],[52,2],[53,4],[55,2],[52,1],[54,4],[53,1],[55,8],[52,8],[53,5],[52,2],[54,2],[54,1],[53,1],[55,3],[54,1],[52,5],[54,6],[0,0],[0,0],[53,2],[52,6],[55,3],[52,4],[52,5],[52,5],[52,6],[53,5],[54,1],[53,1],[53,5],[52,3],[54,3],[53,1],[55,5],[54,2],[52,1],[53,7],[53,3],[54,2],[0,0],[0,0],[0,0],[55,6],[52,2],[52,2],[52,6],[53,5],[53,2],[55,6],[52,2],[52,2],[55,5],[52,3],[52,1],[52,1],[53,3],[53,5],[52,3],[55,5],[54,6],[55,4],[52,2],[52,2],[55,5],[53,5],[55,5],[55,2],[53,7],[52,2],[54,2],[52,3],[54,1],[52,1],[55,4],[55,1],[53,3],[52,1],[52,2],[55,6],[54,6],[52,2],[55,8],[53,4],[53,5],[55,3],[54,5],[55,4],[53,5],[52,1],[54,1],[55,8],[52,7],[54,4],[52,2],[53,3],[50,5],[54,6],[52,1],[53,8],[54,3],[55,7],[55,1],[55,8],[55,3],[54,7],[53,8],[53,1],[54,2],[52,6],[55,2],[53,8],[55,6],[55,7],[54,3],[52,8],[50,5],[55,7],[0,0],[0,0],[0,0],[53,3],[55,7],[55,1],[52,6],[54,8],[54,3],[52,5],[53,1],[53,1],[54,1],[54,3],[54,6],[54,4],[52,1],[52,6],[52,7],[53,6],[52,1],[55,3],[54,7],[54,2],[55,1],[52,3],[55,3],[54,2],[55,5],[52,3],[52,7],[52,2],[54,7],[54,2],[54,1],[53,4],[53,7],[51,4],[52,1],[53,2],[53,7],[55,7],[55,4],[55,3],[53,4],[52,7],[52,3],[52,1],[55,4],[53,1],[55,4],[55,4],[0,0],[0,0],[0,0],[53,8],[55,4],[52,7],[53,1],[55,5],[54,3],[52,5],[55,7],[52,6],[53,8],[0,0],[0,0],[0,0],[0,0],[53,1],[55,6],[53,6],[54,2],[55,2],[55,4],[52,4],[55,6],[52,6],[55,3],[52,2],[54,2],[53,2],[54,7],[52,1],[54,6],[54,2],[54,2],[55,4],[52,2],[55,5],[52,2],[55,3],[55,3],[52,3],[52,3],[52,1],[53,2],[53,7],[53,4],[52,2],[55,1],[52,3],[0,0],[55,7],[52,1],[52,2],[55,2],[54,2],[52,1],[54,3],[55,3],[54,2],[54,1],[54,2],[54,1],[54,1],[55,7],[54,5],[53,7],[52,3],[53,3],[54,1],[0,0],[0,0],[0,0],[53,8],[52,3],[54,2],[53,1],[52,5],[52,4],[53,2],[54,4],[54,6],[55,3],[54,5],[55,1],[52,2],[52,3],[54,3],[52,2],[53,4],[53,7],[54,3],[52,6],[52,1],[52,3],[53,2],[54,5],[0,0],[0,0],[54,4],[52,3],[52,3],[53,6],[52,4],[55,3],[52,5],[53,7],[52,6],[53,4],[54,6],[53,3],[55,1],[52,7],[55,5],[55,3],[53,2],[55,2],[54,1],[53,3],[54,2],[52,1],[53,8],[54,7],[53,6],[53,3],[55,4],[54,2],[54,7],[53,2],[53,2],[54,8],[55,1],[54,2],[55,1],[53,2],[54,2],[54,3],[54,1],[52,5],[55,1],[54,6],[54,3],[52,5],[55,3],[54,3],[55,4],[53,1],[55,2],[0,0],[0,0],[0,0],[55,7],[53,2],[52,1],[54,1],[52,1],[54,3],[53,4],[54,3],[55,2],[52,8],[53,5],[55,2],[55,1],[54,7],[52,3],[53,7],[0,0],[0,0],[0,0],[53,4],[55,7],[52,6],[52,1],[54,1],[54,1],[53,3],[55,8],[53,6],[55,2],[53,2],[52,1],[54,1],[54,2],[52,3],[53,1],[55,7],[53,6],[54,7],[55,2],[53,1],[53,2],[52,2],[54,2],[52,2],[54,3],[55,6],[52,2],[52,1],[53,4],[0,0],[0,0],[0,0],[55,3],[54,4],[52,2],[55,6],[53,4],[52,2],[52,3],[55,4],[54,6],[54,2],[54,4],[54,5],[54,6],[0,0],[0,0],[0,0],[0,0],[0,0],[55,6],[53,2],[55,1],[53,4],[54,4],[54,3],[52,1],[54,4],[53,3],[52,2],[52,4],[52,2],[54,1],[55,7],[52,2],[52,3],[52,1],[53,4],[52,3],[54,2],[52,1],[54,2],[54,1],[53,5],[52,1],[54,4],[54,2],[0,0],[0,0],[0,0],[55,7],[55,7],[52,1],[52,3],[54,1],[53,2],[55,3],[54,6],[53,2],[55,2],[54,3],[55,2],[55,2],[55,6],[53,5],[53,2],[52,2],[54,1],[53,2],[53,7],[52,4],[53,1],[52,5],[55,2],[55,4],[54,5],[54,6],[54,5],[53,5],[52,1],[54,5],[54,5],[52,6],[54,1],[53,1],[55,6],[55,2],[54,2],[52,5],[53,6],[55,1],[55,1],[54,2],[54,4],[55,8],[54,1],[0,0],[0,0],[52,3],[53,3],[54,3],[53,3],[50,5],[52,1],[52,5],[53,3],[53,1],[54,4],[53,6],[55,3],[53,5],[52,2],[55,8],[54,5],[50,5],[54,3],[54,1],[52,5],[55,7],[52,7],[52,6],[52,1],[55,7],[55,8],[54,2],[53,4],[54,1],[53,6],[55,2],[54,5],[55,4],[54,2],[52,6],[52,5],[55,6],[55,2],[55,6],[54,3],[55,6],[53,4],[53,1],[54,2],[52,2],[54,2],[54,5],[54,4],[55,2],[52,2],[55,2],[54,7],[0,0],[0,0],[53,3],[53,5],[55,3],[52,2],[55,4],[53,1],[53,3],[53,3],[55,1],[55,2],[52,1],[54,4],[52,5],[54,3],[0,0],[0,0],[0,0],[53,1],[55,2],[53,1],[54,5],[52,3],[55,5],[50,5],[55,6],[55,5],[54,5],[54,3],[55,3],[53,7],[52,3],[52,1],[55,2],[52,2],[55,1],[53,1],[54,3],[55,1],[52,1],[54,1],[52,2],[55,4],[53,1],[55,2],[52,5],[54,7],[52,6],[0,0],[0,0],[0,0],[0,0],[53,1],[54,1],[52,4],[54,2],[52,1],[54,2],[54,2],[53,1],[52,2],[55,3],[52,1],[53,5],[0,0],[0,0],[0,0],[0,0],[0,0],[54,5],[52,6],[53,3],[55,6],[53,4],[53,2],[54,3],[53,2],[52,4],[55,1],[54,2],[54,4],[54,8],[52,3],[54,4],[55,6],[53,1],[55,3],[52,7],[53,2],[53,1],[52,5],[54,2],[55,2],[52,1],[55,1],[54,2],[0,0],[0,0],[0,0],[52,6],[54,8],[52,6],[52,4],[52,6],[53,8],[54,7],[55,7],[54,7],[55,4],[55,7],[54,4],[54,4],[50,5],[53,2],[52,4],[53,3],[54,1],[53,4],[54,3],[55,5],[52,5],[52,3],[54,5],[55,8],[52,2],[54,3],[54,1],[55,1],[52,7],[52,6],[52,2],[54,7],[53,7],[55,3],[53,2],[53,3],[52,4],[54,6],[52,5],[52,1],[55,3],[55,2],[54,6],[54,3],[54,3],[53,1],[54,6],[0,0],[0,0],[0,0],[54,3],[55,7],[55,2],[54,3],[54,6],[54,1],[55,2],[55,3],[52,8],[54,6],[55,1],[54,3],[55,2],[54,5],[53,3],[52,7],[54,8],[52,3],[52,7],[55,8],[52,2],[55,1],[52,5],[53,1],[55,7],[55,8],[54,5],[53,2],[53,2],[55,2],[54,3],[52,4],[52,8],[54,1],[52,5],[53,2],[52,8],[55,4],[53,6],[55,7],[54,1],[52,2],[53,1],[53,6],[52,3],[55,2],[53,8],[55,2],[54,3],[0,0],[0,0],[54,8],[53,5],[52,6],[55,1],[52,2],[53,7],[52,2],[52,1],[54,2],[55,3],[54,1],[54,3],[55,3],[55,1],[0,0],[0,0],[0,0],[0,0],[54,5],[53,6],[55,6],[54,3],[54,2],[54,2],[53,7],[53,4],[52,8],[53,3],[53,3],[55,6],[54,5],[55,1],[55,3],[54,2],[55,2],[53,1],[55,6],[52,5],[52,1],[55,2],[55,7],[52,2],[53,2],[55,2],[53,1],[55,1],[53,2],[53,4],[52,3],[52,3],[0,0],[0,0],[53,2],[54,5],[55,1],[52,4],[55,5],[54,4],[53,7],[55,8],[55,5],[55,1],[52,2],[52,3],[50,5],[0,0],[0,0],[0,0],[0,0],[53,4],[52,5],[53,2],[54,2],[52,2],[53,2],[52,5],[52,1],[52,1],[55,6],[53,7],[53,6],[55,2],[53,2],[53,7],[54,1],[55,8],[55,2],[54,7],[55,4],[55,4],[53,3],[52,6],[55,3],[55,1],[55,1],[0,0],[0,0],[0,0],[0,0],[52,4],[55,4],[54,1],[52,2],[55,3],[55,7],[52,3],[53,2],[52,5],[54,1],[53,3],[53,8],[52,2],[54,3],[52,7],[53,8],[55,2],[52,7],[54,3],[55,4],[53,6],[55,1],[54,4],[52,7],[53,3],[53,5],[52,3],[53,6],[53,5],[55,5],[54,7],[54,1],[55,7],[54,7],[55,7],[52,7],[53,2],[55,1],[54,8],[53,1],[53,8],[52,4],[52,3],[53,7],[53,3],[55,4],[53,4],[0,0],[0,0],[0,0],[53,6],[53,4],[53,8],[52,1],[52,5],[55,6],[53,1],[54,2],[54,6],[55,4],[55,1],[53,8],[52,2],[54,1],[53,5],[55,6],[53,2],[55,2],[55,7],[53,4],[55,4],[54,3],[52,4],[52,3],[54,1],[52,6],[52,2],[52,7],[55,2],[54,1],[54,8],[55,1],[55,1],[54,3],[54,2],[54,7],[52,8],[54,6],[54,1],[52,1],[55,1],[55,1],[54,7],[53,1],[55,2],[54,1],[53,2],[52,1],[54,6],[53,3],[53,8],[0,0],[52,2],[55,2],[54,6],[54,2],[52,5],[53,4],[52,6],[52,2],[52,4],[52,2],[55,8],[55,2],[52,5],[55,5],[0,0],[0,0],[0,0],[0,0],[54,1],[52,6],[52,2],[0,0],[0,0],[55,6],[55,2],[54,2],[53,1],[53,1],[53,3],[54,6],[54,2],[55,5],[53,7],[54,6],[53,2],[54,1],[50,5],[55,3],[55,3],[55,2],[55,4],[54,3],[55,3],[54,4],[54,2],[53,6],[52,6],[0,0],[0,0],[0,0],[0,0],[55,7],[52,5],[52,2],[54,8],[54,3],[55,6],[52,6],[52,1],[55,3],[53,1],[52,6],[55,5],[53,1],[52,2],[53,6],[55,7],[0,0],[0,0],[55,6],[0,0],[0,0],[0,0],[55,7],[52,3],[54,8],[54,8],[54,2],[52,3],[54,4],[53,8],[53,7],[54,2],[52,4],[52,3],[55,7],[53,8],[54,3],[53,3],[53,3],[53,5],[53,2],[52,5],[53,4],[54,2],[55,6],[53,6],[0,0],[0,0],[52,7],[54,1],[52,6],[54,4],[55,5],[53,6],[53,6],[54,2],[55,8],[54,3],[54,1],[55,5],[52,4],[55,1],[54,5],[55,7],[55,5],[55,5],[54,4],[55,5],[52,1],[52,8],[55,3],[55,6],[54,4],[53,1],[52,1],[54,5],[53,5],[54,7],[52,2],[54,1],[54,6],[55,6],[55,2],[55,1],[53,3],[53,3],[55,8],[54,3],[53,3],[55,7],[53,6],[54,5],[53,6],[54,1],[0,0],[0,0],[0,0],[55,3],[53,6],[52,2],[54,5],[55,5],[55,1],[53,2],[54,2],[53,3],[53,8],[55,2],[53,2],[54,4],[52,3],[55,2],[52,3],[53,2],[53,3],[53,7],[54,7],[52,4],[53,1],[54,2],[54,3],[53,2],[53,1],[55,3],[55,8],[54,1],[54,7],[53,7],[55,2],[54,7],[53,6],[52,8],[53,5],[52,2],[55,5],[52,3],[54,1],[52,3],[55,2],[52,2],[54,4],[53,7],[53,8],[53,6],[53,5],[53,1],[53,3],[54,1],[54,2],[55,2],[55,1],[53,4],[54,2],[54,1],[52,1],[53,3],[54,6],[53,5],[52,2],[52,1],[52,3],[54,4],[52,3],[0,0],[0,0],[0,0],[0,0],[55,3],[55,3],[0,0],[0,0],[54,2],[0,0],[0,0],[54,3],[52,3],[53,6],[52,3],[53,7],[53,3],[52,6],[53,4],[54,1],[52,2],[53,3],[55,2],[54,3],[52,1],[54,2],[55,1],[53,3],[55,3],[53,7],[53,2],[54,1],[54,5],[0,0],[0,0],[0,0],[52,7],[0,0],[54,3],[54,4],[53,5],[53,1],[54,2],[54,5],[54,2],[52,3],[55,4],[54,7],[52,1],[53,1],[53,8],[52,1],[53,2],[0,0],[0,0],[55,2],[0,0],[0,0],[0,0],[55,7],[54,2],[52,1],[52,2],[54,6],[53,8],[54,1],[52,2],[54,2],[55,8],[52,2],[52,1],[52,5],[53,2],[52,8],[53,2],[52,3],[52,1],[54,2],[53,1],[52,6],[54,2],[54,5],[54,6],[0,0],[0,0],[53,6],[52,2],[52,4],[55,2],[55,7],[53,8],[55,3],[55,2],[53,2],[54,6],[54,4],[55,2],[54,3],[52,3],[54,8],[53,5],[53,1],[54,7],[53,6],[55,4],[54,3],[55,4],[52,5],[52,4],[54,4],[52,3],[55,5],[53,3],[52,7],[52,8],[54,8],[55,3],[52,2],[53,3],[55,4],[53,2],[54,8],[54,1],[53,4],[55,3],[53,7],[52,6],[53,3],[55,5],[54,6],[52,1],[52,2],[54,4],[53,2],[52,2],[52,5],[52,1],[53,1],[55,2],[52,2],[55,8],[54,6],[52,3],[53,2],[52,4],[55,2],[53,2],[54,3],[54,6],[55,3],[54,2],[54,6],[54,3],[54,7],[55,3],[52,4],[54,2],[53,1],[53,6],[52,5],[55,3],[54,5],[55,6],[53,8],[52,1],[55,5],[54,2],[54,1],[54,1],[55,1],[53,2],[52,7],[53,7],[53,3],[55,1],[54,1],[54,1],[54,1],[55,1],[54,1],[53,8],[55,1],[54,1],[55,7],[54,3],[53,3],[52,3],[0,0],[55,1],[52,6],[54,2],[52,1],[52,1],[55,7],[54,2],[55,5],[55,1],[53,6],[52,2],[0,0],[55,8],[52,1],[53,1],[53,1],[0,0],[0,0],[0,0],[54,1],[53,2],[0,0],[0,0],[55,3],[55,7],[52,4],[55,3],[52,1],[55,5],[52,4],[54,8],[53,6],[53,6],[53,2],[52,6],[52,4],[54,6],[52,3],[52,1],[54,8],[55,1],[55,4],[55,3],[55,2],[50,5],[0,0],[0,0],[0,0],[0,0],[54,3],[54,3],[53,6],[53,6],[54,3],[54,4],[53,5],[53,1],[54,4],[52,5],[54,2],[55,2],[52,3],[55,7],[52,2],[52,1],[53,3],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[54,3],[53,6],[54,3],[54,7],[53,1],[54,1],[52,3],[54,4],[52,7],[55,4],[55,6],[52,8],[53,2],[54,3],[52,1],[53,3],[55,1],[54,3],[53,3],[54,4],[54,2],[53,1],[55,2],[52,3],[0,0],[0,0],[54,6],[52,1],[50,5],[52,4],[52,4],[54,1],[54,8],[54,2],[55,6],[54,2],[53,8],[52,6],[52,2],[52,1],[52,6],[53,2],[53,2],[52,2],[55,3],[53,3],[52,6],[52,1],[52,4],[52,6],[52,3],[52,1],[53,3],[52,3],[54,5],[54,2],[54,5],[52,3],[53,8],[54,7],[52,7],[53,2],[52,7],[52,6],[50,5],[54,4],[53,2],[52,3],[52,3],[53,1],[52,2],[52,6],[52,4],[53,3],[53,2],[53,4],[53,8],[55,6],[53,1],[53,2],[55,2],[52,7],[53,7],[52,2],[54,7],[54,1],[0,0],[0,0],[55,2],[52,1],[54,1],[52,3],[53,1],[54,4],[55,1],[55,2],[54,1],[52,4],[55,4],[52,3],[52,6],[52,5],[55,2],[55,3],[54,4],[53,4],[52,2],[55,1],[54,8],[54,2],[55,7],[54,2],[52,1],[55,6],[52,2],[55,2],[55,3],[52,6],[53,1],[54,8],[52,6],[53,6],[53,1],[54,4],[52,4],[52,1],[50,5],[53,3],[0,0],[55,1],[55,7],[55,7],[54,4],[55,2],[53,8],[55,2],[50,5],[54,5],[0,0],[53,5],[54,5],[53,2],[55,3],[54,5],[55,6],[53,1],[53,4],[55,3],[52,3],[54,1],[54,4],[0,0],[54,3],[55,3],[52,1],[55,2],[52,3],[55,1],[53,5],[55,2],[52,1],[52,6],[52,3],[53,1],[54,1],[54,1],[54,4],[52,7],[54,4],[54,4],[53,3],[52,5],[53,2],[54,1],[52,2],[54,6],[0,0],[0,0],[54,4],[55,7],[54,5],[52,2],[55,1],[53,2],[53,7],[52,3],[54,1],[54,5],[54,1],[54,7],[54,2],[55,7],[53,1],[53,4],[55,4],[54,2],[52,5],[53,8],[53,3],[0,0],[0,0],[55,3],[55,2],[50,5],[52,7],[52,2],[54,6],[55,1],[54,7],[54,1],[52,4],[54,5],[53,6],[54,4],[55,5],[53,3],[54,6],[54,1],[53,3],[52,3],[52,5],[54,3],[54,5],[0,0],[0,0],[0,0],[53,3],[55,1],[55,1],[53,2],[54,3],[52,8],[54,5],[55,1],[55,2],[55,3],[52,2],[52,5],[54,4],[54,3],[54,1],[53,1],[52,4],[52,2],[54,4],[54,4],[55,8],[52,4],[55,8],[54,1],[53,7],[52,1],[52,1],[52,2],[55,4],[53,1],[52,7],[54,3],[52,5],[54,2],[53,5],[55,5],[53,1],[54,6],[53,2],[52,1],[55,4],[55,5],[54,3],[52,4],[54,7],[53,1],[52,2],[55,4],[52,2],[52,1],[52,1],[52,2],[55,2],[53,2],[53,2],[52,5],[52,3],[53,1],[52,4],[52,3],[0,0],[0,0],[55,1],[53,7],[54,8],[54,3],[52,2],[55,7],[54,2],[54,5],[53,3],[52,3],[54,4],[54,2],[54,6],[54,6],[52,5],[54,1],[55,5],[55,2],[52,2],[55,1],[54,3],[53,7],[52,5],[53,5],[53,7],[54,4],[53,3],[54,1],[55,4],[52,4],[55,3],[54,1],[52,2],[54,6],[55,3],[53,1],[53,4],[54,6],[54,3],[54,6],[55,1],[0,0],[0,0],[0,0],[52,5],[52,5],[52,7],[54,7],[52,7],[0,0],[52,1],[52,1],[53,3],[52,4],[53,2],[54,2],[53,7],[52,7],[54,8],[53,6],[52,8],[52,2],[52,6],[53,4],[0,0],[0,0],[0,0],[52,1],[54,6],[52,3],[54,2],[52,2],[54,3],[53,2],[52,4],[53,4],[55,2],[52,4],[53,3],[55,1],[55,3],[53,4],[54,3],[53,3],[55,2],[54,3],[55,7],[54,1],[0,0],[0,0],[52,2],[52,7],[54,1],[53,4],[53,7],[52,2],[53,3],[52,8],[54,3],[55,3],[53,7],[55,6],[52,4],[54,2],[55,2],[53,4],[54,5],[53,2],[55,1],[53,3],[54,7],[0,0],[0,0],[55,2],[53,2],[55,1],[53,3],[53,2],[54,3],[52,3],[52,1],[53,1],[54,3],[52,4],[54,8],[54,6],[52,6],[53,2],[54,6],[54,2],[55,1],[53,1],[52,4],[52,2],[53,8],[0,0],[0,0],[0,0],[54,3],[54,1],[54,2],[53,1],[52,4],[55,1],[53,7],[53,8],[55,5],[53,1],[54,4],[52,7],[52,5],[54,8],[52,2],[52,5],[55,2],[52,2],[54,2],[52,2],[54,7],[55,7],[55,2],[53,2],[53,2],[55,6],[52,6],[54,2],[52,2],[53,1],[55,4],[54,1],[54,7],[53,1],[53,1],[54,5],[54,1],[53,1],[52,1],[52,2],[54,1],[55,2],[54,1],[54,3],[55,2],[55,4],[55,6],[52,2],[53,2],[55,2],[52,6],[53,3],[55,2],[54,8],[55,7],[54,3],[52,6],[55,6],[55,3],[52,6],[0,0],[54,6],[52,3],[52,7],[52,4],[53,1],[55,8],[52,2],[52,2],[52,1],[53,3],[52,1],[53,2],[53,5],[54,2],[55,6],[53,2],[54,2],[53,1],[53,2],[54,3],[53,4],[54,3],[55,6],[52,2],[52,5],[54,4],[52,5],[54,6],[55,7],[54,4],[54,8],[53,2],[55,3],[54,6],[53,5],[53,8],[55,6],[53,6],[54,3],[54,4],[55,6],[52,5],[0,0],[0,0],[0,0],[52,4],[55,4],[52,5],[52,7],[0,0],[0,0],[53,3],[53,1],[52,7],[52,2],[52,1],[52,8],[55,6],[52,4],[52,5],[55,6],[55,2],[52,6],[54,3],[55,5],[0,0],[0,0],[0,0],[54,7],[50,5],[54,2],[53,2],[55,3],[54,1],[55,8],[54,8],[55,3],[53,8],[55,7],[52,6],[54,3],[54,7],[54,6],[53,6],[54,1],[52,4],[55,1],[53,7],[0,0],[0,0],[0,0],[0,0],[54,2],[53,2],[55,1],[52,4],[55,2],[55,1],[55,4],[55,2],[54,1],[53,6],[54,2],[54,2],[55,6],[55,4],[53,2],[55,1],[53,3],[52,2],[52,1],[54,7],[55,1],[0,0],[0,0],[53,2],[53,1],[54,6],[53,2],[54,2],[54,1],[55,6],[53,2],[53,1],[54,5],[55,1],[53,1],[54,7],[55,2],[54,3],[53,3],[52,4],[52,8],[53,1],[55,1],[53,1],[0,0],[0,0],[0,0],[0,0],[52,1],[52,3],[54,1],[54,2],[55,6],[55,5],[54,1],[54,3],[52,6],[54,6],[55,3],[55,3],[55,2],[54,5],[52,2],[52,2],[53,4],[53,1],[55,7],[53,2],[55,7],[52,5],[53,5],[54,6],[53,6],[55,1],[54,1],[55,4],[53,5],[52,4],[52,5],[55,5],[54,7],[54,3],[52,5],[53,1],[54,1],[53,5],[55,2],[53,8],[53,2],[55,7],[53,1],[55,1],[54,1],[55,3],[53,6],[55,3],[52,4],[52,2],[55,2],[52,1],[53,4],[52,1],[55,6],[55,8],[53,6],[53,2],[55,8],[55,1],[54,1],[0,0],[0,0],[53,6],[53,2],[55,2],[54,8],[54,1],[54,2],[55,5],[55,5],[54,3],[53,5],[55,2],[53,6],[52,6],[54,7],[55,1],[53,4],[54,5],[55,1],[53,5],[53,2],[53,4],[54,5],[54,7],[52,1],[54,2],[55,1],[54,2],[52,1],[52,8],[52,5],[53,2],[52,2],[55,7],[54,1],[52,3],[53,2],[55,5],[53,4],[52,1],[0,0],[0,0],[0,0],[54,5],[54,7],[52,1],[0,0],[0,0],[53,4],[54,7],[52,3],[53,4],[53,3],[53,1],[55,7],[53,3],[53,1],[52,5],[53,5],[54,2],[53,2],[54,7],[54,6],[0,0],[0,0],[0,0],[53,3],[53,3],[55,4],[52,2],[52,3],[54,3],[54,3],[54,1],[54,2],[54,4],[52,7],[52,2],[53,2],[53,7],[52,1],[55,5],[55,3],[54,3],[52,5],[53,1],[0,0],[0,0],[0,0],[55,3],[54,1],[54,6],[52,5],[52,2],[53,3],[52,2],[53,2],[52,4],[52,1],[52,5],[53,6],[52,3],[54,1],[53,7],[54,8],[54,2],[54,2],[53,4],[53,4],[53,5],[0,0],[0,0],[0,0],[53,7],[53,7],[55,6],[52,1],[52,4],[55,4],[54,5],[54,1],[54,1],[54,6],[55,2],[55,6],[52,2],[52,8],[52,4],[54,4],[53,6],[54,7],[55,1],[53,7],[54,7],[53,3],[54,2],[55,1],[0,0],[0,0],[55,8],[53,7],[53,1],[52,3],[53,1],[53,3],[52,3],[54,2],[53,2],[55,8],[55,7],[52,5],[52,2],[53,7],[53,4],[53,6],[53,2],[52,1],[55,1],[53,2],[53,2],[0,0],[0,0],[52,3],[53,1],[55,2],[53,1],[52,3],[52,6],[52,6],[54,3],[52,2],[52,2],[55,7],[53,5],[54,1],[54,2],[53,1],[54,2],[53,8],[52,6],[54,3],[50,5],[55,2],[52,7],[53,2],[52,1],[53,1],[54,1],[55,3],[54,6],[52,7],[54,5],[54,5],[52,2],[52,2],[55,1],[52,8],[0,0],[54,1],[0,0],[0,0],[53,1],[53,4],[53,8],[53,1],[55,6],[53,1],[54,1],[53,4],[54,3],[55,1],[55,3],[54,1],[54,7],[53,3],[52,7],[52,2],[55,3],[55,5],[53,4],[52,7],[55,6],[52,2],[53,1],[52,1],[53,1],[53,3],[53,6],[54,5],[53,3],[52,8],[54,1],[54,5],[54,1],[52,3],[52,1],[52,2],[55,3],[54,2],[55,7],[54,4],[52,8],[0,0],[0,0],[0,0],[0,0],[0,0],[52,2],[55,2],[53,2],[55,6],[52,7],[54,7],[53,2],[53,8],[55,2],[53,3],[52,7],[55,5],[55,8],[52,5],[55,3],[52,1],[52,5],[54,3],[53,7],[0,0],[0,0],[0,0],[54,7],[52,2],[53,2],[54,1],[55,3],[54,3],[52,3],[53,2],[50,5],[52,5],[54,8],[52,5],[52,7],[54,1],[54,7],[50,5],[52,7],[0,0],[0,0],[0,0],[0,0],[52,2],[55,2],[55,8],[54,4],[52,3],[50,5],[55,1],[53,8],[53,2],[55,1],[55,6],[55,7],[54,1],[55,3],[53,3],[55,7],[52,5],[52,4],[53,3],[54,3],[0,0],[0,0],[0,0],[52,6],[53,2],[53,1],[54,1],[52,2],[55,3],[52,6],[54,5],[54,3],[55,8],[55,6],[52,4],[53,4],[52,1],[54,3],[53,7],[52,3],[53,2],[52,3],[53,5],[55,2],[54,3],[55,3],[55,6],[0,0],[0,0],[54,4],[55,3],[53,3],[55,3],[55,2],[54,6],[53,2],[52,6],[52,5],[54,2],[54,2],[55,3],[52,2],[55,5],[55,6],[55,1],[55,6],[54,1],[55,5],[54,1],[52,1],[0,0],[0,0],[53,1],[53,7],[53,2],[52,1],[55,1],[50,5],[54,7],[55,2],[53,6],[52,7],[52,3],[54,4],[54,2],[52,6],[52,2],[53,1],[52,3],[54,1],[54,5],[54,3],[54,1],[53,2],[54,3],[53,1],[55,5],[55,7],[52,4],[53,1],[53,6],[55,2],[53,3],[55,8],[54,8],[53,4],[54,1],[54,7],[54,4],[52,6],[54,5],[55,6],[53,3],[55,8],[54,5],[53,3],[54,2],[54,7],[53,2],[54,6],[54,3],[52,6],[55,3],[0,0],[0,0],[55,3],[53,7],[55,5],[54,5],[53,2],[53,4],[55,4],[54,4],[55,1],[50,5],[54,7],[53,6],[53,3],[53,6],[55,1],[53,7],[54,3],[53,4],[53,1],[51,7],[53,5],[53,4],[52,2],[54,3],[52,4],[55,1],[53,2],[54,3],[0,0],[0,0],[52,5],[52,1],[55,2],[52,3],[52,4],[55,2],[50,5],[53,6],[52,8],[53,3],[50,5],[53,1],[55,1],[53,6],[55,1],[55,8],[53,4],[52,5],[55,2],[52,6],[52,3],[0,0],[0,0],[0,0],[53,7],[55,2],[55,3],[52,2],[54,8],[52,4],[52,5],[54,7],[54,7],[53,6],[53,3],[52,6],[53,8],[52,2],[53,3],[54,2],[52,2],[55,4],[53,2],[52,3],[0,0],[0,0],[55,5],[54,1],[54,4],[54,1],[55,1],[55,3],[54,5],[53,6],[55,5],[55,4],[52,1],[52,5],[52,3],[52,3],[55,6],[53,2],[55,4],[53,8],[53,2],[0,0],[0,0],[0,0],[0,0],[53,5],[53,1],[53,7],[55,8],[52,2],[52,3],[55,1],[55,5],[52,5],[52,3],[55,3],[54,3],[55,8],[55,2],[53,1],[54,6],[55,1],[52,1],[52,1],[52,5],[53,1],[52,8],[54,6],[53,1],[0,0],[0,0],[54,1],[52,7],[54,3],[54,1],[54,2],[55,2],[53,6],[55,2],[54,4],[54,1],[53,2],[52,2],[53,4],[55,1],[52,2],[53,4],[52,4],[52,6],[52,1],[0,0],[0,0],[55,4],[53,2],[0,0],[0,0],[53,7],[55,1],[53,6],[53,1],[55,1],[54,2],[53,1],[52,1],[53,2],[53,4],[54,1],[54,5],[54,3],[55,1],[52,2],[54,1],[54,6],[54,4],[53,2],[54,5],[52,3],[55,4],[53,7],[52,2],[55,1],[52,3],[53,7],[53,5],[52,3],[53,1],[52,1],[54,1],[54,3],[53,2],[0,0],[0,0],[54,7],[55,2],[52,2],[54,1],[55,2],[54,2],[52,6],[53,2],[53,4],[54,7],[55,3],[54,4],[0,0],[0,0],[54,2],[52,1],[54,2],[52,4],[52,2],[52,7],[52,2],[55,1],[54,4],[52,5],[53,8],[53,1],[54,5],[52,6],[53,1],[54,8],[54,4],[55,5],[55,4],[52,7],[54,1],[54,2],[54,7],[53,2],[52,3],[54,1],[52,3],[55,2],[52,1],[53,1],[0,0],[55,3],[54,5],[53,6],[53,2],[55,4],[53,5],[54,6],[55,5],[53,3],[52,5],[53,5],[55,3],[54,1],[55,3],[53,6],[52,4],[55,1],[55,2],[55,3],[55,1],[0,0],[0,0],[0,0],[0,0],[54,1],[54,1],[55,8],[55,1],[53,7],[55,2],[53,5],[52,1],[53,1],[54,5],[52,2],[52,2],[52,1],[55,6],[52,6],[53,1],[54,2],[52,6],[52,1],[0,0],[0,0],[52,4],[52,1],[54,4],[54,5],[55,2],[53,1],[53,1],[54,7],[54,8],[54,2],[55,3],[54,1],[55,1],[52,1],[54,2],[55,3],[52,3],[55,6],[53,4],[52,1],[53,6],[53,3],[0,0],[0,0],[54,3],[52,3],[54,4],[53,8],[55,3],[53,2],[55,1],[55,2],[52,3],[54,7],[52,2],[52,7],[53,3],[52,3],[52,1],[53,3],[54,8],[55,6],[53,4],[54,7],[52,6],[54,5],[55,4],[52,5],[0,0],[0,0],[0,0],[0,0],[55,1],[52,2],[55,6],[52,8],[55,7],[52,4],[52,5],[52,2],[54,1],[53,2],[55,8],[55,3],[52,2],[52,2],[52,2],[54,8],[53,4],[55,3],[53,3],[52,2],[0,0],[0,0],[54,2],[53,2],[55,6],[54,7],[54,2],[52,4],[53,5],[53,1],[52,7],[54,1],[52,1],[54,7],[52,2],[52,1],[53,2],[54,6],[54,6],[54,1],[53,4],[55,1],[53,7],[53,2],[52,2],[52,7],[52,4],[55,3],[53,8],[55,7],[53,5],[55,2],[53,8],[55,6],[54,8],[53,5],[0,0],[0,0],[55,6],[52,7],[52,6],[53,1],[52,5],[55,4],[55,2],[53,5],[55,2],[55,4],[50,5],[55,4],[0,0],[53,5],[54,1],[52,1],[53,5],[54,5],[54,4],[55,6],[53,1],[55,1],[54,1],[55,1],[53,8],[53,6],[52,2],[54,3],[55,8],[53,5],[53,1],[50,5],[52,6],[54,1],[55,3],[52,1],[54,2],[53,2],[53,7],[55,6],[54,1],[53,1],[55,2],[55,2],[53,1],[0,0],[0,0],[53,7],[55,4],[53,3],[55,2],[53,8],[52,5],[54,3],[54,8],[53,6],[52,8],[54,3],[52,6],[52,3],[54,6],[54,1],[53,1],[52,2],[54,7],[53,1],[52,7],[53,2],[0,0],[0,0],[53,6],[54,1],[55,4],[54,2],[52,5],[52,6],[53,1],[55,1],[53,7],[54,6],[54,5],[55,2],[54,8],[55,4],[53,7],[55,3],[53,8],[52,1],[55,8],[0,0],[0,0],[52,1],[54,5],[55,2],[52,5],[54,5],[52,1],[52,8],[55,1],[53,7],[54,5],[53,1],[53,6],[53,4],[53,5],[53,1],[54,5],[55,8],[52,1],[52,5],[55,2],[54,2],[0,0],[0,0],[54,1],[52,7],[55,2],[54,1],[55,3],[53,4],[52,4],[54,4],[53,7],[52,1],[55,2],[55,3],[55,5],[52,8],[55,2],[55,2],[54,1],[54,6],[53,5],[54,1],[55,3],[52,6],[52,5],[53,5],[52,2],[0,0],[0,0],[0,0],[54,3],[54,1],[55,1],[52,3],[53,1],[54,2],[53,2],[52,5],[52,7],[54,3],[55,3],[54,5],[52,1],[52,7],[55,6],[54,3],[53,1],[52,3],[55,4],[52,3],[54,3],[55,1],[54,2],[52,7],[52,2],[52,2],[52,2],[53,6],[55,5],[54,3],[54,8],[52,7],[52,5],[55,7],[54,2],[55,2],[55,2],[53,1],[53,5],[54,4],[55,3],[54,7],[52,7],[52,7],[55,3],[52,4],[55,8],[52,5],[55,1],[52,3],[54,1],[53,8],[54,1],[55,1],[54,1],[55,2],[52,2],[55,1],[0,0],[0,0],[0,0],[54,7],[55,2],[52,3],[55,1],[54,5],[50,5],[55,3],[54,4],[55,4],[52,2],[52,4],[0,0],[0,0],[52,2],[52,5],[53,1],[53,2],[55,1],[54,2],[52,1],[55,1],[54,3],[52,5],[54,2],[52,2],[53,2],[55,1],[52,1],[54,1],[55,7],[52,2],[52,2],[52,1],[54,1],[55,4],[53,1],[53,4],[53,1],[54,4],[52,5],[54,2],[53,6],[0,0],[0,0],[54,4],[54,6],[55,1],[53,7],[54,6],[52,1],[55,1],[53,7],[53,2],[52,2],[54,4],[53,7],[53,5],[53,5],[55,3],[54,1],[54,2],[52,1],[54,7],[53,1],[55,5],[0,0],[0,0],[53,3],[52,2],[55,6],[52,7],[55,8],[52,5],[55,6],[52,5],[52,7],[55,1],[55,4],[54,1],[53,1],[55,4],[53,5],[53,1],[53,7],[52,4],[55,1],[0,0],[55,8],[52,1],[50,5],[55,5],[55,1],[55,7],[54,3],[54,6],[53,3],[54,2],[52,8],[53,3],[54,3],[52,6],[54,2],[54,3],[54,3],[53,7],[52,1],[55,4],[50,5],[54,7],[54,2],[0,0],[0,0],[52,7],[52,6],[52,4],[54,6],[55,6],[52,7],[53,3],[52,6],[55,2],[54,3],[53,5],[54,6],[52,5],[52,2],[50,5],[54,5],[55,1],[52,1],[55,6],[53,3],[53,1],[53,2],[54,5],[53,4],[0,0],[0,0],[0,0],[53,3],[55,5],[54,1],[55,7],[55,2],[52,5],[53,5],[55,5],[55,6],[52,4],[55,6],[54,3],[55,3],[55,7],[53,5],[52,1],[54,1],[53,5],[53,2],[54,7],[55,5],[55,5],[52,1],[55,5],[55,2],[53,3],[54,5],[52,3],[54,1],[52,2],[54,3],[52,6],[52,3],[55,6],[55,7],[53,8],[53,4],[53,1],[55,4],[55,4],[54,7],[52,3],[54,6],[54,3],[52,5],[54,1],[54,4],[55,8],[55,2],[53,2],[55,8],[55,2],[54,7],[52,8],[53,3],[55,3],[53,6],[53,2],[0,0],[0,0],[0,0],[53,7],[54,6],[54,6],[53,2],[53,4],[53,1],[54,1],[52,1],[54,7],[0,0],[55,2],[0,0],[0,0],[52,1],[52,3],[53,3],[52,1],[55,7],[55,6],[53,2],[52,7],[54,2],[53,3],[53,2],[52,3],[55,5],[53,2],[53,5],[53,2],[54,2],[52,4],[52,8],[54,1],[54,3],[53,2],[55,7],[55,6],[54,1],[55,3],[55,3],[53,4],[52,6],[0,0],[0,0],[0,0],[53,2],[53,5],[53,1],[54,4],[53,2],[53,6],[55,4],[0,0],[0,0],[53,6],[54,2],[55,1],[55,2],[53,5],[54,2],[55,4],[52,2],[55,1],[55,3],[52,1],[52,2],[55,3],[0,0],[0,0],[52,6],[53,1],[54,1],[53,1],[52,6],[54,2],[53,5],[54,6],[55,1],[54,1],[54,2],[53,5],[55,3],[55,1],[53,7],[55,3],[55,3],[0,0],[54,6],[53,1],[54,1],[53,4],[52,4],[55,3],[53,3],[53,6],[55,1],[53,3],[52,3],[54,1],[53,2],[53,3],[52,3],[53,1],[53,1],[52,2],[54,1],[52,5],[54,2],[52,3],[52,1],[54,2],[52,8],[52,2],[55,4],[52,5],[52,1],[55,5],[52,1],[54,3],[52,1],[52,4],[52,4],[52,2],[55,2],[53,4],[55,1],[53,8],[54,1],[54,2],[53,5],[55,4],[55,1],[53,1],[55,4],[54,1],[52,2],[53,1],[52,3],[0,0],[0,0],[53,7],[52,3],[53,1],[54,7],[53,5],[54,4],[54,7],[52,7],[53,1],[53,2],[53,1],[52,2],[54,7],[52,2],[54,6],[54,1],[52,5],[53,2],[52,2],[54,1],[55,4],[53,1],[55,6],[55,4],[55,2],[52,7],[55,2],[53,2],[55,1],[54,8],[54,1],[53,3],[54,7],[54,8],[52,1],[53,5],[54,7],[54,2],[54,1],[52,2],[54,8],[55,2],[55,2],[52,3],[55,1],[53,2],[54,2],[54,1],[53,3],[52,4],[55,5],[52,5],[52,1],[55,7],[55,2],[55,2],[55,7],[0,0],[0,0],[0,0],[55,5],[53,2],[53,1],[54,2],[53,2],[53,2],[55,1],[53,2],[55,2],[52,1],[55,1],[55,3],[52,7],[54,8],[55,1],[54,2],[53,1],[55,5],[55,2],[53,3],[52,1],[55,5],[54,2],[54,1],[54,6],[54,1],[52,4],[54,1],[53,1],[54,5],[55,7],[54,7],[54,8],[50,5],[55,1],[52,7],[52,2],[54,3],[55,2],[55,3],[53,5],[55,7],[0,0],[0,0],[0,0],[53,1],[50,5],[54,4],[53,2],[54,2],[52,1],[53,2],[0,0],[0,0],[55,1],[55,1],[54,6],[54,1],[53,1],[54,8],[52,2],[53,7],[52,4],[54,3],[54,7],[55,3],[52,6],[55,6],[55,1],[0,0],[53,4],[55,3],[53,4],[54,6],[52,1],[55,3],[55,6],[54,8],[53,4],[52,2],[52,3],[55,1],[54,3],[55,2],[53,4],[52,5],[0,0],[0,0],[54,5],[53,7],[55,2],[52,5],[50,5],[55,8],[52,3],[52,1],[55,6],[54,1],[55,2],[53,6],[53,1],[53,2],[53,1],[55,8],[55,1],[54,2],[54,1],[54,2],[54,6],[54,5],[52,2],[54,2],[53,1],[53,2],[54,3],[54,8],[54,1],[53,7],[53,1],[53,7],[55,6],[55,4],[53,7],[54,2],[52,1],[52,8],[54,1],[55,7],[55,1],[55,8],[55,6],[54,4],[54,1],[53,3],[52,4],[53,3],[54,8],[54,7],[0,0],[0,0],[54,4],[54,1],[52,1],[50,5],[54,2],[55,2],[55,4],[55,1],[50,5],[54,3],[55,3],[54,3],[54,1],[54,4],[53,2],[54,6],[53,3],[53,5],[53,1],[55,1],[55,1],[55,5],[54,6],[53,1],[54,3],[55,6],[53,5],[55,3],[52,7],[55,2],[53,5],[52,2],[52,7],[52,2],[52,1],[52,7],[53,2],[52,2],[55,6],[55,1],[52,5],[52,4],[55,2],[53,5],[54,2],[53,4],[55,2],[55,3],[51,6],[53,3],[52,5],[55,1],[53,5],[52,2],[52,4],[53,1],[53,1],[52,6],[54,1],[52,2],[54,5],[55,2],[54,6],[52,4],[54,2],[53,2],[54,4],[53,6],[53,6],[55,8],[54,4],[0,0],[0,0],[53,2],[54,8],[54,4],[54,5],[52,3],[55,1],[52,4],[55,6],[53,3],[53,3],[52,6],[53,2],[54,3],[54,6],[52,1],[55,2],[55,2],[52,5],[53,3],[52,5],[55,8],[52,1],[54,5],[53,2],[55,2],[52,2],[54,2],[54,4],[54,1],[0,0],[0,0],[0,0],[55,5],[54,5],[52,3],[52,5],[54,1],[55,2],[53,2],[0,0],[52,1],[54,7],[55,2],[53,6],[55,3],[55,1],[52,6],[55,3],[54,4],[52,3],[52,1],[53,7],[54,7],[55,5],[54,6],[54,1],[55,8],[0,0],[52,3],[52,1],[52,4],[52,2],[54,4],[52,6],[52,5],[53,1],[55,7],[55,1],[54,4],[55,1],[54,1],[55,1],[55,1],[0,0],[0,0],[0,0],[52,3],[53,4],[52,3],[53,5],[52,3],[52,1],[53,2],[52,4],[55,8],[53,3],[53,4],[52,1],[53,1],[55,1],[53,5],[52,3],[53,1],[54,2],[53,2],[52,5],[54,7],[53,2],[53,6],[53,2],[53,3],[52,5],[53,7],[54,5],[55,1],[53,2],[54,2],[54,1],[53,3],[54,1],[53,4],[0,0],[0,0],[54,3],[54,2],[52,3],[53,7],[55,2],[55,5],[53,3],[52,1],[53,2],[55,7],[55,1],[54,4],[55,1],[0,0],[0,0],[54,1],[55,2],[52,6],[52,1],[52,3],[55,8],[53,4],[52,6],[53,1],[54,5],[54,2],[53,3],[53,7],[54,3],[55,2],[55,1],[52,7],[55,6],[54,7],[53,3],[54,5],[52,2],[55,8],[53,3],[54,4],[55,7],[53,1],[53,2],[53,6],[50,5],[55,2],[52,5],[55,6],[54,1],[54,4],[52,4],[54,4],[53,2],[53,2],[55,7],[52,2],[54,1],[53,1],[53,7],[53,6],[50,5],[55,2],[55,8],[54,2],[52,2],[53,4],[52,2],[53,2],[52,2],[52,3],[52,3],[54,4],[53,8],[52,6],[53,2],[53,6],[54,3],[53,6],[54,2],[55,2],[52,7],[55,1],[55,1],[52,3],[54,6],[0,0],[0,0],[54,7],[54,4],[55,3],[54,1],[54,5],[53,3],[55,1],[53,1],[53,1],[54,2],[54,7],[53,2],[55,1],[55,8],[54,1],[53,7],[54,2],[52,6],[54,7],[52,6],[52,3],[54,2],[54,1],[52,2],[54,5],[54,4],[52,5],[53,2],[0,0],[0,0],[53,6],[54,6],[55,2],[53,1],[54,6],[53,2],[55,3],[52,7],[54,3],[53,5],[55,3],[0,0],[0,0],[52,4],[55,1],[52,3],[55,2],[52,1],[53,2],[53,3],[53,1],[53,2],[52,8],[55,4],[54,2],[55,6],[52,1],[55,2],[0,0],[54,1],[55,7],[54,5],[52,3],[53,1],[55,2],[52,5],[55,7],[52,3],[52,4],[54,4],[55,6],[54,3],[52,2],[53,8],[0,0],[0,0],[0,0],[55,1],[52,2],[52,1],[52,3],[54,1],[55,5],[54,2],[54,3],[54,5],[55,2],[53,2],[55,2],[52,8],[54,2],[54,4],[52,1],[54,5],[54,5],[55,1],[52,3],[52,1],[55,6],[52,2],[54,1],[54,1],[55,1],[55,4],[55,3],[53,2],[54,3],[54,1],[52,2],[54,1],[55,7],[0,0],[0,0],[54,1],[54,4],[54,3],[55,3],[54,7],[54,6],[55,1],[54,6],[54,2],[55,5],[54,1],[54,2],[53,2],[0,0],[0,0],[54,3],[52,5],[55,2],[52,4],[54,5],[53,4],[55,1],[54,2],[54,3],[55,5],[55,3],[54,1],[53,2],[53,8],[54,2],[54,4],[53,7],[52,6],[54,1],[53,8],[54,4],[54,4],[52,5],[55,6],[54,5],[53,1],[55,3],[54,1],[53,1],[55,8],[53,4],[53,3],[54,4],[52,6],[55,4],[52,1],[54,2],[52,1],[53,3],[55,4],[52,4],[54,7],[53,5],[55,5],[54,2],[53,4],[52,6],[53,1],[55,2],[53,6],[55,1],[54,1],[54,3],[55,3],[52,1],[52,1],[52,7],[53,6],[54,4],[55,1],[53,3],[52,3],[55,4],[55,1],[55,3],[54,4],[53,4],[55,5],[54,3],[52,8],[52,7],[52,6],[0,0],[0,0],[0,0],[54,4],[55,2],[55,1],[52,5],[53,2],[53,1],[55,5],[54,3],[50,5],[55,3],[52,2],[55,5],[53,7],[50,5],[55,7],[52,2],[53,5],[53,1],[54,4],[52,2],[55,5],[52,6],[55,4],[53,7],[55,4],[0,0],[0,0],[55,6],[54,6],[52,3],[54,2],[54,8],[53,1],[53,2],[55,3],[54,2],[0,0],[53,6],[0,0],[0,0],[54,6],[55,5],[52,1],[53,5],[54,3],[53,2],[53,8],[55,3],[54,3],[52,5],[53,1],[52,4],[55,3],[55,7],[50,5],[52,4],[0,0],[55,1],[52,5],[53,2],[55,2],[52,4],[52,3],[54,5],[53,1],[52,3],[55,3],[54,6],[55,3],[53,8],[54,5],[54,3],[55,2],[54,5],[53,5],[52,1],[54,2],[53,3],[53,3],[54,2],[53,2],[55,4],[55,8],[55,2],[55,1],[55,2],[54,4],[52,4],[55,6],[54,6],[54,1],[55,4],[55,6],[54,6],[53,2],[54,4],[55,1],[54,3],[54,1],[52,1],[53,1],[54,2],[55,2],[54,2],[53,8],[54,4],[55,4],[54,2],[0,0],[55,1],[53,2],[54,6],[55,6],[55,4],[55,4],[53,7],[54,6],[53,3],[53,5],[52,7],[54,3],[54,1],[54,3],[54,4],[0,0],[0,0],[54,1],[55,2],[52,4],[55,2],[53,2],[50,5],[54,2],[55,1],[52,4],[52,2],[54,1],[52,1],[53,4],[55,1],[52,6],[52,1],[52,2],[55,2],[55,1],[53,4],[54,1],[52,4],[55,2],[53,4],[52,6],[54,3],[54,1],[52,3],[54,6],[52,3],[54,5],[54,2],[52,2],[53,2],[55,6],[55,2],[54,3],[52,6],[53,1],[53,3],[53,2],[52,1],[53,2],[54,8],[55,1],[52,3],[52,8],[52,6],[54,2],[53,7],[54,6],[52,7],[54,2],[55,6],[52,2],[52,7],[54,3],[54,7],[54,2],[54,2],[53,3],[53,6],[55,3],[53,2],[52,1],[54,6],[54,7],[55,6],[55,2],[54,1],[52,6],[0,0],[0,0],[0,0],[52,5],[55,4],[52,6],[54,1],[55,2],[55,7],[54,5],[0,0],[0,0],[0,0],[54,7],[55,2],[55,2],[54,3],[55,6],[54,5],[54,3],[53,4],[55,1],[54,3],[52,4],[53,7],[54,1],[52,3],[54,1],[0,0],[54,7],[54,4],[52,3],[53,3],[52,2],[54,1],[54,8],[54,5],[54,7],[54,4],[52,2],[53,7],[53,1],[54,5],[55,3],[52,3],[52,3],[54,5],[54,2],[55,1],[55,1],[53,5],[52,7],[53,8],[53,2],[52,1],[55,7],[52,4],[53,6],[52,4],[0,0],[53,1],[52,8],[52,1],[55,1],[55,1],[53,2],[55,4],[55,1],[52,6],[53,7],[53,5],[54,7],[55,1],[55,1],[52,1],[54,1],[52,7],[55,1],[55,2],[54,1],[55,1],[54,5],[54,2],[55,6],[55,6],[53,1],[53,4],[52,1],[54,3],[52,6],[53,7],[52,6],[54,2],[52,6],[54,3],[54,2],[55,1],[53,1],[55,7],[53,2],[52,5],[54,2],[54,6],[55,2],[54,8],[54,7],[54,3],[54,1],[53,1],[54,4],[52,1],[55,5],[54,3],[0,0],[0,0],[55,1],[52,6],[55,5],[52,6],[53,1],[54,4],[53,1],[54,6],[55,2],[53,2],[54,5],[54,5],[0,0],[54,6],[55,2],[53,6],[53,2],[53,2],[52,7],[54,4],[53,3],[55,2],[53,5],[55,4],[53,6],[52,4],[55,2],[53,4],[54,3],[55,8],[54,8],[53,3],[52,4],[52,7],[52,1],[54,2],[52,7],[55,5],[54,8],[55,5],[54,6],[53,5],[54,4],[52,7],[53,4],[52,1],[55,3],[53,3],[55,4],[53,7],[53,1],[0,0],[0,0],[0,0],[0,0],[55,7],[52,7],[54,1],[52,1],[55,3],[54,2],[53,1],[55,2],[53,2],[53,7],[53,1],[54,4],[53,2],[55,1],[55,1],[53,2],[54,6],[55,6],[55,3],[53,4],[55,2],[54,6],[54,5],[54,3],[55,2],[52,6],[54,4],[54,2],[53,8],[52,1],[0,0],[0,0],[0,0],[55,4],[55,1],[52,7],[53,1],[54,7],[55,2],[53,6],[0,0],[0,0],[0,0],[54,3],[53,6],[52,1],[54,6],[54,6],[54,2],[54,4],[55,7],[52,8],[55,1],[54,2],[52,1],[0,0],[54,3],[0,0],[55,6],[0,0],[55,2],[55,4],[55,6],[55,3],[55,4],[53,2],[54,6],[52,5],[53,6],[55,2],[54,2],[0,0],[0,0],[52,5],[55,6],[52,3],[54,8],[53,7],[54,2],[54,7],[52,3],[55,2],[55,3],[53,1],[52,6],[54,4],[53,6],[52,5],[54,2],[52,5],[0,0],[0,0],[54,2],[54,7],[54,8],[53,2],[54,1],[53,6],[54,3],[54,2],[53,1],[53,2],[52,3],[53,2],[55,8],[55,2],[53,1],[52,2],[0,0],[53,3],[55,1],[54,2],[54,6],[54,1],[55,6],[55,1],[54,6],[55,3],[53,1],[53,1],[54,3],[55,1],[53,1],[54,3],[54,2],[53,1],[52,3],[53,8],[54,2],[54,1],[54,7],[54,2],[53,4],[55,2],[52,2],[55,2],[55,3],[54,1],[54,2],[53,1],[52,8],[0,0],[54,6],[0,0],[0,0],[52,5],[53,1],[55,2],[55,4],[54,3],[55,4],[54,1],[54,3],[54,2],[55,7],[52,2],[54,5],[55,1],[54,1],[53,5],[53,4],[52,3],[55,1],[52,1],[55,7],[53,6],[54,6],[53,1],[52,5],[55,2],[53,3],[55,2],[53,3],[55,2],[53,3],[52,1],[52,6],[55,2],[55,6],[53,7],[53,6],[53,1],[52,4],[52,3],[55,8],[54,6],[53,3],[55,7],[52,2],[55,1],[53,1],[55,1],[55,6],[53,3],[54,6],[52,1],[52,6],[53,4],[54,2],[52,7],[53,5],[55,2],[54,2],[52,3],[55,4],[55,3],[54,4],[55,2],[53,4],[54,1],[52,6],[55,2],[54,4],[52,1],[54,6],[53,4],[54,4],[52,1],[52,2],[54,1],[54,3],[55,6],[54,1],[55,5],[55,7],[55,5],[50,5],[55,2],[54,2],[55,8],[52,1],[52,7],[53,1],[52,5],[50,5],[52,5],[53,6],[52,1],[55,8],[53,2],[0,0],[0,0],[0,0],[55,3],[54,4],[52,3],[53,6],[53,8],[52,8],[52,1],[55,2],[53,4],[55,7],[52,5],[55,3],[55,4],[53,5],[0,0],[0,0],[0,0],[52,5],[52,2],[52,7],[53,5],[55,1],[55,7],[52,3],[52,7],[52,2],[52,2],[53,3],[0,0],[0,0],[53,5],[55,2],[53,4],[53,2],[55,5],[52,7],[53,1],[54,6],[55,6],[54,6],[52,7],[55,7],[52,1],[52,7],[54,7],[53,3],[53,5],[52,1],[52,5],[0,0],[54,7],[52,3],[52,2],[52,6],[55,2],[53,2],[55,4],[54,1],[53,4],[52,3],[53,6],[52,2],[52,4],[54,8],[52,5],[0,0],[52,1],[55,3],[55,4],[53,4],[54,5],[55,2],[53,4],[53,1],[54,4],[54,1],[54,1],[54,1],[55,5],[54,2],[52,8],[53,2],[53,7],[55,1],[53,6],[53,6],[54,2],[54,6],[52,2],[52,3],[52,1],[53,4],[53,5],[53,3],[52,1],[55,1],[54,5],[55,1],[55,3],[55,3],[55,8],[53,5],[55,1],[54,2],[53,2],[54,3],[54,4],[52,7],[52,6],[55,2],[55,1],[52,3],[53,2],[53,6],[52,2],[55,2],[55,5],[55,5],[55,6],[52,1],[53,4],[52,1],[54,2],[54,2],[55,1],[55,5],[54,1],[52,5],[55,4],[52,5],[54,7],[54,3],[54,6],[52,1],[53,1],[54,6],[53,6],[55,3],[54,2],[54,4],[55,5],[54,4],[55,3],[53,3],[55,2],[54,4],[55,7],[52,5],[53,8],[53,3],[55,3],[53,8],[54,2],[50,5],[52,6],[55,3],[53,7],[55,4],[55,4],[52,2],[55,2],[55,7],[54,6],[52,1],[53,6],[54,5],[52,3],[52,1],[52,2],[55,7],[55,2],[52,7],[52,1],[55,1],[55,5],[53,5],[55,2],[53,3],[52,6],[52,1],[53,3],[52,2],[52,4],[52,7],[55,7],[55,2],[54,2],[55,4],[52,1],[55,6],[53,3],[53,3],[55,3],[54,1],[52,2],[54,4],[53,3],[54,2],[52,1],[53,4],[0,0],[0,0],[52,6],[52,2],[52,7],[53,1],[54,6],[52,1],[55,7],[54,5],[53,6],[53,1],[0,0],[52,1],[0,0],[0,0],[0,0],[53,2],[54,1],[55,3],[54,8],[53,7],[55,1],[54,1],[55,7],[53,7],[52,7],[53,5],[52,2],[53,2],[0,0],[0,0],[0,0],[53,1],[53,6],[52,7],[53,2],[52,2],[53,1],[54,2],[52,6],[54,3],[54,1],[54,1],[54,3],[52,4],[53,1],[53,1],[55,4],[54,1],[0,0],[54,3],[52,6],[55,7],[54,2],[52,3],[54,3],[55,4],[52,2],[53,2],[52,8],[54,3],[53,2],[52,1],[0,0],[0,0],[0,0],[53,7],[52,3],[53,6],[54,5],[53,1],[52,1],[55,2],[53,3],[54,4],[52,3],[52,5],[54,2],[54,1],[53,3],[54,1],[52,2],[54,1],[55,1],[52,5],[55,3],[52,2],[53,3],[52,3],[52,8],[50,5],[52,2],[53,7],[54,7],[53,5],[53,1],[52,1],[50,5],[53,2],[0,0],[0,0],[54,7],[52,2],[54,2],[54,3],[52,5],[53,7],[55,2],[52,5],[52,8],[53,6],[54,4],[54,7],[53,7],[55,2],[53,2],[55,6],[53,2],[55,2],[55,2],[54,1],[53,1],[54,3],[52,2],[52,7],[54,2],[54,7],[52,7],[54,5],[55,2],[55,6],[53,1],[53,6],[54,2],[52,7],[54,8],[55,3],[54,3],[54,8],[54,2],[54,1],[52,2],[54,2],[54,1],[54,2],[53,5],[52,1],[52,1],[52,1],[53,3],[52,6],[52,2],[54,2],[55,6],[55,1],[53,4],[55,3],[52,6],[52,6],[54,7],[55,3],[52,7],[54,7],[55,7],[53,2],[52,7],[53,1],[52,6],[53,5],[54,7],[52,2],[55,6],[52,1],[53,3],[52,1],[52,4],[54,2],[52,2],[52,5],[54,3],[52,4],[54,1],[54,1],[52,4],[55,6],[55,1],[54,4],[53,4],[52,1],[55,2],[55,1],[53,2],[53,1],[55,1],[54,4],[53,2],[52,6],[52,2],[54,1],[0,0],[0,0],[54,6],[54,1],[54,8],[54,1],[53,5],[52,4],[53,2],[52,7],[55,2],[54,1],[0,0],[53,5],[0,0],[0,0],[0,0],[0,0],[53,2],[52,1],[52,3],[54,5],[54,6],[53,2],[55,6],[53,3],[52,6],[53,5],[55,7],[55,1],[0,0],[0,0],[0,0],[54,2],[55,4],[53,3],[52,2],[53,3],[53,1],[53,8],[53,5],[52,1],[53,4],[55,7],[53,2],[53,3],[53,3],[53,4],[54,6],[54,2],[54,6],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[52,7],[53,2],[55,1],[55,1],[53,1],[0,0],[0,0],[0,0],[55,8],[55,1],[54,3],[52,5],[55,2],[52,4],[54,2],[52,1],[53,3],[52,2],[52,3],[53,3],[53,4],[50,5],[55,1],[54,3],[54,2],[53,7],[54,2],[55,7],[52,6],[52,6],[53,1],[52,4],[55,1],[54,6],[52,6],[53,2],[54,3],[53,4],[53,7],[53,6],[53,5],[0,0],[0,0],[55,2],[53,2],[54,6],[53,2],[54,3],[54,4],[52,1],[52,2],[52,1],[52,2],[52,3],[54,5],[55,2],[54,1],[54,3],[53,2],[55,7],[53,1],[54,1],[55,1],[52,3],[52,1],[55,4],[55,3],[52,2],[55,4],[52,2],[55,2],[55,1],[55,6],[53,1],[54,5],[55,1],[55,6],[52,1],[53,2],[53,6],[53,5],[54,1],[53,7],[55,3],[53,2],[53,5],[55,4],[53,2],[55,5],[52,6],[55,4],[53,2],[55,1],[53,3],[55,3],[54,3],[52,1],[52,6],[55,3],[53,4],[52,8],[54,7],[52,8],[55,1],[54,7],[52,1],[52,3],[52,4],[54,4],[52,3],[55,7],[53,7],[54,1],[54,8],[53,2],[55,6],[52,8],[53,2],[54,1],[52,1],[54,2],[52,2],[55,1],[52,2],[52,6],[55,7],[55,1],[52,1],[55,3],[55,2],[54,3],[52,1],[54,6],[55,6],[54,5],[54,6],[54,2],[52,1],[52,2],[53,8],[55,1],[55,1],[53,1],[0,0],[53,7],[53,4],[55,2],[52,4],[53,3],[53,2],[53,1],[55,2],[54,1],[53,6],[53,2],[52,4],[52,3],[55,6],[0,0],[55,3],[53,4],[53,2],[55,2],[55,6],[52,2],[53,4],[55,1],[52,5],[55,3],[53,4],[55,2],[0,0],[0,0],[0,0],[55,4],[55,2],[54,4],[55,7],[55,4],[54,8],[55,1],[53,1],[55,1],[54,7],[53,5],[55,5],[54,1],[52,5],[54,1],[53,1],[55,6],[55,1],[53,1],[53,6],[54,1],[54,5],[53,4],[0,0],[0,0],[0,0],[55,6],[52,2],[55,1],[54,1],[55,6],[0,0],[0,0],[0,0],[55,2],[52,4],[53,4],[54,2],[52,3],[53,4],[53,1],[53,6],[52,6],[55,2],[54,4],[52,4],[52,5],[55,1],[55,5],[0,0],[0,0],[53,6],[55,2],[52,2],[54,4],[55,3],[55,4],[53,3],[52,3],[55,3],[55,6],[52,5],[53,2],[53,5],[53,6],[52,4],[55,3],[52,6],[52,2],[0,0],[0,0],[0,0],[52,1],[52,2],[52,1],[52,2],[55,5],[53,1],[52,3],[53,3],[55,5],[55,4],[55,8],[54,3],[55,4],[54,2],[55,2],[50,5],[55,1],[54,6],[53,3],[52,2],[55,7],[55,6],[54,6],[53,2],[53,5],[52,7],[54,3],[52,5],[54,4],[52,1],[52,1],[53,4],[52,6],[54,5],[52,4],[52,3],[54,4],[52,3],[55,2],[54,3],[55,2],[54,2],[52,1],[54,3],[55,4],[53,1],[53,1],[54,1],[55,6],[53,1],[55,2],[52,6],[52,3],[54,5],[54,1],[52,5],[54,6],[53,1],[53,8],[55,3],[54,2],[55,2],[53,4],[53,3],[52,6],[54,1],[52,2],[54,8],[53,6],[53,8],[52,2],[52,3],[54,4],[52,1],[55,1],[52,6],[54,1],[52,2],[53,5],[55,5],[54,6],[55,5],[52,2],[55,5],[54,4],[54,7],[55,2],[52,4],[53,3],[54,3],[54,1],[53,4],[53,8],[52,2],[52,2],[54,1],[54,1],[54,2],[54,8],[53,6],[52,4],[52,7],[55,1],[55,4],[52,4],[54,1],[53,5],[53,1],[52,3],[52,6],[52,2],[53,1],[0,0],[53,1],[52,5],[52,1],[55,2],[55,2],[52,5],[55,4],[52,1],[52,3],[53,3],[54,6],[53,3],[53,2],[52,3],[52,5],[55,1],[55,8],[54,7],[52,2],[54,3],[55,2],[55,3],[53,4],[54,1],[52,4],[53,5],[54,7],[53,7],[53,2],[54,5],[55,3],[55,1],[53,5],[53,1],[53,2],[55,1],[55,1],[52,4],[0,0],[0,0],[0,0],[53,4],[54,2],[53,6],[54,4],[53,3],[55,1],[55,1],[55,2],[0,0],[0,0],[54,4],[54,2],[54,3],[55,2],[52,4],[52,3],[54,1],[55,6],[53,6],[52,6],[55,1],[53,7],[52,1],[0,0],[0,0],[55,2],[55,1],[55,2],[53,7],[55,1],[54,4],[55,5],[53,3],[55,6],[53,8],[52,4],[53,3],[55,6],[54,7],[52,4],[55,4],[53,2],[52,7],[0,0],[0,0],[0,0],[54,1],[53,4],[55,2],[53,2],[54,2],[54,1],[54,7],[52,5],[55,4],[52,3],[52,1],[52,1],[53,1],[52,4],[55,2],[53,2],[54,5],[54,1],[54,5],[55,4],[53,2],[55,1],[54,3],[55,2],[55,1],[53,8],[54,2],[55,3],[53,7],[54,3],[54,3],[53,5],[52,2],[54,5],[54,7],[52,1],[52,1],[52,3],[53,3],[55,6],[53,4],[54,6],[53,3],[53,3],[53,2],[55,5],[52,3],[53,1],[53,5],[52,1],[55,5],[54,3],[54,4],[54,5],[54,1],[54,1],[55,1],[55,2],[55,1],[54,2],[52,7],[55,1],[55,6],[52,2],[54,1],[54,1],[54,1],[52,3],[55,1],[54,3],[54,1],[55,3],[53,2],[54,5],[55,4],[52,2],[53,1],[52,6],[52,1],[54,1],[54,6],[52,3],[53,2],[55,6],[52,3],[52,2],[54,4],[54,3],[53,2],[53,3],[52,2],[52,2],[55,6],[54,4],[54,4],[54,2],[53,1],[54,4],[53,1],[55,5],[54,5],[55,7],[53,1],[54,1],[52,4],[53,6],[52,5],[52,2],[53,3],[54,2],[53,7],[54,7],[0,0],[53,1],[54,4],[55,4],[55,1],[55,1],[53,3],[0,0],[0,0],[0,0],[53,3],[54,2],[53,1],[53,3],[53,2],[52,3],[53,5],[54,6],[52,1],[53,4],[53,2],[54,6],[52,7],[52,4],[55,7],[55,3],[53,3],[55,2],[53,2],[52,4],[53,5],[52,7],[52,6],[54,4],[52,2],[52,6],[52,6],[54,8],[52,5],[52,2],[52,1],[54,7],[0,0],[0,0],[52,4],[53,8],[52,6],[54,1],[53,6],[52,3],[0,0],[0,0],[53,7],[53,5],[55,6],[52,1],[54,1],[54,5],[52,3],[54,5],[55,4],[55,3],[54,3],[52,2],[0,0],[0,0],[52,8],[52,8],[0,0],[0,0],[52,3],[54,6],[54,1],[53,8],[53,2],[52,7],[55,5],[54,6],[55,1],[55,2],[52,4],[53,3],[53,7],[54,5],[55,8],[0,0],[0,0],[0,0],[52,7],[54,1],[55,2],[55,2],[55,3],[55,1],[52,5],[52,4],[55,4],[53,4],[55,4],[54,5],[55,2],[54,1],[53,4],[54,7],[54,3],[55,2],[54,3],[55,4],[53,7],[53,1],[50,5],[54,2],[54,3],[53,4],[52,3],[55,8],[52,3],[54,3],[54,5],[54,6],[53,1],[52,7],[54,2],[54,7],[53,8],[55,2],[54,4],[52,6],[53,2],[55,4],[53,7],[54,3],[55,7],[55,2],[53,3],[55,8],[53,7],[53,7],[53,4],[54,4],[52,7],[53,4],[52,2],[52,5],[55,3],[53,3],[53,1],[55,3],[55,4],[55,1],[53,2],[55,5],[54,2],[54,3],[55,1],[55,3],[53,1],[55,7],[52,6],[53,7],[55,1],[54,3],[52,8],[54,3],[53,3],[54,5],[54,3],[53,6],[53,4],[55,6],[54,4],[54,8],[55,1],[53,3],[52,2],[52,1],[52,2],[54,4],[52,6],[52,3],[55,5],[55,6],[54,2],[53,6],[52,2],[54,6],[52,3],[54,7],[53,5],[54,2],[52,5],[54,3],[53,1],[53,2],[55,3],[54,2],[52,3],[54,1],[55,3],[53,4],[0,0],[54,5],[53,1],[54,4],[53,2],[54,3],[53,3],[0,0],[0,0],[0,0],[53,1],[53,3],[52,1],[54,5],[52,2],[52,1],[52,7],[54,3],[53,7],[55,5],[53,3],[54,1],[53,3],[55,7],[53,2],[52,2],[52,4],[52,1],[54,1],[53,1],[53,2],[53,1],[55,4],[54,1],[53,3],[53,4],[53,2],[54,2],[52,2],[54,2],[55,3],[54,4],[0,0],[0,0],[53,3],[54,5],[53,8],[55,3],[52,6],[52,2],[55,6],[0,0],[0,0],[55,5],[52,1],[53,7],[54,6],[52,2],[52,1],[54,7],[52,8],[53,8],[53,3],[53,1],[55,7],[53,6],[52,1],[53,7],[0,0],[0,0],[55,3],[53,6],[55,1],[54,8],[54,3],[55,1],[52,7],[53,1],[52,2],[52,1],[52,3],[52,5],[54,2],[52,1],[53,2],[53,7],[55,2],[52,1],[55,2],[52,4],[52,1],[55,4],[52,6],[53,5],[53,1],[52,1],[53,4],[52,1],[55,2],[54,7],[55,5],[55,3],[55,2],[55,6],[55,2],[53,2],[52,1],[52,7],[55,2],[54,5],[54,7],[53,1],[53,1],[54,8],[53,2],[54,4],[53,3],[54,2],[52,1],[52,7],[52,5],[54,3],[52,2],[53,2],[53,6],[54,4],[54,2],[55,7],[55,2],[53,2],[53,1],[55,1],[54,2],[54,8],[53,4],[52,6],[55,8],[52,6],[54,2],[55,1],[55,3],[54,1],[52,3],[54,1],[54,5],[54,4],[53,1],[55,4],[53,1],[53,3],[54,7],[55,8],[55,2],[52,4],[55,3],[53,4],[55,1],[54,1],[53,6],[54,5],[55,2],[55,1],[52,1],[53,3],[55,1],[54,4],[54,2],[53,2],[54,3],[52,7],[50,5],[52,1],[54,3],[55,6],[54,6],[54,4],[55,3],[54,2],[53,1],[54,2],[54,5],[55,5],[53,4],[54,3],[53,1],[52,6],[52,1],[55,2],[53,8],[50,5],[52,4],[52,8],[52,4],[54,4],[53,4],[55,2],[53,1],[53,6],[53,1],[55,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[55,6],[54,2],[53,1],[55,8],[55,6],[54,7],[55,5],[52,2],[55,6],[55,6],[53,2],[55,7],[55,5],[50,5],[54,4],[52,2],[51,4],[54,1],[52,1],[52,2],[53,4],[52,2],[52,6],[55,5],[52,2],[54,3],[55,8],[53,4],[52,1],[53,7],[52,2],[53,4],[53,6],[0,0],[0,0],[55,1],[52,2],[55,4],[54,6],[53,6],[0,0],[0,0],[0,0],[52,4],[52,5],[53,1],[52,1],[54,4],[52,2],[52,6],[52,8],[54,4],[54,7],[53,1],[54,2],[52,6],[53,7],[55,3],[52,1],[52,3],[53,6],[53,1],[54,8],[53,5],[55,7],[53,5],[53,6],[54,2],[52,5],[55,1],[52,6],[53,6],[54,7],[52,8],[53,7],[52,1],[53,3],[55,7],[55,4],[52,2],[53,1],[53,2],[54,4],[53,5],[52,2],[52,3],[52,1],[53,1],[54,3],[52,1],[52,6],[52,2],[52,4],[52,6],[54,1],[54,1],[53,2],[53,3],[52,1],[55,1],[52,5],[55,4],[52,3],[55,2],[55,2],[52,2],[55,1],[55,1],[55,3],[55,1],[52,2],[52,2],[54,2],[53,3],[55,2],[53,5],[52,3],[52,2],[52,8],[55,3],[54,4],[53,3],[53,2],[53,6],[54,7],[54,1],[55,4],[52,1],[54,3],[53,3],[55,1],[55,1],[53,6],[54,3],[53,1],[55,7],[55,6],[53,4],[53,3],[53,3],[53,4],[53,5],[53,1],[54,2],[54,4],[53,4],[53,6],[54,1],[54,7],[52,2],[53,2],[55,6],[53,4],[54,1],[55,3],[52,1],[55,6],[53,2],[52,2],[54,8],[53,3],[52,2],[53,3],[55,6],[52,1],[54,2],[55,2],[54,1],[52,4],[55,1],[52,2],[52,8],[53,2],[52,1],[52,2],[53,1],[52,7],[53,2],[53,7],[53,5],[55,4],[54,1],[53,1],[54,3],[52,7],[54,7],[54,7],[53,1],[54,1],[52,7],[0,0],[0,0],[52,1],[53,7],[54,1],[53,1],[52,8],[52,6],[54,7],[52,6],[0,0],[0,0],[53,2],[55,3],[52,1],[54,2],[55,3],[55,5],[52,6],[52,4],[52,2],[54,5],[53,1],[52,1],[53,5],[53,1],[53,1],[53,6],[54,1],[55,2],[55,2],[0,0],[0,0],[54,6],[54,1],[55,5],[55,2],[54,2],[52,7],[55,3],[54,6],[54,3],[55,7],[54,3],[53,5],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[54,5],[53,2],[52,6],[52,3],[54,4],[52,2],[53,2],[53,6],[53,4],[54,4],[54,7],[55,1],[52,5],[54,1],[54,7],[55,4],[54,1],[55,1],[53,1],[55,2],[54,6],[52,7],[52,8],[53,3],[54,4],[52,2],[55,1],[53,3],[52,6],[52,2],[53,6],[55,1],[54,3],[54,5],[53,1],[54,3],[54,2],[52,1],[52,2],[53,4],[54,2],[53,1],[54,7],[54,2],[55,1],[55,4],[52,1],[53,2],[53,1],[53,2],[53,1],[53,4],[55,1],[55,8],[54,2],[54,1],[53,2],[52,1],[54,1],[52,4],[0,0],[0,0],[52,1],[53,2],[52,4],[52,1],[54,4],[53,1],[54,7],[53,5],[53,7],[53,1],[55,7],[53,8],[53,3],[52,4],[52,6],[53,7],[53,3],[55,4],[54,4],[54,3],[54,2],[52,3],[53,5],[53,2],[54,5],[55,8],[53,8],[52,5],[53,1],[52,7],[53,2],[55,4],[53,1],[55,1],[53,6],[52,6],[54,6],[55,2],[55,7],[55,7],[53,1],[54,4],[53,2],[52,4],[53,1],[53,2],[54,3],[52,8],[53,1],[54,6],[52,1],[52,4],[53,3],[53,5],[54,5],[55,5],[53,8],[52,7],[52,2],[52,2],[52,1],[54,1],[55,7],[55,4],[55,7],[53,3],[54,2],[54,5],[54,6],[54,8],[53,1],[52,7],[55,2],[52,5],[55,8],[54,1],[52,6],[55,7],[53,1],[54,2],[53,1],[54,4],[54,6],[52,6],[53,3],[0,0],[0,0],[54,4],[53,6],[52,2],[55,3],[52,6],[53,5],[55,1],[55,5],[0,0],[0,0],[55,2],[54,1],[52,1],[53,3],[52,4],[54,7],[52,3],[52,2],[52,5],[52,2],[52,1],[53,4],[52,1],[54,5],[55,2],[55,4],[55,6],[52,4],[55,2],[0,0],[0,0],[53,4],[54,1],[55,6],[54,6],[55,3],[52,4],[52,2],[52,1],[53,1],[53,1],[55,2],[54,2],[55,6],[55,8],[54,4],[53,2],[53,3],[0,0],[0,0],[0,0],[0,0],[53,2],[54,3],[53,3],[55,1],[53,1],[54,5],[53,2],[52,1],[53,6],[53,6],[54,7],[55,3],[54,1],[55,8],[55,3],[52,7],[54,4],[53,2],[55,7],[52,2],[52,5],[55,5],[54,4],[53,6],[52,2],[52,6],[53,5],[53,3],[52,2],[52,6],[52,4],[52,8],[54,3],[52,8],[55,2],[53,7],[55,2],[52,1],[54,6],[52,1],[53,3],[55,2],[55,2],[55,3],[55,1],[53,8],[53,2],[55,5],[55,6],[52,2],[53,6],[52,4],[53,3],[55,3],[52,2],[52,1],[52,5],[52,8],[53,1],[0,0],[0,0],[53,1],[53,3],[54,6],[53,2],[54,5],[54,1],[52,3],[52,8],[54,5],[53,5],[53,2],[53,5],[52,5],[54,1],[53,7],[53,6],[52,1],[53,2],[54,1],[55,4],[53,1],[52,7],[54,2],[54,4],[55,7],[52,7],[53,1],[55,3],[50,5],[54,7],[52,1],[53,6],[53,7],[55,3],[53,5],[55,3],[53,2],[53,8],[52,3],[55,5],[52,4],[52,4],[55,3],[53,3],[55,6],[55,2],[55,8],[52,8],[52,4],[52,4],[53,5],[53,4],[54,3],[54,2],[53,5],[52,3],[55,3],[52,3],[52,4],[55,7],[53,3],[52,7],[52,1],[55,6],[54,5],[55,2],[54,2],[53,1],[53,3],[52,8],[54,1],[53,1],[52,6],[54,3],[54,2],[55,3],[53,2],[52,1],[55,3],[52,3],[54,2],[54,1],[52,2],[53,6],[55,2],[0,0],[0,0],[55,6],[52,5],[52,5],[53,7],[53,5],[52,5],[55,7],[55,7],[55,7],[52,1],[0,0],[0,0],[55,4],[55,1],[53,5],[54,4],[52,2],[53,2],[53,1],[52,5],[54,5],[52,3],[53,5],[54,1],[53,5],[53,1],[55,5],[52,3],[54,1],[0,0],[53,2],[55,3],[52,8],[52,5],[52,2],[55,7],[53,2],[53,2],[55,6],[52,1],[55,5],[53,7],[55,2],[54,5],[54,1],[55,8],[53,1],[55,4],[52,2],[55,4],[53,2],[0,0],[0,0],[52,8],[52,4],[53,4],[53,2],[55,2],[53,2],[54,3],[55,2],[53,1],[53,1],[55,2],[54,5],[54,1],[55,2],[54,1],[55,4],[53,3],[55,3],[54,1],[52,1],[55,2],[55,2],[54,3],[53,4],[54,6],[53,2],[54,1],[55,2],[54,2],[52,2],[52,6],[55,1],[55,2],[54,6],[53,3],[53,3],[53,3],[55,8],[54,5],[52,2],[54,5],[53,5],[54,5],[54,5],[52,5],[55,1],[54,7],[53,1],[52,1],[55,7],[55,7],[52,8],[54,5],[52,4],[55,2],[54,5],[53,3],[53,1],[0,0],[54,2],[52,3],[54,3],[53,1],[55,2],[52,1],[55,5],[53,2],[53,1],[55,2],[54,3],[52,5],[52,6],[53,6],[54,2],[55,2],[54,4],[55,3],[54,1],[53,5],[55,2],[54,7],[55,5],[53,1],[53,3],[52,7],[55,3],[53,1],[52,5],[52,2],[54,3],[54,1],[0,0],[0,0],[55,7],[52,7],[53,1],[55,3],[52,1],[53,1],[53,8],[55,3],[53,7],[52,7],[52,2],[55,1],[54,2],[55,1],[55,7],[52,5],[55,6],[53,7],[54,1],[55,1],[54,2],[55,2],[52,3],[53,1],[55,4],[52,5],[53,2],[52,3],[55,2],[53,2],[55,7],[52,3],[53,8],[54,1],[54,2],[52,5],[53,3],[54,4],[54,2],[52,7],[52,1],[52,2],[54,8],[52,2],[52,1],[53,7],[53,3],[53,2],[54,5],[55,6],[52,2],[55,6],[0,0],[52,3],[53,2],[53,1],[52,2],[55,1],[52,6],[52,1],[55,1],[52,4],[54,8],[54,3],[0,0],[0,0],[52,2],[52,3],[53,2],[52,8],[54,5],[54,4],[53,6],[55,2],[53,5],[55,2],[53,5],[53,2],[54,6],[54,4],[55,1],[52,6],[54,2],[52,5],[54,5],[0,0],[0,0],[52,6],[55,3],[52,8],[55,1],[52,3],[54,6],[55,1],[54,3],[55,1],[52,1],[53,1],[55,8],[52,4],[54,5],[55,2],[52,3],[55,4],[52,1],[55,5],[0,0],[0,0],[0,0],[52,3],[54,3],[54,7],[52,2],[52,1],[55,1],[55,4],[52,5],[55,2],[54,2],[54,6],[55,5],[52,4],[52,4],[54,6],[52,1],[52,6],[52,3],[53,3],[54,1],[52,3],[53,2],[52,7],[54,7],[55,3],[55,7],[55,7],[52,3],[53,2],[52,1],[55,4],[54,1],[55,1],[54,5],[52,5],[52,1],[55,3],[52,2],[55,1],[52,6],[53,2],[53,4],[53,2],[53,3],[54,2],[54,3],[54,6],[52,4],[52,4],[53,2],[53,2],[54,7],[55,3],[52,4],[52,2],[55,7],[53,6],[52,3],[0,0],[0,0],[53,6],[54,4],[53,2],[52,5],[55,1],[54,4],[54,1],[55,4],[54,6],[55,4],[53,4],[55,1],[52,7],[52,2],[54,1],[52,7],[55,2],[55,1],[54,8],[52,1],[53,2],[52,1],[54,6],[54,1],[53,2],[54,1],[54,1],[55,8],[52,1],[0,0],[0,0],[55,4],[53,1],[54,3],[52,8],[54,8],[53,2],[55,8],[53,7],[55,6],[53,2],[53,1],[53,3],[53,7],[55,3],[54,6],[53,1],[52,3],[54,2],[55,2],[52,6],[53,4],[53,1],[52,4],[53,8],[55,4],[54,2],[52,4],[52,1],[55,3],[53,1],[55,6],[55,2],[55,7],[54,6],[55,1],[55,1],[54,3],[53,1],[53,6],[54,8],[52,1],[55,2],[52,1],[53,2],[52,4],[52,7],[53,3],[55,2],[54,6],[53,2],[53,6],[53,1],[0,0],[0,0],[53,3],[53,2],[53,1],[54,2],[52,3],[54,4],[50,5],[55,8],[55,2],[54,8],[50,5],[53,1],[0,0],[0,0],[52,2],[55,4],[55,4],[52,2],[54,8],[55,3],[54,3],[53,1],[55,2],[52,6],[53,6],[54,2],[53,1],[52,1],[55,8],[0,0],[54,3],[0,0],[0,0],[55,3],[52,2],[55,1],[53,5],[54,2],[54,1],[54,2],[55,4],[52,3],[53,3],[54,5],[53,2],[54,1],[52,7],[54,3],[53,7],[55,8],[53,3],[55,4],[0,0],[0,0],[0,0],[52,3],[54,3],[52,5],[53,6],[53,4],[52,1],[54,1],[53,4],[55,6],[52,1],[52,1],[54,2],[53,5],[55,3],[55,5],[54,5],[52,6],[52,1],[53,5],[55,7],[53,4],[53,3],[52,2],[55,2],[53,5],[54,4],[54,1],[54,3],[52,5],[54,3],[55,2],[55,1],[53,8],[54,5],[53,5],[52,3],[54,5],[53,6],[53,7],[55,8],[53,2],[52,7],[55,8],[53,2],[54,3],[54,6],[54,2],[53,3],[53,7],[55,1],[55,4],[55,5],[52,4],[52,6],[52,1],[55,7],[0,0],[52,2],[0,0],[0,0],[54,3],[54,5],[52,8],[54,5],[54,2],[52,1],[53,3],[54,5],[55,4],[53,2],[55,3],[55,1],[55,6],[53,1],[54,1],[52,4],[52,3],[55,2],[55,7],[53,4],[52,7],[54,2],[54,2],[53,3],[54,2],[55,6],[52,1],[52,2],[0,0],[0,0],[52,6],[55,1],[0,0],[0,0],[53,8],[52,4],[54,2],[53,1],[54,1],[54,2],[55,2],[53,6],[55,7],[53,4],[55,6],[54,2],[53,1],[55,2],[54,1],[55,6],[53,6],[53,8],[54,5],[54,5],[52,2],[55,3],[55,2],[54,3],[54,1],[54,5],[54,8],[53,2],[54,1],[52,2],[53,5],[52,1],[54,5],[55,4],[54,2],[55,1],[55,4],[52,5],[55,2],[55,5],[53,7],[54,1],[52,3],[53,2],[52,1],[52,1],[52,7],[53,2],[0,0],[0,0],[0,0],[52,8],[53,8],[55,1],[52,8],[52,7],[50,5],[52,5],[54,8],[52,7],[55,6],[53,1],[54,8],[0,0],[0,0],[53,1],[53,3],[55,2],[55,1],[52,2],[55,1],[53,2],[52,3],[53,3],[55,6],[53,8],[55,8],[55,2],[55,3],[55,6],[55,2],[54,1],[52,6],[52,1],[52,3],[52,2],[54,6],[55,3],[54,6],[55,6],[55,1],[54,1],[52,3],[52,3],[52,4],[55,3],[55,7],[54,2],[52,3],[52,1],[53,3],[54,6],[54,1],[0,0],[0,0],[0,0],[0,0],[54,3],[55,7],[54,6],[54,2],[52,4],[53,2],[55,6],[52,7],[53,1],[53,2],[52,3],[53,1],[55,3],[55,5],[55,1],[52,2],[54,1],[55,4],[53,2],[52,6],[54,6],[55,8],[54,6],[53,5],[55,2],[52,2],[55,5],[52,1],[53,3],[52,5],[52,4],[52,7],[54,7],[53,4],[55,8],[52,3],[52,2],[55,1],[53,5],[54,8],[52,6],[53,8],[52,2],[55,2],[54,2],[55,8],[54,5],[55,4],[52,1],[55,7],[52,1],[54,2],[52,2],[55,3],[54,3],[53,3],[54,2],[52,3],[52,2],[55,5],[53,1],[52,6],[54,5],[53,3],[52,5],[55,7],[54,2],[53,8],[52,6],[55,1],[55,5],[52,2],[53,5],[53,3],[52,7],[50,5],[53,3],[52,4],[54,7],[52,5],[55,3],[54,3],[53,7],[55,2],[53,5],[52,2],[54,1],[52,6],[54,4],[53,6],[55,5],[0,0],[0,0],[54,7],[54,7],[54,1],[54,2],[52,2],[54,5],[54,7],[54,3],[52,1],[55,4],[53,5],[53,1],[54,1],[55,3],[52,4],[54,3],[54,1],[52,5],[54,7],[55,1],[55,2],[54,2],[52,4],[52,6],[54,5],[55,2],[54,1],[0,0],[53,6],[0,0],[0,0],[55,2],[0,0],[0,0],[0,0],[0,0],[52,1],[53,2],[0,0],[0,0],[0,0],[52,1],[53,3],[52,5],[53,2],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,1],[52,1],[54,7],[55,1],[52,7],[53,6],[54,3],[53,6],[53,1],[52,3],[52,1],[55,7],[54,2],[53,2],[0,0],[0,0],[0,0],[55,1],[55,7],[53,5],[54,1],[55,4],[55,2],[53,3],[53,1],[53,7],[53,5],[52,4],[53,2],[52,5],[53,3],[0,0],[0,0],[52,2],[54,2],[50,5],[50,5],[55,4],[55,2],[53,3],[53,2],[53,2],[54,5],[54,1],[53,2],[52,3],[52,1],[53,2],[54,7],[53,2],[54,8],[52,7],[53,6],[53,6],[55,1],[0,0],[0,0],[54,8],[54,5],[53,3],[53,5],[53,4],[55,4],[54,2],[54,1],[53,2],[52,8],[53,3],[54,7],[53,7],[52,1],[53,2],[55,2],[53,6],[54,2],[55,6],[54,7],[55,1],[54,3],[54,8],[55,2],[54,2],[53,1],[52,4],[52,2],[54,7],[53,1],[54,7],[52,1],[55,3],[54,6],[55,2],[54,7],[52,7],[54,2],[52,3],[53,6],[55,3],[55,6],[54,8],[54,2],[53,2],[55,3],[50,5],[52,5],[52,8],[53,1],[52,2],[52,8],[54,8],[55,1],[52,2],[55,2],[0,0],[0,0],[53,7],[55,5],[0,0],[0,0],[0,0],[0,0],[53,7],[54,1],[54,1],[52,4],[53,4],[55,1],[55,3],[54,6],[52,3],[53,6],[53,2],[53,5],[52,1],[53,2],[52,1],[55,1],[55,2],[53,3],[54,2],[54,8],[52,5],[55,7],[55,2],[55,7],[52,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[54,5],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[54,2],[55,1],[52,8],[54,2],[52,2],[55,5],[53,8],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[52,6],[53,5],[52,4],[52,1],[54,5],[53,3],[53,4],[53,2],[52,3],[55,7],[54,2],[55,2],[0,0],[0,0],[0,0],[53,2],[55,2],[53,2],[52,1],[54,1],[54,1],[55,1],[52,3],[55,6],[55,2],[55,4],[53,2],[55,7],[53,5],[0,0],[0,0],[53,3],[52,5],[55,5],[54,6],[52,5],[55,5],[53,7],[55,4],[53,8],[54,2],[55,2],[55,1],[52,1],[55,1],[54,8],[54,7],[54,8],[53,3],[53,7],[54,2],[53,4],[53,4],[0,0],[0,0],[52,3],[52,2],[53,8],[55,2],[52,1],[54,1],[53,3],[55,5],[55,3],[55,2],[55,5],[52,2],[53,2],[52,1],[55,6],[52,1],[55,1],[54,8],[53,3],[55,5],[53,1],[52,3],[54,5],[50,5],[54,2],[52,3],[52,2],[52,1],[55,7],[52,3],[52,2],[53,3],[55,1],[52,2],[53,5],[53,3],[55,7],[54,5],[53,3],[54,7],[53,4],[55,8],[55,5],[53,3],[53,3],[52,1],[54,1],[53,1],[52,2],[54,7],[54,2],[55,1],[52,2],[52,2],[52,6],[53,4],[0,0],[0,0],[52,8],[55,6],[52,3],[52,3],[53,5],[52,1],[52,5],[53,7],[53,1],[54,4],[53,1],[54,1],[54,2],[53,2],[55,1],[55,3],[53,1],[55,7],[52,1],[53,5],[53,2],[53,4],[54,7],[53,8],[53,4],[53,4],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[52,1],[54,3],[55,1],[52,2],[55,1],[53,2],[54,5],[54,7],[55,2],[52,2],[54,6],[55,1],[54,2],[52,6],[53,2],[52,5],[53,3],[55,3],[52,5],[52,3],[54,2],[55,5],[53,3],[52,4],[52,2],[52,3],[54,4],[54,1],[52,6],[55,6],[54,4],[54,2],[52,3],[52,5],[53,7],[52,5],[53,7],[53,2],[55,1],[54,8],[54,2],[53,5],[54,6],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[55,8],[53,2],[0,0],[55,6],[53,8],[52,2],[55,1],[53,1],[52,3],[55,1],[54,5],[53,1],[52,4],[55,4],[54,2],[53,5],[52,2],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,1],[53,1],[52,5],[54,2],[53,4],[55,6],[54,5],[52,8],[55,3],[54,5],[54,4],[53,5],[55,4],[0,0],[0,0],[0,0],[52,2],[54,5],[54,7],[54,1],[53,3],[52,2],[52,6],[54,1],[55,1],[52,3],[53,5],[53,1],[55,4],[54,6],[55,3],[54,1],[53,7],[55,2],[54,2],[54,6],[0,0],[0,0],[0,0],[53,7],[54,5],[52,1],[55,2],[53,1],[53,1],[53,1],[53,1],[55,2],[55,6],[53,1],[54,3],[53,6],[55,3],[55,2],[52,4],[53,1],[54,8],[53,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[54,3],[0,0],[0,0],[0,0],[54,3],[53,2],[54,1],[54,6],[54,1],[55,4],[54,4],[52,6],[54,7],[54,6],[54,6],[52,1],[54,3],[55,1],[54,1],[52,4],[52,5],[54,7],[53,1],[53,5],[54,1],[50,5],[52,1],[0,0],[53,5],[54,6],[53,3],[53,2],[53,5],[54,1],[55,1],[55,2],[54,7],[52,2],[54,3],[52,3],[54,2],[53,1],[54,5],[55,1],[54,8],[54,6],[54,7],[54,5],[54,5],[53,1],[55,2],[50,5],[53,7],[55,1],[54,2],[55,1],[52,2],[52,2],[52,1],[52,5],[52,1],[55,2],[54,2],[53,3],[52,1],[53,4],[53,1],[52,2],[53,5],[55,2],[53,4],[53,1],[53,2],[54,1],[54,2],[54,1],[53,5],[55,2],[0,0],[0,0],[54,5],[53,8],[52,1],[53,1],[53,5],[0,0],[52,6],[55,2],[53,1],[53,6],[50,5],[53,1],[53,1],[55,2],[53,8],[52,2],[54,4],[52,3],[54,2],[54,2],[52,1],[53,1],[54,6],[0,0],[0,0],[0,0],[52,3],[53,7],[54,6],[0,0],[0,0],[0,0],[54,7],[54,5],[52,3],[50,5],[54,1],[53,3],[55,2],[0,0],[0,0],[0,0],[55,3],[53,4],[55,4],[53,4],[52,3],[52,8],[54,2],[53,3],[53,6],[52,3],[53,1],[54,7],[54,4],[53,5],[54,1],[54,2],[55,7],[55,3],[52,6],[55,2],[50,5],[52,3],[0,0],[0,0],[0,0],[0,0],[53,2],[55,1],[52,8],[53,7],[55,2],[54,1],[53,4],[52,4],[52,1],[55,5],[55,3],[53,1],[0,0],[53,6],[52,7],[53,8],[55,7],[55,5],[54,6],[52,5],[55,1],[54,1],[52,2],[54,2],[53,8],[53,6],[53,5],[53,4],[55,1],[52,5],[54,7],[55,4],[55,3],[52,1],[52,8],[53,4],[53,2],[55,3],[52,4],[53,5],[54,2],[53,7],[55,1],[53,6],[54,5],[54,6],[53,2],[55,6],[53,4],[55,2],[53,6],[55,2],[53,2],[0,0],[0,0],[0,0],[52,1],[52,2],[54,2],[53,3],[52,3],[53,7],[53,5],[53,2],[52,7],[55,2],[54,1],[55,7],[54,6],[52,1],[53,2],[52,5],[50,5],[52,4],[54,4],[0,0],[0,0],[0,0],[0,0],[0,0],[52,1],[52,1],[53,3],[52,8],[55,6],[52,6],[55,3],[53,3],[53,1],[55,7],[52,3],[55,7],[54,1],[54,2],[52,7],[53,2],[54,2],[55,8],[54,1],[55,1],[52,3],[52,2],[53,3],[54,3],[53,1],[54,4],[55,2],[52,2],[52,1],[50,5],[55,5],[53,5],[55,1],[54,5],[55,2],[52,3],[52,4],[55,8],[54,2],[53,3],[54,7],[55,3],[52,2],[54,6],[55,1],[52,1],[55,4],[54,2],[52,1],[55,2],[54,7],[55,1],[0,0],[0,0],[55,2],[54,2],[55,3],[52,5],[55,7],[52,6],[52,3],[52,4],[52,8],[54,3],[52,3],[53,5],[52,7],[52,1],[55,1],[52,7],[55,6],[50,5],[54,3],[53,2],[53,6],[0,0],[0,0],[0,0],[55,2],[52,3],[55,2],[0,0],[0,0],[0,0],[55,1],[54,2],[53,5],[52,1],[54,3],[55,1],[55,6],[0,0],[0,0],[0,0],[54,7],[52,2],[54,1],[53,5],[55,1],[52,1],[53,3],[54,1],[54,3],[53,7],[55,1],[55,2],[53,3],[55,1],[52,6],[53,1],[54,7],[55,3],[53,7],[54,7],[53,2],[54,5],[52,3],[55,3],[54,5],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[54,3],[53,1],[52,6],[52,7],[53,1],[53,7],[53,1],[53,1],[54,2],[53,2],[53,2],[53,8],[52,3],[55,3],[53,7],[52,4],[52,1],[52,1],[53,4],[55,3],[53,2],[53,3],[55,4],[55,2],[55,1],[54,8],[53,2],[54,1],[53,7],[52,2],[54,2],[53,6],[55,2],[52,7],[53,1],[53,3],[52,3],[52,2],[52,3],[55,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,6],[55,2],[52,5],[55,3],[53,5],[53,3],[52,2],[55,1],[55,8],[53,5],[54,5],[52,1],[55,1],[52,6],[55,2],[54,2],[54,1],[53,2],[55,6],[53,8],[54,5],[52,8],[55,1],[54,3],[54,4],[53,2],[55,2],[55,1],[53,7],[54,2],[55,3],[54,1],[54,1],[55,3],[54,7],[53,2],[55,1],[55,3],[53,1],[52,4],[52,3],[52,7],[54,2],[55,4],[54,3],[54,3],[55,3],[55,1],[55,2],[55,5],[55,6],[54,2],[52,1],[54,3],[55,2],[53,2],[0,0],[0,0],[52,1],[54,1],[52,2],[55,1],[54,7],[52,6],[52,1],[55,2],[54,3],[55,5],[53,1],[52,1],[55,6],[52,1],[54,4],[55,4],[53,2],[54,2],[50,5],[53,1],[52,6],[53,7],[52,4],[53,3],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[54,2],[53,2],[52,5],[55,8],[54,7],[55,3],[53,5],[55,3],[52,1],[52,6],[52,7],[53,2],[55,2],[53,3],[54,3],[54,7],[54,1],[55,2],[53,3],[52,3],[54,5],[53,1],[53,2],[52,2],[54,7],[54,3],[55,5],[54,6],[52,4],[52,7],[54,6],[53,5],[55,5],[54,2],[54,3],[53,3],[53,2],[53,6],[55,5],[0,0],[55,4],[55,1],[53,7],[54,7],[54,1],[52,8],[53,7],[53,2],[52,8],[55,4],[55,6],[52,7],[54,4],[55,3],[53,1],[53,4],[52,2],[55,6],[55,2],[55,1],[54,2],[50,5],[53,6],[55,6],[53,2],[53,4],[52,2],[55,5],[52,5],[52,8],[53,1],[55,2],[53,3],[54,2],[52,4],[53,2],[52,1],[54,3],[55,1],[53,8],[52,2],[54,3],[55,6],[54,2],[55,3],[52,4],[55,5],[55,5],[53,2],[53,3],[52,1],[55,7],[55,2],[55,4],[55,3],[52,1],[54,1],[55,3],[53,6],[53,2],[53,2],[53,7],[53,3],[55,4],[55,3],[55,4],[55,4],[54,4],[55,3],[55,1],[55,1],[53,1],[52,8],[53,7],[55,1],[54,2],[53,8],[54,5],[54,6],[52,1],[53,3],[53,5],[52,4],[52,7],[54,1],[52,2],[52,4],[54,2],[52,1],[55,1],[53,1],[52,7],[53,3],[52,5],[54,1],[54,7],[54,8],[52,2],[53,1],[55,3],[55,1],[52,1],[55,8],[54,5],[55,5],[52,2],[55,1],[52,2],[52,2],[55,8],[52,2],[52,8],[55,2],[52,1],[52,2],[54,4],[54,1],[54,2],[52,3],[54,5],[54,5],[52,8],[55,7],[55,5],[52,5],[55,6],[55,4],[53,1],[55,1],[55,2],[0,0],[0,0],[0,0],[0,0],[0,0],[53,1],[53,1],[54,1],[52,7],[52,2],[52,7],[53,2],[54,7],[55,2],[54,2],[54,6],[53,1],[54,3],[54,8],[54,1],[53,2],[55,2],[55,3],[52,5],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,2],[53,1],[53,5],[55,5],[54,4],[52,1],[54,7],[54,3],[54,3],[53,1],[55,7],[54,1],[53,4],[53,1],[55,4],[55,2],[52,6],[54,2],[53,5],[55,4],[54,2],[55,2],[53,1],[53,2],[54,1],[53,3],[55,1],[53,6],[52,2],[52,2],[54,4],[54,4],[55,2],[55,1],[55,6],[54,3],[53,7],[0,0],[0,0],[55,8],[55,6],[55,3],[53,4],[52,3],[54,4],[53,8],[55,2],[52,4],[52,4],[53,1],[55,2],[55,6],[53,3],[52,5],[55,1],[54,6],[55,2],[52,1],[53,8],[55,5],[52,7],[53,5],[55,2],[53,6],[52,2],[52,4],[55,6],[54,6],[53,2],[54,4],[53,8],[52,7],[52,2],[55,2],[53,1],[52,5],[53,2],[53,1],[53,7],[52,6],[52,5],[52,6],[54,8],[53,6],[52,6],[54,6],[52,7],[52,4],[53,2],[53,7],[53,3],[53,2],[54,4],[54,1],[55,4],[52,8],[52,4],[54,6],[52,7],[54,5],[55,1],[53,6],[53,1],[53,7],[52,7],[54,2],[52,7],[54,6],[54,1],[55,6],[53,7],[55,6],[53,7],[55,8],[54,4],[55,7],[54,2],[52,6],[55,5],[54,1],[54,2],[53,7],[54,2],[53,4],[55,7],[52,6],[55,6],[55,8],[53,8],[53,7],[55,6],[53,1],[54,3],[55,1],[55,1],[54,5],[52,2],[53,2],[54,2],[54,3],[52,3],[53,7],[50,5],[53,4],[54,5],[55,4],[52,4],[53,2],[53,2],[53,1],[55,3],[55,1],[52,3],[53,2],[55,7],[53,2],[55,1],[52,7],[54,5],[53,3],[55,3],[53,1],[54,4],[54,2],[53,3],[55,1],[55,4],[52,2],[55,4],[52,6],[53,1],[52,2],[54,4],[53,3],[54,1],[55,5],[53,4],[53,3],[50,5],[55,2],[53,1],[55,2],[55,4],[55,1],[52,1],[54,1],[54,1],[52,3],[52,3],[55,2],[52,6],[54,2],[0,0],[0,0],[0,0],[54,6],[53,3],[53,5],[0,0],[0,0],[55,2],[52,5],[53,2],[55,1],[54,2],[54,2],[53,3],[52,1],[54,5],[55,1],[55,7],[54,6],[52,3],[53,1],[52,1],[53,5],[52,5],[55,3],[53,5],[53,4],[52,6],[55,2],[54,3],[52,8],[55,4],[54,2],[54,2],[55,3],[52,2],[54,1],[54,2],[55,3],[55,1],[55,6],[54,5],[54,1],[55,2],[0,0],[0,0],[55,7],[54,1],[52,1],[54,8],[55,3],[55,3],[54,3],[54,2],[55,2],[50,5],[54,1],[53,7],[55,1],[53,2],[55,3],[53,2],[55,2],[53,3],[53,4],[53,2],[52,8],[54,4],[54,3],[53,5],[53,2],[55,4],[54,5],[55,1],[52,6],[53,4],[55,2],[53,5],[53,2],[53,7],[54,1],[52,4],[54,3],[53,6],[53,6],[55,7],[52,1],[53,6],[54,1],[52,2],[53,3],[55,2],[52,4],[55,8],[55,5],[53,6],[52,6],[52,7],[52,4],[54,3],[55,4],[52,2],[54,1],[53,6],[50,5],[53,2],[52,1],[53,1],[53,7],[55,2],[55,1],[53,7],[55,3],[54,1],[55,1],[54,8],[54,3],[50,5],[55,5],[52,1],[54,2],[54,1],[54,2],[53,3],[54,6],[53,2],[52,5],[54,6],[54,3],[52,2],[52,1],[52,4],[54,2],[54,2],[54,5],[55,6],[53,3],[52,2],[52,5],[54,3],[53,2],[53,4],[54,5],[54,2],[52,1],[53,6],[53,4],[52,4],[52,4],[53,3],[53,5],[55,7],[52,2],[53,5],[55,7],[52,1],[53,6],[52,4],[54,5],[54,3],[54,3],[55,4],[55,2],[52,5],[54,2],[54,2],[54,1],[52,2],[52,1],[54,5],[55,3],[52,7],[53,3],[53,8],[55,1],[52,2],[53,2],[53,4],[54,6],[55,2],[55,2],[52,3],[54,7],[55,1],[55,6],[55,7],[52,7],[52,8],[52,6],[55,6],[55,3],[54,3],[55,1],[52,5],[53,3],[55,3],[55,3],[55,2],[55,4],[53,5],[52,3],[55,1],[54,4],[53,1],[52,3],[52,2],[55,1],[0,0],[52,2],[53,4],[52,3],[53,3],[52,7],[54,7],[53,2],[55,5],[53,3],[52,4],[55,1],[55,1],[54,2],[53,2],[54,1],[55,2],[55,2],[53,5],[55,1],[53,7],[52,3],[52,8],[53,2],[55,5],[53,8],[54,3],[52,5],[53,1],[52,5],[55,2],[55,5],[53,2],[54,6],[54,2],[55,4],[54,5],[0,0],[0,0],[55,1],[52,5],[52,2],[52,1],[55,3],[55,2],[52,3],[53,5],[54,5],[53,2],[52,2],[52,1],[55,4],[53,8],[50,5],[53,4],[54,7],[54,1],[54,5],[55,6],[53,4],[52,2],[54,3],[55,2],[53,6],[54,1],[54,1],[54,5],[53,4],[55,5],[54,5],[54,7],[55,4],[54,7],[54,5],[53,7],[52,2],[55,7],[54,3],[54,6],[54,7],[52,2],[55,6],[54,6],[55,6],[54,5],[55,4],[52,8],[55,1],[54,3],[54,4],[54,4],[55,4],[52,1],[52,2],[54,6],[54,3],[52,1],[53,7],[54,2],[53,1],[52,3],[55,3],[55,2],[52,1],[54,2],[54,4],[55,7],[52,1],[52,2],[54,2],[52,1],[55,7],[55,3],[54,4],[54,1],[52,2],[52,4],[55,2],[53,2],[53,2],[52,2],[55,2],[52,6],[53,2],[54,1],[54,5],[52,3],[54,1],[52,6],[55,8],[52,2],[53,2],[55,2],[55,2],[52,1],[53,1],[55,3],[54,4],[55,5],[54,1],[54,3],[52,5],[52,8],[54,1],[54,3],[53,2],[54,6],[55,2],[52,3],[53,4],[52,1],[54,6],[55,3],[53,2],[54,6],[55,3],[55,6],[53,3],[53,4],[50,5],[55,1],[53,3],[52,1],[52,5],[54,5],[53,3],[53,1],[55,4],[55,6],[55,6],[54,2],[52,4],[52,4],[53,2],[52,3],[52,2],[53,8],[54,5],[54,4],[54,1],[54,5],[52,6],[55,1],[53,6],[53,1],[55,3],[50,5],[54,2],[52,2],[52,8],[53,1],[55,2],[54,1],[55,1],[55,1],[52,8],[55,7],[53,4],[54,8],[52,3],[55,1],[0,0],[0,0],[0,0],[52,1],[55,4],[54,6],[52,6],[55,7],[53,1],[55,4],[55,1],[55,1],[55,1],[54,2],[55,5],[55,5],[55,1],[54,2],[52,4],[54,2],[53,1],[52,1],[55,4],[55,8],[53,2],[53,2],[52,3],[55,4],[54,1],[54,5],[52,7],[55,2],[54,1],[52,8],[53,1],[0,0],[0,0],[0,0],[52,7],[52,4],[52,6],[55,7],[54,1],[53,5],[52,3],[53,5],[52,4],[53,1],[52,7],[53,5],[55,5],[52,2],[52,6],[54,3],[54,1],[55,1],[53,2],[52,2],[55,6],[53,8],[54,5],[55,7],[52,2],[52,1],[53,2],[53,3],[55,3],[54,2],[53,2],[54,2],[0,0],[0,0],[52,6],[52,7],[52,2],[52,6],[52,1],[53,1],[52,1],[54,7],[53,2],[53,6],[55,1],[52,1],[55,7],[52,3],[55,3],[53,2],[54,2],[52,3],[55,7],[53,6],[55,5],[55,5],[53,4],[53,4],[53,4],[52,6],[55,6],[54,4],[54,7],[53,5],[53,4],[53,3],[53,4],[55,4],[53,4],[55,1],[52,7],[55,2],[54,1],[55,1],[54,3],[54,4],[54,1],[52,2],[55,3],[55,3],[53,2],[52,5],[55,1],[52,8],[55,1],[52,8],[54,3],[54,5],[53,6],[54,2],[54,1],[53,5],[52,4],[53,2],[55,3],[52,4],[54,3],[54,4],[55,7],[53,2],[54,1],[55,6],[53,2],[55,7],[53,2],[52,4],[54,8],[55,1],[55,6],[53,1],[52,5],[54,8],[52,2],[53,4],[54,5],[52,2],[54,3],[54,8],[54,4],[54,2],[52,5],[53,8],[55,7],[55,8],[52,7],[53,3],[55,8],[53,2],[53,1],[54,2],[52,2],[55,2],[54,2],[53,7],[55,5],[55,6],[53,3],[54,3],[54,6],[55,7],[52,3],[52,3],[53,1],[54,1],[55,3],[55,2],[55,5],[55,3],[52,5],[52,2],[55,2],[52,2],[54,7],[53,1],[55,3],[55,4],[55,2],[55,5],[54,7],[54,7],[53,3],[53,2],[0,0],[0,0],[0,0],[55,4],[54,2],[54,2],[54,5],[54,2],[54,3],[52,8],[52,1],[55,1],[52,2],[53,8],[54,1],[53,8],[52,1],[54,2],[52,2],[52,3],[55,1],[52,2],[55,2],[52,8],[54,2],[53,4],[55,8],[53,8],[55,1],[55,1],[53,2],[53,5],[53,7],[53,7],[55,4],[0,0],[0,0],[0,0],[52,4],[54,2],[52,1],[54,8],[53,1],[52,6],[55,5],[52,5],[54,1],[52,3],[54,2],[53,2],[54,1],[53,2],[54,3],[52,1],[52,2],[53,2],[54,4],[55,3],[52,1],[53,1],[54,4],[52,4],[52,5],[53,6],[53,3],[52,3],[55,3],[52,5],[53,5],[52,6],[0,0],[0,0],[54,3],[54,8],[54,4],[52,6],[55,1],[54,2],[53,5],[55,1],[55,1],[55,6],[52,1],[54,6],[53,8],[52,5],[55,8],[52,1],[52,6],[0,0],[0,0],[0,0],[0,0],[52,4],[55,5],[53,1],[52,6],[52,2],[54,3],[54,4],[53,3],[55,8],[53,4],[52,4],[55,2],[52,3],[55,6],[55,2],[53,1],[52,7],[55,1],[52,6],[52,2],[55,5],[53,7],[54,7],[54,1],[52,7],[54,7],[53,3],[54,1],[55,4],[53,8],[55,3],[54,5],[52,3],[54,2],[54,4],[54,5],[53,4],[54,3],[53,6],[52,3],[55,7],[53,8],[55,6],[54,2],[54,2],[53,5],[53,1],[55,1],[54,4],[53,7],[55,2],[55,8],[53,1],[53,5],[52,2],[53,2],[54,5],[53,4],[53,5],[52,5],[52,7],[54,3],[55,4],[52,2],[55,6],[53,5],[54,4],[53,4],[52,1],[53,1],[51,9],[53,3],[53,1],[52,3],[53,4],[52,4],[52,2],[54,1],[55,3],[52,3],[52,6],[53,4],[55,8],[53,2],[54,6],[55,1],[53,2],[53,3],[50,5],[54,2],[54,2],[55,6],[54,2],[55,1],[54,2],[52,5],[54,4],[55,1],[52,2],[53,3],[54,2],[54,3],[53,7],[54,7],[54,2],[54,6],[52,3],[0,0],[0,0],[0,0],[52,8],[54,1],[54,2],[54,7],[50,5],[54,1],[55,8],[55,6],[52,2],[55,3],[52,2],[55,6],[53,6],[53,5],[53,3],[55,8],[52,3],[53,2],[53,7],[52,5],[54,4],[54,7],[52,3],[53,6],[55,2],[52,8],[52,4],[54,4],[54,6],[52,3],[52,6],[55,1],[0,0],[0,0],[55,1],[55,3],[55,2],[54,1],[52,4],[53,4],[53,8],[55,5],[53,4],[54,5],[54,4],[54,1],[55,1],[52,2],[53,2],[52,5],[54,4],[54,2],[54,1],[52,2],[52,2],[55,5],[52,3],[55,1],[52,4],[55,3],[52,6],[54,1],[52,3],[54,3],[54,1],[54,6],[0,0],[0,0],[0,0],[53,7],[0,0],[0,0],[53,4],[53,7],[53,6],[52,2],[52,5],[52,3],[55,2],[52,6],[52,3],[54,6],[54,3],[55,5],[53,6],[54,6],[54,4],[54,3],[53,6],[55,2],[55,1],[54,3],[55,5],[54,2],[53,2],[52,2],[52,6],[55,4],[52,2],[52,2],[52,6],[55,7],[55,4],[52,2],[53,6],[54,1],[54,1],[52,2],[53,7],[54,3],[54,7],[54,2],[55,2],[53,1],[54,7],[52,2],[55,4],[52,1],[54,2],[52,6],[53,1],[54,1],[55,3],[53,5],[55,7],[55,4],[53,2],[54,1],[55,3],[54,8],[52,2],[54,2],[52,3],[53,2],[54,3],[55,6],[54,3],[52,8],[53,1],[55,1],[53,2],[55,2],[52,6],[55,3],[53,3],[52,3],[55,6],[52,1],[52,2],[53,1],[52,7],[52,2],[55,4],[55,5],[54,4],[55,1],[54,2],[52,5],[55,1],[53,4],[55,7],[52,7],[52,2],[52,5],[52,4],[55,7],[55,6],[53,5],[52,6],[50,5],[53,1],[53,2],[53,3],[54,1],[53,1],[55,7],[54,1],[55,8],[52,7],[53,1],[54,1],[55,1],[54,7],[55,2],[53,4],[55,3],[53,3],[50,5],[53,3],[54,7],[53,3],[53,8],[54,3],[54,2],[55,6],[53,5],[55,2],[53,3],[52,4],[54,2],[0,0],[0,0],[0,0],[54,1],[54,8],[54,1],[53,5],[55,5],[55,6],[53,2],[55,3],[54,1],[52,6],[54,2],[53,2],[55,7],[54,2],[53,1],[52,2],[53,3],[52,2],[52,2],[54,4],[55,7],[53,4],[55,3],[54,8],[52,3],[55,7],[54,2],[54,7],[53,1],[52,6],[0,0],[0,0],[55,1],[53,1],[53,1],[53,1],[55,6],[54,5],[55,1],[55,1],[53,4],[52,7],[53,1],[55,1],[55,5],[55,6],[53,1],[54,2],[55,1],[52,5],[52,2],[53,5],[53,2],[53,1],[52,2],[55,2],[54,1],[54,3],[54,1],[53,7],[54,1],[54,4],[52,1],[53,2],[53,2],[55,1],[53,2],[0,0],[0,0],[53,2],[52,3],[55,1],[53,7],[52,3],[54,2],[55,2],[55,3],[54,2],[54,2],[54,2],[53,3],[0,0],[0,0],[0,0],[0,0],[53,1],[55,2],[55,1],[54,2],[53,7],[55,1],[54,3],[52,2],[52,2],[53,1],[52,3],[55,1],[50,5],[54,2],[55,1],[52,7],[55,8],[52,6],[52,2],[53,8],[53,3],[54,2],[54,2],[52,4],[54,5],[54,7],[53,1],[53,1],[52,2],[55,6],[55,7],[55,2],[52,1],[53,8],[54,8],[53,2],[55,3],[54,2],[55,1],[54,3],[52,3],[55,3],[55,2],[53,4],[52,4],[52,3],[53,8],[53,4],[52,5],[53,1],[54,6],[53,1],[54,6],[54,8],[52,1],[52,3],[53,7],[53,2],[54,6],[54,1],[53,6],[55,5],[55,3],[52,3],[53,1],[52,3],[52,2],[53,1],[52,2],[54,4],[53,2],[52,1],[52,2],[55,6],[54,4],[55,5],[54,2],[53,5],[52,4],[53,5],[54,1],[53,1],[55,3],[54,3],[55,2],[52,2],[55,6],[55,5],[53,3],[55,8],[55,1],[53,2],[54,7],[52,3],[53,6],[53,2],[52,2],[54,1],[52,4],[53,2],[54,6],[54,4],[53,1],[55,2],[53,1],[54,3],[54,3],[52,1],[54,1],[53,4],[55,2],[54,3],[0,0],[0,0],[0,0],[52,2],[53,3],[55,8],[55,1],[54,2],[52,5],[55,4],[53,5],[52,8],[54,4],[53,2],[52,8],[54,2],[52,2],[54,1],[53,1],[52,1],[55,1],[52,3],[0,0],[0,0],[55,2],[55,8],[55,2],[52,2],[54,5],[55,4],[53,1],[54,4],[54,1],[0,0],[0,0],[52,1],[54,4],[52,1],[53,6],[54,3],[52,8],[53,3],[54,7],[55,2],[52,8],[52,2],[53,6],[55,5],[54,6],[52,2],[53,1],[54,1],[53,1],[55,7],[55,2],[52,2],[53,4],[55,4],[55,1],[54,2],[55,3],[55,8],[53,3],[53,3],[53,3],[52,3],[54,7],[54,3],[53,2],[53,8],[55,5],[52,1],[52,2],[54,4],[55,6],[55,1],[53,1],[52,1],[55,1],[55,3],[54,2],[55,4],[53,2],[53,6],[55,3],[54,4],[52,2],[55,3],[54,1],[54,1],[55,4],[54,6],[52,7],[52,5],[54,2],[53,3],[53,6],[52,6],[53,1],[55,1],[55,8],[52,1],[53,4],[52,2],[55,2],[55,3],[54,2],[52,6],[55,8],[53,2],[55,1],[54,1],[52,5],[53,7],[52,8],[53,3],[53,2],[55,5],[54,2],[53,3],[53,5],[54,1],[54,4],[52,5],[53,2],[55,4],[54,1],[54,3],[53,1],[53,3],[53,5],[55,5],[54,3],[54,7],[50,5],[52,1],[55,4],[53,1],[55,1],[52,4],[52,2],[55,2],[55,2],[52,2],[55,1],[52,5],[54,1],[54,5],[54,3],[54,1],[53,3],[55,7],[53,1],[55,4],[55,3],[55,5],[52,1],[53,2],[54,2],[54,4],[55,8],[52,3],[55,2],[52,3],[54,1],[54,2],[53,3],[55,4],[53,1],[55,5],[55,1],[54,4],[52,2],[52,4],[52,5],[52,1],[52,2],[54,6],[54,2],[54,2],[55,5],[54,1],[53,4],[55,1],[53,6],[53,3],[54,2],[52,2],[54,7],[55,2],[55,4],[53,4],[53,3],[53,4],[53,1],[55,1],[53,4],[52,5],[52,1],[53,7],[0,0],[0,0],[0,0],[55,2],[54,2],[54,2],[52,1],[54,1],[50,5],[53,6],[52,2],[54,5],[52,2],[55,3],[54,1],[53,3],[53,1],[52,6],[52,1],[52,1],[52,7],[54,1],[0,0],[0,0],[53,4],[53,1],[50,5],[55,3],[55,5],[53,6],[53,1],[53,4],[55,7],[0,0],[55,1],[53,2],[53,2],[55,2],[53,2],[52,1],[55,2],[52,2],[54,3],[52,2],[55,6],[54,6],[55,1],[54,1],[54,1],[54,1],[55,4],[54,4],[53,3],[54,3],[53,7],[55,2],[53,3],[55,1],[52,1],[54,6],[53,7],[53,4],[54,2],[55,5],[55,7],[53,7],[55,1],[54,3],[52,7],[55,7],[55,8],[55,2],[55,7],[52,7],[54,7],[55,6],[55,4],[53,2],[53,4],[53,2],[54,5],[55,8],[54,5],[52,6],[55,1],[53,8],[54,2],[55,5],[55,4],[54,5],[53,4],[52,3],[52,1],[52,3],[53,4],[53,1],[53,5],[54,2],[53,7],[52,4],[53,7],[54,1],[52,6],[55,1],[54,4],[54,3],[54,3],[55,2],[53,8],[55,6],[52,1],[52,8],[52,1],[54,4],[55,1],[53,1],[52,1],[55,2],[55,2],[55,3],[55,2],[55,5],[54,7],[53,5],[52,5],[54,7],[54,2],[54,1],[55,1],[52,5],[54,7],[55,6],[52,3],[53,4],[55,6],[52,1],[54,4],[52,6],[53,3],[55,5],[54,2],[54,5],[52,1],[52,5],[55,7],[54,3],[54,5],[55,6],[54,3],[52,7],[55,1],[55,1],[53,5],[53,3],[54,4],[55,2],[52,2],[55,2],[52,1],[53,2],[53,3],[54,8],[52,8],[55,4],[55,3],[55,1],[53,3],[52,3],[54,2],[54,7],[52,2],[54,4],[55,5],[52,1],[54,2],[55,2],[54,4],[52,3],[52,7],[54,5],[55,1],[55,5],[54,8],[54,2],[52,1],[53,3],[52,6],[55,1],[52,4],[55,7],[53,2],[52,5],[54,7],[54,2],[54,1],[54,1],[55,2],[53,2],[54,5],[53,1],[55,1],[53,2],[52,2],[0,0],[0,0],[55,6],[54,1],[54,8],[55,7],[53,1],[55,4],[53,6],[52,6],[52,1],[54,1],[53,1],[52,1],[53,2],[52,4],[52,3],[55,1],[52,1],[0,0],[54,3],[53,1],[52,1],[52,3],[55,4],[53,1],[55,2],[53,2],[55,2],[52,1],[0,0],[52,8],[53,5],[55,3],[52,1],[54,5],[55,8],[53,1],[55,1],[53,7],[54,1],[55,5],[53,3],[54,2],[55,1],[52,2],[53,5],[55,4],[55,2],[54,1],[55,6],[55,2],[55,1],[53,1],[54,4],[52,1],[54,7],[53,4],[52,2],[50,5],[55,3],[55,3],[50,5],[55,1],[53,5],[50,5],[54,1],[55,5],[53,1],[52,1],[53,3],[52,1],[53,6],[52,3],[54,3],[55,6],[53,1],[52,2],[52,3],[53,3],[52,2],[52,1],[54,2],[54,7],[53,6],[55,7],[55,6],[53,6],[54,3],[52,1],[52,5],[52,2],[53,8],[54,6],[52,5],[52,3],[55,4],[53,1],[55,3],[52,1],[54,6],[55,1],[52,5],[55,2],[55,8],[55,5],[52,1],[52,5],[53,6],[52,3],[55,5],[53,3],[54,2],[54,4],[52,3],[53,2],[52,8],[53,8],[55,5],[53,8],[53,2],[55,4],[53,3],[54,7],[55,8],[53,7],[55,6],[52,6],[53,1],[53,2],[54,7],[53,4],[55,3],[54,1],[52,6],[54,4],[53,4],[52,6],[54,7],[52,2],[55,1],[55,8],[53,6],[52,3],[53,2],[53,6],[54,6],[52,1],[54,1],[52,6],[55,8],[53,3],[52,1],[55,7],[54,2],[55,2],[55,1],[53,3],[52,1],[55,1],[55,7],[53,1],[54,1],[52,6],[52,3],[52,6],[53,5],[52,2],[53,1],[54,2],[53,1],[52,4],[55,2],[54,2],[52,3],[54,1],[54,2],[55,3],[52,4],[53,1],[55,5],[53,5],[53,5],[55,5],[54,3],[52,1],[52,7],[52,3],[55,2],[53,6],[54,3],[54,1],[55,1],[52,6],[52,6],[55,1],[55,5],[53,2],[52,7],[55,3],[0,0],[0,0],[0,0],[54,6],[54,1],[53,2],[55,2],[52,3],[54,2],[54,1],[52,6],[54,2],[54,1],[52,2],[55,2],[53,3],[54,1],[53,4],[53,1],[54,3],[55,1],[0,0],[0,0],[53,3],[52,3],[55,1],[52,8],[54,3],[53,3],[0,0],[0,0],[0,0],[54,4],[54,4],[53,2],[55,3],[54,2],[55,3],[53,1],[55,8],[55,7],[52,2],[52,2],[53,2],[52,6],[53,5],[53,7],[53,4],[55,7],[55,6],[55,6],[54,2],[54,7],[53,3],[55,3],[54,4],[52,1],[55,1],[54,1],[54,4],[52,8],[55,7],[52,5],[55,1],[53,1],[55,2],[53,1],[53,2],[54,5],[50,5],[52,5],[52,8],[54,4],[52,1],[53,2],[55,1],[55,7],[54,7],[55,4],[52,1],[52,7],[55,1],[52,4],[53,5],[55,5],[52,5],[55,1],[54,6],[55,2],[55,7],[52,4],[53,1],[54,3],[54,2],[54,4],[52,7],[54,4],[52,1],[53,3],[53,1],[55,3],[55,2],[55,8],[53,2],[54,2],[53,3],[54,2],[52,3],[52,1],[54,5],[52,1],[53,7],[54,1],[52,2],[55,2],[55,8],[54,2],[54,7],[55,3],[54,4],[52,4],[54,3],[54,1],[55,5],[55,1],[54,5],[55,2],[54,3],[53,8],[53,5],[53,4],[54,3],[52,2],[55,6],[53,1],[54,1],[55,2],[53,2],[53,6],[53,1],[53,1],[55,8],[54,5],[53,1],[52,1],[54,2],[52,2],[52,1],[52,3],[52,3],[55,5],[52,3],[52,8],[52,2],[53,5],[53,2],[53,1],[54,1],[53,1],[53,1],[53,6],[54,5],[52,1],[55,1],[54,6],[52,2],[54,3],[52,7],[52,4],[52,1],[55,2],[53,3],[52,7],[55,2],[54,3],[55,1],[53,4],[52,4],[53,1],[53,6],[53,5],[54,2],[52,2],[52,5],[54,8],[54,2],[55,7],[52,1],[53,7],[53,1],[50,5],[54,8],[55,8],[53,6],[52,6],[53,5],[54,5],[52,5],[53,7],[54,7],[54,4],[0,0],[52,5],[55,2],[53,3],[52,3],[55,5],[54,2],[52,3],[54,2],[52,3],[52,6],[54,2],[52,1],[55,1],[54,5],[52,3],[52,1],[52,6],[0,0],[54,1],[0,0],[0,0],[53,8],[52,1],[54,3],[52,7],[54,3],[55,1],[0,0],[0,0],[0,0],[55,1],[53,3],[52,1],[52,1],[53,5],[52,6],[54,3],[54,4],[53,2],[55,3],[54,1],[54,8],[54,2],[54,8],[53,1],[54,4],[54,1],[55,3],[55,5],[53,7],[52,7],[51,5],[55,8],[54,2],[54,4],[55,2],[55,3],[54,5],[53,7],[55,4],[55,4],[53,1],[53,2],[52,8],[53,2],[55,2],[52,5],[55,5],[53,3],[55,2],[53,3],[55,2],[55,2],[54,1],[52,1],[52,6],[55,6],[54,2],[54,3],[54,3],[55,5],[52,3],[54,6],[55,6],[54,5],[54,4],[55,1],[55,1],[53,1],[53,6],[55,6],[54,5],[53,7],[54,6],[53,3],[55,6],[55,1],[53,1],[54,8],[52,6],[55,2],[52,6],[54,2],[54,2],[55,7],[53,6],[52,1],[52,4],[53,1],[52,2],[54,3],[52,2],[55,4],[55,1],[52,2],[55,6],[53,4],[52,7],[53,8],[50,5],[55,1],[53,2],[55,6],[52,1],[55,7],[54,5],[54,7],[54,1],[52,3],[53,1],[52,2],[52,1],[53,1],[53,5],[52,6],[55,8],[54,6],[53,2],[55,4],[55,4],[52,1],[52,3],[53,1],[54,4],[54,2],[54,5],[52,3],[54,3],[53,3],[54,1],[54,7],[54,5],[52,4],[52,2],[53,7],[55,7],[55,1],[55,7],[55,2],[55,7],[54,1],[54,1],[55,2],[55,2],[53,1],[55,6],[55,5],[55,4],[55,5],[55,8],[55,6],[55,6],[55,5],[52,7],[55,3],[55,6],[52,2],[55,7],[53,3],[54,2],[52,1],[52,1],[52,6],[55,6],[54,1],[50,5],[53,6],[52,1],[53,3],[52,6],[55,4],[52,8],[52,4],[53,7],[54,8],[55,5],[53,3],[52,6],[52,5],[55,4],[54,6],[52,2],[55,3],[55,3],[53,8],[52,2],[52,7],[52,4],[0,0],[53,8],[53,6],[53,5],[55,8],[53,7],[54,7],[52,6],[55,3],[52,3],[55,7],[53,6],[54,5],[55,4],[55,7],[52,4],[54,6],[54,1],[52,6],[0,0],[0,0],[0,0],[52,2],[53,5],[55,7],[53,5],[52,6],[53,2],[53,4],[53,1],[55,6],[53,5],[54,3],[53,1],[53,5],[53,6],[53,2],[54,4],[52,1],[52,1],[52,8],[55,1],[52,5],[54,4],[53,6],[54,6],[52,2],[53,8],[53,4],[54,4],[53,1],[54,5],[54,1],[53,1],[53,7],[54,6],[54,1],[53,1],[53,1],[52,5],[54,1],[52,2],[55,4],[53,1],[54,5],[52,3],[53,3],[53,3],[54,7],[54,2],[54,5],[53,3],[54,4],[53,3],[52,3],[55,1],[52,2],[54,2],[53,1],[55,4],[53,8],[52,1],[55,4],[54,1],[52,3],[52,1],[50,5],[52,6],[53,2],[52,1],[54,2],[52,8],[54,8],[55,5],[55,2],[54,7],[55,2],[54,6],[55,7],[55,3],[53,7],[55,4],[54,7],[54,2],[54,5],[52,4],[55,6],[52,3],[53,3],[54,2],[55,6],[55,3],[54,2],[53,4],[55,1],[54,8],[55,3],[53,3],[54,3],[54,1],[54,1],[52,7],[55,3],[53,3],[54,1],[52,2],[52,5],[55,7],[53,5],[53,1],[55,1],[53,7],[54,6],[52,2],[55,8],[52,4],[54,2],[54,2],[52,6],[54,4],[52,7],[55,3],[55,2],[55,2],[52,1],[53,1],[53,7],[55,6],[54,2],[52,6],[52,5],[0,0],[0,0],[54,2],[53,1],[54,1],[55,1],[53,5],[54,2],[52,2],[55,3],[53,5],[54,8],[55,7],[54,1],[53,1],[55,1],[55,2],[53,2],[53,5],[52,6],[54,4],[53,2],[54,4],[53,2],[52,6],[55,6],[54,1],[52,3],[53,7],[54,2],[53,1],[55,2],[54,6],[52,1],[55,4],[52,2],[52,7],[54,1],[52,5],[52,3],[55,1],[54,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,6],[52,2],[55,6],[54,3],[54,4],[55,5],[54,1],[0,0],[0,0],[54,3],[52,6],[55,4],[54,3],[55,1],[53,5],[55,5],[55,3],[52,5],[0,0],[0,0],[52,6],[55,1],[55,2],[52,1],[54,5],[54,2],[55,6],[53,6],[53,2],[54,2],[55,5],[54,2],[52,6],[52,7],[53,5],[54,7],[52,1],[55,1],[55,4],[53,7],[53,4],[54,8],[54,7],[52,8],[54,3],[53,7],[53,6],[53,2],[55,4],[52,1],[54,7],[55,5],[53,7],[55,5],[55,4],[53,6],[54,1],[52,4],[55,1],[52,5],[54,7],[52,2],[55,2],[54,3],[53,5],[55,1],[55,2],[54,1],[55,6],[55,3],[52,5],[53,8],[52,5],[54,6],[55,1],[55,2],[53,3],[52,3],[52,1],[52,6],[55,3],[52,6],[54,4],[55,5],[54,2],[52,8],[54,2],[55,2],[53,7],[53,5],[52,3],[52,5],[52,3],[54,2],[53,5],[55,2],[52,4],[55,1],[53,1],[53,6],[52,2],[53,7],[52,6],[55,7],[55,3],[53,6],[52,2],[55,2],[55,2],[54,3],[52,6],[54,2],[55,7],[52,6],[55,1],[54,1],[55,4],[53,1],[54,2],[55,2],[54,2],[55,3],[54,2],[54,6],[52,2],[54,3],[50,5],[55,8],[52,1],[54,5],[55,3],[54,5],[52,2],[50,5],[55,1],[54,4],[53,2],[54,1],[53,8],[55,3],[53,2],[54,2],[54,5],[54,1],[54,2],[54,4],[55,7],[0,0],[0,0],[55,5],[53,6],[53,2],[53,4],[52,7],[54,3],[53,4],[52,1],[53,5],[54,7],[53,6],[55,3],[52,3],[55,5],[53,1],[55,8],[54,2],[53,4],[55,3],[52,7],[53,4],[53,1],[52,1],[54,2],[53,5],[52,1],[54,8],[55,6],[54,2],[54,5],[55,4],[54,8],[53,3],[55,2],[54,8],[55,2],[55,7],[53,2],[54,1],[52,5],[54,3],[54,2],[55,2],[54,2],[55,1],[54,1],[55,2],[54,1],[0,0],[0,0],[0,0],[55,6],[52,2],[53,1],[55,7],[54,3],[55,1],[53,7],[0,0],[0,0],[55,5],[55,2],[52,2],[54,4],[55,5],[52,5],[54,5],[53,6],[54,4],[0,0],[0,0],[54,6],[54,2],[55,5],[52,1],[54,2],[52,1],[52,2],[53,3],[53,1],[53,4],[52,1],[54,4],[52,2],[52,6],[54,3],[55,2],[54,8],[0,0],[54,1],[55,2],[52,5],[53,6],[54,2],[55,2],[55,2],[54,6],[55,3],[52,3],[54,4],[53,2],[55,3],[54,1],[52,5],[53,5],[52,6],[52,4],[54,2],[54,3],[53,6],[53,1],[55,6],[52,3],[54,1],[52,4],[55,3],[53,1],[53,6],[53,2],[55,8],[53,2],[52,3],[53,2],[54,7],[53,4],[53,1],[55,3],[54,1],[54,2],[53,1],[54,2],[53,2],[53,7],[52,4],[54,4],[55,3],[54,1],[53,5],[53,1],[54,1],[53,1],[52,5],[54,5],[54,2],[55,1],[53,6],[53,5],[53,4],[52,4],[52,5],[54,7],[53,8],[54,2],[52,5],[55,5],[55,2],[54,5],[53,3],[55,2],[54,5],[52,5],[55,3],[54,5],[53,2],[54,7],[54,5],[52,2],[52,6],[54,2],[55,4],[54,1],[52,3],[52,1],[53,3],[54,2],[54,3],[52,1],[53,2],[55,2],[53,1],[53,8],[55,2],[55,2],[53,6],[54,3],[52,1],[52,1],[52,4],[54,5],[55,3],[54,1],[55,7],[55,1],[53,5],[54,3],[55,4],[52,1],[0,0],[0,0],[55,8],[52,6],[0,0],[0,0],[54,2],[55,2],[55,6],[54,7],[54,3],[53,1],[55,1],[55,1],[53,6],[54,6],[52,7],[53,2],[55,4],[54,3],[53,1],[53,1],[53,2],[53,6],[54,8],[54,4],[53,1],[55,1],[54,3],[52,1],[55,3],[52,7],[53,2],[55,1],[54,8],[53,7],[53,1],[53,5],[54,5],[52,6],[52,2],[54,5],[53,4],[52,2],[55,8],[50,5],[53,1],[54,8],[52,1],[54,8],[54,2],[0,0],[0,0],[0,0],[55,1],[52,5],[52,1],[53,1],[54,2],[54,3],[52,3],[53,3],[54,6],[0,0],[0,0],[0,0],[50,5],[55,3],[53,1],[55,6],[53,1],[53,1],[52,3],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,2],[54,1],[55,5],[53,8],[53,2],[55,3],[55,1],[52,3],[54,4],[52,7],[55,1],[52,3],[53,2],[54,4],[54,5],[53,1],[52,6],[54,4],[52,1],[55,2],[54,5],[55,7],[54,2],[52,3],[55,5],[53,2],[54,4],[53,2],[52,3],[54,4],[53,4],[55,3],[53,2],[54,2],[52,2],[55,5],[54,7],[52,7],[55,7],[53,2],[52,6],[55,1],[52,6],[53,2],[52,8],[54,1],[52,5],[53,1],[53,3],[55,2],[54,1],[52,6],[53,3],[53,4],[54,1],[53,5],[52,1],[54,6],[54,1],[54,6],[54,7],[53,6],[53,3],[52,7],[55,2],[53,6],[55,4],[53,4],[55,4],[52,2],[55,4],[52,2],[52,1],[53,4],[52,2],[53,5],[53,1],[52,3],[55,1],[55,2],[53,1],[55,1],[55,3],[54,3],[54,2],[55,6],[52,3],[55,7],[55,3],[54,6],[53,5],[54,2],[54,6],[52,4],[54,1],[53,3],[53,7],[52,1],[53,5],[53,8],[54,6],[53,8],[54,1],[52,1],[53,2],[53,1],[55,2],[54,1],[53,1],[52,3],[55,6],[54,4],[0,0],[0,0],[53,8],[55,2],[55,2],[54,7],[54,4],[54,3],[52,6],[53,3],[55,4],[55,2],[54,3],[52,2],[53,2],[55,1],[53,4],[55,2],[53,6],[53,6],[52,1],[52,2],[55,8],[53,4],[53,3],[54,1],[55,1],[52,5],[53,8],[52,3],[53,3],[54,2],[54,1],[55,8],[54,2],[54,3],[55,1],[54,3],[55,6],[55,2],[55,1],[53,3],[54,1],[55,8],[53,3],[54,1],[55,3],[52,2],[52,3],[54,3],[0,0],[0,0],[54,6],[54,3],[54,2],[52,1],[53,1],[55,2],[52,1],[0,0],[0,0],[0,0],[55,1],[55,5],[53,7],[52,8],[50,5],[53,2],[53,6],[53,6],[53,4],[55,1],[55,7],[54,3],[54,5],[55,1],[52,4],[55,2],[53,6],[55,3],[54,8],[52,1],[53,3],[55,2],[54,4],[55,5],[55,2],[0,0],[55,2],[52,2],[55,2],[52,2],[52,4],[53,6],[54,3],[55,8],[55,1],[55,4],[52,6],[52,4],[52,6],[54,1],[54,7],[54,5],[52,3],[55,2],[55,1],[53,1],[52,4],[52,5],[54,1],[54,8],[52,1],[55,7],[52,3],[52,4],[52,1],[54,2],[55,1],[52,1],[53,1],[54,1],[55,1],[53,3],[53,7],[54,3],[54,5],[55,3],[55,1],[54,4],[52,3],[54,1],[55,2],[55,3],[54,6],[52,6],[55,6],[55,5],[52,4],[54,2],[55,3],[52,2],[54,2],[54,2],[55,5],[54,1],[52,3],[55,3],[54,1],[52,4],[52,4],[53,5],[52,2],[53,1],[54,1],[53,1],[54,7],[54,7],[53,3],[55,1],[52,7],[52,8],[54,1],[52,2],[52,2],[54,1],[53,3],[55,6],[53,1],[55,6],[55,2],[53,1],[53,4],[54,8],[52,2],[54,1],[53,7],[53,3],[52,3],[52,7],[54,1],[53,4],[55,1],[53,1],[52,3],[52,2],[52,7],[52,2],[54,3],[55,1],[52,4],[52,6],[52,1],[53,1],[53,2],[55,3],[53,2],[53,7],[54,8],[53,6],[53,1],[53,8],[52,4],[52,3],[53,2],[54,1],[54,3],[54,8],[53,2],[52,2],[55,1],[52,1],[55,3],[52,8],[53,8],[55,1],[55,1],[54,7],[53,3],[54,3],[53,5],[52,3],[52,6],[55,1],[52,2],[52,1],[54,4],[54,7],[53,2],[54,2],[53,4],[55,2],[54,8],[54,5],[52,1],[54,4],[52,8],[54,4],[52,2],[54,1],[53,1],[52,2],[54,4],[54,2],[53,6],[53,4],[55,2],[52,8],[53,2],[52,4],[0,0],[0,0],[52,7],[55,1],[54,1],[55,1],[52,2],[53,5],[53,6],[0,0],[0,0],[0,0],[55,3],[52,2],[55,1],[53,3],[55,5],[54,7],[55,6],[55,2],[53,2],[53,3],[55,1],[54,5],[53,1],[54,4],[53,5],[54,7],[54,1],[52,1],[52,8],[55,4],[54,4],[53,7],[55,1],[54,3],[54,1],[0,0],[54,7],[52,2],[55,6],[53,5],[54,5],[52,3],[54,1],[53,2],[52,6],[55,4],[55,4],[55,7],[52,2],[53,1],[53,2],[50,5],[55,3],[54,4],[55,3],[53,2],[54,1],[54,6],[54,3],[52,2],[52,3],[55,7],[52,5],[52,3],[55,7],[55,6],[0,0],[0,0],[53,3],[53,2],[55,2],[53,1],[54,8],[52,7],[53,4],[53,7],[53,1],[53,7],[55,2],[53,7],[52,4],[54,4],[55,7],[54,3],[55,7],[53,3],[53,3],[52,8],[52,1],[50,5],[54,6],[53,6],[53,2],[53,5],[52,3],[52,6],[53,4],[53,5],[53,3],[54,5],[54,1],[55,6],[53,2],[53,4],[52,1],[53,2],[55,1],[53,1],[53,1],[55,1],[52,5],[52,1],[53,7],[53,4],[53,6],[55,1],[54,6],[54,1],[55,3],[54,8],[52,4],[54,1],[54,1],[52,2],[53,2],[54,3],[55,2],[54,3],[54,7],[54,1],[54,4],[53,2],[52,3],[53,1],[54,5],[54,6],[52,1],[52,6],[55,6],[55,3],[54,2],[55,3],[55,7],[54,2],[54,4],[55,5],[54,1],[54,3],[53,5],[52,3],[53,1],[52,3],[54,5],[55,4],[54,5],[55,2],[52,1],[53,4],[52,2],[53,4],[54,2],[52,8],[54,1],[53,2],[54,1],[53,1],[52,2],[53,4],[53,3],[52,2],[52,7],[55,3],[54,2],[54,3],[53,7],[53,2],[52,1],[52,2],[53,2],[52,7],[53,3],[55,8],[53,5],[54,4],[54,8],[53,5],[53,5],[54,3],[55,2],[52,3],[52,1],[54,1],[53,6],[55,4],[55,6],[53,7],[55,4],[55,4],[54,6],[52,1],[0,0],[55,5],[53,5],[54,2],[54,3],[55,1],[54,7],[55,2],[54,7],[55,7],[55,5],[52,3],[52,2],[52,1],[52,5],[52,4],[54,6],[52,1],[55,8],[54,6],[54,3],[52,1],[55,2],[52,1],[54,4],[55,1],[53,4],[53,2],[55,4],[54,5],[55,6],[52,6],[52,6],[52,2],[52,2],[0,0],[0,0],[0,0],[55,7],[55,6],[52,2],[53,8],[53,1],[55,3],[53,2],[55,1],[54,1],[54,1],[54,5],[54,7],[53,2],[52,2],[54,6],[55,1],[55,6],[54,2],[53,6],[52,3],[53,2],[53,1],[52,4],[53,4],[55,1],[52,5],[52,1],[55,3],[0,0],[0,0],[53,3],[55,1],[55,2],[52,2],[55,1],[52,5],[54,3],[55,5],[52,2],[52,1],[54,4],[54,7],[54,5],[53,3],[54,4],[53,1],[55,1],[52,7],[53,3],[52,1],[52,3],[53,2],[54,2],[54,2],[0,0],[0,0],[54,6],[52,5],[52,1],[54,7],[53,2],[52,2],[53,1],[54,3],[54,2],[52,7],[55,1],[53,1],[52,2],[55,4],[52,1],[52,1],[55,1],[55,8],[52,4],[54,2],[55,6],[53,1],[52,1],[53,8],[54,6],[55,4],[54,3],[55,3],[52,6],[54,8],[55,5],[52,3],[54,6],[54,2],[52,3],[53,5],[54,5],[52,2],[53,4],[53,7],[55,6],[55,2],[55,3],[54,5],[52,6],[53,1],[54,1],[53,2],[53,2],[53,2],[52,3],[54,2],[53,4],[55,7],[52,8],[52,4],[55,1],[54,7],[50,5],[54,1],[53,5],[53,1],[53,3],[52,4],[53,2],[52,1],[55,1],[54,4],[52,5],[53,1],[54,5],[55,2],[55,6],[52,2],[55,4],[55,6],[53,2],[53,4],[55,1],[53,6],[50,5],[55,1],[52,3],[55,1],[55,3],[52,2],[53,1],[54,6],[53,5],[55,1],[52,6],[54,6],[53,4],[54,1],[52,7],[53,3],[55,1],[54,7],[54,3],[55,3],[54,1],[54,5],[54,6],[52,2],[53,7],[54,3],[53,3],[0,0],[0,0],[52,6],[52,2],[55,4],[53,2],[55,5],[52,6],[54,2],[52,2],[54,2],[54,2],[53,2],[54,4],[55,2],[52,1],[54,6],[52,2],[54,7],[52,2],[52,1],[53,8],[55,7],[54,1],[52,7],[53,3],[54,7],[52,3],[54,1],[55,2],[55,5],[52,3],[53,8],[54,2],[55,1],[0,0],[0,0],[53,1],[52,6],[53,3],[52,4],[55,1],[53,4],[53,1],[53,1],[53,3],[55,4],[52,5],[53,3],[53,2],[55,2],[54,3],[52,1],[54,8],[55,8],[53,2],[52,2],[55,5],[55,5],[52,8],[54,7],[50,5],[53,2],[54,6],[53,1],[0,0],[54,5],[52,4],[52,5],[55,3],[53,2],[54,1],[55,2],[53,7],[55,1],[54,8],[50,5],[54,2],[54,2],[53,2],[55,4],[55,1],[53,8],[52,2],[52,2],[53,5],[0,0],[0,0],[0,0],[0,0],[53,6],[0,0],[0,0],[53,3],[54,4],[55,2],[52,2],[52,2],[53,2],[52,5],[52,1],[54,5],[54,1],[55,8],[53,5],[52,7],[54,7],[52,1],[53,8],[55,5],[55,1],[55,1],[52,3],[52,2],[54,3],[52,3],[55,3],[52,1],[52,7],[54,1],[52,2],[54,3],[53,2],[54,3],[52,7],[53,2],[54,5],[52,2],[55,5],[52,1],[55,2],[54,3],[54,1],[53,5],[55,1],[54,3],[55,2],[55,6],[55,6],[54,1],[53,1],[55,3],[53,2],[55,4],[53,1],[54,8],[54,5],[55,2],[55,3],[53,3],[52,8],[55,8],[52,3],[53,5],[55,4],[52,3],[52,1],[52,2],[54,6],[52,2],[52,1],[55,6],[53,5],[53,3],[55,4],[53,3],[54,1],[52,3],[53,8],[55,2],[0,0],[0,0],[52,8],[53,2],[53,5],[54,1],[55,3],[52,3],[54,3],[54,5],[52,3],[52,7],[54,6],[54,6],[53,6],[54,2],[54,2],[55,2],[53,4],[53,7],[52,7],[53,4],[55,7],[54,1],[52,6],[52,3],[53,1],[54,7],[52,3],[52,1],[0,0],[0,0],[55,5],[55,1],[55,2],[55,4],[52,4],[52,2],[53,2],[55,6],[53,2],[55,1],[53,8],[53,6],[53,1],[54,4],[53,1],[55,6],[54,6],[54,3],[54,4],[53,1],[53,1],[52,7],[52,2],[52,5],[54,1],[53,1],[53,5],[52,5],[55,4],[54,1],[52,3],[53,5],[52,8],[52,3],[0,0],[0,0],[0,0],[53,5],[55,7],[54,7],[54,3],[55,3],[53,7],[53,3],[55,3],[54,3],[55,2],[54,7],[52,5],[55,2],[55,3],[54,6],[53,2],[53,7],[52,4],[52,6],[54,8],[54,4],[53,4],[53,3],[55,3],[52,4],[54,3],[53,2],[52,6],[0,0],[0,0],[54,5],[52,2],[52,3],[54,1],[52,5],[53,2],[53,5],[52,2],[55,8],[52,3],[53,7],[54,5],[53,2],[55,5],[54,8],[52,5],[53,1],[52,7],[53,3],[52,2],[52,6],[0,0],[0,0],[55,4],[54,4],[0,0],[0,0],[55,5],[52,3],[54,1],[52,2],[55,3],[53,5],[55,6],[52,8],[55,1],[55,8],[52,3],[53,1],[53,3],[55,5],[52,3],[55,3],[54,5],[52,3],[52,1],[54,2],[55,8],[53,4],[53,2],[54,1],[53,5],[52,6],[55,1],[53,4],[53,2],[52,7],[55,4],[50,5],[53,8],[54,6],[53,1],[52,2],[52,1],[55,7],[53,8],[53,4],[52,3],[53,1],[53,1],[55,2],[55,7],[53,1],[54,3],[55,7],[53,2],[52,5],[52,1],[55,2],[54,4],[53,7],[54,4],[52,1],[52,3],[54,4],[55,2],[52,5],[53,2],[53,2],[54,6],[55,2],[52,2],[52,7],[55,7],[53,2],[55,3],[54,1],[53,2],[55,5],[52,3],[52,1],[0,0],[0,0],[53,2],[55,3],[52,2],[52,1],[55,2],[53,4],[52,1],[54,3],[53,7],[55,2],[52,8],[54,5],[55,2],[53,1],[53,3],[55,2],[55,4],[55,4],[54,8],[53,1],[55,3],[55,7],[54,2],[54,1],[55,3],[53,1],[55,7],[52,3],[0,0],[0,0],[0,0],[55,1],[53,1],[55,2],[53,1],[52,1],[52,5],[55,1],[53,3],[54,5],[53,8],[53,1],[53,2],[55,1],[52,5],[54,4],[54,3],[54,1],[55,2],[54,2],[52,8],[52,1],[52,1],[54,6],[52,3],[52,1],[54,5],[54,6],[55,3],[54,2],[53,2],[52,6],[52,5],[53,2],[55,3],[0,0],[0,0],[53,1],[52,2],[52,1],[55,3],[55,7],[54,5],[52,2],[52,2],[55,4],[54,2],[55,7],[50,5],[54,5],[54,2],[54,2],[54,1],[54,6],[53,1],[54,1],[55,4],[54,4],[54,7],[54,3],[55,6],[54,7],[55,1],[0,0],[55,4],[0,0],[0,0],[54,8],[52,1],[53,7],[53,4],[52,7],[53,1],[55,2],[55,2],[52,6],[52,8],[52,7],[54,8],[54,2],[53,2],[55,3],[53,1],[54,2],[53,3],[53,2],[53,6],[52,6],[52,6],[55,3],[52,1],[52,7],[0,0],[0,0],[54,6],[53,3],[52,6],[54,6],[53,4],[55,3],[53,1],[53,1],[55,1],[53,3],[52,6],[52,4],[55,4],[52,2],[52,3],[53,6],[52,7],[54,1],[55,7],[54,6],[55,6],[52,7],[55,3],[52,1],[52,1],[52,1],[54,2],[52,3],[54,2],[53,5],[54,1],[55,2],[53,1],[54,4],[53,3],[54,2],[52,3],[55,4],[55,3],[55,2],[54,2],[52,7],[52,6],[53,2],[52,6],[52,2],[54,1],[54,1],[52,6],[55,7],[54,2],[53,3],[54,3],[53,3],[54,1],[54,3],[52,2],[55,6],[54,3],[52,5],[53,2],[55,2],[52,4],[52,2],[52,2],[52,4],[52,4],[52,3],[53,3],[53,3],[52,3],[52,6],[52,4],[0,0],[0,0],[53,7],[54,1],[0,0],[0,0],[53,7],[54,1],[55,2],[55,3],[52,3],[55,4],[55,6],[53,2],[52,1],[52,5],[53,1],[52,4],[54,5],[53,2],[52,3],[55,3],[55,1],[52,4],[54,2],[53,3],[52,4],[53,7],[53,4],[55,6],[52,7],[0,0],[0,0],[0,0],[53,2],[50,5],[55,1],[54,2],[55,4],[53,6],[53,8],[55,6],[55,1],[53,3],[52,7],[54,8],[54,2],[53,1],[55,4],[53,3],[55,8],[53,4],[54,4],[53,6],[53,8],[55,2],[53,5],[55,3],[52,2],[54,2],[55,3],[55,5],[52,2],[53,5],[54,2],[52,1],[54,3],[54,1],[54,5],[0,0],[0,0],[0,0],[0,0],[55,1],[54,4],[52,8],[54,3],[54,7],[52,1],[52,3],[54,5],[53,2],[53,3],[53,4],[54,8],[53,1],[55,4],[53,4],[55,1],[55,6],[55,3],[55,3],[53,2],[53,1],[53,3],[52,1],[53,7],[54,8],[55,3],[53,5],[52,6],[53,7],[53,8],[55,4],[53,1],[55,6],[52,5],[55,5],[55,6],[55,4],[54,8],[53,2],[53,3],[54,2],[55,1],[54,5],[53,3],[52,1],[53,3],[53,2],[52,1],[52,8],[54,5],[53,7],[55,3],[54,3],[52,5],[52,5],[52,2],[55,2],[53,7],[52,1],[54,1],[52,1],[52,1],[53,3],[55,1],[55,3],[55,2],[53,3],[54,3],[55,7],[54,7],[55,8],[52,4],[54,3],[52,3],[53,2],[54,6],[55,3],[54,6],[52,8],[55,4],[52,2],[55,2],[55,1],[50,5],[53,2],[54,4],[52,1],[55,2],[53,4],[52,3],[54,3],[54,1],[54,7],[53,4],[54,1],[53,6],[54,1],[53,3],[52,7],[53,5],[54,7],[52,3],[55,3],[55,5],[52,7],[53,7],[53,1],[55,1],[53,6],[52,1],[55,5],[53,2],[55,2],[55,1],[52,7],[54,3],[55,2],[52,1],[55,5],[54,2],[55,5],[52,1],[52,1],[54,6],[55,2],[53,1],[53,3],[52,4],[52,4],[54,6],[55,5],[0,0],[0,0],[54,6],[52,7],[52,6],[52,7],[55,2],[55,3],[55,5],[53,3],[52,5],[54,4],[55,2],[55,3],[54,4],[54,1],[55,4],[54,6],[52,2],[52,3],[52,7],[53,8],[53,2],[55,2],[53,3],[52,1],[55,4],[0,0],[0,0],[0,0],[53,2],[54,1],[55,4],[54,8],[52,2],[54,8],[54,7],[52,3],[52,7],[52,1],[55,1],[52,2],[53,4],[52,2],[54,2],[53,7],[53,2],[55,4],[53,1],[54,4],[55,6],[52,1],[53,1],[54,3],[55,7],[52,5],[53,1],[54,6],[54,4],[55,3],[52,7],[52,1],[55,2],[52,7],[52,7],[53,3],[0,0],[0,0],[0,0],[52,1],[55,4],[54,5],[54,4],[55,3],[54,3],[53,4],[55,5],[53,3],[53,2],[54,3],[53,3],[52,5],[54,8],[52,6],[55,8],[52,3],[52,5],[55,8],[54,7],[54,2],[53,2],[53,1],[53,5],[54,6],[0,0],[0,0],[54,2],[54,5],[55,4],[54,3],[52,5],[55,2],[55,1],[54,2],[54,2],[54,8],[55,3],[55,5],[54,3],[54,5],[55,3],[53,2],[55,1],[54,8],[54,3],[52,7],[54,5],[55,1],[52,2],[54,1],[53,5],[54,8],[52,2],[53,3],[52,2],[54,7],[54,4],[55,1],[53,3],[50,5],[54,1],[53,1],[55,6],[53,6],[52,3],[53,4],[54,3],[53,6],[52,8],[55,2],[53,5],[55,1],[53,1],[52,1],[55,7],[54,4],[55,1],[52,3],[54,5],[55,5],[54,1],[54,1],[54,1],[53,2],[54,7],[55,3],[52,5],[55,2],[52,2],[55,2],[53,1],[53,5],[53,7],[52,1],[55,6],[55,8],[55,8],[53,4],[52,2],[52,3],[54,2],[54,5],[52,3],[55,1],[55,1],[53,2],[53,7],[52,8],[54,7],[55,2],[52,1],[52,4],[55,5],[52,7],[55,3],[54,7],[55,7],[54,3],[55,3],[52,1],[54,2],[55,7],[52,1],[54,5],[53,4],[53,1],[53,3],[55,2],[52,7],[53,1],[52,5],[55,6],[54,7],[54,3],[55,4],[55,7],[53,8],[55,4],[53,1],[53,2],[53,3],[55,1],[53,1],[52,5],[52,3],[53,4],[55,6],[54,1],[52,2],[53,2],[55,2],[55,2],[54,3],[50,5],[54,1],[52,4],[0,0],[0,0],[53,2],[52,3],[54,7],[54,1],[53,2],[55,6],[53,3],[54,3],[55,3],[52,3],[52,7],[54,6],[53,2],[55,3],[55,1],[55,4],[55,3],[54,3],[53,3],[54,3],[53,3],[55,6],[52,6],[55,1],[55,8],[55,2],[53,3],[53,3],[55,2],[55,8],[52,4],[53,7],[53,1],[55,8],[52,2],[52,2],[55,6],[52,2],[0,0],[0,0],[0,0],[0,0],[52,2],[55,6],[54,1],[55,5],[54,2],[52,1],[54,5],[53,3],[52,5],[52,7],[55,6],[52,5],[55,5],[52,5],[53,5],[55,4],[53,1],[53,6],[52,1],[53,3],[53,5],[50,5],[52,5],[53,7],[0,0],[0,0],[55,5],[55,2],[55,5],[55,5],[54,2],[55,8],[53,2],[52,7],[53,3],[53,5],[52,2],[52,3],[54,3],[53,7],[53,3],[52,1],[55,6],[53,1],[52,2],[53,5],[52,2],[54,5],[55,2],[55,5],[52,3],[55,2],[53,4],[53,3],[52,7],[54,6],[52,5],[54,1],[55,1],[54,6],[55,6],[52,4],[54,4],[55,7],[53,1],[54,5],[52,2],[55,7],[54,3],[54,2],[53,7],[54,8],[52,1],[55,1],[54,3],[53,1],[52,1],[55,1],[52,6],[55,3],[54,3],[53,1],[52,4],[55,3],[53,2],[53,2],[54,1],[53,2],[52,2],[53,1],[53,3],[55,5],[52,4],[52,2],[54,2],[54,3],[55,7],[54,1],[55,3],[55,2],[52,4],[53,3],[52,6],[52,4],[54,6],[52,4],[53,5],[54,3],[52,3],[55,6],[53,7],[50,5],[55,2],[55,7],[53,2],[53,5],[53,2],[53,1],[54,1],[54,7],[53,6],[53,5],[55,7],[55,6],[53,2],[52,5],[53,6],[55,6],[55,1],[54,5],[52,2],[53,6],[54,4],[52,1],[53,3],[52,1],[52,2],[52,2],[53,5],[53,3],[53,4],[52,1],[54,7],[55,7],[53,4],[54,6],[53,1],[55,4],[54,5],[54,2],[52,6],[54,7],[52,5],[54,7],[52,1],[54,2],[0,0],[0,0],[50,5],[54,7],[55,2],[55,7],[53,2],[53,2],[55,1],[53,1],[55,6],[55,2],[54,1],[54,7],[52,6],[54,7],[52,4],[54,4],[52,8],[52,2],[55,3],[54,1],[55,1],[52,2],[53,3],[53,1],[55,1],[52,2],[55,6],[54,1],[52,3],[53,2],[54,4],[55,3],[55,3],[52,6],[53,4],[54,2],[50,5],[53,4],[54,3],[53,8],[54,8],[0,0],[0,0],[52,5],[55,6],[52,5],[53,1],[53,1],[55,3],[55,5],[55,2],[53,4],[55,4],[54,2],[54,1],[55,4],[55,6],[53,2],[53,3],[54,3],[53,1],[52,4],[53,5],[54,4],[55,4],[53,5],[54,3],[55,6],[0,0],[0,0],[0,0],[55,2],[52,3],[54,5],[55,4],[55,6],[53,7],[54,5],[54,2],[52,7],[52,2],[54,6],[54,1],[52,2],[54,1],[54,2],[55,3],[54,3],[54,3],[55,1],[55,5],[55,3],[55,4],[55,6],[54,2],[52,4],[52,3],[54,3],[54,2],[52,5],[55,2],[52,1],[52,1],[52,2],[52,6],[55,2],[54,1],[55,5],[54,7],[55,3],[54,2],[0,0],[0,0],[54,1],[53,3],[52,6],[53,1],[52,3],[52,2],[53,1],[52,2],[53,6],[54,1],[52,3],[52,4],[55,3],[54,2],[52,6],[55,6],[52,7],[54,7],[54,2],[53,3],[52,2],[53,1],[55,1],[54,5],[53,7],[54,2],[55,1],[52,2],[55,5],[52,1],[54,5],[50,5],[55,3],[52,1],[54,2],[55,2],[55,6],[54,8],[54,4],[55,4],[52,5],[55,2],[52,6],[52,4],[54,3],[54,1],[54,3],[53,3],[53,6],[55,1],[53,5],[53,4],[52,1],[53,6],[55,2],[52,2],[53,6],[52,1],[52,6],[53,1],[54,2],[53,2],[54,5],[52,4],[55,2],[53,2],[52,7],[53,4],[55,3],[54,6],[55,2],[54,1],[55,3],[52,8],[52,3],[53,4],[55,2],[53,2],[55,6],[53,1],[54,5],[55,1],[55,2],[55,1],[53,6],[0,0],[52,4],[53,6],[52,2],[53,7],[54,2],[53,7],[55,1],[53,2],[55,3],[54,6],[52,1],[52,1],[54,3],[55,2],[54,3],[55,2],[54,8],[55,4],[54,5],[55,4],[53,2],[53,2],[55,4],[53,1],[55,6],[54,2],[52,3],[55,4],[55,2],[53,1],[52,2],[53,6],[55,1],[55,4],[54,6],[54,6],[55,2],[52,5],[53,5],[52,6],[52,2],[53,6],[0,0],[0,0],[53,5],[54,4],[52,7],[55,5],[54,2],[55,3],[53,2],[52,5],[53,2],[55,2],[53,2],[54,5],[50,5],[55,2],[54,6],[54,4],[55,1],[54,2],[52,5],[54,6],[53,6],[55,2],[52,1],[52,5],[52,5],[0,0],[0,0],[0,0],[53,6],[55,7],[55,1],[52,6],[53,5],[52,6],[55,5],[53,7],[52,1],[55,2],[53,6],[54,1],[50,5],[52,5],[52,5],[52,2],[53,1],[55,2],[52,6],[55,8],[53,1],[52,2],[54,3],[55,2],[54,6],[55,1],[55,3],[52,3],[55,1],[54,7],[52,6],[50,5],[54,1],[53,1],[53,1],[55,5],[52,5],[53,7],[52,6],[55,5],[0,0],[0,0],[53,3],[52,2],[52,4],[55,1],[53,7],[55,7],[55,4],[52,7],[53,5],[54,2],[53,3],[53,4],[53,4],[55,2],[55,2],[52,2],[52,5],[54,6],[54,5],[52,3],[52,3],[53,2],[50,5],[52,1],[53,1],[54,1],[52,5],[55,7],[54,3],[55,3],[55,2],[53,8],[52,1],[52,7],[52,3],[53,5],[52,8],[54,3],[53,7],[54,2],[54,6],[54,1],[52,5],[52,3],[53,3],[52,1],[52,1],[54,3],[55,2],[54,4],[54,2],[55,2],[54,2],[53,4],[53,2],[52,6],[54,4],[54,3],[52,6],[53,3],[54,3],[54,5],[52,5],[54,3],[54,6],[52,5],[54,8],[55,5],[53,8],[54,5],[54,5],[54,2],[54,2],[53,6],[55,1],[54,1],[52,3],[55,1],[52,2],[55,3],[52,2],[52,1],[0,0],[55,1],[0,0],[53,2],[54,1],[55,3],[53,3],[54,3],[55,2],[54,3],[55,2],[54,3],[52,1],[54,7],[54,2],[54,1],[55,6],[54,5],[52,2],[52,1],[55,7],[55,2],[52,4],[52,3],[54,7],[55,3],[55,3],[52,5],[52,8],[55,1],[53,6],[54,1],[55,1],[54,7],[52,6],[55,1],[54,1],[53,5],[55,8],[55,3],[53,4],[52,3],[53,1],[55,2],[53,1],[53,6],[55,3],[0,0],[0,0],[0,0],[0,0],[0,0],[53,1],[54,1],[54,6],[52,1],[55,3],[54,1],[55,2],[53,2],[55,6],[54,5],[54,5],[54,6],[54,2],[55,7],[53,6],[54,3],[53,6],[55,4],[54,3],[53,3],[52,4],[0,0],[0,0],[0,0],[53,1],[55,6],[54,2],[55,2],[55,6],[52,3],[55,3],[54,2],[53,7],[52,4],[53,3],[55,5],[53,7],[52,7],[55,4],[55,2],[52,3],[54,4],[55,3],[54,1],[55,6],[55,8],[54,6],[54,5],[54,1],[52,7],[52,3],[54,2],[53,1],[54,2],[53,2],[52,1],[53,3],[54,1],[53,2],[55,8],[54,2],[53,3],[53,3],[55,4],[0,0],[54,1],[52,4],[54,1],[54,4],[53,3],[55,6],[53,4],[54,3],[55,4],[52,5],[52,7],[52,7],[54,1],[52,4],[55,7],[54,6],[54,3],[52,1],[55,7],[52,2],[55,1],[55,1],[52,6],[55,5],[54,6],[54,2],[53,4],[55,7],[55,4],[55,5],[54,3],[54,7],[53,3],[54,7],[52,4],[54,4],[52,1],[53,3],[54,2],[52,3],[52,2],[54,1],[52,2],[55,3],[54,4],[53,2],[52,1],[55,3],[55,2],[54,2],[55,4],[52,4],[55,1],[55,6],[55,8],[53,2],[54,3],[55,3],[55,4],[54,6],[54,8],[54,3],[52,2],[54,4],[55,1],[52,1],[53,8],[54,2],[52,3],[54,2],[54,4],[52,1],[52,1],[54,2],[54,7],[53,1],[55,3],[54,4],[52,4],[54,1],[52,4],[54,7],[55,2],[55,1],[54,1],[0,0],[0,0],[0,0],[52,1],[55,1],[55,7],[53,1],[52,4],[53,2],[53,1],[54,2],[53,1],[52,8],[54,6],[53,6],[54,3],[52,2],[54,8],[52,2],[52,2],[52,3],[55,7],[53,3],[55,2],[53,8],[53,2],[53,3],[55,1],[53,2],[55,5],[55,2],[54,3],[53,4],[54,2],[54,3],[54,2],[55,1],[53,3],[55,1],[55,1],[53,2],[52,1],[55,6],[53,3],[53,4],[55,6],[53,2],[55,3],[52,3],[0,0],[0,0],[53,2],[55,5],[54,6],[52,6],[54,3],[53,1],[55,4],[54,2],[52,4],[53,2],[54,1],[52,6],[52,1],[52,2],[52,3],[53,3],[55,8],[55,1],[55,1],[52,2],[53,1],[52,3],[53,2],[53,2],[55,4],[54,6],[54,3],[53,1],[54,3],[53,2],[52,4],[52,6],[55,3],[55,8],[55,7],[53,5],[53,7],[55,2],[54,5],[55,3],[52,2],[54,3],[53,3],[55,3],[55,4],[53,6],[52,1],[55,2],[55,7],[55,2],[55,4],[52,3],[53,7],[52,1],[54,7],[55,2],[52,3],[55,7],[55,4],[54,1],[55,3],[52,6],[52,2],[52,3],[54,4],[0,0],[0,0],[53,5],[53,2],[54,2],[55,1],[53,4],[52,3],[52,4],[54,2],[53,2],[55,2],[53,4],[53,1],[55,3],[54,5],[55,3],[53,7],[55,1],[55,7],[52,5],[52,5],[52,5],[52,1],[54,2],[53,6],[52,5],[55,5],[53,8],[54,1],[54,6],[0,0],[0,0],[52,8],[52,8],[53,3],[55,4],[53,5],[52,7],[53,2],[54,2],[52,6],[52,1],[52,2],[52,5],[52,2],[53,3],[52,6],[53,6],[55,8],[54,6],[53,2],[55,2],[55,6],[53,2],[52,6],[54,3],[53,4],[53,2],[54,1],[54,1],[52,3],[53,4],[55,3],[55,6],[52,2],[55,1],[52,6],[52,1],[54,1],[50,5],[53,2],[52,5],[55,5],[55,1],[54,1],[52,3],[54,5],[52,1],[54,5],[52,5],[53,3],[0,0],[53,1],[0,0],[0,0],[0,0],[53,2],[52,7],[54,2],[53,4],[54,2],[54,1],[54,1],[54,8],[55,6],[54,1],[54,3],[54,5],[54,4],[52,2],[55,6],[53,6],[55,7],[52,2],[53,5],[53,8],[53,1],[54,1],[53,5],[53,3],[53,6],[53,4],[54,5],[54,7],[53,7],[55,3],[54,5],[54,3],[52,8],[52,8],[54,3],[53,8],[54,1],[52,7],[50,5],[53,7],[53,1],[54,3],[53,5],[53,2],[52,3],[53,2],[0,0],[0,0],[0,0],[53,7],[53,6],[52,1],[55,2],[54,2],[53,5],[52,2],[53,7],[53,2],[54,3],[54,7],[52,8],[52,1],[55,2],[54,3],[53,5],[54,2],[52,5],[52,2],[53,3],[50,5],[52,2],[52,2],[54,2],[52,3],[55,6],[53,6],[55,7],[54,2],[52,5],[55,4],[52,7],[55,2],[53,1],[54,4],[52,2],[53,4],[54,4],[53,3],[52,2],[55,6],[55,1],[54,1],[55,2],[54,8],[55,2],[52,4],[55,1],[54,7],[53,1],[54,4],[55,3],[50,5],[55,1],[53,1],[55,4],[52,2],[53,2],[55,1],[54,1],[55,1],[53,8],[0,0],[52,2],[0,0],[0,0],[55,4],[53,4],[53,4],[52,4],[54,3],[54,8],[52,2],[54,1],[52,7],[53,2],[55,4],[52,5],[55,1],[53,6],[54,8],[53,2],[54,2],[52,6],[54,6],[54,6],[55,1],[52,1],[55,7],[54,6],[55,6],[52,5],[53,3],[53,3],[53,3],[0,0],[0,0],[52,3],[54,3],[52,4],[54,4],[55,3],[55,6],[52,2],[52,1],[52,2],[53,1],[53,5],[55,8],[55,2],[52,2],[55,5],[55,4],[54,4],[54,5],[54,4],[54,8],[55,3],[55,6],[53,5],[54,1],[53,6],[54,2],[53,2],[54,1],[53,1],[54,4],[52,1],[55,4],[53,7],[53,6],[52,6],[55,2],[54,2],[54,3],[55,5],[54,6],[54,3],[53,4],[52,1],[52,3],[54,1],[53,1],[54,6],[52,4],[52,4],[0,0],[53,2],[0,0],[0,0],[0,0],[55,5],[54,4],[53,1],[52,1],[54,2],[53,6],[53,1],[54,4],[52,8],[54,6],[54,4],[55,6],[52,1],[55,2],[52,1],[53,1],[52,2],[52,2],[52,6],[52,7],[52,1],[53,4],[54,4],[54,6],[50,5],[54,7],[52,4],[53,2],[52,6],[53,4],[53,5],[53,4],[54,7],[55,5],[53,1],[52,6],[52,1],[52,6],[55,2],[52,1],[52,8],[55,5],[53,1],[54,6],[52,2],[53,2],[0,0],[54,6],[54,2],[54,2],[53,7],[53,1],[53,1],[55,6],[54,7],[54,7],[53,3],[55,2],[55,5],[53,1],[53,4],[55,3],[52,8],[55,1],[55,6],[55,2],[54,2],[54,4],[55,3],[53,2],[52,7],[52,2],[52,1],[54,3],[54,6],[55,2],[53,6],[52,3],[54,7],[53,3],[52,2],[53,3],[54,5],[53,2],[55,2],[55,3],[53,3],[53,3],[52,2],[54,7],[53,4],[54,5],[55,2],[52,8],[52,5],[54,2],[52,3],[52,4],[53,1],[52,1],[54,8],[54,5],[55,2],[55,3],[53,3],[54,3],[55,1],[54,1],[52,4],[53,4],[53,2],[52,3],[53,2],[55,5],[53,2],[54,6],[54,1],[52,2],[50,5],[52,1],[53,1],[53,2],[55,1],[54,8],[54,7],[54,2],[54,1],[54,3],[52,4],[55,3],[54,3],[52,2],[55,3],[54,4],[55,2],[54,8],[54,3],[53,2],[55,1],[55,1],[52,1],[53,6],[53,4],[55,1],[0,0],[54,4],[54,6],[54,3],[53,1],[55,5],[55,5],[52,3],[55,4],[55,3],[55,7],[52,2],[52,6],[54,2],[53,5],[53,1],[55,3],[52,7],[52,2],[54,2],[54,1],[54,1],[53,1],[55,4],[52,5],[52,3],[54,6],[52,1],[52,3],[54,3],[54,1],[53,3],[53,8],[53,2],[53,1],[52,1],[53,7],[54,2],[55,2],[55,2],[52,5],[53,3],[54,2],[53,2],[52,3],[53,2],[53,6],[53,4],[52,6],[55,6],[54,4],[0,0],[0,0],[0,0],[52,2],[52,3],[54,3],[52,1],[53,4],[52,5],[54,3],[53,3],[54,3],[52,8],[54,4],[52,1],[52,2],[51,10],[53,2],[53,5],[54,1],[53,3],[52,3],[53,8],[52,5],[55,1],[55,3],[0,0],[0,0],[52,4],[52,7],[52,1],[52,6],[54,3],[55,4],[52,2],[55,1],[53,1],[55,3],[50,5],[55,2],[54,3],[53,6],[52,2],[55,4],[54,5],[52,2],[54,6],[54,2],[52,5],[52,2],[53,2],[53,4],[0,0],[0,0],[0,0],[54,3],[52,5],[55,1],[55,4],[52,1],[53,6],[52,1],[53,2],[54,1],[54,1],[54,5],[52,5],[55,2],[52,6],[54,6],[55,7],[52,3],[55,2],[54,4],[53,2],[53,3],[53,3],[55,3],[52,1],[55,2],[50,5],[53,5],[52,1],[53,3],[55,1],[53,1],[53,3],[54,1],[54,7],[55,5],[53,1],[53,3],[55,4],[54,1],[52,3],[52,2],[54,6],[52,1],[55,4],[54,4],[54,2],[55,1],[55,1],[53,2],[52,8],[52,8],[52,4],[55,2],[52,2],[55,6],[54,3],[54,7],[55,1],[53,6],[53,1],[54,1],[55,3],[53,3],[0,0],[0,0],[54,2],[52,5],[53,1],[52,6],[54,1],[52,4],[53,5],[55,2],[52,7],[53,7],[55,7],[54,2],[54,5],[52,2],[53,7],[55,2],[52,8],[53,2],[52,5],[54,3],[52,3],[53,1],[55,3],[53,6],[52,1],[52,4],[52,8],[52,2],[52,3],[54,8],[54,2],[0,0],[0,0],[53,3],[53,3],[55,6],[52,3],[53,1],[53,5],[54,3],[53,6],[54,4],[54,2],[53,3],[55,7],[53,2],[53,4],[52,7],[54,1],[50,5],[54,6],[53,3],[54,1],[54,2],[54,5],[54,3],[55,2],[53,7],[53,7],[55,7],[52,2],[52,2],[55,4],[55,7],[53,7],[53,2],[55,2],[54,2],[54,4],[54,4],[53,1],[54,3],[54,2],[52,6],[55,5],[54,2],[55,2],[52,2],[54,3],[55,2],[0,0],[0,0],[0,0],[53,5],[53,2],[54,7],[52,7],[52,6],[52,1],[55,5],[54,2],[54,2],[55,3],[54,2],[53,8],[55,3],[55,1],[52,5],[54,4],[53,2],[52,2],[55,5],[53,4],[52,5],[55,2],[53,7],[0,0],[0,0],[55,2],[53,2],[53,7],[50,5],[55,2],[53,8],[52,3],[52,6],[54,2],[55,2],[52,8],[53,3],[53,8],[54,7],[54,3],[54,2],[54,2],[52,4],[53,3],[52,3],[53,1],[54,4],[53,1],[50,5],[0,0],[0,0],[0,0],[52,8],[54,7],[52,3],[53,8],[53,5],[53,2],[52,5],[55,8],[53,7],[55,3],[54,7],[54,1],[52,4],[52,2],[52,7],[54,1],[55,6],[52,3],[55,1],[53,5],[52,7],[54,6],[53,1],[52,6],[55,3],[53,8],[54,4],[53,3],[52,2],[55,2],[55,3],[54,4],[53,8],[53,5],[54,5],[53,2],[54,6],[52,5],[52,6],[53,6],[53,8],[55,1],[54,8],[52,5],[52,1],[52,5],[52,4],[53,1],[54,1],[55,3],[52,3],[52,5],[54,4],[54,7],[52,3],[53,2],[52,2],[52,1],[52,2],[52,3],[54,6],[55,7],[55,4],[0,0],[0,0],[52,5],[53,7],[54,2],[53,1],[53,4],[54,3],[54,6],[55,2],[52,8],[54,6],[55,5],[55,7],[53,3],[52,6],[53,5],[55,1],[53,6],[53,3],[54,5],[54,5],[53,1],[53,4],[55,1],[52,6],[55,2],[52,4],[54,6],[52,8],[53,1],[0,0],[53,3],[0,0],[0,0],[54,3],[52,2],[52,1],[55,2],[54,8],[55,7],[54,7],[52,7],[55,5],[52,2],[54,7],[52,2],[54,6],[55,1],[53,5],[55,2],[53,6],[55,8],[55,2],[52,8],[55,3],[52,2],[54,5],[55,6],[53,2],[55,6],[53,7],[54,7],[52,5],[53,4],[55,5],[52,7],[52,2],[50,5],[54,1],[55,5],[52,2],[55,1],[54,1],[55,1],[54,7],[54,2],[52,2],[53,3],[52,7],[52,8],[55,2],[0,0],[0,0],[0,0],[53,2],[55,8],[52,1],[52,6],[52,1],[52,3],[52,5],[54,4],[55,2],[54,1],[55,1],[53,2],[52,2],[54,1],[54,6],[52,8],[52,6],[52,4],[52,5],[53,1],[53,2],[53,1],[54,4],[0,0],[53,3],[53,3],[54,7],[54,6],[55,1],[53,2],[53,1],[54,4],[54,1],[53,1],[54,2],[52,7],[53,1],[52,7],[55,1],[52,6],[55,2],[52,1],[55,3],[52,4],[53,6],[52,1],[54,1],[55,2],[54,3],[0,0],[0,0],[0,0],[52,5],[52,3],[54,1],[54,1],[55,7],[54,5],[53,6],[55,2],[53,1],[55,1],[53,4],[52,6],[53,2],[55,1],[55,2],[54,5],[52,2],[55,4],[53,6],[55,4],[53,3],[53,1],[52,3],[53,5],[55,6],[54,7],[53,3],[52,2],[53,3],[53,1],[55,2],[54,3],[53,1],[53,3],[53,1],[55,8],[53,2],[55,1],[53,3],[52,1],[52,2],[53,6],[55,6],[55,3],[53,5],[52,7],[55,4],[55,2],[55,3],[54,7],[53,7],[55,2],[55,1],[53,3],[54,4],[54,1],[52,3],[55,2],[52,1],[55,2],[55,6],[55,1],[55,3],[53,7],[54,3],[0,0],[0,0],[0,0],[54,3],[55,6],[53,5],[55,3],[53,2],[54,3],[54,3],[55,2],[52,2],[54,1],[53,1],[54,3],[53,4],[52,2],[53,1],[54,3],[54,1],[52,2],[54,7],[55,1],[52,4],[55,7],[55,6],[55,1],[53,2],[55,5],[54,1],[53,8],[55,2],[55,4],[52,2],[52,7],[52,1],[52,1],[54,1],[53,3],[55,2],[55,7],[55,3],[52,7],[55,3],[53,2],[52,2],[52,1],[52,1],[53,1],[53,2],[52,1],[52,2],[53,4],[52,1],[54,6],[55,8],[54,2],[53,1],[54,2],[54,7],[52,1],[54,3],[54,1],[55,5],[54,6],[52,4],[52,8],[54,7],[54,7],[54,1],[55,1],[53,2],[54,2],[53,1],[54,1],[55,7],[52,1],[55,6],[54,4],[53,4],[0,0],[0,0],[55,5],[54,8],[55,2],[54,4],[52,3],[53,1],[54,4],[55,3],[52,2],[52,7],[53,1],[52,5],[52,3],[55,2],[55,4],[53,5],[52,6],[55,2],[52,6],[52,2],[55,3],[55,1],[52,2],[52,1],[53,3],[52,5],[0,0],[0,0],[53,5],[52,1],[54,2],[53,1],[54,2],[55,2],[52,2],[52,5],[55,2],[54,1],[54,1],[55,2],[54,2],[55,2],[53,1],[55,6],[53,2],[54,6],[54,2],[55,2],[55,1],[53,5],[53,5],[0,0],[0,0],[55,7],[53,5],[54,8],[54,6],[54,8],[55,3],[53,2],[54,4],[52,1],[54,1],[52,3],[55,3],[53,5],[54,2],[52,2],[52,7],[54,2],[55,7],[53,6],[53,5],[53,2],[54,5],[55,3],[52,4],[55,4],[54,3],[54,2],[54,3],[55,2],[54,7],[53,1],[54,1],[55,2],[53,1],[54,2],[54,2],[55,6],[53,4],[53,3],[52,2],[55,3],[52,3],[52,3],[54,6],[54,8],[52,1],[52,6],[53,4],[53,1],[52,1],[55,6],[52,8],[54,6],[54,3],[54,8],[55,1],[55,2],[54,1],[54,6],[52,3],[55,6],[54,2],[54,1],[53,6],[53,2],[0,0],[0,0],[0,0],[55,4],[53,3],[53,6],[55,1],[55,3],[54,5],[53,5],[54,3],[55,6],[52,1],[55,5],[52,1],[54,1],[53,5],[54,2],[55,7],[54,4],[55,1],[53,3],[52,7],[55,1],[52,2],[55,1],[55,3],[54,5],[52,2],[53,2],[55,1],[0,0],[0,0],[55,1],[52,4],[52,7],[53,8],[55,6],[53,2],[54,6],[52,6],[50,5],[54,1],[55,2],[53,1],[53,5],[55,1],[52,1],[52,5],[55,1],[55,3],[55,4],[53,1],[53,1],[52,3],[54,6],[55,2],[53,1],[54,6],[53,7],[53,3],[54,1],[52,2],[54,7],[53,2],[52,2],[53,2],[54,3],[55,7],[53,2],[54,1],[53,2],[53,1],[53,4],[55,7],[53,4],[53,2],[52,4],[53,4],[53,8],[0,0],[0,0],[53,6],[54,3],[55,1],[54,5],[54,3],[53,2],[54,3],[53,3],[54,2],[55,2],[54,3],[55,5],[55,2],[53,2],[54,4],[52,2],[55,5],[53,8],[52,6],[55,1],[55,1],[54,1],[54,1],[55,6],[0,0],[55,3],[0,0],[0,0],[52,7],[53,2],[54,5],[52,3],[53,8],[52,2],[52,1],[52,7],[54,6],[52,3],[52,5],[53,2],[53,2],[53,3],[54,4],[54,4],[52,7],[55,6],[55,2],[55,8],[54,2],[50,5],[53,3],[0,0],[0,0],[52,1],[53,1],[53,8],[53,3],[53,7],[55,7],[53,8],[55,2],[53,2],[52,7],[53,2],[52,2],[52,5],[54,8],[55,2],[52,3],[53,6],[53,4],[52,4],[54,2],[55,4],[53,1],[53,2],[52,4],[53,1],[55,1],[55,4],[55,7],[54,1],[54,1],[53,3],[55,3],[53,6],[52,1],[52,6],[52,2],[52,1],[0,0],[0,0],[52,1],[53,8],[53,5],[54,1],[52,7],[53,3],[52,7],[53,6],[53,1],[53,3],[52,3],[52,1],[55,1],[55,8],[52,1],[54,1],[55,1],[55,3],[54,6],[54,2],[53,2],[52,6],[53,8],[54,3],[55,3],[55,7],[0,0],[0,0],[0,0],[55,6],[53,7],[52,2],[52,6],[53,5],[55,2],[54,1],[52,1],[54,4],[55,2],[53,3],[52,4],[52,7],[54,4],[54,6],[53,5],[54,2],[52,2],[52,3],[55,5],[52,1],[55,1],[53,3],[53,2],[54,8],[55,5],[53,6],[53,2],[0,0],[0,0],[53,1],[53,7],[53,2],[52,2],[55,5],[52,1],[52,5],[53,2],[52,3],[55,2],[55,8],[53,3],[53,2],[55,1],[53,6],[52,3],[54,2],[55,5],[54,7],[53,5],[53,3],[53,8],[55,1],[53,6],[55,3],[52,8],[54,2],[52,1],[53,5],[54,2],[55,5],[53,3],[54,7],[55,5],[52,4],[55,5],[52,5],[55,2],[55,2],[0,0],[0,0],[54,6],[52,3],[55,1],[53,1],[53,1],[54,2],[54,3],[0,0],[54,4],[52,4],[54,1],[53,2],[50,5],[52,2],[52,1],[55,8],[53,2],[52,3],[55,1],[53,6],[53,1],[52,7],[53,8],[53,3],[53,1],[54,3],[54,1],[55,1],[52,6],[55,5],[54,3],[54,1],[52,2],[53,8],[52,2],[54,4],[54,1],[53,2],[54,8],[55,8],[54,2],[53,2],[53,1],[55,2],[53,7],[53,4],[52,3],[53,7],[54,3],[53,7],[52,1],[52,3],[54,8],[54,2],[50,5],[54,3],[54,6],[55,5],[55,7],[0,0],[53,4],[55,4],[55,2],[53,3],[52,1],[52,7],[52,5],[52,7],[54,3],[52,5],[53,1],[52,7],[54,2],[52,6],[53,5],[53,2],[52,2],[53,2],[54,1],[52,1],[53,2],[52,7],[53,4],[53,3],[54,8],[55,2],[53,4],[55,4],[52,4],[52,2],[55,6],[52,1],[55,8],[52,3],[55,3],[52,1],[52,2],[52,2],[0,0],[0,0],[52,7],[55,1],[55,2],[52,3],[54,2],[54,1],[55,3],[54,6],[54,5],[54,2],[53,4],[55,6],[55,1],[52,1],[52,2],[55,4],[52,2],[52,5],[52,1],[54,3],[53,2],[55,7],[52,3],[52,1],[54,7],[54,5],[54,5],[55,3],[52,2],[53,2],[52,1],[53,1],[52,4],[52,3],[53,5],[52,6],[55,2],[55,1],[52,8],[54,7],[55,7],[55,8],[53,2],[55,2],[52,1],[54,1],[53,2],[53,3],[54,2],[54,6],[50,5],[52,8],[54,1],[55,1],[52,1],[52,1],[54,3],[52,8],[0,0],[0,0],[0,0],[0,0],[53,3],[55,3],[52,2],[52,2],[53,3],[52,3],[52,5],[52,3],[55,2],[53,2],[54,6],[55,2],[52,3],[52,1],[53,3],[51,1],[52,1],[53,5],[55,7],[55,1],[53,1],[54,6],[55,1],[55,2],[54,1],[55,7],[54,4],[54,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,3],[54,5],[0,0],[0,0],[53,7],[52,3],[54,2],[52,1],[52,1],[0,0],[0,0],[0,0],[55,2],[55,7],[52,1],[52,4],[53,2],[52,2],[53,8],[53,7],[53,1],[53,5],[53,3],[55,3],[55,2],[54,1],[53,4],[53,3],[53,2],[54,6],[54,8],[53,2],[52,6],[54,5],[50,5],[52,2],[53,8],[53,1],[0,0],[0,0],[55,8],[53,3],[55,4],[54,8],[52,2],[52,5],[54,6],[55,1],[53,1],[52,2],[52,4],[54,3],[55,1],[52,1],[55,2],[54,5],[53,1],[52,2],[54,5],[53,2],[54,4],[52,6],[53,2],[0,0],[0,0],[0,0],[54,2],[52,1],[52,1],[55,2],[52,2],[52,2],[53,5],[54,5],[54,5],[53,1],[54,6],[55,4],[52,6],[55,2],[54,4],[55,3],[53,2],[55,4],[54,1],[54,2],[55,7],[55,1],[52,1],[54,3],[52,5],[54,4],[53,2],[54,4],[55,8],[52,1],[55,3],[55,1],[55,3],[54,1],[52,8],[55,3],[0,0],[53,2],[55,2],[54,6],[54,3],[55,5],[53,1],[55,6],[52,1],[52,2],[55,1],[54,2],[54,1],[51,5],[55,1],[54,2],[55,2],[55,5],[52,7],[55,4],[54,3],[55,1],[53,1],[54,3],[52,7],[52,1],[54,3],[55,7],[54,1],[52,1],[54,1],[54,1],[55,4],[53,1],[53,3],[54,4],[52,4],[50,5],[52,1],[55,7],[54,8],[55,1],[55,3],[55,1],[52,1],[55,1],[52,5],[55,4],[54,8],[53,8],[53,2],[52,6],[55,2],[53,5],[54,5],[53,4],[54,2],[55,4],[53,1],[55,1],[54,1],[0,0],[0,0],[0,0],[53,3],[52,1],[53,3],[52,2],[52,3],[52,1],[54,2],[52,5],[54,3],[54,2],[53,2],[53,1],[53,1],[55,3],[53,7],[53,5],[55,7],[55,1],[55,2],[55,1],[55,2],[54,1],[52,8],[54,7],[54,7],[55,1],[55,1],[52,3],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[55,1],[53,1],[54,1],[52,8],[53,6],[52,4],[54,2],[55,3],[53,6],[54,8],[55,8],[53,3],[53,7],[52,6],[54,3],[55,8],[53,3],[52,1],[52,8],[55,4],[53,7],[53,1],[54,3],[53,6],[55,6],[52,1],[53,1],[53,1],[0,0],[0,0],[54,4],[54,1],[52,5],[52,3],[55,3],[52,2],[54,1],[52,8],[54,1],[52,5],[55,3],[53,2],[53,1],[55,1],[55,6],[52,5],[53,1],[54,4],[55,4],[52,8],[55,7],[55,2],[53,1],[53,2],[0,0],[0,0],[54,3],[52,2],[55,3],[53,5],[53,7],[52,2],[55,2],[53,4],[55,2],[50,5],[55,3],[54,3],[54,1],[54,1],[52,5],[54,5],[52,1],[54,7],[53,5],[52,2],[53,7],[53,1],[52,2],[55,5],[54,7],[55,2],[52,2],[52,7],[54,3],[52,3],[53,2],[52,8],[55,2],[53,8],[53,3],[55,3],[53,1],[54,2],[0,0],[0,0],[55,6],[53,2],[52,7],[55,1],[54,6],[52,5],[55,3],[52,5],[52,3],[52,1],[52,7],[52,4],[53,8],[53,7],[55,6],[54,2],[52,2],[55,6],[52,3],[53,7],[55,5],[55,1],[53,4],[53,5],[53,8],[54,3],[54,8],[50,5],[55,1],[55,3],[54,2],[53,1],[55,3],[54,3],[52,7],[52,2],[55,7],[55,5],[52,2],[52,5],[52,2],[54,3],[53,2],[55,3],[54,5],[54,7],[52,2],[53,1],[54,3],[55,7],[52,7],[55,8],[52,7],[53,6],[54,2],[52,4],[55,3],[0,0],[0,0],[0,0],[52,3],[52,1],[52,4],[55,2],[54,7],[52,6],[53,7],[53,3],[55,4],[52,3],[54,6],[55,5],[54,2],[54,7],[52,1],[52,1],[52,8],[54,6],[52,7],[54,2],[55,2],[55,4],[55,8],[50,5],[53,3],[54,6],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[55,1],[54,1],[52,2],[55,5],[53,2],[52,5],[55,7],[52,6],[55,2],[54,3],[50,5],[53,2],[53,2],[55,1],[53,3],[53,7],[54,6],[53,3],[52,5],[55,1],[54,3],[53,8],[55,1],[54,8],[53,1],[53,5],[53,1],[53,3],[53,7],[52,3],[55,1],[54,3],[53,1],[0,0],[0,0],[0,0],[53,1],[52,6],[55,2],[52,8],[52,6],[53,2],[55,7],[53,3],[55,1],[54,6],[55,1],[55,6],[55,8],[55,7],[54,1],[52,6],[55,4],[53,2],[53,8],[53,5],[53,1],[54,1],[0,0],[0,0],[0,0],[0,0],[0,0],[55,1],[53,5],[52,2],[53,6],[54,8],[55,2],[52,3],[53,3],[52,8],[54,3],[55,2],[52,5],[53,5],[52,7],[53,1],[53,3],[52,2],[55,4],[53,2],[53,4],[53,2],[54,6],[54,1],[54,8],[52,5],[52,1],[53,8],[53,4],[52,5],[54,1],[54,5],[53,2],[0,0],[52,3],[0,0],[0,0],[53,1],[53,7],[52,3],[53,1],[54,1],[52,4],[52,3],[54,4],[54,1],[52,7],[52,5],[54,5],[54,2],[52,2],[55,3],[54,5],[54,2],[53,7],[54,2],[54,2],[54,3],[52,2],[50,5],[52,1],[52,8],[55,7],[52,2],[52,6],[54,7],[54,2],[55,1],[54,1],[54,7],[52,7],[53,7],[54,8],[55,1],[52,8],[52,2],[54,7],[52,5],[54,3],[54,2],[54,6],[54,5],[53,2],[50,5],[54,3],[52,1],[53,2],[55,3],[52,2],[55,2],[53,1],[54,5],[54,2],[54,1],[55,8],[52,3],[0,0],[0,0],[0,0],[54,1],[53,4],[54,2],[52,7],[55,7],[53,3],[52,3],[54,8],[54,2],[53,3],[55,2],[54,4],[0,0],[0,0],[54,2],[55,1],[53,2],[54,2],[55,2],[53,3],[55,2],[54,4],[53,2],[52,7],[0,0],[0,0],[0,0],[52,1],[55,3],[53,1],[55,2],[54,3],[53,2],[54,5],[52,4],[54,5],[0,0],[0,0],[0,0],[0,0],[0,0],[55,3],[54,1],[54,2],[54,1],[52,2],[55,1],[55,4],[55,7],[54,1],[52,1],[52,4],[53,1],[55,7],[53,5],[54,7],[55,1],[53,1],[52,1],[53,8],[53,5],[53,4],[54,2],[55,3],[54,3],[52,1],[54,8],[52,3],[55,3],[55,1],[54,1],[52,6],[0,0],[0,0],[0,0],[53,2],[52,2],[52,6],[52,2],[54,4],[53,2],[55,1],[54,8],[55,6],[54,3],[55,4],[55,3],[55,2],[54,8],[54,2],[54,2],[52,1],[53,8],[55,4],[54,2],[52,5],[52,2],[52,1],[53,1],[53,2],[0,0],[0,0],[52,7],[52,1],[55,6],[54,3],[52,5],[53,6],[55,3],[54,1],[53,6],[53,5],[55,7],[54,3],[54,3],[53,1],[53,5],[54,2],[54,1],[52,7],[52,4],[54,6],[54,4],[52,6],[55,6],[53,7],[52,1],[52,5],[53,1],[52,5],[54,1],[55,4],[52,1],[55,1],[54,3],[52,2],[53,3],[52,5],[53,8],[53,7],[52,1],[52,2],[52,4],[52,8],[55,5],[52,6],[55,1],[55,7],[53,3],[54,1],[53,4],[53,6],[54,3],[54,1],[54,7],[54,7],[55,1],[55,3],[52,1],[55,2],[55,8],[55,4],[55,2],[53,2],[53,6],[52,3],[52,2],[55,2],[52,2],[54,3],[53,7],[54,1],[50,5],[54,4],[53,1],[52,5],[52,2],[55,2],[53,2],[50,5],[53,1],[53,7],[53,2],[54,3],[53,6],[54,2],[55,7],[52,1],[52,6],[54,6],[55,8],[53,2],[54,4],[53,1],[54,1],[55,3],[54,3],[55,1],[0,0],[0,0],[53,6],[54,8],[52,3],[55,1],[53,5],[55,7],[53,1],[54,4],[55,5],[55,6],[53,1],[53,5],[0,0],[0,0],[54,2],[53,7],[53,1],[54,1],[53,6],[52,6],[55,1],[53,3],[53,4],[52,1],[0,0],[0,0],[0,0],[52,4],[55,1],[54,8],[55,7],[54,1],[55,6],[52,2],[53,4],[52,7],[54,5],[52,4],[0,0],[0,0],[0,0],[53,5],[52,1],[53,5],[50,5],[55,2],[54,3],[55,1],[53,5],[52,5],[52,6],[53,2],[54,5],[55,6],[53,2],[52,5],[53,3],[52,1],[53,3],[52,1],[53,4],[54,5],[50,5],[53,2],[54,3],[52,4],[53,1],[55,2],[54,3],[54,8],[54,3],[52,5],[0,0],[0,0],[0,0],[55,1],[52,2],[52,6],[54,2],[54,1],[55,1],[52,5],[52,4],[53,5],[54,2],[55,2],[54,6],[54,1],[52,4],[53,2],[55,1],[52,7],[52,7],[52,4],[55,2],[54,2],[52,4],[52,2],[52,6],[52,1],[55,5],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[54,2],[54,6],[54,5],[54,3],[54,3],[54,2],[52,1],[55,3],[50,5],[54,2],[52,2],[53,1],[52,2],[55,4],[52,8],[54,5],[54,2],[53,1],[54,2],[53,3],[54,4],[55,2],[0,0],[0,0],[52,2],[54,3],[55,1],[54,3],[55,4],[53,1],[52,5],[52,2],[54,5],[53,6],[54,4],[54,5],[54,1],[53,6],[53,7],[55,8],[55,1],[53,1],[53,1],[52,2],[53,6],[53,2],[55,3],[54,4],[52,1],[54,1],[53,1],[53,6],[53,5],[54,2],[55,2],[55,3],[52,4],[52,5],[53,1],[54,1],[52,2],[55,8],[53,3],[52,1],[54,7],[52,6],[53,3],[54,2],[53,1],[52,7],[52,1],[53,1],[52,5],[53,8],[53,2],[53,6],[54,2],[52,4],[55,7],[53,8],[52,6],[54,4],[54,5],[0,0],[0,0],[0,0],[55,4],[0,0],[0,0],[55,2],[52,1],[55,3],[54,6],[55,3],[53,2],[52,1],[52,1],[55,3],[0,0],[52,4],[52,2],[53,4],[54,6],[52,2],[53,7],[54,8],[53,2],[55,4],[53,7],[54,1],[53,5],[52,3],[0,0],[0,0],[0,0],[52,7],[55,1],[52,1],[53,1],[55,3],[53,3],[52,1],[54,3],[52,3],[0,0],[0,0],[0,0],[0,0],[53,2],[53,2],[54,5],[55,4],[53,3],[52,1],[52,2],[52,3],[54,2],[53,5],[54,3],[55,8],[52,2],[52,1],[54,2],[52,3],[52,8],[54,6],[53,4],[53,6],[54,1],[55,2],[52,1],[53,2],[52,1],[55,6],[55,5],[52,6],[52,4],[55,5],[55,6],[55,6],[55,1],[53,5],[52,7],[54,8],[55,2],[55,3],[55,1],[54,8],[54,5],[55,2],[54,3],[55,7],[55,2],[55,1],[54,3],[55,3],[54,2],[55,5],[53,8],[52,6],[55,3],[53,2],[54,2],[54,2],[52,2],[55,8],[53,6],[53,6],[52,3],[55,1],[52,5],[54,1],[55,2],[54,7],[53,2],[55,2],[55,2],[55,4],[52,7],[0,0],[0,0],[54,2],[52,8],[52,7],[53,6],[54,2],[55,1],[55,8],[52,3],[54,6],[52,3],[54,7],[55,6],[52,2],[54,2],[52,4],[53,1],[55,4],[53,6],[53,2],[55,3],[54,2],[0,0],[0,0],[55,2],[52,4],[55,3],[52,6],[52,5],[52,4],[53,3],[52,2],[52,6],[52,3],[55,2],[54,3],[52,3],[55,4],[54,2],[55,4],[55,6],[53,1],[54,5],[54,5],[52,1],[55,1],[50,5],[55,1],[55,6],[54,7],[52,1],[54,8],[53,1],[53,2],[54,1],[53,4],[55,5],[55,5],[52,8],[52,2],[52,3],[52,3],[55,3],[52,5],[55,3],[55,7],[55,2],[55,1],[55,3],[53,4],[54,6],[55,4],[53,5],[52,3],[55,1],[52,4],[55,2],[54,3],[53,2],[53,6],[52,2],[54,6],[54,4],[52,6],[53,5],[53,5],[53,6],[0,0],[0,0],[55,5],[52,7],[52,2],[54,7],[53,1],[53,1],[52,4],[55,5],[55,1],[54,7],[52,2],[0,0],[0,0],[55,1],[55,2],[55,2],[53,2],[55,5],[52,2],[53,2],[54,2],[53,3],[52,7],[0,0],[0,0],[0,0],[0,0],[55,2],[55,8],[53,7],[52,4],[52,1],[55,1],[55,1],[52,2],[55,4],[53,7],[0,0],[0,0],[55,2],[52,3],[50,5],[53,4],[53,2],[55,2],[55,2],[55,1],[55,4],[53,2],[54,2],[54,3],[55,2],[53,2],[52,3],[55,1],[54,8],[52,7],[55,1],[52,2],[54,1],[52,7],[52,4],[55,8],[55,2],[55,1],[52,3],[54,2],[53,2],[53,1],[55,3],[54,4],[52,1],[54,3],[54,1],[53,1],[54,3],[53,1],[54,2],[54,7],[55,6],[52,7],[55,2],[53,4],[54,1],[53,3],[55,3],[52,6],[55,1],[53,4],[55,5],[55,2],[54,1],[55,4],[54,5],[53,4],[53,8],[55,2],[55,3],[52,7],[54,3],[52,1],[54,2],[55,3],[53,6],[54,4],[52,1],[53,1],[54,2],[54,1],[53,1],[0,0],[0,0],[54,1],[55,8],[55,2],[53,8],[55,5],[52,2],[52,6],[54,1],[53,4],[53,6],[53,4],[52,5],[50,5],[55,8],[54,4],[55,4],[54,3],[53,3],[52,6],[54,1],[52,5],[52,2],[55,2],[0,0],[0,0],[0,0],[53,4],[53,2],[54,2],[53,6],[55,5],[53,1],[55,4],[55,1],[53,8],[53,1],[55,8],[55,2],[52,3],[53,2],[53,2],[52,1],[52,2],[53,2],[53,4],[54,4],[54,1],[54,1],[54,2],[53,6],[52,4],[54,2],[53,2],[54,3],[53,2],[55,2],[54,1],[54,4],[54,2],[53,5],[55,3],[54,7],[53,3],[54,1],[52,6],[52,4],[54,5],[54,3],[52,3],[55,3],[54,8],[54,5],[52,3],[52,5],[54,2],[52,7],[55,7],[55,1],[54,7],[55,2],[52,2],[55,3],[55,5],[52,2],[55,7],[52,5],[55,6],[54,7],[55,8],[53,5],[52,1],[55,6],[55,2],[54,7],[53,2],[55,1],[54,6],[0,0],[54,4],[0,0],[0,0],[53,6],[54,1],[52,5],[55,1],[53,2],[54,2],[54,1],[53,8],[53,3],[54,7],[52,1],[52,2],[0,0],[0,0],[0,0],[53,5],[53,8],[53,3],[54,2],[55,6],[53,5],[55,1],[55,2],[54,1],[54,4],[52,5],[0,0],[0,0],[0,0],[0,0],[0,0],[53,4],[54,1],[55,8],[53,7],[54,4],[55,7],[55,1],[52,3],[52,2],[55,1],[54,6],[55,3],[52,2],[55,3],[55,4],[54,6],[53,6],[54,5],[53,6],[55,3],[52,2],[54,3],[55,7],[55,2],[52,7],[55,2],[55,3],[52,1],[55,2],[54,8],[53,3],[53,2],[53,2],[53,2],[55,2],[54,2],[52,4],[54,1],[52,4],[55,3],[53,2],[52,2],[53,1],[52,1],[53,6],[53,1],[53,2],[54,7],[55,3],[53,3],[52,5],[52,4],[55,2],[52,6],[53,1],[53,7],[53,1],[54,5],[55,1],[52,4],[52,1],[54,8],[54,7],[54,4],[52,7],[53,1],[0,0],[53,1],[53,7],[53,1],[54,2],[53,1],[52,7],[53,5],[54,7],[53,2],[53,3],[55,2],[55,2],[55,6],[52,4],[54,2],[54,1],[55,3],[55,3],[53,6],[55,1],[53,4],[55,7],[55,4],[54,3],[0,0],[0,0],[0,0],[52,7],[53,6],[55,2],[53,4],[52,2],[53,2],[54,5],[53,1],[55,1],[54,1],[54,4],[54,3],[53,2],[53,4],[54,1],[52,6],[54,1],[52,3],[54,2],[54,6],[54,1],[54,4],[55,3],[55,2],[52,1],[55,6],[53,1],[54,7],[55,6],[50,5],[55,3],[55,5],[54,6],[54,2],[52,4],[52,2],[54,2],[54,3],[55,4],[55,1],[55,2],[55,3],[55,5],[54,5],[54,2],[55,8],[50,5],[55,6],[52,2],[55,2],[52,6],[54,3],[54,1],[55,6],[53,3],[53,1],[52,3],[54,6],[54,6],[54,3],[54,7],[55,3],[53,8],[52,8],[55,1],[54,4],[52,7],[54,4],[53,4],[53,2],[52,2],[53,3],[55,4],[54,1],[52,4],[55,4],[54,2],[55,1],[54,7],[52,1],[55,8],[54,1],[53,3],[54,1],[52,5],[53,2],[53,2],[52,3],[55,6],[0,0],[0,0],[53,4],[54,4],[53,1],[52,7],[55,2],[50,5],[53,5],[52,2],[54,6],[52,2],[53,6],[52,4],[52,2],[50,5],[0,0],[0,0],[52,3],[53,2],[53,1],[55,1],[54,5],[52,3],[54,2],[52,4],[54,7],[53,6],[53,4],[55,3],[52,1],[53,2],[54,2],[55,4],[53,2],[52,6],[55,1],[53,6],[53,3],[55,5],[52,3],[54,5],[55,1],[54,5],[52,6],[52,3],[54,3],[54,8],[54,6],[54,8],[55,1],[52,5],[55,2],[54,2],[52,4],[50,5],[53,5],[53,2],[52,1],[53,7],[53,8],[52,4],[53,1],[55,6],[53,8],[55,2],[55,3],[53,3],[55,1],[53,6],[55,3],[52,3],[55,2],[54,5],[55,1],[52,3],[55,5],[52,3],[52,4],[55,7],[53,2],[54,6],[55,3],[0,0],[0,0],[54,1],[55,2],[54,2],[55,3],[54,6],[54,3],[55,6],[52,8],[52,7],[53,7],[52,1],[54,4],[52,1],[55,1],[54,2],[53,7],[55,6],[55,7],[55,2],[55,1],[55,2],[55,3],[55,2],[0,0],[0,0],[0,0],[53,2],[55,4],[52,8],[54,5],[54,2],[55,6],[52,7],[55,1],[54,4],[53,6],[55,3],[53,5],[55,2],[53,4],[55,3],[52,5],[55,6],[55,2],[55,5],[55,1],[54,4],[52,1],[54,1],[55,3],[55,7],[54,5],[55,7],[55,3],[55,2],[52,1],[55,1],[55,7],[54,3],[53,2],[52,3],[55,2],[55,4],[54,8],[53,1],[54,2],[52,1],[54,6],[55,2],[55,3],[55,1],[54,2],[54,1],[53,4],[52,5],[54,2],[52,8],[54,3],[54,3],[53,3],[52,7],[53,7],[53,2],[55,3],[55,3],[55,2],[53,4],[54,2],[54,7],[54,1],[53,2],[53,3],[53,2],[52,6],[52,1],[52,3],[54,2],[54,2],[55,5],[0,0],[0,0],[53,3],[52,4],[52,1],[53,2],[53,4],[52,1],[53,1],[52,2],[53,2],[54,1],[52,4],[53,1],[52,1],[55,1],[0,0],[0,0],[54,6],[54,3],[54,1],[53,2],[52,2],[54,3],[53,5],[53,4],[54,6],[53,6],[54,2],[53,7],[52,1],[55,4],[0,0],[0,0],[55,5],[54,6],[54,4],[55,2],[55,2],[52,4],[54,8],[54,5],[52,1],[52,7],[52,1],[55,1],[53,5],[55,6],[54,1],[54,3],[54,2],[53,3],[54,1],[52,7],[54,1],[55,5],[54,5],[52,2],[52,2],[53,1],[52,3],[50,5],[52,3],[55,4],[53,5],[52,3],[54,7],[53,4],[54,1],[55,7],[53,2],[52,4],[55,2],[55,2],[54,5],[53,2],[52,4],[53,1],[52,8],[55,2],[53,3],[53,4],[53,2],[52,1],[52,2],[52,6],[55,6],[52,1],[52,7],[54,2],[53,1],[55,3],[55,5],[52,5],[54,3],[53,4],[55,6],[55,2],[54,3],[0,0],[0,0],[52,1],[53,3],[54,1],[54,2],[53,2],[53,1],[52,1],[52,7],[55,3],[55,5],[52,4],[54,7],[54,7],[55,6],[53,1],[55,2],[52,4],[55,7],[52,1],[52,6],[53,4],[52,3],[52,2],[54,3],[53,6],[55,4],[54,8],[55,4],[52,4],[53,2],[55,3],[54,6],[54,5],[54,1],[54,8],[54,4],[54,1],[55,5],[53,1],[53,4],[55,7],[55,5],[52,1],[55,5],[54,2],[53,1],[54,7],[52,4],[55,8],[54,2],[54,2],[55,5],[55,1],[50,5],[53,6],[52,4],[50,5],[53,2],[55,6],[52,2],[53,7],[53,2],[54,6],[52,4],[53,8],[55,1],[53,7],[55,3],[53,6],[54,7],[55,5],[55,3],[55,6],[52,3],[52,1],[52,3],[54,1],[54,8],[52,3],[52,5],[53,2],[52,1],[54,3],[52,5],[52,6],[53,2],[52,2],[52,5],[52,5],[54,3],[54,5],[52,2],[54,7],[52,5],[52,3],[55,8],[55,2],[52,8],[52,3],[0,0],[0,0],[55,2],[54,4],[52,3],[55,6],[53,5],[55,8],[53,1],[53,4],[54,5],[55,3],[54,2],[54,7],[52,5],[55,8],[0,0],[0,0],[0,0],[52,1],[53,4],[53,2],[55,5],[55,3],[54,3],[54,3],[53,4],[52,1],[52,2],[55,1],[55,8],[53,3],[0,0],[0,0],[54,3],[54,6],[54,5],[54,1],[54,2],[52,5],[52,1],[55,8],[54,7],[52,5],[54,2],[55,4],[53,6],[52,2],[52,3],[55,1],[54,2],[54,6],[54,2],[55,1],[52,1],[54,1],[52,1],[52,7],[55,3],[55,6],[53,1],[55,6],[52,3],[53,3],[52,7],[52,3],[53,4],[55,1],[55,3],[52,7],[55,6],[52,6],[55,6],[53,2],[53,4],[53,8],[52,1],[53,1],[54,2],[54,3],[54,2],[55,4],[54,3],[52,2],[52,3],[52,5],[54,6],[55,1],[53,3],[54,1],[55,3],[53,5],[54,4],[52,5],[52,4],[54,2],[53,3],[52,3],[53,2],[0,0],[0,0],[53,4],[54,3],[53,3],[53,6],[53,1],[53,2],[52,3],[52,7],[54,4],[52,2],[52,1],[53,2],[53,7],[53,7],[55,6],[55,5],[54,4],[52,7],[55,3],[52,2],[53,7],[55,1],[54,6],[53,3],[54,5],[53,4],[54,7],[53,5],[52,3],[55,5],[55,8],[54,8],[55,3],[53,2],[55,3],[53,3],[53,5],[52,3],[52,2],[55,3],[52,6],[54,7],[54,6],[54,4],[53,2],[55,3],[54,4],[52,1],[53,2],[55,1],[54,7],[52,3],[55,1],[52,1],[52,2],[54,8],[52,7],[54,6],[54,3],[55,2],[54,2],[54,1],[53,2],[53,1],[52,2],[55,1],[53,3],[52,2],[55,3],[55,6],[52,3],[52,3],[54,5],[55,2],[52,1],[55,2],[53,1],[52,6],[55,3],[54,8],[54,3],[55,1],[55,5],[54,2],[55,1],[52,4],[54,5],[52,8],[52,1],[54,4],[53,2],[54,3],[53,3],[52,7],[55,8],[54,4],[53,3],[55,4],[54,5],[55,6],[0,0],[0,0],[0,0],[0,0],[53,1],[54,3],[53,6],[52,3],[53,1],[52,2],[54,3],[52,3],[52,1],[54,2],[55,3],[0,0],[0,0],[0,0],[54,2],[54,6],[54,5],[50,5],[53,1],[55,1],[53,1],[55,4],[52,4],[50,5],[53,1],[53,4],[52,3],[54,2],[0,0],[0,0],[0,0],[53,2],[52,8],[53,4],[54,1],[53,1],[54,5],[55,1],[52,5],[53,4],[53,7],[55,1],[55,4],[52,4],[55,1],[54,5],[54,5],[55,3],[53,6],[54,2],[53,7],[54,8],[53,5],[54,6],[53,6],[52,7],[52,2],[54,3],[55,1],[52,7],[52,4],[54,7],[52,2],[52,8],[54,4],[53,4],[53,3],[55,4],[52,3],[53,7],[53,5],[54,3],[55,3],[55,2],[53,7],[55,1],[54,6],[52,1],[55,1],[52,5],[54,3],[54,1],[54,4],[53,1],[52,5],[54,2],[53,7],[55,5],[53,3],[52,5],[55,7],[54,6],[53,3],[0,0],[0,0],[54,4],[55,2],[0,0],[0,0],[52,2],[52,2],[52,3],[55,8],[55,1],[55,5],[55,1],[52,5],[55,2],[53,3],[54,1],[54,2],[53,2],[53,1],[50,5],[54,1],[55,2],[54,4],[52,1],[52,1],[52,4],[53,1],[55,8],[54,7],[53,1],[54,2],[55,2],[54,3],[55,5],[53,7],[54,1],[53,7],[52,3],[54,8],[55,4],[52,6],[53,2],[53,3],[52,6],[54,4],[55,4],[53,2],[54,2],[55,5],[53,1],[52,8],[54,2],[54,1],[50,5],[54,2],[54,3],[53,2],[54,5],[52,1],[53,2],[52,2],[52,3],[54,2],[54,3],[53,7],[55,3],[55,1],[55,4],[53,8],[54,4],[53,4],[54,4],[54,5],[53,2],[52,1],[54,7],[52,3],[52,6],[55,6],[54,7],[53,2],[55,4],[55,7],[53,7],[54,2],[54,3],[52,5],[54,5],[55,1],[55,6],[54,2],[55,4],[54,6],[54,5],[53,7],[55,3],[55,5],[54,7],[52,5],[54,6],[55,1],[53,2],[53,6],[0,0],[0,0],[0,0],[54,8],[53,2],[54,6],[53,3],[55,3],[54,2],[55,7],[52,7],[54,6],[53,1],[53,1],[0,0],[0,0],[0,0],[54,7],[52,1],[55,7],[55,1],[53,6],[55,2],[52,2],[55,7],[55,7],[55,7],[54,2],[55,2],[55,5],[55,4],[54,6],[0,0],[54,5],[54,5],[52,6],[55,6],[54,4],[54,4],[52,6],[55,5],[52,1],[54,6],[54,4],[54,1],[54,1],[54,2],[53,7],[52,3],[54,1],[54,2],[55,6],[53,1],[53,8],[55,7],[53,1],[55,1],[52,2],[55,1],[52,8],[53,2],[55,1],[53,8],[55,5],[55,7],[53,2],[0,0],[0,0],[54,1],[54,1],[55,8],[52,3],[54,5],[53,1],[55,3],[52,8],[53,7],[53,6],[54,1],[55,7],[55,1],[54,2],[54,7],[54,6],[55,2],[55,4],[52,1],[53,2],[52,6],[53,5],[55,8],[54,1],[55,4],[53,7],[52,3],[55,3],[0,0],[52,8],[54,5],[0,0],[0,0],[0,0],[55,7],[54,7],[54,7],[55,3],[52,3],[55,2],[54,7],[54,2],[53,4],[55,1],[53,4],[53,6],[55,6],[54,1],[52,3],[53,1],[53,7],[52,6],[54,6],[55,7],[55,3],[53,4],[53,7],[55,5],[55,6],[53,1],[54,1],[50,5],[54,1],[55,2],[53,8],[52,7],[52,2],[55,1],[50,5],[54,1],[55,5],[54,1],[52,8],[54,4],[52,3],[55,4],[52,2],[55,1],[55,1],[54,1],[53,2],[52,4],[52,3],[52,4],[53,5],[55,2],[53,7],[53,2],[53,2],[55,7],[54,8],[53,2],[55,2],[53,3],[54,7],[54,3],[53,3],[53,4],[54,1],[54,2],[54,8],[55,7],[52,4],[52,3],[55,3],[53,2],[54,2],[53,8],[55,2],[55,3],[52,5],[54,5],[54,5],[55,7],[52,1],[52,2],[53,3],[55,3],[55,2],[54,7],[53,2],[55,4],[53,7],[54,1],[54,6],[53,3],[55,8],[55,3],[53,5],[55,5],[54,6],[52,3],[0,0],[0,0],[0,0],[54,2],[55,2],[53,4],[54,1],[53,3],[55,5],[53,4],[53,3],[55,1],[55,1],[0,0],[0,0],[55,5],[53,1],[54,3],[54,1],[54,6],[54,5],[53,4],[53,1],[52,3],[54,2],[53,4],[55,3],[53,3],[52,2],[53,7],[53,3],[54,1],[0,0],[52,2],[52,2],[54,8],[54,1],[55,1],[54,4],[52,1],[52,1],[53,2],[53,3],[52,5],[52,3],[55,6],[55,3],[53,4],[53,2],[52,1],[55,1],[52,2],[55,5],[54,2],[53,5],[53,5],[55,2],[55,1],[55,2],[52,3],[52,4],[52,4],[54,2],[53,2],[50,5],[53,6],[0,0],[0,0],[0,0],[55,2],[54,6],[55,6],[55,3],[54,2],[53,6],[52,1],[55,2],[55,1],[54,2],[53,1],[53,3],[53,2],[53,6],[55,3],[54,1],[53,1],[52,6],[52,1],[52,1],[54,3],[53,4],[53,1],[54,3],[55,3],[53,5],[55,1],[53,6],[0,0],[0,0],[0,0],[53,3],[52,2],[53,6],[54,1],[52,3],[54,1],[54,5],[53,1],[55,2],[52,2],[53,8],[53,1],[55,2],[54,4],[52,3],[55,2],[55,1],[54,1],[54,5],[54,5],[54,4],[55,1],[55,2],[53,2],[54,7],[52,2],[55,2],[55,3],[52,5],[55,6],[53,1],[53,3],[53,2],[54,2],[54,6],[52,1],[54,7],[52,7],[55,2],[53,8],[55,1],[52,4],[52,8],[0,0],[0,0],[53,1],[55,6],[55,4],[55,7],[54,3],[55,1],[54,1],[52,8],[52,2],[54,1],[53,3],[54,6],[55,1],[53,1],[54,8],[52,5],[55,3],[55,2],[55,5],[52,2],[55,1],[52,4],[55,1],[53,7],[52,6],[52,1],[54,4],[52,5],[55,2],[53,3],[54,2],[52,1],[52,3],[52,2],[54,1],[52,3],[54,1],[55,8],[53,5],[55,2],[52,7],[52,5],[55,7],[54,1],[52,8],[55,2],[52,5],[53,5],[55,4],[52,2],[54,5],[55,8],[55,1],[54,2],[53,1],[53,1],[52,3],[54,5],[52,5],[54,2],[52,8],[55,1],[55,7],[55,3],[55,5],[52,5],[53,8],[55,4],[0,0],[0,0],[54,3],[53,7],[52,5],[52,3],[52,1],[52,5],[54,2],[52,5],[54,6],[52,1],[53,5],[55,2],[52,7],[55,1],[55,3],[55,6],[52,3],[0,0],[55,8],[52,6],[55,3],[52,5],[55,1],[53,7],[55,6],[55,5],[53,3],[52,3],[52,4],[55,2],[53,7],[53,7],[54,2],[54,4],[52,3],[55,2],[55,2],[53,2],[55,5],[54,1],[54,1],[54,7],[52,2],[52,3],[54,4],[53,4],[53,3],[52,2],[54,6],[54,2],[52,6],[0,0],[53,2],[0,0],[0,0],[55,8],[52,8],[55,6],[53,1],[52,1],[53,1],[52,4],[54,6],[55,1],[52,1],[55,6],[53,3],[54,5],[55,5],[55,4],[53,8],[52,1],[53,6],[53,1],[53,3],[54,1],[54,5],[55,5],[52,6],[55,1],[54,4],[52,6],[0,0],[0,0],[0,0],[55,1],[54,5],[52,2],[53,1],[55,3],[53,1],[55,3],[52,6],[54,4],[53,1],[55,5],[53,1],[53,1],[55,1],[53,6],[55,3],[55,2],[52,7],[54,7],[52,2],[52,3],[54,1],[55,5],[52,1],[53,2],[53,4],[54,3],[55,3],[55,8],[54,3],[54,7],[52,6],[52,7],[55,3],[52,3],[52,2],[53,4],[52,4],[53,2],[54,2],[55,3],[55,6],[52,8],[0,0],[0,0],[52,7],[53,6],[50,5],[55,4],[54,2],[55,4],[55,3],[54,1],[55,2],[52,2],[50,5],[53,8],[55,6],[52,3],[55,7],[55,5],[52,2],[54,5],[54,3],[52,2],[55,1],[53,5],[52,5],[55,6],[55,5],[55,7],[52,7],[54,2],[53,5],[54,1],[54,3],[53,1],[54,4],[54,2],[53,2],[54,5],[53,3],[55,2],[53,4],[52,4],[52,4],[52,4],[54,5],[53,4],[52,1],[55,6],[52,5],[54,1],[53,6],[54,2],[53,2],[52,7],[54,2],[54,6],[53,1],[55,2],[54,6],[54,3],[53,6],[55,7],[55,5],[55,2],[55,5],[54,2],[53,7],[55,2],[55,6],[54,5],[0,0],[55,4],[53,3],[53,5],[55,2],[54,1],[54,3],[53,6],[53,2],[53,2],[53,1],[54,3],[52,1],[54,2],[55,6],[52,5],[55,6],[55,1],[55,7],[0,0],[0,0],[54,3],[55,7],[54,8],[52,3],[54,1],[54,2],[52,5],[55,5],[55,3],[53,2],[53,2],[52,2],[53,2],[54,1],[55,5],[55,5],[53,1],[55,3],[52,6],[54,1],[55,2],[53,1],[55,5],[54,2],[53,3],[52,1],[55,3],[53,1],[54,2],[54,7],[53,1],[54,1],[0,0],[52,1],[0,0],[0,0],[55,2],[52,4],[50,5],[55,2],[52,2],[55,3],[54,4],[54,2],[55,1],[52,5],[52,5],[54,8],[53,1],[53,6],[53,2],[53,2],[53,8],[55,7],[54,8],[55,4],[52,8],[53,3],[52,2],[52,1],[53,8],[55,5],[52,7],[55,2],[55,1],[0,0],[52,6],[55,5],[55,3],[54,5],[55,2],[55,1],[53,5],[52,1],[52,1],[55,1],[53,6],[55,3],[55,4],[54,6],[54,3],[54,7],[55,4],[54,2],[52,2],[53,2],[52,6],[54,3],[52,4],[53,4],[54,2],[54,4],[55,1],[55,1],[52,4],[52,4],[53,3],[52,2],[55,7],[53,8],[55,3],[52,3],[55,2],[52,6],[54,1],[55,4],[54,1],[54,8],[0,0],[0,0],[52,2],[54,2],[0,0],[0,0],[52,2],[55,3],[54,5],[54,6],[53,2],[54,1],[52,6],[54,7],[54,3],[52,7],[55,1],[52,3],[53,4],[53,4],[52,4],[54,3],[52,6],[53,2],[53,1],[55,4],[53,2],[53,6],[54,1],[55,5],[53,7],[53,5],[53,4],[52,7],[55,6],[54,3],[52,6],[53,5],[53,3],[53,1],[54,4],[54,3],[55,1],[53,6],[55,2],[55,2],[52,5],[55,2],[55,4],[54,1],[53,1],[53,4],[53,1],[53,2],[52,3],[53,6],[54,3],[52,3],[53,2],[55,2],[52,4],[52,2],[54,1],[53,4],[52,4],[53,6],[55,6],[52,5],[0,0],[53,7],[0,0],[0,0],[55,6],[52,8],[55,7],[55,1],[52,3],[52,8],[52,4],[53,6],[54,3],[55,8],[54,4],[54,1],[54,8],[55,3],[54,1],[53,3],[55,2],[53,3],[0,0],[0,0],[55,3],[55,2],[53,1],[54,6],[52,1],[52,7],[52,7],[53,4],[55,4],[55,3],[52,7],[52,7],[55,2],[55,1],[54,5],[52,7],[53,2],[53,6],[54,2],[54,6],[54,8],[55,1],[50,5],[52,1],[52,5],[54,2],[54,3],[53,1],[54,5],[52,5],[52,4],[54,8],[0,0],[55,1],[0,0],[0,0],[52,2],[55,4],[55,2],[53,1],[55,1],[54,1],[55,1],[53,1],[54,7],[53,1],[53,1],[55,1],[52,7],[55,3],[53,3],[53,5],[54,5],[55,4],[52,1],[52,3],[54,5],[52,7],[53,5],[54,6],[52,3],[55,1],[55,1],[54,5],[53,1],[0,0],[54,2],[54,1],[52,2],[55,1],[53,1],[52,3],[55,2],[54,3],[53,4],[55,8],[53,1],[54,1],[55,2],[52,2],[54,5],[54,4],[53,4],[52,7],[0,0],[0,0],[53,5],[52,3],[55,2],[55,8],[52,2],[53,1],[53,5],[54,7],[55,2],[53,6],[52,2],[54,5],[53,2],[54,2],[55,4],[52,1],[55,3],[53,8],[55,4],[52,6],[54,4],[54,2],[55,7],[52,6],[54,1],[54,5],[0,0],[0,0],[52,1],[54,6],[55,3],[54,6],[54,5],[54,7],[55,4],[55,4],[54,5],[55,3],[55,4],[55,1],[53,1],[52,2],[55,2],[55,6],[53,1],[54,4],[53,1],[52,3],[54,2],[55,8],[55,2],[55,2],[54,7],[53,2],[55,7],[54,7],[54,2],[53,1],[53,4],[53,7],[55,8],[54,1],[55,1],[52,7],[53,3],[54,6],[52,2],[52,2],[53,3],[52,6],[55,8],[54,7],[54,7],[51,1],[55,2],[54,1],[52,8],[52,2],[54,1],[54,2],[54,7],[55,2],[55,1],[54,4],[55,4],[55,5],[54,3],[52,1],[55,6],[50,5],[0,0],[52,4],[0,0],[0,0],[0,0],[55,2],[54,1],[54,1],[53,3],[54,1],[53,2],[55,2],[53,3],[54,6],[54,6],[53,4],[52,2],[52,3],[54,2],[52,1],[52,2],[54,7],[0,0],[0,0],[52,1],[55,2],[52,2],[53,6],[53,1],[54,2],[53,3],[55,3],[52,3],[52,6],[53,2],[52,1],[52,5],[55,4],[52,2],[53,3],[53,7],[55,4],[54,7],[53,3],[55,1],[52,5],[52,6],[55,7],[55,1],[55,1],[55,7],[53,2],[52,7],[52,2],[52,3],[54,3],[0,0],[53,1],[55,4],[0,0],[54,5],[53,2],[54,8],[55,4],[54,1],[53,3],[52,1],[54,1],[52,3],[54,1],[54,3],[55,1],[52,4],[52,8],[53,1],[52,7],[55,7],[55,1],[52,3],[52,1],[52,1],[52,3],[52,4],[54,3],[54,8],[55,2],[53,2],[52,8],[54,2],[54,5],[54,2],[55,1],[52,6],[52,5],[53,4],[52,1],[54,1],[54,6],[53,1],[55,3],[55,5],[55,2],[52,3],[53,7],[55,2],[54,3],[55,1],[55,6],[0,0],[0,0],[54,1],[52,2],[54,1],[55,5],[53,3],[55,1],[50,5],[52,2],[55,7],[50,5],[54,3],[53,2],[52,3],[52,4],[53,6],[54,2],[52,2],[55,3],[55,4],[52,1],[53,2],[52,7],[54,5],[55,3],[55,1],[55,2],[55,1],[54,4],[53,2],[52,2],[55,1],[54,1],[52,2],[54,2],[55,2],[55,1],[54,7],[54,4],[52,2],[52,7],[52,6],[55,1],[55,6],[53,7],[55,7],[55,3],[52,7],[54,8],[53,2],[55,5],[53,7],[55,7],[53,3],[55,6],[53,5],[53,4],[54,1],[54,3],[55,2],[55,4],[52,4],[55,1],[55,2],[54,5],[53,3],[53,5],[54,7],[54,5],[55,2],[52,5],[54,5],[53,5],[52,3],[53,8],[53,7],[54,1],[52,6],[55,2],[54,7],[55,3],[54,5],[55,8],[55,1],[52,2],[52,7],[52,7],[52,5],[54,3],[54,4],[53,5],[0,0],[55,2],[0,0],[0,0],[0,0],[53,6],[55,1],[52,8],[0,0],[0,0],[55,4],[55,2],[53,1],[53,3],[53,2],[52,5],[52,5],[52,8],[52,3],[53,6],[55,4],[55,6],[0,0],[0,0],[52,5],[52,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,5],[0,0],[0,0],[53,1],[53,2],[54,1],[55,1],[55,7],[53,6],[53,2],[54,7],[52,8],[54,3],[52,4],[55,2],[50,5],[53,5],[55,1],[52,2],[55,1],[52,2],[52,4],[52,3],[55,2],[55,6],[53,3],[52,7],[52,1],[53,2],[52,5],[52,2],[52,2],[55,6],[54,8],[55,7],[54,2],[52,7],[53,2],[55,2],[54,2],[55,2],[54,7],[55,7],[52,6],[53,4],[53,6],[55,3],[53,7],[55,2],[52,8],[52,4],[0,0],[53,5],[53,8],[52,6],[52,3],[54,3],[55,4],[55,3],[53,3],[53,8],[53,2],[53,8],[55,1],[52,1],[53,1],[54,3],[54,4],[53,2],[52,1],[54,2],[55,1],[52,8],[54,8],[55,1],[52,3],[52,7],[53,4],[54,7],[55,4],[55,1],[52,6],[54,2],[53,2],[53,4],[53,3],[54,1],[52,6],[55,3],[54,2],[55,1],[54,5],[55,2],[54,1],[54,4],[55,6],[53,4],[55,3],[55,2],[53,8],[52,1],[52,3],[54,4],[55,2],[55,4],[53,1],[53,4],[53,3],[52,3],[55,4],[53,7],[52,2],[54,2],[54,3],[52,8],[55,5],[54,5],[53,4],[55,1],[54,4],[54,7],[52,2],[52,2],[53,2],[54,4],[54,3],[52,2],[55,2],[55,4],[54,5],[52,5],[52,6],[54,8],[52,4],[54,2],[53,7],[55,8],[54,6],[52,2],[53,3],[50,5],[53,2],[54,7],[0,0],[55,4],[0,0],[0,0],[53,6],[53,5],[52,1],[54,1],[0,0],[0,0],[55,6],[52,1],[54,5],[54,5],[52,2],[54,2],[53,1],[55,6],[53,4],[55,7],[53,1],[55,8],[0,0],[0,0],[53,2],[52,7],[55,4],[54,3],[53,5],[55,1],[52,2],[54,6],[52,7],[55,8],[54,3],[54,7],[53,2],[52,1],[55,5],[53,6],[52,5],[55,6],[55,3],[53,1],[54,2],[55,5],[53,1],[52,6],[53,6],[52,7],[55,1],[52,4],[54,4],[53,2],[52,3],[55,3],[52,1],[0,0],[0,0],[0,0],[0,0],[53,8],[55,6],[54,3],[55,5],[52,1],[53,1],[54,3],[53,8],[55,5],[53,2],[53,6],[54,1],[55,5],[55,3],[53,5],[54,2],[55,2],[54,5],[53,5],[55,2],[55,4],[52,2],[54,7],[53,3],[52,5],[52,3],[53,2],[54,5],[0,0],[55,2],[53,1],[53,2],[52,2],[52,1],[55,2],[52,1],[53,6],[54,2],[55,1],[53,1],[52,1],[54,3],[52,3],[52,1],[54,3],[53,6],[52,1],[53,7],[52,2],[0,0],[0,0],[54,6],[55,7],[55,1],[54,2],[54,3],[53,2],[53,2],[55,4],[55,7],[54,2],[54,8],[52,6],[55,6],[52,4],[53,1],[54,5],[55,1],[53,1],[52,5],[52,5],[52,2],[53,3],[52,2],[53,1],[53,4],[53,2],[53,4],[55,4],[52,8],[55,2],[54,2],[55,5],[52,3],[55,7],[53,4],[52,7],[54,1],[52,1],[55,4],[52,2],[53,3],[54,3],[53,3],[53,5],[53,1],[54,4],[52,7],[52,2],[52,3],[53,8],[53,1],[53,4],[52,6],[54,1],[55,1],[54,2],[54,5],[55,2],[52,4],[52,3],[54,1],[53,3],[52,3],[55,3],[54,2],[52,3],[54,4],[53,5],[52,7],[52,3],[55,1],[52,5],[54,4],[52,1],[55,3],[53,2],[55,1],[55,8],[54,1],[53,1],[55,1],[55,4],[54,3],[54,3],[52,5],[54,7],[55,2],[53,3],[0,0],[0,0],[0,0],[0,0],[54,3],[52,2],[53,2],[0,0],[0,0],[53,1],[53,4],[0,0],[0,0],[53,1],[55,5],[55,2],[52,3],[54,1],[0,0],[0,0],[0,0],[0,0],[0,0],[54,7],[54,8],[53,6],[52,6],[55,6],[55,8],[54,4],[53,4],[54,4],[55,7],[53,5],[53,8],[50,5],[55,2],[54,5],[55,2],[52,7],[55,1],[52,2],[53,7],[55,6],[55,4],[53,7],[54,1],[53,6],[53,2],[53,3],[52,1],[54,1],[53,2],[54,2],[53,2],[55,1],[52,5],[52,1],[54,1],[52,2],[0,0],[0,0],[0,0],[52,2],[54,3],[52,1],[53,1],[54,2],[54,5],[55,4],[53,1],[54,2],[53,4],[55,4],[53,2],[54,2],[52,4],[55,5],[55,1],[55,2],[52,5],[54,2],[52,2],[55,4],[52,3],[53,2],[55,1],[52,7],[52,1],[0,0],[55,1],[52,4],[54,3],[55,3],[53,7],[54,1],[52,8],[54,2],[52,7],[53,4],[53,6],[53,1],[53,1],[55,3],[52,3],[52,3],[53,4],[55,1],[0,0],[55,2],[0,0],[0,0],[55,4],[55,3],[54,4],[53,5],[53,1],[52,5],[53,3],[55,1],[52,5],[55,2],[55,2],[54,3],[53,8],[54,2],[52,2],[52,2],[54,1],[55,1],[55,2],[55,2],[53,2],[54,1],[52,3],[53,7],[55,3],[53,1],[53,1],[52,8],[53,5],[52,1],[52,3],[55,2],[53,1],[52,7],[55,1],[54,1],[52,1],[52,2],[54,7],[53,2],[55,1],[52,7],[55,3],[54,7],[53,5],[55,7],[53,2],[53,4],[52,5],[52,3],[54,4],[54,4],[54,7],[53,5],[54,5],[53,7],[55,3],[54,2],[55,2],[55,5],[54,4],[52,6],[55,5],[55,7],[53,2],[53,4],[52,6],[53,5],[54,2],[52,2],[52,1],[53,2],[52,1],[53,2],[55,3],[55,2],[52,3],[53,1],[52,3],[54,3],[53,2],[52,4],[52,2],[52,6],[53,6],[53,8],[53,7],[54,6],[0,0],[0,0],[0,0],[0,0],[55,6],[55,3],[53,2],[53,2],[55,1],[52,7],[54,4],[0,0],[0,0],[53,5],[52,8],[52,3],[53,7],[53,4],[0,0],[52,4],[55,4],[53,1],[52,2],[54,2],[55,5],[52,2],[54,1],[54,1],[52,5],[52,5],[54,7],[55,5],[53,8],[54,5],[54,6],[53,7],[53,7],[52,6],[55,1],[53,7],[54,3],[53,5],[55,1],[52,3],[52,6],[54,8],[52,6],[54,1],[53,2],[54,5],[54,3],[55,6],[53,5],[53,4],[52,1],[54,1],[53,6],[52,1],[54,2],[55,2],[0,0],[0,0],[0,0],[55,2],[53,4],[50,5],[52,2],[53,2],[55,6],[55,6],[52,6],[52,1],[55,2],[53,3],[52,3],[55,4],[55,1],[54,7],[52,1],[54,2],[55,4],[53,4],[55,7],[55,6],[54,1],[54,8],[52,5],[53,2],[54,3],[0,0],[53,5],[52,5],[53,6],[52,7],[54,2],[54,2],[54,1],[53,5],[55,2],[53,3],[55,5],[54,1],[55,2],[54,4],[54,5],[53,6],[54,2],[53,3],[55,2],[50,5],[52,6],[0,0],[53,2],[53,1],[53,3],[55,6],[52,1],[55,5],[53,7],[53,1],[52,2],[55,3],[52,1],[54,3],[54,4],[54,3],[52,7],[55,3],[53,2],[52,3],[54,1],[55,1],[52,4],[53,5],[53,3],[52,4],[52,3],[54,7],[54,1],[52,2],[54,6],[53,2],[55,5],[55,2],[54,6],[54,7],[0,0],[0,0],[0,0],[55,3],[52,2],[55,1],[54,5],[52,2],[53,5],[55,4],[55,5],[53,1],[52,2],[53,3],[54,8],[53,7],[53,7],[53,5],[52,2],[53,4],[52,1],[52,4],[53,2],[55,1],[55,1],[53,5],[54,8],[54,4],[52,2],[53,5],[53,8],[55,3],[52,3],[53,3],[54,1],[55,7],[53,3],[55,4],[52,4],[54,1],[53,4],[55,6],[53,2],[50,5],[54,1],[55,1],[53,2],[55,1],[55,6],[52,2],[52,6],[52,2],[52,6],[0,0],[0,0],[0,0],[0,0],[0,0],[53,7],[52,1],[55,2],[52,4],[53,3],[55,4],[53,2],[52,6],[53,3],[53,8],[54,3],[54,5],[54,6],[55,7],[0,0],[0,0],[52,2],[52,4],[54,7],[53,7],[54,1],[53,5],[55,5],[52,3],[55,4],[55,1],[53,6],[54,2],[54,2],[52,1],[53,3],[52,6],[53,5],[54,4],[54,8],[54,2],[54,3],[54,3],[55,1],[55,2],[53,4],[54,5],[52,8],[55,4],[53,1],[52,7],[55,2],[55,3],[52,5],[53,5],[54,2],[55,4],[54,2],[52,1],[53,1],[53,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,8],[54,3],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[52,6],[52,2],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,5],[53,4],[54,2],[54,8],[52,2],[54,3],[54,2],[52,2],[55,6],[52,2],[52,3],[55,1],[55,6],[52,5],[52,1],[52,6],[52,2],[55,2],[0,0],[0,0],[52,5],[55,7],[52,3],[53,3],[53,6],[54,7],[55,3],[55,2],[52,3],[54,6],[55,1],[55,2],[55,2],[55,3],[53,2],[55,1],[52,1],[55,4],[55,7],[53,7],[54,7],[52,3],[54,5],[54,2],[52,8],[55,4],[55,8],[54,2],[54,7],[54,1],[0,0],[0,0],[52,5],[54,1],[55,7],[54,2],[55,6],[55,1],[53,8],[53,1],[53,4],[54,3],[54,3],[53,6],[53,6],[55,1],[54,2],[55,4],[54,1],[0,0],[0,0],[54,5],[52,5],[53,7],[55,7],[53,7],[55,2],[54,8],[55,1],[54,6],[52,5],[55,1],[54,3],[52,2],[55,3],[54,3],[54,4],[55,1],[55,1],[54,2],[52,3],[55,4],[55,8],[50,5],[54,4],[55,3],[53,2],[55,6],[55,3],[53,1],[53,1],[54,3],[53,2],[53,6],[54,2],[53,2],[54,2],[55,5],[54,2],[55,3],[55,4],[55,6],[53,4],[0,0],[54,3],[54,3],[55,5],[54,4],[54,5],[54,3],[54,3],[54,5],[54,1],[55,6],[55,4],[55,8],[52,1],[52,5],[53,1],[55,7],[55,1],[55,8],[55,7],[53,2],[52,2],[54,3],[53,4],[52,3],[55,3],[54,4],[54,2],[54,8],[54,1],[52,2],[52,2],[54,3],[52,1],[55,3],[54,3],[54,5],[52,4],[54,5],[52,3],[53,7],[53,1],[53,6],[55,3],[0,0],[0,0],[0,0],[0,0],[54,6],[52,8],[52,3],[55,5],[55,6],[52,1],[52,6],[55,3],[52,7],[53,2],[54,6],[55,3],[55,4],[55,8],[52,1],[53,1],[55,6],[53,2],[52,7],[53,2],[55,1],[54,7],[53,6],[54,6],[54,6],[53,7],[55,6],[52,3],[53,5],[55,5],[54,3],[54,6],[53,3],[54,3],[0,0],[0,0],[0,0],[0,0],[0,0],[55,5],[0,0],[0,0],[52,2],[55,2],[55,5],[53,2],[52,6],[53,2],[55,6],[55,4],[55,6],[52,6],[54,1],[53,1],[52,8],[53,3],[52,3],[0,0],[0,0],[52,2],[55,2],[54,8],[55,7],[53,2],[50,5],[55,8],[52,1],[53,3],[52,5],[53,3],[55,2],[54,2],[53,2],[54,1],[54,6],[55,5],[53,2],[54,4],[53,8],[53,2],[54,2],[54,1],[52,3],[55,1],[55,2],[52,3],[52,6],[0,0],[0,0],[0,0],[54,2],[54,2],[53,3],[55,2],[55,2],[55,2],[52,2],[55,1],[53,8],[54,7],[54,3],[55,1],[54,5],[53,2],[54,3],[53,7],[52,7],[0,0],[0,0],[55,5],[55,2],[53,6],[53,7],[55,8],[54,3],[55,5],[54,7],[54,2],[53,2],[55,7],[54,2],[55,2],[53,2],[54,2],[54,1],[52,2],[52,4],[54,1],[55,4],[55,7],[53,3],[55,8],[52,1],[55,2],[53,1],[53,3],[52,4],[54,3],[55,3],[52,7],[54,5],[53,2],[53,1],[55,4],[55,3],[52,4],[55,7],[55,2],[52,3],[54,2],[54,6],[52,6],[0,0],[0,0],[0,0],[53,1],[53,6],[55,1],[52,2],[55,4],[54,6],[52,7],[52,4],[54,8],[54,2],[54,1],[52,4],[55,8],[53,7],[53,7],[54,2],[55,1],[53,2],[55,6],[53,6],[53,4],[54,3],[55,5],[55,7],[54,2],[53,2],[53,5],[55,1],[55,1],[55,5],[55,1],[55,3],[55,4],[53,5],[52,2],[55,3],[52,3],[54,1],[54,2],[53,2],[54,5],[55,6],[55,2],[55,5],[54,3],[54,3],[53,2],[0,0],[0,0],[0,0],[55,6],[54,1],[52,4],[54,2],[55,2],[55,8],[52,5],[52,3],[52,8],[53,7],[53,3],[54,1],[54,2],[52,3],[52,1],[55,8],[53,2],[55,4],[55,6],[54,1],[54,3],[54,4],[52,1],[54,2],[55,6],[53,2],[53,3],[52,2],[54,2],[55,7],[54,1],[54,2],[53,6],[54,3],[53,5],[0,0],[0,0],[53,1],[54,1],[52,3],[52,1],[53,7],[53,1],[55,3],[54,3],[54,5],[54,7],[52,5],[55,1],[52,3],[55,7],[55,1],[0,0],[54,4],[52,1],[53,2],[53,2],[52,4],[54,1],[54,1],[54,6],[55,3],[52,3],[54,6],[53,3],[55,5],[53,7],[55,6],[54,4],[52,1],[55,4],[53,3],[55,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,6],[53,2],[52,2],[50,5],[53,1],[52,3],[54,2],[53,7],[50,5],[55,2],[53,6],[52,3],[54,4],[54,2],[55,2],[54,2],[54,6],[52,3],[0,0],[0,0],[0,0],[52,5],[54,7],[52,7],[52,7],[52,3],[54,8],[55,2],[55,2],[53,3],[54,3],[52,8],[53,2],[55,2],[55,2],[53,1],[52,2],[54,6],[54,1],[52,6],[53,3],[53,3],[53,3],[52,1],[53,7],[55,5],[52,3],[52,1],[52,2],[52,7],[54,1],[54,8],[55,1],[52,6],[53,1],[54,5],[53,8],[52,2],[52,1],[54,5],[53,2],[54,4],[54,5],[55,1],[0,0],[0,0],[52,2],[54,3],[53,2],[54,2],[55,1],[52,4],[52,2],[54,6],[54,4],[54,7],[54,2],[53,5],[54,2],[52,1],[54,5],[54,5],[54,5],[52,1],[52,7],[53,2],[54,2],[53,4],[52,2],[53,4],[54,6],[55,8],[53,1],[54,7],[54,1],[52,2],[53,4],[55,7],[55,5],[55,3],[52,3],[54,4],[55,4],[53,2],[55,8],[55,5],[55,5],[53,8],[54,7],[53,1],[54,2],[54,4],[54,1],[0,0],[0,0],[0,0],[53,4],[53,2],[52,2],[52,8],[52,8],[55,4],[53,1],[53,1],[52,6],[54,8],[54,7],[54,2],[54,3],[55,6],[55,7],[53,6],[55,7],[52,7],[52,6],[54,5],[54,6],[53,7],[53,4],[53,1],[52,3],[55,3],[54,2],[52,8],[52,2],[53,5],[53,5],[52,7],[52,2],[54,4],[50,5],[52,5],[52,6],[0,0],[0,0],[0,0],[55,6],[52,1],[54,7],[55,2],[53,1],[52,2],[54,2],[55,4],[52,2],[52,2],[53,8],[55,1],[52,3],[55,4],[0,0],[0,0],[54,2],[55,4],[52,1],[54,2],[54,3],[53,1],[53,4],[54,1],[54,2],[53,6],[55,2],[55,7],[53,4],[52,5],[0,0],[0,0],[0,0],[0,0],[0,0],[53,1],[55,6],[52,2],[50,5],[53,1],[52,2],[53,5],[54,8],[53,7],[53,4],[53,6],[53,2],[55,5],[54,1],[53,1],[55,1],[54,3],[53,1],[54,2],[52,5],[55,2],[54,6],[54,2],[54,4],[54,2],[54,7],[53,4],[53,3],[52,1],[0,0],[52,8],[54,2],[53,7],[53,6],[53,7],[53,5],[52,5],[54,4],[55,3],[53,3],[52,2],[53,5],[55,3],[50,5],[53,4],[54,2],[54,5],[52,2],[52,1],[55,1],[52,8],[52,7],[54,2],[55,1],[55,2],[52,5],[52,2],[52,3],[52,3],[55,3],[53,1],[52,2],[55,4],[55,1],[52,2],[55,2],[53,3],[52,2],[55,7],[55,4],[55,5],[54,5],[52,2],[52,4],[0,0],[0,0],[53,2],[55,3],[54,1],[52,1],[54,6],[52,2],[55,1],[52,7],[54,2],[54,7],[54,2],[52,1],[55,6],[54,1],[55,3],[54,5],[53,2],[55,1],[53,2],[54,1],[55,2],[52,3],[55,4],[55,3],[52,3],[53,4],[52,3],[54,2],[52,2],[54,2],[53,1],[55,7],[54,3],[55,1],[55,1],[55,1],[54,8],[53,3],[52,2],[53,5],[52,4],[53,2],[54,7],[52,6],[52,6],[52,1],[0,0],[0,0],[0,0],[55,3],[55,6],[55,4],[55,1],[52,3],[55,5],[55,3],[54,1],[52,1],[55,2],[54,3],[53,4],[54,3],[53,1],[53,4],[54,1],[53,2],[53,6],[52,7],[55,2],[53,4],[52,8],[55,2],[55,3],[54,3],[54,4],[52,3],[55,1],[53,8],[55,5],[55,2],[52,2],[55,6],[53,8],[55,6],[55,2],[53,1],[0,0],[0,0],[0,0],[0,0],[0,0],[54,2],[53,6],[53,6],[55,2],[55,3],[55,6],[55,4],[53,2],[54,3],[55,1],[0,0],[0,0],[0,0],[0,0],[52,1],[54,2],[52,1],[55,5],[52,1],[54,5],[54,3],[52,5],[54,2],[52,2],[52,1],[54,2],[54,2],[53,1],[0,0],[0,0],[0,0],[54,2],[54,5],[53,7],[55,2],[53,8],[53,2],[53,2],[52,4],[53,1],[53,5],[52,3],[52,6],[55,7],[54,3],[54,1],[53,6],[53,4],[53,1],[54,6],[53,4],[54,5],[52,2],[53,2],[55,8],[53,1],[53,6],[55,1],[52,2],[54,7],[55,1],[0,0],[0,0],[53,2],[53,5],[54,5],[54,8],[53,3],[55,2],[52,5],[53,7],[53,2],[53,5],[53,7],[53,5],[54,5],[55,2],[54,3],[53,2],[55,2],[52,2],[54,7],[53,4],[52,1],[55,1],[55,5],[53,3],[55,2],[53,4],[52,2],[54,3],[55,4],[54,3],[54,7],[52,1],[52,3],[54,1],[55,4],[53,3],[55,2],[55,2],[54,1],[54,2],[55,2],[55,1],[55,2],[52,6],[0,0],[0,0],[52,3],[52,1],[55,1],[52,4],[54,6],[52,8],[52,2],[54,6],[54,3],[54,7],[52,5],[55,3],[53,4],[52,2],[55,7],[52,1],[55,2],[54,5],[52,2],[54,7],[54,1],[54,2],[55,3],[53,3],[55,7],[52,2],[55,2],[55,4],[53,1],[54,2],[52,3],[52,1],[52,2],[54,2],[53,4],[52,4],[53,3],[55,5],[55,5],[55,6],[54,2],[54,1],[53,3],[53,3],[54,5],[53,2],[54,4],[54,3],[53,8],[53,4],[53,4],[53,1],[53,3],[53,3],[53,3],[52,7],[52,4],[55,2],[55,4],[53,4],[53,1],[55,3],[54,3],[52,2],[55,3],[53,3],[54,3],[53,4],[54,6],[53,5],[53,4],[52,8],[53,4],[52,2],[53,2],[52,5],[53,2],[54,2],[54,8],[52,1],[52,5],[54,2],[53,1],[50,5],[52,1],[52,2],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[53,5],[53,1],[54,5],[54,7],[53,2],[53,7],[54,2],[53,1],[52,3],[55,2],[54,4],[0,0],[52,1],[54,4],[55,2],[53,2],[52,5],[52,6],[55,1],[53,7],[52,6],[52,3],[54,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[54,5],[55,7],[52,4],[54,1],[52,6],[54,3],[52,6],[53,2],[54,1],[55,8],[52,6],[52,5],[52,4],[53,4],[52,1],[54,3],[55,4],[54,2],[54,7],[53,3],[54,1],[52,3],[52,6],[53,3],[52,6],[52,6],[53,4],[55,7],[53,7],[53,7],[0,0],[0,0],[53,7],[53,7],[52,4],[54,6],[55,8],[52,6],[54,2],[52,1],[55,5],[54,1],[54,1],[54,7],[55,1],[54,2],[54,1],[52,3],[54,2],[54,7],[54,2],[52,6],[53,6],[52,2],[52,3],[53,7],[54,1],[55,2],[53,4],[53,4],[53,3],[54,1],[52,8],[55,3],[53,2],[53,4],[53,4],[52,2],[52,1],[55,2],[54,7],[54,1],[52,1],[53,1],[52,2],[54,3],[55,4],[0,0],[0,0],[52,8],[53,2],[54,8],[54,4],[53,7],[53,1],[52,2],[53,5],[53,3],[54,7],[52,2],[55,5],[53,5],[52,2],[52,7],[55,5],[53,2],[53,2],[52,6],[55,2],[55,3],[53,2],[53,4],[55,6],[54,7],[54,5],[53,1],[52,1],[54,4],[54,4],[55,5],[52,6],[55,4],[54,1],[52,2],[55,5],[53,1],[52,2],[53,1],[55,7],[53,2],[52,5],[55,3],[52,1],[54,3],[52,3],[54,5],[54,1],[54,2],[53,8],[52,1],[52,2],[53,1],[54,5],[54,5],[53,1],[53,2],[55,4],[52,2],[52,1],[50,5],[55,2],[52,3],[52,7],[53,1],[54,1],[52,4],[54,7],[53,4],[52,5],[52,5],[55,5],[54,2],[52,7],[54,5],[54,1],[52,2],[52,1],[54,3],[55,7],[53,3],[54,3],[53,1],[55,7],[55,6],[52,3],[54,2],[52,2],[53,4],[52,3],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[52,2],[0,0],[0,0],[52,6],[53,5],[54,2],[55,1],[53,3],[53,5],[53,4],[55,8],[52,4],[53,3],[55,2],[0,0],[0,0],[54,2],[55,3],[52,2],[52,8],[52,6],[53,1],[52,8],[55,1],[54,3],[53,4],[55,6],[53,3],[53,1],[53,5],[53,4],[55,5],[53,7],[52,1],[54,2],[54,7],[55,4],[53,1],[55,8],[54,6],[55,1],[51,2],[53,6],[52,1],[54,1],[53,3],[53,7],[55,2],[52,8],[52,2],[55,7],[52,7],[53,7],[53,1],[53,3],[52,6],[53,7],[53,2],[53,3],[54,3],[52,3],[55,5],[54,8],[53,6],[52,1],[55,2],[55,3],[55,4],[54,1],[52,2],[52,7],[52,1],[53,2],[55,7],[53,6],[55,2],[54,2],[52,1],[54,6],[55,2],[53,8],[53,2],[55,7],[53,1],[54,2],[54,5],[52,1],[53,8],[55,5],[55,1],[52,5],[54,5],[52,5],[54,7],[54,8],[55,2],[54,3],[0,0],[0,0],[54,7],[54,7],[53,3],[52,3],[52,1],[53,2],[52,6],[52,5],[52,5],[53,6],[53,7],[55,6],[55,1],[52,6],[54,5],[54,5],[55,6],[52,4],[54,6],[52,2],[54,3],[52,6],[54,4],[54,5],[54,2],[54,2],[54,2],[54,4],[50,5],[55,5],[52,1],[54,3],[55,8],[53,3],[52,5],[55,1],[55,4],[52,4],[55,5],[50,5],[52,2],[52,1],[53,6],[52,5],[53,2],[54,4],[53,8],[55,2],[55,8],[54,4],[52,1],[53,3],[54,6],[52,1],[52,3],[54,7],[53,4],[53,1],[53,6],[55,6],[55,6],[52,7],[53,3],[53,1],[55,4],[53,1],[54,2],[53,5],[54,6],[55,8],[52,1],[55,2],[54,2],[54,8],[54,6],[55,7],[54,6],[54,1],[52,2],[53,1],[54,3],[50,5],[54,6],[52,3],[52,2],[53,1],[53,1],[53,4],[52,2],[52,3],[54,5],[53,1],[0,0],[0,0],[55,5],[54,6],[53,3],[54,2],[53,3],[55,6],[54,7],[0,0],[0,0],[0,0],[0,0],[54,3],[53,2],[55,4],[55,4],[53,6],[53,1],[53,2],[54,2],[53,7],[52,1],[53,1],[52,7],[54,1],[52,4],[54,1],[52,5],[54,7],[54,1],[52,3],[55,1],[53,8],[52,1],[53,2],[54,1],[52,2],[53,5],[53,4],[55,7],[53,2],[53,1],[52,5],[53,2],[52,1],[52,2],[54,1],[55,5],[53,3],[55,3],[53,6],[53,5],[55,4],[54,2],[52,2],[52,7],[55,1],[53,4],[0,0],[0,0],[54,4],[54,2],[55,2],[55,2],[54,3],[54,5],[53,5],[55,3],[54,6],[55,5],[53,3],[52,7],[53,1],[51,4],[52,3],[55,3],[55,8],[52,1],[55,4],[55,6],[53,7],[53,2],[53,2],[55,7],[54,8],[55,3],[0,0],[0,0],[55,2],[53,1],[55,7],[52,2],[55,2],[52,2],[53,6],[53,3],[53,1],[55,8],[55,2],[55,1],[54,3],[53,5],[54,3],[54,2],[53,5],[52,3],[52,1],[53,4],[53,5],[54,5],[53,1],[52,2],[55,2],[53,2],[54,3],[54,2],[53,2],[55,6],[55,1],[54,3],[53,3],[53,6],[53,1],[52,6],[53,4],[52,2],[52,4],[52,2],[52,1],[53,2],[55,1],[50,5],[54,2],[54,7],[53,5],[54,6],[55,7],[55,2],[53,4],[55,6],[55,3],[53,6],[55,2],[52,1],[52,1],[53,2],[53,8],[55,7],[52,7],[54,7],[54,2],[52,1],[50,5],[52,3],[54,4],[53,7],[53,2],[54,1],[53,1],[53,3],[52,2],[55,1],[55,2],[52,5],[52,1],[52,1],[52,6],[52,3],[54,2],[55,1],[54,1],[52,1],[52,3],[53,2],[52,2],[53,1],[55,1],[53,5],[54,2],[55,1],[54,1],[52,2],[54,1],[54,1],[55,4],[55,3],[54,6],[53,1],[53,1],[53,3],[55,3],[52,2],[54,8],[55,2],[55,3],[53,2],[55,2],[55,1],[55,6],[52,6],[55,1],[54,2],[54,3],[54,3],[52,7],[55,1],[55,3],[53,3],[53,1],[54,2],[55,7],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[55,3],[53,4],[55,5],[53,5],[53,7],[54,1],[50,5],[54,3],[53,1],[52,4],[52,3],[52,2],[53,1],[54,5],[55,6],[53,3],[55,7],[55,3],[52,2],[54,2],[52,3],[55,2],[54,2],[52,6],[55,6],[55,3],[53,2],[53,3],[55,1],[53,3],[54,3],[53,2],[55,3],[54,3],[54,5],[0,0],[0,0],[52,6],[54,1],[53,4],[55,1],[52,2],[54,3],[54,1],[52,1],[54,5],[52,7],[52,7],[53,6],[55,1],[55,7],[54,3],[54,2],[55,7],[52,1],[55,4],[53,7],[53,1],[53,2],[52,2],[55,6],[53,2],[50,5],[0,0],[0,0],[54,7],[53,3],[53,6],[54,2],[53,1],[55,4],[53,2],[52,6],[52,3],[52,7],[52,3],[55,6],[54,6],[55,7],[54,6],[52,4],[55,2],[55,1],[53,2],[52,3],[0,0],[0,0],[52,2],[54,4],[52,7],[55,6],[55,5],[52,3],[0,0],[0,0],[52,5],[52,8],[53,1],[55,8],[55,3],[55,6],[55,3],[53,7],[52,5],[53,1],[55,2],[53,1],[55,7],[52,3],[54,2],[55,1],[52,1],[54,1],[55,3],[55,4],[54,7],[55,3],[52,2],[53,1],[54,4],[54,5],[53,3],[55,5],[53,1],[53,1],[54,3],[54,2],[53,1],[55,8],[52,2],[55,3],[55,2],[54,3],[52,2],[52,1],[54,2],[53,4],[55,5],[54,4],[54,5],[52,3],[54,3],[55,5],[54,4],[54,6],[55,2],[50,5],[52,2],[54,2],[54,7],[54,1],[55,6],[54,7],[53,3],[53,1],[54,5],[53,6],[53,4],[52,6],[55,6],[53,3],[53,1],[53,7],[53,4],[54,2],[55,1],[55,2],[55,4],[53,2],[55,1],[54,3],[55,5],[55,5],[55,8],[55,3],[54,1],[55,4],[53,2],[52,3],[53,3],[52,1],[53,1],[54,4],[54,5],[52,8],[53,1],[52,2],[54,6],[0,0],[0,0],[0,0],[54,6],[55,1],[53,6],[55,5],[52,4],[55,6],[54,8],[55,3],[0,0],[54,6],[52,7],[53,1],[53,3],[50,5],[53,7],[55,1],[52,2],[54,8],[54,3],[54,7],[54,3],[55,3],[52,6],[54,3],[52,4],[53,3],[52,3],[52,6],[54,1],[52,3],[54,3],[53,6],[54,3],[53,7],[55,2],[54,7],[52,3],[55,5],[53,1],[52,3],[55,7],[55,7],[52,2],[54,2],[53,4],[0,0],[0,0],[52,7],[53,1],[52,2],[52,1],[55,6],[53,8],[55,7],[55,5],[54,3],[54,3],[52,3],[55,2],[54,7],[53,1],[52,3],[54,3],[52,5],[54,3],[54,5],[52,2],[54,3],[54,5],[55,5],[54,1],[54,3],[0,0],[52,6],[55,5],[52,2],[52,4],[54,4],[53,1],[53,5],[52,1],[54,6],[54,8],[53,1],[54,2],[54,3],[54,1],[53,1],[55,2],[54,4],[52,2],[55,2],[54,2],[52,2],[0,0],[0,0],[52,1],[54,7],[55,1],[52,1],[53,2],[55,4],[0,0],[0,0],[53,6],[52,6],[52,5],[54,2],[52,3],[54,6],[54,6],[53,2],[55,1],[54,3],[54,7],[54,8],[53,2],[52,2],[54,1],[52,1],[55,6],[54,1],[55,3],[55,3],[54,1],[54,5],[54,6],[53,1],[53,1],[54,1],[53,3],[55,1],[52,5],[52,3],[53,6],[52,6],[55,6],[53,4],[55,3],[53,2],[54,2],[54,6],[52,1],[52,1],[55,1],[53,2],[54,5],[54,6],[52,1],[53,2],[54,4],[55,1],[52,6],[54,4],[55,3],[55,2],[53,2],[54,1],[54,6],[54,2],[52,5],[55,4],[54,1],[53,1],[55,1],[52,2],[54,1],[55,4],[55,1],[54,1],[52,2],[55,2],[52,3],[52,6],[54,2],[54,3],[54,6],[52,3],[53,3],[53,6],[55,2],[53,2],[53,5],[55,6],[55,1],[54,5],[55,6],[53,1],[54,1],[55,4],[52,5],[53,2],[52,1],[54,6],[53,4],[52,2],[53,5],[0,0],[0,0],[0,0],[53,7],[53,7],[54,2],[53,5],[54,4],[54,7],[53,3],[54,8],[0,0],[55,1],[52,2],[55,7],[53,1],[52,4],[55,8],[52,3],[55,8],[54,2],[53,4],[54,1],[53,2],[53,6],[55,3],[53,2],[52,6],[54,2],[53,1],[52,7],[52,3],[52,3],[55,5],[54,2],[53,3],[52,4],[52,3],[53,2],[54,8],[52,6],[54,3],[53,2],[54,8],[52,1],[52,1],[55,2],[55,3],[54,1],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[55,1],[52,5],[53,4],[52,5],[52,2],[52,7],[53,2],[55,2],[52,5],[52,3],[54,1],[55,2],[53,1],[52,6],[55,6],[52,8],[53,7],[53,3],[55,5],[53,5],[53,2],[52,2],[0,0],[0,0],[55,1],[55,1],[54,2],[52,6],[55,4],[52,3],[54,4],[55,5],[55,5],[54,4],[52,6],[54,6],[55,3],[53,1],[53,1],[54,2],[53,4],[52,6],[53,1],[0,0],[0,0],[53,2],[55,5],[52,2],[53,2],[55,5],[0,0],[52,8],[53,2],[52,2],[54,3],[53,3],[52,2],[52,6],[54,7],[54,2],[53,6],[54,4],[54,6],[55,6],[55,1],[54,6],[52,7],[52,3],[53,6],[52,4],[54,7],[0,0],[0,0],[54,3],[53,5],[55,8],[52,3],[54,2],[52,1],[52,4],[52,5],[52,4],[55,3],[54,2],[54,2],[54,1],[54,8],[54,6],[52,5],[54,1],[55,4],[54,6],[54,6],[52,1],[53,6],[52,8],[52,3],[52,4],[53,4],[53,1],[55,5],[55,5],[52,4],[52,1],[54,6],[54,4],[55,3],[53,4],[52,6],[53,1],[54,5],[55,1],[55,5],[53,8],[52,7],[55,3],[53,1],[54,2],[50,5],[53,2],[53,7],[52,5],[54,1],[54,1],[53,4],[53,4],[53,8],[53,2],[54,2],[53,4],[54,6],[54,3],[55,3],[55,5],[52,2],[52,5],[52,6],[53,8],[54,4],[54,7],[55,3],[55,2],[55,4],[54,7],[55,5],[53,1],[53,1],[55,2],[54,2],[55,7],[53,6],[52,6],[54,6],[53,8],[54,1],[54,3],[0,0],[0,0],[0,0],[52,2],[53,6],[53,8],[53,3],[55,3],[53,2],[53,8],[53,2],[54,2],[53,7],[52,4],[54,6],[53,2],[53,3],[54,7],[52,6],[54,2],[53,5],[55,4],[53,1],[54,6],[54,2],[54,1],[54,4],[54,3],[52,1],[53,1],[55,3],[52,5],[53,1],[53,1],[52,2],[54,3],[52,1],[53,4],[52,5],[50,5],[53,8],[53,2],[55,2],[0,0],[0,0],[0,0],[53,2],[52,5],[55,1],[54,1],[54,2],[53,2],[55,1],[54,3],[52,5],[55,1],[54,1],[55,4],[54,6],[52,7],[54,1],[55,6],[52,3],[54,2],[0,0],[54,4],[0,0],[0,0],[55,2],[53,5],[54,7],[52,1],[55,5],[55,1],[53,2],[55,5],[52,1],[54,1],[52,3],[55,2],[52,5],[53,1],[54,4],[52,2],[54,3],[50,5],[52,1],[0,0],[0,0],[52,3],[53,2],[54,6],[54,2],[54,1],[55,2],[55,6],[0,0],[0,0],[53,6],[53,1],[53,4],[52,1],[54,3],[54,6],[53,3],[54,3],[55,3],[53,6],[55,2],[53,6],[55,7],[55,3],[54,3],[53,1],[53,5],[0,0],[0,0],[52,2],[52,3],[55,5],[53,1],[53,6],[53,1],[55,4],[54,5],[54,2],[53,8],[55,1],[54,2],[55,8],[55,5],[55,3],[53,7],[54,1],[52,2],[52,8],[53,3],[52,5],[55,7],[55,5],[54,3],[55,7],[53,5],[53,2],[55,3],[53,2],[52,7],[53,8],[55,2],[55,3],[53,6],[53,2],[53,8],[54,7],[52,7],[52,2],[55,4],[52,7],[54,3],[54,7],[54,1],[53,1],[55,6],[53,4],[54,7],[54,3],[55,4],[55,1],[55,2],[55,2],[54,7],[55,1],[53,3],[54,7],[55,2],[54,2],[55,3],[54,2],[54,2],[53,4],[55,1],[52,5],[52,1],[52,3],[55,3],[54,1],[53,7],[54,2],[52,1],[53,2],[55,2],[54,4],[52,3],[55,5],[53,3],[52,5],[52,2],[53,2],[54,5],[53,1],[55,3],[53,3],[0,0],[0,0],[52,8],[53,4],[52,3],[52,2],[54,2],[52,1],[55,4],[53,1],[52,3],[52,1],[55,3],[53,2],[55,7],[54,3],[55,4],[53,5],[54,3],[52,1],[53,8],[0,0],[0,0],[55,3],[54,2],[55,1],[55,6],[52,2],[55,4],[54,4],[54,2],[52,1],[55,1],[53,3],[53,1],[54,8],[55,7],[52,2],[55,3],[54,1],[52,1],[53,6],[50,5],[0,0],[54,7],[52,7],[53,5],[54,7],[53,3],[55,7],[55,5],[55,1],[53,4],[55,2],[52,2],[54,1],[52,4],[54,5],[53,1],[55,3],[53,2],[55,7],[54,3],[54,5],[55,1],[52,2],[52,2],[55,7],[50,5],[55,3],[55,2],[53,2],[54,8],[55,1],[55,4],[54,2],[53,2],[54,5],[54,7],[52,2],[54,1],[54,3],[54,1],[55,8],[52,5],[55,7],[0,0],[0,0],[55,1],[54,1],[54,8],[55,2],[0,0],[52,1],[0,0],[0,0],[55,1],[55,4],[54,3],[55,1],[52,8],[54,3],[52,4],[54,8],[53,2],[53,2],[55,7],[52,2],[53,8],[54,3],[53,1],[55,4],[0,0],[0,0],[53,4],[54,1],[0,0],[0,0],[53,1],[55,3],[54,3],[52,4],[55,2],[53,2],[52,3],[54,1],[53,1],[55,2],[54,6],[52,6],[55,5],[52,7],[55,2],[50,5],[53,6],[55,1],[55,5],[54,6],[52,6],[52,3],[54,5],[55,3],[52,1],[53,2],[52,2],[52,6],[53,4],[55,2],[55,6],[53,2],[53,3],[53,5],[52,8],[54,7],[55,5],[54,2],[53,5],[52,3],[52,2],[55,2],[54,6],[53,7],[53,1],[54,5],[52,6],[54,5],[54,2],[55,1],[54,4],[52,6],[52,5],[52,4],[55,1],[54,3],[52,7],[53,7],[50,5],[54,3],[55,4],[52,1],[54,5],[52,3],[54,2],[53,4],[55,5],[54,1],[54,7],[55,7],[52,8],[54,3],[54,2],[55,5],[53,2],[55,2],[54,2],[55,3],[55,2],[55,7],[53,3],[53,4],[53,3],[0,0],[53,4],[54,4],[52,4],[55,3],[54,2],[52,2],[53,8],[54,3],[52,5],[54,1],[53,1],[53,3],[55,1],[52,2],[54,2],[55,6],[52,2],[52,1],[55,8],[0,0],[0,0],[55,3],[55,5],[53,2],[54,5],[50,5],[55,1],[52,6],[52,3],[52,1],[53,6],[55,8],[54,3],[54,3],[54,6],[53,4],[52,7],[52,4],[52,2],[0,0],[0,0],[0,0],[52,4],[52,2],[54,4],[52,2],[52,8],[52,5],[52,1],[53,6],[55,5],[53,1],[54,5],[53,1],[54,7],[52,6],[54,2],[52,7],[52,7],[53,3],[53,4],[53,6],[0,0],[0,0],[55,7],[55,3],[52,1],[52,5],[54,7],[54,2],[54,2],[53,6],[55,8],[52,7],[52,2],[54,2],[52,2],[54,3],[52,3],[52,2],[52,2],[54,1],[53,7],[53,5],[0,0],[0,0],[53,2],[53,4],[54,4],[52,1],[52,7],[55,6],[52,4],[53,4],[52,1],[54,5],[53,2],[54,5],[52,4],[54,1],[52,4],[53,3],[53,1],[54,8],[55,2],[53,7],[54,1],[55,4],[55,7],[52,2],[50,5],[53,2],[53,6],[55,6],[0,0],[0,0],[55,6],[52,2],[53,7],[52,2],[55,1],[55,6],[55,8],[55,3],[55,5],[52,5],[53,7],[55,4],[55,2],[52,1],[53,4],[53,6],[55,2],[53,6],[53,4],[53,7],[54,1],[52,2],[53,8],[52,3],[53,2],[53,3],[53,3],[55,2],[55,7],[55,4],[53,2],[54,1],[52,3],[54,1],[52,2],[55,2],[53,6],[53,4],[53,4],[54,1],[54,3],[55,1],[52,2],[54,5],[53,6],[55,3],[54,8],[54,1],[53,3],[55,5],[52,3],[53,6],[54,2],[52,7],[53,6],[53,5],[55,1],[53,8],[54,2],[55,1],[54,5],[54,1],[53,3],[55,8],[55,7],[52,3],[52,2],[54,2],[55,6],[52,1],[55,5],[53,8],[55,4],[53,6],[53,1],[53,3],[54,3],[55,2],[55,1],[54,1],[54,3],[55,2],[53,4],[54,1],[0,0],[0,0],[55,6],[54,5],[55,3],[54,7],[54,3],[52,1],[54,1],[52,1],[55,5],[52,2],[52,1],[54,1],[55,3],[55,5],[55,6],[52,6],[0,0],[0,0],[55,1],[55,1],[0,0],[0,0],[55,3],[53,3],[54,6],[52,1],[52,3],[55,3],[55,5],[52,4],[54,1],[52,6],[52,5],[54,7],[53,4],[54,1],[55,4],[0,0],[0,0],[0,0],[54,2],[54,3],[54,3],[55,2],[52,1],[52,1],[52,1],[55,1],[54,5],[55,3],[53,2],[53,5],[55,2],[53,3],[54,2],[53,3],[53,1],[54,7],[55,5],[55,7],[0,0],[0,0],[52,3],[55,2],[52,2],[52,5],[54,2],[53,3],[53,2],[54,8],[54,4],[52,4],[54,5],[55,2],[52,1],[55,1],[52,6],[52,2],[53,1],[52,2],[52,2],[54,2],[54,2],[0,0],[0,0],[54,3],[54,1],[52,4],[54,2],[54,4],[0,0],[0,0],[54,1],[55,3],[53,2],[54,7],[55,7],[52,5],[52,5],[53,2],[55,2],[52,6],[52,2],[55,1],[54,5],[54,6],[54,2],[52,2],[53,2],[55,6],[52,6],[54,1],[52,6],[54,4],[52,3],[55,6],[54,4],[53,2],[53,2],[54,3],[52,6],[54,1],[52,8],[54,3],[52,3],[54,1],[52,1],[55,5],[54,3],[55,5],[53,6],[54,2],[52,7],[52,2],[55,1],[53,3],[53,2],[52,3],[53,1],[52,7],[52,1],[52,1],[52,4],[55,1],[55,3],[52,2],[54,8],[52,4],[52,1],[53,6],[53,1],[54,1],[52,2],[54,5],[54,3],[52,3],[53,2],[55,1],[55,3],[55,1],[50,5],[55,1],[54,2],[53,4],[55,3],[55,1],[55,1],[52,3],[52,3],[52,4],[55,3],[53,6],[52,6],[53,6],[55,7],[53,5],[54,2],[55,4],[54,5],[53,2],[52,3],[52,6],[55,4],[54,2],[53,1],[54,2],[55,1],[52,1],[52,5],[54,2],[52,7],[53,2],[52,1],[52,1],[55,6],[53,1],[52,1],[55,2],[0,0],[0,0],[52,2],[54,1],[54,1],[53,2],[55,3],[55,2],[54,2],[53,7],[53,5],[53,7],[55,1],[52,2],[55,8],[54,1],[53,2],[53,2],[53,3],[53,6],[53,5],[53,6],[0,0],[0,0],[50,5],[52,7],[53,6],[54,2],[53,2],[52,4],[53,1],[55,3],[53,2],[53,2],[55,1],[52,4],[55,2],[53,3],[0,0],[0,0],[0,0],[0,0],[52,5],[54,6],[55,8],[53,2],[52,6],[53,1],[55,5],[54,3],[53,2],[53,7],[55,5],[54,1],[55,1],[54,1],[55,5],[52,8],[55,1],[53,4],[52,2],[52,5],[54,1],[55,6],[0,0],[0,0],[0,0],[52,1],[55,5],[52,8],[54,2],[52,2],[53,5],[55,4],[54,3],[55,2],[54,2],[52,8],[55,3],[55,4],[52,1],[52,4],[53,7],[55,8],[54,2],[0,0],[0,0],[53,3],[55,1],[55,1],[53,8],[54,6],[0,0],[0,0],[54,3],[55,1],[53,3],[53,1],[55,1],[55,1],[55,4],[53,1],[53,7],[55,2],[55,2],[52,4],[54,5],[53,1],[52,1],[54,5],[54,2],[52,2],[54,3],[55,2],[53,2],[55,5],[54,2],[53,6],[52,3],[54,2],[53,2],[55,5],[53,5],[55,6],[55,1],[54,1],[55,1],[54,3],[54,2],[55,5],[52,2],[52,8],[53,3],[52,2],[53,3],[53,6],[54,7],[53,4],[52,3],[53,6],[52,7],[53,1],[52,1],[52,5],[52,3],[52,1],[53,3],[53,1],[55,5],[52,6],[53,1],[53,7],[53,1],[54,2],[53,8],[55,1],[55,8],[54,6],[52,1],[53,6],[54,6],[53,8],[54,1],[52,7],[55,1],[53,4],[54,1],[55,6],[55,1],[54,1],[55,2],[54,4],[52,4],[55,2],[52,2],[52,1],[52,4],[55,4],[53,2],[54,1],[55,5],[53,1],[54,1],[53,1],[53,4],[53,3],[54,1],[54,4],[54,5],[54,2],[52,1],[54,3],[55,4],[52,3],[55,2],[55,1],[55,1],[54,5],[53,7],[53,3],[0,0],[52,4],[54,1],[55,5],[53,3],[53,6],[54,2],[52,2],[54,1],[53,3],[55,1],[54,3],[53,2],[53,1],[50,5],[54,3],[52,5],[55,4],[53,3],[54,2],[54,4],[53,1],[53,2],[52,3],[55,8],[55,2],[53,1],[53,1],[55,2],[53,1],[53,8],[55,3],[53,2],[55,2],[52,4],[54,2],[54,3],[55,3],[0,0],[0,0],[52,3],[54,5],[55,1],[55,2],[55,3],[55,7],[54,5],[52,3],[53,5],[55,3],[53,2],[52,1],[54,2],[54,8],[54,4],[52,2],[54,2],[53,5],[53,8],[54,3],[53,1],[53,1],[52,1],[55,1],[0,0],[0,0],[0,0],[54,5],[55,2],[53,6],[53,6],[53,1],[53,3],[54,4],[50,5],[55,4],[52,3],[53,6],[53,5],[50,5],[52,5],[52,7],[55,1],[55,2],[52,2],[55,3],[0,0],[0,0],[54,7],[54,7],[53,7],[53,1],[55,2],[53,1],[0,0],[0,0],[0,0],[52,6],[53,2],[52,3],[54,2],[52,1],[53,5],[52,1],[50,5],[53,3],[55,1],[55,1],[55,5],[52,2],[53,7],[55,3],[54,4],[52,6],[54,3],[55,3],[52,1],[52,2],[55,7],[55,8],[54,2],[54,1],[55,4],[52,6],[52,4],[52,3],[52,5],[55,5],[52,8],[55,6],[54,3],[53,1],[55,2],[55,2],[53,5],[52,7],[52,2],[53,3],[53,3],[55,7],[53,7],[54,3],[55,8],[53,3],[53,2],[55,2],[55,3],[52,7],[52,5],[55,8],[54,6],[54,5],[55,3],[52,2],[53,4],[53,4],[54,1],[55,8],[55,2],[55,3],[55,4],[55,3],[53,5],[54,1],[53,2],[52,8],[53,4],[52,2],[55,3],[52,5],[53,1],[54,3],[55,2],[53,8],[54,7],[54,2],[53,3],[52,2],[52,4],[52,1],[55,2],[55,3],[52,5],[54,1],[54,3],[52,2],[54,2],[53,7],[52,2],[54,2],[54,8],[52,7],[55,5],[52,4],[52,6],[53,2],[54,3],[54,3],[54,1],[52,6],[52,4],[0,0],[0,0],[50,5],[52,1],[54,1],[53,3],[52,2],[50,5],[55,7],[52,6],[55,1],[52,2],[55,2],[54,1],[52,4],[55,8],[54,5],[54,4],[54,7],[52,3],[54,4],[54,7],[54,7],[55,4],[54,2],[53,7],[54,6],[52,2],[53,1],[55,1],[52,7],[54,2],[53,4],[54,3],[54,3],[54,2],[54,3],[0,0],[0,0],[54,4],[55,2],[54,5],[52,5],[52,5],[54,1],[55,1],[52,3],[55,2],[52,2],[54,1],[54,2],[55,1],[52,5],[55,6],[55,2],[53,1],[55,6],[55,2],[54,2],[54,4],[52,2],[54,5],[52,8],[0,0],[0,0],[0,0],[55,4],[55,5],[54,2],[52,2],[53,7],[52,5],[52,1],[52,7],[54,1],[55,2],[55,5],[55,4],[54,2],[53,6],[55,1],[54,4],[53,2],[55,7],[52,1],[0,0],[0,0],[52,7],[53,4],[53,1],[53,1],[53,6],[55,1],[0,0],[0,0],[0,0],[52,1],[53,2],[53,2],[55,1],[55,6],[52,2],[53,4],[55,2],[53,3],[52,6],[54,4],[53,5],[54,3],[53,1],[52,5],[54,6],[53,2],[52,8],[55,2],[54,1],[52,1],[54,4],[55,2],[55,2],[54,1],[53,8],[53,1],[53,6],[55,3],[53,7],[53,4],[52,2],[54,4],[53,5],[55,3],[55,2],[53,5],[55,1],[55,1],[55,1],[54,3],[55,7],[55,6],[55,2],[53,3],[55,1],[54,1],[52,3],[52,7],[54,2],[53,3],[54,1],[52,2],[52,7],[55,4],[54,3],[55,1],[54,3],[54,2],[54,3],[53,2],[52,4],[55,8],[54,2],[53,2],[53,2],[54,2],[55,2],[53,4],[52,4],[55,1],[53,5],[55,5],[52,1],[53,1],[52,3],[54,1],[55,1],[52,5],[55,3],[53,1],[52,4],[55,2],[54,1],[54,2],[52,2],[52,3],[55,2],[52,2],[55,3],[55,2],[55,5],[54,2],[54,6],[55,4],[55,2],[55,7],[54,8],[55,2],[54,3],[55,8],[52,7],[52,1],[55,4],[0,0],[0,0],[50,5],[52,1],[55,3],[54,2],[53,6],[54,2],[52,2],[52,3],[53,7],[53,2],[54,7],[52,3],[52,3],[55,3],[52,5],[55,2],[55,3],[54,8],[52,1],[53,8],[55,1],[52,3],[54,2],[52,2],[52,5],[54,2],[52,5],[54,1],[55,5],[55,1],[52,4],[55,5],[52,1],[52,7],[54,1],[0,0],[0,0],[55,6],[54,1],[53,4],[54,1],[53,1],[53,3],[54,5],[53,2],[52,2],[54,1],[55,5],[53,2],[55,1],[55,1],[52,5],[55,3],[52,2],[55,6],[55,7],[55,2],[54,3],[55,2],[53,3],[52,5],[53,5],[53,7],[55,5],[54,2],[53,4],[55,1],[54,2],[52,1],[52,4],[54,3],[55,6],[53,2],[53,2],[52,2],[54,5],[55,2],[52,5],[52,1],[55,5],[55,3],[54,2],[54,7],[53,2],[0,0],[0,0],[53,8],[54,1],[51,6],[53,2],[54,5],[0,0],[0,0],[0,0],[52,7],[53,1],[55,3],[54,5],[54,5],[53,7],[54,1],[52,8],[53,1],[53,3],[52,1],[50,5],[54,2],[54,1],[52,5],[52,1],[53,6],[55,1],[53,2],[53,2],[52,1],[52,7],[53,7],[52,6],[53,3],[55,7],[54,4],[55,5],[53,6],[52,7],[53,6],[54,1],[54,6],[55,6],[52,3],[55,2],[53,3],[53,8],[52,8],[53,4],[53,2],[53,1],[53,5],[55,1],[54,4],[55,2],[54,6],[52,3],[55,1],[0,0],[0,0],[55,1],[54,7],[52,1],[53,3],[53,5],[53,2],[53,7],[53,1],[53,6],[54,1],[52,6],[55,8],[50,5],[55,7],[54,5],[52,3],[53,2],[53,2],[53,2],[53,1],[53,4],[54,1],[54,1],[54,6],[52,1],[53,3],[54,1],[54,7],[54,1],[53,7],[54,5],[54,2],[54,8],[53,3],[55,1],[55,1],[55,6],[55,2],[52,5],[0,0],[0,0],[53,6],[55,6],[55,2],[53,2],[54,2],[52,5],[52,5],[55,2],[54,2],[53,5],[55,5],[55,2],[0,0],[0,0],[0,0],[55,2],[52,4],[55,3],[55,3],[52,7],[55,2],[53,6],[53,3],[52,4],[54,1],[52,2],[52,3],[53,6],[54,7],[53,1],[54,1],[55,2],[55,4],[55,6],[52,4],[55,6],[55,2],[52,2],[53,4],[55,6],[53,7],[53,3],[52,3],[52,5],[52,1],[53,2],[52,8],[52,1],[54,3],[52,7],[53,1],[54,1],[53,1],[54,6],[53,5],[52,4],[53,1],[54,3],[53,3],[53,1],[52,3],[55,4],[55,2],[54,3],[53,4],[53,4],[54,7],[53,1],[53,2],[54,3],[53,2],[52,1],[52,1],[52,5],[52,3],[52,5],[54,7],[54,4],[55,1],[52,3],[53,6],[54,3],[55,3],[55,1],[55,2],[52,6],[52,6],[52,1],[53,4],[54,1],[54,5],[52,3],[54,4],[52,1],[53,1],[55,5],[53,4],[55,2],[0,0],[0,0],[54,7],[52,3],[54,2],[52,5],[55,1],[54,3],[52,1],[53,2],[55,7],[52,5],[54,3],[52,2],[54,3],[55,8],[52,3],[55,1],[54,6],[53,5],[54,4],[52,8],[53,1],[52,2],[55,6],[54,1],[52,1],[53,4],[52,8],[53,2],[52,3],[55,3],[55,3],[52,7],[52,4],[53,1],[55,3],[55,5],[53,3],[54,3],[55,6],[52,5],[54,1],[54,3],[55,1],[55,2],[53,2],[53,1],[53,5],[52,6],[52,2],[55,5],[53,2],[54,4],[54,4],[55,3],[53,1],[52,4],[52,6],[0,0],[0,0],[53,4],[52,1],[55,6],[54,1],[53,3],[55,1],[52,1],[54,3],[54,4],[53,2],[54,3],[53,2],[54,4],[54,7],[53,1],[54,2],[53,1],[54,3],[52,6],[52,7],[54,3],[55,3],[53,3],[53,5],[53,6],[50,5],[54,3],[55,3],[54,1],[54,3],[55,1],[52,1],[54,2],[55,8],[55,7],[55,1],[52,8],[52,7],[54,6],[0,0],[0,0],[53,1],[54,2],[53,1],[52,2],[54,2],[54,1],[52,6],[53,1],[55,6],[54,1],[55,2],[52,5],[0,0],[0,0],[0,0],[53,2],[53,5],[54,5],[54,6],[55,2],[52,3],[52,3],[53,2],[52,8],[55,1],[53,1],[53,1],[53,1],[52,1],[55,3],[52,2],[55,2],[54,3],[52,4],[54,4],[55,2],[52,8],[52,1],[54,1],[52,1],[55,4],[53,6],[54,3],[54,1],[54,7],[53,1],[52,3],[53,5],[52,5],[0,0],[0,0],[0,0],[52,1],[54,4],[53,1],[52,6],[54,5],[55,3],[53,6],[54,3],[52,6],[52,2],[54,4],[52,7],[53,1],[55,2],[55,2],[55,4],[55,5],[53,6],[55,4],[54,3],[55,1],[53,2],[54,4],[52,4],[54,5],[54,6],[52,8],[53,3],[55,6],[53,4],[53,4],[55,4],[55,3],[55,6],[55,1],[54,3],[54,6],[55,2],[54,3],[52,1],[55,2],[55,5],[55,5],[55,6],[52,4],[0,0],[0,0],[55,2],[55,6],[53,8],[52,2],[54,2],[53,6],[52,1],[52,3],[54,2],[54,1],[54,3],[53,8],[53,2],[52,7],[55,3],[55,2],[55,1],[53,4],[52,4],[55,5],[54,4],[53,1],[53,1],[52,2],[52,3],[52,1],[55,3],[55,6],[53,8],[52,2],[54,3],[54,5],[55,5],[54,3],[53,2],[52,1],[54,3],[54,2],[52,7],[54,3],[53,1],[53,4],[52,1],[53,3],[54,2],[52,2],[54,4],[53,5],[53,3],[52,5],[54,5],[54,3],[53,3],[54,3],[54,1],[52,2],[53,7],[55,1],[53,2],[52,2],[0,0],[52,1],[54,3],[52,3],[52,4],[54,2],[54,7],[55,3],[53,4],[54,1],[54,2],[52,4],[53,2],[55,6],[54,5],[52,1],[55,1],[52,4],[54,8],[55,6],[53,7],[52,5],[54,5],[54,1],[52,3],[53,4],[55,3],[54,6],[53,3],[54,2],[52,2],[52,5],[54,2],[52,3],[52,1],[53,6],[55,4],[52,1],[55,3],[0,0],[54,2],[53,2],[54,2],[54,7],[53,4],[53,5],[55,6],[54,1],[55,4],[53,1],[53,2],[55,4],[54,2],[0,0],[0,0],[0,0],[53,1],[52,1],[53,1],[54,1],[54,6],[54,5],[52,7],[55,1],[52,1],[52,3],[52,8],[52,6],[54,2],[55,2],[54,1],[52,5],[55,8],[52,2],[54,4],[52,2],[54,5],[53,2],[52,3],[52,1],[55,7],[53,5],[53,7],[53,4],[52,2],[54,1],[54,1],[54,1],[52,3],[55,4],[0,0],[0,0],[0,0],[54,4],[53,1],[55,4],[55,7],[52,2],[55,3],[55,5],[53,4],[55,5],[54,5],[52,7],[53,1],[52,1],[55,5],[55,1],[55,2],[53,7],[52,1],[53,3],[53,2],[53,3],[54,1],[53,3],[52,1],[54,4],[55,1],[54,2],[52,2],[53,3],[50,5],[54,3],[55,2],[53,1],[52,3],[52,1],[52,7],[52,4],[54,5],[52,2],[53,5],[53,3],[52,5],[54,4],[52,3],[53,7],[0,0],[0,0],[53,2],[52,4],[53,2],[53,1],[55,4],[55,8],[53,6],[52,3],[52,2],[54,2],[52,1],[54,1],[54,3],[53,2],[53,5],[55,3],[54,2],[55,2],[55,4],[54,4],[55,1],[55,3],[53,1],[54,4],[55,8],[52,6],[54,6],[54,2],[55,4],[54,8],[52,1],[54,2],[53,5],[53,1],[54,2],[55,5],[52,3],[54,2],[54,6],[52,1],[54,6],[52,8],[53,2],[54,2],[55,6],[52,1],[52,3],[52,5],[54,3],[52,4],[54,4],[55,5],[52,8],[52,7],[52,2],[54,7],[53,3],[54,1],[54,3],[53,3],[54,6],[54,2],[55,3],[53,1],[53,5],[54,4],[54,1],[53,6],[54,6],[54,3],[54,1],[52,2],[55,2],[55,2],[53,2],[55,1],[52,3],[53,2],[54,3],[54,3],[54,1],[55,7],[54,4],[53,2],[53,4],[55,5],[52,2],[54,1],[53,7],[54,2],[52,2],[53,6],[52,7],[52,6],[52,4],[53,3],[54,1],[55,1],[53,2],[55,8],[52,2],[0,0],[0,0],[53,1],[55,8],[55,1],[53,4],[54,2],[54,2],[52,1],[53,5],[52,4],[52,1],[0,0],[55,3],[52,5],[54,6],[55,5],[55,5],[54,6],[55,7],[52,1],[53,3],[55,5],[55,2],[55,4],[55,1],[52,7],[53,3],[55,2],[55,6],[53,6],[54,3],[53,3],[52,2],[55,4],[54,4],[55,1],[53,6],[52,7],[53,6],[54,4],[54,3],[52,1],[55,2],[52,7],[52,3],[55,5],[0,0],[0,0],[0,0],[0,0],[0,0],[55,1],[54,2],[53,5],[53,1],[55,6],[53,2],[55,6],[53,6],[54,5],[54,4],[54,4],[54,2],[55,2],[54,6],[53,1],[54,1],[53,1],[52,2],[54,2],[54,2],[52,1],[52,4],[54,2],[54,7],[52,3],[53,5],[53,3],[55,2],[53,2],[52,1],[53,4],[55,2],[55,1],[53,7],[55,1],[53,3],[53,6],[54,7],[55,5],[53,1],[55,2],[53,1],[53,3],[53,7],[53,3],[50,5],[0,0],[0,0],[54,5],[52,1],[0,0],[0,0],[53,3],[53,5],[55,1],[55,3],[55,6],[50,5],[55,6],[53,2],[52,2],[52,2],[52,1],[55,3],[54,7],[55,1],[53,1],[54,2],[55,4],[55,7],[54,4],[55,7],[53,4],[52,1],[55,2],[54,3],[54,4],[53,7],[52,4],[55,2],[55,1],[55,7],[53,5],[55,3],[55,3],[53,4],[54,8],[52,2],[55,6],[53,3],[53,3],[55,2],[53,1],[55,4],[54,3],[55,1],[52,2],[54,2],[55,1],[52,2],[55,1],[55,2],[52,5],[52,5],[54,5],[53,1],[55,7],[54,1],[55,1],[0,0],[0,0],[54,5],[54,1],[54,6],[52,5],[53,2],[53,2],[55,6],[55,1],[53,1],[52,2],[54,5],[55,1],[52,2],[53,2],[54,4],[52,4],[52,1],[53,4],[54,2],[52,5],[53,3],[54,2],[55,8],[52,5],[55,1],[53,3],[53,8],[52,7],[54,4],[55,7],[54,2],[55,3],[55,3],[53,1],[52,2],[0,0],[52,1],[0,0],[0,0],[53,2],[55,3],[53,3],[52,3],[52,8],[52,8],[55,6],[54,3],[55,6],[52,2],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[54,5],[54,3],[52,3],[53,3],[53,2],[53,4],[52,1],[50,5],[55,2],[54,8],[52,2],[55,2],[54,1],[54,4],[53,2],[53,1],[53,5],[53,2],[53,4],[55,6],[52,1],[53,6],[52,5],[52,2],[54,1],[55,2],[52,3],[55,3],[55,4],[52,5],[0,0],[0,0],[53,2],[53,6],[52,8],[52,6],[54,2],[54,3],[55,3],[55,6],[55,2],[52,2],[55,3],[52,5],[0,0],[0,0],[54,3],[55,8],[55,2],[54,7],[55,2],[55,3],[54,6],[54,7],[52,1],[53,2],[55,5],[52,1],[52,6],[52,2],[54,6],[53,1],[54,4],[54,2],[52,1],[55,1],[52,5],[55,3],[54,2],[55,3],[52,3],[52,4],[53,1],[53,6],[54,3],[54,2],[52,8],[53,1],[55,6],[55,6],[0,0],[0,0],[52,5],[55,8],[0,0],[0,0],[55,3],[54,7],[55,1],[55,6],[53,3],[55,5],[53,4],[52,4],[53,6],[52,3],[54,1],[52,1],[52,4],[55,1],[52,1],[54,6],[54,7],[52,6],[55,3],[55,1],[53,4],[53,4],[52,1],[55,6],[52,6],[53,7],[54,4],[53,8],[52,7],[55,1],[53,5],[52,3],[52,3],[52,2],[54,1],[52,5],[52,5],[53,2],[55,6],[53,1],[55,7],[54,6],[54,5],[50,5],[55,2],[55,3],[54,1],[52,6],[54,1],[52,4],[54,1],[53,2],[53,2],[53,1],[52,1],[52,1],[53,6],[0,0],[0,0],[54,6],[55,1],[53,4],[53,3],[54,3],[53,2],[52,2],[54,5],[54,2],[55,2],[54,1],[55,2],[53,2],[54,3],[55,2],[55,5],[50,5],[55,4],[53,1],[54,2],[54,7],[52,1],[55,3],[55,8],[54,2],[53,2],[54,8],[54,1],[53,1],[53,5],[52,1],[53,7],[55,7],[55,3],[52,1],[55,6],[52,2],[54,3],[55,2],[54,3],[53,4],[53,3],[54,5],[54,2],[52,6],[55,6],[55,5],[55,7],[55,1],[54,1],[52,1],[0,0],[55,3],[54,2],[55,7],[54,7],[52,4],[55,1],[54,2],[52,3],[53,1],[55,5],[52,1],[52,3],[54,2],[55,4],[54,2],[54,3],[53,4],[54,3],[53,1],[54,4],[52,1],[55,6],[53,7],[54,3],[55,3],[52,7],[52,7],[54,1],[53,4],[52,5],[55,1],[54,1],[52,5],[52,1],[0,0],[50,5],[53,4],[54,6],[53,4],[52,3],[54,5],[54,6],[54,3],[53,4],[53,3],[55,6],[54,6],[0,0],[0,0],[53,2],[52,8],[53,2],[53,3],[52,7],[53,3],[55,7],[52,1],[54,7],[53,3],[54,3],[53,5],[52,1],[53,6],[52,3],[55,8],[53,1],[53,7],[52,3],[52,2],[54,3],[55,3],[55,4],[52,1],[52,5],[55,3],[55,3],[55,2],[54,2],[54,2],[54,2],[54,1],[54,5],[0,0],[0,0],[53,1],[53,1],[0,0],[0,0],[55,3],[53,5],[0,0],[0,0],[54,4],[55,3],[54,7],[53,1],[53,2],[54,3],[52,6],[52,2],[52,6],[53,1],[53,3],[55,4],[54,4],[53,4],[53,1],[54,4],[54,6],[52,3],[52,3],[55,1],[55,2],[55,6],[55,1],[55,2],[53,2],[54,6],[52,7],[52,2],[53,2],[54,6],[52,2],[52,6],[53,3],[55,2],[54,7],[52,1],[53,3],[53,1],[52,8],[54,1],[54,3],[54,1],[52,5],[50,5],[52,3],[55,6],[54,4],[52,4],[54,7],[52,1],[53,2],[54,2],[52,6],[55,7],[55,6],[55,6],[0,0],[0,0],[0,0],[53,1],[55,1],[53,4],[54,5],[54,3],[54,2],[54,7],[55,1],[53,2],[53,8],[55,5],[53,3],[52,3],[52,1],[53,3],[52,5],[53,2],[52,1],[53,4],[55,1],[52,7],[53,3],[53,5],[55,3],[54,2],[53,3],[52,4],[54,2],[52,8],[54,5],[52,7],[54,7],[52,4],[55,2],[0,0],[0,0],[53,1],[53,5],[52,1],[52,4],[52,4],[54,7],[55,7],[53,4],[55,8],[52,1],[52,2],[0,0],[0,0],[52,5],[54,4],[53,1],[54,2],[55,7],[53,4],[53,2],[53,5],[54,1],[54,7],[54,2],[52,1],[52,3],[53,2],[53,4],[53,5],[54,5],[52,5],[53,2],[52,2],[54,3],[55,2],[55,6],[54,2],[54,3],[54,8],[53,3],[52,2],[52,2],[53,1],[54,7],[55,3],[52,2],[0,0],[0,0],[52,6],[55,5],[52,1],[53,1],[54,5],[52,1],[53,5],[54,3],[53,5],[55,5],[55,6],[53,5],[0,0],[52,6],[54,2],[54,2],[54,6],[52,1],[54,1],[54,3],[54,1],[55,2],[52,3],[52,1],[52,2],[55,1],[52,1],[54,4],[55,8],[54,1],[52,4],[52,7],[52,3],[54,2],[53,3],[54,7],[54,3],[53,3],[52,2],[53,4],[53,8],[55,2],[53,1],[52,2],[53,3],[53,3],[55,6],[0,0],[0,0],[54,7],[53,2],[53,6],[54,5],[55,6],[55,1],[0,0],[0,0],[55,4],[54,8],[53,1],[55,1],[53,8],[55,4],[53,2],[55,5],[55,3],[52,8],[55,3],[54,5],[50,5],[52,2],[52,1],[53,5],[55,3],[55,3],[54,6],[55,5],[52,4],[52,1],[53,1],[50,5],[52,2],[54,1],[54,2],[54,1],[54,2],[55,6],[53,2],[54,3],[55,3],[54,5],[55,2],[52,4],[52,2],[55,1],[54,3],[55,1],[54,6],[55,1],[55,3],[55,6],[55,1],[54,4],[54,4],[55,1],[54,1],[52,7],[52,4],[53,1],[54,1],[54,4],[52,6],[55,1],[0,0],[0,0],[0,0],[52,3],[54,2],[52,5],[53,7],[53,3],[54,3],[55,7],[55,1],[54,3],[53,6],[53,4],[53,4],[52,4],[53,4],[55,7],[53,5],[55,1],[53,5],[53,6],[55,5],[50,5],[53,1],[53,6],[53,2],[52,6],[55,4],[52,2],[52,1],[53,1],[55,7],[53,1],[52,8],[53,5],[55,6],[0,0],[0,0],[54,3],[53,2],[53,1],[54,7],[54,1],[53,7],[54,3],[52,4],[52,4],[55,2],[55,2],[0,0],[0,0],[55,1],[53,3],[52,2],[53,5],[54,1],[52,1],[52,1],[54,5],[54,6],[53,2],[54,6],[53,4],[52,1],[52,6],[53,8],[54,2],[54,7],[53,3],[53,2],[55,7],[53,6],[54,7],[55,5],[55,1],[53,5],[55,2],[53,6],[53,3],[55,3],[55,1],[53,2],[53,3],[0,0],[0,0],[0,0],[53,5],[55,4],[52,2],[54,1],[54,6],[54,1],[54,3],[52,1],[55,1],[55,4],[53,2],[52,6],[55,2],[52,5],[0,0],[0,0],[53,3],[54,3],[52,2],[52,4],[52,2],[50,5],[53,3],[52,2],[52,3],[52,2],[55,1],[54,4],[55,2],[54,3],[52,2],[53,5],[53,2],[54,3],[52,5],[52,1],[55,3],[54,1],[52,1],[52,3],[54,4],[55,3],[55,7],[54,6],[54,4],[55,2],[55,7],[55,7],[0,0],[0,0],[55,1],[53,6],[55,1],[53,3],[54,8],[54,7],[54,2],[53,2],[52,1],[53,3],[53,8],[54,5],[55,1],[55,2],[52,7],[54,5],[53,2],[53,8],[52,3],[55,1],[52,4],[52,3],[54,4],[52,6],[55,4],[52,7],[52,4],[52,1],[52,7],[54,1],[53,7],[55,1],[53,6],[53,2],[52,2],[53,2],[54,3],[54,2],[52,2],[53,7],[53,2],[55,3],[55,6],[54,6],[53,2],[55,5],[53,4],[53,3],[52,3],[52,3],[55,1],[53,3],[53,2],[54,8],[54,5],[55,6],[55,1],[52,1],[53,5],[53,3],[55,2],[55,6],[55,1],[0,0],[0,0],[0,0],[55,7],[52,5],[53,6],[54,1],[52,4],[55,1],[55,6],[54,2],[55,5],[54,2],[55,3],[54,4],[53,3],[53,2],[54,1],[55,7],[52,5],[53,3],[52,3],[54,2],[55,7],[52,3],[52,5],[53,6],[50,5],[52,1],[52,1],[54,1],[54,3],[53,2],[53,2],[52,3],[54,2],[55,3],[53,2],[55,2],[0,0],[0,0],[0,0],[54,1],[53,1],[55,2],[52,7],[55,3],[54,2],[53,7],[54,5],[0,0],[0,0],[0,0],[53,4],[52,5],[52,6],[55,6],[52,7],[52,2],[53,1],[54,3],[53,6],[54,1],[0,0],[0,0],[55,2],[52,3],[55,7],[54,5],[54,2],[53,4],[54,2],[52,7],[55,1],[53,4],[55,2],[55,5],[52,1],[52,2],[53,3],[54,5],[52,1],[52,1],[0,0],[0,0],[0,0],[52,3],[55,4],[53,2],[53,7],[54,2],[55,4],[53,2],[52,4],[52,1],[53,6],[53,7],[55,1],[55,7],[0,0],[52,3],[0,0],[0,0],[55,2],[52,6],[52,8],[52,2],[55,1],[53,4],[52,2],[52,1],[54,4],[52,5],[53,5],[52,3],[52,8],[53,1],[53,4],[55,1],[52,1],[53,2],[54,3],[55,2],[52,2],[53,1],[52,2],[54,2],[54,5],[55,2],[55,2],[52,7],[53,8],[53,2],[55,5],[53,1],[0,0],[0,0],[0,0],[0,0],[54,2],[53,7],[55,4],[52,2],[55,3],[55,2],[52,7],[52,3],[55,4],[52,8],[54,6],[54,1],[55,5],[52,7],[52,5],[53,7],[52,3],[54,8],[54,5],[52,4],[54,7],[55,3],[54,4],[52,5],[52,3],[52,3],[52,7],[53,1],[54,3],[54,1],[53,7],[55,5],[53,6],[54,3],[52,6],[55,7],[53,3],[55,1],[55,8],[54,7],[54,1],[55,3],[52,2],[54,2],[55,3],[54,7],[52,2],[55,8],[54,6],[54,1],[54,2],[53,2],[55,8],[54,2],[53,1],[53,3],[54,5],[53,5],[53,7],[53,8],[55,3],[52,4],[53,1],[55,2],[0,0],[50,5],[54,2],[52,6],[53,5],[54,3],[52,1],[55,1],[55,3],[52,8],[53,3],[52,1],[55,2],[52,1],[53,1],[52,4],[54,6],[54,2],[52,4],[54,2],[52,7],[53,6],[53,7],[53,2],[52,1],[52,3],[53,2],[52,2],[54,2],[53,7],[55,6],[53,6],[55,3],[54,1],[54,5],[53,4],[0,0],[0,0],[0,0],[55,8],[55,3],[54,5],[52,2],[54,7],[53,3],[54,2],[52,4],[0,0],[0,0],[0,0],[54,6],[53,2],[55,3],[55,1],[55,8],[52,2],[53,6],[50,5],[53,3],[53,4],[0,0],[0,0],[52,5],[55,7],[53,6],[54,5],[52,6],[52,8],[52,4],[55,1],[54,1],[55,1],[54,3],[55,8],[53,1],[52,6],[53,5],[53,2],[53,3],[54,7],[0,0],[0,0],[0,0],[52,2],[52,6],[53,6],[54,5],[53,2],[54,5],[55,3],[53,1],[53,6],[54,3],[52,3],[54,1],[55,1],[55,4],[54,6],[53,3],[55,3],[55,7],[55,1],[52,3],[54,2],[52,7],[54,7],[52,4],[52,6],[54,3],[53,3],[53,7],[54,8],[55,2],[52,2],[55,2],[53,3],[54,7],[52,4],[52,2],[54,3],[52,6],[53,5],[55,2],[53,3],[54,5],[55,1],[53,2],[55,3],[54,1],[54,8],[52,3],[55,2],[55,8],[55,2],[0,0],[0,0],[53,6],[54,8],[54,1],[54,7],[53,2],[55,2],[53,4],[52,6],[55,8],[53,2],[53,1],[53,7],[52,2],[53,3],[52,4],[54,2],[54,2],[52,5],[52,3],[55,4],[53,7],[55,5],[53,8],[53,1],[54,3],[55,2],[0,0],[0,0],[54,5],[52,2],[52,2],[54,2],[54,1],[54,4],[52,4],[55,2],[52,2],[52,3],[54,1],[53,4],[50,5],[0,0],[0,0],[53,8],[54,3],[52,2],[52,5],[54,3],[55,6],[54,3],[54,6],[55,4],[52,1],[54,8],[53,2],[52,5],[55,6],[54,1],[53,1],[54,2],[54,6],[53,8],[54,5],[53,3],[53,5],[54,8],[54,2],[55,8],[54,6],[54,2],[54,3],[53,7],[52,2],[54,7],[54,2],[54,7],[52,2],[52,3],[55,3],[53,8],[55,1],[55,8],[55,1],[52,2],[52,5],[52,1],[52,2],[52,5],[53,6],[52,4],[53,7],[54,7],[55,7],[55,2],[54,8],[55,2],[55,8],[55,4],[53,1],[53,4],[0,0],[0,0],[0,0],[53,3],[55,7],[55,2],[52,2],[52,1],[55,3],[53,3],[53,8],[0,0],[0,0],[0,0],[55,3],[53,6],[52,1],[53,5],[52,5],[52,1],[52,2],[53,4],[54,1],[0,0],[0,0],[52,6],[54,6],[0,0],[0,0],[53,3],[53,4],[52,7],[52,1],[54,5],[50,5],[54,2],[54,1],[52,2],[52,7],[54,2],[54,1],[55,1],[55,1],[0,0],[0,0],[53,2],[54,1],[53,1],[54,1],[54,1],[54,5],[55,3],[54,5],[54,7],[55,3],[54,2],[54,1],[52,1],[52,5],[55,2],[55,3],[55,5],[0,0],[0,0],[52,2],[53,5],[54,3],[52,1],[54,2],[52,1],[54,4],[55,1],[55,2],[54,1],[54,2],[53,2],[52,1],[52,1],[54,5],[55,2],[52,2],[53,1],[54,8],[53,1],[54,4],[53,3],[55,2],[53,3],[53,5],[52,6],[52,3],[53,3],[54,2],[54,3],[54,5],[55,1],[52,2],[53,3],[55,2],[0,0],[0,0],[53,3],[53,1],[52,1],[53,6],[55,2],[55,2],[52,3],[52,3],[53,7],[54,5],[52,3],[54,2],[53,1],[54,8],[52,4],[55,1],[53,2],[55,5],[55,6],[54,7],[54,6],[53,8],[53,1],[54,7],[55,1],[0,0],[0,0],[50,5],[54,2],[55,3],[55,3],[53,6],[55,2],[55,8],[53,4],[53,3],[53,6],[52,3],[55,1],[55,2],[0,0],[0,0],[53,6],[54,5],[52,3],[53,1],[55,1],[55,6],[52,2],[53,5],[54,3],[54,1],[52,1],[52,2],[50,5],[53,2],[54,2],[53,7],[53,3],[54,6],[50,5],[55,2],[54,3],[53,4],[52,3],[55,4],[52,5],[55,8],[52,6],[52,7],[54,3],[53,1],[55,7],[53,8],[53,3],[54,7],[54,4],[52,6],[53,3],[52,1],[0,0],[0,0],[53,4],[53,1],[55,7],[55,7],[52,8],[54,4],[53,2],[53,5],[53,8],[55,7],[53,1],[53,3],[54,8],[55,7],[54,2],[53,4],[54,4],[54,6],[55,7],[53,5],[54,5],[54,2],[52,6],[55,2],[53,1],[52,2],[55,2],[54,3],[53,3],[0,0],[0,0],[55,5],[52,1],[52,1],[53,1],[55,3],[52,5],[54,7],[52,2],[53,3],[55,5],[53,7],[53,6],[52,2],[0,0],[0,0],[54,2],[53,7],[54,5],[54,3],[52,5],[54,6],[53,3],[53,6],[54,7],[54,5],[52,1],[53,2],[54,1],[55,8],[0,0],[0,0],[52,5],[52,4],[54,8],[53,2],[55,6],[54,7],[52,7],[54,1],[52,2],[53,3],[52,6],[52,4],[53,3],[53,2],[54,4],[53,2],[53,5],[0,0],[0,0],[52,6],[55,3],[54,4],[55,7],[53,8],[52,5],[53,2],[55,1],[55,1],[54,1],[53,5],[53,5],[54,7],[52,1],[55,1],[53,2],[54,2],[55,2],[52,2],[53,6],[55,2],[54,7],[52,2],[55,3],[53,3],[52,7],[54,4],[52,2],[54,5],[53,3],[53,1],[55,2],[53,6],[54,4],[55,6],[0,0],[0,0],[0,0],[0,0],[55,2],[53,6],[52,3],[53,1],[55,3],[54,1],[52,1],[53,1],[53,5],[54,6],[52,1],[55,3],[53,2],[53,3],[53,1],[55,7],[54,5],[55,3],[52,7],[53,2],[55,1],[52,7],[52,2],[0,0],[54,3],[54,1],[55,7],[52,5],[53,7],[55,3],[53,2],[53,1],[53,2],[55,1],[54,7],[52,2],[52,2],[0,0],[0,0],[55,3],[54,6],[0,0],[0,0],[54,4],[54,2],[53,7],[54,2],[54,1],[55,1],[54,3],[52,3],[55,2],[54,2],[53,1],[55,4],[54,4],[52,4],[50,5],[55,3],[55,7],[55,2],[53,2],[55,1],[53,4],[55,1],[55,4],[54,3],[52,5],[52,6],[54,1],[53,7],[55,7],[53,1],[55,1],[55,3],[54,2],[54,4],[53,8],[0,0],[0,0],[53,4],[53,7],[52,2],[53,1],[54,2],[52,6],[55,5],[52,2],[54,3],[53,3],[52,4],[55,6],[55,3],[53,5],[55,1],[54,6],[53,2],[55,7],[55,2],[55,3],[54,5],[52,1],[55,7],[54,2],[54,2],[55,2],[55,6],[52,2],[55,2],[0,0],[0,0],[53,2],[52,1],[55,5],[54,1],[55,7],[54,6],[53,8],[55,7],[53,2],[53,4],[54,2],[52,1],[52,6],[52,4],[55,1],[52,7],[53,2],[53,1],[53,2],[54,6],[54,2],[53,1],[55,2],[55,2],[52,1],[52,1],[55,2],[53,8],[55,5],[0,0],[53,2],[54,2],[52,2],[52,3],[52,2],[55,1],[54,7],[54,5],[52,2],[53,5],[54,1],[53,3],[54,3],[52,4],[53,2],[53,6],[54,6],[53,5],[55,6],[54,2],[0,0],[0,0],[0,0],[54,3],[54,4],[54,8],[52,8],[54,1],[53,5],[53,1],[52,1],[54,7],[52,2],[53,2],[54,1],[52,2],[54,7],[55,2],[52,2],[53,8],[52,5],[53,7],[54,1],[55,3],[52,7],[52,1],[52,5],[53,2],[55,3],[50,5],[55,1],[53,7],[52,5],[52,2],[52,3],[55,5],[54,1],[0,0],[0,0],[55,5],[53,1],[53,6],[55,2],[54,2],[52,4],[52,4],[53,2],[54,1],[54,1],[53,1],[53,7],[52,6],[54,2],[54,3],[54,6],[53,2],[52,4],[54,1],[52,5],[54,1],[55,2],[55,1],[52,8],[53,7],[0,0],[0,0],[52,3],[54,8],[54,7],[52,6],[54,3],[54,1],[55,1],[52,5],[55,2],[52,6],[54,4],[53,5],[54,1],[53,1],[0,0],[0,0],[53,8],[55,4],[52,2],[55,1],[55,3],[52,1],[52,7],[53,3],[53,2],[52,4],[55,1],[55,3],[52,1],[54,4],[54,3],[55,1],[53,5],[53,8],[52,1],[52,2],[53,4],[55,2],[52,7],[52,6],[55,6],[55,3],[54,3],[52,3],[53,5],[52,7],[54,3],[53,5],[52,4],[52,5],[52,8],[0,0],[54,1],[52,5],[52,3],[53,4],[55,2],[52,1],[54,4],[52,1],[54,8],[54,4],[52,3],[53,4],[55,7],[53,2],[52,1],[54,5],[55,3],[52,5],[52,2],[55,4],[54,6],[55,1],[52,1],[55,6],[54,7],[54,3],[54,2],[53,3],[55,4],[53,4],[0,0],[54,7],[55,4],[54,3],[53,1],[54,6],[53,6],[52,7],[53,2],[54,5],[53,3],[53,5],[52,3],[54,5],[52,4],[52,8],[55,6],[53,5],[53,1],[55,1],[52,2],[55,2],[53,4],[53,6],[55,3],[53,2],[53,1],[55,2],[53,5],[54,5],[55,8],[54,2],[52,7],[0,0],[0,0],[54,2],[55,4],[54,1],[54,1],[55,4],[52,4],[54,4],[55,2],[53,2],[55,4],[52,2],[52,3],[55,2],[55,6],[53,2],[53,4],[54,2],[0,0],[0,0],[0,0],[53,6],[55,1],[52,8],[53,3],[53,6],[54,2],[54,6],[53,1],[52,4],[55,3],[52,2],[54,4],[53,5],[55,1],[53,1],[54,1],[52,5],[54,3],[55,3],[53,1],[53,5],[55,2],[54,8],[53,1],[53,5],[52,2],[52,3],[52,3],[55,2],[55,1],[54,5],[54,6],[55,2],[53,2],[55,5],[0,0],[0,0],[55,1],[54,3],[53,6],[55,1],[53,5],[54,1],[53,3],[55,3],[53,7],[54,4],[50,5],[52,2],[53,1],[55,2],[55,2],[53,2],[52,3],[52,3],[55,5],[55,5],[55,1],[54,2],[0,0],[53,3],[0,0],[0,0],[55,7],[53,4],[53,1],[55,1],[52,2],[54,1],[54,2],[54,5],[55,1],[54,2],[54,2],[55,1],[55,2],[55,6],[52,1],[52,2],[54,8],[55,3],[53,7],[55,1],[55,7],[52,1],[55,3],[55,3],[52,7],[53,1],[53,3],[53,3],[53,2],[54,1],[53,3],[53,2],[53,4],[55,4],[54,1],[55,4],[54,2],[52,3],[52,4],[52,8],[54,2],[54,2],[54,6],[55,1],[55,3],[55,2],[54,3],[55,5],[55,5],[52,5],[52,5],[52,2],[54,7],[0,0],[0,0],[52,6],[54,1],[52,3],[55,7],[53,8],[52,2],[54,7],[53,6],[54,1],[54,1],[54,1],[55,4],[52,2],[54,1],[52,5],[52,2],[53,2],[52,3],[53,1],[55,4],[52,6],[52,2],[53,2],[54,1],[55,1],[55,3],[0,0],[0,0],[55,1],[53,8],[52,6],[53,4],[54,4],[52,2],[52,3],[53,1],[52,6],[55,3],[53,1],[54,2],[54,8],[52,8],[53,3],[50,5],[53,1],[55,7],[53,4],[53,1],[53,6],[54,2],[53,4],[54,3],[54,7],[55,5],[52,5],[54,6],[53,6],[52,1],[0,0],[55,8],[0,0],[0,0],[52,1],[53,6],[54,2],[55,3],[55,7],[55,6],[53,3],[55,3],[55,2],[52,5],[55,1],[53,1],[53,4],[54,7],[55,7],[53,5],[55,5],[0,0],[0,0],[0,0],[52,4],[54,6],[55,8],[54,3],[55,3],[52,6],[52,6],[54,4],[52,2],[54,2],[54,1],[50,5],[53,1],[54,3],[54,3],[52,3],[54,4],[54,3],[55,2],[52,2],[54,3],[53,5],[55,2],[55,5],[52,5],[54,4],[52,2],[53,5],[53,2],[55,3],[54,4],[53,4],[54,6],[52,4],[55,6],[0,0],[0,0],[0,0],[0,0],[54,1],[55,1],[52,6],[55,1],[55,3],[55,1],[53,1],[55,1],[52,6],[55,3],[52,2],[52,1],[54,2],[53,2],[55,4],[55,3],[54,3],[55,6],[55,4],[55,1],[54,3],[54,7],[53,3],[55,5],[52,3],[55,1],[52,4],[54,1],[52,8],[54,3],[55,3],[54,1],[54,1],[52,4],[55,3],[52,4],[53,2],[52,7],[50,5],[53,6],[55,8],[54,1],[53,4],[55,2],[55,3],[52,5],[54,6],[54,5],[52,2],[55,6],[54,1],[54,3],[52,2],[55,1],[55,2],[54,2],[54,3],[52,3],[53,1],[53,1],[52,3],[55,1],[50,5],[54,3],[53,1],[53,3],[53,2],[53,5],[55,4],[55,2],[52,3],[54,1],[53,4],[55,8],[52,1],[0,0],[52,2],[0,0],[0,0],[54,5],[54,2],[55,6],[52,6],[55,1],[52,1],[52,6],[54,1],[55,2],[54,2],[52,8],[54,2],[53,2],[52,3],[52,4],[54,1],[53,8],[54,5],[52,1],[55,1],[53,2],[53,8],[55,5],[54,1],[55,7],[55,2],[0,0],[52,7],[52,7],[54,2],[53,4],[53,3],[52,1],[53,2],[55,7],[52,2],[53,6],[55,6],[55,6],[55,2],[55,8],[52,4],[52,4],[53,7],[52,4],[53,5],[52,7],[55,2],[52,8],[53,7],[52,5],[54,7],[54,4],[55,5],[54,2],[52,1],[55,4],[55,3],[55,5],[53,8],[52,7],[52,2],[55,5],[52,5],[52,3],[52,3],[54,1],[55,5],[55,7],[52,6],[55,3],[50,5],[55,1],[52,1],[54,6],[55,6],[53,2],[53,1],[55,4],[55,3],[55,5],[53,3],[52,1],[53,1],[55,1],[53,2],[53,1],[52,6],[53,2],[54,2],[54,1],[53,6],[55,2],[55,1],[54,2],[55,1],[53,1],[53,1],[55,5],[54,5],[54,4],[54,2],[53,7],[55,1],[53,6],[53,4],[55,5],[53,6],[53,5],[53,3],[54,2],[52,3],[55,3],[52,3],[50,5],[53,7],[53,8],[53,2],[54,1],[0,0],[0,0],[53,2],[55,2],[53,8],[54,4],[52,5],[52,3],[52,1],[55,1],[54,7],[53,1],[52,7],[52,5],[52,1],[52,4],[55,7],[53,7],[54,6],[54,2],[52,5],[55,1],[55,8],[54,4],[0,0],[0,0],[55,2],[52,2],[55,8],[52,1],[55,1],[54,7],[55,3],[52,6],[54,3],[54,8],[53,7],[53,7],[55,5],[55,6],[55,6],[53,3],[55,4],[55,6],[54,3],[52,2],[52,3],[55,3],[54,2],[50,5],[55,1],[54,2],[52,5],[55,6],[53,1],[53,3],[55,1],[53,2],[54,1],[54,1],[52,4],[52,3],[52,2],[52,7],[53,5],[54,4],[55,1],[52,1],[52,3],[52,1],[55,6],[53,3],[53,7],[55,6],[52,2],[55,3],[53,4],[52,1],[55,7],[54,6],[52,1],[55,1],[53,1],[52,2],[55,2],[55,4],[52,2],[54,4],[54,1],[54,8],[51,4],[53,8],[54,7],[54,8],[54,7],[55,1],[53,2],[54,1],[55,1],[53,2],[53,2],[54,2],[54,7],[52,4],[55,1],[54,2],[55,1],[0,0],[0,0],[55,4],[54,8],[55,8],[52,1],[55,2],[55,3],[55,2],[54,5],[53,4],[52,4],[55,1],[54,1],[52,6],[55,2],[55,3],[55,1],[55,1],[52,2],[54,2],[53,1],[53,3],[54,2],[52,3],[53,7],[54,1],[52,1],[52,4],[54,1],[54,3],[52,7],[55,5],[52,6],[0,0],[0,0],[54,5],[52,3],[54,6],[52,1],[53,4],[54,2],[55,6],[55,2],[54,8],[53,7],[55,3],[55,2],[53,1],[53,2],[54,1],[52,3],[54,4],[55,1],[55,3],[52,7],[53,2],[52,1],[53,1],[55,6],[55,4],[55,4],[52,6],[55,2],[53,5],[53,8],[52,4],[53,6],[53,2],[55,2],[55,3],[53,3],[54,1],[52,1],[55,3],[54,2],[53,2],[54,5],[53,4],[54,1],[53,3],[55,7],[55,4],[52,7],[52,3],[54,8],[52,2],[52,3],[52,7],[52,3],[54,6],[54,4],[55,7],[54,4],[0,0],[0,0],[52,7],[55,2],[55,6],[54,4],[55,7],[53,1],[54,8],[55,5],[53,5],[52,6],[53,4],[54,1],[53,3],[52,4],[52,8],[55,2],[52,5],[55,1],[52,3],[52,5],[52,7],[0,0],[0,0],[54,2],[55,7],[52,5],[54,6],[52,5],[50,5],[53,5],[54,1],[52,8],[52,4],[54,1],[54,3],[52,7],[54,2],[53,5],[52,2],[52,4],[53,7],[55,3],[54,1],[53,1],[52,3],[54,1],[52,1],[52,2],[55,5],[55,1],[55,5],[54,1],[55,3],[55,4],[53,1],[53,4],[53,2],[53,2],[54,3],[54,2],[52,2],[54,3],[53,2],[52,6],[54,6],[54,7],[52,2],[55,7],[54,6],[53,7],[54,6],[52,1],[55,2],[54,1],[53,6],[54,3],[0,0],[0,0],[52,6],[52,2],[55,2],[53,1],[55,4],[53,3],[54,7],[52,6],[55,2],[54,1],[52,4],[53,4],[54,8],[53,1],[55,1],[52,8],[52,7],[52,7],[55,1],[55,2],[52,2],[53,5],[52,2],[54,6],[52,1],[55,4],[0,0],[0,0],[54,1],[55,2],[53,6],[54,7],[52,6],[55,4],[52,3],[52,1],[53,3],[52,3],[53,3],[55,6],[54,4],[52,3],[53,8],[53,3],[53,6],[55,6],[54,3],[54,1],[53,5],[54,3],[55,3],[54,1],[53,3],[55,2],[52,8],[54,6],[52,1],[54,5],[52,1],[54,1],[0,0],[0,0],[0,0],[54,1],[52,7],[55,1],[53,4],[54,2],[54,2],[52,2],[53,6],[55,2],[55,5],[55,4],[55,1],[52,2],[54,8],[54,2],[52,2],[55,1],[54,2],[52,2],[53,1],[55,1],[52,2],[53,3],[54,2],[55,6],[54,3],[52,6],[55,8],[55,7],[55,7],[54,6],[52,8],[53,3],[54,7],[54,5],[54,6],[53,4],[52,2],[55,2],[55,4],[54,3],[54,2],[55,8],[55,4],[52,2],[54,3],[54,2],[52,7],[52,3],[53,4],[53,2],[53,3],[55,1],[52,2],[55,3],[52,5],[55,8],[0,0],[0,0],[0,0],[0,0],[55,8],[53,5],[53,1],[55,2],[54,4],[53,3],[55,2],[55,4],[54,5],[52,2],[54,2],[54,8],[52,1],[54,1],[54,1],[52,3],[55,4],[55,1],[53,5],[52,7],[54,6],[0,0],[0,0],[0,0],[55,3],[52,2],[54,3],[52,3],[53,1],[55,6],[54,6],[54,5],[55,5],[53,1],[54,8],[53,6],[54,4],[55,1],[55,3],[54,1],[55,5],[53,2],[54,3],[53,2],[55,1],[55,8],[54,8],[54,3],[52,4],[54,7],[53,3],[53,2],[52,2],[54,5],[54,8],[54,1],[53,5],[53,7],[53,7],[50,5],[52,3],[54,7],[55,6],[54,8],[52,4],[53,3],[53,3],[54,8],[53,5],[54,7],[53,5],[54,4],[55,3],[53,4],[0,0],[0,0],[53,4],[55,5],[53,2],[53,8],[52,1],[55,1],[54,5],[55,4],[53,8],[54,5],[55,7],[52,5],[53,3],[53,7],[54,5],[53,6],[53,1],[54,2],[55,2],[55,7],[53,1],[54,3],[52,2],[55,8],[52,7],[55,4],[0,0],[54,5],[54,3],[55,3],[54,8],[54,2],[53,6],[54,7],[55,1],[54,4],[55,3],[53,7],[54,2],[53,4],[54,2],[55,1],[52,4],[55,1],[55,1],[53,8],[55,5],[55,2],[55,5],[54,7],[54,8],[54,3],[52,2],[55,5],[55,1],[54,8],[53,3],[50,5],[53,1],[52,4],[55,2],[53,6],[0,0],[0,0],[0,0],[52,4],[54,2],[54,3],[55,3],[54,1],[53,3],[52,3],[53,2],[54,2],[55,7],[53,3],[52,4],[55,3],[53,1],[54,3],[55,1],[55,4],[52,2],[55,2],[54,1],[53,2],[50,5],[55,7],[55,3],[53,4],[52,6],[54,2],[54,5],[55,4],[53,7],[53,7],[53,6],[54,5],[55,2],[53,5],[54,3],[52,5],[55,7],[54,5],[54,3],[53,4],[53,6],[54,6],[52,4],[54,2],[54,2],[52,1],[52,2],[52,5],[54,2],[53,1],[53,3],[55,1],[55,7],[55,5],[54,5],[53,5],[0,0],[0,0],[52,2],[55,4],[55,3],[52,4],[53,8],[55,3],[53,7],[55,1],[52,6],[53,5],[54,2],[54,7],[52,5],[54,2],[53,6],[53,2],[52,2],[55,4],[53,7],[50,5],[52,1],[0,0],[0,0],[0,0],[55,1],[52,7],[55,2],[55,5],[54,2],[54,2],[50,5],[53,3],[53,8],[54,4],[53,7],[52,6],[52,3],[52,3],[53,1],[54,1],[53,5],[53,5],[52,5],[52,5],[52,2],[52,3],[53,3],[52,5],[55,7],[55,1],[54,4],[55,3],[55,2],[55,8],[55,1],[54,3],[54,6],[55,2],[54,2],[54,2],[54,1],[52,4],[53,1],[53,2],[53,5],[54,2],[55,3],[53,2],[52,3],[55,4],[53,3],[55,3],[55,6],[54,8],[54,5],[52,1],[0,0],[0,0],[0,0],[53,1],[52,3],[52,3],[53,3],[54,2],[52,4],[53,3],[55,2],[52,3],[55,6],[55,1],[53,4],[54,2],[53,1],[55,2],[55,3],[54,5],[55,1],[53,6],[55,2],[54,4],[55,1],[54,2],[55,4],[55,5],[0,0],[0,0],[52,1],[52,3],[53,3],[55,1],[53,3],[54,6],[55,2],[54,2],[52,2],[55,1],[54,4],[52,2],[54,6],[53,6],[52,3],[55,2],[55,7],[54,3],[53,2],[52,3],[52,5],[53,7],[54,5],[53,3],[52,8],[54,2],[55,1],[52,2],[54,4],[53,4],[52,6],[54,6],[0,0],[0,0],[0,0],[55,2],[52,4],[54,1],[55,6],[52,3],[55,4],[54,3],[52,1],[54,8],[54,7],[53,3],[52,7],[54,1],[54,5],[52,8],[54,5],[53,2],[53,2],[52,3],[55,4],[54,1],[55,2],[52,4],[55,2],[52,1],[54,2],[54,5],[54,2],[55,1],[54,5],[53,5],[55,1],[52,8],[53,3],[55,3],[53,2],[55,1],[53,7],[54,4],[52,2],[55,2],[52,3],[52,2],[54,3],[52,3],[54,4],[52,2],[52,8],[52,8],[53,6],[53,2],[52,3],[55,2],[52,6],[52,3],[54,3],[53,7],[54,1],[0,0],[0,0],[54,6],[55,3],[55,5],[55,2],[53,3],[54,2],[52,3],[52,1],[53,7],[55,2],[52,6],[53,7],[53,7],[55,1],[53,8],[52,8],[53,2],[54,2],[50,5],[54,1],[0,0],[0,0],[0,0],[54,2],[53,2],[53,1],[52,6],[52,6],[54,1],[53,6],[53,2],[53,2],[52,6],[52,5],[52,2],[55,1],[55,2],[55,1],[53,3],[54,3],[53,1],[54,3],[54,7],[54,1],[53,6],[52,4],[52,3],[53,6],[52,1],[54,4],[53,3],[52,2],[53,6],[53,2],[53,4],[53,7],[55,7],[52,4],[55,1],[54,5],[52,8],[55,4],[53,2],[52,2],[50,5],[52,7],[54,4],[52,6],[53,1],[53,4],[53,6],[55,6],[53,2],[55,2],[54,1],[0,0],[0,0],[0,0],[55,3],[54,6],[52,5],[54,4],[53,7],[53,1],[52,1],[53,2],[53,6],[55,5],[54,5],[55,6],[52,2],[52,5],[53,5],[53,2],[53,2],[52,6],[54,6],[52,1],[52,3],[54,8],[54,2],[0,0],[53,7],[0,0],[0,0],[53,3],[54,3],[55,1],[54,2],[53,1],[52,2],[55,4],[55,3],[53,2],[55,2],[55,8],[55,2],[54,2],[54,2],[55,7],[55,7],[53,2],[55,4],[55,4],[52,8],[55,5],[53,2],[54,5],[55,2],[53,7],[55,3],[55,1],[53,4],[54,6],[52,2],[0,0],[0,0],[0,0],[0,0],[0,0],[52,5],[55,2],[52,8],[53,4],[55,3],[55,1],[53,3],[54,2],[55,1],[53,2],[52,8],[54,2],[53,5],[55,6],[54,3],[54,2],[52,3],[52,2],[55,5],[55,2],[54,3],[55,2],[53,1],[52,6],[54,2],[53,1],[54,2],[55,4],[55,4],[54,4],[52,7],[52,7],[52,3],[52,4],[52,2],[55,6],[55,2],[53,8],[52,6],[55,2],[54,1],[53,5],[52,2],[55,1],[54,4],[53,6],[52,2],[53,2],[53,2],[54,2],[55,6],[52,2],[53,5],[52,5],[52,6],[55,2],[52,4],[52,2],[0,0],[0,0],[0,0],[0,0],[53,3],[53,3],[55,5],[52,7],[54,6],[52,2],[53,1],[50,5],[0,0],[0,0],[55,2],[54,7],[55,6],[55,1],[54,1],[53,4],[52,3],[55,1],[52,8],[52,1],[52,2],[55,2],[53,2],[52,2],[55,4],[53,4],[52,2],[52,2],[54,1],[52,5],[55,6],[55,1],[53,1],[54,1],[55,4],[52,1],[52,5],[52,1],[52,1],[53,3],[53,4],[55,3],[53,1],[54,5],[53,7],[53,1],[52,7],[55,5],[53,1],[52,7],[53,7],[52,1],[54,1],[52,2],[54,3],[54,7],[55,8],[54,1],[53,8],[55,4],[54,1],[55,6],[54,5],[52,7],[54,3],[53,4],[52,4],[55,1],[54,2],[54,1],[53,2],[52,3],[54,4],[0,0],[0,0],[0,0],[54,6],[54,2],[54,4],[54,2],[54,6],[53,2],[52,2],[53,8],[53,4],[54,2],[54,3],[54,7],[54,3],[52,1],[52,4],[55,8],[55,2],[54,6],[55,2],[52,2],[55,2],[52,4],[55,6],[54,3],[53,6],[54,4],[53,5],[53,3],[53,6],[54,6],[52,1],[54,5],[52,2],[55,3],[55,2],[55,1],[55,8],[55,4],[55,2],[52,5],[53,4],[55,3],[54,2],[53,3],[52,3],[55,5],[55,4],[53,1],[54,7],[54,4],[54,6],[55,1],[54,1],[52,8],[54,6],[52,1],[55,4],[55,4],[0,0],[53,5],[55,5],[54,5],[52,2],[55,1],[53,1],[52,6],[52,3],[55,1],[54,1],[52,2],[55,2],[53,3],[54,1],[54,7],[54,6],[54,1],[55,2],[53,4],[53,7],[55,3],[53,8],[54,5],[52,3],[54,4],[53,2],[52,6],[53,4],[53,2],[53,3],[55,4],[55,4],[55,5],[52,2],[55,5],[54,3],[52,8],[53,2],[55,6],[53,1],[51,8],[53,8],[53,4],[52,3],[55,5],[52,6],[55,5],[52,5],[54,3],[54,7],[55,1],[54,1],[54,5],[52,2],[54,1],[55,7],[53,1],[53,4],[55,1],[53,2],[53,1],[55,1],[55,7],[0,0],[0,0],[54,5],[53,1],[54,4],[55,3],[53,1],[53,6],[54,5],[53,2],[0,0],[0,0],[52,7],[52,5],[54,1],[53,4],[50,5],[53,3],[55,8],[52,3],[55,4],[54,1],[55,1],[54,6],[52,7],[52,1],[55,6],[55,3],[54,4],[54,2],[52,2],[53,3],[53,4],[55,3],[53,1],[55,2],[55,3],[53,8],[52,4],[55,1],[54,4],[54,2],[54,6],[54,8],[53,3],[52,1],[54,2],[54,3],[53,2],[52,2],[54,2],[52,5],[52,4],[54,4],[52,2],[54,7],[55,3],[52,4],[53,6],[52,4],[52,2],[55,6],[54,1],[52,1],[52,1],[52,3],[55,4],[53,7],[53,6],[54,2],[54,1],[55,2],[53,8],[54,2],[55,6],[53,6],[53,8],[53,5],[53,8],[54,8],[54,1],[53,2],[55,5],[52,2],[52,1],[54,1],[54,8],[55,1],[53,2],[52,2],[55,7],[55,7],[54,4],[54,1],[54,2],[55,6],[55,2],[54,3],[53,8],[54,1],[52,3],[53,6],[53,5],[0,0],[0,0],[53,6],[52,3],[52,1],[53,3],[54,1],[53,3],[53,7],[55,6],[55,1],[53,6],[54,3],[53,7],[54,8],[53,1],[52,4],[54,3],[52,2],[53,7],[54,3],[55,7],[54,4],[53,3],[54,3],[53,1],[54,5],[55,3],[53,3],[52,2],[54,2],[54,2],[0,0],[0,0],[55,2],[53,5],[52,6],[54,2],[53,2],[55,3],[52,6],[54,7],[54,1],[55,1],[53,1],[53,7],[55,2],[54,2],[53,4],[55,1],[54,4],[52,5],[52,2],[55,3],[53,6],[55,7],[54,6],[52,6],[53,5],[54,3],[55,1],[52,8],[52,8],[55,2],[52,1],[53,7],[55,7],[55,2],[53,4],[52,1],[55,2],[55,2],[55,4],[54,2],[55,3],[53,2],[53,2],[52,2],[55,3],[53,2],[52,2],[52,1],[53,3],[55,3],[52,2],[55,3],[52,1],[52,7],[53,1],[52,2],[52,2],[53,4],[53,3],[52,2],[52,7],[55,4],[52,2],[54,4],[0,0],[0,0],[52,6],[55,3],[52,1],[52,3],[53,1],[54,5],[52,2],[0,0],[54,3],[55,1],[52,5],[55,1],[54,3],[52,7],[53,8],[52,2],[54,3],[53,1],[55,4],[55,5],[54,7],[55,3],[54,8],[54,3],[54,5],[55,7],[52,1],[54,4],[54,2],[52,2],[53,2],[52,1],[54,2],[54,3],[53,5],[53,5],[54,3],[50,5],[53,2],[53,4],[53,6],[54,5],[55,8],[55,1],[52,1],[52,2],[54,4],[54,1],[55,1],[53,1],[52,5],[53,3],[52,5],[55,6],[52,1],[53,8],[55,5],[52,1],[55,8],[52,2],[52,5],[52,8],[54,1],[53,6],[54,1],[53,4],[52,6],[53,5],[55,1],[55,1],[55,4],[55,2],[54,6],[53,5],[50,5],[53,3],[54,6],[55,3],[54,1],[52,5],[50,5],[54,1],[55,2],[55,2],[52,6],[52,3],[53,4],[52,1],[52,7],[55,6],[55,5],[53,6],[54,3],[53,1],[53,1],[54,4],[54,4],[53,2],[54,5],[52,5],[0,0],[0,0],[54,3],[55,6],[55,6],[52,2],[55,1],[55,7],[53,6],[53,2],[54,6],[54,1],[53,1],[52,2],[55,2],[55,5],[53,5],[55,1],[55,1],[54,2],[55,4],[54,3],[55,2],[55,4],[54,4],[55,4],[53,2],[53,1],[55,3],[54,4],[53,2],[55,7],[0,0],[0,0],[52,1],[55,4],[54,2],[52,5],[55,5],[53,2],[52,8],[52,1],[55,6],[55,2],[55,4],[55,6],[54,7],[53,1],[53,2],[52,3],[54,7],[55,1],[55,5],[55,5],[55,2],[55,5],[53,7],[52,6],[55,7],[55,8],[53,2],[0,0],[0,0],[53,5],[54,1],[54,1],[52,5],[54,5],[53,2],[55,1],[53,3],[55,6],[53,2],[52,7],[54,2],[52,3],[55,4],[55,7],[52,5],[55,8],[52,5],[52,1],[55,3],[53,1],[53,1],[54,2],[53,7],[54,2],[55,1],[52,7],[55,6],[55,1],[55,3],[55,2],[53,7],[54,3],[52,5],[55,3],[0,0],[0,0],[0,0],[0,0],[53,3],[54,7],[55,7],[53,1],[54,2],[53,6],[53,1],[0,0],[0,0],[55,5],[53,2],[52,7],[54,1],[53,2],[53,2],[54,6],[55,1],[54,2],[52,5],[52,1],[53,6],[54,7],[53,1],[52,2],[53,2],[53,2],[55,6],[55,5],[52,5],[55,6],[55,5],[55,1],[52,1],[53,6],[53,5],[53,5],[52,5],[54,6],[55,4],[50,5],[54,1],[52,6],[53,6],[54,7],[52,6],[52,8],[52,2],[53,4],[52,6],[53,2],[53,3],[53,6],[55,2],[53,2],[55,3],[53,4],[54,7],[52,1],[54,4],[53,6],[52,4],[53,1],[54,4],[53,5],[54,4],[52,1],[54,7],[53,7],[52,2],[55,2],[54,6],[53,4],[55,2],[54,1],[54,4],[53,7],[52,4],[53,1],[53,6],[55,3],[52,1],[52,5],[54,3],[54,5],[55,1],[53,6],[52,7],[52,3],[55,2],[52,1],[52,1],[54,2],[53,1],[53,5],[53,7],[53,3],[54,4],[54,4],[52,1],[0,0],[0,0],[0,0],[0,0],[54,4],[55,2],[52,1],[53,6],[54,2],[55,3],[52,4],[53,1],[53,2],[53,3],[52,7],[55,2],[55,2],[54,7],[53,7],[54,6],[54,7],[53,5],[54,7],[52,2],[54,2],[52,3],[52,6],[55,1],[53,2],[52,2],[53,4],[0,0],[54,1],[52,3],[55,1],[53,5],[55,1],[52,1],[52,1],[55,7],[53,5],[52,3],[54,8],[52,1],[55,1],[53,6],[52,2],[52,3],[54,7],[52,3],[52,5],[53,2],[55,4],[55,4],[54,6],[55,4],[52,1],[52,3],[54,1],[55,7],[0,0],[0,0],[54,7],[53,1],[53,1],[54,5],[53,1],[54,8],[54,2],[54,3],[55,1],[53,1],[55,3],[53,7],[52,1],[54,2],[53,6],[53,5],[52,3],[54,7],[53,3],[53,1],[54,1],[55,1],[52,1],[54,8],[55,6],[55,1],[52,3],[52,8],[53,1],[55,3],[52,3],[53,3],[52,6],[53,1],[53,7],[55,2],[52,1],[0,0],[0,0],[54,1],[53,1],[54,3],[52,3],[55,2],[0,0],[54,3],[0,0],[0,0],[53,3],[53,1],[54,1],[53,3],[52,6],[53,8],[53,2],[53,4],[52,4],[55,4],[52,5],[54,5],[53,5],[53,1],[54,2],[55,8],[55,1],[53,2],[54,2],[53,6],[55,3],[54,2],[52,1],[53,3],[52,1],[53,7],[52,1],[55,3],[54,5],[55,2],[55,7],[54,2],[54,2],[54,1],[55,5],[54,5],[55,2],[52,2],[55,6],[55,5],[54,3],[53,4],[53,2],[55,1],[53,2],[54,2],[53,2],[54,7],[53,3],[54,6],[52,3],[55,6],[53,4],[52,6],[54,1],[52,1],[52,3],[52,5],[52,2],[53,1],[52,1],[54,3],[54,6],[55,8],[55,7],[55,1],[55,1],[55,4],[55,3],[55,3],[55,4],[55,1],[54,3],[54,2],[55,7],[55,1],[53,4],[54,4],[54,2],[55,8],[53,2],[54,3],[53,6],[54,7],[53,2],[52,3],[55,7],[53,1],[54,6],[54,3],[54,3],[0,0],[0,0],[0,0],[53,8],[54,1],[53,5],[52,4],[54,3],[55,4],[55,3],[52,6],[52,5],[55,3],[54,1],[54,3],[55,7],[54,7],[55,2],[54,2],[54,5],[53,6],[54,2],[53,2],[55,7],[54,1],[52,5],[54,3],[52,8],[53,1],[0,0],[0,0],[55,7],[53,3],[54,5],[54,3],[54,8],[53,3],[53,4],[55,7],[52,1],[52,4],[53,2],[53,1],[54,6],[53,2],[53,6],[54,5],[52,2],[54,1],[53,7],[55,6],[55,6],[52,1],[54,6],[55,7],[54,5],[55,2],[52,3],[0,0],[0,0],[53,3],[55,5],[0,0],[0,0],[53,2],[53,2],[55,2],[55,6],[52,1],[54,1],[54,2],[54,8],[53,1],[52,2],[53,5],[54,7],[54,4],[53,3],[55,2],[52,4],[53,7],[52,6],[52,2],[53,1],[52,4],[52,2],[55,2],[52,1],[52,7],[54,1],[54,2],[53,2],[55,3],[52,8],[55,1],[52,2],[54,3],[54,1],[55,4],[0,0],[0,0],[54,3],[52,5],[52,1],[52,3],[52,4],[53,3],[54,6],[52,2],[52,4],[52,3],[54,4],[53,1],[52,6],[52,3],[54,2],[52,1],[53,5],[52,5],[55,4],[55,2],[52,2],[54,2],[53,6],[54,5],[55,6],[55,5],[53,1],[50,5],[55,1],[55,8],[53,5],[54,2],[52,3],[52,7],[54,1],[54,8],[53,1],[55,3],[53,5],[52,3],[55,1],[54,1],[53,2],[54,5],[55,6],[54,3],[53,4],[55,6],[53,3],[55,1],[52,6],[52,4],[52,3],[53,1],[53,1],[54,4],[55,1],[54,5],[53,2],[52,4],[55,4],[52,3],[53,6],[55,7],[52,4],[54,3],[52,3],[55,6],[53,3],[53,2],[52,3],[53,6],[52,3],[53,3],[53,4],[52,7],[55,5],[53,3],[55,4],[52,5],[54,1],[53,1],[53,4],[52,4],[52,2],[54,4],[54,4],[53,1],[54,5],[53,5],[55,5],[54,6],[55,2],[52,5],[53,6],[54,5],[55,3],[52,3],[0,0],[0,0],[0,0],[52,5],[52,3],[53,7],[52,1],[53,1],[54,3],[54,5],[55,6],[55,4],[55,5],[53,2],[54,8],[53,2],[55,2],[54,5],[54,7],[52,2],[55,2],[53,1],[53,7],[54,5],[53,1],[53,3],[53,7],[55,1],[55,4],[0,0],[0,0],[54,1],[52,1],[54,2],[53,6],[53,2],[53,2],[54,2],[54,6],[54,3],[53,3],[52,1],[54,1],[52,1],[55,2],[52,4],[53,8],[52,2],[54,7],[53,1],[53,1],[55,3],[55,2],[54,2],[54,2],[52,2],[53,3],[55,1],[52,5],[53,1],[54,4],[54,1],[52,4],[0,0],[0,0],[52,2],[54,1],[54,2],[54,3],[53,5],[54,4],[52,7],[52,3],[52,7],[54,4],[53,8],[52,2],[53,1],[54,2],[52,1],[53,5],[55,3],[52,2],[53,3],[53,8],[54,6],[54,2],[53,5],[54,8],[55,3],[52,3],[54,1],[55,1],[54,6],[55,1],[55,2],[55,3],[55,2],[53,7],[55,6],[0,0],[0,0],[55,4],[55,7],[55,6],[54,1],[54,1],[54,7],[0,0],[0,0],[52,3],[54,2],[53,2],[54,4],[52,5],[54,4],[54,8],[52,2],[55,5],[53,5],[52,2],[53,6],[52,1],[52,1],[55,7],[54,2],[55,5],[53,2],[54,6],[54,5],[52,4],[53,2],[53,5],[55,5],[55,2],[53,2],[55,7],[54,6],[53,1],[55,5],[53,2],[52,1],[55,2],[53,1],[53,5],[54,3],[52,2],[55,4],[53,2],[52,3],[53,2],[55,1],[52,5],[52,1],[54,4],[55,8],[52,3],[54,7],[54,7],[52,4],[54,3],[54,4],[53,3],[53,5],[55,6],[53,5],[55,7],[55,1],[54,2],[54,3],[54,2],[55,3],[55,6],[55,2],[52,2],[52,2],[54,2],[52,3],[55,1],[54,3],[53,4],[53,6],[54,3],[55,1],[52,5],[55,1],[52,2],[53,2],[54,5],[52,3],[53,4],[52,2],[52,1],[53,2],[53,4],[55,2],[53,1],[53,6],[52,1],[0,0],[0,0],[54,3],[55,7],[53,7],[55,3],[54,3],[55,4],[52,2],[52,1],[55,7],[55,2],[53,5],[54,2],[50,5],[54,2],[54,6],[51,1],[50,5],[53,5],[54,2],[53,2],[54,5],[53,8],[52,4],[52,2],[54,1],[52,4],[52,3],[54,3],[54,6],[54,4],[55,6],[54,5],[53,2],[54,1],[52,2],[55,1],[54,6],[54,7],[52,3],[54,5],[53,1],[53,6],[55,4],[55,2],[54,7],[55,1],[54,1],[55,2],[52,6],[55,4],[55,1],[55,1],[55,2],[55,3],[55,3],[55,4],[53,2],[52,5],[52,3],[55,2],[53,1],[54,3],[54,1],[53,4],[52,2],[53,3],[52,6],[54,2],[53,3],[55,2],[52,2],[52,5],[55,2],[55,5],[55,3],[54,6],[52,6],[53,1],[54,2],[53,2],[54,3],[54,5],[55,1],[55,2],[54,6],[55,1],[55,2],[52,3],[55,6],[54,6],[54,3],[53,8],[54,1],[54,1],[55,1],[52,1],[53,4],[54,5],[53,6],[54,8],[0,0],[0,0],[53,8],[55,3],[55,2],[52,1],[52,4],[0,0],[0,0],[53,1],[53,2],[54,1],[52,1],[53,4],[55,3],[55,8],[54,3],[54,2],[53,2],[53,1],[53,6],[55,2],[55,5],[55,3],[55,2],[53,7],[55,6],[54,1],[55,4],[55,3],[54,1],[52,6],[50,5],[55,1],[54,5],[52,3],[54,2],[54,7],[53,6],[54,6],[53,1],[53,5],[55,5],[53,2],[53,2],[52,2],[52,4],[53,3],[54,5],[53,7],[54,1],[54,5],[53,1],[53,2],[53,4],[52,2],[55,5],[54,2],[54,6],[52,7],[54,4],[52,2],[53,2],[52,1],[52,3],[54,2],[54,7],[53,5],[53,4],[54,3],[53,1],[52,1],[54,2],[55,8],[54,1],[54,1],[52,1],[55,1],[55,4],[55,2],[55,1],[52,1],[55,4],[52,6],[55,5],[52,3],[52,3],[54,2],[55,2],[53,6],[55,1],[55,5],[52,4],[53,8],[53,1],[54,6],[54,1],[0,0],[0,0],[53,1],[55,7],[55,2],[52,7],[53,8],[52,1],[53,4],[54,2],[53,5],[54,5],[52,1],[54,5],[53,1],[55,1],[55,3],[54,6],[53,2],[53,1],[52,1],[55,3],[53,7],[54,6],[55,3],[52,7],[53,1],[55,8],[53,5],[53,3],[55,4],[54,6],[0,0],[0,0],[54,7],[53,3],[54,3],[53,2],[53,3],[53,3],[52,2],[54,1],[52,3],[54,5],[54,4],[55,2],[55,7],[52,7],[52,2],[55,3],[53,5],[52,1],[55,3],[52,3],[55,4],[53,2],[52,6],[52,5],[52,2],[52,1],[54,5],[55,1],[53,2],[52,7],[53,1],[55,3],[54,7],[55,6],[52,1],[54,1],[54,4],[52,6],[55,1],[52,1],[54,2],[54,2],[53,1],[55,6],[55,1],[52,8],[52,1],[53,4],[52,1],[54,4],[54,3],[54,5],[55,2],[53,8],[53,1],[55,5],[54,1],[52,3],[52,2],[53,2],[54,1],[55,5],[54,2],[55,3],[54,2],[52,6],[54,5],[55,2],[53,8],[0,0],[0,0],[55,2],[53,6],[55,4],[55,4],[55,1],[55,1],[55,3],[0,0],[0,0],[0,0],[55,6],[54,2],[55,3],[52,2],[52,1],[54,1],[53,2],[52,1],[55,6],[53,3],[54,8],[52,8],[53,1],[52,6],[54,1],[52,1],[53,2],[52,3],[53,6],[53,6],[53,1],[53,3],[54,5],[54,7],[55,4],[55,8],[55,8],[55,3],[54,3],[52,2],[55,1],[52,1],[54,5],[54,1],[55,4],[54,2],[54,2],[54,4],[54,5],[52,3],[55,1],[53,3],[53,2],[53,6],[52,5],[54,7],[55,1],[54,8],[54,1],[53,1],[55,3],[53,2],[53,3],[54,3],[52,5],[52,6],[53,2],[52,5],[53,6],[55,1],[53,2],[54,4],[52,5],[55,3],[54,7],[54,3],[53,7],[55,4],[52,3],[52,8],[52,3],[52,6],[54,4],[52,4],[52,2],[53,6],[52,7],[52,2],[54,1],[54,4],[52,4],[53,2],[52,8],[52,4],[0,0],[0,0],[54,7],[55,4],[55,2],[54,2],[53,2],[52,3],[52,5],[53,1],[52,6],[54,7],[54,5],[53,7],[54,2],[54,3],[55,7],[54,4],[55,2],[55,2],[54,2],[54,2],[53,6],[54,3],[54,4],[54,6],[55,1],[55,1],[55,8],[52,1],[54,4],[52,1],[55,8],[0,0],[0,0],[54,7],[53,4],[55,5],[55,3],[55,7],[53,1],[55,5],[54,2],[53,3],[55,2],[52,5],[54,2],[50,5],[53,6],[53,7],[52,7],[54,3],[53,1],[53,2],[53,5],[52,2],[53,4],[53,2],[55,3],[53,2],[52,3],[52,5],[54,1],[55,7],[53,1],[54,4],[53,3],[52,3],[55,3],[53,6],[52,2],[53,2],[55,7],[54,7],[52,7],[54,6],[54,2],[55,1],[52,1],[55,5],[52,5],[52,2],[52,2],[53,3],[52,2],[54,3],[53,6],[52,2],[53,1],[53,1],[54,2],[54,6],[52,2],[55,3],[53,2],[54,2],[55,2],[53,6],[53,2],[53,3],[52,2],[54,6],[55,7],[54,2],[54,1],[0,0],[0,0],[53,2],[53,7],[54,7],[55,3],[55,4],[52,4],[0,0],[0,0],[0,0],[52,7],[52,5],[54,4],[52,5],[50,5],[54,1],[54,6],[55,1],[55,6],[54,7],[54,2],[55,5],[54,3],[55,5],[52,4],[52,7],[53,1],[54,3],[52,3],[55,7],[55,4],[52,3],[55,1],[53,2],[52,3],[54,5],[53,1],[53,7],[55,3],[54,3],[54,3],[54,5],[53,3],[52,1],[52,2],[52,1],[55,5],[53,5],[55,6],[54,3],[53,5],[54,5],[55,2],[53,5],[53,3],[53,1],[54,7],[54,5],[55,2],[52,3],[53,2],[54,1],[55,1],[52,3],[52,5],[55,3],[53,5],[53,3],[54,1],[53,5],[52,1],[52,6],[54,3],[55,1],[54,5],[52,7],[55,6],[54,7],[54,3],[53,3],[53,3],[54,3],[52,2],[54,2],[54,3],[55,6],[53,2],[54,3],[54,4],[52,3],[52,2],[54,2],[53,2],[0,0],[0,0],[55,6],[53,3],[52,2],[55,5],[55,4],[55,5],[55,7],[53,1],[55,3],[53,4],[53,7],[55,1],[50,5],[55,3],[54,1],[52,4],[54,4],[52,2],[53,3],[54,2],[55,3],[53,8],[54,2],[52,2],[52,2],[53,7],[54,6],[55,2],[52,8],[52,1],[53,1],[55,5],[0,0],[0,0],[54,1],[53,6],[55,5],[54,1],[53,2],[54,4],[53,3],[52,8],[54,3],[55,3],[52,1],[53,5],[55,2],[55,4],[54,8],[54,2],[55,5],[53,8],[52,4],[54,7],[53,3],[52,4],[52,1],[52,5],[55,2],[53,7],[55,4],[53,3],[55,4],[54,8],[52,3],[54,2],[55,2],[55,4],[54,6],[55,4],[53,2],[54,2],[55,2],[52,2],[52,4],[53,7],[54,5],[52,3],[52,1],[52,2],[52,3],[54,3],[54,1],[54,2],[55,4],[52,1],[55,1],[55,7],[53,4],[54,2],[54,2],[54,1],[54,4],[55,2],[54,3],[54,7],[53,7],[52,1],[54,1],[52,3],[55,2],[52,8],[53,3],[54,4],[0,0],[0,0],[54,8],[54,1],[52,6],[52,7],[55,3],[52,3],[0,0],[0,0],[0,0],[52,1],[55,1],[55,1],[55,3],[53,8],[53,2],[55,2],[52,8],[52,6],[55,2],[53,5],[52,6],[55,1],[53,5],[52,1],[54,2],[53,2],[52,4],[55,7],[54,5],[53,2],[53,5],[52,4],[53,5],[53,2],[53,1],[54,1],[54,3],[55,2],[52,5],[53,5],[55,7],[55,6],[54,2],[53,1],[55,1],[52,8],[54,2],[54,7],[53,3],[52,2],[53,6],[55,1],[55,4],[54,5],[52,3],[53,4],[52,5],[54,4],[55,5],[55,6],[55,3],[55,2],[55,4],[54,1],[53,1],[0,0],[0,0],[52,1],[52,7],[55,2],[55,7],[52,2],[52,6],[55,1],[52,3],[53,5],[53,7],[54,5],[52,1],[52,7],[53,6],[52,3],[53,6],[53,2],[52,2],[55,3],[54,1],[53,6],[53,3],[50,5],[55,2],[0,0],[0,0],[55,3],[52,2],[53,5],[54,2],[55,7],[53,3],[52,1],[52,2],[54,6],[53,3],[54,2],[55,2],[53,7],[54,7],[55,1],[54,3],[55,5],[53,6],[55,3],[55,1],[55,7],[52,7],[52,3],[55,3],[54,5],[55,3],[55,2],[53,1],[54,6],[50,5],[54,8],[53,7],[55,5],[0,0],[0,0],[0,0],[54,4],[54,4],[53,2],[53,2],[53,2],[54,3],[55,4],[54,5],[55,1],[54,2],[53,5],[54,4],[54,2],[52,2],[52,2],[55,2],[52,3],[52,4],[53,3],[52,2],[55,7],[53,3],[54,2],[52,4],[53,3],[55,4],[54,2],[53,5],[53,3],[53,3],[52,8],[53,7],[54,8],[55,5],[52,2],[52,5],[53,1],[52,6],[54,5],[55,1],[54,1],[55,3],[54,3],[53,2],[54,6],[52,2],[55,6],[54,2],[52,1],[52,3],[52,7],[55,6],[55,5],[55,4],[54,2],[54,4],[55,3],[53,2],[55,3],[54,7],[53,4],[54,3],[53,2],[54,3],[52,6],[55,1],[55,2],[54,2],[0,0],[0,0],[54,4],[55,7],[54,1],[54,5],[52,4],[53,7],[55,5],[54,4],[53,6],[53,3],[0,0],[0,0],[53,1],[54,5],[53,4],[54,1],[53,1],[55,3],[53,3],[55,3],[54,7],[53,8],[53,7],[53,1],[54,4],[54,3],[54,3],[52,5],[54,5],[55,2],[52,2],[53,4],[54,3],[54,2],[54,4],[53,1],[55,4],[55,7],[53,2],[53,1],[55,7],[54,7],[52,8],[54,6],[54,6],[54,5],[55,1],[54,1],[55,5],[55,4],[53,2],[53,3],[54,3],[55,7],[52,7],[55,8],[55,5],[55,1],[53,4],[53,2],[53,3],[52,8],[54,5],[53,7],[55,1],[54,1],[0,0],[0,0],[55,2],[55,2],[52,7],[52,1],[55,1],[53,2],[55,2],[52,4],[55,2],[55,7],[54,7],[55,1],[55,8],[53,2],[55,4],[53,3],[52,3],[55,6],[53,2],[54,4],[55,2],[52,6],[53,1],[0,0],[0,0],[55,7],[55,2],[54,4],[54,6],[52,5],[54,8],[53,2],[54,7],[53,2],[55,1],[52,2],[55,5],[54,5],[55,7],[52,3],[52,3],[53,4],[55,1],[53,8],[54,2],[55,6],[53,2],[55,1],[53,8],[55,6],[52,3],[52,4],[53,2],[53,1],[53,3],[54,1],[55,3],[55,1],[52,7],[0,0],[0,0],[0,0],[54,6],[53,3],[54,3],[53,4],[52,1],[54,5],[54,3],[55,3],[53,3],[53,2],[53,4],[52,7],[55,1],[52,6],[52,5],[55,6],[54,2],[53,1],[55,5],[54,4],[54,4],[54,2],[55,1],[53,1],[52,6],[52,3],[54,3],[54,7],[53,1],[54,2],[52,2],[52,3],[54,8],[54,7],[55,4],[55,6],[54,1],[52,4],[52,2],[52,1],[52,3],[55,2],[54,1],[55,2],[52,8],[54,3],[53,3],[52,2],[53,1],[53,5],[55,6],[55,7],[53,3],[52,6],[54,2],[53,5],[54,5],[52,4],[53,2],[52,3],[52,2],[53,2],[53,1],[55,1],[53,5],[55,3],[54,4],[54,2],[0,0],[0,0],[54,3],[53,4],[52,1],[55,4],[54,7],[54,7],[50,5],[52,7],[55,3],[55,7],[0,0],[0,0],[55,6],[52,3],[52,6],[53,5],[54,2],[54,2],[53,2],[55,3],[55,2],[52,2],[55,2],[55,7],[53,5],[54,2],[54,2],[53,3],[55,7],[54,1],[54,5],[50,5],[53,4],[52,5],[54,6],[54,2],[53,1],[54,7],[55,2],[55,5],[52,1],[52,4],[52,2],[53,1],[53,2],[54,1],[53,4],[53,3],[52,3],[53,7],[52,3],[53,3],[52,5],[54,6],[53,2],[53,1],[54,3],[54,2],[53,6],[55,2],[55,4],[54,6],[53,5],[53,5],[53,2],[50,5],[0,0],[0,0],[53,1],[53,6],[53,1],[54,7],[53,3],[54,2],[53,1],[53,4],[53,2],[53,2],[55,5],[53,7],[52,2],[52,1],[53,3],[52,1],[54,2],[52,6],[55,4],[52,1],[52,5],[55,5],[0,0],[0,0],[52,1],[55,1],[53,2],[52,7],[55,5],[55,6],[53,6],[54,4],[55,5],[54,5],[54,1],[54,2],[52,3],[52,5],[53,3],[55,8],[54,2],[55,4],[53,2],[53,3],[54,7],[55,7],[53,6],[53,7],[55,1],[54,1],[55,6],[55,1],[52,6],[53,7],[55,2],[54,8],[55,4],[54,1],[53,1],[54,2],[0,0],[55,1],[53,2],[55,3],[53,2],[52,4],[55,7],[54,1],[53,3],[55,8],[55,1],[53,1],[55,7],[52,3],[55,7],[52,1],[55,1],[53,2],[55,2],[53,2],[52,3],[53,3],[52,1],[53,3],[52,4],[55,2],[53,1],[52,6],[54,1],[52,5],[55,7],[54,1],[53,7],[53,3],[55,2],[55,3],[52,1],[52,2],[52,6],[54,7],[55,3],[53,2],[54,1],[52,5],[55,2],[53,1],[53,3],[55,3],[55,1],[54,5],[53,8],[54,4],[55,2],[52,1],[54,3],[54,5],[54,8],[55,1],[53,8],[55,2],[52,2],[52,1],[52,2],[52,1],[54,6],[53,1],[53,3],[52,3],[52,2],[54,2],[52,7],[0,0],[0,0],[54,1],[52,2],[55,5],[52,2],[54,3],[55,3],[54,6],[52,2],[55,6],[54,3],[53,3],[52,3],[54,3],[54,2],[52,7],[55,2],[53,1],[54,5],[54,7],[55,5],[52,8],[54,1],[55,4],[55,2],[53,7],[52,1],[54,2],[53,8],[54,2],[53,6],[52,1],[53,6],[54,8],[55,4],[55,3],[53,5],[52,3],[55,3],[55,7],[52,2],[54,3],[52,1],[53,2],[52,1],[53,1],[54,2],[52,2],[53,2],[52,3],[55,8],[55,3],[53,3],[52,3],[55,5],[55,2],[54,4],[55,3],[50,5],[53,1],[52,3],[53,2],[52,4],[52,6],[52,2],[54,5],[55,1],[55,5],[0,0],[0,0],[55,7],[53,8],[52,1],[52,6],[53,4],[54,3],[53,2],[53,2],[53,7],[53,2],[53,5],[52,1],[55,4],[53,3],[55,1],[52,4],[54,1],[54,4],[52,5],[54,6],[0,0],[53,2],[53,4],[54,7],[55,6],[54,1],[53,7],[52,8],[52,4],[54,2],[52,3],[55,2],[52,2],[55,8],[53,4],[53,1],[54,6],[52,1],[52,2],[52,2],[54,1],[55,6],[54,2],[54,4],[52,3],[53,7],[54,1],[52,2],[54,2],[54,4],[54,4],[54,5],[54,6],[52,2],[55,1],[53,2],[53,7],[0,0],[0,0],[54,4],[53,3],[52,2],[52,1],[53,7],[55,2],[52,4],[54,1],[52,4],[54,1],[55,1],[55,1],[54,6],[53,1],[53,3],[53,1],[55,1],[54,6],[55,7],[54,3],[50,5],[54,3],[54,3],[55,4],[54,5],[52,1],[53,3],[55,3],[54,8],[54,8],[55,1],[55,1],[55,3],[55,2],[55,2],[54,4],[53,7],[53,2],[52,2],[52,2],[55,3],[55,6],[53,7],[55,5],[55,8],[54,2],[54,2],[53,1],[54,4],[53,2],[54,2],[55,3],[52,1],[54,2],[55,8],[55,2],[55,2],[53,2],[54,3],[53,6],[52,5],[54,1],[55,6],[53,5],[54,4],[50,5],[55,2],[55,3],[52,3],[52,2],[0,0],[0,0],[52,1],[55,4],[55,4],[55,3],[55,2],[52,1],[52,6],[55,5],[54,7],[55,6],[53,3],[54,2],[55,7],[54,1],[55,5],[54,1],[53,4],[54,2],[55,2],[52,4],[53,4],[54,1],[55,4],[52,3],[53,1],[55,7],[54,3],[53,6],[55,8],[53,1],[52,4],[52,8],[52,6],[52,1],[54,8],[53,2],[55,7],[55,1],[54,3],[54,2],[52,1],[55,4],[54,1],[55,5],[53,2],[53,4],[52,5],[53,5],[55,3],[52,6],[55,6],[50,5],[55,4],[52,5],[52,1],[53,2],[54,1],[52,3],[54,7],[55,2],[52,6],[50,5],[53,5],[52,2],[52,6],[0,0],[53,4],[0,0],[0,0],[55,4],[54,3],[53,1],[53,6],[53,1],[52,1],[54,1],[53,2],[52,2],[55,1],[52,1],[55,7],[52,5],[52,3],[54,7],[54,1],[52,1],[55,6],[55,6],[52,3],[53,3],[0,0],[0,0],[53,3],[53,2],[54,2],[52,4],[54,1],[55,3],[52,7],[54,5],[53,3],[55,1],[55,4],[53,1],[55,1],[52,3],[52,2],[55,2],[55,4],[53,6],[53,2],[52,1],[53,6],[53,8],[55,5],[53,5],[54,3],[52,2],[52,3],[55,8],[54,8],[52,5],[53,6],[53,2],[54,5],[52,3],[0,0],[0,0],[53,2],[54,3],[53,3],[52,7],[55,2],[54,2],[54,3],[53,3],[53,1],[54,7],[54,4],[55,3],[55,5],[52,8],[55,1],[52,3],[53,2],[55,2],[54,4],[54,2],[52,3],[52,4],[53,2],[55,1],[54,4],[52,5],[55,4],[54,4],[52,7],[54,1],[52,2],[55,7],[55,7],[55,1],[55,3],[53,2],[53,6],[53,2],[53,6],[54,4],[52,5],[52,4],[55,1],[55,3],[53,2],[54,6],[55,4],[54,7],[55,1],[54,1],[54,1],[53,2],[52,4],[53,1],[55,8],[0,0],[0,0],[54,2],[52,1],[52,8],[54,3],[53,1],[54,2],[53,5],[54,4],[55,2],[52,3],[55,2],[50,5],[0,0],[0,0],[55,3],[54,1],[54,3],[54,6],[52,1],[55,1],[52,2],[53,3],[55,7],[52,1],[53,1],[54,4],[53,4],[54,5],[54,3],[54,2],[53,2],[54,5],[52,5],[53,7],[53,7],[55,6],[52,5],[52,3],[52,2],[54,8],[52,2],[54,1],[51,7],[53,6],[54,8],[53,7],[53,4],[53,3],[55,4],[54,6],[54,3],[55,4],[54,2],[52,6],[55,8],[54,1],[53,1],[54,1],[53,3],[53,8],[53,2],[53,3],[53,4],[54,2],[53,7],[52,4],[55,1],[54,7],[54,1],[50,5],[55,5],[52,5],[52,3],[54,4],[52,5],[53,6],[52,1],[55,1],[55,2],[54,6],[53,1],[55,5],[52,8],[53,4],[55,7],[52,1],[55,2],[55,8],[53,1],[55,2],[53,1],[54,2],[52,4],[54,7],[52,3],[53,8],[53,7],[55,1],[52,2],[53,2],[54,3],[54,2],[54,6],[54,2],[53,8],[0,0],[0,0],[55,8],[53,3],[53,7],[53,3],[53,8],[53,2],[52,7],[53,1],[54,1],[54,7],[53,3],[52,1],[52,2],[52,3],[54,6],[55,1],[53,2],[54,2],[54,3],[54,4],[50,5],[52,7],[52,8],[55,6],[54,7],[53,1],[54,6],[55,5],[52,4],[55,2],[53,4],[54,8],[54,1],[52,2],[55,1],[0,0],[53,2],[53,7],[53,1],[53,8],[55,2],[53,2],[53,2],[52,8],[54,4],[55,4],[55,2],[54,4],[52,3],[54,2],[53,2],[53,7],[53,3],[53,5],[53,2],[54,1],[52,5],[54,8],[52,5],[54,3],[55,4],[55,4],[54,5],[54,1],[53,7],[52,3],[55,5],[54,6],[53,8],[55,6],[53,2],[55,1],[52,4],[53,6],[54,6],[53,6],[53,1],[54,7],[53,1],[53,4],[52,2],[54,1],[54,4],[55,4],[54,1],[52,1],[55,8],[54,2],[54,4],[52,1],[54,6],[0,0],[0,0],[53,4],[55,4],[53,6],[54,2],[52,4],[53,4],[52,3],[52,3],[53,4],[52,6],[53,3],[52,3],[0,0],[0,0],[53,1],[53,6],[54,7],[52,5],[54,7],[52,2],[53,3],[52,1],[53,1],[53,5],[54,2],[52,4],[55,2],[50,5],[52,3],[54,1],[55,1],[54,7],[54,3],[55,6],[53,1],[54,7],[55,8],[52,5],[53,4],[53,1],[52,6],[55,7],[54,2],[55,5],[54,1],[52,8],[55,4],[52,4],[55,3],[52,1],[53,2],[53,3],[53,1],[55,2],[52,2],[54,1],[55,2],[55,3],[53,1],[54,4],[54,5],[54,6],[53,8],[50,5],[54,6],[53,5],[55,8],[52,1],[54,3],[53,7],[52,6],[53,3],[54,1],[52,4],[55,4],[53,4],[54,7],[54,3],[54,3],[52,4],[54,2],[55,3],[0,0],[0,0],[54,4],[52,7],[55,3],[54,2],[53,4],[54,1],[54,3],[54,3],[54,5],[55,6],[52,8],[52,2],[55,1],[55,4],[54,5],[55,1],[52,7],[52,8],[54,5],[55,6],[54,3],[54,1],[53,3],[54,2],[52,5],[53,1],[53,1],[53,1],[54,1],[53,5],[54,5],[52,3],[54,5],[54,2],[55,3],[55,2],[55,3],[52,2],[54,3],[54,3],[55,4],[55,2],[53,5],[54,1],[54,4],[54,1],[53,4],[52,3],[55,6],[53,6],[55,2],[55,5],[54,4],[53,1],[53,1],[55,7],[55,6],[0,0],[0,0],[52,2],[54,3],[52,5],[52,1],[53,4],[52,8],[53,5],[52,3],[52,7],[54,3],[54,3],[52,4],[55,5],[53,7],[0,0],[0,0],[54,8],[54,1],[52,4],[55,2],[54,1],[53,1],[52,4],[53,4],[52,4],[52,3],[55,5],[53,1],[52,4],[54,2],[54,2],[55,2],[55,5],[52,2],[53,3],[54,2],[54,3],[52,3],[55,2],[54,1],[52,8],[53,4],[52,4],[52,5],[52,3],[55,1],[52,2],[52,6],[55,3],[53,2],[52,2],[52,2],[52,1],[53,2],[55,3],[0,0],[54,3],[55,6],[54,5],[53,7],[53,5],[54,3],[53,2],[52,3],[54,1],[52,6],[52,3],[54,7],[54,4],[53,2],[0,0],[0,0],[55,1],[55,8],[53,4],[53,3],[53,2],[54,3],[54,2],[53,7],[55,2],[53,6],[53,7],[53,5],[54,2],[54,1],[52,1],[53,3],[52,2],[55,1],[54,5],[53,2],[53,1],[53,1],[55,2],[54,2],[55,5],[54,4],[53,4],[55,2],[54,1],[52,6],[52,6],[52,2],[53,1],[53,3],[55,2],[52,4],[54,4],[52,3],[52,8],[53,5],[53,2],[53,1],[55,5],[55,4],[54,3],[55,6],[53,2],[54,5],[52,7],[54,1],[52,1],[52,3],[55,2],[54,7],[53,7],[53,1],[54,3],[53,1],[52,4],[55,5],[54,5],[55,3],[55,4],[54,8],[54,2],[55,6],[53,2],[0,0],[0,0],[50,5],[54,3],[54,4],[54,1],[54,5],[54,3],[52,2],[53,5],[52,2],[54,2],[55,8],[55,2],[55,3],[55,2],[54,6],[53,3],[54,1],[55,2],[55,1],[52,3],[54,2],[0,0],[0,0],[52,1],[53,2],[54,6],[52,1],[54,7],[53,4],[53,7],[55,3],[55,2],[52,1],[55,3],[53,2],[52,6],[54,7],[54,4],[54,6],[0,0],[0,0],[52,3],[54,3],[53,4],[53,1],[54,7],[52,7],[53,1],[52,7],[53,1],[54,5],[54,1],[50,5],[54,1],[54,4],[54,2],[52,2],[0,0],[0,0],[54,1],[55,3],[52,2],[54,6],[54,2],[53,2],[54,8],[53,2],[52,1],[54,2],[55,6],[55,8],[54,3],[55,4],[0,0],[0,0],[53,6],[53,3],[52,6],[53,7],[54,2],[53,1],[53,4],[52,2],[53,1],[54,1],[53,5],[55,4],[54,8],[54,2],[54,1],[53,1],[53,2],[53,5],[52,6],[52,1],[54,6],[53,1],[53,1],[52,6],[52,4],[55,2],[52,3],[52,2],[54,8],[55,2],[53,4],[52,6],[53,2],[52,2],[54,3],[54,1],[55,4],[52,3],[52,7],[55,6],[54,2],[0,0],[0,0],[53,3],[54,5],[55,3],[55,1],[54,1],[53,1],[54,4],[52,1],[54,6],[52,2],[52,4],[0,0],[0,0],[54,5],[52,1],[52,7],[52,7],[53,6],[53,1],[55,3],[50,5],[54,4],[55,4],[52,3],[53,1],[54,2],[53,6],[52,1],[54,3],[53,4],[55,3],[52,2],[54,4],[52,2],[52,2],[52,6],[55,1],[54,1],[53,2],[54,2],[55,6],[53,1],[54,1],[55,3],[54,3],[52,3],[55,2],[55,6],[52,2],[53,3],[55,2],[55,1],[55,6],[55,8],[53,8],[54,1],[52,8],[55,1],[55,7],[55,2],[54,5],[55,6],[55,1],[55,4],[53,3],[55,6],[54,2],[54,7],[53,2],[54,7],[52,1],[55,2],[55,8],[54,4],[54,2],[53,6],[53,7],[55,2],[53,2],[54,1],[54,7],[53,1],[0,0],[0,0],[0,0],[54,6],[54,5],[54,2],[55,5],[55,2],[53,1],[54,2],[52,1],[53,5],[53,7],[52,3],[55,4],[52,2],[52,5],[54,5],[55,2],[52,5],[55,4],[0,0],[0,0],[53,4],[52,6],[52,1],[53,5],[55,2],[55,5],[52,7],[54,2],[54,4],[54,5],[53,6],[52,4],[53,3],[55,3],[54,2],[54,1],[0,0],[0,0],[53,3],[53,4],[54,2],[54,5],[52,3],[55,2],[54,3],[55,2],[53,3],[55,1],[54,4],[52,3],[52,5],[52,5],[53,6],[52,3],[52,2],[0,0],[0,0],[0,0],[52,4],[52,6],[52,8],[52,2],[53,7],[54,1],[55,2],[55,6],[52,3],[52,7],[50,5],[55,2],[0,0],[52,8],[54,7],[55,2],[55,5],[55,1],[53,1],[53,4],[52,5],[55,4],[54,5],[53,2],[52,1],[52,1],[52,3],[53,5],[52,5],[52,5],[55,5],[53,7],[52,6],[55,5],[54,1],[53,4],[52,2],[54,2],[52,2],[53,6],[55,4],[53,3],[53,2],[52,2],[53,3],[55,4],[53,4],[54,4],[55,1],[54,1],[52,4],[52,3],[55,5],[0,0],[53,1],[0,0],[0,0],[53,1],[52,2],[55,3],[54,6],[55,4],[55,2],[52,5],[53,3],[52,5],[55,6],[0,0],[0,0],[53,4],[53,8],[52,1],[53,4],[55,6],[53,2],[53,4],[55,6],[52,6],[52,2],[55,7],[55,4],[55,6],[55,3],[52,2],[53,8],[53,3],[52,1],[53,1],[54,3],[55,5],[55,7],[52,6],[54,7],[53,7],[55,7],[52,1],[54,8],[53,8],[55,1],[53,1],[54,3],[54,2],[54,4],[55,4],[54,6],[55,4],[55,1],[52,6],[52,7],[55,4],[55,5],[52,5],[55,2],[52,4],[55,2],[52,3],[54,5],[53,4],[55,2],[55,1],[53,2],[54,7],[55,1],[54,3],[52,4],[52,4],[53,5],[55,3],[53,3],[54,2],[55,2],[52,4],[53,2],[55,2],[53,1],[54,8],[53,1],[52,7],[52,3],[0,0],[0,0],[0,0],[54,5],[55,3],[53,6],[55,1],[53,8],[55,6],[54,6],[55,5],[55,1],[52,1],[53,3],[55,1],[52,4],[52,3],[55,8],[52,7],[53,1],[54,2],[55,2],[0,0],[52,1],[52,3],[52,5],[53,6],[53,3],[54,1],[54,5],[52,1],[53,5],[52,7],[53,8],[53,7],[52,4],[54,1],[55,7],[52,5],[0,0],[52,4],[53,5],[54,5],[53,3],[54,3],[54,1],[54,2],[53,1],[54,3],[53,7],[52,1],[55,4],[54,1],[54,3],[54,8],[50,5],[55,3],[53,5],[54,6],[53,5],[53,4],[52,2],[52,2],[55,7],[54,1],[54,3],[54,4],[53,7],[53,3],[55,5],[52,5],[52,3],[53,7],[52,2],[55,8],[0,0],[0,0],[53,5],[55,7],[53,4],[53,2],[54,5],[52,1],[55,2],[52,5],[54,3],[55,1],[54,1],[53,1],[55,6],[53,1],[52,1],[52,6],[52,6],[55,4],[54,1],[52,2],[55,6],[54,3],[54,2],[53,5],[54,4],[52,2],[54,3],[55,2],[52,3],[54,8],[52,4],[54,4],[52,2],[55,3],[52,1],[55,8],[53,2],[54,1],[52,1],[53,3],[53,1],[53,5],[53,5],[55,7],[53,3],[53,1],[52,1],[55,3],[54,2],[55,2],[54,1],[0,0],[0,0],[53,2],[52,5],[55,3],[55,1],[53,7],[54,4],[54,2],[53,2],[53,3],[55,7],[52,2],[55,6],[54,1],[53,4],[53,3],[54,6],[54,1],[54,5],[52,3],[52,6],[55,4],[55,2],[53,3],[53,2],[52,1],[55,3],[54,2],[53,2],[55,2],[55,1],[52,2],[55,2],[54,1],[55,1],[53,3],[54,3],[54,6],[52,4],[53,3],[52,6],[52,6],[54,3],[53,4],[52,6],[52,3],[55,1],[54,3],[54,6],[52,6],[52,1],[52,3],[54,7],[55,4],[53,4],[52,2],[53,6],[54,2],[54,2],[54,8],[53,8],[55,4],[54,4],[52,1],[54,2],[54,4],[54,2],[55,7],[52,1],[53,6],[55,6],[0,0],[0,0],[0,0],[55,5],[53,1],[52,6],[54,7],[53,7],[52,1],[52,2],[55,2],[53,2],[54,2],[55,2],[52,2],[55,2],[52,6],[52,1],[53,3],[55,2],[53,2],[0,0],[0,0],[54,1],[55,1],[52,4],[55,1],[55,3],[53,5],[52,1],[55,7],[52,5],[55,5],[53,1],[54,7],[53,4],[54,2],[53,8],[55,8],[55,5],[55,1],[0,0],[0,0],[54,5],[55,2],[52,5],[55,2],[53,1],[53,1],[53,2],[53,1],[55,5],[52,1],[53,4],[55,6],[55,1],[55,1],[55,6],[55,6],[0,0],[0,0],[53,1],[53,6],[52,6],[52,6],[55,7],[54,6],[54,2],[54,6],[53,8],[52,7],[55,8],[52,3],[0,0],[54,6],[0,0],[0,0],[55,2],[55,5],[55,6],[54,1],[54,7],[52,3],[55,1],[55,4],[52,2],[54,1],[55,4],[55,2],[53,8],[54,2],[52,2],[54,2],[55,6],[52,5],[55,3],[55,8],[53,6],[52,3],[53,3],[55,4],[52,3],[52,2],[55,6],[55,7],[54,5],[54,7],[53,7],[54,3],[52,8],[54,8],[55,1],[54,8],[52,5],[52,3],[55,2],[0,0],[0,0],[54,7],[55,8],[52,1],[55,6],[53,3],[54,3],[55,3],[54,2],[53,5],[52,8],[53,1],[0,0],[0,0],[55,6],[52,2],[52,1],[52,8],[53,1],[54,4],[55,2],[52,2],[54,2],[52,1],[55,2],[55,1],[55,7],[52,3],[53,2],[55,2],[53,2],[54,5],[53,2],[53,2],[50,5],[52,5],[55,1],[54,7],[52,2],[53,1],[53,3],[52,3],[53,1],[55,1],[53,4],[54,6],[55,4],[53,1],[50,5],[53,1],[54,8],[52,1],[52,7],[55,3],[54,1],[52,1],[53,7],[52,2],[54,3],[53,4],[55,7],[52,2],[55,4],[53,5],[53,2],[54,6],[54,2],[54,2],[53,2],[53,5],[55,3],[55,4],[52,4],[53,3],[55,5],[55,2],[54,5],[52,8],[53,6],[52,5],[52,1],[54,1],[55,1],[54,1],[55,1],[52,7],[52,2],[53,3],[53,5],[55,3],[54,8],[52,1],[54,2],[55,1],[53,8],[52,3],[55,4],[54,1],[54,1],[55,5],[55,1],[53,5],[53,2],[55,2],[0,0],[0,0],[53,2],[54,4],[55,8],[53,6],[52,1],[55,8],[54,3],[53,4],[54,1],[54,7],[52,7],[52,4],[54,2],[53,3],[53,6],[55,1],[0,0],[52,1],[0,0],[0,0],[54,8],[55,4],[54,5],[52,2],[55,3],[52,1],[53,3],[54,5],[52,7],[53,2],[53,3],[55,2],[52,6],[55,3],[54,1],[54,4],[0,0],[0,0],[52,4],[52,3],[53,3],[54,6],[53,1],[54,4],[53,1],[55,5],[55,2],[52,3],[55,3],[55,4],[52,6],[55,1],[54,5],[55,7],[53,4],[53,6],[53,2],[52,1],[55,6],[52,8],[55,2],[53,5],[53,3],[53,8],[52,2],[53,5],[53,3],[54,2],[53,3],[53,2],[52,1],[55,4],[53,5],[55,2],[55,3],[55,2],[52,2],[55,2],[55,3],[52,1],[53,7],[53,1],[52,2],[54,8],[52,3],[53,4],[53,2],[53,1],[54,6],[54,8],[55,1],[54,7],[52,3],[0,0],[0,0],[55,4],[54,4],[54,6],[52,2],[55,1],[55,2],[55,7],[55,4],[52,1],[53,5],[53,4],[0,0],[0,0],[52,1],[55,2],[53,3],[52,3],[53,2],[53,6],[53,3],[52,2],[52,7],[54,3],[53,7],[52,1],[53,2],[53,6],[52,4],[52,7],[53,7],[55,4],[55,4],[50,5],[54,8],[52,2],[53,3],[52,4],[55,4],[55,6],[55,1],[55,5],[55,6],[53,3],[53,6],[54,1],[55,7],[52,3],[55,2],[54,4],[52,1],[55,3],[52,8],[53,2],[52,7],[54,2],[52,1],[55,7],[53,2],[52,1],[53,3],[53,7],[54,6],[54,8],[53,5],[54,4],[52,3],[55,4],[54,5],[53,7],[54,7],[55,6],[53,1],[54,2],[52,7],[53,2],[54,2],[54,5],[52,5],[52,1],[54,4],[52,2],[53,6],[54,6],[54,5],[53,2],[54,1],[55,1],[55,2],[55,4],[52,3],[52,1],[53,5],[53,7],[54,1],[53,6],[53,1],[54,7],[55,6],[52,7],[53,1],[54,2],[54,6],[0,0],[0,0],[52,5],[54,4],[54,4],[53,5],[52,6],[53,2],[52,6],[55,3],[52,3],[54,2],[53,7],[53,5],[53,6],[52,5],[53,5],[54,3],[54,1],[55,1],[52,2],[53,2],[55,6],[55,4],[53,2],[55,6],[52,1],[53,4],[54,3],[52,3],[52,7],[53,3],[55,3],[52,5],[54,7],[52,2],[53,2],[52,5],[53,2],[0,0],[55,6],[53,1],[54,2],[55,2],[53,7],[55,2],[54,6],[52,8],[55,2],[55,5],[52,6],[54,5],[52,6],[52,1],[54,1],[0,0],[0,0],[53,3],[52,3],[52,6],[54,5],[53,5],[53,1],[53,2],[52,2],[53,1],[54,1],[52,2],[55,4],[53,1],[52,4],[54,2],[53,5],[54,2],[53,2],[54,2],[55,7],[55,4],[54,3],[52,8],[55,1],[53,6],[52,6],[54,2],[53,6],[53,1],[55,6],[54,3],[53,2],[55,2],[54,4],[52,3],[55,5],[55,2],[54,3],[52,2],[54,1],[53,4],[0,0],[0,0],[0,0],[53,2],[55,1],[54,4],[53,5],[52,1],[53,8],[53,2],[0,0],[0,0],[52,6],[52,4],[54,3],[55,2],[55,2],[55,3],[53,3],[54,2],[52,2],[54,5],[53,5],[53,2],[55,2],[52,4],[52,5],[53,7],[55,4],[54,1],[53,2],[52,2],[52,2],[53,3],[54,1],[55,7],[50,5],[55,6],[52,2],[53,4],[52,2],[55,7],[52,1],[52,2],[52,5],[53,7],[54,1],[54,3],[52,2],[52,5],[54,1],[52,5],[52,5],[53,2],[54,7],[54,3],[53,1],[54,2],[54,3],[54,5],[54,1],[55,7],[54,5],[53,4],[54,2],[52,6],[52,3],[53,5],[53,5],[55,2],[55,1],[55,6],[55,7],[55,2],[54,1],[53,4],[54,1],[54,1],[52,3],[52,2],[50,5],[52,7],[53,1],[53,1],[55,1],[53,2],[55,2],[53,2],[55,8],[54,5],[54,2],[52,3],[55,4],[53,5],[52,3],[55,2],[55,3],[55,5],[53,4],[53,5],[53,6],[52,5],[54,2],[54,1],[54,1],[54,3],[54,2],[53,3],[53,1],[55,4],[55,2],[52,6],[52,2],[54,1],[52,5],[55,7],[52,6],[55,2],[50,5],[53,1],[53,3],[52,7],[53,6],[0,0],[0,0],[52,3],[54,7],[54,6],[54,3],[50,5],[55,8],[53,6],[54,5],[53,5],[53,4],[54,5],[54,6],[54,5],[55,2],[54,2],[55,2],[54,4],[53,1],[0,0],[0,0],[53,6],[52,1],[54,8],[54,3],[52,3],[55,4],[52,6],[52,5],[54,8],[52,2],[55,2],[53,2],[0,0],[0,0],[54,7],[53,3],[53,1],[54,4],[55,3],[52,2],[53,2],[54,5],[53,3],[53,1],[52,1],[52,1],[55,2],[52,3],[54,4],[54,3],[54,3],[54,2],[54,2],[55,2],[53,7],[55,6],[53,6],[54,1],[54,2],[52,3],[54,6],[52,3],[52,7],[54,1],[54,1],[53,7],[52,4],[53,1],[54,3],[55,3],[55,1],[55,5],[55,1],[52,1],[53,6],[0,0],[0,0],[0,0],[55,1],[53,1],[52,2],[53,5],[55,7],[53,6],[55,2],[0,0],[0,0],[53,5],[55,8],[54,2],[55,1],[54,1],[55,7],[54,6],[55,5],[52,2],[52,7],[55,6],[53,1],[52,1],[55,1],[52,2],[54,1],[54,2],[54,4],[55,1],[52,2],[53,5],[53,6],[54,3],[55,1],[55,6],[55,2],[53,6],[54,2],[53,3],[54,2],[55,2],[53,4],[55,3],[52,1],[55,6],[55,6],[53,5],[54,7],[55,1],[53,1],[55,6],[53,2],[53,6],[52,1],[55,4],[53,5],[54,1],[53,8],[53,8],[55,2],[52,4],[54,1],[52,5],[52,7],[55,2],[55,1],[52,1],[55,2],[54,8],[55,2],[53,1],[54,7],[53,2],[52,3],[54,2],[54,1],[52,3],[55,5],[53,3],[55,1],[55,6],[55,5],[54,1],[55,1],[52,2],[53,1],[54,6],[52,2],[55,1],[53,6],[54,7],[52,2],[55,5],[54,4],[55,1],[53,7],[54,1],[55,7],[55,1],[53,5],[0,0],[0,0],[53,6],[55,1],[52,2],[54,6],[53,2],[53,8],[54,3],[52,2],[54,4],[53,6],[55,3],[54,5],[53,3],[52,6],[55,8],[52,2],[54,1],[55,3],[54,6],[0,0],[0,0],[52,5],[54,6],[55,6],[52,2],[54,7],[53,6],[52,5],[52,2],[55,7],[54,4],[53,4],[55,7],[54,6],[54,2],[53,1],[53,2],[0,0],[54,5],[0,0],[0,0],[55,5],[55,2],[53,5],[54,1],[53,3],[53,1],[52,3],[55,3],[54,5],[53,3],[55,2],[54,4],[52,5],[55,2],[0,0],[0,0],[0,0],[54,3],[55,1],[55,5],[55,3],[54,3],[55,3],[53,3],[55,3],[55,2],[54,1],[52,6],[55,5],[53,1],[53,5],[53,8],[55,5],[52,7],[53,1],[53,2],[54,3],[54,6],[52,2],[54,5],[54,3],[53,3],[53,6],[50,5],[55,4],[55,3],[55,6],[55,3],[54,1],[53,1],[52,1],[53,4],[52,5],[52,6],[52,4],[0,0],[0,0],[0,0],[54,1],[55,1],[53,5],[54,5],[53,3],[55,2],[53,7],[53,3],[0,0],[0,0],[55,7],[54,7],[53,1],[52,3],[52,2],[52,2],[55,3],[54,1],[55,6],[54,2],[55,2],[53,2],[54,4],[55,5],[52,1],[54,7],[54,6],[55,4],[54,7],[54,2],[54,1],[52,2],[54,1],[55,7],[55,3],[55,7],[53,7],[55,6],[55,2],[53,3],[55,1],[53,3],[55,1],[52,3],[52,1],[53,5],[52,2],[55,4],[55,3],[55,1],[52,1],[53,1],[53,3],[52,1],[52,6],[55,3],[53,3],[52,4],[54,3],[53,1],[54,6],[54,4],[53,1],[52,1],[54,3],[54,6],[55,5],[50,5],[53,3],[53,2],[53,6],[53,1],[55,2],[55,6],[54,4],[52,4],[52,1],[54,4],[52,3],[52,7],[55,5],[52,8],[54,6],[55,1],[52,2],[53,5],[54,3],[53,4],[55,1],[52,2],[53,3],[52,4],[55,6],[53,1],[54,3],[54,5],[55,2],[52,4],[53,4],[0,0],[0,0],[55,7],[52,1],[55,4],[54,2],[53,2],[55,8],[55,5],[55,6],[53,1],[55,4],[52,5],[55,3],[55,3],[53,2],[55,3],[52,3],[52,2],[52,5],[54,7],[53,1],[54,1],[0,0],[0,0],[0,0],[53,5],[55,6],[53,1],[55,3],[54,2],[54,3],[54,5],[55,6],[53,7],[54,7],[53,1],[55,2],[55,4],[55,4],[53,7],[52,1],[53,4],[53,8],[53,5],[55,2],[52,1],[54,8],[52,1],[55,6],[53,2],[53,1],[52,2],[52,7],[53,8],[52,6],[53,3],[0,0],[0,0],[0,0],[53,1],[53,5],[54,1],[55,3],[54,1],[54,3],[54,2],[52,1],[55,5],[52,5],[52,2],[54,6],[54,8],[54,2],[54,3],[52,6],[52,7],[50,5],[53,1],[52,1],[54,2],[54,5],[52,2],[55,3],[52,5],[54,2],[55,5],[54,7],[52,3],[55,6],[55,2],[52,3],[53,7],[54,6],[53,3],[55,3],[53,7],[54,1],[54,3],[55,6],[54,5],[54,1],[54,3],[54,5],[52,2],[55,1],[53,1],[54,2],[54,1],[0,0],[0,0],[0,0],[52,2],[52,2],[55,3],[53,1],[54,2],[52,2],[53,1],[50,5],[52,2],[54,2],[54,2],[52,7],[52,3],[54,4],[53,3],[53,1],[55,4],[54,2],[55,4],[54,8],[54,4],[54,1],[53,4],[55,3],[52,2],[54,5],[53,1],[55,2],[52,2],[53,3],[54,7],[53,7],[54,2],[54,1],[55,5],[54,3],[52,7],[53,5],[54,4],[54,1],[55,2],[54,3],[55,3],[52,8],[54,1],[55,3],[52,5],[55,3],[55,5],[54,3],[55,5],[54,2],[52,3],[53,7],[52,5],[55,1],[53,1],[54,3],[52,6],[55,2],[52,6],[54,2],[54,7],[52,4],[54,4],[55,1],[53,6],[55,5],[53,4],[54,3],[52,6],[54,7],[54,7],[53,7],[53,3],[55,1],[53,3],[54,4],[52,2],[55,2],[52,3],[53,5],[55,4],[54,2],[54,6],[53,3],[53,3],[55,1],[0,0],[0,0],[53,2],[54,4],[55,1],[52,3],[52,3],[55,7],[52,7],[53,1],[55,7],[55,8],[55,3],[53,3],[54,7],[55,7],[52,2],[55,1],[52,4],[53,1],[55,5],[55,3],[53,2],[0,0],[0,0],[0,0],[54,5],[52,1],[55,2],[54,8],[55,4],[55,5],[53,3],[54,4],[52,2],[54,3],[54,6],[54,7],[54,2],[52,2],[55,1],[0,0],[0,0],[52,4],[54,7],[52,3],[52,1],[55,8],[52,3],[54,8],[54,3],[53,2],[55,5],[53,3],[53,1],[54,2],[54,7],[0,0],[0,0],[0,0],[53,8],[54,2],[54,2],[54,2],[53,1],[53,2],[52,4],[55,7],[54,3],[53,3],[55,1],[55,4],[55,3],[52,1],[52,4],[55,2],[53,2],[55,2],[54,3],[52,8],[52,3],[53,2],[54,5],[52,4],[52,2],[52,4],[55,3],[55,3],[52,6],[53,5],[54,3],[55,7],[55,4],[54,1],[53,6],[54,1],[53,1],[54,8],[53,2],[52,2],[54,3],[54,2],[55,4],[54,7],[55,1],[54,7],[54,6],[50,5],[55,6],[55,4],[55,8],[0,0],[0,0],[55,4],[54,6],[53,1],[53,1],[53,3],[55,4],[54,3],[52,3],[55,4],[53,1],[55,8],[52,1],[55,3],[53,3],[53,2],[55,2],[54,3],[54,1],[54,5],[55,3],[53,2],[53,2],[53,1],[55,5],[55,1],[53,2],[55,1],[53,2],[52,6],[53,8],[53,7],[55,2],[53,6],[52,4],[54,4],[52,2],[52,6],[54,2],[55,5],[55,3],[52,7],[54,4],[54,3],[54,2],[55,8],[52,6],[54,7],[53,6],[52,2],[53,1],[53,6],[54,2],[53,2],[53,1],[54,6],[53,2],[53,3],[53,1],[55,7],[55,2],[55,5],[55,3],[53,8],[53,4],[54,1],[52,3],[55,5],[55,7],[53,1],[52,3],[55,3],[52,8],[54,2],[54,2],[53,6],[52,8],[52,2],[55,8],[52,1],[53,1],[52,5],[55,2],[54,1],[54,1],[54,3],[55,3],[0,0],[0,0],[55,1],[52,2],[54,3],[52,3],[53,2],[52,7],[55,2],[55,8],[54,1],[55,2],[55,8],[53,1],[55,1],[55,4],[53,4],[53,1],[52,5],[54,2],[55,7],[54,1],[52,4],[52,2],[0,0],[0,0],[0,0],[50,5],[55,3],[53,5],[53,4],[55,5],[54,2],[53,4],[54,2],[54,7],[54,4],[55,8],[55,3],[54,3],[50,5],[55,1],[0,0],[0,0],[55,1],[55,3],[54,3],[53,6],[52,6],[54,5],[53,7],[55,4],[54,3],[54,4],[55,7],[53,3],[54,4],[53,5],[52,1],[55,3],[54,3],[52,2],[55,2],[52,7],[52,2],[54,3],[52,6],[55,5],[53,1],[53,6],[52,1],[54,1],[52,3],[53,5],[55,1],[54,4],[53,2],[54,1],[52,4],[54,2],[53,2],[52,1],[54,6],[54,1],[52,5],[55,1],[52,1],[52,8],[55,8],[55,2],[52,1],[55,1],[55,2],[53,2],[54,6],[52,1],[52,6],[54,4],[53,1],[54,6],[54,2],[53,2],[54,1],[52,7],[53,2],[53,5],[54,3],[53,3],[55,1],[55,6],[52,1],[55,1],[52,2],[0,0],[0,0],[53,3],[55,3],[54,6],[55,3],[54,3],[54,7],[53,6],[52,5],[54,1],[55,7],[54,1],[53,1],[53,3],[55,6],[53,3],[55,2],[50,5],[53,7],[53,2],[52,2],[55,4],[55,3],[55,3],[55,6],[54,3],[53,2],[54,2],[54,7],[55,1],[55,8],[52,2],[54,1],[52,8],[52,7],[54,3],[54,3],[55,2],[53,2],[54,1],[52,1],[55,5],[55,7],[52,2],[54,2],[52,7],[54,8],[52,2],[53,6],[53,6],[54,5],[52,5],[50,5],[55,5],[54,3],[52,7],[55,3],[55,1],[53,7],[53,4],[54,1],[54,3],[53,2],[52,2],[53,4],[54,1],[52,2],[55,8],[53,3],[52,5],[55,4],[53,3],[52,7],[53,6],[54,1],[54,3],[52,8],[52,2],[55,4],[55,3],[53,1],[55,1],[54,1],[52,3],[55,8],[0,0],[0,0],[55,5],[53,5],[52,1],[55,3],[54,8],[55,1],[55,3],[52,5],[54,2],[52,5],[52,3],[53,1],[52,8],[53,4],[54,3],[52,2],[52,2],[55,2],[53,2],[53,2],[54,4],[55,1],[54,3],[53,1],[52,4],[52,6],[53,2],[50,5],[53,4],[54,1],[52,3],[53,2],[53,3],[52,1],[54,1],[52,1],[52,1],[50,5],[55,3],[54,2],[55,7],[52,7],[53,1],[0,0],[0,0],[0,0],[52,1],[53,5],[54,2],[55,3],[52,1],[52,6],[53,1],[52,2],[52,1],[53,2],[55,5],[55,4],[54,4],[54,4],[52,2],[52,2],[55,5],[52,7],[52,6],[54,5],[52,2],[54,3],[52,7],[54,2],[52,5],[52,7],[54,2],[52,5],[53,1],[54,4],[52,6],[53,3],[55,4],[53,7],[54,2],[54,1],[52,1],[54,7],[55,3],[54,3],[55,1],[52,4],[54,3],[55,2],[55,8],[54,1],[52,1],[55,2],[52,4],[55,1],[54,8],[54,7],[53,5],[52,4],[54,1],[52,3],[52,8],[53,1],[52,2],[52,2],[53,6],[55,5],[53,3],[54,1],[52,1],[53,1],[0,0],[0,0],[53,6],[53,1],[52,5],[55,1],[54,3],[53,1],[52,4],[52,2],[54,1],[52,4],[55,1],[55,2],[52,5],[53,2],[55,6],[55,1],[53,7],[52,1],[53,2],[54,3],[52,4],[53,3],[53,2],[55,2],[52,3],[55,5],[54,5],[55,3],[52,3],[54,8],[55,2],[54,7],[55,2],[54,2],[55,1],[52,2],[52,7],[53,1],[52,2],[55,6],[53,2],[55,5],[54,4],[52,2],[55,2],[54,1],[55,6],[54,6],[52,1],[52,4],[54,1],[54,4],[53,8],[53,5],[54,4],[53,2],[53,1],[53,3],[54,7],[52,1],[54,4],[52,1],[54,1],[55,8],[55,6],[54,5],[53,1],[52,1],[52,2],[54,2],[52,1],[55,8],[53,7],[54,7],[53,3],[55,4],[54,5],[54,7],[53,2],[53,2],[53,1],[53,3],[53,1],[0,0],[0,0],[54,6],[52,6],[52,3],[55,2],[54,1],[52,1],[52,2],[54,2],[53,6],[52,4],[52,4],[54,7],[52,2],[53,1],[54,6],[54,1],[54,3],[55,5],[54,7],[55,1],[55,4],[53,1],[53,2],[52,4],[50,5],[54,1],[53,3],[53,5],[52,6],[55,3],[54,2],[55,2],[53,1],[54,4],[54,2],[52,5],[54,4],[55,8],[54,7],[55,6],[55,2],[53,2],[52,6],[52,5],[0,0],[0,0],[0,0],[55,7],[54,3],[52,5],[53,7],[53,2],[55,1],[55,6],[55,3],[54,2],[55,7],[54,5],[55,3],[55,3],[53,3],[53,1],[52,5],[55,7],[53,6],[53,8],[53,8],[55,5],[53,1],[55,1],[55,1],[55,1],[52,7],[55,2],[54,2],[54,8],[55,7],[52,5],[54,2],[53,6],[54,1],[52,3],[53,6],[54,5],[52,1],[55,2],[54,2],[52,2],[53,8],[54,1],[53,3],[53,3],[50,5],[54,3],[55,3],[54,6],[53,3],[55,1],[52,8],[52,3],[55,8],[55,1],[55,3],[52,4],[54,4],[55,3],[53,2],[55,6],[53,7],[52,1],[54,2],[53,4],[55,2],[55,2],[0,0],[52,2],[52,3],[55,2],[53,1],[54,3],[55,2],[55,3],[54,2],[54,1],[54,1],[53,2],[55,2],[55,6],[53,2],[52,3],[53,1],[54,2],[53,5],[53,7],[52,6],[54,1],[54,8],[53,3],[52,4],[53,3],[54,4],[55,1],[55,7],[55,5],[55,2],[53,3],[55,2],[55,6],[55,3],[54,3],[53,1],[52,4],[53,1],[53,7],[52,1],[53,7],[54,6],[52,1],[55,6],[54,8],[53,7],[55,1],[52,4],[54,2],[53,4],[53,2],[52,5],[52,3],[55,1],[53,5],[55,6],[55,4],[52,7],[54,6],[53,2],[54,4],[53,4],[52,3],[53,6],[53,6],[54,5],[52,8],[55,1],[54,2],[52,6],[53,1],[50,5],[52,5],[52,2],[54,6],[53,7],[53,5],[52,2],[52,3],[55,1],[54,4],[53,1],[0,0],[0,0],[52,3],[54,1],[53,5],[55,1],[55,3],[53,7],[53,5],[54,7],[52,4],[53,2],[54,4],[53,3],[52,4],[53,3],[52,4],[55,4],[52,2],[53,3],[52,2],[54,3],[52,7],[52,7],[54,7],[54,4],[52,5],[55,2],[53,2],[53,3],[53,1],[54,6],[54,2],[53,7],[53,3],[53,8],[54,1],[50,5],[54,8],[53,7],[55,6],[55,4],[52,4],[53,7],[55,2],[52,6],[54,5],[0,0],[0,0],[0,0],[55,4],[54,6],[53,2],[55,4],[55,6],[53,5],[54,2],[52,1],[54,7],[52,1],[54,3],[54,2],[53,3],[53,3],[53,1],[55,2],[55,3],[54,7],[55,6],[55,7],[55,1],[53,8],[52,1],[50,5],[53,5],[55,2],[52,7],[55,6],[52,8],[52,8],[54,1],[54,1],[55,1],[53,8],[55,7],[52,4],[55,1],[53,3],[52,4],[53,1],[54,2],[53,8],[52,1],[53,6],[54,7],[53,1],[53,6],[52,6],[52,2],[55,1],[55,1],[53,5],[53,5],[52,2],[54,5],[52,7],[52,2],[53,3],[52,6],[53,3],[53,2],[52,1],[53,7],[54,4],[53,6],[54,1],[55,5],[0,0],[53,2],[54,8],[54,7],[53,4],[54,1],[55,7],[53,1],[52,2],[53,1],[54,2],[55,2],[55,2],[53,1],[54,3],[52,6],[55,6],[55,1],[55,1],[54,3],[52,3],[54,3],[52,2],[54,5],[55,5],[53,1],[52,6],[54,2],[54,2],[55,1],[52,1],[54,3],[55,6],[55,2],[55,1],[54,6],[55,2],[52,2],[52,4],[54,8],[53,4],[52,4],[54,1],[55,2],[53,7],[54,5],[52,7],[52,2],[55,2],[52,2],[55,2],[52,7],[55,2],[52,5],[53,5],[53,2],[53,2],[53,4],[54,1],[53,2],[53,3],[54,2],[54,6],[54,3],[53,7],[53,2],[53,1],[53,1],[55,6],[55,2],[53,2],[53,4],[53,5],[52,2],[55,1],[52,6],[55,1],[53,4],[52,7],[52,1],[55,8],[52,4],[0,0],[0,0],[53,7],[50,5],[52,1],[54,5],[53,3],[53,5],[55,1],[55,8],[54,6],[55,6],[53,2],[55,1],[54,5],[53,6],[52,1],[52,2],[52,5],[55,3],[52,1],[54,5],[53,2],[52,5],[52,4],[53,6],[52,2],[52,3],[54,1],[53,2],[55,1],[54,2],[52,3],[55,1],[54,8],[54,2],[54,3],[54,2],[53,4],[53,1],[53,1],[53,1],[53,6],[55,5],[53,5],[55,2],[55,5],[52,2],[55,8],[52,6],[53,7],[55,8],[55,6],[55,1],[53,2],[52,3],[52,1],[53,3],[54,5],[55,5],[52,3],[52,1],[53,6],[52,4],[54,2],[53,3],[53,7],[53,3],[54,3],[54,1],[52,6],[52,5],[52,4],[55,2],[54,3],[55,8],[52,6],[52,5],[55,4],[54,5],[54,3],[54,4],[53,1],[55,2],[53,7],[55,1],[55,5],[55,3],[53,4],[52,1],[55,7],[52,8],[55,7],[54,1],[53,5],[55,7],[55,8],[55,2],[54,8],[55,6],[53,4],[52,4],[54,2],[53,1],[54,7],[54,7],[52,5],[52,1],[55,4],[53,1],[53,3],[54,3],[53,3],[54,4],[53,1],[54,4],[54,2],[52,8],[0,0],[0,0],[54,3],[55,2],[55,2],[52,1],[50,5],[52,7],[52,3],[53,1],[54,7],[52,1],[55,4],[52,5],[52,2],[53,7],[53,2],[52,2],[54,3],[53,2],[54,8],[55,4],[53,1],[55,2],[53,5],[55,2],[54,7],[55,2],[53,1],[54,2],[55,4],[54,7],[55,4],[54,1],[53,8],[53,6],[53,2],[55,1],[53,2],[53,2],[55,2],[54,1],[53,4],[53,3],[53,3],[53,4],[54,2]]} \ No newline at end of file diff --git a/db/conn.go b/db/conn.go new file mode 100644 index 0000000..9779889 --- /dev/null +++ b/db/conn.go @@ -0,0 +1,155 @@ +package db + +import ( + "database/sql" + "errors" + "fmt" + _ "github.com/go-sql-driver/mysql" + "log/slog" + "os" + "path/filepath" + "slgserver/config" + "time" + "xorm.io/xorm" + "xorm.io/xorm/log" +) + +var MasterDB *xorm.Engine + +var logFileHandle *os.File + +var ( + ConnectDBErr = errors.New("connect db error") + UseDBErr = errors.New("use db error") +) + +// TestDB 测试数据库 +func TestDB() error { + mysqlConfig, err := config.GetSection("mysql") + if err != nil { + slog.Error("get mysql config error", "error", err) + panic(err) + } + + tmpDns := fmt.Sprintf("%s:%s@tcp(%s:%s)/?charset=%s&parseTime=True&loc=Local", + mysqlConfig["user"], + mysqlConfig["password"], + mysqlConfig["host"], + mysqlConfig["port"], + mysqlConfig["charset"]) + egnine, err := xorm.NewEngine("mysql", tmpDns) + if err != nil { + slog.Error("new engine error", "error", err) + panic(err) + } + defer egnine.Close() + + // 测试数据库连接是否 OK + if err = egnine.Ping(); err != nil { + slog.Error("ping db error", "error", err) + return ConnectDBErr + } + + _, err = egnine.Exec("use " + mysqlConfig["dbname"]) + if err != nil { + slog.Error("use db error", "error", err) + // 使用参数化查询避免SQL注入风险 + createDBQuery := fmt.Sprintf("CREATE DATABASE `%s` DEFAULT CHARACTER SET %s", mysqlConfig["dbname"], mysqlConfig["charset"]) + _, err = egnine.Exec(createDBQuery) + if err != nil { + slog.Error("create database error", "error", err) + + return UseDBErr + } + + slog.Info("create database successfully") + } + + // 初始化 MasterDB + return Init() +} + +func Init() error { + mysqlConfig, err := config.GetSection("mysql") + if err != nil { + slog.Error("get mysql config error", "error", err) + return err + } + + // 启动时就打开数据库连接 + if err = initEngine(mysqlConfig); err != nil { + slog.Error("mysql is not open", "error", err) + return err + } + + return nil +} + +func fillDns(mysqlConfig map[string]string) string { + return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True&loc=Local", + mysqlConfig["user"], + mysqlConfig["password"], + mysqlConfig["host"], + mysqlConfig["port"], + mysqlConfig["dbname"], + mysqlConfig["charset"]) +} + +func initEngine(mysqlConfig map[string]string) error { + + var err error + dns := fillDns(mysqlConfig) + + MasterDB, err = xorm.NewEngine("mysql", dns) + if err != nil { + return err + } + + // 数据库连接池配置,根据实际负载调整 + maxIdle := config.GetInt("mysql.max_idle", 10) // 默认值从2提升到10 + maxConn := config.GetInt("mysql.max_conn", 100) // 默认值从10提升到100 + + MasterDB.SetMaxIdleConns(maxIdle) + MasterDB.SetMaxOpenConns(maxConn) + + // 设置连接最大生存时间,避免长时间连接导致的问题 + MasterDB.SetConnMaxLifetime(time.Hour) + + showSQL := config.GetBool("xorm.show_sql", false) + logLevel := config.GetInt("xorm.log_level", 1) + logFile := config.GetPath("xorm.log_file", "") + + if logFile != "" { + if logFileHandle != nil { + logFileHandle.Close() + } + // 确保日志文件目录存在 + if err := os.MkdirAll(filepath.Dir(logFile), 0755); err != nil { + return fmt.Errorf("failed to create log directory: %w", err) + } + f, err := os.OpenFile(logFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) + if err != nil { + return err + } + logFileHandle = f + MasterDB.SetLogger(log.NewSimpleLogger(f)) + } + + MasterDB.SetLogLevel(log.LogLevel(logLevel)) + MasterDB.ShowSQL(showSQL) + + return nil +} + +func StdMasterDB() *sql.DB { + return MasterDB.DB().DB +} + +func Close() { + if MasterDB != nil { + MasterDB.Close() + } + if logFileHandle != nil { + logFileHandle.Close() + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e83f79f --- /dev/null +++ b/go.mod @@ -0,0 +1,60 @@ +module slgserver + +go 1.25 + +require ( + github.com/gin-gonic/gin v1.11.0 + github.com/go-sql-driver/mysql v1.9.3 + github.com/go-think/openssl v1.20.0 + github.com/gorilla/websocket v1.5.3 + github.com/mitchellh/mapstructure v1.5.0 + github.com/spf13/viper v1.21.0 + gopkg.in/ini.v1 v1.67.0 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 + xorm.io/xorm v1.3.11 +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/bytedance/gopkg v0.1.3 // indirect + github.com/bytedance/sonic v1.14.2 // indirect + github.com/bytedance/sonic/loader v0.4.0 // indirect + github.com/cloudwego/base64x v0.1.6 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.11 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.28.0 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/goccy/go-yaml v1.18.0 // indirect + github.com/golang/snappy v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.56.0 // indirect + github.com/sagikazarmark/locafero v0.12.0 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/syndtr/goleveldb v1.0.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.3.1 // indirect + go.uber.org/mock v0.6.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/arch v0.23.0 // indirect + golang.org/x/crypto v0.44.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect + golang.org/x/tools v0.39.0 // indirect + google.golang.org/protobuf v1.36.10 // indirect + xorm.io/builder v0.3.13 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c8c30f9 --- /dev/null +++ b/go.sum @@ -0,0 +1,200 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= +gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= +github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= +github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= +github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE= +github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980= +github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o= +github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= +github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= +github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik= +github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= +github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688= +github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/go-think/openssl v1.20.0 h1:awyPzo559r0eOePQ35jLwXVjY0hws/2et+9OHQCEUZc= +github.com/go-think/openssl v1.20.0/go.mod h1:Ug+hrHD5ldaCqpHVuSaP1z/HogGbEtXEbUJmiHai+II= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= +github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.56.0 h1:q/TW+OLismmXAehgFLczhCDTYB3bFmua4D9lsNBWxvY= +github.com/quic-go/quic-go v0.56.0/go.mod h1:9gx5KsFQtw2oZ6GZTyh+7YEvOxWCL9WZAepnHxgAo6c= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= +github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= +github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg= +golang.org/x/arch v0.23.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= +golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= +modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= +modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= +modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= +modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= +modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.20.4 h1:J8+m2trkN+KKoE7jglyHYYYiaq5xmz2HoHJIiBlRzbE= +modernc.org/sqlite v1.20.4/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo= +xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= +xorm.io/xorm v1.3.11 h1:i4tlVUASogb0ZZFJHA7dZqoRU2pUpUsutnNdaOlFyMI= +xorm.io/xorm v1.3.11/go.mod h1:cs0ePc8O4a0jD78cNvD+0VFwhqotTvLQZv372QsDw7Q= diff --git a/log/log.go b/log/log.go new file mode 100644 index 0000000..0e5cb08 --- /dev/null +++ b/log/log.go @@ -0,0 +1,46 @@ +package log + +import ( + "io" + "log/slog" + "os" + "path" + "path/filepath" + "slgserver/config" + "strings" + + "gopkg.in/natefinch/lumberjack.v2" +) + +func init() { + fileDir := config.GetString("log.file_dir", "../log/") + maxSize := config.GetInt("log.max_size", 128) + maxBackups := config.GetInt("log.max_backups", 30) + maxAge := config.GetInt("log.max_age", 7) + compress := config.GetBool("log.compress", true) + + sa := strings.Split(filepath.Base(os.Args[0]), ".") + fileName := sa[0] + ".log" + hook := &lumberjack.Logger{ + Filename: path.Join(fileDir, fileName), // 日志文件路径 + MaxSize: maxSize, // 每个日志文件保存的最大尺寸 单位:M + MaxBackups: maxBackups, // 日志文件最多保存多少个备份 + MaxAge: maxAge, // 文件最多保存多少天 + Compress: compress, // 是否压缩 + } + + // 创建多写入器:同时写入标准输出和文件 + multiWriter := io.MultiWriter(os.Stdout, hook) + + // 创建 JSON handler,包含调用者信息 + opts := &slog.HandlerOptions{ + Level: slog.LevelInfo, + AddSource: true, // 添加调用者信息 + } + + handler := slog.NewJSONHandler(multiWriter, opts) + logger := slog.New(handler) + + // 使用 slog 标准方式设置默认 logger + slog.SetDefault(logger) +} diff --git a/main/chatserver.exe b/main/chatserver.exe new file mode 100644 index 0000000..fddb637 Binary files /dev/null and b/main/chatserver.exe differ diff --git a/main/chatserver.go b/main/chatserver.go new file mode 100644 index 0000000..44251ca --- /dev/null +++ b/main/chatserver.go @@ -0,0 +1,28 @@ +package main + +import ( + "log/slog" + "os" + "slgserver/config" + "slgserver/net" + "slgserver/server/chatserver" +) + +func getChatServerAddr() string { + host := config.GetString("chatserver.host", "") + port := config.GetString("chatserver.port", "8002") + return host + ":" + port +} + +func main() { + if wd, err := os.Getwd(); err == nil { + slog.Info("working directory", "dir", wd) + } else { + slog.Warn("get working directory failed", "error", err) + } + chatserver.Init() + needSecret := config.GetBool("chatserver.need_secret", false) + s := net.NewServer(getChatServerAddr(), needSecret) + s.Router(chatserver.MyRouter) + s.Start() +} diff --git a/main/gateserver.exe b/main/gateserver.exe new file mode 100644 index 0000000..e78bf83 Binary files /dev/null and b/main/gateserver.exe differ diff --git a/main/gateserver.go b/main/gateserver.go new file mode 100644 index 0000000..37e34b0 --- /dev/null +++ b/main/gateserver.go @@ -0,0 +1,30 @@ +package main + +import ( + "log/slog" + "os" + "slgserver/config" + "slgserver/net" + "slgserver/server/gateserver" + "slgserver/server/gateserver/controller" +) + +func getGateServerAddr() string { + host := config.GetString("gateserver.host", "") + port := config.GetString("gateserver.port", "8004") + return host + ":" + port +} + +func main() { + if wd, err := os.Getwd(); err == nil { + slog.Info("working directory", "dir", wd) + } else { + slog.Warn("get working directory failed", "error", err) + } + gateserver.Init() + needSecret := config.GetBool("gateserver.need_secret", false) + s := net.NewServer(getGateServerAddr(), needSecret) + s.Router(gateserver.MyRouter) + s.SetOnBeforeClose(controller.GHandle.OnServerConnClose) + s.Start() +} diff --git a/main/httpserver.exe b/main/httpserver.exe new file mode 100644 index 0000000..a467729 Binary files /dev/null and b/main/httpserver.exe differ diff --git a/main/httpserver.go b/main/httpserver.go new file mode 100644 index 0000000..e49c584 --- /dev/null +++ b/main/httpserver.go @@ -0,0 +1,29 @@ +package main + +import ( + "github.com/gin-gonic/gin" + "slgserver/config" + "slgserver/db" + "slgserver/server/httpserver/controller" +) + +func main() { + // 设置 Gin 为 release 模式 + gin.SetMode(gin.ReleaseMode) + + db.TestDB() + + r := gin.Default() + + g := r.Group("") + new(controller.AccountController).RegisterRoutes(g) + + addr := getHttpAddr() + r.Run(addr) +} + +func getHttpAddr() string { + host := config.GetString("httpserver.host", "") + port := config.GetString("httpserver.port", "8088") + return host + ":" + port +} \ No newline at end of file diff --git a/main/loginserver.exe b/main/loginserver.exe new file mode 100644 index 0000000..2f96718 Binary files /dev/null and b/main/loginserver.exe differ diff --git a/main/loginserver.go b/main/loginserver.go new file mode 100644 index 0000000..fecaa7d --- /dev/null +++ b/main/loginserver.go @@ -0,0 +1,28 @@ +package main + +import ( + "log/slog" + "os" + "slgserver/config" + "slgserver/net" + "slgserver/server/loginserver" +) + +func getLoginServerAddr() string { + host := config.GetString("loginserver.host", "") + port := config.GetString("loginserver.port", "8003") + return host + ":" + port +} + +func main() { + if wd, err := os.Getwd(); err == nil { + slog.Info("working directory", "dir", wd) + } else { + slog.Warn("get working directory failed", "error", err) + } + loginserver.Init() + needSecret := config.GetBool("loginserver.need_secret", false) + s := net.NewServer(getLoginServerAddr(), needSecret) + s.Router(loginserver.MyRouter) + s.Start() +} diff --git a/main/slgserver.exe b/main/slgserver.exe new file mode 100644 index 0000000..80ce639 Binary files /dev/null and b/main/slgserver.exe differ diff --git a/main/slgserver.go b/main/slgserver.go new file mode 100644 index 0000000..5c3e1af --- /dev/null +++ b/main/slgserver.go @@ -0,0 +1,28 @@ +package main + +import ( + "log/slog" + "os" + "slgserver/config" + "slgserver/net" + "slgserver/server/slgserver/run" +) + +func getServerAddr() string { + host := config.GetString("slgserver.host", "") + port := config.GetString("slgserver.port", "8001") + return host + ":" + port +} + +func main() { + if wd, err := os.Getwd(); err == nil { + slog.Info("working directory", "dir", wd) + } else { + slog.Warn("get working directory failed", "error", err) + } + run.Init() + needSecret := config.GetBool("slgserver.need_secret", false) + s := net.NewServer(getServerAddr(), needSecret) + s.Router(run.MyRouter) + s.Start() +} diff --git a/main/wstest.go b/main/wstest.go new file mode 100644 index 0000000..5af85cb --- /dev/null +++ b/main/wstest.go @@ -0,0 +1,125 @@ +package main + +import ( + "github.com/go-think/openssl" + "github.com/mitchellh/mapstructure" + "github.com/gorilla/websocket" + "log/slog" + "slgserver/net" + proto2 "slgserver/server/loginserver/proto" + "slgserver/util" + "time" +) + +var origin = "httpserver://127.0.0.1:8002/" +var secretKey = []byte("") +var session = "" + +func main() { + + var dialer *websocket.Dialer + //通过Dialer连接websocket服务器 + conn, _, err := dialer.Dial("ws://127.0.0.1:8001", nil) + if err != nil { + slog.Error("dial websocket failed", "error", err) + return + } + + go do(conn) + go timeWriter(conn) + + time.Sleep(10 * time.Second) +} + +func do(conn *websocket.Conn) { + defer func() { + if err := recover(); err != nil { + slog.Error("do panic", "error", err) + } + }() + + for { + _, message, _ := conn.ReadMessage() + msg := &net.RspBody{} + if len(secretKey) == 0 { + message, _ = util.UnZip(message) + if err := util.Unmarshal(message, msg); err == nil { + if msg.Name == "handshake" { + h := &net.Handshake{} + mapstructure.Decode(msg.Msg, h) + + secretKey = []byte(h.Key) + } + slog.Info("received message", "name", msg.Name) + } + } else { + message, _ = util.UnZip(message) + data, err := util.AesCBCDecrypt(message, secretKey, secretKey, openssl.ZEROS_PADDING) + if err == nil { + if err := util.Unmarshal(data, msg); err == nil { + slog.Info("received message", + "name", msg.Name, + "code", msg.Code, + "payload", msg.Msg) + if msg.Name == "login" { + lr := &proto2.LoginRsp{} + mapstructure.Decode(msg.Msg, lr) + session = lr.Session + } + } else { + secretKey = []byte("") + } + } else { + secretKey = []byte("") + } + } + } +} + +func login(conn *websocket.Conn) { + l := &proto2.LoginReq{Ip: "127.0.0.1", Username: "test", Password: "123456"} + send(conn, "login", l) +} + +func reLogin(conn *websocket.Conn, session string) { + l := &proto2.ReLoginReq{Session: session} + slog.Info("relogin session", "session", session) + send(conn, "reLogin", l) +} + +func logout(conn *websocket.Conn) { + l := &proto2.LogoutReq{UId: 5} + send(conn, "logout", l) +} + +func send(conn *websocket.Conn, name string, dd interface{}) { + msg := &net.ReqBody{Name: name, Msg: dd} + + if len(secretKey) == 0 { + + } else { + if data, err := util.Marshal(msg); err == nil { + data, _ := util.AesCBCEncrypt(data, secretKey, secretKey, openssl.ZEROS_PADDING) + data, _ = util.Zip(data) + + conn.WriteMessage(websocket.BinaryMessage, data) + } + } +} + +func timeWriter(conn *websocket.Conn) { + + time.Sleep(time.Second * 1) + login(conn) + + time.Sleep(time.Second * 1) + reLogin(conn, session) + + time.Sleep(20 * time.Second) + + //time.Sleep(time.Second * 1) + //reLogin(conn, "123") + // + //time.Sleep(time.Second * 1) + //logout(conn) +} diff --git a/middleware/check_login.go b/middleware/check_login.go new file mode 100644 index 0000000..f7656d6 --- /dev/null +++ b/middleware/check_login.go @@ -0,0 +1,25 @@ +package middleware + +import ( + "log/slog" + "slgserver/constant" + "slgserver/net" +) + +func CheckLogin() net.MiddlewareFunc { + return func(next net.HandlerFunc) net.HandlerFunc { + return func(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + + _, err := req.Conn.GetProperty("uid") + if err != nil { + slog.Warn("connect not found uid", + "msgName", req.Body.Name) + rsp.Body.Code = constant.UserNotInConnect + req.Conn.Push("account.pleaseLogin", nil) + return + } + + next(req, rsp) + } + } +} \ No newline at end of file diff --git a/middleware/check_rid.go b/middleware/check_rid.go new file mode 100644 index 0000000..2604339 --- /dev/null +++ b/middleware/check_rid.go @@ -0,0 +1,23 @@ +package middleware + +import ( + "log/slog" + "slgserver/constant" + "slgserver/net" +) + +func CheckRId() net.MiddlewareFunc { + return func(next net.HandlerFunc) net.HandlerFunc { + return func(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + + _, err := req.Conn.GetProperty("rid") + if err != nil { + rsp.Body.Code = constant.RoleNotInConnect + slog.Warn("connect not found role", + "msgName", req.Body.Name) + return + } + next(req, rsp) + } + } +} \ No newline at end of file diff --git a/middleware/check_role.go b/middleware/check_role.go new file mode 100644 index 0000000..c2dff20 --- /dev/null +++ b/middleware/check_role.go @@ -0,0 +1,23 @@ +package middleware + +import ( + "log/slog" + "slgserver/constant" + "slgserver/net" +) + +func CheckRole() net.MiddlewareFunc { + return func(next net.HandlerFunc) net.HandlerFunc { + return func(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + + _, err := req.Conn.GetProperty("role") + if err != nil { + rsp.Body.Code = constant.RoleNotInConnect + slog.Warn("connect not found role", + "msgName", req.Body.Name) + return + } + next(req, rsp) + } + } +} \ No newline at end of file diff --git a/middleware/elapsed_time.go b/middleware/elapsed_time.go new file mode 100644 index 0000000..fe46379 --- /dev/null +++ b/middleware/elapsed_time.go @@ -0,0 +1,23 @@ +package middleware + +import ( + "fmt" + "log/slog" + "slgserver/net" + "time" +) + +func ElapsedTime() net.MiddlewareFunc { + return func(next net.HandlerFunc) net.HandlerFunc { + return func(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + bt := time.Now().UnixNano() + next(req, rsp) + et := time.Now().UnixNano() + diff := (et - bt)/int64(time.Millisecond) + + slog.Info("ElapsedTime:", + "msgName", req.Body.Name, + "cost", fmt.Sprintf("%dms", diff)) + } + } +} \ No newline at end of file diff --git a/middleware/log.go b/middleware/log.go new file mode 100644 index 0000000..177bec9 --- /dev/null +++ b/middleware/log.go @@ -0,0 +1,20 @@ +package middleware + +import ( + "fmt" + "log/slog" + "slgserver/net" +) + +func Log() net.MiddlewareFunc { + return func(next net.HandlerFunc) net.HandlerFunc { + return func(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + + slog.Info("client req", + "msgName", req.Body.Name, + "data", fmt.Sprintf("%v", req.Body.Msg)) + + next(req, rsp) + } + } +} \ No newline at end of file diff --git a/net/clientconn.go b/net/clientconn.go new file mode 100644 index 0000000..cda270a --- /dev/null +++ b/net/clientconn.go @@ -0,0 +1,254 @@ +package net + +import ( + "context" + "errors" + "fmt" + "github.com/go-think/openssl" + "github.com/mitchellh/mapstructure" + "github.com/gorilla/websocket" + "log/slog" + "slgserver/constant" + "slgserver/util" + "sync" + "time" +) + +// 客户端连接 +type ClientConn struct { + wsSocket *websocket.Conn // 底层websocket + isClosed bool + Seq int64 + onClose func(conn*ClientConn) + onPush func(conn*ClientConn, body*RspBody) + //链接属性 + property map[string]interface{} + //保护链接属性修改的锁 + propertyLock sync.RWMutex + syncCtxs map[int64]*syncCtx + syncLock sync.RWMutex + handshakeChan chan bool + handshake bool +} + +func NewClientConn(wsSocket *websocket.Conn) *ClientConn { + conn := &ClientConn{ + wsSocket: wsSocket, + isClosed: false, + property: make(map[string]interface{}), + Seq: 0, + syncCtxs: make(map[int64]*syncCtx), + handshakeChan: make(chan bool), + } + + return conn +} + +func (this *ClientConn) waitHandshake() bool{ + if this.handshake == false{ + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + select { + case _ = <-this.handshakeChan:{ + slog.Info("recv handshakeChan") + return true + } + case <-ctx.Done():{ + slog.Info("recv handshakeChan timeout") + return false + } + } + } + return true +} + +func (this *ClientConn) Start() bool{ + this.handshake = false + go this.wsReadLoop() + return this.waitHandshake() +} + +func (this *ClientConn) Addr() string { + return this.wsSocket.RemoteAddr().String() +} + +func (this *ClientConn) Push(name string, data interface{}) { + rsp := &WsMsgRsp{Body: &RspBody{Name: name, Msg: data, Seq: 0}} + this.write(rsp.Body) +} + +func (this *ClientConn) Send(name string, data interface{}) *RspBody{ + this.syncLock.Lock() + sync := newSyncCtx() + this.Seq += 1 + seq := this.Seq + req := ReqBody{Name: name, Msg: data, Seq: seq} + this.syncCtxs[this.Seq] = sync + this.syncLock.Unlock() + + rsp := &RspBody{Code: constant.OK, Name: name, Seq: seq } + err := this.write(req) + if err != nil{ + sync.cancel() + }else{ + r := sync.wait() + if r == nil{ + rsp.Code = constant.ProxyConnectError + }else{ + rsp = r + } + } + + this.syncLock.Lock() + delete(this.syncCtxs, seq) + this.syncLock.Unlock() + + return rsp +} + +func (this *ClientConn) wsReadLoop() { + defer func() { + if err := recover(); err != nil { + e := fmt.Sprintf("%v", err) + slog.Error("wsReadLoop error", "err", e) + this.Close() + } + }() + + for { + // 读一个message + _, data, err := this.wsSocket.ReadMessage() + if err != nil { + break + } + + data, err = util.UnZip(data) + if err != nil { + slog.Error("wsReadLoop UnZip error", "error", err) + continue + } + + //需要检测是否有加密 + body := &RspBody{} + if secretKey, err := this.GetProperty("secretKey"); err == nil { + key := secretKey.(string) + d, err := util.AesCBCDecrypt(data, []byte(key), []byte(key), openssl.ZEROS_PADDING) + if err != nil { + slog.Error("AesDecrypt error", "error", err) + }else{ + data = d + } + } + + if err := util.Unmarshal(data, body); err == nil { + if body.Seq == 0 { + if body.Name == HandshakeMsg{ + h := Handshake{} + mapstructure.Decode(body.Msg, &h) + slog.Info("client 收到握手协议", "data", string(data)) + if h.Key != ""{ + this.SetProperty("secretKey", h.Key) + }else{ + this.RemoveProperty("secretKey") + } + this.handshake = true + this.handshakeChan <- true + }else{ + //推送,需要推送到指定的代理连接 + if this.onPush != nil{ + this.onPush(this, body) + }else{ + slog.Warn("clientconn not deal push") + } + } + }else{ + this.syncLock.RLock() + s, ok := this.syncCtxs[body.Seq] + this.syncLock.RUnlock() + if ok { + s.outChan <- body + }else{ + slog.Warn("seq not found sync", + "seq", body.Seq, + "msgName", body.Name) + } + } + + }else{ + slog.Error("wsReadLoop Unmarshal error", "error", err) + } + } + + this.Close() +} + + +func (this *ClientConn) write(msg interface{}) error{ + data, err := util.Marshal(msg) + if err == nil { + if secretKey, err:= this.GetProperty("secretKey"); err == nil { + key := secretKey.(string) + slog.Info("secretKey", "secretKey", key) + data, _ = util.AesCBCEncrypt(data, []byte(key), []byte(key), openssl.ZEROS_PADDING) + } + }else { + slog.Error("wsWriteLoop Marshal body error", "error", err) + return err + } + + if data, err := util.Zip(data); err == nil{ + if err := this.wsSocket.WriteMessage(websocket.BinaryMessage, data); err != nil { + this.Close() + return err + } + }else{ + return err + } + return nil +} + +func (this *ClientConn) Close() { + this.wsSocket.Close() + if !this.isClosed { + this.isClosed = true + if this.onClose != nil{ + this.onClose(this) + } + } +} + +//设置链接属性 +func (this *ClientConn) SetProperty(key string, value interface{}) { + this.propertyLock.Lock() + defer this.propertyLock.Unlock() + + this.property[key] = value +} + +//获取链接属性 +func (this *ClientConn) GetProperty(key string) (interface{}, error) { + this.propertyLock.RLock() + defer this.propertyLock.RUnlock() + + if value, ok := this.property[key]; ok { + return value, nil + } else { + return nil, errors.New("no property found") + } +} + +//移除链接属性 +func (this *ClientConn) RemoveProperty(key string) { + this.propertyLock.Lock() + defer this.propertyLock.Unlock() + + delete(this.property, key) +} + +func (this *ClientConn) SetOnClose(hookFunc func (*ClientConn)) { + this.onClose = hookFunc +} + +func (this *ClientConn) SetOnPush(hookFunc func (*ClientConn, *RspBody)) { + this.onPush = hookFunc +} diff --git a/net/conn.go b/net/conn.go new file mode 100644 index 0000000..4c37c2d --- /dev/null +++ b/net/conn.go @@ -0,0 +1,70 @@ +package net + +import ( + "context" + "time" +) + +type ReqBody struct { + Seq int64 `json:"seq"` + Name string `json:"name"` + Msg interface{} `json:"msg"` + Proxy string `json:"proxy"` +} + +type RspBody struct { + Seq int64 `json:"seq"` + Name string `json:"name"` + Code int `json:"code"` + Msg interface{} `json:"msg"` +} + +type WsMsgReq struct { + Body *ReqBody + Conn WSConn +} + +type WsMsgRsp struct { + Body* RspBody +} + +const HandshakeMsg = "handshake" +const HeartbeatMsg = "heartbeat" + +type Handshake struct { + Key string `json:"key"` +} + +type Heartbeat struct { + CTime int64 `json:"ctime"` + STime int64 `json:"stime"` +} + +type WSConn interface { + SetProperty(key string, value interface{}) + GetProperty(key string) (interface{}, error) + RemoveProperty(key string) + Addr() string + Push(name string, data interface{}) +} + +type syncCtx struct { + ctx context.Context + cancel context.CancelFunc + outChan chan *RspBody +} + +func newSyncCtx() *syncCtx { + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + return &syncCtx{ctx: ctx, cancel: cancel, outChan: make(chan *RspBody)} +} + +func (this* syncCtx) wait() *RspBody{ + defer this.cancel() + select { + case data := <- this.outChan: + return data + case <-this.ctx.Done(): + return nil + } +} \ No newline at end of file diff --git a/net/connMgr.go b/net/connMgr.go new file mode 100644 index 0000000..876509d --- /dev/null +++ b/net/connMgr.go @@ -0,0 +1,202 @@ +package net + +import ( + "github.com/gorilla/websocket" + "log/slog" + "slgserver/server/slgserver/conn" + "slgserver/server/slgserver/pos" + "sync" + "sync/atomic" +) + +var ConnMgr = Mgr{} +var cid int64 = 0 + +type Mgr struct { + cm sync.RWMutex + um sync.RWMutex + rm sync.RWMutex + + connCache map[int64]WSConn + userCache map[int]WSConn + roleCache map[int]WSConn +} + +func (this *Mgr) NewConn(wsSocket *websocket.Conn, needSecret bool) *ServerConn { + this.cm.Lock() + defer this.cm.Unlock() + + id := atomic.AddInt64(&cid, 1) + if this.connCache == nil { + this.connCache = make(map[int64]WSConn) + } + + if this.userCache == nil { + this.userCache = make(map[int]WSConn) + } + + if this.roleCache == nil { + this.roleCache = make(map[int]WSConn) + } + + c := NewServerConn(wsSocket, needSecret) + c.SetProperty("cid", id) + this.connCache[id] = c + + return c +} + +func (this *Mgr) UserLogin(conn WSConn, session string, uid int) { + this.um.Lock() + defer this.um.Unlock() + + oldConn, ok := this.userCache[uid] + if ok { + if conn != oldConn { + slog.Warn("rob login", + "uid", uid, + "oldAddr", oldConn.Addr(), + "newAddr", conn.Addr()) + + //这里需要通知旧端被抢登录 + oldConn.Push("robLogin", nil) + } + } + this.userCache[uid] = conn + conn.SetProperty("session", session) + conn.SetProperty("uid", uid) +} + +func (this *Mgr) UserLogout(conn WSConn) { + this.removeUser(conn) +} + +func (this *Mgr) removeUser(conn WSConn) { + this.um.Lock() + uid, err := conn.GetProperty("uid") + if err == nil { + //只删除自己的conn + id := uid.(int) + c, ok := this.userCache[id] + if ok && c == conn { + delete(this.userCache, id) + } + } + this.um.Unlock() + + this.rm.Lock() + rid, err := conn.GetProperty("rid") + if err == nil { + //只删除自己的conn + id := rid.(int) + c, ok := this.roleCache[id] + if ok && c == conn { + delete(this.roleCache, id) + } + } + this.rm.Unlock() + + conn.RemoveProperty("session") + conn.RemoveProperty("uid") + conn.RemoveProperty("role") + conn.RemoveProperty("rid") +} + +func (this *Mgr) RoleEnter(conn WSConn, rid int) { + this.rm.Lock() + defer this.rm.Unlock() + conn.SetProperty("rid", rid) + this.roleCache[rid] = conn +} + +func (this *Mgr) RemoveConn(conn WSConn) { + this.cm.Lock() + cid, err := conn.GetProperty("cid") + if err == nil { + delete(this.connCache, cid.(int64)) + conn.RemoveProperty("cid") + } + this.cm.Unlock() + + this.removeUser(conn) +} + +func (this *Mgr) PushByRoleId(rid int, msgName string, data interface{}) bool { + if rid <= 0 { + return false + } + this.rm.Lock() + defer this.rm.Unlock() + conn, ok := this.roleCache[rid] + if ok { + conn.Push(msgName, data) + return true + } else { + return false + } +} + +func (this *Mgr) Count() int { + this.cm.RLock() + defer this.cm.RUnlock() + + return len(this.connCache) +} + +func (this *Mgr) Push(pushSync conn.PushSync) { + + proto := pushSync.ToProto() + belongRIds := pushSync.BelongToRId() + isCellView := pushSync.IsCellView() + x, y := pushSync.Position() + cells := make(map[int]int) + + //推送给开始位置 + if isCellView { + cellRIds := pos.RPMgr.GetCellRoleIds(x, y, 8, 6) + for _, rid := range cellRIds { + //是否能出现在视野 + if can := pushSync.IsCanView(rid, x, y); can { + this.PushByRoleId(rid, pushSync.PushMsgName(), proto) + cells[rid] = rid + } + } + } + + //推送给目标位置 + tx, ty := pushSync.TPosition() + if tx >= 0 && ty >= 0 { + var cellRIds []int + if isCellView { + cellRIds = pos.RPMgr.GetCellRoleIds(tx, ty, 8, 6) + } else { + cellRIds = pos.RPMgr.GetCellRoleIds(tx, ty, 0, 0) + } + + for _, rid := range cellRIds { + if _, ok := cells[rid]; !ok { + if can := pushSync.IsCanView(rid, tx, ty); can { + this.PushByRoleId(rid, pushSync.PushMsgName(), proto) + cells[rid] = rid + } + } + } + } + + //推送给自己 + for _, rid := range belongRIds { + if _, ok := cells[rid]; !ok { + this.PushByRoleId(rid, pushSync.PushMsgName(), proto) + } + } + +} + +func (this *Mgr) pushAll(msgName string, data interface{}) { + + this.rm.Lock() + defer this.rm.Unlock() + for _, conn := range this.roleCache { + conn.Push(msgName, data) + } +} diff --git a/net/proxyClient.go b/net/proxyClient.go new file mode 100644 index 0000000..f75492b --- /dev/null +++ b/net/proxyClient.go @@ -0,0 +1,68 @@ +package net + +import ( + "errors" + "github.com/gorilla/websocket" + "time" +) + +type ProxyClient struct { + proxy string + conn *ClientConn +} + +func (this*ProxyClient) Connect() error { + var dialer = websocket.Dialer{ + Subprotocols: []string{"p1", "p2"}, + ReadBufferSize: 1024, + WriteBufferSize: 1024, + HandshakeTimeout: 30 * time.Second, + } + ws, _, err := dialer.Dial(this.proxy, nil) + if err == nil{ + this.conn = NewClientConn(ws) + if this.conn.Start() == false{ + return errors.New("handshake fail") + } + } + return err +} + +func (this*ProxyClient) Send(msgName string, msg interface{}) (*RspBody, error){ + if this.conn != nil { + return this.conn.Send(msgName, msg), nil + } + return nil, errors.New("conn not found") +} + + +func (this *ProxyClient) SetOnPush(hookFunc func (*ClientConn, *RspBody)) { + if this.conn != nil { + this.conn.SetOnPush(hookFunc) + } +} + +func (this *ProxyClient) SetOnClose(hookFunc func (*ClientConn)) { + if this.conn != nil { + this.conn.SetOnClose(hookFunc) + } +} + +func (this *ProxyClient) SetProperty(key string, value interface{}) { + if this.conn != nil { + this.conn.SetProperty(key, value) + } +} + +func (this *ProxyClient) Close() { + if this.conn != nil { + this.conn.Close() + } +} + +func NewProxyClient(proxy string) *ProxyClient { + return & ProxyClient{ + proxy: proxy, + } +} + diff --git a/net/router.go b/net/router.go new file mode 100644 index 0000000..bce715c --- /dev/null +++ b/net/router.go @@ -0,0 +1,95 @@ +package net + +import ( + "encoding/json" + "log/slog" + "strings" +) + +type HandlerFunc func(req *WsMsgReq, rsp *WsMsgRsp) +type MiddlewareFunc func(HandlerFunc) HandlerFunc + +type Group struct { + prefix string + hMap map[string]HandlerFunc + hMapMidd map[string][]MiddlewareFunc + middleware []MiddlewareFunc +} + +func (this *Group) AddRouter(name string, handlerFunc HandlerFunc, middleware ...MiddlewareFunc) { + this.hMap[name] = handlerFunc + this.hMapMidd[name] = middleware +} + +func (this *Group) Use(middleware ...MiddlewareFunc) *Group { + this.middleware = append(this.middleware, middleware...) + return this +} + +func (this *Group) applyMiddleware(name string) HandlerFunc { + + h, ok := this.hMap[name] + if !ok { + //通配符 + h, ok = this.hMap["*"] + } + + if ok { + for i := len(this.middleware) - 1; i >= 0; i-- { + h = this.middleware[i](h) + } + + for i := len(this.hMapMidd[name]) - 1; i >= 0; i-- { + h = this.hMapMidd[name][i](h) + } + } + + return h +} + +func (this *Group) exec(name string, req *WsMsgReq, rsp *WsMsgRsp) { + slog.Debug("route exec", "group", this.prefix, "name", name) + h := this.applyMiddleware(name) + if h == nil { + slog.Warn("Group has not", + "msgName", req.Body.Name) + } else { + h(req, rsp) + } + if dd, err := json.Marshal(rsp.Body); err == nil { + slog.Debug("route response", "group", this.prefix, "name", name, "size", len(dd)) + } +} + +type Router struct { + groups []*Group +} + +func (this *Router) Group(prefix string) *Group { + g := &Group{prefix: prefix, + hMap: make(map[string]HandlerFunc), + hMapMidd: make(map[string][]MiddlewareFunc), + } + + this.groups = append(this.groups, g) + return g +} + +func (this *Router) Run(req *WsMsgReq, rsp *WsMsgRsp) { + name := req.Body.Name + msgName := name + sArr := strings.Split(name, ".") + prefix := "" + if len(sArr) == 2 { + prefix = sArr[0] + msgName = sArr[1] + } + + for _, g := range this.groups { + if g.prefix == prefix { + g.exec(msgName, req, rsp) + } else if g.prefix == "*" { + g.exec(msgName, req, rsp) + } + } +} diff --git a/net/server.go b/net/server.go new file mode 100644 index 0000000..740d067 --- /dev/null +++ b/net/server.go @@ -0,0 +1,137 @@ +package net + +import ( + "context" + "github.com/gorilla/websocket" + "log/slog" + "net/http" + "os" + "os/signal" + "slgserver/config" + "strings" + "syscall" + "time" +) + +// http升级websocket协议的配置 +var wsUpgrader = websocket.Upgrader{ + // 允许配置的 CORS 请求 + CheckOrigin: checkOrigin, +} + +var allowedOrigins = loadAllowedOrigins() + +type server struct { + addr string + router *Router + needSecret bool + beforeClose func(WSConn) + httpServer *http.Server +} + +func NewServer(addr string, needSecret bool) *server { + s := server{ + addr: addr, + needSecret: needSecret, + } + return &s +} + +func (this *server) Router(router *Router) { + this.router = router +} + +func (this *server) Start() { + mux := http.NewServeMux() + mux.HandleFunc("/", this.wsHandler) + + this.httpServer = &http.Server{ + Addr: this.addr, + Handler: mux, + } + + slog.Info("server starting", "addr", this.addr) + + go func() { + if err := this.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { + slog.Error("server start failed", "error", err, "addr", this.addr) + } + }() + + this.waitForShutdown() +} + +func (this *server) waitForShutdown() { + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) + <-quit + + slog.Info("server shutting down...") + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + if err := this.httpServer.Shutdown(ctx); err != nil { + slog.Error("server shutdown error", "error", err) + } else { + slog.Info("server shutdown gracefully") + } +} + +func (this *server) SetOnBeforeClose(hookFunc func(WSConn)) { + this.beforeClose = hookFunc +} + +func (this *server) wsHandler(resp http.ResponseWriter, req *http.Request) { + + wsSocket, err := wsUpgrader.Upgrade(resp, req, nil) + if err != nil { + slog.Warn("websocket upgrade failed", "error", err, "remote", req.RemoteAddr) + return + } + + conn := ConnMgr.NewConn(wsSocket, this.needSecret) + slog.Info("client connect", "addr", wsSocket.RemoteAddr().String()) + + conn.SetRouter(this.router) + conn.SetOnClose(ConnMgr.RemoveConn) + conn.SetOnBeforeClose(this.beforeClose) + conn.Start() + conn.Handshake() + +} + +func checkOrigin(r *http.Request) bool { + if len(allowedOrigins) == 0 { + return true + } + origin := strings.ToLower(strings.TrimSpace(r.Header.Get("Origin"))) + if origin == "" { + return true + } + if _, ok := allowedOrigins[origin]; ok { + return true + } + slog.Warn("origin not allowed", "origin", origin) + return false +} + +func loadAllowedOrigins() map[string]struct{} { + origins := config.GetString("server.allowed_origins", "") + if origins == "" { + return nil + } + originMap := make(map[string]struct{}) + items := strings.Split(origins, ",") + for _, item := range items { + val := strings.ToLower(strings.TrimSpace(item)) + if val == "" { + continue + } + if val == "*" { + return nil + } + originMap[val] = struct{}{} + } + return originMap +} diff --git a/net/serverconn.go b/net/serverconn.go new file mode 100644 index 0000000..1a11d10 --- /dev/null +++ b/net/serverconn.go @@ -0,0 +1,287 @@ +package net + +import ( + "errors" + "fmt" + "log/slog" + "slgserver/util" + "sync" + "time" + + "github.com/go-think/openssl" + "github.com/mitchellh/mapstructure" + "github.com/gorilla/websocket" +) + +// 客户端连接 +type ServerConn struct { + wsSocket *websocket.Conn // 底层websocket + outChan chan *WsMsgRsp // 写队列 + isClosed bool + needSecret bool + Seq int64 + router *Router + beforeClose func(conn WSConn) + onClose func(conn WSConn) + //链接属性 + property map[string]interface{} + //保护链接属性修改的锁 + propertyLock sync.RWMutex + closeChan chan struct{} + closeOnce sync.Once +} + +func NewServerConn(wsSocket *websocket.Conn, needSecret bool) *ServerConn { + conn := &ServerConn{ + wsSocket: wsSocket, + outChan: make(chan *WsMsgRsp, 1000), + isClosed: false, + property: make(map[string]interface{}), + needSecret: needSecret, + Seq: 0, + closeChan: make(chan struct{}), + } + + return conn +} + +// 开启异步 +func (this *ServerConn) Start() { + go this.wsReadLoop() + go this.wsWriteLoop() +} + +func (this *ServerConn) Addr() string { + return this.wsSocket.RemoteAddr().String() +} + +func (this *ServerConn) Push(name string, data interface{}) { + rsp := &WsMsgRsp{Body: &RspBody{Name: name, Msg: data, Seq: 0}} + this.enqueue(rsp) +} + +func (this *ServerConn) Send(name string, data interface{}) { + this.Seq += 1 + rsp := &WsMsgRsp{Body: &RspBody{Name: name, Msg: data, Seq: this.Seq}} + this.enqueue(rsp) +} + +func (this *ServerConn) wsReadLoop() { + defer func() { + if err := recover(); err != nil { + e := fmt.Sprintf("%v", err) + slog.Error("wsReadLoop error", "err", e) + this.Close() + } + }() + + for { + select { + case <-this.closeChan: + return + default: + } + // 读一个message + _, data, err := this.wsSocket.ReadMessage() + slog.Debug("ws read message", "size", len(data)) + if err != nil { + break + } + + data, err = util.UnZip(data) + if err != nil { + slog.Error("wsReadLoop UnZip error", "error", err) + continue + } + + body := &ReqBody{} + if this.needSecret { + //检测是否有加密,没有加密发起Handshake + if secretKey, err := this.GetProperty("secretKey"); err == nil { + key := secretKey.(string) + d, err := util.AesCBCDecrypt(data, []byte(key), []byte(key), openssl.ZEROS_PADDING) + if err != nil { + slog.Error("AesDecrypt error", "error", err) + this.Handshake() + } else { + data = d + } + } else { + slog.Info("secretKey not found client need handshake", "error", err) + this.Handshake() + return + } + } + + if err := util.Unmarshal(data, body); err == nil { + req := &WsMsgReq{Conn: this, Body: body} + rsp := &WsMsgRsp{Body: &RspBody{Name: body.Name, Seq: req.Body.Seq}} + + if req.Body.Name == HeartbeatMsg { + h := &Heartbeat{} + mapstructure.Decode(body.Msg, h) + h.STime = time.Now().UnixNano() / 1e6 + rsp.Body.Msg = h + } else { + if this.router != nil { + this.router.Run(req, rsp) + } + } + this.outChan <- rsp + } else { + slog.Error("wsReadLoop Unmarshal error", "error", err) + this.Handshake() + } + } + + this.Close() +} + +func (this *ServerConn) wsWriteLoop() { + + defer func() { + if err := recover(); err != nil { + slog.Error("wsWriteLoop error") + this.Close() + } + }() + + for { + select { + case <-this.closeChan: + return + case msg := <-this.outChan: + if msg == nil { + continue + } + // 写给websocket + this.write(msg.Body) + } + } +} + +func (this *ServerConn) write(msg interface{}) error { + data, err := util.Marshal(msg) + slog.Debug("ws write message", "size", len(data)) + if err == nil { + if this.needSecret { + if secretKey, err := this.GetProperty("secretKey"); err == nil { + key := secretKey.(string) + data, _ = util.AesCBCEncrypt(data, []byte(key), []byte(key), openssl.ZEROS_PADDING) + } + } + } else { + slog.Error("wsWriteLoop Marshal body error", "error", err) + return err + } + + if data, err := util.Zip(data); err == nil { + if err := this.wsSocket.WriteMessage(websocket.BinaryMessage, data); err != nil { + this.Close() + return err + } + } else { + return err + } + return nil +} + +func (this *ServerConn) Close() { + this.closeOnce.Do(func() { + this.wsSocket.Close() + close(this.closeChan) + if !this.isClosed { + this.isClosed = true + + if this.beforeClose != nil { + this.beforeClose(this) + } + + if this.onClose != nil { + this.onClose(this) + } + } + }) +} + +// 设置链接属性 +func (this *ServerConn) SetProperty(key string, value interface{}) { + this.propertyLock.Lock() + defer this.propertyLock.Unlock() + + this.property[key] = value +} + +// 获取链接属性 +func (this *ServerConn) GetProperty(key string) (interface{}, error) { + this.propertyLock.RLock() + defer this.propertyLock.RUnlock() + + if value, ok := this.property[key]; ok { + return value, nil + } else { + return nil, errors.New("no property found") + } +} + +func (this *ServerConn) SetRouter(router *Router) { + this.router = router +} + +func (this *ServerConn) SetOnClose(hookFunc func(WSConn)) { + this.onClose = hookFunc +} + +func (this *ServerConn) SetOnBeforeClose(hookFunc func(WSConn)) { + this.beforeClose = hookFunc +} + +// 移除链接属性 +func (this *ServerConn) RemoveProperty(key string) { + this.propertyLock.Lock() + defer this.propertyLock.Unlock() + + delete(this.property, key) +} + +// 握手协议 +func (this *ServerConn) Handshake() { + + secretKey := "" + if this.needSecret { + key, err := this.GetProperty("secretKey") + if err == nil { + secretKey = key.(string) + } else { + secretKey = util.RandSeq(16) + } + } + + handshake := &Handshake{Key: secretKey} + body := &RspBody{Name: HandshakeMsg, Msg: handshake} + if data, err := util.Marshal(body); err == nil { + if secretKey != "" { + this.SetProperty("secretKey", secretKey) + } else { + this.RemoveProperty("secretKey") + } + + slog.Info("handshake secretKey", + "secretKey", secretKey) + + if data, err = util.Zip(data); err == nil { + this.wsSocket.WriteMessage(websocket.BinaryMessage, data) + } + + } else { + slog.Error("handshake Marshal body error", "error", err) + } +} + +func (this *ServerConn) enqueue(rsp *WsMsgRsp) { + select { + case <-this.closeChan: + return + case this.outChan <- rsp: + } +} diff --git a/server/chatserver/controller/chat.go b/server/chatserver/controller/chat.go new file mode 100644 index 0000000..f0b3639 --- /dev/null +++ b/server/chatserver/controller/chat.go @@ -0,0 +1,204 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "log/slog" + "slgserver/constant" + "slgserver/middleware" + "slgserver/net" + "slgserver/server/chatserver/logic" + "slgserver/server/chatserver/proto" + "slgserver/util" + "sync" +) + +var DefaultChat = Chat{ + worldGroup: logic.NewGroup(), + unionGroups: make(map[int]*logic.Group), + ridToUnionGroups: make(map[int]int), +} + +type Chat struct { + unionMutex sync.RWMutex + worldGroup *logic.Group //世界频道 + unionGroups map[int]*logic.Group //联盟频道 + ridToUnionGroups map[int]int //rid对应的联盟频道 +} + +func (this*Chat) InitRouter(r *net.Router) { + g := r.Group("chat").Use(middleware.ElapsedTime(), middleware.Log()) + + g.AddRouter("login", this.login) + g.AddRouter("logout", this.logout, middleware.CheckRId()) + g.AddRouter("chat", this.chat, middleware.CheckRId()) + g.AddRouter("history", this.history, middleware.CheckRId()) + g.AddRouter("join", this.join, middleware.CheckRId()) + g.AddRouter("exit", this.exit, middleware.CheckRId()) +} + +func (this*Chat) login(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.LoginReq{} + rspObj := &proto.LoginRsp{} + rsp.Body.Code = constant.OK + rsp.Body.Msg = rspObj + + mapstructure.Decode(req.Body.Msg, reqObj) + rspObj.RId = reqObj.RId + rspObj.NickName = reqObj.NickName + + sess, err := util.ParseSession(reqObj.Token) + if err != nil{ + rsp.Body.Code = constant.InvalidParam + return + } + if sess.IsValid() == false || sess.Id != reqObj.RId{ + rsp.Body.Code = constant.InvalidParam + return + } + net.ConnMgr.RoleEnter(req.Conn, reqObj.RId) + + this.worldGroup.Enter(logic.NewUser(reqObj.RId, reqObj.NickName)) +} + +func (this*Chat) logout(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.LogoutReq{} + rspObj := &proto.LogoutRsp{} + rsp.Body.Code = constant.OK + rsp.Body.Msg = rspObj + + mapstructure.Decode(req.Body.Msg, reqObj) + rspObj.RId = reqObj.RId + + net.ConnMgr.UserLogout(req.Conn) + this.worldGroup.Exit(reqObj.RId) +} + +func (this*Chat) chat(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ChatReq{} + rspObj := &proto.ChatMsg{} + rsp.Body.Code = constant.OK + rsp.Body.Msg = rspObj + + mapstructure.Decode(req.Body.Msg, reqObj) + + p, _ := req.Conn.GetProperty("rid") + rid := p.(int) + if reqObj.Type == 0 { + //世界聊天 + rsp.Body.Msg = this.worldGroup.PutMsg(reqObj.Msg, rid, 0) + }else if reqObj.Type == 1{ + //联盟聊天 + this.unionMutex.RLock() + id, ok := this.ridToUnionGroups[rid] + if ok { + g, ok := this.unionGroups[id] + if ok { + g.PutMsg(reqObj.Msg, rid, 1) + }else{ + slog.Warn("chat not found rid in unionGroups", "rid", rid) + } + }else{ + slog.Warn("chat not found rid in ridToUnionGroups", "rid", rid) + } + this.unionMutex.RUnlock() + } + +} + +//历史记录 +func (this*Chat) history(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.HistoryReq{} + rspObj := &proto.HistoryRsp{} + rsp.Body.Code = constant.OK + + mapstructure.Decode(req.Body.Msg, reqObj) + rspObj.Msgs = []proto.ChatMsg{} + p, _ := req.Conn.GetProperty("rid") + rid := p.(int) + + if reqObj.Type == 0 { + r := this.worldGroup.History() + rspObj.Msgs = r + }else if reqObj.Type == 1 { + this.unionMutex.RLock() + id, ok := this.ridToUnionGroups[rid] + if ok { + g, ok := this.unionGroups[id] + if ok { + rspObj.Msgs = g.History() + } + } + this.unionMutex.RUnlock() + } + rspObj.Type = reqObj.Type + rsp.Body.Msg = rspObj +} + +func (this*Chat) join(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.JoinReq{} + rspObj := &proto.JoinRsp{} + rsp.Body.Code = constant.OK + rsp.Body.Msg = rspObj + rspObj.Type = reqObj.Type + mapstructure.Decode(req.Body.Msg, reqObj) + p, _ := req.Conn.GetProperty("rid") + rid := p.(int) + if reqObj.Type == 1 { + u := this.worldGroup.GetUser(rid) + if u == nil { + rsp.Body.Code = constant.InvalidParam + return + } + + this.unionMutex.Lock() + gId, ok := this.ridToUnionGroups[rid] + if ok { + if gId != reqObj.Id { + //联盟聊天只能有一个,顶掉旧的 + if g,ok := this.unionGroups[gId]; ok { + g.Exit(rid) + } + + _, ok = this.unionGroups[reqObj.Id] + if ok == false { + this.unionGroups[reqObj.Id] = logic.NewGroup() + } + this.ridToUnionGroups[rid] = reqObj.Id + this.unionGroups[reqObj.Id].Enter(u) + } + }else{ + //新加入 + _, ok = this.unionGroups[reqObj.Id] + if ok == false { + this.unionGroups[reqObj.Id] = logic.NewGroup() + } + this.ridToUnionGroups[rid] = reqObj.Id + this.unionGroups[reqObj.Id].Enter(u) + } + this.unionMutex.Unlock() + } +} + +func (this*Chat) exit(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ExitReq{} + rspObj := &proto.ExitRsp{} + rsp.Body.Code = constant.OK + rsp.Body.Msg = rspObj + rspObj.Type = reqObj.Type + mapstructure.Decode(req.Body.Msg, reqObj) + p, _ := req.Conn.GetProperty("rid") + rid := p.(int) + + if reqObj.Type == 1 { + this.unionMutex.Lock() + id, ok := this.ridToUnionGroups[rid] + if ok { + g, ok := this.unionGroups[id] + if ok { + g.Exit(rid) + } + } + delete(this.ridToUnionGroups, rid) + this.unionMutex.Unlock() + } +} diff --git a/server/chatserver/init.go b/server/chatserver/init.go new file mode 100644 index 0000000..96a4153 --- /dev/null +++ b/server/chatserver/init.go @@ -0,0 +1,20 @@ +package chatserver + +import ( + "slgserver/db" + "slgserver/net" + "slgserver/server/chatserver/controller" +) + +var MyRouter = &net.Router{} + +func Init() { + db.TestDB() + + //全部初始化完才注册路由,防止服务器还没启动就绪收到请求 + initRouter() +} + +func initRouter() { + controller.DefaultChat.InitRouter(MyRouter) +} diff --git a/server/chatserver/logic/entity.go b/server/chatserver/logic/entity.go new file mode 100644 index 0000000..bca1a4f --- /dev/null +++ b/server/chatserver/logic/entity.go @@ -0,0 +1,22 @@ +package logic + +import "time" + +type User struct { + rid int + nickName string +} + +func NewUser(rid int, nickName string) *User { + return &User{ + rid: rid, + nickName: nickName, + } +} + +type Msg struct { + RId int `json:"rid"` + NickName string `json:"nickName"` + Msg string `json:"msg"` + Time time.Time `json:"time"` +} \ No newline at end of file diff --git a/server/chatserver/logic/group.go b/server/chatserver/logic/group.go new file mode 100644 index 0000000..220f93a --- /dev/null +++ b/server/chatserver/logic/group.go @@ -0,0 +1,79 @@ +package logic + +import ( + "slgserver/net" + "slgserver/server/chatserver/proto" + "sync" + "time" +) + +type Group struct { + userMutex sync.RWMutex + msgMutex sync.RWMutex + users map[int]*User + msgs ItemQueue +} + +func NewGroup() *Group { + return &Group{users: map[int]*User{}} +} + +func (this*Group) Enter(u *User) { + this.userMutex.Lock() + defer this.userMutex.Unlock() + this.users[u.rid] = u +} + +func (this*Group) Exit(rid int) { + this.userMutex.Lock() + defer this.userMutex.Unlock() + delete(this.users, rid) +} + +func (this*Group) GetUser(rid int) *User { + this.userMutex.Lock() + defer this.userMutex.Unlock() + return this.users[rid] +} + +func (this*Group) PutMsg(text string, rid int, t int8) *proto.ChatMsg { + + this.userMutex.RLock() + u, ok := this.users[rid] + this.userMutex.RUnlock() + if ok == false{ + return nil + } + + msg := &Msg{Msg: text, RId: rid, Time: time.Now(), NickName: u.nickName} + this.msgMutex.Lock() + size := this.msgs.Size() + if size > 100 { + this.msgs.Dequeue() + } + this.msgs.Enqueue(msg) + this.msgMutex.Unlock() + + //广播 + this.userMutex.RLock() + c := &proto.ChatMsg{RId: msg.RId, NickName: msg.NickName, Time: msg.Time.Unix(), Msg: msg.Msg, Type: t} + for _, user := range this.users { + net.ConnMgr.PushByRoleId(user.rid, "chat.push", c) + } + this.userMutex.RUnlock() + return c +} + +func (this*Group) History() []proto.ChatMsg { + r := make([]proto.ChatMsg, 0) + this.msgMutex.RLock() + items := this.msgs.items + for _, item := range items { + msg := item.(*Msg) + c := proto.ChatMsg{RId: msg.RId, NickName: msg.NickName, Time: msg.Time.Unix(), Msg: msg.Msg} + r = append(r, c) + } + this.msgMutex.RUnlock() + + return r +} \ No newline at end of file diff --git a/server/chatserver/logic/queue.go b/server/chatserver/logic/queue.go new file mode 100644 index 0000000..474c867 --- /dev/null +++ b/server/chatserver/logic/queue.go @@ -0,0 +1,45 @@ +package logic + +type Item interface { +} + +// Item the type of the queue +type ItemQueue struct { + items []Item +} + +type ItemQueuer interface { + New() ItemQueue + Enqueue(t Item) + Dequeue() *Item + IsEmpty() bool + Size() int +} + +// New creates a new ItemQueue +func (s *ItemQueue) New() *ItemQueue { + s.items = []Item{} + return s +} + +// Enqueue adds an Item to the end of the queue +func (s *ItemQueue) Enqueue(t Item) { + s.items = append(s.items, t) +} + +// dequeue +func (s *ItemQueue) Dequeue() *Item { + item := s.items[0] // 先进先出 + s.items = s.items[1:len(s.items)] + + return &item +} + +func (s *ItemQueue) IsEmpty() bool { + return len(s.items) == 0 +} + +// Size returns the number of Items in the queue +func (s *ItemQueue) Size() int { + return len(s.items) +} \ No newline at end of file diff --git a/server/chatserver/proto/chat.go b/server/chatserver/proto/chat.go new file mode 100644 index 0000000..5aec785 --- /dev/null +++ b/server/chatserver/proto/chat.go @@ -0,0 +1,64 @@ +package proto + +type LoginReq struct { + RId int `json:"rid"` + NickName string `json:"nickName"` + Token string `json:"token"` +} + +type LoginRsp struct { + RId int `json:"rid"` + NickName string `json:"nickName"` +} + +type LogoutReq struct { + RId int `json:"RId"` +} + +type LogoutRsp struct { + RId int `json:"RId"` +} + +type ChatReq struct { + Type int8 `json:"type"` //0世界聊天、1联盟聊天 + Msg string `json:"msg"` +} + + +type ChatMsg struct { + RId int `json:"rid"` + NickName string `json:"nickName"` + Type int8 `json:"type"` //0世界聊天、1联盟聊天 + Msg string `json:"msg"` + Time int64 `json:"time"` +} + + +type HistoryReq struct { + Type int8 `json:"type"` //0世界聊天、1联盟聊天 +} + +type HistoryRsp struct { + Type int8 `json:"type"` //0世界聊天、1联盟聊天 + Msgs []ChatMsg `json:"msgs"` +} + +type JoinReq struct { + Type int8 `json:"type"` //0世界聊天、1联盟聊天 + Id int `json:"id"` +} + +type JoinRsp struct { + Type int8 `json:"type"` //0世界聊天、1联盟聊天 + Id int `json:"id"` +} + +type ExitReq struct { + Type int8 `json:"type"` //0世界聊天、1联盟聊天 + Id int `json:"id"` +} + +type ExitRsp struct { + Type int8 `json:"type"` //0世界聊天、1联盟聊天 + Id int `json:"id"` +} \ No newline at end of file diff --git a/server/gateserver/controller/handle.go b/server/gateserver/controller/handle.go new file mode 100644 index 0000000..82ed555 --- /dev/null +++ b/server/gateserver/controller/handle.go @@ -0,0 +1,205 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "log/slog" + "slgserver/config" + "slgserver/constant" + "slgserver/middleware" + "slgserver/net" + chat_proto "slgserver/server/chatserver/proto" + "slgserver/server/slgserver/proto" + "strings" + "sync" +) + +var GHandle = Handle{ + proxys: make(map[string]map[int64]*net.ProxyClient), +} + +type Handle struct { + proxyMutex sync.Mutex + proxys map[string]map[int64]*net.ProxyClient + slgProxy string + chatProxy string + loginProxy string +} + +func isAccount(msgName string) bool { + sArr := strings.Split(msgName, ".") + prefix := "" + if len(sArr) == 2{ + prefix = sArr[0] + } + if prefix == "account"{ + return true + }else{ + return false + } +} + +func isChat(msgName string) bool { + sArr := strings.Split(msgName, ".") + prefix := "" + if len(sArr) == 2{ + prefix = sArr[0] + } + if prefix == "chat"{ + return true + }else{ + return false + } +} + + + +func (this*Handle) InitRouter(r *net.Router) { + this.init() + g := r.Group("*").Use(middleware.ElapsedTime(), middleware.Log()) + g.AddRouter("*", this.all) +} + +func (this*Handle) init() { + this.slgProxy = config.GetString("gateserver.slg_proxy", "ws://127.0.0.1:8001") + this.chatProxy = config.GetString("gateserver.chat_proxy", "ws://127.0.0.1:8002") + this.loginProxy = config.GetString("gateserver.login_proxy", "ws://127.0.0.1:8003") +} + +func (this*Handle) onPush(conn *net.ClientConn, body *net.RspBody) { + gc, err := conn.GetProperty("gateConn") + if err != nil{ + return + } + gateConn := gc.(net.WSConn) + gateConn.Push(body.Name, body.Msg) +} + +func (this*Handle) onProxyClose(conn *net.ClientConn) { + p, err := conn.GetProperty("proxy") + if err == nil { + proxyStr := p.(string) + this.proxyMutex.Lock() + _, ok := this.proxys[proxyStr] + if ok { + c, err := conn.GetProperty("cid") + if err == nil{ + cid := c.(int64) + delete(this.proxys[proxyStr], cid) + } + } + this.proxyMutex.Unlock() + } +} + +func (this*Handle) OnServerConnClose (conn net.WSConn){ + c, err := conn.GetProperty("cid") + arr := make([]*net.ProxyClient, 0) + + if err == nil{ + cid := c.(int64) + this.proxyMutex.Lock() + for _, m := range this.proxys { + proxy, ok := m[cid] + if ok { + arr = append(arr, proxy) + } + delete(m, cid) + } + this.proxyMutex.Unlock() + } + + for _, client := range arr { + client.Close() + } + +} + +func (this*Handle) all(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + slog.Info("gateserver handle all begin", + "proxyStr", req.Body.Proxy, + "msgName", req.Body.Name) + this.deal(req, rsp) + + if req.Body.Name == "role.enterServer" && rsp.Body.Code == constant.OK { + //登录聊天服 + rspObj := &proto.EnterServerRsp{} + mapstructure.Decode(rsp.Body.Msg, rspObj) + r := &chat_proto.LoginReq{RId: rspObj.Role.RId, NickName: rspObj.Role.NickName, Token: rspObj.Token} + reqBody := &net.ReqBody{Seq: 0, Name: "chat.login", Msg: r, Proxy: ""} + rspBody := &net.RspBody{Seq: 0, Name: "chat.login", Msg: r, Code: 0} + this.deal(&net.WsMsgReq{Body: reqBody, Conn:req.Conn}, &net.WsMsgRsp{Body: rspBody}) + } + + slog.Info("gateserver handle all end", + "proxyStr", req.Body.Proxy, + "msgName", req.Body.Name) +} + +func (this*Handle) deal(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + //协议转发 + proxyStr := req.Body.Proxy + if isAccount(req.Body.Name){ + proxyStr = this.loginProxy + }else if isChat(req.Body.Name){ + proxyStr = this.chatProxy + } else{ + proxyStr = this.slgProxy + } + + if proxyStr == ""{ + rsp.Body.Code = constant.ProxyNotInConnect + return + } + + this.proxyMutex.Lock() + _, ok := this.proxys[proxyStr] + if ok == false { + this.proxys[proxyStr] = make(map[int64]*net.ProxyClient) + } + + var err error + var proxy *net.ProxyClient + d, _ := req.Conn.GetProperty("cid") + cid := d.(int64) + proxy, ok = this.proxys[proxyStr][cid] + this.proxyMutex.Unlock() + + if ok == false { + proxy = net.NewProxyClient(proxyStr) + + this.proxyMutex.Lock() + this.proxys[proxyStr][cid] = proxy + this.proxyMutex.Unlock() + + //发起链接,这里是阻塞的,所以不要上锁 + err = proxy.Connect() + if err == nil{ + proxy.SetProperty("cid", cid) + proxy.SetProperty("proxy", proxyStr) + proxy.SetProperty("gateConn", req.Conn) + proxy.SetOnPush(this.onPush) + proxy.SetOnClose(this.onProxyClose) + } + } + + if err != nil { + this.proxyMutex.Lock() + delete(this.proxys[proxyStr], cid) + this.proxyMutex.Unlock() + rsp.Body.Code = constant.ProxyConnectError + return + } + + rsp.Body.Seq = req.Body.Seq + rsp.Body.Name = req.Body.Name + + r, err := proxy.Send(req.Body.Name, req.Body.Msg) + if err == nil{ + rsp.Body.Code = r.Code + rsp.Body.Msg = r.Msg + }else{ + rsp.Body.Code = constant.ProxyConnectError + rsp.Body.Msg = nil + } +} + diff --git a/server/gateserver/init.go b/server/gateserver/init.go new file mode 100644 index 0000000..2dd3ef2 --- /dev/null +++ b/server/gateserver/init.go @@ -0,0 +1,19 @@ +package gateserver + +import ( + "slgserver/net" + "slgserver/server/gateserver/controller" +) + +var MyRouter = &net.Router{} + +func Init() { + //全部初始化完才注册路由,防止服务器还没启动就绪收到请求 + initRouter() +} + +func initRouter() { + controller.GHandle.InitRouter(MyRouter) +} + + diff --git a/server/httpserver/controller/account.go b/server/httpserver/controller/account.go new file mode 100644 index 0000000..50ef861 --- /dev/null +++ b/server/httpserver/controller/account.go @@ -0,0 +1,59 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "net/http" + "log/slog" + "slgserver/constant" + myhttp "slgserver/server/httpserver" + "slgserver/server/httpserver/logic" + "slgserver/server/httpserver/middleware" +) + +type AccountController struct{} + +func (self AccountController) RegisterRoutes(g *gin.RouterGroup) { + g.Use(middleware.Cors()) + + g.Any("/account/register", self.register) + g.Any("/account/changepwd", self.changePwd) + g.Any("/account/forgetpwd", self.forgetPwd) + g.Any("/account/resetpwd", self.resetPwd) +} + +func (self AccountController) register(ctx *gin.Context) { + slog.Info("register") + data := make(map[string]interface{}) + if err := logic.DefaultUser.CreateUser(ctx); err != nil { + data["code"] = err.(*myhttp.MyError).Id() + data["errmsg"] = err.(*myhttp.MyError).Error() + }else{ + data["code"] = constant.OK + } + + ctx.JSON(http.StatusOK, data) +} + +func (self AccountController) forgetPwd(ctx *gin.Context) { + slog.Info("forgetPwd") + ctx.String(http.StatusOK, "forgetPwd") +} + +func (self AccountController) changePwd(ctx *gin.Context) { + slog.Info("changePwd") + data := make(map[string]interface{}) + if err := logic.DefaultUser.ChangePassword(ctx); err != nil { + data["code"] = err.(*myhttp.MyError).Id() + data["errmsg"] = err.(*myhttp.MyError).Error() + }else{ + data["code"] = constant.OK + } + + ctx.JSON(http.StatusOK, data) +} + +func (self AccountController) resetPwd(ctx *gin.Context) { + slog.Info("resetPwd") + ctx.String(http.StatusOK, "resetPwd") +} + diff --git a/server/httpserver/logic/account.go b/server/httpserver/logic/account.go new file mode 100644 index 0000000..ba464d6 --- /dev/null +++ b/server/httpserver/logic/account.go @@ -0,0 +1,88 @@ +package logic + +import ( + "fmt" + "github.com/gin-gonic/gin" + "math/rand" + "slgserver/constant" + "slgserver/db" + myhttp "slgserver/server/httpserver" + "slgserver/server/loginserver/model" + "slgserver/util" + "time" +) + +type UserLogic struct{} +var DefaultUser = UserLogic{} + +func (self UserLogic) CreateUser(ctx *gin.Context) error { + account := ctx.Query("username") + pwd := ctx.Query("password") + hardware := ctx.Query("hardware") + + if len(account) > 0 && len(pwd) > 0 { + if self.UserExists("username", account) { + return myhttp.New("账号已经存在", constant.UserExist) + } + + passcode := fmt.Sprintf("%x", rand.Int31()) + user := &model.User{ + Username: account, + Passcode: passcode, + Passwd: util.Password(pwd, passcode), + Hardware: hardware, + Ctime: time.Now(), + Mtime: time.Now()} + + if _, err := db.MasterDB.Insert(user); err != nil { + return myhttp.New("数据库出错", constant.DBError) + } else{ + return nil + } + }else{ + return myhttp.New("用户名或密码是空", constant.InvalidParam) + } +} + +func (self UserLogic) ChangePassword(ctx *gin.Context) error { + account := ctx.Query("username") + pwd := ctx.Query("password") + newpwd := ctx.Query("newpassword") + + user := &model.User{} + if len(account) > 0 && len(pwd) > 0 && len(newpwd) > 0{ + if _, err := db.MasterDB.Where("username=?", account).Get(user); err != nil { + return myhttp.New("数据库出错", constant.DBError) + }else{ + if util.Password(pwd, user.Passcode) == user.Passwd { + passcode := fmt.Sprintf("%x", rand.Int31()) + changeData := map[string]interface{}{ + "passwd": util.Password(newpwd, passcode), + "passcode": passcode, + "Mtime": time.Now(), + } + + if _, err := db.MasterDB.Table(user).Where("username=?", account).Update(changeData); err !=nil { + return myhttp.New("数据库出错", constant.DBError) + }else{ + return nil + } + + }else{ + return myhttp.New("原密码错误", constant.PwdIncorrect) + } + } + + }else{ + return myhttp.New("用户名或密码是空", constant.InvalidParam) + } +} + +func (UserLogic) UserExists(field, val string) bool { + userLogin := &model.User{} + _, err := db.MasterDB.Where(field+"=?", val).Get(userLogin) + if err != nil || userLogin.UId == 0 { + return false + } + return true +} diff --git a/server/httpserver/middleware/cors.go b/server/httpserver/middleware/cors.go new file mode 100644 index 0000000..157bda4 --- /dev/null +++ b/server/httpserver/middleware/cors.go @@ -0,0 +1,22 @@ +package middleware + +import ( + "github.com/gin-gonic/gin" +) + +func Cors() gin.HandlerFunc { + return func(ctx *gin.Context) { + ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*") + ctx.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept") + ctx.Writer.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS, POST, PUT, DELETE") + ctx.Writer.Header().Set("Content-Type", "application/json") + + if ctx.Request.Method == "OPTIONS" { + ctx.AbortWithStatus(204) + return + } + + ctx.Next() + } +} + diff --git a/server/httpserver/myerror.go b/server/httpserver/myerror.go new file mode 100644 index 0000000..cd99836 --- /dev/null +++ b/server/httpserver/myerror.go @@ -0,0 +1,21 @@ +package httpserver + +type MyError struct { + err string + id int +} + +func New(err string, id int) error { + return &MyError{err: err, id: id} +} + +func (self *MyError) Error() string { + return self.err +} + +func (self *MyError) Id() int { + return self.id +} + + + diff --git a/server/loginserver/controller/account.go b/server/loginserver/controller/account.go new file mode 100644 index 0000000..1afab08 --- /dev/null +++ b/server/loginserver/controller/account.go @@ -0,0 +1,189 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "slgserver/constant" + "slgserver/db" + "log/slog" + "slgserver/middleware" + "slgserver/net" + "slgserver/server/loginserver/model" + "slgserver/server/loginserver/proto" + "slgserver/util" + "time" +) + +var DefaultAccount = Account{} + +type Account struct { +} + +func (this*Account) InitRouter(r *net.Router) { + g := r.Group("account").Use(middleware.ElapsedTime(), middleware.Log()) + + g.AddRouter("login", this.login) + g.AddRouter("reLogin", this.reLogin) + g.AddRouter("logout", this.logout, middleware.CheckLogin()) + g.AddRouter("serverList", this.serverList, middleware.CheckLogin()) +} + +func (this*Account) login(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + + reqObj := &proto.LoginReq{} + rspObj := &proto.LoginRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + + user := &model.User{} + ok, err := db.MasterDB.Table(user).Where("username=?", reqObj.Username).Get(user) + if err!= nil { + slog.Error("login db error", + "username", reqObj.Username, + "error", err) + + rsp.Body.Code = constant.DBError + }else{ + if ok { + pwd := util.Password(reqObj.Password, user.Passcode) + if pwd != user.Passwd{ + //密码不正确 + slog.Warn("login password not right", + "username", user.Username) + rsp.Body.Code = constant.PwdIncorrect + }else{ + tt := time.Now() + s := util.NewSession(user.UId, tt) + + sessStr := s.String() + + slog.Info("login", + "username", user.Username, + "session", sessStr) + + //登录成功,写记录 + lh := &model.LoginHistory{UId: user.UId, CTime: tt, Ip: reqObj.Ip, + Hardware: reqObj.Hardware, State: model.Login} + db.MasterDB.Insert(lh) + + ll := &model.LoginLast{} + ok, _ := db.MasterDB.Table(ll).Where("uid=?", user.UId).Get(ll) + if ok { + ll.IsLogout = 0 + ll.Ip = reqObj.Ip + ll.LoginTime = time.Now() + ll.Session = sessStr + ll.Hardware = reqObj.Hardware + + _, err := db.MasterDB.ID(ll.Id).Cols( + "is_logout", "ip", "login_time", "session", "hardware").Update(ll) + if err != nil { + slog.Error("update login_last table fail", "error", err) + } + + + }else{ + ll = &model.LoginLast{UId: user.UId, LoginTime: tt, + Ip: reqObj.Ip, Session: sessStr, + Hardware: reqObj.Hardware, IsLogout: 0} + db.MasterDB.Insert(ll) + } + + rspObj.Session = sessStr + rspObj.Password = reqObj.Password + rspObj.Username = reqObj.Username + rspObj.UId = user.UId + + rsp.Body.Code = constant.OK + + net.ConnMgr.UserLogin(req.Conn, sessStr, ll.UId) + } + }else{ + //数据库出错 + slog.Warn("login username not found", "username", reqObj.Username) + rsp.Body.Code = constant.UserNotExist + } + } + +} + +func (this*Account) reLogin(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ReLoginReq{} + rspObj := &proto.ReLoginRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + if reqObj.Session == ""{ + rsp.Body.Code = constant.SessionInvalid + return + } + + rsp.Body.Msg = rspObj + rspObj.Session = reqObj.Session + + sess, err := util.ParseSession(reqObj.Session) + if err != nil{ + rsp.Body.Code = constant.SessionInvalid + }else{ + if sess.IsValid() { + //数据库验证一下 + ll := &model.LoginLast{} + db.MasterDB.Table(ll).Where("uid=?", sess.Id).Get(ll) + + if ll.Session == reqObj.Session { + if ll.Hardware == reqObj.Hardware { + rsp.Body.Code = constant.OK + net.ConnMgr.UserLogin(req.Conn, reqObj.Session, ll.UId) + }else{ + rsp.Body.Code = constant.HardwareIncorrect + } + }else{ + rsp.Body.Code = constant.SessionInvalid + } + }else{ + rsp.Body.Code = constant.SessionInvalid + } + } +} + +func (this*Account) logout(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + + reqObj := &proto.LogoutReq{} + rspObj := &proto.LogoutRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rspObj.UId = reqObj.UId + rsp.Body.Code = constant.OK + + slog.Info("logout", "uid", reqObj.UId) + + tt := time.Now() + //登出,写记录 + lh := &model.LoginHistory{UId: reqObj.UId, CTime: tt, State: model.Logout} + db.MasterDB.Insert(lh) + + ll := &model.LoginLast{} + ok, _ := db.MasterDB.Table(ll).Where("uid=?", reqObj.UId).Get(ll) + if ok { + ll.IsLogout = 1 + ll.LogoutTime = time.Now() + db.MasterDB.ID(ll.Id).Cols("is_logout", "logout_time").Update(ll) + + }else{ + ll = &model.LoginLast{UId: reqObj.UId, LogoutTime: tt, IsLogout: 0} + db.MasterDB.Insert(ll) + } + + net.ConnMgr.UserLogout(req.Conn) + +} + +func (this*Account) serverList(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ServerListReq{} + rspObj := &proto.ServerListRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Code = constant.OK + + s := proto.Server{Id: 1, Slg: "ws://127.0.0.1:8001", Chat: "ws://127.0.0.1:8002"} + r := make([]proto.Server, 0) + rspObj.Lists = append(r, s) + + rsp.Body.Msg = rspObj +} diff --git a/server/loginserver/init.go b/server/loginserver/init.go new file mode 100644 index 0000000..078f7a6 --- /dev/null +++ b/server/loginserver/init.go @@ -0,0 +1,21 @@ +package loginserver + +import ( + "slgserver/db" + "slgserver/net" + "slgserver/server/loginserver/controller" +) + + +var MyRouter = &net.Router{} + +func Init() { + db.TestDB() + //全部初始化完才注册路由,防止服务器还没启动就绪收到请求 + initRouter() +} + +func initRouter() { + controller.DefaultAccount.InitRouter(MyRouter) +} + diff --git a/server/loginserver/model/login.go b/server/loginserver/model/login.go new file mode 100644 index 0000000..aa31559 --- /dev/null +++ b/server/loginserver/model/login.go @@ -0,0 +1,39 @@ +package model + +import ( + "time" +) + +const ( + Login = iota + Logout +) + +type LoginHistory struct { + Id int `xorm:"id pk autoincr"` + UId int `xorm:"uid"` + CTime time.Time `xorm:"ctime"` + Ip string `xorm:"ip"` + State int8 `xorm:"state"` + Hardware string `xorm:"hardware"` +} + +func (this *LoginHistory) TableName() string { + return "tb_login_history" +} + + +type LoginLast struct { + Id int `xorm:"id pk autoincr"` + UId int `xorm:"uid"` + LoginTime time.Time `xorm:"login_time"` + LogoutTime time.Time `xorm:"logout_time"` + Ip string `xorm:"ip"` + Session string `xorm:"session"` + IsLogout int8 `xorm:"is_logout"` + Hardware string `xorm:"hardware"` +} + +func (this *LoginLast) TableName() string { + return "tb_login_last" +} \ No newline at end of file diff --git a/server/loginserver/model/user.go b/server/loginserver/model/user.go new file mode 100644 index 0000000..8424b69 --- /dev/null +++ b/server/loginserver/model/user.go @@ -0,0 +1,19 @@ +package model + +import "time" + +type User struct { + UId int `xorm:"uid pk autoincr"` + Username string `xorm:"username" validate:"min=4,max=20,regexp=^[a-zA-Z0-9_]*$"` + Passcode string `xorm:"passcode"` + Passwd string `xorm:"passwd"` + Hardware string `xorm:"hardware"` + Status int `xorm:"status"` + Ctime time.Time `xorm:"ctime"` + Mtime time.Time `xorm:"mtime"` + IsOnline bool `xorm:"-"` +} + +func (this *User) TableName() string { + return "tb_user_info" +} \ No newline at end of file diff --git a/server/loginserver/proto/account.go b/server/loginserver/proto/account.go new file mode 100644 index 0000000..6f8b50e --- /dev/null +++ b/server/loginserver/proto/account.go @@ -0,0 +1,47 @@ +package proto + +type LoginReq struct { + Username string `json:"username"` + Password string `json:"password"` + Ip string `json:"ip"` + Hardware string `json:"hardware"` +} + +type LoginRsp struct { + Username string `json:"username"` + Password string `json:"password"` + Session string `json:"session"` + UId int `json:"uid"` +} + +type ReLoginReq struct { + Session string `json:"session"` + Ip string `json:"ip"` + Hardware string `json:"hardware"` +} + +type ReLoginRsp struct { + Session string `json:"session"` +} + +type LogoutReq struct { + UId int `json:"uid"` +} + +type LogoutRsp struct { + UId int `json:"uid"` +} + +type Server struct { + Id int `json:"id"` + Slg string `json:"slg"` + Chat string `json:"chat"` +} + +type ServerListReq struct { + +} + +type ServerListRsp struct { + Lists []Server +} diff --git a/server/slgserver/conn/push_sync.go b/server/slgserver/conn/push_sync.go new file mode 100644 index 0000000..fc0cb4d --- /dev/null +++ b/server/slgserver/conn/push_sync.go @@ -0,0 +1,12 @@ +package conn + +type PushSync interface { + IsCellView() bool //是否格子视野 + IsCanView(rid, x, y int)bool //是否能出现在视野 + BelongToRId() []int //属于的rid + PushMsgName() string //推送名字 + Position() (int, int) //x, y + TPosition() (int, int) //目标x, y + ToProto() interface{} //转成proto + Push() //推送 +} diff --git a/server/slgserver/controller/army.go b/server/slgserver/controller/army.go new file mode 100644 index 0000000..b170280 --- /dev/null +++ b/server/slgserver/controller/army.go @@ -0,0 +1,569 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "slgserver/constant" + "slgserver/middleware" + "slgserver/net" + "slgserver/server/slgserver/global" + "slgserver/server/slgserver/logic" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/proto" + "slgserver/server/slgserver/static_conf" + "slgserver/server/slgserver/static_conf/facility" + "slgserver/server/slgserver/static_conf/general" + "time" +) + +var DefaultArmy = Army{ + +} + +type Army struct { + +} + + +func (this*Army) InitRouter(r *net.Router) { + g := r.Group("army").Use(middleware.ElapsedTime(), middleware.Log(), + middleware.CheckLogin(), middleware.CheckRole()) + + g.AddRouter("myList", this.myList) + g.AddRouter("myOne", this.myOne) + g.AddRouter("dispose", this.dispose) + g.AddRouter("conscript", this.conscript) + g.AddRouter("assign", this.assign) + +} + +//我的军队列表 +func (this*Army) myList(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ArmyListReq{} + rspObj := &proto.ArmyListRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + rspObj.CityId = reqObj.CityId + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + city,ok := mgr.RCMgr.Get(reqObj.CityId) + if ok == false{ + rsp.Body.Code = constant.CityNotExist + return + } + + if city.RId != role.RId { + rsp.Body.Code = constant.CityNotMe + return + } + + as, _ := mgr.AMgr.GetByCity(reqObj.CityId) + rspObj.Armys = make([]proto.Army, len(as)) + for i, v := range as { + rspObj.Armys[i] = v.ToProto().(proto.Army) + } +} + +//我的某一个军队 +func (this*Army) myOne(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ArmyOneReq{} + rspObj := &proto.ArmyOneRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + city, ok := mgr.RCMgr.Get(reqObj.CityId) + if ok == false{ + rsp.Body.Code = constant.CityNotExist + return + } + + if city.RId != role.RId { + rsp.Body.Code = constant.CityNotMe + return + } + + a, ok := mgr.AMgr.GetByCityOrder(reqObj.CityId, reqObj.Order) + if ok { + rspObj.Army = a.ToProto().(proto.Army) + }else{ + rsp.Body.Code = constant.ArmyNotFound + } + +} + +//配置武将 +func (this*Army) dispose(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + + reqObj := &proto.DisposeReq{} + rspObj := &proto.DisposeRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if reqObj.Order <= 0 || reqObj.Order > 5 || reqObj.Position < -1 || reqObj.Position >2 { + rsp.Body.Code = constant.InvalidParam + return + } + + city, ok := mgr.RCMgr.Get(reqObj.CityId) + if ok == false { + rsp.Body.Code = constant.CityNotExist + return + } + + if city.RId != role.RId { + rsp.Body.Code = constant.CityNotMe + return + } + + //校场每升一级一个队伍 + jc, ok := mgr.RFMgr.GetFacility(city.CityId, facility.JiaoChang) + if ok == false || jc.GetLevel() < reqObj.Order { + rsp.Body.Code = constant.ArmyNotEnough + return + } + + newG, ok := mgr.GMgr.GetByGId(reqObj.GeneralId) + if ok == false{ + rsp.Body.Code = constant.GeneralNotFound + return + } + + if newG.RId != role.RId{ + rsp.Body.Code = constant.GeneralNotMe + return + } + + army, err := mgr.AMgr.GetOrCreate(role.RId, reqObj.CityId, reqObj.Order) + if err != nil{ + rsp.Body.Code = constant.DBError + return + } + + if army.FromX != city.X || army.FromY != city.Y { + rsp.Body.Code = constant.ArmyIsOutside + return + } + + //下阵 + if reqObj.Position == -1{ + for pos, g := range army.Gens { + if g != nil && g.Id == newG.Id{ + + //征兵中不能下阵 + if army.PositionCanModify(pos) == false{ + if army.Cmd == model.ArmyCmdConscript{ + rsp.Body.Code = constant.GeneralBusy + }else{ + rsp.Body.Code = constant.ArmyBusy + } + return + } + + army.GeneralArray[pos] = 0 + army.SoldierArray[pos] = 0 + army.Gens[pos] = nil + army.SyncExecute() + break + } + } + newG.Order = 0 + newG.CityId = 0 + newG.SyncExecute() + }else{ + + //征兵中不能下阵 + if army.PositionCanModify(reqObj.Position) == false{ + if army.Cmd == model.ArmyCmdConscript{ + rsp.Body.Code = constant.GeneralBusy + }else{ + rsp.Body.Code = constant.ArmyBusy + } + return + } + + if newG.CityId != 0{ + rsp.Body.Code = constant.GeneralBusy + return + } + + if mgr.AMgr.IsRepeat(role.RId, newG.CfgId) == false{ + rsp.Body.Code = constant.GeneralRepeat + return + } + + //判断是否能配前锋 + tst, ok := mgr.RFMgr.GetFacility(city.CityId, facility.TongShuaiTing) + if reqObj.Position == 2 && ( ok == false || tst.GetLevel() < reqObj.Order) { + rsp.Body.Code = constant.TongShuaiNotEnough + return + } + + //判断cost + cost := general.General.Cost(newG.CfgId) + for i, g := range army.Gens { + if g == nil || i == reqObj.Position { + continue + } + cost += general.General.Cost(g.CfgId) + } + + if mgr.GetCityCost(city.CityId) < cost{ + rsp.Body.Code = constant.CostNotEnough + return + } + + oldG := army.Gens[reqObj.Position] + if oldG != nil { + //旧的下阵 + oldG.CityId = 0 + oldG.Order = 0 + oldG.SyncExecute() + } + + //新的上阵 + army.GeneralArray[reqObj.Position] = reqObj.GeneralId + army.Gens[reqObj.Position] = newG + army.SoldierArray[reqObj.Position] = 0 + + newG.Order = reqObj.Order + newG.CityId = reqObj.CityId + newG.SyncExecute() + } + + army.FromX = city.X + army.FromY = city.Y + army.SyncExecute() + //队伍 + rspObj.Army = army.ToProto().(proto.Army) +} + +//征兵 +func (this*Army) conscript(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ConscriptReq{} + rspObj := &proto.ConscriptRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + if reqObj.ArmyId <= 0 || len(reqObj.Cnts) != 3 || + reqObj.Cnts[0] < 0 || reqObj.Cnts[1] < 0 || reqObj.Cnts[2] < 0{ + rsp.Body.Code = constant.InvalidParam + return + } + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + army,ok := mgr.AMgr.Get(reqObj.ArmyId) + if ok == false{ + rsp.Body.Code = constant.ArmyNotFound + return + } + + if role.RId != army.RId{ + rsp.Body.Code = constant.ArmyNotMe + return + } + + //判断该位置是否能征兵 + for pos, cnt := range reqObj.Cnts { + if cnt > 0{ + if army.Gens[pos] == nil{ + rsp.Body.Code = constant.InvalidParam + return + } + if army.PositionCanModify(pos) == false{ + rsp.Body.Code = constant.GeneralBusy + return + } + } + } + + lv := mgr.RFMgr.GetFacilityLv(army.CityId, facility.MBS) + if lv <= 0{ + rsp.Body.Code = constant.BuildMBSNotFound + return + } + + //判断是否超过上限 + for i, g := range army.Gens { + if g == nil { + continue + } + + l, e := general.GenBasic.GetLevel(g.Level) + add := mgr.RFMgr.GetAdditions(army.CityId, facility.TypeSoldierLimit) + if e == nil{ + if l.Soldiers + add[0] < reqObj.Cnts[i]+army.SoldierArray[i]{ + rsp.Body.Code = constant.OutArmyLimit + return + } + }else{ + rsp.Body.Code = constant.InvalidParam + return + } + } + + //开始征兵 + total := 0 + for _, n := range reqObj.Cnts { + total += n + } + + conscript := static_conf.Basic.ConScript + needWood := total*conscript.CostWood + needGrain := total*conscript.CostGrain + needIron := total*conscript.CostIron + needStone := total*conscript.CostStone + needGold := total*conscript.CostGold + + nr := facility.NeedRes{Grain: needGrain, Wood: needWood, + Gold: needGold, Iron: needIron, Decree: 0, + Stone: needStone} + + if code := mgr.RResMgr.TryUseNeed(army.RId, nr); code == constant.OK { + curTime := time.Now().Unix() + for i, _ := range army.SoldierArray { + if reqObj.Cnts[i] > 0{ + army.ConscriptCntArray[i] = reqObj.Cnts[i] + army.ConscriptTimeArray[i] = int64(reqObj.Cnts[i]*conscript.CostTime) + curTime - 2 + } + } + + army.Cmd = model.ArmyCmdConscript + army.SyncExecute() + + //队伍 + rspObj.Army = army.ToProto().(proto.Army) + + //资源 + if rRes, ok := mgr.RResMgr.Get(role.RId); ok { + rspObj.RoleRes = rRes.ToProto().(proto.RoleRes) + } + rsp.Body.Code = constant.OK + }else{ + rsp.Body.Code = constant.ResNotEnough + } +} + +//派遣队伍 +func (this*Army) assign(req *net.WsMsgReq, rsp *net.WsMsgRsp){ + reqObj := &proto.AssignArmyReq{} + rspObj := &proto.AssignArmyRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + army,ok := mgr.AMgr.Get(reqObj.ArmyId) + if ok == false{ + rsp.Body.Code = constant.ArmyNotFound + return + } + + if role.RId != army.RId{ + rsp.Body.Code = constant.ArmyNotMe + return + } + + if reqObj.Cmd == model.ArmyCmdBack{ + rsp.Body.Code = this.__back__(army) + }else if reqObj.Cmd == model.ArmyCmdAttack { + rsp.Body.Code = this.__attack__(reqObj, army, role) + }else if reqObj.Cmd == model.ArmyCmdDefend { + rsp.Body.Code = this.__defend__(reqObj, army, role) + }else if reqObj.Cmd == model.ArmyCmdReclamation { + rsp.Body.Code = this.__reclamation__(reqObj, army, role) + }else if reqObj.Cmd == model.ArmyCmdTransfer { + rsp.Body.Code = this.__transfer__(reqObj, army, role) + } + + rspObj.Army = army.ToProto().(proto.Army) +} + + +func (this*Army) __pre__(reqObj *proto.AssignArmyReq, army* model.Army, role *model.Role) int{ + + if reqObj.X < 0 || reqObj.X >= global.MapWith || + reqObj.Y < 0 || reqObj.Y >= global.MapHeight { + return constant.InvalidParam + } + + if army.IsCanOutWar() == false{ + if army.Cmd != model.ArmyCmdIdle{ + return constant.ArmyBusy + }else{ + return constant.ArmyNotMain + } + } + + if army.IsIdle() == false { + return constant.ArmyBusy + } + + //判断该地是否是能攻击类型 + cfg, ok := mgr.NMMgr.PositionBuild(reqObj.X, reqObj.Y) + if ok == false || cfg.Type == 0 { + return constant.InvalidParam + } + + if logic.IsCanArrive(reqObj.X, reqObj.Y, role.RId) == false{ + return constant.UnReachable + } + + return constant.OK +} + +func (this*Army) __after__(reqObj *proto.AssignArmyReq, army* model.Army) int{ + //最后才消耗体力 + cost := static_conf.Basic.General.CostPhysicalPower + ok := mgr.GMgr.PhysicalPowerIsEnough(army, cost) + if ok == false{ + return constant.PhysicalPowerNotEnough + } + + if reqObj.Cmd == model.ArmyCmdReclamation || reqObj.Cmd == model.ArmyCmdTransfer { + cost := static_conf.Basic.General.ReclamationCost + if mgr.RResMgr.DecreeIsEnough(army.RId, cost) == false{ + return constant.DecreeNotEnough + }else{ + mgr.RResMgr.TryUseDecree(army.RId, cost) + } + } + + mgr.GMgr.TryUsePhysicalPower(army, cost) + + army.ToX = reqObj.X + army.ToY = reqObj.Y + army.Cmd = reqObj.Cmd + army.State = model.ArmyRunning + + //speed := mgr.AMgr.GetSpeed(army) + //t := mgr.TravelTime(speed, army.FromX, army.FromY, army.ToX, army.ToY) + army.Start = time.Now() + //army.End = time.Now().Add(time.Duration(t) * time.Millisecond) + army.End = time.Now().Add(40*time.Second) + logic.ArmyLogic.PushAction(army) + return constant.OK +} + +//返回 +func (this*Army) __back__(army* model.Army) int{ + if army.Cmd == model.ArmyCmdAttack || + army.Cmd == model.ArmyCmdDefend || + army.Cmd == model.ArmyCmdReclamation { + logic.ArmyLogic.ArmyBack(army) + }else if army.IsIdle(){ + city, ok := mgr.RCMgr.Get(army.CityId) + if ok { + if city.X != army.FromX || city.Y != army.FromY{ + logic.ArmyLogic.ArmyBack(army) + } + } + + } + return constant.OK +} + +//攻击 +func (this*Army) __attack__(reqObj *proto.AssignArmyReq, army* model.Army, role *model.Role) int{ + + code := this.__pre__(reqObj, army, role) + if code != constant.OK { + return code + } + + if logic.IsCanArrive(reqObj.X, reqObj.Y, role.RId) == false{ + return constant.UnReachable + } + + //免战 + if logic.IsWarFree(reqObj.X, reqObj.Y){ + return constant.BuildWarFree + } + + if logic.IsCanDefend(reqObj.X, reqObj.Y, role.RId) == true { + return constant.BuildCanNotAttack + } + + return this.__after__(reqObj, army) +} + +//驻守 +func (this*Army) __defend__(reqObj *proto.AssignArmyReq, army* model.Army, role *model.Role) int{ + + code := this.__pre__(reqObj, army, role) + if code != constant.OK { + return code + } + + if logic.IsCanDefend(reqObj.X, reqObj.Y, role.RId) == false { + return constant.BuildCanNotDefend + } + + return this.__after__(reqObj, army) +} + +func (this*Army) __reclamation__(reqObj *proto.AssignArmyReq, army* model.Army, role *model.Role) int{ + + code := this.__pre__(reqObj, army, role) + if code != constant.OK { + return code + } + + if mgr.RBMgr.BuildIsRId(reqObj.X, reqObj.Y, role.RId) == false { + return constant.BuildNotMe + } + + return this.__after__(reqObj, army) +} + +func (this*Army) __transfer__(reqObj *proto.AssignArmyReq, army* model.Army, role *model.Role) int{ + + code := this.__pre__(reqObj, army, role) + if code != constant.OK { + return code + } + + if army.FromX == reqObj.X && army.FromY == reqObj.Y{ + return constant.CanNotTransfer + } + + if mgr.RBMgr.BuildIsRId(reqObj.X, reqObj.Y, role.RId) == false { + return constant.BuildNotMe + } + + b, ok := mgr.RBMgr.PositionBuild(reqObj.X, reqObj.Y) + if ok == false { + return constant.BuildNotMe + } + + if b.Level <= 0 || b.IsHasTransferAuth() == false { + return constant.CanNotTransfer + } + + cnt := 0 + if b.IsRoleFortress() { + cnt = static_conf.MapBCConf.GetHoldArmyCnt(b.Type, b.Level) + }else{ + cnt = 5 + } + + if cnt > mgr.AMgr.BelongPosArmyCnt(b.RId, b.X, b.Y) { + return this.__after__(reqObj, army) + }else{ + return constant.HoldIsFull + } + +} \ No newline at end of file diff --git a/server/slgserver/controller/city.go b/server/slgserver/controller/city.go new file mode 100644 index 0000000..8ec0ede --- /dev/null +++ b/server/slgserver/controller/city.go @@ -0,0 +1,109 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "slgserver/constant" + "slgserver/middleware" + "slgserver/net" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/proto" +) + +var DefaultCity = City{ + +} +type City struct { + +} + +func (this*City) InitRouter(r *net.Router) { + g := r.Group("city").Use(middleware.ElapsedTime(), middleware.Log(), + middleware.CheckLogin(), middleware.CheckRole()) + + g.AddRouter("facilities", this.facilities) + g.AddRouter("upFacility", this.upFacility) + +} + +func (this*City) facilities(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.FacilitiesReq{} + rspObj := &proto.FacilitiesRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rspObj.CityId = reqObj.CityId + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + city, ok := mgr.RCMgr.Get(reqObj.CityId) + if ok == false { + rsp.Body.Code = constant.CityNotExist + return + } + + role := r.(*model.Role) + if city.RId != role.RId { + rsp.Body.Code = constant.CityNotMe + return + } + + f, ok := mgr.RFMgr.Get(reqObj.CityId) + if ok == false { + rsp.Body.Code = constant.CityNotExist + return + } + + t := f.Facility() + + rspObj.Facilities = make([]proto.Facility, len(t)) + for i, v := range t { + rspObj.Facilities[i].Name = v.Name + rspObj.Facilities[i].Level = v.GetLevel() + rspObj.Facilities[i].Type = v.Type + rspObj.Facilities[i].UpTime = v.UpTime + } + +} + +//升级需要耗费时间,为了减少定时任务,升级这里做成被动触发产生,不做定时任务 +func (this*City) upFacility(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.UpFacilityReq{} + rspObj := &proto.UpFacilityRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rspObj.CityId = reqObj.CityId + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + city, ok := mgr.RCMgr.Get(reqObj.CityId) + if ok == false { + rsp.Body.Code = constant.CityNotExist + return + } + + role := r.(*model.Role) + if city.RId != role.RId { + rsp.Body.Code = constant.CityNotMe + return + } + + _, ok = mgr.RFMgr.Get(reqObj.CityId) + if ok == false { + rsp.Body.Code = constant.CityNotExist + return + } + + out, errCode := mgr.RFMgr.UpFacility(role.RId ,reqObj.CityId, reqObj.FType) + rsp.Body.Code = errCode + if errCode == constant.OK{ + rspObj.Facility.Level = out.GetLevel() + rspObj.Facility.Type = out.Type + rspObj.Facility.Name = out.Name + rspObj.Facility.UpTime = out.UpTime + + if roleRes, ok:= mgr.RResMgr.Get(role.RId); ok { + rspObj.RoleRes = roleRes.ToProto().(proto.RoleRes) + } + } + +} diff --git a/server/slgserver/controller/coalition.go b/server/slgserver/controller/coalition.go new file mode 100644 index 0000000..af71ed8 --- /dev/null +++ b/server/slgserver/controller/coalition.go @@ -0,0 +1,688 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "log/slog" + "slgserver/constant" + "slgserver/db" + "slgserver/middleware" + "slgserver/net" + "slgserver/server/slgserver/logic" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/proto" + "slgserver/server/slgserver/static_conf" + "time" +) + +var DefaultCoalition= coalition{ + +} + +type coalition struct { + +} + +func (this *coalition) InitRouter(r *net.Router) { + g := r.Group("union").Use(middleware.ElapsedTime(), middleware.Log(), + middleware.CheckLogin(), middleware.CheckRole()) + + g.AddRouter("create", this.create) + g.AddRouter("list", this.list) + g.AddRouter("join", this.join) + g.AddRouter("verify", this.verify) + g.AddRouter("member", this.member) + g.AddRouter("applyList", this.applyList) + g.AddRouter("exit", this.exit) + g.AddRouter("dismiss", this.dismiss) + g.AddRouter("notice", this.notice) + g.AddRouter("modNotice", this.modNotice) + g.AddRouter("kick", this.kick) + g.AddRouter("appoint", this.appoint) + g.AddRouter("abdicate", this.abdicate) + g.AddRouter("info", this.info) + g.AddRouter("log", this.log) + +} + +//创建联盟 +func (this *coalition) create(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.CreateReq{} + rspObj := &proto.CreateRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + rspObj.Name = reqObj.Name + + has := mgr.RAttrMgr.IsHasUnion(role.RId) + if has { + rsp.Body.Code = constant.UnionAlreadyHas + return + } + + c, ok := mgr.UnionMgr.Create(reqObj.Name, role.RId) + if ok { + rspObj.Id = c.Id + logic.Union.MemberEnter(role.RId, c.Id) + model.NewCreate(role.NickName, c.Id, role.RId) + }else{ + rsp.Body.Code = constant.UnionCreateError + } +} + +//联盟列表 +func (this *coalition) list(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ListReq{} + rspObj := &proto.ListRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + l := mgr.UnionMgr.List() + rspObj.List = make([]proto.Union, len(l)) + for i, u := range l { + rspObj.List[i] = u.ToProto().(proto.Union) + main := make([]proto.Major, 0) + if r, ok := mgr.RMgr.Get(u.Chairman); ok { + m := proto.Major{Name: r.NickName, RId: r.RId, Title: proto.UnionChairman} + main = append(main, m) + } + + if r, ok := mgr.RMgr.Get(u.ViceChairman); ok { + m := proto.Major{Name: r.NickName, RId: r.RId, Title: proto.UnionViceChairman} + main = append(main, m) + } + rspObj.List[i].Major = main + } +} + +//加入 +func (this *coalition) join(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.JoinReq{} + rspObj := &proto.JoinRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + has := mgr.RAttrMgr.IsHasUnion(role.RId) + if has { + rsp.Body.Code = constant.UnionAlreadyHas + return + } + + u, ok := mgr.UnionMgr.Get(reqObj.Id) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + return + } + + if len(u.MemberArray) >= static_conf.Basic.Union.MemberLimit{ + rsp.Body.Code = constant.PeopleIsFull + return + } + + //判断当前是否已经有申请 + has, _ = db.MasterDB.Table(model.CoalitionApply{}).Where( + "union_id=? and state=? and rid=?", + reqObj.Id, proto.UnionUntreated, role.RId).Get(&model.CoalitionApply{}) + if has { + rsp.Body.Code = constant.HasApply + return + } + + //写入申请列表 + apply := &model.CoalitionApply{ + RId: role.RId, + UnionId: reqObj.Id, + Ctime: time.Now(), + State: proto.UnionUntreated} + + _, err := db.MasterDB.InsertOne(apply) + if err != nil{ + rsp.Body.Code = constant.DBError + slog.Warn("db error", "error", err) + return + } + + //推送主、副盟主 + apply.SyncExecute() +} + +//审核 +func (this *coalition) verify(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + + reqObj := &proto.VerifyReq{} + rspObj := &proto.VerifyRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rspObj.Id = reqObj.Id + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + + apply := &model.CoalitionApply{} + ok, err := db.MasterDB.Table(model.CoalitionApply{}).Where( + "id=? and state=?", reqObj.Id, proto.UnionUntreated).Get(apply) + if ok && err == nil{ + targetRole, ok := mgr.RMgr.Get(apply.RId) + if ok == false{ + rsp.Body.Code = constant.RoleNotExist + return + } + + if u, ok := mgr.UnionMgr.Get(apply.UnionId); ok { + + if u.Chairman != role.RId && u.ViceChairman != role.RId { + rsp.Body.Code = constant.PermissionDenied + return + } + + if len(u.MemberArray) >= static_conf.Basic.Union.MemberLimit{ + rsp.Body.Code = constant.PeopleIsFull + return + } + + if ok := mgr.RAttrMgr.IsHasUnion(apply.RId); ok { + rsp.Body.Code = constant.UnionAlreadyHas + }else{ + if reqObj.Decide == proto.UnionAdopt { + //同意 + c, ok := mgr.UnionMgr.Get(apply.UnionId) + if ok { + c.MemberArray = append(c.MemberArray, apply.RId) + logic.Union.MemberEnter(apply.RId, apply.UnionId) + c.SyncExecute() + model.NewJoin(targetRole.NickName, apply.UnionId, role.RId, apply.RId) + } + } + } + apply.State = reqObj.Decide + db.MasterDB.Table(apply).ID(apply.Id).Cols("state").Update(apply) + }else{ + rsp.Body.Code = constant.UnionNotFound + return + } + + }else{ + rsp.Body.Code = constant.InvalidParam + } + +} + +//成员列表 +func (this *coalition) member(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.MemberReq{} + rspObj := &proto.MemberRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rspObj.Id = reqObj.Id + rsp.Body.Code = constant.OK + + union, ok := mgr.UnionMgr.Get(reqObj.Id) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + return + } + + rspObj.Members = make([]proto.Member, 0) + for _, rid := range union.MemberArray { + if role, ok := mgr.RMgr.Get(rid); ok { + m := proto.Member{RId: role.RId, Name: role.NickName } + if main, ok := mgr.RCMgr.GetMainCity(role.RId); ok { + m.X = main.X + m.Y = main.Y + } + + if rid == union.Chairman { + m.Title = proto.UnionChairman + }else if rid == union.ViceChairman { + m.Title = proto.UnionViceChairman + }else { + m.Title = proto.UnionCommon + } + rspObj.Members = append(rspObj.Members, m) + } + } +} + + +//申请列表 +func (this *coalition) applyList(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ApplyReq{} + rspObj := &proto.ApplyRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + u, ok := mgr.UnionMgr.Get(reqObj.Id) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + return + } + + if u.Chairman != role.RId && u.ViceChairman != role.RId { + rspObj.Applys = make([]proto.ApplyItem, 0) + return + } + + applys := make([]*model.CoalitionApply, 0) + err := db.MasterDB.Table(model.CoalitionApply{}).Where( + "union_id=? and state=?", reqObj.Id, 0).Find(&applys) + if err != nil{ + rsp.Body.Code = constant.DBError + return + } + + rspObj.Id = reqObj.Id + rspObj.Applys = make([]proto.ApplyItem, 0) + for _, apply := range applys { + if r, ok := mgr.RMgr.Get(apply.RId);ok{ + a := proto.ApplyItem{Id: apply.Id, RId: apply.RId, NickName: r.NickName} + rspObj.Applys = append(rspObj.Applys, a) + } + } +} + +//退出 +func (this *coalition) exit(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ExitReq{} + rspObj := &proto.ExitRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if ok := mgr.RAttrMgr.IsHasUnion(role.RId); ok == false { + rsp.Body.Code = constant.UnionNotFound + return + } + + attribute, _ := mgr.RAttrMgr.Get(role.RId) + u, ok := mgr.UnionMgr.Get(attribute.UnionId) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + return + } + + //盟主不能退出 + if u.Chairman == role.RId { + rsp.Body.Code = constant.UnionNotAllowExit + return + } + + for i, rid := range u.MemberArray { + if rid == role.RId{ + u.MemberArray = append(u.MemberArray[:i], u.MemberArray[i+1:]...) + } + } + + if u.ViceChairman == role.RId{ + u.ViceChairman = 0 + } + + logic.Union.MemberExit(role.RId) + u.SyncExecute() + model.NewExit(role.NickName, u.Id, role.RId) + +} + + +//解散 +func (this *coalition) dismiss(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.DismissReq{} + rspObj := &proto.DismissRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if ok := mgr.RAttrMgr.IsHasUnion(role.RId); ok == false { + rsp.Body.Code = constant.UnionNotFound + return + } + + attribute, _ := mgr.RAttrMgr.Get(role.RId) + u, ok := mgr.UnionMgr.Get(attribute.UnionId) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + return + } + + //盟主才能解散 + if u.Chairman != role.RId { + rsp.Body.Code = constant.PermissionDenied + return + } + unionId := attribute.UnionId + logic.Union.Dismiss(unionId) + + model.NewDismiss(role.NickName, unionId, role.RId) +} + +//公告 +func (this *coalition) notice(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.NoticeReq{} + rspObj := &proto.NoticeRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + u, ok := mgr.UnionMgr.Get(reqObj.Id) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + return + } + + rspObj.Text = u.Notice +} + +//修改公告 +func (this *coalition) modNotice(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ModNoticeReq{} + rspObj := &proto.ModNoticeRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + + rsp.Body.Code = constant.OK + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if len(reqObj.Text) > 200 { + rsp.Body.Code = constant.ContentTooLong + return + } + + if ok := mgr.RAttrMgr.IsHasUnion(role.RId); ok == false { + rsp.Body.Code = constant.UnionNotFound + return + } + + attribute, _ := mgr.RAttrMgr.Get(role.RId) + u, ok := mgr.UnionMgr.Get(attribute.UnionId) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + return + } + + if u.Chairman != role.RId && u.ViceChairman != role.RId { + rsp.Body.Code = constant.PermissionDenied + return + } + + rspObj.Text = reqObj.Text + rspObj.Id = u.Id + u.Notice = reqObj.Text + u.SyncExecute() + + model.NewModNotice(role.NickName, u.Id, role.RId) +} + +//踢人 +func (this *coalition) kick(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.KickReq{} + rspObj := &proto.KickRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rspObj.RId = reqObj.RId + + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if ok := mgr.RAttrMgr.IsHasUnion(role.RId); ok == false { + rsp.Body.Code = constant.UnionNotFound + return + } + + opAr, _ := mgr.RAttrMgr.Get(role.RId) + u, ok := mgr.UnionMgr.Get(opAr.UnionId) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + return + } + + if u.Chairman != role.RId && u.ViceChairman != role.RId { + rsp.Body.Code = constant.PermissionDenied + return + } + + if role.RId == reqObj.RId { + rsp.Body.Code = constant.PermissionDenied + return + } + + targetRole, ok := mgr.RMgr.Get(reqObj.RId) + if ok == false { + rsp.Body.Code = constant.RoleNotExist + return + } + + target, ok := mgr.RAttrMgr.Get(reqObj.RId) + if ok { + if target.UnionId == u.Id{ + for i, rid := range u.MemberArray { + if rid == reqObj.RId{ + u.MemberArray = append(u.MemberArray[:i], u.MemberArray[i+1:]...) + } + } + if u.ViceChairman == reqObj.RId{ + u.ViceChairman = 0 + } + logic.Union.MemberExit(reqObj.RId) + target.UnionId = 0 + u.SyncExecute() + + model.NewKick(role.NickName, targetRole.NickName, u.Id, role.RId, target.RId) + }else{ + rsp.Body.Code = constant.NotBelongUnion + } + }else{ + rsp.Body.Code = constant.NotBelongUnion + } +} + +//任命 +func (this *coalition) appoint(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.AppointReq{} + rspObj := &proto.AppointRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rspObj.RId = reqObj.RId + + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if ok := mgr.RAttrMgr.IsHasUnion(role.RId); ok == false { + rsp.Body.Code = constant.UnionNotFound + return + } + + opAr, _ := mgr.RAttrMgr.Get(role.RId) + u, ok := mgr.UnionMgr.Get(opAr.UnionId) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + return + } + + if u.Chairman != role.RId { + rsp.Body.Code = constant.PermissionDenied + return + } + + targetRole, ok := mgr.RMgr.Get(reqObj.RId) + if ok == false { + rsp.Body.Code = constant.RoleNotExist + return + } + + target, ok := mgr.RAttrMgr.Get(reqObj.RId) + if ok { + if target.UnionId == u.Id{ + if reqObj.Title == proto.UnionViceChairman { + u.ViceChairman = reqObj.RId + rspObj.Title = reqObj.Title + u.SyncExecute() + model.NewAppoint(role.NickName, targetRole.NickName, u.Id, role.RId, targetRole.RId, reqObj.Title) + }else if reqObj.Title == proto.UnionCommon { + if u.ViceChairman == reqObj.RId{ + u.ViceChairman = 0 + } + rspObj.Title = reqObj.Title + model.NewAppoint(role.NickName, targetRole.NickName, u.Id, role.RId, targetRole.RId, reqObj.Title) + }else{ + rsp.Body.Code = constant.InvalidParam + } + }else{ + rsp.Body.Code = constant.NotBelongUnion + } + }else{ + rsp.Body.Code = constant.NotBelongUnion + } + +} + +//禅让 +func (this *coalition) abdicate(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.AbdicateReq{} + rspObj := &proto.AbdicateRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if ok := mgr.RAttrMgr.IsHasUnion(role.RId); ok == false { + rsp.Body.Code = constant.UnionNotFound + return + } + + opAr, _ := mgr.RAttrMgr.Get(role.RId) + u, ok := mgr.UnionMgr.Get(opAr.UnionId) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + return + } + + targetRole, ok := mgr.RMgr.Get(reqObj.RId) + if ok == false { + rsp.Body.Code = constant.RoleNotExist + return + } + + if u.Chairman != role.RId && u.ViceChairman != role.RId { + rsp.Body.Code = constant.PermissionDenied + return + } + + target, ok := mgr.RAttrMgr.Get(reqObj.RId) + if ok { + if target.UnionId == u.Id{ + if role.RId == u.Chairman{ + u.Chairman = reqObj.RId + if u.ViceChairman == reqObj.RId{ + u.ViceChairman = 0 + } + u.SyncExecute() + + model.NewAbdicate(role.NickName, targetRole.NickName, u.Id, + role.RId, targetRole.RId, proto.UnionChairman) + }else if role.RId == u.ViceChairman { + u.ViceChairman = reqObj.RId + u.SyncExecute() + + model.NewAbdicate(role.NickName, targetRole.NickName, u.Id, + role.RId, targetRole.RId, proto.UnionViceChairman) + } + }else{ + rsp.Body.Code = constant.NotBelongUnion + } + }else{ + rsp.Body.Code = constant.NotBelongUnion + } + +} + +//联盟信息 +func (this *coalition) info(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.InfoReq{} + rspObj := &proto.InfoRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rspObj.Id = reqObj.Id + + rsp.Body.Code = constant.OK + + u, ok := mgr.UnionMgr.Get(reqObj.Id) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + }else{ + rspObj.Info = u.ToProto().(proto.Union) + main := make([]proto.Major, 0) + if r, ok := mgr.RMgr.Get(u.Chairman); ok { + m := proto.Major{Name: r.NickName, RId: r.RId, Title: proto.UnionChairman} + main = append(main, m) + } + + if r, ok := mgr.RMgr.Get(u.ViceChairman); ok { + m := proto.Major{Name: r.NickName, RId: r.RId, Title: proto.UnionViceChairman} + main = append(main, m) + } + rspObj.Info.Major = main + } +} + +//联盟日志 +func (this *coalition) log(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.LogReq{} + rspObj := &proto.LogRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rspObj.Logs = make([]proto.UnionLog, 0) + + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + opAr, _ := mgr.RAttrMgr.Get(role.RId) + u, ok := mgr.UnionMgr.Get(opAr.UnionId) + if ok == false{ + rsp.Body.Code = constant.UnionNotFound + return + } + + //开始查询日志 + logs := make([]*model.CoalitionLog, 0) + err := db.MasterDB.Table(model.CoalitionLog{}).Where( + "union_id=?", u.Id).Desc("ctime").Find(&logs) + if err != nil{ + slog.Warn("db error", "error", err) + } + + for _, cLog := range logs { + rspObj.Logs = append(rspObj.Logs, cLog.ToProto().(proto.UnionLog)) + } +} \ No newline at end of file diff --git a/server/slgserver/controller/general.go b/server/slgserver/controller/general.go new file mode 100644 index 0000000..a74d90f --- /dev/null +++ b/server/slgserver/controller/general.go @@ -0,0 +1,385 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "slgserver/constant" + "slgserver/middleware" + "slgserver/net" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/proto" + "slgserver/server/slgserver/static_conf" + "slgserver/server/slgserver/static_conf/skill" +) + +var DefaultGeneral = General{ + +} + +type General struct { + +} + + +func (this*General) InitRouter(r *net.Router) { + g := r.Group("general").Use(middleware.ElapsedTime(), middleware.Log(), + middleware.CheckLogin(), middleware.CheckRole()) + + g.AddRouter("myGenerals", this.myGenerals) + g.AddRouter("drawGeneral", this.drawGenerals) + g.AddRouter("composeGeneral", this.composeGeneral) + g.AddRouter("addPrGeneral", this.addPrGeneral) + g.AddRouter("convert", this.convert) + g.AddRouter("upSkill", this.upSkill) + g.AddRouter("downSkill", this.downSkill) + g.AddRouter("lvSkill", this.lvSkill) + +} + +func (this*General) myGenerals(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.MyGeneralReq{} + rspObj := &proto.MyGeneralRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + gs, ok := mgr.GMgr.GetOrCreateByRId(role.RId) + if ok { + rsp.Body.Code = constant.OK + rspObj.Generals = make([]proto.General, 0) + for _, v := range gs { + rspObj.Generals = append(rspObj.Generals, v.ToProto().(proto.General)) + } + }else{ + rsp.Body.Code = constant.DBError + } +} + + +func (this*General) drawGenerals(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.DrawGeneralReq{} + rspObj := &proto.DrawGeneralRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + cost := static_conf.Basic.General.DrawGeneralCost * reqObj.DrawTimes + ok := mgr.RResMgr.GoldIsEnough(role.RId,cost) + if ok == false{ + rsp.Body.Code = constant.GoldNotEnough + return + } + + limit := static_conf.Basic.General.Limit + cnt := mgr.GMgr.Count(role.RId) + if cnt + reqObj.DrawTimes > limit{ + rsp.Body.Code = constant.OutGeneralLimit + return + } + + gs, ok := mgr.GMgr.RandCreateGeneral(role.RId,reqObj.DrawTimes) + + if ok { + mgr.RResMgr.TryUseGold(role.RId, cost) + rsp.Body.Code = constant.OK + rspObj.Generals = make([]proto.General, len(gs)) + for i, v := range gs { + rspObj.Generals[i] = v.ToProto().(proto.General) + } + }else{ + rsp.Body.Code = constant.DBError + } +} + +func (this*General) composeGeneral(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ComposeGeneralReq{} + rspObj := &proto.ComposeGeneralRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + + gs, ok := mgr.GMgr.HasGeneral(role.RId,reqObj.CompId) + //是否有这个武将 + if ok == false{ + rsp.Body.Code = constant.GeneralNoHas + return + } + + //是否都有这个武将 + gss ,ok := mgr.GMgr.HasGenerals(role.RId,reqObj.GIds) + if ok == false{ + rsp.Body.Code = constant.GeneralNoHas + return + } + + + ok = true + for _, v := range gss { + t := v + if t.CfgId != gs.CfgId { + ok = false + } + } + + //是否同一个类型的武将 + if ok == false { + rsp.Body.Code = constant.GeneralNoSame + return + } + + //是否超过武将星级 + if int(gs.Star - gs.StarLv) < len(gss){ + rsp.Body.Code = constant.GeneralStarMax + return + } + + gs.StarLv += int8(len(gss)) + gs.HasPrPoint += static_conf.Basic.General.PrPoint * len(gss) + gs.SyncExecute() + + for _, v := range gss { + t := v + t.ParentId = gs.Id + t.State = model.GeneralComposeStar + t.SyncExecute() + } + + rspObj.Generals = make([]proto.General, len(gss)) + for i, v := range gss { + rspObj.Generals[i] = v.ToProto().(proto.General) + } + rspObj.Generals = append(rspObj.Generals,gs.ToProto().(proto.General)) + +} + + +func (this*General) addPrGeneral(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.AddPrGeneralReq{} + rspObj := &proto.AddPrGeneralRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + gs, ok := mgr.GMgr.HasGeneral(role.RId,reqObj.CompId) + //是否有这个武将 + if ok == false{ + rsp.Body.Code = constant.GeneralNoHas + return + } + + all:= reqObj.ForceAdd + reqObj.StrategyAdd + reqObj.DefenseAdd + reqObj.SpeedAdd + reqObj.DestroyAdd + if gs.HasPrPoint < all{ + rsp.Body.Code = constant.DBError + return + } + + gs.ForceAdded = reqObj.ForceAdd + gs.StrategyAdded = reqObj.StrategyAdd + gs.DefenseAdded = reqObj.DefenseAdd + gs.SpeedAdded = reqObj.SpeedAdd + gs.DestroyAdded = reqObj.DestroyAdd + + gs.UsePrPoint = all + gs.SyncExecute() + + rsp.Body.Code = constant.OK + + rspObj.Generals = gs.ToProto().(proto.General) + +} + +func (this*General) convert(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ConvertReq{} + rspObj := &proto.ConvertRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + roleRes, ok:= mgr.RResMgr.Get(role.RId) + if ok == false { + rsp.Body.Code = constant.DBError + return + } + + gold := 0 + okArray := make([]int, 0) + for _, gid := range reqObj.GIds { + g, ok := mgr.GMgr.GetByGId(gid) + if ok && g.Order == 0{ + okArray = append(okArray, gid) + gold += 10* int(g.Star)*(1 + int(g.StarLv)) + g.State = model.GeneralConvert + g.SyncExecute() + } + } + + roleRes.Gold += gold + rspObj.AddGold = gold + rspObj.Gold = roleRes.Gold + rspObj.GIds = okArray + + roleRes.SyncExecute() +} + +func (this*General) upSkill(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.UpDownSkillReq{} + rspObj := &proto.UpDownSkillRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + rspObj.Pos = reqObj.Pos + rspObj.CfgId = reqObj.CfgId + rspObj.GId = reqObj.GId + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if reqObj.Pos <0 || reqObj.Pos >= model.SkillLimit { + rsp.Body.Code = constant.InvalidParam + return + } + + g,ok := mgr.GMgr.GetByGId(reqObj.GId) + if ok == false{ + rsp.Body.Code = constant.GeneralNotFound + return + } + + if g.RId != role.RId{ + rsp.Body.Code = constant.GeneralNotMe + return + } + + skill, ok := mgr.SkillMgr.GetSkillOrCreate(role.RId, reqObj.CfgId) + if ok == false { + rsp.Body.Code = constant.DBError + return + } + + if skill.IsInLimit() == false{ + rsp.Body.Code = constant.OutSkillLimit + return + } + + if skill.ArmyIsIn(g.CurArms) == false{ + rsp.Body.Code = constant.OutArmNotMatch + return + } + + if g.UpSkill(skill.Id, reqObj.CfgId, reqObj.Pos) == false{ + rsp.Body.Code = constant.UpSkillError + return + } + skill.UpSkill(g.Id) + g.SyncExecute() + skill.SyncExecute() +} + +func (this*General) downSkill(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.UpDownSkillReq{} + rspObj := &proto.UpDownSkillRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + rspObj.Pos = reqObj.Pos + rspObj.CfgId = reqObj.CfgId + rspObj.GId = reqObj.GId + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if reqObj.Pos <0 || reqObj.Pos >= model.SkillLimit { + rsp.Body.Code = constant.InvalidParam + return + } + + g,ok := mgr.GMgr.GetByGId(reqObj.GId) + if ok == false{ + rsp.Body.Code = constant.GeneralNotFound + return + } + + if g.RId != role.RId{ + rsp.Body.Code = constant.GeneralNotMe + return + } + + skill, ok := mgr.SkillMgr.GetSkillOrCreate(role.RId, reqObj.CfgId) + if ok == false{ + rsp.Body.Code = constant.DBError + return + } + + if g.DownSkill(skill.Id, reqObj.Pos) == false{ + rsp.Body.Code = constant.DownSkillError + return + } + skill.DownSkill(g.Id) + g.SyncExecute() + skill.SyncExecute() +} + +func (this*General) lvSkill(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.LvSkillReq{} + rspObj := &proto.LvSkillRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + rspObj.Pos = reqObj.Pos + rspObj.GId = reqObj.GId + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + g, ok := mgr.GMgr.GetByGId(reqObj.GId) + if ok == false{ + rsp.Body.Code = constant.GeneralNotFound + return + } + + if g.RId != role.RId { + rsp.Body.Code = constant.GeneralNotMe + return + } + + gSkill, err := g.PosSkill(reqObj.Pos) + if err != nil{ + rsp.Body.Code = constant.PosNotSkill + return + } + + skillCfg, ok := skill.Skill.GetCfg(gSkill.CfgId) + if ok == false{ + rsp.Body.Code = constant.PosNotSkill + return + } + + if gSkill.Lv > len(skillCfg.Levels){ + rsp.Body.Code = constant.SkillLevelFull + return + } + + gSkill.Lv += 1 + g.SyncExecute() +} diff --git a/server/slgserver/controller/interior.go b/server/slgserver/controller/interior.go new file mode 100644 index 0000000..e949578 --- /dev/null +++ b/server/slgserver/controller/interior.go @@ -0,0 +1,200 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "slgserver/constant" + "slgserver/middleware" + "slgserver/net" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/proto" + "slgserver/server/slgserver/static_conf" + "slgserver/server/slgserver/static_conf/facility" + "time" +) + +var DefaultInterior = Interior{} + +type Interior struct { + +} + +func (this*Interior) InitRouter(r *net.Router) { + g := r.Group("interior").Use(middleware.ElapsedTime(), + middleware.Log(), middleware.CheckRole()) + g.AddRouter("collect", this.collect) + g.AddRouter("openCollect", this.openCollect) + g.AddRouter("transform", this.transform) + +} + +func (this*Interior) collect(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.CollectionReq{} + rspObj := &proto.CollectionRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + roleRes, ok:= mgr.RResMgr.Get(role.RId) + if ok == false { + rsp.Body.Code = constant.DBError + return + } + + roleAttr, ok:= mgr.RAttrMgr.Get(role.RId) + if ok == false { + rsp.Body.Code = constant.DBError + return + } + + curTime := time.Now() + lastTime := roleAttr.LastCollectTime + if curTime.YearDay() != lastTime.YearDay() || curTime.Year() != lastTime.Year(){ + roleAttr.CollectTimes = 0 + roleAttr.LastCollectTime = time.Time{} + } + + timeLimit := static_conf.Basic.Role.CollectTimesLimit + //是否超过征收次数上限 + if roleAttr.CollectTimes >= timeLimit{ + rsp.Body.Code = constant.OutCollectTimesLimit + return + } + + //cd内不能操作 + need := lastTime.Add(time.Duration(static_conf.Basic.Role.CollectTimesLimit)*time.Second) + if curTime.Before(need){ + rsp.Body.Code = constant.InCdCanNotOperate + return + } + + gold := mgr.GetYield(roleRes.RId).Gold + rspObj.Gold = gold + roleRes.Gold += gold + //更新 + roleRes.SyncExecute() + + roleAttr.LastCollectTime = curTime + roleAttr.CollectTimes += 1 + roleAttr.SyncExecute() + + interval := static_conf.Basic.Role.CollectInterval + if roleAttr.CollectTimes >= timeLimit { + y, m, d := roleAttr.LastCollectTime.Add(24*time.Hour).Date() + nextTime := time.Date(y, m, d, 0, 0, 0, 0, time.FixedZone("IST", 3600)) + rspObj.NextTime = nextTime.UnixNano()/1e6 + }else{ + nextTime := roleAttr.LastCollectTime.Add(time.Duration(interval)*time.Second) + rspObj.NextTime = nextTime.UnixNano()/1e6 + } + + rspObj.CurTimes = roleAttr.CollectTimes + rspObj.Limit = timeLimit + +} + +func (this*Interior) openCollect(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.OpenCollectionReq{} + rspObj := &proto.OpenCollectionRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + roleAttr, ok:= mgr.RAttrMgr.Get(role.RId) + if ok == false { + rsp.Body.Code = constant.DBError + return + } + + interval := static_conf.Basic.Role.CollectInterval + timeLimit := static_conf.Basic.Role.CollectTimesLimit + rspObj.Limit = timeLimit + rspObj.CurTimes = roleAttr.CollectTimes + if roleAttr.LastCollectTime.IsZero() { + rspObj.NextTime = 0 + }else{ + if roleAttr.CollectTimes >= timeLimit { + y, m, d := roleAttr.LastCollectTime.Add(24*time.Hour).Date() + nextTime := time.Date(y, m, d, 0, 0, 0, 0, time.FixedZone("IST", 3600)) + rspObj.NextTime = nextTime.UnixNano()/1e6 + }else{ + nextTime := roleAttr.LastCollectTime.Add(time.Duration(interval)*time.Second) + rspObj.NextTime = nextTime.UnixNano()/1e6 + } + } +} + + +func (this*Interior) transform(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.TransformReq{} + rspObj := &proto.TransformRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + roleRes, ok:= mgr.RResMgr.Get(role.RId) + if ok == false { + rsp.Body.Code = constant.DBError + return + } + + main, _ := mgr.RCMgr.GetMainCity(role.RId) + + lv := mgr.RFMgr.GetFacilityLv(main.CityId, facility.JiShi) + if lv <= 0{ + rsp.Body.Code = constant.NotHasJiShi + return + } + + len := 4 + ret := make([]int, len) + + for i := 0 ;i < len; i++{ + //ret[i] = reqObj.To[i] - reqObj.From[i] + if reqObj.From[i] > 0{ + ret[i] = -reqObj.From[i] + } + + if reqObj.To[i] > 0{ + ret[i] = reqObj.To[i] + } + } + + + if roleRes.Wood + ret[0] < 0{ + rsp.Body.Code = constant.InvalidParam + return + } + + if roleRes.Iron + ret[1] < 0{ + rsp.Body.Code = constant.InvalidParam + return + } + + if roleRes.Stone + ret[2] < 0{ + rsp.Body.Code = constant.InvalidParam + return + } + + if roleRes.Grain + ret[3] < 0{ + rsp.Body.Code = constant.InvalidParam + return + } + + roleRes.Wood += ret[0] + roleRes.Iron += ret[1] + roleRes.Stone += ret[2] + roleRes.Grain += ret[3] + roleRes.SyncExecute() + +} + diff --git a/server/slgserver/controller/nation_map.go b/server/slgserver/controller/nation_map.go new file mode 100644 index 0000000..47ccb6b --- /dev/null +++ b/server/slgserver/controller/nation_map.go @@ -0,0 +1,274 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "slgserver/constant" + "slgserver/middleware" + "slgserver/net" + "slgserver/server/slgserver/logic" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/proto" + "slgserver/server/slgserver/static_conf" +) + +var DefaultMap = NationMap{} + +type NationMap struct { + +} + +func (this*NationMap) InitRouter(r *net.Router) { + g := r.Group("nationMap").Use(middleware.ElapsedTime(), middleware.Log()) + g.AddRouter("config", this.config) + g.AddRouter("scan", this.scan, middleware.CheckRole()) + g.AddRouter("scanBlock", this.scanBlock, middleware.CheckRole()) + g.AddRouter("giveUp", this.giveUp, middleware.CheckRole()) + g.AddRouter("build", this.build, middleware.CheckRole()) + g.AddRouter("upBuild", this.upBuild, middleware.CheckRole()) + g.AddRouter("delBuild", this.delBuild, middleware.CheckRole()) + +} + +/* +获取配置 +*/ +func (this*NationMap) config(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ConfigReq{} + rspObj := &proto.ConfigRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + m := static_conf.MapBuildConf.Cfg + rspObj.Confs = make([]proto.Conf, len(m)) + i := 0 + for _, v := range m { + rspObj.Confs[i].Type = v.Type + rspObj.Confs[i].Name = v.Name + rspObj.Confs[i].Level = v.Level + rspObj.Confs[i].Defender = v.Defender + rspObj.Confs[i].Durable = v.Durable + rspObj.Confs[i].Grain = v.Grain + rspObj.Confs[i].Iron = v.Iron + rspObj.Confs[i].Stone = v.Stone + rspObj.Confs[i].Wood = v.Wood + i++ + } +} + +/* +扫描地图 +*/ +func (this*NationMap) scan(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ScanReq{} + rspObj := &proto.ScanRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + x := reqObj.X + y := reqObj.Y + + rb := mgr.RBMgr.Scan(x, y) + rspObj.MRBuilds = make([]proto.MapRoleBuild, len(rb)) + for i, v := range rb { + rspObj.MRBuilds[i] = v.ToProto().(proto.MapRoleBuild) + } + + cb := mgr.RCMgr.Scan(x, y) + rspObj.MCBuilds = make([]proto.MapRoleCity, len(cb)) + for i, v := range cb { + rspObj.MCBuilds[i] = v.ToProto().(proto.MapRoleCity) + } +} + +func (this*NationMap) scanBlock(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.ScanBlockReq{} + rspObj := &proto.ScanRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + x := reqObj.X + y := reqObj.Y + + rb := mgr.RBMgr.ScanBlock(x, y, reqObj.Length) + rspObj.MRBuilds = make([]proto.MapRoleBuild, len(rb)) + for i, v := range rb { + rspObj.MRBuilds[i] = v.ToProto().(proto.MapRoleBuild) + } + + cb := mgr.RCMgr.ScanBlock(x, y, reqObj.Length) + rspObj.MCBuilds = make([]proto.MapRoleCity, len(cb)) + for i, v := range cb { + rspObj.MCBuilds[i] = v.ToProto().(proto.MapRoleCity) + } + + armys := logic.ArmyLogic.ScanBlock(role.RId, x, y, reqObj.Length) + rspObj.Armys = make([]proto.Army, len(armys)) + for i, v := range armys { + rspObj.Armys[i] = v.ToProto().(proto.Army) + } +} + +func (this*NationMap) giveUp(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.GiveUpReq{} + rspObj := &proto.GiveUpRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + x := reqObj.X + y := reqObj.Y + + rspObj.X = x + rspObj.Y = y + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if mgr.RBMgr.BuildIsRId(x, y, role.RId) == false{ + rsp.Body.Code = constant.BuildNotMe + return + } + + rsp.Body.Code = mgr.RBMgr.GiveUp(x, y) +} + +//建造 +func (this*NationMap) build(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.BuildReq{} + rspObj := &proto.BuildRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + x := reqObj.X + y := reqObj.Y + + rspObj.X = x + rspObj.Y = y + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if mgr.RBMgr.BuildIsRId(x, y, role.RId) == false{ + rsp.Body.Code = constant.BuildNotMe + return + } + + b, ok := mgr.RBMgr.PositionBuild(x, y) + if ok == false { + rsp.Body.Code = constant.BuildNotMe + return + } + + if b.IsResBuild() == false || b.IsBusy(){ + rsp.Body.Code = constant.CanNotBuildNew + return + } + + cnt := mgr.RBMgr.RoleFortressCnt(role.RId) + if cnt >= static_conf.Basic.Build.FortressLimit{ + rsp.Body.Code = constant.CanNotBuildNew + return + } + + cfg, ok := static_conf.MapBCConf.BuildConfig(reqObj.Type, 1) + if ok == false{ + rsp.Body.Code = constant.InvalidParam + return + } + + code := mgr.RResMgr.TryUseNeed(role.RId, cfg.Need) + if code != constant.OK { + rsp.Body.Code = code + return + } + + b.BuildOrUp(*cfg) + b.SyncExecute() + +} + + +func (this*NationMap) upBuild(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.UpBuildReq{} + rspObj := &proto.UpBuildRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + x := reqObj.X + y := reqObj.Y + + rspObj.X = x + rspObj.Y = y + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if mgr.RBMgr.BuildIsRId(x, y, role.RId) == false{ + rsp.Body.Code = constant.BuildNotMe + return + } + + b, ok := mgr.RBMgr.PositionBuild(x, y) + if ok == false { + rsp.Body.Code = constant.BuildNotMe + return + } + + if b.IsHaveModifyLVAuth() == false || b.IsInGiveUp() || b.IsBusy(){ + rsp.Body.Code = constant.CanNotUpBuild + return + } + + + cfg, ok := static_conf.MapBCConf.BuildConfig(b.Type, b.Level+1) + if ok == false{ + rsp.Body.Code = constant.InvalidParam + return + } + + code := mgr.RResMgr.TryUseNeed(role.RId, cfg.Need) + if code != constant.OK { + rsp.Body.Code = code + return + } + b.BuildOrUp(*cfg) + b.SyncExecute() + rspObj.Build = b.ToProto().(proto.MapRoleBuild) +} + +func (this*NationMap) delBuild(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.UpBuildReq{} + rspObj := &proto.UpBuildRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + x := reqObj.X + y := reqObj.Y + + rspObj.X = x + rspObj.Y = y + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if mgr.RBMgr.BuildIsRId(x, y, role.RId) == false{ + rsp.Body.Code = constant.BuildNotMe + return + } + + rsp.Body.Code = mgr.RBMgr.Destroy(x, y) + b, ok := mgr.RBMgr.PositionBuild(x, y) + if ok { + rspObj.Build = b.ToProto().(proto.MapRoleBuild) + } +} diff --git a/server/slgserver/controller/role.go b/server/slgserver/controller/role.go new file mode 100644 index 0000000..7cf4ca6 --- /dev/null +++ b/server/slgserver/controller/role.go @@ -0,0 +1,412 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "log/slog" + "math/rand" + "slgserver/constant" + "slgserver/db" + "slgserver/middleware" + "slgserver/net" + "slgserver/server/slgserver/global" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/pos" + "slgserver/server/slgserver/proto" + "slgserver/server/slgserver/static_conf" + "slgserver/util" + "time" +) + +var DefaultRole = Role{} + +type Role struct { + +} + +func (this*Role) InitRouter(r *net.Router) { + g := r.Group("role").Use(middleware.ElapsedTime(), middleware.Log()) + + g.AddRouter("enterServer", this.enterServer) + g.AddRouter("create", this.create, middleware.CheckLogin()) + g.AddRouter("roleList", this.roleList, middleware.CheckLogin()) + g.AddRouter("myCity", this.myCity, middleware.CheckRole()) + g.AddRouter("myRoleRes", this.myRoleRes, middleware.CheckRole()) + g.AddRouter("myRoleBuild", this.myRoleBuild, middleware.CheckRole()) + g.AddRouter("myProperty", this.myProperty, middleware.CheckRole()) + g.AddRouter("upPosition", this.upPosition, middleware.CheckRole()) + g.AddRouter("posTagList", this.posTagList, middleware.CheckRole()) + g.AddRouter("opPosTag", this.opPosTag, middleware.CheckRole()) +} + +func (this*Role) create(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.CreateRoleReq{} + rspObj := &proto.CreateRoleRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + + uid, _ := req.Conn.GetProperty("uid") + reqObj.UId = uid.(int) + rspObj.Role.UId = reqObj.UId + + r := make([]model.Role, 0) + has, _ := db.MasterDB.Table(r).Where("uid=?", reqObj.UId).Get(r) + if has { + slog.Info("role has create", "uid", reqObj.UId) + rsp.Body.Code = constant.RoleAlreadyCreate + }else { + + role := &model.Role{UId: reqObj.UId, HeadId: reqObj.HeadId, Sex: reqObj.Sex, + NickName: reqObj.NickName, CreatedAt: time.Now()} + + if _, err := db.MasterDB.Insert(role); err != nil { + slog.Info("role create error", + "uid", reqObj.UId, "error", err) + rsp.Body.Code = constant.DBError + }else{ + rspObj.Role.RId = role.RId + rspObj.Role.UId = reqObj.UId + rspObj.Role.NickName = reqObj.NickName + rspObj.Role.Sex = reqObj.Sex + rspObj.Role.HeadId = reqObj.HeadId + + rsp.Body.Code = constant.OK + } + } +} + +func (this*Role) roleList(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.RoleListReq{} + rspObj := &proto.RoleListRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + uid, _ := req.Conn.GetProperty("uid") + uid = uid.(int) + + r := make([]*model.Role, 0) + err := db.MasterDB.Table(r).Where("uid=?", uid).Find(&r) + if err == nil{ + rl := make([]proto.Role, len(r)) + for i, v := range r { + rl[i] = v.ToProto().(proto.Role) + } + rspObj.Roles = rl + rsp.Body.Code = constant.OK + }else{ + rsp.Body.Code = constant.DBError + } +} + +func (this*Role) enterServer(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.EnterServerReq{} + rspObj := &proto.EnterServerRsp{} + rspObj.Time = time.Now().UnixNano()/1e6 + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + //校验session是否合法 + sess, err := util.ParseSession(reqObj.Session) + if err != nil || sess.IsValid() == false{ + rsp.Body.Code = constant.SessionInvalid + return + } + uid := sess.Id + req.Conn.SetProperty("uid", uid) + //查询角色 + role := &model.Role{} + b, err := db.MasterDB.Table(role).Where("uid=?", uid).Get(role) + if err != nil{ + slog.Warn("enterServer db error", "error", err) + rsp.Body.Code = constant.DBError + return + } + if b { + rsp.Body.Code = constant.OK + rspObj.Role = role.ToProto().(proto.Role) + req.Conn.SetProperty("role", role) + net.ConnMgr.RoleEnter(req.Conn, role.RId) + + var e error = nil + roleRes, ok := mgr.RResMgr.Get(role.RId) + if ok == false{ + + roleRes = &model.RoleRes{RId: role.RId, + Wood: static_conf.Basic.Role.Wood, + Iron: static_conf.Basic.Role.Iron, + Stone: static_conf.Basic.Role.Stone, + Grain: static_conf.Basic.Role.Grain, + Gold: static_conf.Basic.Role.Gold, + Decree: static_conf.Basic.Role.Decree} + _ ,e = db.MasterDB.Insert(roleRes) + if e != nil { + slog.Error("insert rres error", "error", e) + } + } + + if e == nil { + mgr.RResMgr.Add(roleRes) + rspObj.RoleRes = roleRes.ToProto().(proto.RoleRes) + rsp.Body.Code = constant.OK + }else{ + rsp.Body.Code = constant.DBError + return + } + + //玩家的一些属性 + if _, ok := mgr.RAttrMgr.TryCreate(role.RId); ok == false{ + rsp.Body.Code = constant.DBError + return + } + + //查询是否有城市 + _, ok = mgr.RCMgr.GetByRId(role.RId) + if ok == false{ + citys := make([]*model.MapRoleCity, 0) + //随机生成一个城市 + for true { + x := rand.Intn(global.MapWith) + y := rand.Intn(global.MapHeight) + if mgr.NMMgr.IsCanBuildCity(x, y){ + //建立城市 + c := &model.MapRoleCity{RId: role.RId, X: x, Y: y, + IsMain: 1, + CurDurable: static_conf.Basic.City.Durable, + Name: role.NickName, + CreatedAt: time.Now(), + } + + //插入 + _, err := db.MasterDB.Table(c).Insert(c) + if err != nil{ + rsp.Body.Code = constant.DBError + }else{ + citys = append(citys, c) + //更新城市缓存 + mgr.RCMgr.Add(c) + } + + //生成城市里面的设施 + mgr.RFMgr.GetAndTryCreate(c.CityId, c.RId) + break + } + } + } + rspObj.Token = util.NewSession(role.RId, time.Now()).String() + }else{ + rsp.Body.Code = constant.RoleNotExist + } +} + +func (this*Role) myCity(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.MyCityReq{} + rspObj := &proto.MyCityRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role, _ := r.(*model.Role) + + + citys,ok := mgr.RCMgr.GetByRId(role.RId) + if ok { + rspObj.Citys = make([]proto.MapRoleCity, len(citys)) + //赋值发送 + for i, v := range citys { + rspObj.Citys[i] = v.ToProto().(proto.MapRoleCity) + } + + }else{ + rspObj.Citys = make([]proto.MapRoleCity, 0) + } + +} + +func (this*Role) myRoleRes(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.MyRoleResReq{} + rspObj := &proto.MyRoleResRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + roleRes, ok := mgr.RResMgr.Get(role.RId) + if ok == false{ + rsp.Body.Code = constant.RoleNotExist + return + }else{ + rspObj.RoleRes = roleRes.ToProto().(proto.RoleRes) + rsp.Body.Code = constant.OK + } +} + +func (this*Role) myProperty(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.MyRolePropertyReq{} + rspObj := &proto.MyRolePropertyRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + //城市 + c, ok := mgr.RCMgr.GetByRId(role.RId) + if ok { + rspObj.Citys = make([]proto.MapRoleCity, len(c)) + for i, v := range c { + rspObj.Citys[i] = v.ToProto().(proto.MapRoleCity) + } + }else{ + rspObj.Citys = make([]proto.MapRoleCity, 0) + } + + + //建筑 + ra, ok := mgr.RBMgr.GetRoleBuild(role.RId) + if ok { + rspObj.MRBuilds = make([]proto.MapRoleBuild, len(ra)) + for i, v := range ra { + rspObj.MRBuilds[i] = v.ToProto().(proto.MapRoleBuild) + } + }else{ + rspObj.MRBuilds = make([]proto.MapRoleBuild, 0) + } + + //资源 + roleRes, ok := mgr.RResMgr.Get(role.RId) + if ok { + rspObj.RoleRes = roleRes.ToProto().(proto.RoleRes) + }else{ + rsp.Body.Code = constant.RoleNotExist + return + } + + //武将 + gs, ok := mgr.GMgr.GetOrCreateByRId(role.RId) + if ok { + rspObj.Generals = make([]proto.General, 0) + for _, v := range gs { + rspObj.Generals = append(rspObj.Generals, v.ToProto().(proto.General)) + } + }else{ + rsp.Body.Code = constant.DBError + return + } + + //军队 + ar, ok := mgr.AMgr.GetByRId(role.RId) + if ok { + rspObj.Armys = make([]proto.Army, len(ar)) + for i, v := range ar { + rspObj.Armys[i] = v.ToProto().(proto.Army) + } + }else{ + rspObj.Armys = make([]proto.Army, 0) + } + +} + +func (this*Role) myRoleBuild(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.MyRoleBuildReq{} + rspObj := &proto.MyRoleBuildRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + ra, ok := mgr.RBMgr.GetRoleBuild(role.RId) + if ok { + rspObj.MRBuilds = make([]proto.MapRoleBuild, len(ra)) + for i, v := range ra { + rspObj.MRBuilds[i] = v.ToProto().(proto.MapRoleBuild) + } + }else{ + rspObj.MRBuilds = make([]proto.MapRoleBuild, 0) + } + +} + +func (this*Role) upPosition(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.UpPositionReq{} + rspObj := &proto.UpPositionRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + rspObj.X = reqObj.X + rspObj.Y = reqObj.Y + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + pos.RPMgr.Push(reqObj.X, reqObj.Y, role.RId) + +} + +func (this*Role) posTagList(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.PosTagListReq{} + rspObj := &proto.PosTagListRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + attr, ok := mgr.RAttrMgr.Get(role.RId) + if ok == false { + rsp.Body.Code = constant.RoleNotExist + return + } + + rspObj.PosTags = attr.PosTagArray + +} + +func (this*Role) opPosTag(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.PosTagReq{} + rspObj := &proto.PosTagRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + rspObj.X = reqObj.X + rspObj.Y = reqObj.Y + rspObj.Type = reqObj.Type + rspObj.Name = reqObj.Name + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + attr, ok := mgr.RAttrMgr.Get(role.RId) + if ok == false { + rsp.Body.Code = constant.RoleNotExist + return + } + if reqObj.Type == 0{ + attr.RemovePosTag(reqObj.X, reqObj.Y) + attr.SyncExecute() + }else if reqObj.Type == 1{ + + limit := static_conf.Basic.Role.PosTagLimit + if int(limit) >= len(attr.PosTagArray){ + attr.AddPosTag(reqObj.X, reqObj.Y, reqObj.Name) + attr.SyncExecute() + }else{ + rsp.Body.Code = constant.OutPosTagLimit + } + }else{ + rsp.Body.Code = constant.InvalidParam + } +} + diff --git a/server/slgserver/controller/skill.go b/server/slgserver/controller/skill.go new file mode 100644 index 0000000..a8d4142 --- /dev/null +++ b/server/slgserver/controller/skill.go @@ -0,0 +1,42 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "slgserver/constant" + "slgserver/middleware" + "slgserver/net" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/proto" +) + +var DefaultSkill = Skill{ + +} +type Skill struct { + +} + +func (this*Skill) InitRouter(r *net.Router) { + g := r.Group("skill").Use(middleware.ElapsedTime(), middleware.Log(), + middleware.CheckLogin(), middleware.CheckRole()) + + g.AddRouter("list", this.list) + +} + +func (this*Skill) list(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.SkillListReq{} + rspObj := &proto.SkillListRsp{} + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + rspObj.List = make([]proto.Skill, 0) + skills, _ := mgr.SkillMgr.Get(role.RId) + for _, skill := range skills { + rspObj.List = append(rspObj.List, skill.ToProto().(proto.Skill)) + } +} diff --git a/server/slgserver/controller/war.go b/server/slgserver/controller/war.go new file mode 100644 index 0000000..3a9adad --- /dev/null +++ b/server/slgserver/controller/war.go @@ -0,0 +1,103 @@ +package controller + +import ( + "github.com/mitchellh/mapstructure" + "log/slog" + "slgserver/constant" + "slgserver/db" + "slgserver/middleware" + "slgserver/net" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/proto" +) + +var DefaultWar = War{} + +type War struct { + +} + +func (this*War) InitRouter(r *net.Router) { + g := r.Group("war").Use(middleware.ElapsedTime(), + middleware.Log(), middleware.CheckRole()) + g.AddRouter("report", this.report) + g.AddRouter("read", this.read) +} + +func (this*War) report(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.WarReportReq{} + rspObj := &proto.WarReportRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + //查询最近30条战报吧 + l := make([]*model.WarReport, 0) + err := db.MasterDB.Table(model.WarReport{}).Where("a_rid=? or d_rid=?", + role.RId, role.RId).Desc("ctime").Limit(100, 0).Find(&l) + + if err != nil{ + slog.Warn("db error", "error", err) + rsp.Body.Code = constant.DBError + return + } + + rspObj.List = make([]proto.WarReport, len(l)) + for i, v := range l { + rspObj.List[i] = v.ToProto().(proto.WarReport) + } +} + +func (this*War) read(req *net.WsMsgReq, rsp *net.WsMsgRsp) { + reqObj := &proto.WarReadReq{} + rspObj := &proto.WarReadRsp{} + + mapstructure.Decode(req.Body.Msg, reqObj) + rsp.Body.Msg = rspObj + rsp.Body.Code = constant.OK + rspObj.Id = reqObj.Id + + r, _ := req.Conn.GetProperty("role") + role := r.(*model.Role) + + if reqObj.Id == 0 { + m := model.WarReport{AttackIsRead: true, DefenseIsRead: true} + _, err := db.MasterDB.Table(model.WarReport{}).Where("a_rid=?", role.RId).Cols("a_is_read").Update(m) + if err != nil { + slog.Error("db error", "error", err) + } + _, err = db.MasterDB.Table(model.WarReport{}).Where("d_rid=?", role.RId).Cols("d_is_read").Update(m) + if err != nil { + slog.Error("db error", "error", err) + } + }else{ + wr := &model.WarReport{} + ok, err := db.MasterDB.Table(model.WarReport{}).Where("id=?", + reqObj.Id).Get(wr) + + if err != nil { + slog.Warn("db error", "error", err) + rsp.Body.Code = constant.DBError + return + } + + if ok { + if wr.AttackRid == role.RId { + wr.AttackIsRead = true + db.MasterDB.Table(wr).ID(wr.Id).Cols("a_is_read").Update(wr) + rsp.Body.Code = constant.OK + }else if wr.DefenseRid == role.RId { + wr.DefenseIsRead = true + db.MasterDB.Table(wr).ID(wr.Id).Cols("d_is_read").Update(wr) + rsp.Body.Code = constant.OK + }else{ + rsp.Body.Code = constant.InvalidParam + } + } + } + +} diff --git a/server/slgserver/global/global.go b/server/slgserver/global/global.go new file mode 100644 index 0000000..8fdefc9 --- /dev/null +++ b/server/slgserver/global/global.go @@ -0,0 +1,8 @@ +package global + +var MapWith = 200 +var MapHeight = 200 + +func ToPosition(x, y int) int { + return x+ MapHeight*y +} diff --git a/server/slgserver/logic/army_logic.go b/server/slgserver/logic/army_logic.go new file mode 100644 index 0000000..d3510ce --- /dev/null +++ b/server/slgserver/logic/army_logic.go @@ -0,0 +1,456 @@ +package logic + +import ( + "slgserver/server/slgserver/global" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/static_conf" + "slgserver/util" + "sync" + "time" +) + +type armyLogic struct { + sys *sysArmyLogic + passBy sync.RWMutex + stop sync.RWMutex + out sync.RWMutex + endTime sync.RWMutex + + interruptId chan int + giveUpId chan int + arriveArmys chan *model.Army + updateArmys chan *model.Army + + outArmys map[int]*model.Army //城外的军队 + endTimeArmys map[int64][]*model.Army //key:到达时间 + stopInPosArmys map[int]map[int]*model.Army //玩家停留位置的军队 key:posId,armyId + passByPosArmys map[int]map[int]*model.Army //玩家路过位置的军队 key:posId,armyId +} + +func (this *armyLogic) init(){ + + armys := mgr.AMgr.All() + for _, army := range armys { + //恢复已经执行行动的军队 + if army.Cmd != model.ArmyCmdIdle { + e := army.End.Unix() + _, ok := this.endTimeArmys[e] + if ok == false{ + this.endTimeArmys[e] = make([]*model.Army, 0) + } + this.endTimeArmys[e] = append(this.endTimeArmys[e], army) + } + } + + curTime := time.Now().Unix() + for kT, armys := range this.endTimeArmys { + if kT <= curTime { + for _, a := range armys { + if a.Cmd == model.ArmyCmdAttack { + this.Arrive(a) + }else if a.Cmd == model.ArmyCmdDefend { + this.Arrive(a) + }else if a.Cmd == model.ArmyCmdBack { + if curTime >= a.End.Unix() { + a.ToX = a.FromX + a.ToY = a.FromY + a.Cmd = model.ArmyCmdIdle + a.State = model.ArmyStop + } + } + a.SyncExecute() + } + delete(this.endTimeArmys, kT) + }else{ + for _, a := range armys { + a.State = model.ArmyRunning + } + } + } +} + +func (this*armyLogic) check() { + for true { + t := time.Now().Unix() + time.Sleep(100*time.Millisecond) + + this.endTime.Lock() + for k, armies := range this.endTimeArmys { + if k <= t{ + for _, army := range armies { + this.Arrive(army) + } + delete(this.endTimeArmys, k) + } + } + this.endTime.Unlock() + } +} + +func (this *armyLogic) running(){ + passbyTimer := time.NewTicker(10 * time.Second) + for { + select { + case <-passbyTimer.C:{ + this.updatePassBy() + } + case army := <-this.updateArmys:{ + this.exeUpdate(army) + } + case army := <-this.arriveArmys:{ + this.exeArrive(army) + } + case giveId := <- this.giveUpId:{ + //在该位置驻守、调动的都需要返回 + this.stop.RLock() + armys, ok := this.stopInPosArmys[giveId] + this.stop.RUnlock() + + if ok { + for _, army := range armys { + this.ArmyBack(army) + } + this.deleteStopArmy(giveId) + } + } + case interruptId := <- this.interruptId:{ + //只有调动到该位置的军队需要返回 + var targets []*model.Army + this.stop.Lock() + armys, ok := this.stopInPosArmys[interruptId] + if ok { + for key, army := range armys { + if army.FromX == army.ToX && army.FromY == army.ToY{ + targets = append(targets, army) + delete(armys, key) + } + } + } + this.stop.Unlock() + + for _, target := range targets { + this.ArmyBack(target) + } + } + } + } +} + +func (this* armyLogic) updatePassBy() { + + temp := make(map[int]map[int]*model.Army) + this.out.RLock() + for _, army := range this.outArmys { + if army.State == model.ArmyRunning { + x, y := army.Position() + posId := global.ToPosition(x, y) + if _, ok := temp[posId]; ok == false { + temp[posId] = make(map[int]*model.Army) + } + temp[posId][army.Id] = army + army.CheckSyncCell() + } + } + this.out.RUnlock() + + this.stop.RLock() + for posId, armys := range this.stopInPosArmys { + for _, army := range armys { + if _, ok := temp[posId]; ok == false { + temp[posId] = make(map[int]*model.Army) + } + temp[posId][army.Id] = army + } + } + this.stop.RUnlock() + + this.passBy.Lock() + this.passByPosArmys = temp + this.passBy.Unlock() +} + +func (this *armyLogic) exeUpdate(army *model.Army) { + army.SyncExecute() + if army.Cmd == model.ArmyCmdBack { + this.stop.Lock() + posId := global.ToPosition(army.ToX, army.ToY) + armys, ok := this.stopInPosArmys[posId] + if ok { + delete(armys, army.Id) + this.stopInPosArmys[posId] = armys + } + this.stop.Unlock() + } + + this.out.Lock() + if army.Cmd != model.ArmyCmdIdle { + this.outArmys[army.Id] = army + }else{ + delete(this.outArmys, army.RId) + } + this.out.Unlock() +} + +func (this *armyLogic) exeArrive(army *model.Army) { + if army.Cmd == model.ArmyCmdAttack { + if IsCanArrive(army.ToX, army.ToY, army.RId) && + IsWarFree(army.ToX, army.ToY) == false && + IsCanDefend(army.ToX, army.ToY, army.RId) == false{ + newBattle(army) + } else{ + war := NewEmptyWar(army) + war.SyncExecute() + } + this.ArmyBack(army) + }else if army.Cmd == model.ArmyCmdDefend { + //呆在哪里不动 + ok := IsCanDefend(army.ToX, army.ToY, army.RId) + if ok { + //目前是自己的领地才能驻守 + army.State = model.ArmyStop + this.addStopArmy(army) + this.Update(army) + }else{ + war := NewEmptyWar(army) + war.SyncExecute() + this.ArmyBack(army) + } + + }else if army.Cmd == model.ArmyCmdReclamation { + if army.State == model.ArmyRunning { + + ok := mgr.RBMgr.BuildIsRId(army.ToX, army.ToY, army.RId) + if ok { + //目前是自己的领地才能屯田 + this.addStopArmy(army) + this.Reclamation(army) + }else{ + war := NewEmptyWar(army) + war.SyncExecute() + this.ArmyBack(army) + } + + }else { + this.ArmyBack(army) + //增加场量 + rr, ok := mgr.RResMgr.Get(army.RId) + if ok { + b, ok1 := mgr.RBMgr.PositionBuild(army.ToX, army.ToY) + if ok1 { + rr.Stone += b.Stone + rr.Iron += b.Iron + rr.Wood += b.Wood + rr.Gold += rr.Gold + rr.Grain += rr.Grain + rr.SyncExecute() + } + } + } + }else if army.Cmd == model.ArmyCmdBack { + army.State = model.ArmyStop + army.Cmd = model.ArmyCmdIdle + army.ToX = army.FromX + army.ToY = army.FromY + + this.Update(army) + }else if army.Cmd == model.ArmyCmdTransfer { + //调动到位置了 + if army.State == model.ArmyRunning{ + + ok := mgr.RBMgr.BuildIsRId(army.ToX, army.ToY, army.RId) + if ok == false{ + this.ArmyBack(army) + }else{ + b, _ := mgr.RBMgr.PositionBuild(army.ToX, army.ToY) + if b.IsHasTransferAuth(){ + army.State = model.ArmyStop + army.Cmd = model.ArmyCmdIdle + x := army.ToX + y := army.ToY + army.FromX = x + army.FromY = y + army.ToX = x + army.ToY = y + this.addStopArmy(army) + this.Update(army) + }else{ + this.ArmyBack(army) + } + } + } + } +} + +func (this *armyLogic) ScanBlock(rid, x, y, length int) []*model.Army { + + if x < 0 || x >= global.MapWith || y < 0 || y >= global.MapHeight { + return nil + } + + maxX := util.MinInt(global.MapWith, x+length-1) + maxY := util.MinInt(global.MapHeight, y+length-1) + out := make([]*model.Army, 0) + + this.passBy.RLock() + for i := x; i <= maxX; i++ { + for j := y; j <= maxY; j++ { + + posId := global.ToPosition(i, j) + armys, ok := this.passByPosArmys[posId] + if ok { + is := armyIsInView(rid, i, j) + if is == false{ + continue + } + for _, army := range armys { + out = append(out, army) + } + } + } + } + this.passBy.RUnlock() + return out +} + +func (this *armyLogic) Arrive(army *model.Army) { + this.arriveArmys <- army +} + +func (this *armyLogic) Update(army *model.Army) { + this.updateArmys <- army +} + +func (this *armyLogic) Interrupt(posId int) { + this.interruptId <- posId +} + +func (this *armyLogic) GiveUp(posId int) { + this.giveUpId <- posId +} + +func (this* armyLogic) GetStopArmys(posId int)[]*model.Army { + ret := make([]*model.Army, 0) + this.stop.RLock() + armys, ok := this.stopInPosArmys[posId] + if ok { + for _, army := range armys { + ret = append(ret, army) + } + } + this.stop.RUnlock() + return ret +} + +func (this *armyLogic) deleteStopArmy(posId int) { + this.stop.Lock() + delete(this.stopInPosArmys, posId) + this.stop.Unlock() +} + +func (this*armyLogic) addStopArmy(army *model.Army) { + posId := global.ToPosition(army.ToX, army.ToY) + + this.stop.Lock() + if _, ok := this.stopInPosArmys[posId]; ok == false { + this.stopInPosArmys[posId] = make(map[int]*model.Army) + } + this.stopInPosArmys[posId][army.Id] = army + this.stop.Unlock() +} + + +func (this*armyLogic) addAction(t int64, army *model.Army) { + this.endTime.Lock() + defer this.endTime.Unlock() + _, ok := this.endTimeArmys[t] + if ok == false { + this.endTimeArmys[t] = make([]*model.Army, 0) + } + this.endTimeArmys[t] = append(this.endTimeArmys[t], army) +} + +//把行动丢进来 +func (this*armyLogic) PushAction(army *model.Army) { + + if army.Cmd == model.ArmyCmdAttack || + army.Cmd == model.ArmyCmdDefend || + army.Cmd == model.ArmyCmdTransfer{ + t := army.End.Unix() + this.addAction(t, army) + + }else if army.Cmd == model.ArmyCmdReclamation { + if army.State == model.ArmyRunning { + t := army.End.Unix() + this.addAction(t, army) + }else{ + costTime := static_conf.Basic.General.ReclamationTime + t := army.End.Unix()+int64(costTime) + this.addAction(t, army) + } + }else if army.Cmd == model.ArmyCmdBack { + + if army.FromX == army.ToX && army.FromY == army.ToY { + //处理调动到其他地方待命的情况,会归属的城池 + city, ok := mgr.RCMgr.Get(army.CityId) + if ok { + army.FromX = city.X + army.FromY = city.Y + + //计算回去的时间 + //speed := mgr.AMgr.GetSpeed(army) + //t := mgr.TravelTime(speed, army.FromX, army.FromY, army.ToX, army.ToY) + army.Start = time.Now() + //army.End = time.Now().Add(time.Duration(t) * time.Millisecond) + army.End = time.Now().Add(40*time.Second) + } + + }else{ + cur := time.Now() + diff := army.End.Unix()-army.Start.Unix() + if cur.Unix() < army.End.Unix(){ + diff = cur.Unix()-army.Start.Unix() + } + army.Start = cur + army.End = cur.Add(time.Duration(diff) * time.Second) + + } + army.Cmd = model.ArmyCmdBack + this.addAction(army.End.Unix(), army) + } + + this.Update(army) + +} + +func (this*armyLogic) ArmyBack(army *model.Army) { + army.ClearConscript() + + army.State = model.ArmyRunning + army.Cmd = model.ArmyCmdBack + + this.endTime.Lock() + t := army.End.Unix() + if actions, ok := this.endTimeArmys[t]; ok { + for i, v := range actions { + if v.Id == army.Id{ + actions = append(actions[:i], actions[i+1:]...) + this.endTimeArmys[t] = actions + break + } + } + } + this.endTime.Unlock() + this.PushAction(army) +} + +func (this*armyLogic) Reclamation(army *model.Army) { + army.State = model.ArmyStop + army.Cmd = model.ArmyCmdReclamation + this.PushAction(army) +} + + + + + diff --git a/server/slgserver/logic/army_war.go b/server/slgserver/logic/army_war.go new file mode 100644 index 0000000..9095e65 --- /dev/null +++ b/server/slgserver/logic/army_war.go @@ -0,0 +1,575 @@ +package logic + +import ( + "encoding/json" + "log/slog" + "math/rand" + "slgserver/server/slgserver/global" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/proto" + "slgserver/server/slgserver/static_conf" + "slgserver/server/slgserver/static_conf/facility" + "slgserver/server/slgserver/static_conf/general" + "slgserver/util" + "time" +) + +// 战斗位置的属性 +type armyPosition struct { + general *model.General + soldiers int //兵力 + force int //武力 + strategy int //策略 + defense int //防御 + speed int //速度 + destroy int //破坏 + arms int //兵种 + position int //位置 +} + +const maxRound = 10 + +type armyWar struct { + attack *model.Army + defense *model.Army + attackPos []*armyPosition + defensePos []*armyPosition +} + +type battle struct { + AId int `json:"a_id"` //本回合发起攻击的武将id + DId int `json:"d_id"` //本回合防御方的武将id + ALoss int `json:"a_loss"` //本回合攻击方损失的兵力 + DLoss int `json:"d_loss"` //本回合防守方损失的兵力 +} + +func (this *battle) to() []int { + r := make([]int, 0) + r = append(r, this.AId) + r = append(r, this.DId) + r = append(r, this.ALoss) + r = append(r, this.DLoss) + return r +} + +type warRound struct { + Battle [][]int `json:"b"` +} + +type WarResult struct { + round []*warRound + result int //0失败,1平,2胜利 +} + +func NewWar(attack *model.Army, defense *model.Army) *WarResult { + + w := armyWar{attack: attack, defense: defense} + w.init() + wars := w.battle() + + result := &WarResult{round: wars} + if w.attackPos[0].soldiers == 0 { + result.result = 0 + } else if w.defensePos[0] != nil && w.defensePos[0].soldiers != 0 { + result.result = 1 + } else { + result.result = 2 + } + + return result +} + +// 初始化军队和武将属性、兵种、加成等 +func (this *armyWar) init() { + + //城内设施加成 + attackAdds := []int{0, 0, 0, 0} + if this.attack.CityId > 0 { + attackAdds = mgr.RFMgr.GetAdditions(this.attack.CityId, + facility.TypeForce, + facility.TypeDefense, + facility.TypeSpeed, + facility.TypeStrategy) + } + + defenseAdds := []int{0, 0, 0, 0} + if this.defense.CityId > 0 { + defenseAdds = mgr.RFMgr.GetAdditions(this.defense.CityId, + facility.TypeForce, + facility.TypeDefense, + facility.TypeSpeed, + facility.TypeStrategy) + } + + //阵营加成 + aCampAdds := []int{0} + aCamp := this.attack.GetCamp() + if aCamp > 0 { + aCampAdds = mgr.RFMgr.GetAdditions(this.attack.CityId, facility.TypeHanAddition-1+aCamp) + } + + dCampAdds := []int{0} + dCamp := this.attack.GetCamp() + if dCamp > 0 { + dCampAdds = mgr.RFMgr.GetAdditions(this.defense.CityId, facility.TypeHanAddition-1+aCamp) + } + + this.attackPos = make([]*armyPosition, 0) + this.defensePos = make([]*armyPosition, 0) + + for i, g := range this.attack.Gens { + if g == nil { + this.attackPos = append(this.attackPos, nil) + } else { + pos := &armyPosition{ + general: g, + soldiers: this.attack.SoldierArray[i], + force: g.GetForce() + attackAdds[0] + aCampAdds[0], + defense: g.GetDefense() + attackAdds[1] + aCampAdds[0], + speed: g.GetSpeed() + attackAdds[2] + aCampAdds[0], + strategy: g.GetStrategy() + attackAdds[3] + aCampAdds[0], + destroy: g.GetDestroy() + aCampAdds[0], + arms: g.CurArms, + position: i, + } + this.attackPos = append(this.attackPos, pos) + } + } + + for i, g := range this.defense.Gens { + if g == nil { + this.defensePos = append(this.defensePos, nil) + } else { + pos := &armyPosition{ + general: g, + soldiers: this.defense.SoldierArray[i], + force: g.GetForce() + defenseAdds[0] + dCampAdds[0], + defense: g.GetDefense() + defenseAdds[1] + dCampAdds[0], + speed: g.GetSpeed() + defenseAdds[2] + dCampAdds[0], + strategy: g.GetStrategy() + defenseAdds[3] + dCampAdds[0], + destroy: g.GetDestroy() + dCampAdds[0], + arms: g.CurArms, + position: i, + } + this.defensePos = append(this.defensePos, pos) + } + } + + slog.Debug("army defense positions initialized", "positions", this.defensePos) +} + +func (this *armyWar) battle() []*warRound { + rounds := make([]*warRound, 0) + cur := 0 + for true { + r, isEnd := this.round() + rounds = append(rounds, r) + cur += 1 + if cur >= maxRound || isEnd { + break + } + } + + for i := 0; i < 3; i++ { + if this.attackPos[i] != nil { + this.attack.SoldierArray[i] = this.attackPos[i].soldiers + } + if this.defensePos[i] != nil { + this.defense.SoldierArray[i] = this.defensePos[i].soldiers + } + } + + return rounds +} + +// 回合 +func (this *armyWar) round() (*warRound, bool) { + + war := &warRound{} + n := rand.Intn(10) + attack := this.attackPos + defense := this.defensePos + + isEnd := false + //随机先手 + if n%2 == 0 { + attack = this.defensePos + defense = this.attackPos + } + + for _, att := range attack { + + ////////攻击方begin////////// + if att == nil || att.soldiers == 0 { + continue + } + + def, _ := this.randArmyPosition(defense) + if def == nil { + isEnd = true + goto end + } + + attHarmRatio := general.GenArms.GetHarmRatio(att.arms, def.arms) + attHarm := float64(util.AbsInt(att.force-def.defense)*att.soldiers) * attHarmRatio * 0.0005 + attKill := int(attHarm) + attKill = util.MinInt(attKill, def.soldiers) + def.soldiers -= attKill + att.general.Exp += attKill * 5 + + //大营干死了,直接结束 + if def.position == 0 && def.soldiers == 0 { + isEnd = true + goto end + } + ////////攻击方end////////// + + ////////防守方begin////////// + if def.soldiers == 0 || att.soldiers == 0 { + continue + } + + defHarmRatio := general.GenArms.GetHarmRatio(def.arms, att.arms) + defHarm := float64(util.AbsInt(def.force-att.defense)*def.soldiers) * defHarmRatio * 0.0005 + defKill := int(defHarm) + + defKill = util.MinInt(defKill, att.soldiers) + att.soldiers -= defKill + def.general.Exp += defKill * 5 + + b := battle{AId: att.general.Id, ALoss: defKill, DId: def.general.Id, DLoss: attKill} + war.Battle = append(war.Battle, b.to()) + + //大营干死了,直接结束 + if att.position == 0 && att.soldiers == 0 { + isEnd = true + goto end + } + ////////防守方end////////// + + } + +end: + return war, isEnd +} + +// 随机一个目标队伍 +func (this *armyWar) randArmyPosition(pos []*armyPosition) (*armyPosition, int) { + isEmpty := true + for _, v := range pos { + if v != nil && v.soldiers != 0 { + isEmpty = false + break + } + } + + if isEmpty { + return nil, -1 + } + + for true { + r := rand.Intn(100) + index := r % len(pos) + if pos[index] != nil && pos[index].soldiers != 0 { + return pos[index], index + } + } + + return nil, -1 +} + +func NewEmptyWar(attack *model.Army) *model.WarReport { + //战报处理 + pArmy := attack.ToProto().(proto.Army) + begArmy, _ := json.Marshal(pArmy) + + //武将战斗前 + begGeneral := make([][]int, 0) + for _, g := range attack.Gens { + if g != nil { + pg := g.ToProto().(proto.General) + begGeneral = append(begGeneral, pg.ToArray()) + } + } + begGeneralData, _ := json.Marshal(begGeneral) + + wr := &model.WarReport{X: attack.ToX, Y: attack.ToY, AttackRid: attack.RId, + AttackIsRead: false, DefenseIsRead: true, DefenseRid: 0, + BegAttackArmy: string(begArmy), BegDefenseArmy: "", + EndAttackArmy: string(begArmy), EndDefenseArmy: "", + BegAttackGeneral: string(begGeneralData), + EndAttackGeneral: string(begGeneralData), + BegDefenseGeneral: "", + EndDefenseGeneral: "", + Rounds: "", + Result: 0, + CTime: time.Now(), + } + return wr +} + +func checkCityOccupy(wr *model.WarReport, attackArmy *model.Army, city *model.MapRoleCity) { + destory := mgr.GMgr.GetDestroy(attackArmy) + wr.DestroyDurable = util.MinInt(destory, city.CurDurable) + city.DurableChange(-destory) + + if city.CurDurable == 0 { + aAttr, _ := mgr.RAttrMgr.Get(attackArmy.RId) + if aAttr.UnionId != 0 { + //有联盟才能俘虏玩家 + wr.Occupy = 1 + dAttr, _ := mgr.RAttrMgr.Get(city.RId) + dAttr.ParentId = aAttr.UnionId + Union.PutChild(aAttr.UnionId, city.RId) + dAttr.SyncExecute() + city.OccupyTime = time.Now() + } else { + wr.Occupy = 0 + } + } else { + wr.Occupy = 0 + } + city.SyncExecute() +} + +// 简单战斗 +func newBattle(attackArmy *model.Army) { + city, ok := mgr.RCMgr.PositionCity(attackArmy.ToX, attackArmy.ToY) + if ok { + + //驻守队伍被打 + posId := global.ToPosition(attackArmy.ToX, attackArmy.ToY) + enemys := ArmyLogic.GetStopArmys(posId) + + //城内空闲的队伍被打 + if armys, ok := mgr.AMgr.GetByCity(city.CityId); ok { + for _, enemy := range armys { + if enemy.IsCanOutWar() { + enemys = append(enemys, enemy) + } + } + } + + if len(enemys) == 0 { + //没有队伍 + destory := mgr.GMgr.GetDestroy(attackArmy) + city.DurableChange(-destory) + city.SyncExecute() + + wr := NewEmptyWar(attackArmy) + wr.Result = 2 + wr.DefenseRid = city.RId + wr.DefenseIsRead = false + checkCityOccupy(wr, attackArmy, city) + wr.SyncExecute() + } else { + lastWar, warReports := trigger(attackArmy, enemys, true) + if lastWar.result > 1 { + wr := warReports[len(warReports)-1] + checkCityOccupy(wr, attackArmy, city) + } + for _, wr := range warReports { + wr.SyncExecute() + } + } + } else { + //打建筑 + executeBuild(attackArmy) + } + +} + +func trigger(army *model.Army, enemys []*model.Army, isRoleEnemy bool) (*WarResult, []*model.WarReport) { + + posId := global.ToPosition(army.ToX, army.ToY) + warReports := make([]*model.WarReport, 0) + var lastWar *WarResult = nil + + for _, enemy := range enemys { + //战报处理 + pArmy := army.ToProto().(proto.Army) + pEnemy := enemy.ToProto().(proto.Army) + + begArmy1, _ := json.Marshal(pArmy) + begArmy2, _ := json.Marshal(pEnemy) + + //武将战斗前 + begGeneral1 := make([][]int, 0) + for _, g := range army.Gens { + if g != nil { + pg := g.ToProto().(proto.General) + begGeneral1 = append(begGeneral1, pg.ToArray()) + } + } + begGeneralData1, _ := json.Marshal(begGeneral1) + + begGeneral2 := make([][]int, 0) + for _, g := range enemy.Gens { + if g != nil { + pg := g.ToProto().(proto.General) + begGeneral2 = append(begGeneral2, pg.ToArray()) + } + } + begGeneralData2, _ := json.Marshal(begGeneral2) + + lastWar = NewWar(army, enemy) + + //武将战斗后 + endGeneral1 := make([][]int, 0) + for _, g := range army.Gens { + if g != nil { + pg := g.ToProto().(proto.General) + endGeneral1 = append(endGeneral1, pg.ToArray()) + level, exp := general.GenBasic.ExpToLevel(g.Exp) + g.Level = level + g.Exp = exp + g.SyncExecute() + } + } + endGeneralData1, _ := json.Marshal(endGeneral1) + + endGeneral2 := make([][]int, 0) + for _, g := range enemy.Gens { + if g != nil { + pg := g.ToProto().(proto.General) + endGeneral2 = append(endGeneral2, pg.ToArray()) + level, exp := general.GenBasic.ExpToLevel(g.Exp) + g.Level = level + g.Exp = exp + g.SyncExecute() + } + } + endGeneralData2, _ := json.Marshal(endGeneral2) + + pArmy = army.ToProto().(proto.Army) + pEnemy = enemy.ToProto().(proto.Army) + endArmy1, _ := json.Marshal(pArmy) + endArmy2, _ := json.Marshal(pEnemy) + + rounds, _ := json.Marshal(lastWar.round) + wr := &model.WarReport{X: army.ToX, Y: army.ToY, AttackRid: army.RId, + AttackIsRead: false, DefenseIsRead: false, DefenseRid: enemy.RId, + BegAttackArmy: string(begArmy1), BegDefenseArmy: string(begArmy2), + EndAttackArmy: string(endArmy1), EndDefenseArmy: string(endArmy2), + BegAttackGeneral: string(begGeneralData1), + BegDefenseGeneral: string(begGeneralData2), + EndAttackGeneral: string(endGeneralData1), + EndDefenseGeneral: string(endGeneralData2), + Rounds: string(rounds), + Result: lastWar.result, + CTime: time.Now(), + } + + warReports = append(warReports, wr) + enemy.ToSoldier() + enemy.ToGeneral() + + if isRoleEnemy { + if lastWar.result > 1 { + if isRoleEnemy { + ArmyLogic.deleteStopArmy(posId) + } + ArmyLogic.ArmyBack(enemy) + } + enemy.SyncExecute() + } else { + wr.DefenseIsRead = true + } + } + army.SyncExecute() + return lastWar, warReports +} + +func executeBuild(army *model.Army) { + roleBuild, _ := mgr.RBMgr.PositionBuild(army.ToX, army.ToY) + + posId := global.ToPosition(army.ToX, army.ToY) + posArmys := ArmyLogic.GetStopArmys(posId) + isRoleEnemy := len(posArmys) != 0 + var enemys []*model.Army + if isRoleEnemy == false { + enemys = ArmyLogic.sys.GetArmy(army.ToX, army.ToY) + } else { + for _, v := range posArmys { + enemys = append(enemys, v) + } + } + + lastWar, warReports := trigger(army, enemys, isRoleEnemy) + + if lastWar.result > 1 { + if roleBuild != nil { + destory := mgr.GMgr.GetDestroy(army) + wr := warReports[len(warReports)-1] + wr.DestroyDurable = util.MinInt(destory, roleBuild.CurDurable) + roleBuild.CurDurable = util.MaxInt(0, roleBuild.CurDurable-destory) + if roleBuild.CurDurable == 0 { + //攻占了玩家的领地 + bLimit := static_conf.Basic.Role.BuildLimit + if bLimit > mgr.RBMgr.BuildCnt(army.RId) { + wr.Occupy = 1 + mgr.RBMgr.RemoveFromRole(roleBuild) + mgr.RBMgr.AddBuild(army.RId, army.ToX, army.ToY) + OccupyRoleBuild(army.RId, army.ToX, army.ToY) + } else { + wr.Occupy = 0 + } + } else { + wr.Occupy = 0 + } + + } else { + //占领系统领地 + wr := warReports[len(warReports)-1] + blimit := static_conf.Basic.Role.BuildLimit + if blimit > mgr.RBMgr.BuildCnt(army.RId) { + OccupySystemBuild(army.RId, army.ToX, army.ToY) + wr.DestroyDurable = 10000 + wr.Occupy = 1 + } else { + wr.Occupy = 0 + } + ArmyLogic.sys.DelArmy(army.ToX, army.ToY) + } + } + + //领地发生变化 + if newRoleBuild, ok := mgr.RBMgr.PositionBuild(army.ToX, army.ToY); ok { + newRoleBuild.SyncExecute() + } + + for _, wr := range warReports { + wr.SyncExecute() + } +} + +func OccupyRoleBuild(rid, x, y int) { + newId := rid + + if b, ok := mgr.RBMgr.PositionBuild(x, y); ok { + + b.CurDurable = b.MaxDurable + b.OccupyTime = time.Now() + + oldId := b.RId + slog.Info("battle in role build", + "oldRId", oldId, + "newRId", newId) + b.RId = rid + } +} + +func OccupySystemBuild(rid, x, y int) { + + if _, ok := mgr.RBMgr.PositionBuild(x, y); ok { + return + } + + if mgr.NMMgr.IsCanBuild(x, y) { + rb, ok := mgr.RBMgr.AddBuild(rid, x, y) + if ok { + rb.OccupyTime = time.Now() + } + } +} diff --git a/server/slgserver/logic/check_build.go b/server/slgserver/logic/check_build.go new file mode 100644 index 0000000..4c14361 --- /dev/null +++ b/server/slgserver/logic/check_build.go @@ -0,0 +1,99 @@ +package logic + +import ( + "slgserver/server/slgserver/logic/mgr" + "slgserver/util" +) + +//是否能到达 +func IsCanArrive(x, y, rid int) bool { + var radius = 0 + unionId := getUnionId(rid) + b, ok := mgr.RBMgr.PositionBuild(x, y) + if ok { + radius = b.CellRadius() + } + + c, ok := mgr.RCMgr.PositionCity(x, y) + if ok { + radius = c.CellRadius() + } + + //查找10格半径 + for tx := x-10; tx <= x+10; tx++ { + for ty := y-10; ty <= y+10; ty++ { + b1, ok := mgr.RBMgr.PositionBuild(tx, ty) + if ok { + absX := util.AbsInt(x-tx) + absY := util.AbsInt(y-ty) + if absX <= radius+b1.CellRadius()+1 && absY <= radius+b1.CellRadius()+1{ + unionId1 := getUnionId(b1.RId) + parentId := getParentId(b1.RId) + if b1.RId == rid || (unionId != 0 && (unionId == unionId1 || unionId == parentId)){ + return true + } + } + } + + c1, ok := mgr.RCMgr.PositionCity(tx, ty) + if ok { + absX := util.AbsInt(x-tx) + absY := util.AbsInt(y-ty) + if absX <= radius+c1.CellRadius()+1 && absY <= radius+c1.CellRadius()+1{ + unionId1 := getUnionId(c1.RId) + parentId := getParentId(c1.RId) + if c1.RId == rid || (unionId != 0 && (unionId == unionId1 || unionId == parentId)){ + return true + } + } + } + } + } + + return false +} + +func IsCanDefend(x, y, rid int) bool{ + unionId := getUnionId(rid) + + b, ok := mgr.RBMgr.PositionBuild(x, y) + if ok { + tUnionId := getUnionId(b.RId) + tParentId := getParentId(b.RId) + if b.RId == rid{ + return true + }else if tUnionId > 0 { + return tUnionId == unionId + }else if tParentId > 0 { + return tParentId == unionId + } + } + + c, ok := mgr.RCMgr.PositionCity(x, y) + if ok { + tUnionId := getUnionId(c.RId) + tParentId := getParentId(c.RId) + if c.RId == rid{ + return true + }else if tUnionId > 0 { + return tUnionId == unionId + }else if tParentId > 0 { + return tParentId == unionId + } + } + return false +} + +//是否是免战 +func IsWarFree(x, y int) bool{ + b, ok := mgr.RBMgr.PositionBuild(x, y) + if ok { + return b.IsWarFree() + } + + c, ok := mgr.RCMgr.PositionCity(x, y) + if ok && getParentId(c.RId) > 0 { + return c.IsWarFree() + } + return false +} \ No newline at end of file diff --git a/server/slgserver/logic/coalition_logic.go b/server/slgserver/logic/coalition_logic.go new file mode 100644 index 0000000..4f89867 --- /dev/null +++ b/server/slgserver/logic/coalition_logic.go @@ -0,0 +1,169 @@ +package logic + +import ( + "log/slog" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "sync" +) + +func getUnionId(rid int) int { + attr, ok := mgr.RAttrMgr.Get(rid) + if ok { + return attr.UnionId + }else{ + return 0 + } +} + +func getUnionName(unionId int) string { + if unionId <= 0{ + return "" + } + + u, ok := mgr.UnionMgr.Get(unionId) + if ok { + return u.Name + }else{ + return "" + } +} + +func getParentId(rid int) int { + attr, ok := mgr.RAttrMgr.Get(rid) + if ok { + return attr.ParentId + }else{ + return 0 + } +} + +func getMainMembers(unionId int) []int { + u, ok := mgr.UnionMgr.Get(unionId) + r := make([]int, 0) + if ok { + if u.Chairman != 0{ + r = append(r, u.Chairman) + } + if u.ViceChairman != 0{ + r = append(r, u.ViceChairman) + } + } + return r +} + + +type coalitionLogic struct { + mutex sync.RWMutex + children map[int]map[int]int //key:unionId,key&value:child rid +} + +func NewCoalitionLogic() *coalitionLogic { + c := &coalitionLogic{ + children: make(map[int]map[int]int), + } + c.init() + return c +} + +func (this*coalitionLogic) init() { + //初始化下属玩家 + attrs := mgr.RAttrMgr.List() + for _, attr := range attrs { + if attr.ParentId !=0 { + this.PutChild(attr.ParentId, attr.RId) + } + } +} + +func (this*coalitionLogic) MemberEnter(rid, unionId int) { + + attr, ok := mgr.RAttrMgr.TryCreate(rid) + if ok { + attr.UnionId = unionId + if attr.ParentId == unionId{ + this.DelChild(unionId, attr.RId) + } + }else{ + slog.Warn("EnterUnion not found roleAttribute", "rid", rid) + } + + if rcs, ok := mgr.RCMgr.GetByRId(rid); ok { + for _, rc := range rcs { + rc.SyncExecute() + } + } +} + +func (this*coalitionLogic) MemberExit(rid int) { + + if ra, ok := mgr.RAttrMgr.Get(rid); ok { + ra.UnionId = 0 + } + + if rcs, ok := mgr.RCMgr.GetByRId(rid); ok { + for _, rc := range rcs { + rc.SyncExecute() + } + } +} + +//解散 +func (this*coalitionLogic) Dismiss(unionId int) { + u, ok := mgr.UnionMgr.Get(unionId) + if ok { + mgr.UnionMgr.Remove(unionId) + for _, rid := range u.MemberArray { + this.MemberExit(rid) + this.DelUnionAllChild(unionId) + } + u.State = model.UnionDismiss + u.MemberArray = []int{} + u.SyncExecute() + } +} + +func (this*coalitionLogic) PutChild(unionId, rid int) { + this.mutex.Lock() + _, ok := this.children[unionId] + if ok == false { + this.children[unionId] = make(map[int]int) + } + this.children[unionId][rid] = rid + this.mutex.Unlock() +} + +func (this*coalitionLogic) DelChild(unionId, rid int) { + this.mutex.Lock() + children, ok := this.children[unionId] + if ok { + attr, ok := mgr.RAttrMgr.Get(rid) + if ok { + attr.ParentId = 0 + attr.SyncExecute() + } + delete(children, rid) + } + this.mutex.Unlock() +} + +func (this*coalitionLogic) DelUnionAllChild(unionId int) { + this.mutex.Lock() + children, ok := this.children[unionId] + if ok { + for _, child := range children { + attr, ok := mgr.RAttrMgr.Get(child) + if ok { + attr.ParentId = 0 + attr.SyncExecute() + } + + city, ok := mgr.RCMgr.GetMainCity(child) + if ok { + city.SyncExecute() + } + } + delete(this.children, unionId) + } + this.mutex.Unlock() +} diff --git a/server/slgserver/logic/init.go b/server/slgserver/logic/init.go new file mode 100644 index 0000000..6ba06d7 --- /dev/null +++ b/server/slgserver/logic/init.go @@ -0,0 +1,65 @@ +package logic + +import ( + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "time" +) + + +var Union *coalitionLogic +var ArmyLogic *armyLogic + +func BeforeInit() { + //初始化一些方法 + model.ArmyIsInView = armyIsInView + model.GetUnionId = getUnionId + model.GetRoleNickName = mgr.RoleNickName + model.GetParentId = getParentId + model.GetMainMembers = getMainMembers + model.GetUnionName = getUnionName + model.GetYield = mgr.GetYield + model.GetDepotCapacity = mgr.GetDepotCapacity + model.GetCityCost = mgr.GetCityCost + model.GetMaxDurable = mgr.GetMaxDurable + model.GetCityLv = mgr.GetCityLV + model.MapResTypeLevel = mgr.NMMgr.MapResTypeLevel +} + +//逻辑相关的初始化放在这里 +func Init() { + + Union = NewCoalitionLogic() + ArmyLogic = &armyLogic{ + arriveArmys: make(chan *model.Army, 100), + interruptId: make(chan int, 100), + giveUpId: make(chan int, 100), + updateArmys: make(chan *model.Army, 100), + outArmys: make(map[int]*model.Army), + endTimeArmys: make(map[int64][]*model.Army), + stopInPosArmys: make(map[int]map[int]*model.Army), + passByPosArmys: make(map[int]map[int]*model.Army), + sys: NewSysArmy()} + + ArmyLogic.init() + go ArmyLogic.check() + go ArmyLogic.running() + +} + +func AfterInit() { + go func() { + for true { + time.Sleep(1*time.Second) + buildIds := mgr.RBMgr.CheckGiveUp() + for _, buildId := range buildIds { + ArmyLogic.GiveUp(buildId) + } + + buildIds = mgr.RBMgr.CheckDestroy() + for _, buildId := range buildIds { + ArmyLogic.Interrupt(buildId) + } + } + }() +} \ No newline at end of file diff --git a/server/slgserver/logic/mgr/army_mgr.go b/server/slgserver/logic/mgr/army_mgr.go new file mode 100644 index 0000000..121e380 --- /dev/null +++ b/server/slgserver/logic/mgr/army_mgr.go @@ -0,0 +1,286 @@ +package mgr + +import ( + "log/slog" + "slgserver/db" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/static_conf/facility" + "sync" +) + + +type armyMgr struct { + mutex sync.RWMutex + armyById map[int]*model.Army //key:armyId + armyByCityId map[int][]*model.Army //key:cityId + armyByRId map[int][]*model.Army //key:rid +} + +var AMgr = &armyMgr{ + armyById: make(map[int]*model.Army), + armyByCityId: make(map[int][]*model.Army), + armyByRId: make(map[int][]*model.Army), +} + +func (this*armyMgr) Load() { + + db.MasterDB.Table(model.Army{}).Find(this.armyById) + + for _, army := range this.armyById { + //处理征兵 + army.CheckConscript() + cid := army.CityId + c,ok:= this.armyByCityId[cid] + if ok { + this.armyByCityId[cid] = append(c, army) + }else{ + this.armyByCityId[cid] = make([]*model.Army, 0) + this.armyByCityId[cid] = append(this.armyByCityId[cid], army) + } + + //rid + if _, ok := this.armyByRId[army.RId]; ok == false{ + this.armyByRId[army.RId] = make([]*model.Army, 0) + } + this.armyByRId[army.RId] = append(this.armyByRId[army.RId], army) + this.updateGenerals(army) + } + +} + +func (this*armyMgr) insertOne(army *model.Army) { + + aid := army.Id + cid := army.CityId + + this.armyById[aid] = army + if _, r:= this.armyByCityId[cid]; r == false{ + this.armyByCityId[cid] = make([]*model.Army, 0) + } + this.armyByCityId[cid] = append(this.armyByCityId[cid], army) + + if _, ok := this.armyByRId[army.RId]; ok == false{ + this.armyByRId[army.RId] = make([]*model.Army, 0) + } + this.armyByRId[army.RId] = append(this.armyByRId[army.RId], army) + + this.updateGenerals(army) + +} + +func (this*armyMgr) insertMutil(armys []*model.Army) { + for _, v := range armys { + this.insertOne(v) + } +} + + +func (this*armyMgr) Get(aid int) (*model.Army, bool){ + this.mutex.RLock() + a, ok := this.armyById[aid] + this.mutex.RUnlock() + if ok { + a.CheckConscript() + return a, true + }else{ + army := &model.Army{} + ok, err := db.MasterDB.Table(model.Army{}).Where("id=?", aid).Get(army) + if ok { + this.mutex.Lock() + this.insertOne(army) + this.mutex.Unlock() + return army, true + }else{ + if err == nil{ + slog.Warn("armyMgr GetByRId armyId db not found", + "armyId", aid) + return nil, false + }else{ + slog.Warn("armyMgr GetByRId db error", "armyId", aid) + return nil, false + } + } + } +} + +func (this*armyMgr) GetByCity(cid int) ([]*model.Army, bool){ + this.mutex.RLock() + as, ok := this.armyByCityId[cid] + this.mutex.RUnlock() + if ok { + for _, a := range as { + a.CheckConscript() + } + return as, true + }else{ + m := make([]*model.Army, 0) + err := db.MasterDB.Table(model.Army{}).Where("cityId=?", cid).Find(&m) + if err!=nil{ + slog.Warn("armyMgr GetByCity db error", "cityId", cid) + return m, false + }else{ + this.mutex.Lock() + this.insertMutil(m) + this.mutex.Unlock() + return m, true + } + } +} + +func (this*armyMgr) GetByCityOrder(cid int, order int8) (*model.Army, bool){ + rs, ok := this.GetByCity(cid) + if ok { + for _, r := range rs { + if r.Order == order{ + return r, true + } + } + }else{ + return nil, false + } + return nil, false +} + +func (this*armyMgr) GetByRId(rid int) ([]*model.Army, bool){ + this.mutex.RLock() + as, ok := this.armyByRId[rid] + this.mutex.RUnlock() + + if ok { + for _, a := range as { + a.CheckConscript() + } + } + return as, ok +} + +//归属于该位置的军队数量 +func (this*armyMgr) BelongPosArmyCnt(rid int, x, y int) int{ + cnt := 0 + armys, ok := this.GetByRId(rid) + if ok { + for _, army := range armys { + if army.FromX == x && army.FromY == y{ + cnt += 1 + }else if army.Cmd == model.ArmyCmdTransfer && army.ToX == x && army.ToY == y { + cnt += 1 + } + } + } + + return cnt +} + +func (this*armyMgr) GetOrCreate(rid int, cid int, order int8) (*model.Army, error){ + + this.mutex.RLock() + armys, ok := this.armyByCityId[cid] + this.mutex.RUnlock() + + if ok { + for _, v := range armys { + if v.Order == order{ + return v, nil + } + } + } + + + + //需要创建 + army := &model.Army{RId: rid, + Order: order, + CityId: cid, + Generals: `[0,0,0]`, + Soldiers: `[0,0,0]`, + GeneralArray: []int{0,0,0}, + SoldierArray: []int{0,0,0}, + ConscriptCnts: `[0,0,0]`, + ConscriptTimes: `[0,0,0]`, + ConscriptCntArray: []int{0,0,0}, + ConscriptTimeArray: []int64{0,0,0}, + } + + city, ok := RCMgr.Get(cid) + if ok { + army.FromX = city.X + army.FromY = city.Y + army.ToX = city.X + army.ToY = city.Y + } + + _, err := db.MasterDB.Insert(army) + if err == nil{ + this.mutex.Lock() + this.insertOne(army) + this.mutex.Unlock() + return army, nil + }else{ + slog.Warn("db error", "error", err) + return nil, err + } +} + +func (this*armyMgr) GetSpeed(army*model.Army) int{ + speed := 100000 + for _, g := range army.Gens { + if g != nil { + s := g.GetSpeed() + if s < speed { + speed = s + } + } + } + + //阵营加成 + camp := army.GetCamp() + campAdds := []int{0} + if camp > 0{ + campAdds = RFMgr.GetAdditions(army.CityId, facility.TypeHanAddition-1+camp) + } + return speed + campAdds[0] +} + +//能否已经重复上阵了 +func (this*armyMgr) IsRepeat(rid int, cfgId int) bool{ + armys, ok := this.GetByRId(rid) + if ok == false{ + return true + } + + for _, army := range armys { + for _, g := range army.Gens { + if g != nil { + if g.CfgId == cfgId && g.CityId != 0{ + return false + } + } + } + } + return true +} + +func (this*armyMgr) updateGenerals(armys... *model.Army) { + for _, army := range armys { + army.Gens = make([]*model.General, 0) + for _, gid := range army.GeneralArray { + if gid == 0{ + army.Gens = append(army.Gens, nil) + }else{ + g, _ := GMgr.GetByGId(gid) + army.Gens = append(army.Gens, g) + } + } + } +} + +func (this*armyMgr) All()[]*model.Army { + this.mutex.RLock() + defer this.mutex.RUnlock() + armys := make([]*model.Army, 0) + for _, army := range this.armyById { + armys = append(armys, army) + } + return armys +} + diff --git a/server/slgserver/logic/mgr/city_facility_mgr.go b/server/slgserver/logic/mgr/city_facility_mgr.go new file mode 100644 index 0000000..5734be8 --- /dev/null +++ b/server/slgserver/logic/mgr/city_facility_mgr.go @@ -0,0 +1,326 @@ +package mgr + +import ( + "encoding/json" + "log/slog" + "slgserver/constant" + "slgserver/db" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/static_conf/facility" + "sync" + "time" +) + +var RFMgr = facilityMgr{ + facilities: make(map[int]*model.CityFacility), + facilitiesByRId: make(map[int][]*model.CityFacility), +} + +type facilityMgr struct { + mutex sync.RWMutex + facilities map[int]*model.CityFacility + facilitiesByRId map[int][]*model.CityFacility //key:rid +} + +func (this*facilityMgr) Load() { + + err := db.MasterDB.Find(this.facilities) + if err != nil { + slog.Error("facilityMgr load city_facility table error") + } + + for _, cityFacility := range this.facilities { + rid := cityFacility.RId + _, ok := this.facilitiesByRId[rid] + if ok == false { + this.facilitiesByRId[rid] = make([]*model.CityFacility, 0) + } + this.facilitiesByRId[rid] = append(this.facilitiesByRId[rid], cityFacility) + } + +} +func (this*facilityMgr) GetByRId(rid int) ([]*model.CityFacility, bool){ + this.mutex.RLock() + r, ok := this.facilitiesByRId[rid] + this.mutex.RUnlock() + return r, ok +} + +func (this*facilityMgr) Get(cid int) (*model.CityFacility, bool){ + this.mutex.RLock() + r, ok := this.facilities[cid] + this.mutex.RUnlock() + + if ok { + return r, true + } + + r = &model.CityFacility{} + ok, err := db.MasterDB.Table(r).Where("cityId=?", cid).Get(r) + if err != nil{ + slog.Warn("db error", "error", err) + } + + if ok { + this.mutex.Lock() + this.facilities[cid] = r + this.mutex.Unlock() + return r, true + }else{ + return nil, false + } +} + +func (this*facilityMgr) GetFacility(cid int, fType int8) (*model.Facility, bool){ + cf, ok := this.Get(cid) + if ok == false{ + return nil, false + } + + facilities := cf.Facility() + for _, v := range facilities { + if v.Type == fType{ + return &v, true + } + } + return nil, false +} + +func (this*facilityMgr) GetFacilityLv(cid int, fType int8) int8{ + f, ok := this.GetFacility(cid, fType) + if ok { + return f.GetLevel() + }else{ + return 0 + } +} + +/* +获取城内设施加成 +*/ +func (this*facilityMgr) GetAdditions(cid int, additionType... int8 ) []int{ + cf, ok := this.Get(cid) + ret := make([]int, len(additionType)) + if ok == false{ + return ret + } + + for i, at := range additionType { + total := 0 + facilities := cf.Facility() + for _, f := range facilities { + if f.GetLevel() > 0{ + adds := facility.FConf.GetAdditions(f.Type) + values := facility.FConf.GetValues(f.Type, f.GetLevel()) + + for i, add := range adds { + if add == at { + total += values[i] + } + } + } + } + ret[i] = total + } + + return ret +} +/* +如果不存在尝试去创建 +*/ +func (this*facilityMgr) GetAndTryCreate(cid, rid int) (*model.CityFacility, bool){ + r, ok := this.Get(cid) + if ok { + return r, true + }else{ + if _, ok:= RCMgr.Get(cid); ok { + //创建 + fs := make([]model.Facility, len(facility.FConf.List)) + + for i, v := range facility.FConf.List { + f := model.Facility{Type: v.Type, PrivateLevel: 0, Name: v.Name} + fs[i] = f + } + + sdata, _ := json.Marshal(fs) + cf := &model.CityFacility{CityId: cid, RId: rid, Facilities: string(sdata)} + db.MasterDB.Table(cf).Insert(cf) + + this.mutex.Lock() + this.facilities[cid] = cf + this.mutex.Unlock() + + return cf, true + }else{ + slog.Warn("cid not found", "cid", cid) + return nil, false + } + } +} + +func (this*facilityMgr) UpFacility(rid, cid int, fType int8) (*model.Facility, int){ + this.mutex.RLock() + f, ok := this.facilities[cid] + this.mutex.RUnlock() + + if ok == false{ + slog.Warn("UpFacility cityId not found", + "cityId", cid, + "type", int(fType)) + return nil, constant.CityNotExist + }else{ + facilities := make([]*model.Facility, 0) + var out *model.Facility + json.Unmarshal([]byte(f.Facilities), &facilities) + for _, fac := range facilities { + if fac.Type == fType { + maxLevel := facility.FConf.MaxLevel(fType) + if fac.CanLV() == false { + //正在升级中了 + slog.Warn("UpFacility error because already in up", + "curLevel", int(fac.GetLevel()), + "maxLevel", int(maxLevel), + "cityId", cid, + "type", int(fType)) + return nil, constant.UpError + }else if fac.GetLevel() >= maxLevel { + slog.Warn("UpFacility error", + "curLevel", int(fac.GetLevel()), + "maxLevel", int(maxLevel), + "cityId", cid, + "type", int(fType)) + return nil, constant.UpError + }else{ + need, ok := facility.FConf.Need(fType, fac.GetLevel()+1) + if ok == false { + slog.Warn("UpFacility Need config error", + "curLevel", int(fac.GetLevel()), + "cityId", cid, + "type", int(fType)) + return nil, constant.UpError + } + + code := RResMgr.TryUseNeed(rid, *need) + if code == constant.OK { + fac.UpTime = time.Now().Unix() + out = fac + if t, err := json.Marshal(facilities); err == nil{ + f.Facilities = string(t) + f.SyncExecute() + return out, constant.OK + }else{ + return nil, constant.UpError + } + }else{ + slog.Warn("UpFacility Need Res Not Enough", + "curLevel", int(fac.GetLevel()), + "cityId", cid, + "type", int(fType)) + return nil, code + } + } + } + } + + slog.Warn("UpFacility error not found type", + "cityId", cid, + "type", int(fType)) + return nil, constant.UpError + } +} + + +func (this*facilityMgr) GetYield(rid int)model.Yield{ + cfs, ok := this.GetByRId(rid) + var y model.Yield + if ok { + for _, cf := range cfs { + for _, f := range cf.Facility() { + if f.GetLevel() > 0{ + values := facility.FConf.GetValues(f.Type, f.GetLevel()) + additions := facility.FConf.GetAdditions(f.Type) + for i, aType := range additions { + if aType == facility.TypeWood { + y.Wood += values[i] + }else if aType == facility.TypeGrain { + y.Grain += values[i] + }else if aType == facility.TypeIron { + y.Iron += values[i] + }else if aType == facility.TypeStone { + y.Stone += values[i] + }else if aType == facility.TypeTax { + y.Gold += values[i] + } + } + } + } + } + } + return y +} + +func (this*facilityMgr) GetDepotCapacity(rid int)int{ + cfs, ok := this.GetByRId(rid) + limit := 0 + if ok { + for _, cf := range cfs { + for _, f := range cf.Facility() { + if f.GetLevel() > 0{ + values := facility.FConf.GetValues(f.Type, f.GetLevel()) + additions := facility.FConf.GetAdditions(f.Type) + for i, aType := range additions { + if aType == facility.TypeWarehouseLimit { + limit += values[i] + } + } + } + } + } + } + return limit +} + +func (this*facilityMgr) GetCost(cid int) int8{ + cf, ok := this.Get(cid) + limit := 0 + if ok { + for _, f := range cf.Facility() { + if f.GetLevel() > 0{ + values := facility.FConf.GetValues(f.Type, f.GetLevel()) + additions := facility.FConf.GetAdditions(f.Type) + for i, aType := range additions { + if aType == facility.TypeCost { + limit += values[i] + } + } + } + } + } + return int8(limit) +} + +func (this*facilityMgr) GetMaxDurable(cid int) int{ + cf, ok := this.Get(cid) + limit := 0 + if ok { + for _, f := range cf.Facility() { + if f.GetLevel() > 0{ + values := facility.FConf.GetValues(f.Type, f.GetLevel()) + additions := facility.FConf.GetAdditions(f.Type) + for i, aType := range additions { + if aType == facility.TypeDurable { + limit += values[i] + } + } + } + } + } + return limit +} + +func (this*facilityMgr) GetCityLV(cid int) int8{ + return this.GetFacilityLv(cid, facility.Main) +} + + + diff --git a/server/slgserver/logic/mgr/coalition_mgr.go b/server/slgserver/logic/mgr/coalition_mgr.go new file mode 100644 index 0000000..e0a12d7 --- /dev/null +++ b/server/slgserver/logic/mgr/coalition_mgr.go @@ -0,0 +1,98 @@ +package mgr + +import ( + "log/slog" + "slgserver/db" + "slgserver/server/slgserver/model" + "sync" + "time" +) + +type coalitionMgr struct { + mutex sync.RWMutex + unions map[int]*model.Coalition +} + +var UnionMgr = &coalitionMgr{ + unions: make(map[int]*model.Coalition), +} + +func (this*coalitionMgr) Load() { + + rr := make([]*model.Coalition, 0) + err := db.MasterDB.Where("state=?", model.UnionRunning).Find(&rr) + if err != nil { + slog.Error("coalitionMgr load union table error") + } + + for _, v := range rr { + this.unions[v.Id] = v + } +} + + +func (this*coalitionMgr) Get(unionId int) (*model.Coalition, bool){ + + this.mutex.RLock() + r, ok := this.unions[unionId] + this.mutex.RUnlock() + + if ok { + return r, true + } + + m := &model.Coalition{} + ok, err := db.MasterDB.Table(new(model.Coalition)).Where( + "unionId=? and state=?", unionId, model.UnionRunning).Get(m) + if ok { + + this.mutex.Lock() + this.unions[unionId] = m + this.mutex.Unlock() + + return m, true + }else{ + if err == nil{ + slog.Warn("coalitionMgr not found", "unionId", unionId) + return nil, false + }else{ + slog.Warn("db error", "error", err) + return nil, false + } + } +} + +func (this*coalitionMgr) Create(name string, rid int) (*model.Coalition, bool){ + m := &model.Coalition{Name: name, Ctime: time.Now(), + CreateId: rid, Chairman: rid, State: model.UnionRunning, MemberArray: []int{rid}} + + _, err := db.MasterDB.Table(new(model.Coalition)).InsertOne(m) + if err == nil { + + this.mutex.Lock() + this.unions[m.Id] = m + this.mutex.Unlock() + + return m, true + }else{ + slog.Error("db error", "error", err) + return nil, false + } +} + +func (this*coalitionMgr) List() []*model.Coalition { + r := make([]*model.Coalition, 0) + this.mutex.RLock() + for _, coalition := range this.unions { + r = append(r, coalition) + } + this.mutex.RUnlock() + return r +} + +func (this*coalitionMgr) Remove(unionId int) { + this.mutex.Lock() + delete(this.unions, unionId) + this.mutex.Unlock() +} + diff --git a/server/slgserver/logic/mgr/general_mgr.go b/server/slgserver/logic/mgr/general_mgr.go new file mode 100644 index 0000000..a06754e --- /dev/null +++ b/server/slgserver/logic/mgr/general_mgr.go @@ -0,0 +1,353 @@ +package mgr + +import ( + "log/slog" + "math/rand" + "slgserver/db" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/static_conf" + "slgserver/server/slgserver/static_conf/general" + "slgserver/util" + "sync" + "time" +) + +type generalMgr struct { + mutex sync.RWMutex + genByRole map[int][]*model.General + genByGId map[int]*model.General +} + +var GMgr = &generalMgr{ + genByRole: make(map[int][]*model.General), + genByGId: make(map[int]*model.General), +} + +func (this*generalMgr) updatePhysicalPower() { + limit := static_conf.Basic.General.PhysicalPowerLimit + recoverCnt := static_conf.Basic.General.RecoveryPhysicalPower + for true { + time.Sleep(1*time.Hour) + this.mutex.RLock() + for _, g := range this.genByGId { + if g.PhysicalPower < limit{ + g.PhysicalPower = util.MinInt(limit, g.PhysicalPower+recoverCnt) + g.SyncExecute() + } + } + this.mutex.RUnlock() + } +} + +//创建npc +func (this*generalMgr) createNPC() ([]*model.General, bool){ + + gs := make([]*model.General, 0) + sess := db.MasterDB.NewSession() + sess.Begin() + + for _, v := range general.General.GMap { + if v.Star >= 3{ + arr := []int8{1,5,10,20} + for _, level := range arr{ + r, ok := this.NewGeneral(v.CfgId, 0, level) + if ok == false { + sess.Rollback() + return nil, false + } + gs = append(gs, r) + } + + } + } + + if err := sess.Commit(); err != nil{ + slog.Warn("db error", "error", err) + return nil, false + }else{ + return gs, true + } +} + +func (this*generalMgr) add(g *model.General) { + this.mutex.Lock() + + if _,ok := this.genByRole[g.RId]; ok == false{ + this.genByRole[g.RId] = make([]*model.General, 0) + } + this.genByRole[g.RId] = append(this.genByRole[g.RId], g) + this.genByGId[g.Id] = g + + this.mutex.Unlock() +} + + + +func (this*generalMgr) Load(){ + + err := db.MasterDB.Table(model.General{}).Where("state=?", + model.GeneralNormal).Find(this.genByGId) + + if err != nil { + slog.Warn("db error", "error", err) + return + } + + for _, v := range this.genByGId { + if _, ok := this.genByRole[v.RId]; ok==false { + this.genByRole[v.RId] = make([]*model.General, 0) + } + this.genByRole[v.RId] = append(this.genByRole[v.RId], v) + } + + if len(this.genByGId) == 0{ + this.createNPC() + } + + go this.updatePhysicalPower() +} + +func (this*generalMgr) GetByRId(rid int) ([]*model.General, bool){ + this.mutex.Lock() + r, ok := this.genByRole[rid] + this.mutex.Unlock() + + if ok { + out := make([]*model.General, 0) + for _, g := range r { + if g.IsActive(){ + out = append(out, g) + } + } + return out, true + } + + gs := make([]*model.General, 0) + err := db.MasterDB.Table(new(model.General)).Where( + "rid=? and state=?", rid, model.GeneralNormal).Find(&gs) + + if err == nil { + if len(gs) > 0 { + for _, g := range gs { + this.add(g) + } + return gs, true + }else{ + slog.Warn("general not fount", "rid", rid) + return nil, false + } + }else{ + slog.Warn("db error", "error", err) + return nil, false + } +} + +//查找将领 +func (this*generalMgr) GetByGId(gid int) (*model.General, bool){ + this.mutex.RLock() + g, ok := this.genByGId[gid] + this.mutex.RUnlock() + if ok { + if g.IsActive(){ + return g, true + }else{ + return nil, false + } + }else{ + + g := &model.General{} + r, err := db.MasterDB.Table(new(model.General)).Where( + "id=? and state=?", gid, model.GeneralNormal).Get(g) + + if err == nil{ + if r { + this.add(g) + return g, true + }else{ + slog.Warn("general gid not found", "gid", gid) + return nil, false + } + + }else{ + slog.Warn("general gid not found", "gid", gid) + return nil, false + } + } +} + +//这个角色是否有这个武将 +func (this*generalMgr) HasGeneral(rid int ,gid int) (*model.General,bool){ + r, ok := this.GetByRId(rid) + if ok { + for _, v := range r { + t := v + if t.Id == gid { + return t,true + } + } + } + return nil,false +} + +func (this*generalMgr) HasGenerals(rid int, gIds []int) ([]*model.General,bool){ + gs := make([]*model.General, 0) + for i := 0; i < len(gIds); i++ { + g,ok := this.HasGeneral(rid, gIds[i]) + if ok{ + gs = append(gs,g) + }else{ + return gs,false + } + } + return gs,true +} + +func (this*generalMgr) Count(rid int) int{ + gs, ok := this.GetByRId(rid) + if ok { + return len(gs) + }else{ + return 0 + } +} + +func (this*generalMgr) NewGeneral(cfgId int, rid int, level int8) (*model.General, bool) { + g, ok := model.NewGeneral(cfgId, rid, level) + if ok { + this.add(g) + } + return g, ok +} + +/* +如果不存在则去创建 +*/ +func (this*generalMgr) GetOrCreateByRId(rid int) ([]*model.General, bool){ + r, ok := this.GetByRId(rid) + if ok { + return r, true + }else{ + //创建 + gs := make([]*model.General, 0) + sess := db.MasterDB.NewSession() + sess.Begin() + + g, ok := this.RandCreateGeneral(rid,3) + if ok == false{ + sess.Rollback() + return nil, false + } + gs = g + + if err := sess.Commit(); err != nil{ + slog.Warn("db error", "error", err) + return nil, false + }else{ + return gs, true + } + } +} + + +/* +随机创建一个 +*/ +func (this*generalMgr) RandCreateGeneral(rid int, nums int) ([]*model.General, bool){ + gs := make([]*model.General, 0) + sess := db.MasterDB.NewSession() + sess.Begin() + + for i := 0; i < nums; i++ { + cfgId := general.General.Draw() + g, ok := this.NewGeneral(cfgId, rid, 1) + if ok == false{ + sess.Rollback() + return nil, false + } + gs = append(gs, g) + } + + if err := sess.Commit(); err != nil{ + slog.Warn("db error", "error", err) + return nil, false + }else{ + return gs, true + } +} + + +//获取npc武将 +func (this*generalMgr) GetNPCGenerals(cnt int, star int8, level int8) ([]model.General, bool) { + gs, ok := this.GetByRId(0) + if ok == false { + return make([]model.General, 0), false + }else{ + target := make([]model.General, 0) + for _, g := range gs { + if g.Level == level && g.Star == star{ + target = append(target, *g) + } + } + + if len(target) < cnt{ + return make([]model.General, 0), false + }else{ + m := make(map[int]int) + for true { + r := rand.Intn(len(target)) + m[r] = r + if len(m) == cnt{ + break + } + } + + rgs := make([]model.General, 0) + for _, v := range m { + t := target[v] + rgs = append(rgs, t) + } + return rgs, true + } + } +} + +func (this *generalMgr) GetDestroy(army *model.Army) int{ + destroy := 0 + for _, g := range army.Gens { + if g != nil { + destroy += g.GetDestroy() + } + } + return destroy +} + +//体力是否足够 +func (this*generalMgr) PhysicalPowerIsEnough(army *model.Army, cost int) bool{ + for _, g := range army.Gens { + if g == nil{ + continue + } + if g.PhysicalPower < cost{ + return false + } + } + return true +} + +//尝试使用体力 +func (this *generalMgr) TryUsePhysicalPower(army *model.Army, cost int) bool{ + + if this.PhysicalPowerIsEnough(army, cost) == false{ + return false + } + + for _, g := range army.Gens { + if g == nil{ + continue + } + g.PhysicalPower -= cost + g.SyncExecute() + } + + return true +} diff --git a/server/slgserver/logic/mgr/national_map_mgr.go b/server/slgserver/logic/mgr/national_map_mgr.go new file mode 100644 index 0000000..2ed79de --- /dev/null +++ b/server/slgserver/logic/mgr/national_map_mgr.go @@ -0,0 +1,176 @@ +package mgr + +import ( + "encoding/json" + "log/slog" + "math" + "os" + "slgserver/config" + "slgserver/server/slgserver/global" + "slgserver/server/slgserver/model" + "slgserver/util" + "sync" +) + +const ScanWith = 3 +const ScanHeight = 3 + +type NMArray struct { + arr []model.NationalMap +} + +type mapData struct { + Width int `json:"w"` + Height int `json:"h"` + List [][]int `json:"list"` +} + +func Distance(begX, begY, endX, endY int) float64 { + w := math.Abs(float64(endX - begX)) + h := math.Abs(float64(endY - begY)) + return math.Sqrt(w*w + h*h) +} + +func TravelTime(speed, begX, begY, endX, endY int) int { + dis := Distance(begX, begY, endX, endY) + t := dis / float64(speed) * 100000000 + return int(t) +} + +type NationalMapMgr struct { + mutex sync.RWMutex + conf map[int]model.NationalMap + sysBuild map[int]model.NationalMap +} + +var NMMgr = &NationalMapMgr{ + conf: make(map[int]model.NationalMap), + sysBuild: make(map[int]model.NationalMap), +} + +func (this *NationalMapMgr) Load() { + + fileName := config.GetPath("logic.map_data", + "data/conf/mapRes_0.json") + + jdata, err := os.ReadFile(fileName) + if err != nil { + slog.Error("NationalMapMgr load file error", "error", err) + os.Exit(0) + } + + m := &mapData{} + err = json.Unmarshal(jdata, m) + if err != nil { + slog.Error("NationalMapMgr Unmarshal json error", "error", err) + os.Exit(0) + } + + //转成服务用的结构 + global.MapWith = m.Width + global.MapHeight = m.Height + + for i, v := range m.List { + t := int8(v[0]) + l := int8(v[1]) + d := model.NationalMap{Y: i / global.MapHeight, X: i % global.MapWith, MId: i, Type: t, Level: l} + this.conf[i] = d + if d.Type == model.MapBuildSysCity || + d.Type == model.MapBuildSysFortress { + this.sysBuild[i] = d + } + } + + slog.Info("sysBuild len", "len", len(this.sysBuild)) + +} + +func (this *NationalMapMgr) IsCanBuild(x, y int) bool { + posIndex := global.ToPosition(x, y) + this.mutex.RLock() + defer this.mutex.RUnlock() + c, ok := this.conf[posIndex] + if ok { + if c.Type == 0 { + return false + } else { + return true + } + } else { + return false + } +} + +func (this *NationalMapMgr) IsCanBuildCity(x, y int) bool { + + //系统城池附近5格不能有玩家城池 + for _, nationalMap := range this.sysBuild { + if nationalMap.Type == model.MapBuildSysCity { + if x >= nationalMap.X-5 && x <= nationalMap.X+5 && + y >= nationalMap.Y-5 && y <= nationalMap.Y+5 { + return false + } + } + } + + for i := x - 2; i <= x+2; i++ { + if i < 0 || i > global.MapWith { + return false + } + + for j := y - 2; j <= y+2; j++ { + if j < 0 || j > global.MapHeight { + return false + } + } + + if this.IsCanBuild(x, y) == false || + RBMgr.IsEmpty(x, y) == false || + RCMgr.IsEmpty(x, y) == false { + return false + } + } + return true +} + +func (this *NationalMapMgr) MapResTypeLevel(x, y int) (bool, int8, int8) { + n, ok := this.PositionBuild(x, y) + if ok { + return true, n.Type, n.Level + } + return false, 0, 0 +} + +func (this *NationalMapMgr) PositionBuild(x, y int) (model.NationalMap, bool) { + posIndex := global.ToPosition(x, y) + this.mutex.RLock() + defer this.mutex.RUnlock() + b, ok := this.conf[posIndex] + return b, ok +} + +func (this *NationalMapMgr) Scan(x, y int) []model.NationalMap { + this.mutex.RLock() + defer this.mutex.RUnlock() + + minX := util.MaxInt(0, x-ScanWith) + maxX := util.MinInt(40, x+ScanWith) + + minY := util.MaxInt(0, y-ScanHeight) + maxY := util.MinInt(40, y+ScanHeight) + + c := (maxX - minX + 1) * (maxY - minY + 1) + r := make([]model.NationalMap, c) + + index := 0 + for i := minX; i <= maxX; i++ { + for j := minY; j <= maxY; j++ { + v, ok := this.conf[global.ToPosition(i, j)] + if ok { + r[index] = v + } + index++ + } + } + return r +} diff --git a/server/slgserver/logic/mgr/role_attribute_mgr.go b/server/slgserver/logic/mgr/role_attribute_mgr.go new file mode 100644 index 0000000..9f97f3f --- /dev/null +++ b/server/slgserver/logic/mgr/role_attribute_mgr.go @@ -0,0 +1,121 @@ +package mgr + +import ( + "log/slog" + "slgserver/db" + "slgserver/server/slgserver/model" + "sync" +) + +type roleAttributeMgr struct { + mutex sync.RWMutex + attribute map[int]*model.RoleAttribute //key:rid +} + +var RAttrMgr = &roleAttributeMgr{ + attribute: make(map[int]*model.RoleAttribute), +} + +func (this*roleAttributeMgr) Load() { + //加载 + t := make(map[int]*model.RoleAttribute) + err := db.MasterDB.Find(t) + if err != nil { + slog.Error("roleAttributeMgr load role_attribute table error", "error", err) + } + + //获取联盟id + for _, v:= range t { + this.attribute[v.RId] = v + } + + l := UnionMgr.List() + for _, c := range l { + for _, rid := range c.MemberArray { + attr, ok := this.attribute[rid] + if ok { + attr.UnionId = c.Id + }else{ + attr := this.create(rid) + if attr != nil{ + attr.UnionId = c.Id + } + } + } + } +} + + +func (this*roleAttributeMgr) Get(rid int) (*model.RoleAttribute, bool){ + + this.mutex.RLock() + r, ok := this.attribute[rid] + this.mutex.RUnlock() + + if ok { + return r, true + }else { + return nil, false + } +} + +func (this*roleAttributeMgr) TryCreate(rid int) (*model.RoleAttribute, bool){ + attr, ok := this.Get(rid) + if ok { + return attr, true + }else{ + this.mutex.Lock() + defer this.mutex.Unlock() + attr := this.create(rid) + return attr, attr != nil + } +} + +func (this*roleAttributeMgr) create(rid int) *model.RoleAttribute { + roleAttr := &model.RoleAttribute{RId: rid, ParentId: 0, UnionId: 0} + if _ , err := db.MasterDB.Insert(roleAttr); err != nil { + slog.Error("insert RoleAttribute error", "error", err) + return nil + }else{ + this.attribute[rid] = roleAttr + return roleAttr + } +} + + +func (this*roleAttributeMgr) IsHasUnion(rid int) bool{ + + this.mutex.RLock() + r, ok := this.attribute[rid] + this.mutex.RUnlock() + + if ok { + return r.UnionId != 0 + }else { + return false + } +} + +func (this*roleAttributeMgr) UnionId(rid int) int{ + + this.mutex.RLock() + r, ok := this.attribute[rid] + this.mutex.RUnlock() + + if ok { + return r.UnionId + }else { + return 0 + } +} + +func (this*roleAttributeMgr) List() []*model.RoleAttribute { + this.mutex.RLock() + defer this.mutex.RUnlock() + ret := make([]*model.RoleAttribute, 0) + for _, attribute := range this.attribute { + ret = append(ret, attribute) + } + return ret +} + diff --git a/server/slgserver/logic/mgr/role_build_mgr.go b/server/slgserver/logic/mgr/role_build_mgr.go new file mode 100644 index 0000000..0a906a1 --- /dev/null +++ b/server/slgserver/logic/mgr/role_build_mgr.go @@ -0,0 +1,436 @@ +package mgr + +import ( + "log/slog" + "slgserver/constant" + "slgserver/db" + "slgserver/server/slgserver/global" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/static_conf" + "slgserver/util" + "sync" + "time" +) + +type roleBuildMgr struct { + baseMutex sync.RWMutex + giveUpMutex sync.RWMutex + destroyMutex sync.RWMutex + dbRB map[int]*model.MapRoleBuild //key:dbId + posRB map[int]*model.MapRoleBuild //key:posId + roleRB map[int][]*model.MapRoleBuild //key:roleId + giveUpRB map[int64]map[int]*model.MapRoleBuild //key:time + destroyRB map[int64]map[int]*model.MapRoleBuild //key:time + +} + +var RBMgr = &roleBuildMgr{ + dbRB: make(map[int]*model.MapRoleBuild), + posRB: make(map[int]*model.MapRoleBuild), + roleRB: make(map[int][]*model.MapRoleBuild), + giveUpRB: make(map[int64]map[int]*model.MapRoleBuild), + destroyRB: make(map[int64]map[int]*model.MapRoleBuild), +} + +func (this *roleBuildMgr) Load() { + + if total, err := db.MasterDB.Where("type = ? or type = ?", + model.MapBuildSysCity, + model.MapBuildSysFortress).Count(new(model.MapRoleBuild)); err != nil { + slog.Error("db error when loading role build", "error", err) + panic("db error: " + err.Error()) + } else { + //初始化系统建筑到数据库 + if int64(len(NMMgr.sysBuild)) != total { + db.MasterDB.Where("type = ? or type = ?", + model.MapBuildSysCity, + model.MapBuildSysFortress).Delete(new(model.MapRoleBuild)) + for _, sysBuild := range NMMgr.sysBuild { + + build := model.MapRoleBuild{ + RId: 0, + Type: sysBuild.Type, + Level: sysBuild.Level, + X: sysBuild.X, + Y: sysBuild.Y, + } + build.Init() + db.MasterDB.InsertOne(&build) + } + } + } + + err := db.MasterDB.Find(this.dbRB) + if err != nil { + slog.Error("roleBuildMgr load role_build table error", "error", err) + } + + curTime := time.Now().Unix() + + //转成posRB 和 roleRB + for _, v := range this.dbRB { + v.Init() + + //恢复正在放弃的土地 + if v.GiveUpTime != 0 { + _, ok := this.giveUpRB[v.GiveUpTime] + if ok == false { + this.giveUpRB[v.GiveUpTime] = make(map[int]*model.MapRoleBuild) + } + this.giveUpRB[v.GiveUpTime][v.Id] = v + } + + //恢复正在拆除的建筑 + if v.OPLevel == 0 && v.Level != v.OPLevel { + t := v.EndTime.Unix() + if curTime >= t { + v.ConvertToRes() + } else { + _, ok := this.destroyRB[t] + if ok == false { + this.destroyRB[t] = make(map[int]*model.MapRoleBuild) + } + this.destroyRB[t][v.Id] = v + } + } + + posId := global.ToPosition(v.X, v.Y) + this.posRB[posId] = v + _, ok := this.roleRB[v.RId] + if ok == false { + this.roleRB[v.RId] = make([]*model.MapRoleBuild, 0) + } + this.roleRB[v.RId] = append(this.roleRB[v.RId], v) + + //过滤掉到了放弃时间的领地 + if v.GiveUpTime != 0 && v.GiveUpTime <= curTime { + this.RemoveFromRole(v) + } + + } + +} + +// 检测正在放弃的土地是否到期了 +func (this *roleBuildMgr) CheckGiveUp() []int { + var ret []int + var builds []*model.MapRoleBuild + + curTime := time.Now().Unix() + this.giveUpMutex.Lock() + for i := curTime - 10; i <= curTime; i++ { + gs, ok := this.giveUpRB[i] + if ok { + for _, g := range gs { + builds = append(builds, g) + ret = append(ret, global.ToPosition(g.X, g.Y)) + } + } + } + this.giveUpMutex.Unlock() + + for _, build := range builds { + this.RemoveFromRole(build) + } + + return ret +} + +// 检测正在拆除的建筑是否到期 +func (this *roleBuildMgr) CheckDestroy() []int { + var ret []int + var builds []*model.MapRoleBuild + + curTime := time.Now().Unix() + this.destroyMutex.Lock() + for i := curTime - 10; i <= curTime; i++ { + gs, ok := this.destroyRB[i] + if ok { + for _, g := range gs { + builds = append(builds, g) + ret = append(ret, global.ToPosition(g.X, g.Y)) + } + } + } + this.destroyMutex.Unlock() + + for _, build := range builds { + build.ConvertToRes() + build.SyncExecute() + } + return ret +} + +/* +该位置是否被角色占领 +*/ +func (this *roleBuildMgr) IsEmpty(x, y int) bool { + this.baseMutex.RLock() + defer this.baseMutex.RUnlock() + posId := global.ToPosition(x, y) + _, ok := this.posRB[posId] + return !ok +} + +func (this *roleBuildMgr) PositionBuild(x, y int) (*model.MapRoleBuild, bool) { + this.baseMutex.RLock() + defer this.baseMutex.RUnlock() + posId := global.ToPosition(x, y) + b, ok := this.posRB[posId] + if ok { + return b, ok + } else { + return nil, false + } +} + +func (this *roleBuildMgr) RoleFortressCnt(rid int) int { + bs, ok := this.GetRoleBuild(rid) + cnt := 0 + if ok == false { + return 0 + } else { + for _, b := range bs { + if b.IsRoleFortress() { + cnt += 1 + } + } + } + return cnt +} + +func (this *roleBuildMgr) AddBuild(rid, x, y int) (*model.MapRoleBuild, bool) { + + posId := global.ToPosition(x, y) + this.baseMutex.Lock() + rb, ok := this.posRB[posId] + this.baseMutex.Unlock() + if ok { + rb.RId = rid + this.baseMutex.Lock() + if _, ok := this.roleRB[rid]; ok == false { + this.roleRB[rid] = make([]*model.MapRoleBuild, 0) + } + this.roleRB[rid] = append(this.roleRB[rid], rb) + this.baseMutex.Unlock() + return rb, true + + } else { + + if b, ok := NMMgr.PositionBuild(x, y); ok { + if cfg, _ := static_conf.MapBuildConf.BuildConfig(b.Type, b.Level); cfg != nil { + rb := &model.MapRoleBuild{ + RId: rid, X: x, Y: y, + Type: b.Type, Level: b.Level, OPLevel: b.Level, + Name: cfg.Name, CurDurable: cfg.Durable, + MaxDurable: cfg.Durable, + } + rb.Init() + + if _, err := db.MasterDB.Table(model.MapRoleBuild{}).Insert(rb); err == nil { + this.baseMutex.Lock() + this.posRB[posId] = rb + this.dbRB[rb.Id] = rb + if _, ok := this.roleRB[rid]; ok == false { + this.roleRB[rid] = make([]*model.MapRoleBuild, 0) + } + this.roleRB[rid] = append(this.roleRB[rid], rb) + this.baseMutex.Unlock() + return rb, true + } else { + slog.Warn("db error", "error", err) + } + } + } + } + return nil, false +} + +func (this *roleBuildMgr) RemoveFromRole(build *model.MapRoleBuild) { + this.baseMutex.Lock() + rb, ok := this.roleRB[build.RId] + if ok { + for i, v := range rb { + if v.Id == build.Id { + this.roleRB[build.RId] = append(rb[:i], rb[i+1:]...) + break + } + } + } + this.baseMutex.Unlock() + + //移除放弃事件 + t := build.GiveUpTime + this.giveUpMutex.Lock() + if ms, ok := this.giveUpRB[t]; ok { + delete(ms, build.Id) + } + this.giveUpMutex.Unlock() + + //移除拆除事件 + t = build.EndTime.Unix() + this.destroyMutex.Lock() + if ms, ok := this.destroyRB[t]; ok { + delete(ms, build.Id) + } + this.destroyMutex.Unlock() + + build.Reset() + build.SyncExecute() +} + +func (this *roleBuildMgr) GetRoleBuild(rid int) ([]*model.MapRoleBuild, bool) { + this.baseMutex.RLock() + defer this.baseMutex.RUnlock() + ra, ok := this.roleRB[rid] + return ra, ok +} + +func (this *roleBuildMgr) BuildCnt(rid int) int { + bs, ok := this.GetRoleBuild(rid) + if ok { + return len(bs) + } else { + return 0 + } +} + +func (this *roleBuildMgr) Scan(x, y int) []*model.MapRoleBuild { + if x < 0 || x >= global.MapWith || y < 0 || y >= global.MapHeight { + return nil + } + + this.baseMutex.RLock() + defer this.baseMutex.RUnlock() + + minX := util.MaxInt(0, x-ScanWith) + maxX := util.MinInt(global.MapWith, x+ScanWith) + minY := util.MaxInt(0, y-ScanHeight) + maxY := util.MinInt(global.MapHeight, y+ScanHeight) + + rb := make([]*model.MapRoleBuild, 0) + for i := minX; i <= maxX; i++ { + for j := minY; j <= maxY; j++ { + posId := global.ToPosition(i, j) + v, ok := this.posRB[posId] + if ok && v.RId != 0 { + rb = append(rb, v) + } + } + } + + return rb +} + +func (this *roleBuildMgr) ScanBlock(x, y, length int) []*model.MapRoleBuild { + if x < 0 || x >= global.MapWith || y < 0 || y >= global.MapHeight { + return nil + } + + this.baseMutex.RLock() + defer this.baseMutex.RUnlock() + + maxX := util.MinInt(global.MapWith, x+length-1) + maxY := util.MinInt(global.MapHeight, y+length-1) + + rb := make([]*model.MapRoleBuild, 0) + for i := x; i <= maxX; i++ { + for j := y; j <= maxY; j++ { + posId := global.ToPosition(i, j) + v, ok := this.posRB[posId] + if ok && (v.RId != 0 || v.IsSysCity() || v.IsSysFortress()) { + rb = append(rb, v) + } + } + } + + return rb +} + +func (this *roleBuildMgr) BuildIsRId(x, y, rid int) bool { + b, ok := this.PositionBuild(x, y) + if ok { + return b.RId == rid + } else { + return false + } +} + +func (this *roleBuildMgr) GetYield(rid int) model.Yield { + builds, ok := this.GetRoleBuild(rid) + var y model.Yield + if ok { + for _, b := range builds { + y.Iron += b.Iron + y.Wood += b.Wood + y.Grain += b.Grain + y.Stone += b.Grain + } + } + return y +} + +func (this *roleBuildMgr) GiveUp(x, y int) int { + b, ok := this.PositionBuild(x, y) + if ok == false { + return constant.CannotGiveUp + } + + if b.IsWarFree() { + return constant.BuildWarFree + } + + if b.GiveUpTime > 0 { + return constant.BuildGiveUpAlready + } + + b.GiveUpTime = time.Now().Unix() + static_conf.Basic.Build.GiveUpTime + b.SyncExecute() + + this.giveUpMutex.Lock() + _, ok = this.giveUpRB[b.GiveUpTime] + if ok == false { + this.giveUpRB[b.GiveUpTime] = make(map[int]*model.MapRoleBuild) + } + this.giveUpRB[b.GiveUpTime][b.Id] = b + this.giveUpMutex.Unlock() + + return constant.OK +} + +func (this *roleBuildMgr) Destroy(x, y int) int { + + b, ok := this.PositionBuild(x, y) + if ok == false { + return constant.BuildNotMe + } + + if b.IsHaveModifyLVAuth() == false || b.IsInGiveUp() || b.IsBusy() { + return constant.CanNotDestroy + } + + cfg, ok := static_conf.MapBCConf.BuildConfig(b.Type, b.Level) + if ok == false { + return constant.InvalidParam + } + + code := RResMgr.TryUseNeed(b.RId, cfg.Need) + if code != constant.OK { + return code + } + + b.EndTime = time.Now().Add(time.Duration(cfg.Time) * time.Second) + this.destroyMutex.Lock() + t := b.EndTime.Unix() + _, ok = this.destroyRB[t] + if ok == false { + this.destroyRB[t] = make(map[int]*model.MapRoleBuild) + } + this.destroyRB[t][b.Id] = b + this.destroyMutex.Unlock() + + b.DelBuild(*cfg) + b.SyncExecute() + + return constant.OK +} diff --git a/server/slgserver/logic/mgr/role_city_mgr.go b/server/slgserver/logic/mgr/role_city_mgr.go new file mode 100644 index 0000000..1abf5db --- /dev/null +++ b/server/slgserver/logic/mgr/role_city_mgr.go @@ -0,0 +1,204 @@ +package mgr + +import ( + "log/slog" + "slgserver/db" + "slgserver/server/slgserver/global" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/static_conf" + "slgserver/util" + "sync" + "time" +) + + +type roleCityMgr struct { + mutex sync.RWMutex + dbCity map[int]*model.MapRoleCity //key: cid + posCity map[int]*model.MapRoleCity //key: pos + roleCity map[int][]*model.MapRoleCity //key: rid +} + +var RCMgr = &roleCityMgr{ + dbCity: make(map[int]*model.MapRoleCity), + posCity: make(map[int]*model.MapRoleCity), + roleCity: make(map[int][]*model.MapRoleCity), +} + +func GetCityCost(cid int) int8 { + return RFMgr.GetCost(cid) + static_conf.Basic.City.Cost +} + +func GetMaxDurable(cid int) int { + return RFMgr.GetMaxDurable(cid) + static_conf.Basic.City.Durable +} + +func GetCityLV(cid int) int8 { + return RFMgr.GetCityLV(cid) +} + +func (this*roleCityMgr) Load() { + + err := db.MasterDB.Find(this.dbCity) + if err != nil { + slog.Error("roleCityMgr load role_city table error") + } + + //转成posCity、roleCity + for _, v := range this.dbCity { + posId := global.ToPosition(v.X, v.Y) + this.posCity[posId] = v + _, ok := this.roleCity[v.RId] + if ok == false{ + this.roleCity[v.RId] = make([]*model.MapRoleCity, 0) + } + this.roleCity[v.RId] = append(this.roleCity[v.RId], v) + } + + go this.running() +} + +func (this*roleCityMgr) running() { + for true { + t := static_conf.Basic.City.RecoveryTime + time.Sleep(time.Duration(t) * time.Second) + this.mutex.RLock() + for _, city := range this.dbCity { + if city.CurDurable < GetMaxDurable(city.CityId){ + city.DurableChange(100) + city.SyncExecute() + } + } + this.mutex.RUnlock() + } +} + +/* +该位置是否被角色建立城池 +*/ +func (this*roleCityMgr) IsEmpty(x, y int) bool { + this.mutex.RLock() + defer this.mutex.RUnlock() + posId := global.ToPosition(x, y) + _, ok := this.posCity[posId] + return !ok +} + +func (this*roleCityMgr) PositionCity(x, y int) (*model.MapRoleCity, bool) { + this.mutex.RLock() + defer this.mutex.RUnlock() + posId := global.ToPosition(x, y) + c,ok := this.posCity[posId] + return c, ok +} + +func (this*roleCityMgr) Add(city *model.MapRoleCity) { + + this.mutex.Lock() + defer this.mutex.Unlock() + this.dbCity[city.CityId] = city + this.posCity[global.ToPosition(city.X, city.Y)] = city + + _, ok := this.roleCity[city.RId] + if ok == false{ + this.roleCity[city.RId] = make([]*model.MapRoleCity, 0) + } + this.roleCity[city.RId] = append(this.roleCity[city.RId], city) +} + +func (this*roleCityMgr) Scan(x, y int) []*model.MapRoleCity { + if x < 0 || x >= global.MapWith || y < 0 || y >= global.MapHeight { + return nil + } + + this.mutex.RLock() + defer this.mutex.RUnlock() + + minX := util.MaxInt(0, x-ScanWith) + maxX := util.MinInt(40, x+ScanWith) + minY := util.MaxInt(0, y-ScanHeight) + maxY := util.MinInt(40, y+ScanHeight) + + cb := make([]*model.MapRoleCity, 0) + for i := minX; i <= maxX; i++ { + for j := minY; j <= maxY; j++ { + posId := global.ToPosition(i, j) + v, ok := this.posCity[posId] + if ok { + cb = append(cb, v) + } + } + } + return cb +} + +func (this*roleCityMgr) ScanBlock(x, y, length int) []*model.MapRoleCity { + if x < 0 || x >= global.MapWith || y < 0 || y >= global.MapHeight { + return nil + } + + this.mutex.RLock() + defer this.mutex.RUnlock() + + maxX := util.MinInt(global.MapWith, x+length-1) + maxY := util.MinInt(global.MapHeight, y+length-1) + + cb := make([]*model.MapRoleCity, 0) + for i := x; i <= maxX; i++ { + for j := y; j <= maxY; j++ { + posId := global.ToPosition(i, j) + v, ok := this.posCity[posId] + if ok { + cb = append(cb, v) + } + } + } + return cb +} + +func (this*roleCityMgr) GetByRId(rid int) ([]*model.MapRoleCity, bool){ + this.mutex.RLock() + r, ok := this.roleCity[rid] + this.mutex.RUnlock() + return r, ok +} + +func (this*roleCityMgr) GetMainCity(rid int) (*model.MapRoleCity, bool){ + citys, ok := this.GetByRId(rid) + if ok == false { + return nil, false + }else{ + for _, city := range citys { + if city.IsMain == 1{ + return city, true + } + } + } + return nil, false +} + +func (this*roleCityMgr) Get(cid int) (*model.MapRoleCity, bool){ + this.mutex.RLock() + r, ok := this.dbCity[cid] + this.mutex.RUnlock() + + if ok { + return r, true + } + + + r = &model.MapRoleCity{} + ok, err := db.MasterDB.Table(r).Where("cityId=?", cid).Get(r) + if err != nil{ + slog.Warn("db error", "error", err) + } + + if ok { + this.mutex.Lock() + this.dbCity[cid] = r + this.mutex.Unlock() + return r, true + }else{ + return nil, false + } +} diff --git a/server/slgserver/logic/mgr/role_mgr.go b/server/slgserver/logic/mgr/role_mgr.go new file mode 100644 index 0000000..fd1bbad --- /dev/null +++ b/server/slgserver/logic/mgr/role_mgr.go @@ -0,0 +1,48 @@ +package mgr + +import ( + "log/slog" + "slgserver/db" + "slgserver/server/slgserver/model" + "sync" +) + +func RoleNickName(rid int) string { + vRole, ok := RMgr.Get(rid) + if ok { + return vRole.NickName + } + return "" +} + +type roleMgr struct { + mutex sync.RWMutex + roles map[int]*model.Role +} + +var RMgr = &roleMgr{ + roles: make(map[int]*model.Role), +} + +func (this*roleMgr) Get(rid int) (*model.Role, bool){ + this.mutex.RLock() + r, ok := this.roles[rid] + this.mutex.RUnlock() + + if ok { + return r, true + } + + m := &model.Role{} + ok, err := db.MasterDB.Table(new(model.Role)).Where("rid=?", rid).Get(m) + if ok { + this.mutex.Lock() + this.roles[rid] = m + this.mutex.Unlock() + return m, true + }else{ + slog.Warn("db error", "error", err, "rid", rid) + return nil, false + } +} + diff --git a/server/slgserver/logic/mgr/role_res_mgr.go b/server/slgserver/logic/mgr/role_res_mgr.go new file mode 100644 index 0000000..2171c3f --- /dev/null +++ b/server/slgserver/logic/mgr/role_res_mgr.go @@ -0,0 +1,248 @@ +package mgr + +import ( + "log/slog" + "slgserver/constant" + "slgserver/db" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/static_conf" + "slgserver/server/slgserver/static_conf/facility" + "slgserver/util" + "sync" + "time" +) + +type roleResMgr struct { + mutex sync.RWMutex + rolesRes map[int]*model.RoleRes +} + +var RResMgr = &roleResMgr{ + rolesRes: make(map[int]*model.RoleRes), +} + +//获取产量 +func GetYield(rid int) model.Yield { + by := RBMgr.GetYield(rid) + cy := RFMgr.GetYield(rid) + var y model.Yield + + y.Gold = by.Gold + cy.Gold + static_conf.Basic.Role.GoldYield + y.Stone = by.Stone + cy.Stone + static_conf.Basic.Role.StoneYield + y.Iron = by.Iron + cy.Iron + static_conf.Basic.Role.IronYield + y.Grain = by.Grain + cy.Grain + static_conf.Basic.Role.GrainYield + y.Wood = by.Wood + cy.Wood + static_conf.Basic.Role.WoodYield + + return y +} + +//获取仓库容量 +func GetDepotCapacity(rid int) int { + return RFMgr.GetDepotCapacity(rid) + static_conf.Basic.Role.DepotCapacity +} + +func (this*roleResMgr) Load() { + + rr := make([]*model.RoleRes, 0) + err := db.MasterDB.Find(&rr) + if err != nil { + slog.Error("roleResMgr load role_res table error") + } + + for _, v := range rr { + this.rolesRes[v.RId] = v + } + + go this.produce() + +} + + +func (this*roleResMgr) Get(rid int) (*model.RoleRes, bool){ + + this.mutex.RLock() + r, ok := this.rolesRes[rid] + this.mutex.RUnlock() + + if ok { + return r, true + } + + m := &model.RoleRes{} + ok, err := db.MasterDB.Table(new(model.RoleRes)).Where("rid=?", rid).Get(m) + if ok { + + this.mutex.Lock() + this.rolesRes[rid] = m + this.mutex.Unlock() + + return m, true + }else{ + if err == nil{ + slog.Warn("RoleRes not found", "rid", rid) + return nil, false + }else{ + slog.Warn("db error", "error", err) + return nil, false + } + } +} + +func (this*roleResMgr) Add(res *model.RoleRes) (){ + + this.mutex.Lock() + this.rolesRes[res.RId] = res + this.mutex.Unlock() +} + +func (this*roleResMgr) TryUseNeed(rid int, need facility.NeedRes) int{ + + this.mutex.RLock() + rr, ok := this.rolesRes[rid] + this.mutex.RUnlock() + + if ok { + if need.Decree <= rr.Decree && need.Grain <= rr.Grain && + need.Stone <= rr.Stone && need.Wood <= rr.Wood && + need.Iron <= rr.Iron && need.Gold <= rr.Gold { + rr.Decree -= need.Decree + rr.Iron -= need.Iron + rr.Wood -= need.Wood + rr.Stone -= need.Stone + rr.Grain -= need.Grain + rr.Gold -= need.Gold + + rr.SyncExecute() + return constant.OK + }else{ + if need.Decree > rr.Decree{ + return constant.DecreeNotEnough + }else{ + return constant.ResNotEnough + } + } + }else { + return constant.RoleNotExist + } +} + +//政令是否足够 +func (this*roleResMgr) DecreeIsEnough(rid int, cost int) bool { + + this.mutex.RLock() + rr, ok := this.rolesRes[rid] + this.mutex.RUnlock() + + if ok { + if rr.Decree >= cost { + return true + }else{ + return false + } + }else{ + return false + } +} + +func (this*roleResMgr) TryUseDecree(rid int, decree int) bool{ + + this.mutex.RLock() + rr, ok := this.rolesRes[rid] + this.mutex.RUnlock() + + if ok { + if rr.Decree >= decree { + rr.Decree -= decree + rr.SyncExecute() + return true + }else{ + return false + } + }else{ + return false + } +} + + + +//金币是否足够 +func (this*roleResMgr) GoldIsEnough(rid int, cost int) bool { + + this.mutex.RLock() + rr, ok := this.rolesRes[rid] + this.mutex.RUnlock() + + if ok { + if rr.Gold >= cost { + return true + }else{ + return false + } + }else{ + return false + } +} + + +func (this*roleResMgr) TryUseGold(rid int, gold int) bool{ + + this.mutex.RLock() + rr, ok := this.rolesRes[rid] + this.mutex.RUnlock() + + if ok { + if rr.Gold >= gold { + rr.Gold -= gold + rr.SyncExecute() + return true + }else{ + return false + } + }else{ + return false + } +} + + +func (this*roleResMgr) produce() { + index := 1 + for true { + t := static_conf.Basic.Role.RecoveryTime + time.Sleep(time.Duration(t) * time.Second) + this.mutex.RLock() + for _, v := range this.rolesRes { + //加判断是因为爆仓了,资源不无故减少 + capacity := GetDepotCapacity(v.RId) + yield := GetYield(v.RId) + if v.Wood < capacity{ + v.Wood += util.MinInt(yield.Wood/6, capacity) + } + + if v.Iron < capacity{ + v.Iron += util.MinInt(yield.Iron/6, capacity) + } + + if v.Stone < capacity{ + v.Stone += util.MinInt(yield.Stone/6, capacity) + } + + if v.Grain < capacity{ + v.Grain += util.MinInt(yield.Grain/6, capacity) + } + + if v.Gold < capacity{ + v.Grain += util.MinInt(yield.Grain/6, capacity) + } + + if index%6 == 0{ + if v.Decree < static_conf.Basic.Role.DecreeLimit{ + v.Decree+=1 + } + } + v.SyncExecute() + } + index++ + this.mutex.RUnlock() + } +} + diff --git a/server/slgserver/logic/mgr/skill_mgr.go b/server/slgserver/logic/mgr/skill_mgr.go new file mode 100644 index 0000000..2cee978 --- /dev/null +++ b/server/slgserver/logic/mgr/skill_mgr.go @@ -0,0 +1,97 @@ +package mgr + +import ( + "log/slog" + "slgserver/db" + "slgserver/server/slgserver/model" + "sync" +) + +type skillMgr struct { + mutex sync.RWMutex + skillMap map[int][]*model.Skill +} + +var SkillMgr = &skillMgr{ + skillMap: make(map[int][]*model.Skill), +} + + +func (this*skillMgr) Load() { + + rr := make([]*model.Skill, 0) + err := db.MasterDB.Find(&rr) + if err != nil { + slog.Error("skillMgr load role_res table error") + } + + for _, v := range rr { + if this.skillMap[v.RId] == nil{ + this.skillMap[v.RId] = make([]*model.Skill, 0) + } + this.skillMap[v.RId] = append(this.skillMap[v.RId], v) + } +} + + +func (this*skillMgr) Get(rid int) ([]*model.Skill, bool){ + + this.mutex.RLock() + r, ok := this.skillMap[rid] + this.mutex.RUnlock() + + if ok { + return r, true + } + + m := make([]*model.Skill, 0) + ok, err := db.MasterDB.Table(new(model.Skill)).Where("rid=?", rid).Get(&m) + if ok { + + this.mutex.Lock() + this.skillMap[rid] = m + this.mutex.Unlock() + + return m, true + }else{ + if err == nil{ + slog.Warn("skill not found", "rid", rid) + return nil, false + }else{ + slog.Warn("db error", "error", err) + return nil, false + } + } +} + +func (this*skillMgr) GetSkillOrCreate(rid int, cfg int) (*model.Skill, bool){ + + success := true + m, ok := this.Get(rid) + var ret *model.Skill = nil + if ok { + for _, v := range m { + if v.CfgId != cfg{ + continue + }else{ + ret = v + } + } + } + + if ret == nil { + ret = model.NewSkill(rid, cfg) + _, err := db.MasterDB.InsertOne(ret) + if err != nil { + slog.Warn("db error", "error", err) + success = false + }else{ + if this.skillMap[rid] == nil{ + this.skillMap[rid] = make([]*model.Skill, 0) + } + this.skillMap[rid] = append(this.skillMap[rid], ret) + } + } + return ret, success + +} diff --git a/server/slgserver/logic/sys_army_logic.go b/server/slgserver/logic/sys_army_logic.go new file mode 100644 index 0000000..b0cf0a2 --- /dev/null +++ b/server/slgserver/logic/sys_army_logic.go @@ -0,0 +1,95 @@ +package logic + +import ( + "slgserver/server/slgserver/global" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/static_conf" + "sync" +) + + +func NewSysArmy() *sysArmyLogic { + return &sysArmyLogic{ + sysArmys: make(map[int][]*model.Army), + } +} + +type sysArmyLogic struct { + mutex sync.Mutex + sysArmys map[int][]*model.Army //key:posId 系统建筑军队 +} + +func (this* sysArmyLogic) getArmyCfg(x, y int) (star int8, lv int8, soilders int) { + defender := 1 + star = 3 + lv = 5 + soilders = 100 + + if mapBuild, ok := mgr.NMMgr.PositionBuild(x, y); ok{ + cfg, ok := static_conf.MapBuildConf.BuildConfig(mapBuild.Type, mapBuild.Level) + if ok { + defender = cfg.Defender + if npc, ok := static_conf.Basic.GetNPC(cfg.Level); ok { + soilders = npc.Soilders + } + } + } + + if defender == 1{ + star = 3 + lv = 5 + }else if defender == 2{ + star = 4 + lv = 10 + }else { + star = 5 + lv = 20 + } + + return star, lv, soilders +} + +func (this *sysArmyLogic) GetArmy(x, y int) []*model.Army { + posId := global.ToPosition(x, y) + this.mutex.Lock() + a, ok := this.sysArmys[posId] + this.mutex.Unlock() + if ok { + return a + }else{ + armys := make([]*model.Army, 0) + + star, lv, soilders := this.getArmyCfg(x, y) + out, ok := mgr.GMgr.GetNPCGenerals(3, star, lv) + if ok { + gsId := make([]int, 0) + gs := make([]*model.General, 3) + + for i := 0; i < len(out) ; i++ { + gs[i] = &out[i] + } + + scnt := []int{soilders, soilders, soilders} + army := &model.Army{RId: 0, Order: 0, CityId: 0, + GeneralArray: gsId, Gens: gs, SoldierArray: scnt} + army.ToGeneral() + army.ToSoldier() + + armys = append(armys, army) + posId := global.ToPosition(x, y) + this.sysArmys[posId] = armys + } + + return armys + } +} + +func (this *sysArmyLogic) DelArmy(x, y int) { + this.mutex.Lock() + defer this.mutex.Unlock() + posId := global.ToPosition(x, y) + delete(this.sysArmys, posId) +} + + diff --git a/server/slgserver/logic/view.go b/server/slgserver/logic/view.go new file mode 100644 index 0000000..7772ed8 --- /dev/null +++ b/server/slgserver/logic/view.go @@ -0,0 +1,36 @@ +package logic + +import ( + "slgserver/server/slgserver/global" + "slgserver/server/slgserver/logic/mgr" + "slgserver/util" +) + +var ViewWidth = 5 +var ViewHeight = 5 + +//是否在视野范围内 +func armyIsInView(rid, x, y int) bool { + unionId := getUnionId(rid) + for i := util.MaxInt(x-ViewWidth, 0); i < util.MinInt(x+ViewWidth, global.MapWith) ; i++ { + for j := util.MaxInt(y-ViewHeight, 0); j < util.MinInt(y+ViewHeight, global.MapHeight) ; j++ { + build, ok := mgr.RBMgr.PositionBuild(i, j) + if ok { + tUnionId := getUnionId(build.RId) + if (tUnionId != 0 && unionId == tUnionId) || build.RId == rid{ + return true + } + } + + city, ok := mgr.RCMgr.PositionCity(i, j) + if ok { + tUnionId := getUnionId(city.RId) + if (tUnionId != 0 && unionId == tUnionId) || city.RId == rid{ + return true + } + } + } + } + + return false +} \ No newline at end of file diff --git a/server/slgserver/model/army.go b/server/slgserver/model/army.go new file mode 100644 index 0000000..0238f66 --- /dev/null +++ b/server/slgserver/model/army.go @@ -0,0 +1,338 @@ +package model + +import ( + "encoding/json" + "fmt" + "log/slog" + "slgserver/db" + "slgserver/net" + "slgserver/server/slgserver/global" + "slgserver/server/slgserver/proto" + "slgserver/util" + "time" + "xorm.io/xorm" +) + +const ( + ArmyCmdIdle = 0 //空闲 + ArmyCmdAttack = 1 //攻击 + ArmyCmdDefend = 2 //驻守 + ArmyCmdReclamation = 3 //屯垦 + ArmyCmdBack = 4 //撤退 + ArmyCmdConscript = 5 //征兵 + ArmyCmdTransfer = 6 //调动 +) + +const ( + ArmyStop = 0 + ArmyRunning = 1 +) + +/*******db 操作begin********/ +var dbArmyMgr *armyDBMgr + +func init() { + dbArmyMgr = &armyDBMgr{armys: make(chan *Army, 100)} + go dbArmyMgr.running() +} + +type armyDBMgr struct { + armys chan *Army +} + +func (this *armyDBMgr) running() { + for true { + select { + case army := <-this.armys: + if army.Id > 0 { + _, err := db.MasterDB.Table(army).ID(army.Id).Cols( + "soldiers", "generals", "conscript_times", + "conscript_cnts", "cmd", "from_x", "from_y", "to_x", + "to_y", "start", "end").Update(army) + if err != nil { + slog.Warn("db error", "error", err) + } + } else { + slog.Warn("update army fail, because id <= 0") + } + } + } +} + +func (this *armyDBMgr) push(army *Army) { + this.armys <- army +} + +/*******db 操作end********/ + +// 军队 +type Army struct { + Id int `xorm:"id pk autoincr"` + RId int `xorm:"rid"` + CityId int `xorm:"cityId"` + Order int8 `xorm:"order"` + Generals string `xorm:"generals"` + Soldiers string `xorm:"soldiers"` + ConscriptTimes string `xorm:"conscript_times"` //征兵结束时间,json数组 + ConscriptCnts string `xorm:"conscript_cnts"` //征兵数量,json数组 + Cmd int8 `xorm:"cmd"` + FromX int `xorm:"from_x"` + FromY int `xorm:"from_y"` + ToX int `xorm:"to_x"` + ToY int `xorm:"to_y"` + Start time.Time `json:"-"xorm:"start"` + End time.Time `json:"-"xorm:"end"` + State int8 `xorm:"-"` //状态:0:running,1:stop + GeneralArray []int `json:"-" xorm:"-"` + SoldierArray []int `json:"-" xorm:"-"` + ConscriptTimeArray []int64 `json:"-" xorm:"-"` + ConscriptCntArray []int `json:"-" xorm:"-"` + Gens []*General `json:"-" xorm:"-"` + CellX int `json:"-" xorm:"-"` + CellY int `json:"-" xorm:"-"` +} + +func (this *Army) TableName() string { + return "tb_army" + fmt.Sprintf("_%d", ServerId) +} + +// 是否能出战 +func (this *Army) IsCanOutWar() bool { + return this.Gens[0] != nil && this.Cmd == ArmyCmdIdle +} + +func (this *Army) AfterSet(name string, cell xorm.Cell) { + if name == "generals" { + this.GeneralArray = []int{0, 0, 0} + if cell != nil { + gs, ok := (*cell).([]uint8) + if ok { + json.Unmarshal(gs, &this.GeneralArray) + slog.Debug("army generals loaded", "array", this.GeneralArray) + } + } + } else if name == "soldiers" { + this.SoldierArray = []int{0, 0, 0} + if cell != nil { + ss, ok := (*cell).([]uint8) + if ok { + json.Unmarshal(ss, &this.SoldierArray) + slog.Debug("army soldiers loaded", "array", this.SoldierArray) + } + } + } else if name == "conscript_times" { + this.ConscriptTimeArray = []int64{0, 0, 0} + if cell != nil { + ss, ok := (*cell).([]uint8) + if ok { + json.Unmarshal(ss, &this.ConscriptTimeArray) + slog.Debug("army conscript times loaded", "array", this.ConscriptTimeArray) + } + } + } else if name == "conscript_cnts" { + this.ConscriptCntArray = []int{0, 0, 0} + if cell != nil { + ss, ok := (*cell).([]uint8) + if ok { + json.Unmarshal(ss, &this.ConscriptCntArray) + slog.Debug("army conscript counts loaded", "array", this.ConscriptCntArray) + } + } + } +} + +func (this *Army) beforeModify() { + data, _ := json.Marshal(this.GeneralArray) + this.Generals = string(data) + + data, _ = json.Marshal(this.SoldierArray) + this.Soldiers = string(data) + + data, _ = json.Marshal(this.ConscriptTimeArray) + this.ConscriptTimes = string(data) + + data, _ = json.Marshal(this.ConscriptCntArray) + this.ConscriptCnts = string(data) +} + +func (this *Army) BeforeInsert() { + this.beforeModify() +} + +func (this *Army) BeforeUpdate() { + this.beforeModify() +} + +func (this *Army) ToSoldier() { + if this.SoldierArray != nil { + data, _ := json.Marshal(this.SoldierArray) + this.Soldiers = string(data) + } +} + +func (this *Army) ToGeneral() { + if this.GeneralArray != nil { + data, _ := json.Marshal(this.GeneralArray) + this.Generals = string(data) + } +} + +// 获取军队阵营 +func (this *Army) GetCamp() int8 { + var camp int8 = 0 + for _, g := range this.Gens { + if g == nil { + return 0 + } + if camp == 0 { + camp = g.GetCamp() + } else { + if camp != g.GetCamp() { + return 0 + } + } + } + return camp +} + +// 检测征兵是否完成,服务器不做定时任务,用到的时候再检测 +func (this *Army) CheckConscript() { + if this.Cmd == ArmyCmdConscript { + curTime := time.Now().Unix() + finish := true + for i, endTime := range this.ConscriptTimeArray { + if endTime > 0 { + if endTime <= curTime { + this.SoldierArray[i] += this.ConscriptCntArray[i] + this.ConscriptCntArray[i] = 0 + this.ConscriptTimeArray[i] = 0 + } else { + finish = false + } + } + } + + if finish { + this.Cmd = ArmyCmdIdle + } + } +} + +// 队伍指定的位置是否能变化(上下阵) +func (this *Army) PositionCanModify(position int) bool { + if position >= 3 || position < 0 { + return false + } + + if this.Cmd == ArmyCmdIdle { + return true + } else if this.Cmd == ArmyCmdConscript { + endTime := this.ConscriptTimeArray[position] + return endTime == 0 + } else { + return false + } +} + +func (this *Army) ClearConscript() { + if this.Cmd == ArmyCmdConscript { + for i, _ := range this.ConscriptTimeArray { + this.ConscriptCntArray[i] = 0 + this.ConscriptTimeArray[i] = 0 + } + this.Cmd = ArmyCmdIdle + } +} + +func (this *Army) IsIdle() bool { + return this.Cmd == ArmyCmdIdle +} + +/* 推送同步 begin */ +func (this *Army) IsCellView() bool { + return true +} + +func (this *Army) IsCanView(rid, x, y int) bool { + if ArmyIsInView != nil { + return ArmyIsInView(rid, x, y) + } + return false +} + +func (this *Army) BelongToRId() []int { + return []int{this.RId} +} + +func (this *Army) PushMsgName() string { + return "army.push" +} + +func (this *Army) Position() (int, int) { + diffTime := this.End.Unix() - this.Start.Unix() + passTime := time.Now().Unix() - this.Start.Unix() + rate := float32(passTime) / float32(diffTime) + x := 0 + y := 0 + if this.Cmd == ArmyCmdBack { + diffX := this.FromX - this.ToX + diffY := this.FromY - this.ToY + x = int(rate*float32(diffX)) + this.ToX + y = int(rate*float32(diffY)) + this.ToY + } else { + diffX := this.ToX - this.FromX + diffY := this.ToY - this.FromY + x = int(rate*float32(diffX)) + this.FromX + y = int(rate*float32(diffY)) + this.FromY + } + + x = util.MinInt(util.MaxInt(x, 0), global.MapWith) + y = util.MinInt(util.MaxInt(y, 0), global.MapHeight) + slog.Info("army Position:", "x", x, "y", y) + return x, y +} + +func (this *Army) TPosition() (int, int) { + return this.ToX, this.ToY +} + +func (this *Army) ToProto() interface{} { + + p := proto.Army{} + p.CityId = this.CityId + p.Id = this.Id + p.UnionId = GetUnionId(this.RId) + p.Order = this.Order + p.Generals = this.GeneralArray + p.Soldiers = this.SoldierArray + p.ConTimes = this.ConscriptTimeArray + p.ConCnts = this.ConscriptCntArray + p.Cmd = this.Cmd + p.State = this.State + p.FromX = this.FromX + p.FromY = this.FromY + p.ToX = this.ToX + p.ToY = this.ToY + p.Start = this.Start.Unix() + p.End = this.End.Unix() + return p +} + +func (this *Army) Push() { + net.ConnMgr.Push(this) +} + +/* 推送同步 end */ + +func (this *Army) SyncExecute() { + dbArmyMgr.push(this) + this.Push() + this.CellX, this.CellY = this.Position() +} + +func (this *Army) CheckSyncCell() { + x, y := this.Position() + if x != this.CellX || y != this.CellY { + this.SyncExecute() + } +} diff --git a/server/slgserver/model/city_facility.go b/server/slgserver/model/city_facility.go new file mode 100644 index 0000000..fc38fa6 --- /dev/null +++ b/server/slgserver/model/city_facility.go @@ -0,0 +1,90 @@ +package model + +import ( + "encoding/json" + "fmt" + "log/slog" + "slgserver/db" + "slgserver/server/slgserver/static_conf/facility" + "time" +) + +/*******db 操作begin********/ +var dbCFMgr *cfDBMgr +func init() { + dbCFMgr = &cfDBMgr{cs: make(chan *CityFacility, 100)} + go dbCFMgr.running() +} + +type cfDBMgr struct { + cs chan *CityFacility +} + +func (this*cfDBMgr) running() { + for true { + select { + case c := <- this.cs: + if c.Id >0 { + _, err := db.MasterDB.Table(c).ID(c.Id).Cols("facilities").Update(c) + if err != nil{ + slog.Warn("db error", "error", err) + } + }else{ + slog.Warn("update CityFacility fail, because id <= 0") + } + } + } +} + +func (this*cfDBMgr) push(c *CityFacility) { + this.cs <- c +} +/*******db 操作end********/ + + +type Facility struct { + Name string `json:"name"` + PrivateLevel int8 `json:"level"` //等级,外部读的时候不能直接读,要用GetLevel + Type int8 `json:"type"` + UpTime int64 `json:"up_time"` //升级的时间戳,0表示该等级已经升级完成了 +} + +//升级这里做成被动触发产生,不做定时 +func (this* Facility) GetLevel() int8 { + if this.UpTime > 0{ + cur := time.Now().Unix() + cost := facility.FConf.CostTime(this.Type, this.PrivateLevel+1) + if cur >= this.UpTime + int64(cost){ + this.PrivateLevel +=1 + this.UpTime = 0 + } + } + return this.PrivateLevel +} + +func (this* Facility) CanLV() bool { + this.GetLevel() + return this.UpTime == 0 +} + +type CityFacility struct { + Id int `xorm:"id pk autoincr"` + RId int `xorm:"rid"` + CityId int `xorm:"cityId"` + Facilities string `xorm:"facilities"` +} + +func (this *CityFacility) TableName() string { + return "tb_city_facility" + fmt.Sprintf("_%d", ServerId) +} + + +func (this *CityFacility) SyncExecute() { + dbCFMgr.push(this) +} + +func (this*CityFacility) Facility()[]Facility { + facilities := make([]Facility, 0) + json.Unmarshal([]byte(this.Facilities), &facilities) + return facilities +} \ No newline at end of file diff --git a/server/slgserver/model/coalition.go b/server/slgserver/model/coalition.go new file mode 100644 index 0000000..951c290 --- /dev/null +++ b/server/slgserver/model/coalition.go @@ -0,0 +1,323 @@ +package model + +import ( + "encoding/json" + "fmt" + "log/slog" + "slgserver/db" + "slgserver/net" + "slgserver/server/slgserver/proto" + "time" + "xorm.io/xorm" +) + +const ( + UnionDismiss = 0 //解散 + UnionRunning = 1 //运行中 +) + +/*******db 操作begin********/ +var dbCoalitionMgr *coalitionDBMgr + +func init() { + dbCoalitionMgr = &coalitionDBMgr{coalitions: make(chan *Coalition, 100)} + go dbCoalitionMgr.running() +} + +type coalitionDBMgr struct { + coalitions chan *Coalition +} + +func (this *coalitionDBMgr) running() { + for true { + select { + case coalition := <-this.coalitions: + if coalition.Id > 0 { + _, err := db.MasterDB.Table(coalition).ID(coalition.Id).Cols("name", + "members", "chairman", "vice_chairman", "notice", "state").Update(coalition) + if err != nil { + slog.Warn("db error", "error", err) + } + } else { + slog.Warn("update coalition fail, because id <= 0") + } + } + } +} + +func (this *coalitionDBMgr) push(coalition *Coalition) { + this.coalitions <- coalition +} + +/*******db 操作end********/ + +type Coalition struct { + Id int `xorm:"id pk autoincr"` + Name string `xorm:"name"` + Members string `xorm:"members"` + MemberArray []int `xorm:"-"` + CreateId int `xorm:"create_id"` + Chairman int `xorm:"chairman"` + ViceChairman int `xorm:"vice_chairman"` + Notice string `xorm:"notice"` + State int8 `xorm:"state"` + Ctime time.Time `xorm:"ctime"` +} + +func (this *Coalition) ToProto() interface{} { + p := proto.Union{} + + p.Id = this.Id + p.Name = this.Name + p.Notice = this.Notice + p.Cnt = this.Cnt() + + return p +} + +func (this *Coalition) TableName() string { + return "tb_coalition" + fmt.Sprintf("_%d", ServerId) +} + +func (this *Coalition) AfterSet(name string, cell xorm.Cell) { + if name == "members" { + if cell != nil { + ss, ok := (*cell).([]uint8) + if ok { + json.Unmarshal(ss, &this.MemberArray) + } + if this.MemberArray == nil { + this.MemberArray = []int{} + slog.Debug("coalition members loaded", "members", this.MemberArray) + } + } + } +} + +func (this *Coalition) BeforeInsert() { + data, _ := json.Marshal(this.MemberArray) + this.Members = string(data) +} + +func (this *Coalition) BeforeUpdate() { + data, _ := json.Marshal(this.MemberArray) + this.Members = string(data) +} + +func (this *Coalition) Cnt() int { + return len(this.MemberArray) +} + +func (this *Coalition) SyncExecute() { + dbCoalitionMgr.push(this) +} + +type CoalitionApply struct { + Id int `xorm:"id pk autoincr"` + UnionId int `xorm:"union_id"` + RId int `xorm:"rid"` + State int8 `xorm:"state"` + Ctime time.Time `xorm:"ctime"` +} + +func (this *CoalitionApply) TableName() string { + return "tb_coalition_apply" + fmt.Sprintf("_%d", ServerId) +} + +/* 推送同步 begin */ +func (this *CoalitionApply) IsCellView() bool { + return false +} + +func (this *CoalitionApply) IsCanView(rid, x, y int) bool { + return false +} + +func (this *CoalitionApply) BelongToRId() []int { + r := GetMainMembers(this.UnionId) + return append(r, this.RId) +} + +func (this *CoalitionApply) PushMsgName() string { + return "unionApply.push" +} + +func (this *CoalitionApply) Position() (int, int) { + return -1, -1 +} + +func (this *CoalitionApply) TPosition() (int, int) { + return -1, -1 +} + +func (this *CoalitionApply) ToProto() interface{} { + p := proto.ApplyItem{} + p.RId = this.RId + p.Id = this.Id + p.NickName = GetRoleNickName(this.RId) + return p +} + +func (this *CoalitionApply) Push() { + net.ConnMgr.Push(this) +} + +/* 推送同步 end */ + +func (this *CoalitionApply) SyncExecute() { + this.Push() +} + +const ( + UnionOpCreate = 0 //创建 + UnionOpDismiss = 1 //解散 + UnionOpJoin = 2 //加入 + UnionOpExit = 3 //退出 + UnionOpKick = 4 //踢出 + UnionOpAppoint = 5 //任命 + UnionOpAbdicate = 6 //禅让 + UnionOpModNotice = 7 //修改公告 +) + +type CoalitionLog struct { + Id int `xorm:"id pk autoincr"` + UnionId int `xorm:"union_id"` + OPRId int `xorm:"op_rid"` + TargetId int `xorm:"target_id"` + State int8 `xorm:"state"` + Des string `xorm:"des"` + Ctime time.Time `xorm:"ctime"` +} + +func (this *CoalitionLog) TableName() string { + return "tb_coalition_log" + fmt.Sprintf("_%d", ServerId) +} + +func (this *CoalitionLog) ToProto() interface{} { + p := proto.UnionLog{} + p.OPRId = this.OPRId + p.TargetId = this.TargetId + p.Des = this.Des + p.State = this.State + p.Ctime = this.Ctime.UnixNano() / 1e6 + return p +} + +func NewCreate(opNickName string, unionId int, opRId int) { + ulog := &CoalitionLog{ + UnionId: unionId, + OPRId: opRId, + TargetId: 0, + State: UnionOpCreate, + Des: opNickName + " 创建了联盟", + Ctime: time.Now(), + } + + db.MasterDB.InsertOne(ulog) +} + +func NewDismiss(opNickName string, unionId int, opRId int) { + ulog := &CoalitionLog{ + UnionId: unionId, + OPRId: opRId, + TargetId: 0, + State: UnionOpDismiss, + Des: opNickName + " 解散了联盟", + Ctime: time.Now(), + } + db.MasterDB.InsertOne(ulog) +} + +func NewJoin(targetNickName string, unionId int, opRId int, targetId int) { + ulog := &CoalitionLog{ + UnionId: unionId, + OPRId: opRId, + TargetId: targetId, + State: UnionOpJoin, + Des: targetNickName + " 加入了联盟", + Ctime: time.Now(), + } + db.MasterDB.InsertOne(ulog) +} + +func NewExit(opNickName string, unionId int, opRId int) { + ulog := &CoalitionLog{ + UnionId: unionId, + OPRId: opRId, + TargetId: opRId, + State: UnionOpExit, + Des: opNickName + " 退出了联盟", + Ctime: time.Now(), + } + db.MasterDB.InsertOne(ulog) +} + +func NewKick(opNickName string, targetNickName string, unionId int, opRId int, targetId int) { + ulog := &CoalitionLog{ + UnionId: unionId, + OPRId: opRId, + TargetId: targetId, + State: UnionOpKick, + Des: opNickName + " 将 " + targetNickName + " 踢出了联盟", + Ctime: time.Now(), + } + db.MasterDB.InsertOne(ulog) +} + +func NewAppoint(opNickName string, targetNickName string, + unionId int, opRId int, targetId int, memberType int) { + + title := "" + if memberType == proto.UnionChairman { + title = "盟主" + } else if memberType == proto.UnionViceChairman { + title = "副盟主" + } else { + title = "普通成员" + } + + ulog := &CoalitionLog{ + UnionId: unionId, + OPRId: opRId, + TargetId: targetId, + State: UnionOpAppoint, + Des: opNickName + " 将 " + targetNickName + " 任命为 " + title, + Ctime: time.Now(), + } + db.MasterDB.InsertOne(ulog) +} + +func NewAbdicate(opNickName string, targetNickName string, + unionId int, opRId int, targetId int, memberType int) { + + title := "" + if memberType == proto.UnionChairman { + title = "盟主" + } else if memberType == proto.UnionViceChairman { + title = "副盟主" + } else { + title = "普通成员" + } + + ulog := &CoalitionLog{ + UnionId: unionId, + OPRId: opRId, + TargetId: targetId, + State: UnionOpAbdicate, + Des: opNickName + " 将 " + title + " 禅让给 " + targetNickName, + Ctime: time.Now(), + } + db.MasterDB.InsertOne(ulog) +} + +func NewModNotice(opNickName string, unionId int, opRId int) { + ulog := &CoalitionLog{ + UnionId: unionId, + OPRId: opRId, + TargetId: 0, + State: UnionOpModNotice, + Des: opNickName + " 修改了公告", + Ctime: time.Now(), + } + db.MasterDB.InsertOne(ulog) +} diff --git a/server/slgserver/model/general.go b/server/slgserver/model/general.go new file mode 100644 index 0000000..196d72e --- /dev/null +++ b/server/slgserver/model/general.go @@ -0,0 +1,326 @@ +package model + +import ( + "encoding/json" + "errors" + "fmt" + "log/slog" + "slgserver/db" + "slgserver/net" + "slgserver/server/slgserver/proto" + "slgserver/server/slgserver/static_conf" + "slgserver/server/slgserver/static_conf/general" + "time" + "xorm.io/xorm" +) + +const ( + GeneralNormal = 0 //正常 + GeneralComposeStar = 1 //星级合成 + GeneralConvert = 2 //转换 +) + +/*******db 操作begin********/ +var dbGeneralMgr *generalDBMgr + +func init() { + dbGeneralMgr = &generalDBMgr{gs: make(chan *General, 100)} + go dbGeneralMgr.running() +} + +type generalDBMgr struct { + gs chan *General +} + +func (this *generalDBMgr) running() { + for true { + select { + case g := <-this.gs: + if g.Id > 0 && g.RId > 0 { + _, err := db.MasterDB.Table(g).ID(g.Id).Cols( + "level", "exp", "order", "cityId", + "physical_power", "star_lv", "has_pr_point", + "use_pr_point", "force_added", "strategy_added", + "defense_added", "speed_added", "destroy_added", + "parentId", "compose_type", "skills", "state").Update(g) + if err != nil { + slog.Warn("db error", "error", err) + } + } else { + slog.Warn("update general fail, because id <= 0") + } + } + } +} + +func (this *generalDBMgr) push(g *General) { + this.gs <- g +} + +/*******db 操作end********/ + +const SkillLimit = 3 + +func NewGeneral(cfgId int, rid int, level int8) (*General, bool) { + + cfg, ok := general.General.GMap[cfgId] + if ok { + sa := make([]*proto.GSkill, SkillLimit) + ss, _ := json.Marshal(sa) + g := &General{ + PhysicalPower: static_conf.Basic.General.PhysicalPowerLimit, + RId: rid, + CfgId: cfg.CfgId, + Order: 0, + CityId: 0, + Level: level, + CreatedAt: time.Now(), + CurArms: cfg.Arms[0], + HasPrPoint: 0, + UsePrPoint: 0, + AttackDis: 0, + ForceAdded: 0, + StrategyAdded: 0, + DefenseAdded: 0, + SpeedAdded: 0, + DestroyAdded: 0, + Star: cfg.Star, + StarLv: 0, + ParentId: 0, + SkillsArray: sa, + Skills: string(ss), + State: GeneralNormal, + } + + if _, err := db.MasterDB.Table(General{}).Insert(g); err != nil { + slog.Warn("db error", "error", err) + return nil, false + } else { + return g, true + } + } else { + return nil, false + } +} + +type General struct { + Id int `xorm:"id pk autoincr"` + RId int `xorm:"rid"` + CfgId int `xorm:"cfgId"` + PhysicalPower int `xorm:"physical_power"` + Level int8 `xorm:"level"` + Exp int `xorm:"exp"` + Order int8 `xorm:"order"` + CityId int `xorm:"cityId"` + CreatedAt time.Time `xorm:"created_at"` + CurArms int `xorm:"arms"` + HasPrPoint int `xorm:"has_pr_point"` + UsePrPoint int `xorm:"use_pr_point"` + AttackDis int `xorm:"attack_distance"` + ForceAdded int `xorm:"force_added"` + StrategyAdded int `xorm:"strategy_added"` + DefenseAdded int `xorm:"defense_added"` + SpeedAdded int `xorm:"speed_added"` + DestroyAdded int `xorm:"destroy_added"` + StarLv int8 `xorm:"star_lv"` + Star int8 `xorm:"star"` + ParentId int `xorm:"parentId"` + Skills string `xorm:"skills"` + SkillsArray []*proto.GSkill `xorm:"-"` + State int8 `xorm:"state"` +} + +func (this *General) TableName() string { + return "tb_general" + fmt.Sprintf("_%d", ServerId) +} + +func (this *General) AfterSet(name string, cell xorm.Cell) { + if name == "skills" { + this.SkillsArray = make([]*proto.GSkill, 3) + if cell != nil { + gs, ok := (*cell).([]uint8) + if ok { + json.Unmarshal(gs, &this.Skills) + slog.Debug("general skills loaded", "skills", this.SkillsArray) + } + } + } +} + +func (this *General) beforeModify() { + data, _ := json.Marshal(this.SkillsArray) + this.Skills = string(data) +} + +func (this *General) BeforeInsert() { + this.beforeModify() +} + +func (this *General) BeforeUpdate() { + this.beforeModify() +} + +func (this *General) GetDestroy() int { + cfg, ok := general.General.GMap[this.CfgId] + if ok { + return cfg.Destroy + cfg.DestroyGrow*int(this.Level) + this.DestroyAdded + } + return 0 +} + +func (this *General) IsActive() bool { + return this.State == GeneralNormal +} + +func (this *General) GetSpeed() int { + cfg, ok := general.General.GMap[this.CfgId] + if ok { + return cfg.Speed + cfg.SpeedGrow*int(this.Level) + this.SpeedAdded + } + return 0 +} + +func (this *General) GetForce() int { + cfg, ok := general.General.GMap[this.CfgId] + if ok { + return cfg.Force + cfg.ForceGrow*int(this.Level) + this.ForceAdded + } + return 0 +} + +func (this *General) GetDefense() int { + cfg, ok := general.General.GMap[this.CfgId] + if ok { + return cfg.Defense + cfg.DefenseGrow*int(this.Level) + this.DefenseAdded + } + return 0 +} + +func (this *General) GetStrategy() int { + cfg, ok := general.General.GMap[this.CfgId] + if ok { + return cfg.Strategy + cfg.StrategyGrow*int(this.Level) + this.StrategyAdded + } + return 0 +} + +// 获取阵营 +func (this *General) GetCamp() int8 { + cfg, ok := general.General.GMap[this.CfgId] + if ok { + return cfg.Camp + } + return 0 +} + +func (this *General) UpSkill(skillId int, cfgId int, pos int) bool { + if pos < 0 || pos >= SkillLimit { + return false + } + + for _, skill := range this.SkillsArray { + if skill != nil && skill.Id == skillId { + //已经上过同类型的技能了 + return false + } + } + + s := this.SkillsArray[pos] + if s == nil { + this.SkillsArray[pos] = &proto.GSkill{Id: skillId, Lv: 1, CfgId: cfgId} + return true + } else { + if s.Id == 0 { + s.Id = skillId + s.CfgId = cfgId + s.Lv = 1 + return true + } else { + return false + } + } +} + +func (this *General) DownSkill(skillId int, pos int) bool { + if pos < 0 || pos >= SkillLimit { + return false + } + s := this.SkillsArray[pos] + if s != nil && s.Id == skillId { + s.Id = 0 + s.Lv = 0 + s.CfgId = 0 + return true + } else { + return false + } +} + +func (this *General) PosSkill(pos int) (*proto.GSkill, error) { + if pos >= len(this.SkillsArray) { + return nil, errors.New("skill index out of range") + } + return this.SkillsArray[pos], nil +} + +/* 推送同步 begin */ +func (this *General) IsCellView() bool { + return false +} + +func (this *General) IsCanView(rid, x, y int) bool { + return false +} + +func (this *General) BelongToRId() []int { + return []int{this.RId} +} + +func (this *General) PushMsgName() string { + return "general.push" +} + +func (this *General) Position() (int, int) { + return -1, -1 +} + +func (this *General) TPosition() (int, int) { + return -1, -1 +} + +func (this *General) ToProto() interface{} { + p := proto.General{} + p.CityId = this.CityId + p.Order = this.Order + p.PhysicalPower = this.PhysicalPower + p.Id = this.Id + p.CfgId = this.CfgId + p.Level = this.Level + p.Exp = this.Exp + p.CurArms = this.CurArms + p.HasPrPoint = this.HasPrPoint + p.UsePrPoint = this.UsePrPoint + p.AttackDis = this.AttackDis + p.ForceAdded = this.ForceAdded + p.StrategyAdded = this.StrategyAdded + p.DefenseAdded = this.DefenseAdded + p.SpeedAdded = this.SpeedAdded + p.DestroyAdded = this.DestroyAdded + p.StarLv = this.StarLv + p.Star = this.Star + p.State = this.State + p.ParentId = this.ParentId + p.Skills = this.SkillsArray + return p +} + +func (this *General) Push() { + net.ConnMgr.Push(this) +} + +/* 推送同步 end */ + +func (this *General) SyncExecute() { + dbGeneralMgr.push(this) + this.Push() +} diff --git a/server/slgserver/model/map_role_build.go b/server/slgserver/model/map_role_build.go new file mode 100644 index 0000000..8be687b --- /dev/null +++ b/server/slgserver/model/map_role_build.go @@ -0,0 +1,285 @@ +package model + +import ( + "fmt" + "log/slog" + "slgserver/db" + "slgserver/net" + "slgserver/server/slgserver/proto" + "slgserver/server/slgserver/static_conf" + "slgserver/util" + "time" +) + +const ( + MapBuildSysFortress = 50 //系统要塞 + MapBuildSysCity = 51 //系统城市 + MapBuildFortress = 56 //玩家要塞 +) + +/*******db 操作begin********/ +var dbRBMgr *rbDBMgr +func init() { + dbRBMgr = &rbDBMgr{builds: make(chan *MapRoleBuild, 100)} + go dbRBMgr.running() +} + +type rbDBMgr struct { + builds chan *MapRoleBuild +} + +func (this *rbDBMgr) running() { + for true { + select { + case b := <- this.builds: + if b.Id >0 { + _, err := db.MasterDB.Table(b).ID(b.Id).Cols( + "rid", "name", "type", "level", "op_level", + "cur_durable", "max_durable", "occupy_time", + "giveUp_time", "end_time").Update(b) + if err != nil{ + slog.Warn("db error", "error", err) + } + }else{ + slog.Warn("update role build fail, because id <= 0") + } + } + } +} + +func (this *rbDBMgr) push(b *MapRoleBuild) { + this.builds <- b +} +/*******db 操作end********/ + +type MapRoleBuild struct { + Id int `xorm:"id pk autoincr"` + RId int `xorm:"rid"` + Type int8 `xorm:"type"` + Level int8 `xorm:"level"` + OPLevel int8 `xorm:"op_level"` //操作level + X int `xorm:"x"` + Y int `xorm:"y"` + Name string `xorm:"name"` + Wood int `xorm:"-"` + Iron int `xorm:"-"` + Stone int `xorm:"-"` + Grain int `xorm:"-"` + Defender int `xorm:"-"` + CurDurable int `xorm:"cur_durable"` + MaxDurable int `xorm:"max_durable"` + OccupyTime time.Time `xorm:"occupy_time"` + EndTime time.Time `xorm:"end_time"` //建造或升级完的时间 + GiveUpTime int64 `xorm:"giveUp_time"` +} + +func (this *MapRoleBuild) TableName() string { + return "tb_map_role_build" + fmt.Sprintf("_%d", ServerId) +} + +func (this* MapRoleBuild) Init() { + if cfg, _ := static_conf.MapBuildConf.BuildConfig(this.Type, this.Level); cfg != nil { + this.Name = cfg.Name + this.Level = cfg.Level + this.Type = cfg.Type + this.Wood = cfg.Wood + this.Iron = cfg.Iron + this.Stone = cfg.Stone + this.Grain = cfg.Grain + this.MaxDurable = cfg.Durable + this.CurDurable = cfg.Durable + this.Defender = cfg.Defender + } +} + + +func (this* MapRoleBuild) Reset() { + ok, t, level := MapResTypeLevel(this.X, this.Y) + if ok { + if cfg, _ := static_conf.MapBuildConf.BuildConfig(t, level); cfg != nil { + this.Name = cfg.Name + this.Level = cfg.Level + this.Type = cfg.Type + this.Wood = cfg.Wood + this.Iron = cfg.Iron + this.Stone = cfg.Stone + this.Grain = cfg.Grain + this.MaxDurable = cfg.Durable + this.Defender = cfg.Defender + } + } + + this.GiveUpTime = 0 + this.RId = 0 + this.EndTime = time.Time{} + this.OPLevel = this.Level + this.CurDurable = util.MinInt(this.MaxDurable, this.CurDurable) +} + +func (this* MapRoleBuild) ConvertToRes() { + rid := this.RId + giveUp := this.GiveUpTime + this.Reset() + this.RId = rid + this.GiveUpTime = giveUp +} + +func (this* MapRoleBuild) IsInGiveUp() bool { + return this.GiveUpTime != 0 +} + +func (this* MapRoleBuild) IsWarFree() bool { + curTime := time.Now().Unix() + if curTime - this.OccupyTime.Unix() < static_conf.Basic.Build.WarFree{ + return true + }else{ + return false + } +} + +func (this* MapRoleBuild) IsResBuild() bool { + return this.Grain > 0 || this.Stone > 0 || this.Iron > 0 || this.Wood > 0 +} + +//是否有修改等级权限 +func (this* MapRoleBuild) IsHaveModifyLVAuth() bool { + return this.Type == MapBuildFortress +} + +func (this* MapRoleBuild) IsBusy() bool{ + if this.Level != this.OPLevel{ + return true + }else { + return false + } +} + +func (this* MapRoleBuild) IsRoleFortress() bool { + return this.Type == MapBuildFortress +} + +func (this* MapRoleBuild) IsSysFortress() bool { + return this.Type == MapBuildSysFortress +} + +func (this* MapRoleBuild) IsSysCity() bool { + return this.Type == MapBuildSysCity +} + +func (this* MapRoleBuild) CellRadius() int { + if this.IsSysCity(){ + if this.Level >= 8{ + return 3 + }else if this.Level >= 5{ + return 2 + }else { + return 1 + } + }else{ + return 0 + } +} +//是否有调兵权限 +func (this* MapRoleBuild) IsHasTransferAuth() bool { + return this.Type == MapBuildFortress || this.Type == MapBuildSysFortress +} + +func (this* MapRoleBuild) BuildOrUp(cfg static_conf.BCLevelCfg) { + this.Type = cfg.Type + this.Level = cfg.Level -1 + this.Name = cfg.Name + this.OPLevel = cfg.Level + this.GiveUpTime = 0 + + this.Wood = 0 + this.Iron = 0 + this.Stone = 0 + this.Grain = 0 + this.EndTime = time.Now().Add(time.Duration(cfg.Time) * time.Second) +} + +func (this* MapRoleBuild) DelBuild(cfg static_conf.BCLevelCfg) { + this.OPLevel = 0 + this.EndTime = time.Now().Add(time.Duration(cfg.Time) * time.Second) +} + +/* 推送同步 begin */ +func (this *MapRoleBuild) IsCellView() bool{ + return true +} + +func (this *MapRoleBuild) IsCanView(rid, x, y int) bool{ + return true +} + + +func (this *MapRoleBuild) BelongToRId() []int{ + return []int{this.RId} +} + +func (this *MapRoleBuild) PushMsgName() string{ + return "roleBuild.push" +} + +func (this *MapRoleBuild) Position() (int, int){ + return this.X, this.Y +} + +func (this *MapRoleBuild) TPosition() (int, int){ + return -1, -1 +} + +func (this *MapRoleBuild) ToProto() interface{}{ + + p := proto.MapRoleBuild{} + p.RNick = GetRoleNickName(this.RId) + p.UnionId = GetUnionId(this.RId) + p.UnionName = GetUnionName(p.UnionId) + p.ParentId = GetParentId(this.RId) + p.X = this.X + p.Y = this.Y + p.Type = this.Type + p.RId = this.RId + p.Name = this.Name + + p.OccupyTime = this.OccupyTime.UnixNano()/1e6 + p.GiveUpTime = this.GiveUpTime*1000 + p.EndTime = this.EndTime.UnixNano()/1e6 + + if this.EndTime.IsZero() == false{ + if this.IsHasTransferAuth(){ + if time.Now().Before(this.EndTime) == false{ + + if this.OPLevel == 0{ + this.ConvertToRes() + }else{ + this.Level = this.OPLevel + this.EndTime = time.Time{} + cfg, ok := static_conf.MapBCConf.BuildConfig(this.Type, this.Level) + if ok { + this.MaxDurable = cfg.Durable + this.CurDurable = util.MinInt(this.MaxDurable, this.CurDurable) + this.Defender = cfg.Defender + } + } + } + } + } + + p.CurDurable = this.CurDurable + p.MaxDurable = this.MaxDurable + p.Defender = this.Defender + p.Level = this.Level + p.OPLevel = this.OPLevel + return p +} + +func (this *MapRoleBuild) Push(){ + net.ConnMgr.Push(this) +} +/* 推送同步 end */ + +func (this *MapRoleBuild) SyncExecute() { + dbRBMgr.push(this) + this.Push() +} \ No newline at end of file diff --git a/server/slgserver/model/map_role_city.go b/server/slgserver/model/map_role_city.go new file mode 100644 index 0000000..6e18c48 --- /dev/null +++ b/server/slgserver/model/map_role_city.go @@ -0,0 +1,144 @@ +package model + +import ( + "fmt" + "log/slog" + "slgserver/db" + "slgserver/net" + "slgserver/server/slgserver/proto" + "slgserver/server/slgserver/static_conf" + "slgserver/util" + "sync" + "time" +) + +/*******db 操作begin********/ +var dbRCMgr *rcDBMgr +func init() { + dbRCMgr = &rcDBMgr{builds: make(chan *MapRoleCity, 100)} + go dbRCMgr.running() +} + +type rcDBMgr struct { + builds chan *MapRoleCity +} + +func (this*rcDBMgr) running() { + for true { + select { + case b := <- this.builds: + if b.CityId >0 { + _, err := db.MasterDB.Table(b).ID(b.CityId).Cols("cur_durable", "occupy_time").Update(b) + if err != nil{ + slog.Warn("db error", "error", err) + } + }else{ + slog.Warn("update role city build fail, because CityId <= 0") + } + } + } +} + +func (this*rcDBMgr) push(b *MapRoleCity) { + this.builds <- b +} +/*******db 操作end********/ + +type MapRoleCity struct { + mutex sync.Mutex `xorm:"-"` + CityId int `xorm:"cityId pk autoincr"` + RId int `xorm:"rid"` + Name string `xorm:"name" validate:"min=4,max=20,regexp=^[a-zA-Z0-9_]*$"` + X int `xorm:"x"` + Y int `xorm:"y"` + IsMain int8 `xorm:"is_main"` + CurDurable int `xorm:"cur_durable"` + CreatedAt time.Time `xorm:"created_at"` + OccupyTime time.Time `xorm:"occupy_time"` +} + +func (this* MapRoleCity) IsWarFree() bool { + curTime := time.Now().Unix() + if curTime - this.OccupyTime.Unix() < static_conf.Basic.Build.WarFree{ + return true + }else{ + return false + } +} + +func (this*MapRoleCity) DurableChange(change int) { + this.mutex.Lock() + defer this.mutex.Unlock() + + t := this.CurDurable + change + if t < 0{ + this.CurDurable = 0 + }else{ + this.CurDurable = util.MinInt(GetMaxDurable(this.CityId), t) + } +} + +func (this *MapRoleCity) Level() int8 { + return GetCityLv(this.CityId) +} + +func (this* MapRoleCity) CellRadius() int { + return 1 +} + +func (this *MapRoleCity) TableName() string { + return "tb_map_role_city" + fmt.Sprintf("_%d", ServerId) +} + +/* 推送同步 begin */ +func (this *MapRoleCity) IsCellView() bool{ + return true +} + +func (this *MapRoleCity) IsCanView(rid, x, y int) bool{ + return true +} + +func (this *MapRoleCity) BelongToRId() []int{ + return []int{this.RId} +} + +func (this *MapRoleCity) PushMsgName() string{ + return "roleCity.push" +} + +func (this *MapRoleCity) Position() (int, int){ + return this.X, this.Y +} + +func (this *MapRoleCity) TPosition() (int, int){ + return -1, -1 +} + +func (this *MapRoleCity) ToProto() interface{}{ + p := proto.MapRoleCity{} + p.X = this.X + p.Y = this.Y + p.CityId = this.CityId + p.UnionId = GetUnionId(this.RId) + p.UnionName = GetUnionName(p.UnionId) + p.ParentId = GetParentId(this.RId) + p.MaxDurable = GetMaxDurable(this.RId) + p.CurDurable = this.CurDurable + p.Level = this.Level() + p.RId = this.RId + p.Name = this.Name + p.IsMain = this.IsMain == 1 + p.OccupyTime = this.OccupyTime.UnixNano()/1e6 + return p +} + +func (this *MapRoleCity) Push(){ + net.ConnMgr.Push(this) +} +/* 推送同步 end */ + +func (this *MapRoleCity) SyncExecute() { + dbRCMgr.push(this) + this.Push() +} \ No newline at end of file diff --git a/server/slgserver/model/national_map.go b/server/slgserver/model/national_map.go new file mode 100644 index 0000000..ffd4aa0 --- /dev/null +++ b/server/slgserver/model/national_map.go @@ -0,0 +1,11 @@ +package model + +type NationalMap struct { + MId int `xorm:"mid"` + X int `xorm:"x"` + Y int `xorm:"y"` + Type int8 `xorm:"type"` + Level int8 `xorm:"level"` +} + + diff --git a/server/slgserver/model/role.go b/server/slgserver/model/role.go new file mode 100644 index 0000000..35f438e --- /dev/null +++ b/server/slgserver/model/role.go @@ -0,0 +1,36 @@ +package model + +import ( + "fmt" + "slgserver/server/slgserver/proto" + "time" +) + +type Role struct { + RId int `xorm:"rid pk autoincr"` + UId int `xorm:"uid"` + NickName string `xorm:"nick_name" validate:"min=4,max=20,regexp=^[a-zA-Z0-9_]*$"` + Balance int `xorm:"balance"` + HeadId int16 `xorm:"headId"` + Sex int8 `xorm:"sex"` + Profile string `xorm:"profile"` + LoginTime time.Time `xorm:"login_time"` + LogoutTime time.Time `xorm:"logout_time"` + CreatedAt time.Time `xorm:"created_at"` +} + +func (this *Role) TableName() string { + return "tb_role" + fmt.Sprintf("_%d", ServerId) +} + +func (this *Role) ToProto() interface{}{ + p := proto.Role{} + p.UId = this.UId + p.RId = this.RId + p.Sex = this.Sex + p.NickName = this.NickName + p.HeadId = this.HeadId + p.Balance = this.Balance + p.Profile = this.Profile + return p +} diff --git a/server/slgserver/model/role_attribute.go b/server/slgserver/model/role_attribute.go new file mode 100644 index 0000000..12d2d05 --- /dev/null +++ b/server/slgserver/model/role_attribute.go @@ -0,0 +1,153 @@ +package model + +import ( + "encoding/json" + "fmt" + "log/slog" + "slgserver/db" + "slgserver/net" + "slgserver/server/slgserver/proto" + "time" + "xorm.io/xorm" +) + +/*******db 操作begin********/ +var dbRAttrMgr *roleAttrDBMgr + +func init() { + dbRAttrMgr = &roleAttrDBMgr{rattr: make(chan *RoleAttribute, 100)} + go dbRAttrMgr.running() +} + +type roleAttrDBMgr struct { + rattr chan *RoleAttribute +} + +func (this *roleAttrDBMgr) running() { + for true { + select { + case attr := <-this.rattr: + if attr.Id > 0 { + _, err := db.MasterDB.Table(attr).ID(attr.Id).Cols( + "parent_id", "collect_times", "last_collect_time", "pos_tags").Update(attr) + if err != nil { + slog.Warn("db error", "error", err) + } + } else { + slog.Warn("update role attr fail, because id <= 0") + } + } + } +} + +func (this *roleAttrDBMgr) push(attr *RoleAttribute) { + this.rattr <- attr +} + +/*******db 操作end********/ + +type RoleAttribute struct { + Id int `xorm:"id pk autoincr"` + RId int `xorm:"rid"` + UnionId int `xorm:"-"` //联盟id + ParentId int `xorm:"parent_id"` //上级id(被沦陷) + CollectTimes int8 `xorm:"collect_times"` //征收次数 + LastCollectTime time.Time `xorm:"last_collect_time"` //最后征收的时间 + PosTags string `xorm:"pos_tags"` //位置标记 + PosTagArray []proto.PosTag `xorm:"-"` +} + +func (this *RoleAttribute) TableName() string { + return "tb_role_attribute" + fmt.Sprintf("_%d", ServerId) +} + +func (this *RoleAttribute) AfterSet(name string, cell xorm.Cell) { + if name == "pos_tags" { + this.PosTagArray = make([]proto.PosTag, 0) + if cell != nil { + data, ok := (*cell).([]uint8) + if ok { + json.Unmarshal(data, &this.PosTagArray) + slog.Debug("role pos tags loaded", "tags", this.PosTagArray) + } + } + } +} + +func (this *RoleAttribute) beforeModify() { + if this.PosTagArray == nil { + this.PosTagArray = make([]proto.PosTag, 0) + } + data, _ := json.Marshal(this.PosTagArray) + this.PosTags = string(data) +} + +func (this *RoleAttribute) BeforeInsert() { + this.beforeModify() +} + +func (this *RoleAttribute) BeforeUpdate() { + this.beforeModify() +} + +func (this *RoleAttribute) RemovePosTag(x, y int) { + tags := make([]proto.PosTag, 0) + for _, tag := range this.PosTagArray { + if tag.X != x || tag.Y != y { + tags = append(tags, tag) + } + } + this.PosTagArray = tags +} + +func (this *RoleAttribute) AddPosTag(x, y int, name string) { + ok := true + for _, tag := range this.PosTagArray { + if tag.X == x && tag.Y == y { + ok = false + break + } + } + if ok { + this.PosTagArray = append(this.PosTagArray, proto.PosTag{X: x, Y: y, Name: name}) + } +} + +/* 推送同步 begin */ +func (this *RoleAttribute) IsCellView() bool { + return false +} + +func (this *RoleAttribute) IsCanView(rid, x, y int) bool { + return false +} + +func (this *RoleAttribute) BelongToRId() []int { + return []int{this.RId} +} + +func (this *RoleAttribute) PushMsgName() string { + return "roleAttr.push" +} + +func (this *RoleAttribute) ToProto() interface{} { + return nil +} + +func (this *RoleAttribute) Position() (int, int) { + return -1, -1 +} + +func (this *RoleAttribute) TPosition() (int, int) { + return -1, -1 +} + +func (this *RoleAttribute) Push() { + net.ConnMgr.Push(this) +} + +/* 推送同步 end */ + +func (this *RoleAttribute) SyncExecute() { + dbRAttrMgr.push(this) +} diff --git a/server/slgserver/model/role_res.go b/server/slgserver/model/role_res.go new file mode 100644 index 0000000..dabb14e --- /dev/null +++ b/server/slgserver/model/role_res.go @@ -0,0 +1,122 @@ +package model + +import ( + "fmt" + "log/slog" + "slgserver/db" + "slgserver/net" + "slgserver/server/slgserver/proto" +) + +type Yield struct { + Wood int + Iron int + Stone int + Grain int + Gold int +} + +/*******db 操作begin********/ +var dbRResMgr *roleResDBMgr +func init() { + dbRResMgr = &roleResDBMgr{ress: make(chan *RoleRes, 100)} + go dbRResMgr.running() +} + +type roleResDBMgr struct { + ress chan *RoleRes +} + +func (this *roleResDBMgr) running() { + for true { + select { + case res := <- this.ress: + if res.Id >0 { + _, err := db.MasterDB.Table(res).ID(res.Id).Cols( + "wood", "iron", "stone", + "grain", "gold", "decree").Update(res) + if err != nil{ + slog.Warn("db error", "error", err) + } + }else{ + slog.Warn("update role build fail, because id <= 0") + } + } + } +} + +func (this *roleResDBMgr) push(res *RoleRes) { + this.ress <- res +} +/*******db 操作end********/ + + +type RoleRes struct { + Id int `xorm:"id pk autoincr"` + RId int `xorm:"rid"` + Wood int `xorm:"wood"` + Iron int `xorm:"iron"` + Stone int `xorm:"stone"` + Grain int `xorm:"grain"` + Gold int `xorm:"gold"` + Decree int `xorm:"decree"` //令牌 +} + +func (this *RoleRes) TableName() string { + return "tb_role_res" + fmt.Sprintf("_%d", ServerId) +} + + +/* 推送同步 begin */ +func (this *RoleRes) IsCellView() bool{ + return false +} + +func (this *RoleRes) IsCanView(rid, x, y int) bool{ + return false +} + +func (this *RoleRes) BelongToRId() []int{ + return []int{this.RId} +} + +func (this *RoleRes) PushMsgName() string{ + return "roleRes.push" +} + +func (this *RoleRes) ToProto() interface{}{ + p := proto.RoleRes{} + p.Gold = this.Gold + p.Grain = this.Grain + p.Stone = this.Stone + p.Iron = this.Iron + p.Wood = this.Wood + p.Decree = this.Decree + + y := GetYield(this.RId) + p.GoldYield = y.Gold + p.GrainYield = y.Grain + p.StoneYield = y.Stone + p.IronYield = y.Iron + p.WoodYield = y.Wood + p.DepotCapacity = GetDepotCapacity(this.RId) + return p +} + +func (this *RoleRes) Position() (int, int){ + return -1, -1 +} + +func (this *RoleRes) TPosition() (int, int){ + return -1, -1 +} + +func (this *RoleRes) Push(){ + net.ConnMgr.Push(this) +} +/* 推送同步 end */ + +func (this *RoleRes) SyncExecute() { + dbRResMgr.push(this) + this.Push() +} \ No newline at end of file diff --git a/server/slgserver/model/skill.go b/server/slgserver/model/skill.go new file mode 100644 index 0000000..1831536 --- /dev/null +++ b/server/slgserver/model/skill.go @@ -0,0 +1,178 @@ +package model + +import ( + "encoding/json" + "fmt" + "log/slog" + "slgserver/db" + "slgserver/net" + "slgserver/server/slgserver/proto" + "slgserver/server/slgserver/static_conf/skill" + "xorm.io/xorm" +) + + +/*******db 操作begin********/ +var dbSkillMgr *skillDBMgr +func init() { + dbSkillMgr = &skillDBMgr{skills: make(chan *Skill, 100)} + go dbSkillMgr.running() +} + + +type skillDBMgr struct { + skills chan *Skill +} + +func (this*skillDBMgr) running() { + for true { + select { + case skill := <- this.skills: + if skill.Id >0 { + _, err := db.MasterDB.Table(skill).ID(skill.Id).Cols( + "cfgId", "belong_generals", "rid").Update(skill) + if err != nil{ + slog.Warn("db error", "error", err) + } + }else{ + db.MasterDB.Table(skill).InsertOne(skill) + } + } + } +} + +func (this*skillDBMgr) push(skill *Skill) { + this.skills <- skill +} +/*******db 操作end********/ + +//军队 +type Skill struct { + Id int `xorm:"id pk autoincr"` + RId int `xorm:"rid"` + CfgId int `xorm:"cfgId"` + BelongGenerals string `xorm:"belong_generals"` + Generals []int `xorm:"-"` +} + +func NewSkill(rid int, cfgId int) *Skill{ + return &Skill{ + CfgId: cfgId, + RId: rid, + Generals: []int{}, + BelongGenerals: "[]", + } +} + +func (this *Skill) TableName() string { + return "tb_skill" + fmt.Sprintf("_%d", ServerId) +} + + +func (this *Skill) AfterSet(name string, cell xorm.Cell){ + if name == "belong_generals"{ + this.Generals = []int{} + if cell != nil{ + gs, ok := (*cell).([]uint8) + if ok { + json.Unmarshal(gs, &this.BelongGenerals) + } + } + } +} + +func (this *Skill) beforeModify() { + data, _ := json.Marshal(this.Generals) + this.BelongGenerals = string(data) +} + +func (this *Skill) BeforeInsert() { + this.beforeModify() +} + +func (this *Skill) BeforeUpdate() { + this.beforeModify() +} + + + +/* 推送同步 begin */ +func (this *Skill) IsCellView() bool{ + return false +} + +func (this *Skill) IsCanView(rid, x, y int) bool{ + return false +} + +func (this *Skill) BelongToRId() []int{ + return []int{this.RId} +} + +func (this *Skill) PushMsgName() string{ + return "skill.push" +} + +func (this *Skill) Position() (int, int){ + return -1, -1 +} + +func (this *Skill) TPosition() (int, int){ + return -1, -1 +} + +func (this *Skill) ToProto() interface{}{ + p := proto.Skill{} + p.Id = this.Id + p.CfgId = this.CfgId + p.Generals = this.Generals + return p +} +func (this *Skill) Push(){ + net.ConnMgr.Push(this) +} +/* 推送同步 end */ + +func (this *Skill) SyncExecute() { + dbSkillMgr.push(this) + this.Push() +} + +func (this *Skill) Limit() int { + cfg, _ := skill.Skill.GetCfg(this.CfgId) + return cfg.Limit +} + +func (this *Skill) IsInLimit() bool{ + //fmt.Println("this.BelongGenerals", this.BelongGenerals) + return len(this.Generals) < this.Limit() +} + +func (this *Skill) ArmyIsIn(armId int) bool { + cfg, _ := skill.Skill.GetCfg(this.CfgId) + for _, arm := range cfg.Arms { + if arm == armId{ + return true + } + } + return false +} + +func (this *Skill) UpSkill(gId int) { + this.Generals = append(this.Generals, gId) + data, _ := json.Marshal(this.Generals) + this.BelongGenerals = string(data) +} + +func (this *Skill) DownSkill(gId int) { + gs := make([]int, 0) + for _, general := range this.Generals { + if gId != general { + gs = append(gs, general) + } + } + this.Generals = gs + + data, _ := json.Marshal(this.Generals) + this.BelongGenerals = string(data) +} \ No newline at end of file diff --git a/server/slgserver/model/util.go b/server/slgserver/model/util.go new file mode 100644 index 0000000..560ac4e --- /dev/null +++ b/server/slgserver/model/util.go @@ -0,0 +1,16 @@ +package model + +var ArmyIsInView func(rid, x, y int) bool +var GetUnionId func(rid int) int +var GetUnionName func(unionId int) string +var GetRoleNickName func(rid int) string +var GetParentId func(rid int) int +var GetMainMembers func(unionId int) []int +var GetYield func(rid int) Yield +var GetDepotCapacity func(rid int) int +var GetCityCost func(cid int) int8 +var GetMaxDurable func(cid int) int +var GetCityLv func(cid int) int8 +var MapResTypeLevel func(x, y int) (bool, int8, int8) + +var ServerId = 0 \ No newline at end of file diff --git a/server/slgserver/model/war_report.go b/server/slgserver/model/war_report.go new file mode 100644 index 0000000..65cd1e6 --- /dev/null +++ b/server/slgserver/model/war_report.go @@ -0,0 +1,101 @@ +package model + +import ( + "fmt" + "log/slog" + "slgserver/db" + "slgserver/net" + "slgserver/server/slgserver/proto" + "time" +) + + +type WarReport struct { + Id int `xorm:"id pk autoincr"` + AttackRid int `xorm:"a_rid"` + DefenseRid int `xorm:"d_rid"` + BegAttackArmy string `xorm:"b_a_army"` + BegDefenseArmy string `xorm:"b_d_army"` + EndAttackArmy string `xorm:"e_a_army"` + EndDefenseArmy string `xorm:"e_d_army"` + BegAttackGeneral string `xorm:"b_a_general"` + BegDefenseGeneral string `xorm:"b_d_general"` + EndAttackGeneral string `xorm:"e_a_general"` + EndDefenseGeneral string `xorm:"e_d_general"` + Result int `xorm:"result"` //0失败,1打平,2胜利 + Rounds string `xorm:"rounds"` //回合 + AttackIsRead bool `xorm:"a_is_read"` + DefenseIsRead bool `xorm:"d_is_read"` + DestroyDurable int `xorm:"destroy"` + Occupy int `xorm:"occupy"` + X int `xorm:"x"` + Y int `xorm:"y"` + CTime time.Time `xorm:"ctime"` +} + +func (this *WarReport) TableName() string { + return "tb_war_report" + fmt.Sprintf("_%d", ServerId) +} + +/* 推送同步 begin */ +func (this *WarReport) IsCellView() bool{ + return false +} + +func (this *WarReport) IsCanView(rid, x, y int) bool{ + return false +} + +func (this *WarReport) BelongToRId() []int{ + return []int{this.AttackRid, this.DefenseRid} +} + +func (this *WarReport) PushMsgName() string{ + return "warReport.push" +} + +func (this *WarReport) Position() (int, int){ + return this.X, this.Y +} + +func (this *WarReport) TPosition() (int, int){ + return -1, -1 +} + +func (this *WarReport) ToProto() interface{}{ + p := proto.WarReport{} + p.CTime = int(this.CTime.UnixNano() / 1e6) + p.Id = this.Id + p.AttackRid = this.AttackRid + p.DefenseRid = this.DefenseRid + p.BegAttackArmy = this.BegAttackArmy + p.BegDefenseArmy = this.BegDefenseArmy + p.EndAttackArmy = this.EndAttackArmy + p.EndDefenseArmy = this.EndDefenseArmy + p.BegAttackGeneral = this.BegAttackGeneral + p.BegDefenseGeneral = this.BegDefenseGeneral + p.EndAttackGeneral = this.EndAttackGeneral + p.EndDefenseGeneral = this.EndDefenseGeneral + p.Result = this.Result + p.Rounds = this.Rounds + p.AttackIsRead = this.AttackIsRead + p.DefenseIsRead = this.DefenseIsRead + p.DestroyDurable = this.DestroyDurable + p.Occupy = this.Occupy + p.X = this.X + p.X = this.X + return p +} + +func (this *WarReport) Push(){ + net.ConnMgr.Push(this) +} +/* 推送同步 end */ + +func (this *WarReport) SyncExecute() { + _, err := db.MasterDB.InsertOne(this) + if err != nil{ + slog.Warn("db error", "error", err) + } + this.Push() +} diff --git a/server/slgserver/pos/position.go b/server/slgserver/pos/position.go new file mode 100644 index 0000000..b84e8ff --- /dev/null +++ b/server/slgserver/pos/position.go @@ -0,0 +1,63 @@ +package pos + +import "sync" + +var RPMgr = RolePosMgr{ + posCaches: make(map[position]map[int]int), + ridCaches: make(map[int]position), +} + +type position struct { + X int + Y int +} + +type RolePosMgr struct { + mutex sync.RWMutex + posCaches map[position]map[int]int + ridCaches map[int]position +} + +func (this *RolePosMgr) Push(x, y, rid int) { + this.mutex.Lock() + defer this.mutex.Unlock() + + //旧的要删除 + if r, ok := this.ridCaches[rid]; ok { + if r.X == x && r.Y == y{ + return + } + if c, ok1 := this.posCaches[r]; ok1 { + delete(c, rid) + } + } + + //新的写入 + p := position{x, y} + _, ok := this.posCaches[p] + if ok == false { + this.posCaches[p] = make(map[int]int) + } + this.posCaches[p][rid] = rid + this.ridCaches[rid] = p +} + +func (this *RolePosMgr) GetCellRoleIds(x, y, width, height int) []int{ + this.mutex.RLock() + defer this.mutex.RUnlock() + + l := make([]int, 0) + for i := x-width; i <= x+width; i++ { + for j := y-height; j <= y+height; j++ { + pos := position{i, j} + r, ok := this.posCaches[pos] + if ok { + for _, v := range r { + l = append(l, v) + } + } + } + } + return l +} + diff --git a/server/slgserver/proto/city.go b/server/slgserver/proto/city.go new file mode 100644 index 0000000..22c8a7b --- /dev/null +++ b/server/slgserver/proto/city.go @@ -0,0 +1,36 @@ +package proto + +type Facility struct { + Name string `json:"name"` + Level int8 `json:"level"` + Type int8 `json:"type"` + UpTime int64 `json:"up_time"` //升级的时间戳,0表示该等级已经升级完成了 +} + +type FacilitiesReq struct { + CityId int `json:"cityId"` +} + +type FacilitiesRsp struct { + CityId int `json:"cityId"` + Facilities []Facility `json:"facilities"` +} + +type UpFacilityReq struct { + CityId int `json:"cityId"` + FType int8 `json:"fType"` +} + +type UpFacilityRsp struct { + CityId int `json:"cityId"` + Facility Facility `json:"facility"` + RoleRes RoleRes `json:"role_res"` +} + +type UpCityReq struct { + CityId int `json:"cityId"` +} + +type UpCityRsp struct { + City MapRoleCity `json:"city"` +} \ No newline at end of file diff --git a/server/slgserver/proto/coalition.go b/server/slgserver/proto/coalition.go new file mode 100644 index 0000000..2f181fe --- /dev/null +++ b/server/slgserver/proto/coalition.go @@ -0,0 +1,195 @@ +package proto + +const ( + UnionChairman = 0 //盟主 + UnionViceChairman = 1 //副盟主 + UnionCommon = 2 //普通成员 +) + +const ( + UnionUntreated = 0 //未处理 + UnionRefuse = 1 //拒绝 + UnionAdopt = 2 //通过 +) + +type Member struct { + RId int `json:"rid"` + Name string `json:"name"` + Title int8 `json:"title"` + X int `json:"x"` + Y int `json:"y"` +} + +type Major struct { + RId int `json:"rid"` + Name string `json:"name"` + Title int8 `json:"title"` +} + + +type Union struct { + Id int `json:"id"` //联盟id + Name string `json:"name"` //联盟名字 + Cnt int `json:"cnt"` //联盟人数 + Notice string `json:"notice"` //公告 + Major []Major `json:"major"` //联盟主要人物,盟主副盟主 +} + +type ApplyItem struct { + Id int `json:"id"` + RId int `json:"rid"` + NickName string `json:"nick_name"` +} + + +//创建联盟 +type CreateReq struct { + Name string `json:"name"` +} + +type CreateRsp struct { + Id int `json:"id"` //联盟id + Name string `json:"name"` +} + +//联盟列表 +type ListReq struct { +} + +type ListRsp struct { + List []Union `json:"list"` +} + +//申请加入联盟 +type JoinReq struct { + Id int `json:"id"` //联盟id +} + +type JoinRsp struct { + +} + +//联盟成员 +type MemberReq struct { + Id int `json:"id"` //联盟id +} + +type MemberRsp struct { + Id int `json:"id"` //联盟id + Members []Member `json:"Members"` +} + + +//获取申请列表 +type ApplyReq struct { + Id int `json:"id"` +} + +type ApplyRsp struct { + Id int `json:"id"` + Applys []ApplyItem `json:"applys"` +} + +//审核 +type VerifyReq struct { + Id int `json:"id"` //申请操作的id + Decide int8 `json:"decide"` //1是拒绝,2是通过 +} + +type VerifyRsp struct { + Id int `json:"id"` //申请操作的id + Decide int8 `json:"decide"` //1是拒绝,2是通过 +} + +//退出 +type ExitReq struct { + +} + +type ExitRsp struct { + +} + + +//解散 +type DismissReq struct { + +} + +type DismissRsp struct { + +} + + +type NoticeReq struct { + Id int `json:"id"` //联盟id +} + +type NoticeRsp struct { + Text string `json:"text"` +} + +//修改公告 +type ModNoticeReq struct { + Text string `json:"text"` +} + +type ModNoticeRsp struct { + Id int `json:"id"` //联盟id + Text string `json:"text"` +} + +//踢人 +type KickReq struct { + RId int `json:"rid"` +} + +type KickRsp struct { + RId int `json:"rid"` +} + +//任命 +type AppointReq struct { + RId int `json:"rid"` + Title int `json:"title"` //职位,0盟主、1副盟主、2普通成员 +} + +type AppointRsp struct { + RId int `json:"rid"` + Title int `json:"title"` //职位,0盟主、1副盟主、2普通成员 +} + +//禅让(盟主副盟主) +type AbdicateReq struct { + RId int `json:"rid"` //禅让给的rid +} + +type AbdicateRsp struct { + +} + + +//联盟信息 +type InfoReq struct { + Id int `json:"id"` //联盟id +} + +type InfoRsp struct { + Id int `json:"id"` //联盟id + Info Union `json:"info"` +} + +type UnionLog struct { + OPRId int `json:"op_rid"` + TargetId int `json:"target_id"` + State int8 `json:"state"` + Des string `json:"des"` + Ctime int64 `json:"ctime"` +} + +type LogReq struct { +} + +type LogRsp struct { + Logs []UnionLog `json:"logs"` +} \ No newline at end of file diff --git a/server/slgserver/proto/general.go b/server/slgserver/proto/general.go new file mode 100644 index 0000000..217404d --- /dev/null +++ b/server/slgserver/proto/general.go @@ -0,0 +1,207 @@ +package proto + +type GSkill struct { + Id int `json:"id"` + Lv int `json:"lv"` + CfgId int `json:"cfgId"` +} +type General struct { + Id int `json:"id"` + CfgId int `json:"cfgId"` + PhysicalPower int `json:"physical_power"` + Order int8 `json:"order"` + Level int8 `json:"level"` + Exp int `json:"exp"` + CityId int `json:"cityId"` + CurArms int `json:"curArms"` + HasPrPoint int `json:"hasPrPoint"` + UsePrPoint int `json:"usePrPoint"` + AttackDis int `json:"attack_distance"` + ForceAdded int `json:"force_added"` + StrategyAdded int `json:"strategy_added"` + DefenseAdded int `json:"defense_added"` + SpeedAdded int `json:"speed_added"` + DestroyAdded int `json:"destroy_added"` + StarLv int8 `json:"star_lv"` + Star int8 `json:"star"` + ParentId int `json:"parentId"` + Skills []*GSkill `json:"skills"` + State int8 `json:"state"` + +} + +func (this*General) ToArray()[]int { + r := make([]int, 0) + + r = append(r, this.Id) + r = append(r, this.CfgId) + r = append(r, this.PhysicalPower) + r = append(r, int(this.Order)) + r = append(r, int(this.Level)) + r = append(r, this.Exp) + r = append(r, this.CityId) + r = append(r, this.CurArms) + r = append(r, this.HasPrPoint) + r = append(r, this.UsePrPoint) + r = append(r, this.AttackDis) + r = append(r, this.ForceAdded) + r = append(r, this.StrategyAdded) + r = append(r, this.SpeedAdded) + r = append(r, this.DefenseAdded) + r = append(r, this.DestroyAdded) + r = append(r, int(this.StarLv)) + r = append(r, int(this.Star)) + return r +} + +type MyGeneralReq struct { + +} + +type MyGeneralRsp struct { + Generals []General `json:"generals"` +} + + +type ArmyListReq struct { + CityId int `json:"cityId"` +} + +type ArmyListRsp struct { + CityId int `json:"cityId"` + Armys []Army `json:"armys"` +} + + +type ArmyOneReq struct { + CityId int `json:"cityId"` + Order int8 `json:"order"` +} + +type ArmyOneRsp struct { + Army Army `json:"army"` +} + +type Army struct { + Id int `json:"id"` + CityId int `json:"cityId"` + UnionId int `json:"union_id"` //联盟id + Order int8 `json:"order"` //第几队,1-5队 + Generals []int `json:"generals"` + Soldiers []int `json:"soldiers"` + ConTimes []int64 `json:"con_times"` + ConCnts []int `json:"con_cnts"` + Cmd int8 `json:"cmd"` + State int8 `json:"state"` //状态:0:running,1:stop + FromX int `json:"from_x"` + FromY int `json:"from_y"` + ToX int `json:"to_x"` + ToY int `json:"to_y"` + Start int64 `json:"start"`//出征开始时间 + End int64 `json:"end"`//出征结束时间 +} + +//配置武将 +type DisposeReq struct { + CityId int `json:"cityId"` //城市id + GeneralId int `json:"generalId"` //将领id + Order int8 `json:"order"` //第几队,1-5队 + Position int `json:"position"` //位置,-1到2,-1是解除该武将上阵状态 +} + +type DisposeRsp struct { + Army Army `json:"army"` +} + +//征兵 +type ConscriptReq struct { + ArmyId int `json:"armyId"` //队伍id + Cnts []int `json:"cnts"` //征兵人数 +} + +type ConscriptRsp struct { + Army Army `json:"army"` + RoleRes RoleRes `json:"role_res"` +} + +//派遣队伍 +type AssignArmyReq struct { + ArmyId int `json:"armyId"` //队伍id + Cmd int8 `json:"cmd"` //命令:0:空闲 1:攻击 2:驻军 3:返回 + X int `json:"x"` + Y int `json:"y"` +} + +type AssignArmyRsp struct { + Army Army `json:"army"` +} + + +//抽卡 +type DrawGeneralReq struct { + DrawTimes int `json:"drawTimes"` //抽卡次数 +} + +type DrawGeneralRsp struct { + Generals []General `json:"generals"` +} + + + +//合成 +type ComposeGeneralReq struct { + CompId int `json:"compId"` + GIds []int `json:"gIds"` //合成材料 +} + +type ComposeGeneralRsp struct { + Generals []General `json:"generals"` +} + +//加点 +type AddPrGeneralReq struct { + CompId int `json:"compId"` + ForceAdd int `json:"forceAdd"` + StrategyAdd int `json:"strategyAdd"` + DefenseAdd int `json:"defenseAdd"` + SpeedAdd int `json:"speedAdd"` + DestroyAdd int `json:"destroyAdd"` +} + +type AddPrGeneralRsp struct { + Generals General `json:"general"` +} + +type ConvertReq struct { + GIds []int `json:"gIds"` +} + +type ConvertRsp struct { + GIds []int `json:"gIds"` + Gold int `json:"gold"` + AddGold int `json:"add_gold"` +} + +type UpDownSkillReq struct { + GId int `json:"gId"` //武将id + CfgId int `json:"cfgId"` //技能配置id + Pos int `json:"pos"` //位置0-2 +} + +type UpDownSkillRsp struct { + GId int `json:"gId"` //武将id + CfgId int `json:"cfgId"` //技能配置id + Pos int `json:"pos"` //位置0-2 +} + + +type LvSkillReq struct { + GId int `json:"gId"` //武将id + Pos int `json:"pos"` //位置0-2 +} + +type LvSkillRsp struct { + GId int `json:"gId"` //武将id + Pos int `json:"pos"` //位置0-2 +} + diff --git a/server/slgserver/proto/interior.go b/server/slgserver/proto/interior.go new file mode 100644 index 0000000..ddc0508 --- /dev/null +++ b/server/slgserver/proto/interior.go @@ -0,0 +1,29 @@ +package proto + +type CollectionReq struct { +} + +type CollectionRsp struct { + Gold int `json:"gold"` + Limit int8 `json:"limit"` + CurTimes int8 `json:"cur_times"` + NextTime int64 `json:"next_time"` +} + +type OpenCollectionReq struct { +} + +type OpenCollectionRsp struct { + Limit int8 `json:"limit"` + CurTimes int8 `json:"cur_times"` + NextTime int64 `json:"next_time"` +} + +type TransformReq struct { + From []int `json:"from"` //0 Wood 1 Iron 2 Stone 3 Grain + To []int `json:"to"` //0 Wood 1 Iron 2 Stone 3 Grain +} + +type TransformRsp struct { +} + diff --git a/server/slgserver/proto/nation_map.go b/server/slgserver/proto/nation_map.go new file mode 100644 index 0000000..a987af0 --- /dev/null +++ b/server/slgserver/proto/nation_map.go @@ -0,0 +1,104 @@ +package proto + +type Conf struct { + Type int8 `json:"type"` + Level int8 `json:"level"` + Name string `json:"name"` + Wood int `json:"Wood"` + Iron int `json:"iron"` + Stone int `json:"stone"` + Grain int `json:"grain"` + Durable int `json:"durable"` //耐久 + Defender int `json:"defender"` //防御等级 +} + +type ConfigReq struct { + +} + +type ConfigRsp struct { + Confs []Conf +} + + +type MapRoleBuild struct { + RId int `json:"rid"` + RNick string `json:"RNick"` //角色昵称 + Name string `json:"name"` + UnionId int `json:"union_id"` //联盟id + UnionName string `json:"union_name"` //联盟名字 + ParentId int `json:"parent_id"` //上级id + X int `json:"x"` + Y int `json:"y"` + Type int8 `json:"type"` + Level int8 `json:"level"` + OPLevel int8 `json:"op_level"` + CurDurable int `json:"cur_durable"` + MaxDurable int `json:"max_durable"` + Defender int `json:"defender"` + OccupyTime int64 `json:"occupy_time"` + EndTime int64 `json:"end_time"` //建造完的时间 + GiveUpTime int64 `json:"giveUp_time"` //领地到了这个时间会被放弃 +} + + +type ScanReq struct { + X int `json:"x"` + Y int `json:"y"` +} + +type ScanRsp struct { + MRBuilds []MapRoleBuild `json:"mr_builds"` //角色建筑,包含被占领的基础建筑 + MCBuilds []MapRoleCity `json:"mc_builds"` //角色城市 + Armys []Army `json:"armys"` //军队 +} + +type ScanBlockReq struct { + X int `json:"x"` + Y int `json:"y"` + Length int `json:"length"` +} + +type GiveUpReq struct { + X int `json:"x"` + Y int `json:"y"` +} + +type GiveUpRsp struct { + X int `json:"x"` + Y int `json:"y"` +} + +type BuildReq struct { + X int `json:"x"` + Y int `json:"y"` + Type int8 `json:"type"` +} + +type BuildRsp struct { + X int `json:"x"` + Y int `json:"y"` + Type int8 `json:"type"` +} + +type UpBuildReq struct { + X int `json:"x"` + Y int `json:"y"` +} + +type UpBuildRsp struct { + X int `json:"x"` + Y int `json:"y"` + Build MapRoleBuild `json:"build"` +} + +type DelBuildReq struct { + X int `json:"x"` + Y int `json:"y"` +} + +type DelBuildRsp struct { + X int `json:"x"` + Y int `json:"y"` + Build MapRoleBuild `json:"build"` +} \ No newline at end of file diff --git a/server/slgserver/proto/role.go b/server/slgserver/proto/role.go new file mode 100644 index 0000000..25b3aa5 --- /dev/null +++ b/server/slgserver/proto/role.go @@ -0,0 +1,154 @@ +package proto + +type Role struct { + RId int `json:"rid"` + UId int `json:"uid"` + NickName string `json:"nickName"` + Sex int8 `json:"sex"` + Balance int `json:"balance"` + HeadId int16 `json:"headId"` + Profile string `json:"profile"` +} + +type RoleRes struct { + Wood int `json:"wood"` + Iron int `json:"iron"` + Stone int `json:"stone"` + Grain int `json:"grain"` + Gold int `json:"gold"` + Decree int `json:"decree"` //令牌 + WoodYield int `json:"wood_yield"` + IronYield int `json:"iron_yield"` + StoneYield int `json:"stone_yield"` + GrainYield int `json:"grain_yield"` + GoldYield int `json:"gold_yield"` + DepotCapacity int `json:"depot_capacity"` //仓库容量 +} + +type CreateRoleReq struct { + UId int `json:"uid"` + NickName string `json:"nickName"` + Sex int8 `json:"sex"` + SId int `json:"sid"` + HeadId int16 `json:"headId"` +} + +type CreateRoleRsp struct { + Role Role `json:"role"` +} + +type RoleListReq struct { + UId int `json:"uid"` +} + +type RoleListRsp struct { + Roles []Role +} + +type EnterServerReq struct { + Session string `json:"session"` +} + +type EnterServerRsp struct { + Role Role `json:"role"` + RoleRes RoleRes `json:"role_res"` + Time int64 `json:"time"` + Token string `json:"token"` +} + +type MapRoleCity struct { + CityId int `json:"cityId"` + RId int `json:"rid"` + Name string `json:"name"` + UnionId int `json:"union_id"` //联盟id + UnionName string `json:"union_name"` //联盟名字 + ParentId int `json:"parent_id"` //上级id + X int `json:"x"` + Y int `json:"y"` + IsMain bool `json:"is_main"` + Level int8 `json:"level"` + CurDurable int `json:"cur_durable"` + MaxDurable int `json:"max_durable"` + OccupyTime int64 `json:"occupy_time"` +} + +type MyCityReq struct { + +} + +type MyCityRsp struct { + Citys []MapRoleCity `json:"citys"` +} + +type MyRoleResReq struct { + +} + +type MyRoleResRsp struct { + RoleRes RoleRes `json:"role_res"` +} + +type MyRoleBuildReq struct { + +} + +type MyRoleBuildRsp struct { + MRBuilds []MapRoleBuild `json:"mr_builds"` //角色建筑,包含被占领的基础建筑 +} + +/* +建筑发生变化 +*/ +type RoleBuildStatePush struct { + MRBuild MapRoleBuild `json:"mr_build"` //角色建筑,包含被占领的基础建筑 +} + +type MyRolePropertyReq struct { + +} + +type MyRolePropertyRsp struct { + RoleRes RoleRes `json:"role_res"` + MRBuilds []MapRoleBuild `json:"mr_builds"` //角色建筑,包含被占领的基础建筑 + Generals []General `json:"generals"` + Citys []MapRoleCity `json:"citys"` + Armys []Army `json:"armys"` +} + +type UpPositionReq struct { + X int `json:"x"` + Y int `json:"y"` +} + +type UpPositionRsp struct { + X int `json:"x"` + Y int `json:"y"` +} + +type PosTag struct { + X int `json:"x"` + Y int `json:"y"` + Name string `json:"name"` +} + +type PosTagListReq struct { + +} + +type PosTagListRsp struct { + PosTags []PosTag `json:"pos_tags"` +} + +type PosTagReq struct { + Type int `json:"type"` //1是标记,0是取消标记 + X int `json:"x"` + Y int `json:"y"` + Name string `json:"name"` +} + +type PosTagRsp struct { + Type int `json:"type"` //1是标记,0是取消标记 + X int `json:"x"` + Y int `json:"y"` + Name string `json:"name"` +} diff --git a/server/slgserver/proto/skill.go b/server/slgserver/proto/skill.go new file mode 100644 index 0000000..3bdab11 --- /dev/null +++ b/server/slgserver/proto/skill.go @@ -0,0 +1,16 @@ +package proto + + +type Skill struct { + Id int `json:"id"` + CfgId int `json:"cfgId"` + Generals []int `json:"generals"` +} + +type SkillListReq struct { + +} + +type SkillListRsp struct { + List []Skill `json:"list"` +} \ No newline at end of file diff --git a/server/slgserver/proto/war.go b/server/slgserver/proto/war.go new file mode 100644 index 0000000..74e1941 --- /dev/null +++ b/server/slgserver/proto/war.go @@ -0,0 +1,45 @@ +package proto + +type WarReport struct { + Id int `json:"id"` + AttackRid int `json:"a_rid"` + DefenseRid int `json:"d_rid"` + BegAttackArmy string `json:"b_a_army"` + BegDefenseArmy string `json:"b_d_army"` + EndAttackArmy string `json:"e_a_army"` + EndDefenseArmy string `json:"e_d_army"` + BegAttackGeneral string `json:"b_a_general"` + BegDefenseGeneral string `json:"b_d_general"` + EndAttackGeneral string `json:"e_a_general"` + EndDefenseGeneral string `json:"e_d_general"` + Result int `json:"result"` //0失败,1打平,2胜利 + Rounds string `json:"rounds"` //回合 + AttackIsRead bool `json:"a_is_read"` + DefenseIsRead bool `json:"d_is_read"` + DestroyDurable int `json:"destroy"` + Occupy int `json:"occupy"` + X int `json:"x"` + Y int `json:"y"` + CTime int `json:"ctime"` +} + + +type WarReportPush struct { + List []WarReport `json:"list"` +} + +type WarReportReq struct { + +} + +type WarReportRsp struct { + List []WarReport `json:"list"` +} + +type WarReadReq struct { + Id uint `json:"id"` //0全部已读 +} + +type WarReadRsp struct { + Id uint `json:"id"` +} \ No newline at end of file diff --git a/server/slgserver/run/init.go b/server/slgserver/run/init.go new file mode 100644 index 0000000..789fdf3 --- /dev/null +++ b/server/slgserver/run/init.go @@ -0,0 +1,65 @@ +package run + +import ( + "slgserver/config" + "slgserver/db" + "slgserver/net" + "slgserver/server/slgserver/controller" + "slgserver/server/slgserver/logic" + "slgserver/server/slgserver/logic/mgr" + "slgserver/server/slgserver/model" + "slgserver/server/slgserver/static_conf" + "slgserver/server/slgserver/static_conf/facility" + "slgserver/server/slgserver/static_conf/general" + "slgserver/server/slgserver/static_conf/skill" +) + +var MyRouter = &net.Router{} + +func Init() { + db.TestDB() + + facility.FConf.Load() + general.GenBasic.Load() + skill.Skill.Load() + + general.General.Load() + static_conf.Basic.Load() + static_conf.MapBuildConf.Load() + static_conf.MapBCConf.Load() + + serverId := config.GetInt("logic.server_id", 1) + model.ServerId = serverId + + logic.BeforeInit() + + mgr.NMMgr.Load() + //需要先加载联盟相关的信息 + mgr.UnionMgr.Load() + mgr.RAttrMgr.Load() + mgr.RCMgr.Load() + mgr.RBMgr.Load() + mgr.RFMgr.Load() + mgr.RResMgr.Load() + mgr.SkillMgr.Load() + mgr.GMgr.Load() + mgr.AMgr.Load() + logic.Init() + logic.AfterInit() + + //全部初始化完才注册路由,防止服务器还没启动就绪收到请求 + initRouter() +} + +func initRouter() { + + controller.DefaultRole.InitRouter(MyRouter) + controller.DefaultMap.InitRouter(MyRouter) + controller.DefaultCity.InitRouter(MyRouter) + controller.DefaultGeneral.InitRouter(MyRouter) + controller.DefaultArmy.InitRouter(MyRouter) + controller.DefaultWar.InitRouter(MyRouter) + controller.DefaultCoalition.InitRouter(MyRouter) + controller.DefaultInterior.InitRouter(MyRouter) + controller.DefaultSkill.InitRouter(MyRouter) +} \ No newline at end of file diff --git a/server/slgserver/static_conf/basic.go b/server/slgserver/static_conf/basic.go new file mode 100644 index 0000000..b05549b --- /dev/null +++ b/server/slgserver/static_conf/basic.go @@ -0,0 +1,119 @@ +package static_conf + +import ( + "encoding/json" + "log/slog" + "os" + "path" + "slgserver/config" +) + +var Basic basic + +type conscript struct { + Des string `json:"des"` + CostWood int `json:"cost_wood"` + CostIron int `json:"cost_iron"` + CostStone int `json:"cost_stone"` + CostGrain int `json:"cost_grain"` + CostGold int `json:"cost_gold"` + CostTime int `json:"cost_time"` //每征一个兵需要花费时间 +} + +type general struct { + Des string `json:"des"` + PhysicalPowerLimit int `json:"physical_power_limit"` //体力上限 + CostPhysicalPower int `json:"cost_physical_power"` //消耗体力 + RecoveryPhysicalPower int `json:"recovery_physical_power"` //恢复体力 + ReclamationTime int `json:"reclamation_time"` //屯田消耗时间,单位秒 + ReclamationCost int `json:"reclamation_cost"` //屯田消耗政令 + DrawGeneralCost int `json:"draw_general_cost"` //抽卡消耗金币 + PrPoint int `json:"pr_point"` //合成一个武将或者的技能点 + Limit int `json:"limit"` //武将数量上限 + +} + +type role struct { + Des string `json:"des"` + Wood int `json:"wood"` + Iron int `json:"iron"` + Stone int `json:"stone"` + Grain int `json:"grain"` + Gold int `json:"gold"` + Decree int `json:"decree"` + WoodYield int `json:"wood_yield"` + IronYield int `json:"iron_yield"` + StoneYield int `json:"stone_yield"` + GrainYield int `json:"grain_yield"` + GoldYield int `json:"gold_yield"` + DepotCapacity int `json:"depot_capacity"` //仓库初始容量 + BuildLimit int `json:"build_limit"` //野外建筑上限 + RecoveryTime int `json:"recovery_time"` + DecreeLimit int `json:"decree_limit"` //令牌上限 + CollectTimesLimit int8 `json:"collect_times_limit"` //每日征收次数上限 + CollectInterval int `json:"collect_interval"` //征收间隔 + PosTagLimit int8 `json:"pos_tag_limit"` //位置标签上限 +} + +type city struct { + Des string `json:"des"` + Cost int8 `json:"cost"` + Durable int `json:"durable"` + RecoveryTime int `json:"recovery_time"` + TransformRate int `json:"transform_rate"` +} + +type build struct { + Des string `json:"des"` + WarFree int64 `json:"war_free"` //免战时间,单位秒 + GiveUpTime int64 `json:"giveUp_time"` //建筑放弃时间 + FortressLimit int `json:"fortress_limit"` //要塞上限 +} + +type npcLevel struct { + Soilders int `json:"soilders"` +} + +type npc struct { + Des string `json:"des"` + Levels []npcLevel `json:"levels"` +} + +type union struct { + Des string `json:"des"` + MemberLimit int `json:"member_limit"` +} + +type basic struct { + ConScript conscript `json:"conscript"` + General general `json:"general"` + Role role `json:"role"` + City city `json:"city"` + Npc npc `json:"npc"` + Union union `json:"union"` + Build build `json:"build"` +} + +func (this *basic) Load() { + jsonDir := config.GetPath("logic.json_data", "data/conf/json/") + fileName := path.Join(jsonDir, "basic.json") + jdata, err := os.ReadFile(fileName) + if err != nil { + slog.Error("basic load file error", "error", err, "file", fileName) + os.Exit(0) + } + + json.Unmarshal(jdata, this) + + slog.Debug("basic config loaded") +} + +func (this *basic) GetNPC(level int8) (*npcLevel, bool) { + if level <= 0 { + return nil, false + } + if len(this.Npc.Levels) >= int(level) { + return &this.Npc.Levels[level-1], true + } + return nil, false +} diff --git a/server/slgserver/static_conf/facility/facility.go b/server/slgserver/static_conf/facility/facility.go new file mode 100644 index 0000000..da1c6f4 --- /dev/null +++ b/server/slgserver/static_conf/facility/facility.go @@ -0,0 +1,58 @@ +package facility + +import ( + "encoding/json" + "log/slog" + "os" +) + +type conditions struct { + Type int `json:"type"` + Level int `json:"level"` +} + +type facility struct { + Title string `json:"title"` + Des string `json:"des"` + Name string `json:"name"` + Type int8 `json:"type"` + Additions []int8 `json:"additions"` + Conditions []conditions `json:"conditions"` + Levels []fLevel `json:"levels"` +} + +type NeedRes struct { + Decree int `json:"decree"` + Grain int `json:"grain"` + Wood int `json:"wood"` + Iron int `json:"iron"` + Stone int `json:"stone"` + Gold int `json:"gold"` +} + +type fLevel struct { + Level int `json:"level"` + Values []int `json:"values"` + Need NeedRes `json:"need"` + Time int `json:"time"` //升级需要的时间 +} + +func NewFacility(jsonName string) *facility { + f := &facility{} + f.load(jsonName) + return f +} + +func (this *facility) load(jsonName string) { + + jdata, err := os.ReadFile(jsonName) + if err != nil { + slog.Error("facility load file error", + "error", err, "file", jsonName) + os.Exit(0) + } + + json.Unmarshal(jdata, this) + + slog.Debug("facility file loaded", "name", this.Name) +} diff --git a/server/slgserver/static_conf/facility/facility_addition.go b/server/slgserver/static_conf/facility/facility_addition.go new file mode 100644 index 0000000..1928274 --- /dev/null +++ b/server/slgserver/static_conf/facility/facility_addition.go @@ -0,0 +1,31 @@ +package facility + + +const ( + TypeDurable = 1 //耐久 + TypeCost = 2 + TypeArmyTeams = 3 //队伍数量 + TypeSpeed = 4 //速度 + TypeDefense = 5 //防御 + TypeStrategy = 6 //谋略 + TypeForce = 7 //攻击武力 + TypeConscriptTime = 8 //征兵时间 + TypeReserveLimit = 9 //预备役上限 + TypeUnkonw = 10 + TypeHanAddition = 11 + TypeQunAddition = 12 + TypeWeiAddition = 13 + TypeShuAddition = 14 + TypeWuAddition = 15 + TypeDealTaxRate = 16//交易税率 + TypeWood = 17 + TypeIron = 18 + TypeGrain = 19 + TypeStone = 20 + TypeTax = 21//税收 + TypeExtendTimes = 22//扩建次数 + TypeWarehouseLimit = 23//仓库容量 + TypeSoldierLimit = 24//带兵数量 + TypeVanguardLimit = 25//前锋数量 +) + diff --git a/server/slgserver/static_conf/facility/facility_conf.go b/server/slgserver/static_conf/facility/facility_conf.go new file mode 100644 index 0000000..cf0a03e --- /dev/null +++ b/server/slgserver/static_conf/facility/facility_conf.go @@ -0,0 +1,134 @@ +package facility + +import ( + "encoding/json" + "log/slog" + "os" + "path" + "slgserver/config" +) + +const ( + Main = 0 //主城 + JiaoChang = 13 //校场 + TongShuaiTing = 14 //统帅厅 + JiShi = 15 //集市 + MBS = 16 //募兵所 +) + +var FConf facilityConf + +type conf struct { + Name string + Type int8 +} + +type facilityConf struct { + Title string `json:"title"` + List []conf `json:"list"` + facilitys map[int8]*facility +} + +func (this *facilityConf) Load() { + this.facilitys = make(map[int8]*facility, 0) + jsonDir := config.GetPath("logic.json_data", "data/conf/json/") + fileName := path.Join(jsonDir, "facility", "facility.json") + jdata, err := os.ReadFile(fileName) + if err != nil { + slog.Error("facilityConf load file error", + "error", err, + "file", fileName) + os.Exit(0) + } + + json.Unmarshal(jdata, this) + + fdir := path.Join(jsonDir, "facility") + files, err := os.ReadDir(fdir) + if err != nil { + return + } + for _, file := range files { + if file.IsDir() { + continue + } else { + if file.Name() == "facility.json" || file.Name() == "facility_addition.json" { + continue + } + fileName := path.Join(fdir, file.Name()) + f := NewFacility(fileName) + this.facilitys[f.Type] = f + } + } + slog.Debug("facility config loaded", "count", len(this.facilitys)) +} + +func (this *facilityConf) MaxLevel(fType int8) int8 { + f, ok := this.facilitys[fType] + if ok { + return int8(len(f.Levels)) + } else { + return 0 + } +} + +func (this *facilityConf) Need(fType int8, level int8) (*NeedRes, bool) { + if level <= 0 { + return nil, false + } + + f, ok := this.facilitys[fType] + if ok { + if int8(len(f.Levels)) >= level { + return &f.Levels[level-1].Need, true + } else { + return nil, false + } + } else { + return nil, false + } +} + +// 升级需要的时间 +func (this *facilityConf) CostTime(fType int8, level int8) int { + if level <= 0 { + return 0 + } + + f, ok := this.facilitys[fType] + if ok { + if int8(len(f.Levels)) >= level { + return f.Levels[level-1].Time - 2 //比客户端快2s,保证客户端倒计时完一定是升级成功了 + } else { + return 0 + } + } else { + return 0 + } +} + +func (this *facilityConf) GetValues(fType int8, level int8) []int { + if level <= 0 { + return []int{} + } + + f, ok := this.facilitys[fType] + if ok { + if int8(len(f.Levels)) >= level { + return f.Levels[level-1].Values + } else { + return []int{} + } + } else { + return []int{} + } +} + +func (this *facilityConf) GetAdditions(fType int8) []int8 { + f, ok := this.facilitys[fType] + if ok { + return f.Additions + } else { + return []int8{} + } +} diff --git a/server/slgserver/static_conf/general/general.go b/server/slgserver/static_conf/general/general.go new file mode 100644 index 0000000..6326862 --- /dev/null +++ b/server/slgserver/static_conf/general/general.go @@ -0,0 +1,85 @@ +package general + +import ( + "encoding/json" + "log/slog" + "math/rand" + "os" + "path" + "slgserver/config" + "time" +) + +var General general + +type g struct { + Name string `json:"name"` + CfgId int `json:"cfgId"` + Force int `json:"force"` + Strategy int `json:"strategy"` + Defense int `json:"defense"` + Speed int `json:"speed"` + Destroy int `json:"destroy"` + ForceGrow int `json:"force_grow"` + StrategyGrow int `json:"strategy_grow"` + DefenseGrow int `json:"defense_grow"` + SpeedGrow int `json:"speed_grow"` + DestroyGrow int `json:"destroy_grow"` + Cost int8 `json:"cost"` + Probability int `json:"probability"` + Star int8 `json:"star"` + Arms []int `json:"arms"` + Camp int8 `json:"camp"` +} + +type general struct { + Title string `json:"title"` + GArr []g `json:"list"` + GMap map[int]g + totalProbability int +} + +func (this *general) Load() { + jsonDir := config.GetPath("logic.json_data", "data/conf/json/") + fileName := path.Join(jsonDir, "general", "general.json") + jdata, err := os.ReadFile(fileName) + if err != nil { + slog.Error("general load file error", + "error", err, + "file", fileName) + os.Exit(0) + } + + this.totalProbability = 0 + + json.Unmarshal(jdata, this) + this.GMap = make(map[int]g) + for _, v := range this.GArr { + this.GMap[v.CfgId] = v + this.totalProbability += v.Probability + } + slog.Debug("general config loaded", "count", len(this.GArr)) +} + +func (this *general) Cost(cfgId int) int8 { + c, ok := this.GMap[cfgId] + if ok { + return c.Cost + } else { + return 0 + } +} + +func (this *general) Draw() int { + rand.Seed(time.Now().UnixNano()) + rate := rand.Intn(this.totalProbability) + + cur := 0 + for _, g := range this.GArr { + if rate >= cur && rate < cur+g.Probability { + return g.CfgId + } + cur += g.Probability + } + return 0 +} diff --git a/server/slgserver/static_conf/general/general_arms.go b/server/slgserver/static_conf/general/general_arms.go new file mode 100644 index 0000000..36f74da --- /dev/null +++ b/server/slgserver/static_conf/general/general_arms.go @@ -0,0 +1,67 @@ +package general + +import ( + "encoding/json" + "log/slog" + "os" + "path" + "slgserver/config" +) + +var GenArms Arms + +type gArmsCondition struct { + Level int `json:"level"` + StarLevel int `json:"star_lv"` +} + +type gArmsCost struct { + Gold int `json:"gold"` +} + +type gArms struct { + Id int `json:"id"` + Name string `json:"name"` + Condition gArmsCondition `json:"condition"` + ChangeCost gArmsCost `json:"change_cost"` + HarmRatio []int `json:"harm_ratio"` +} + +type Arms struct { + Title string `json:"title"` + Arms []gArms `json:"arms"` + AMap map[int]gArms +} + +func (this *Arms) Load() { + jsonDir := config.GetPath("logic.json_data", "data/conf/json/") + fileName := path.Join(jsonDir, "general", "general_arms.json") + jdata, err := os.ReadFile(fileName) + if err != nil { + slog.Error("general load file error", "error", err, "file", fileName) + os.Exit(0) + } + + json.Unmarshal(jdata, this) + + this.AMap = make(map[int]gArms) + for _, v := range this.Arms { + this.AMap[v.Id] = v + } + + slog.Debug("general arms loaded", "count", len(this.Arms)) +} + +func (this *Arms) GetArm(id int) (gArms, error) { + return this.AMap[id], nil +} + +func (this *Arms) GetHarmRatio(attId, defId int) float64 { + attArm, ok1 := this.AMap[attId] + _, ok2 := this.AMap[defId] + if ok1 && ok2 { + return float64(attArm.HarmRatio[defId-1]) / 100.0 + } else { + return 1.0 + } +} diff --git a/server/slgserver/static_conf/general/general_basic.go b/server/slgserver/static_conf/general/general_basic.go new file mode 100644 index 0000000..386ccb5 --- /dev/null +++ b/server/slgserver/static_conf/general/general_basic.go @@ -0,0 +1,67 @@ +package general + +import ( + "encoding/json" + "errors" + "log/slog" + "os" + "path" + "slgserver/config" +) + +var GenBasic Basic + +type gLevel struct { + Level int8 `json:"level"` + Exp int `json:"exp"` + Soldiers int `json:"soldiers"` +} + +type Basic struct { + Title string `json:"title"` + Levels []gLevel `json:"levels"` +} + +func (this *Basic) Load() { + jsonDir := config.GetPath("logic.json_data", "data/conf/json/") + fileName := path.Join(jsonDir, "general", "general_basic.json") + jdata, err := os.ReadFile(fileName) + if err != nil { + slog.Error("general load file error", "error", err, "file", fileName) + os.Exit(0) + } + + json.Unmarshal(jdata, this) + + slog.Debug("general basic config loaded", "levels", len(this.Levels)) + + General.Load() + GenArms.Load() +} + +func (this *Basic) GetLevel(l int8) (*gLevel, error) { + if l <= 0 { + return nil, errors.New("level error") + } + if int(l) <= len(this.Levels) { + return &this.Levels[l-1], nil + } else { + return nil, errors.New("level error") + } +} + +func (this *Basic) ExpToLevel(exp int) (int8, int) { + var level int8 = 0 + limitExp := this.Levels[len(this.Levels)-1].Exp + for _, v := range this.Levels { + if exp >= v.Exp && v.Level > level { + level = v.Level + } + } + + if limitExp < exp { + return level, limitExp + } else { + return level, exp + } +} diff --git a/server/slgserver/static_conf/map_build.go b/server/slgserver/static_conf/map_build.go new file mode 100644 index 0000000..f05c87f --- /dev/null +++ b/server/slgserver/static_conf/map_build.go @@ -0,0 +1,64 @@ +package static_conf + +import ( + "encoding/json" + "log/slog" + "os" + "path" + "slgserver/config" +) + +// 地图资源配置 +var MapBuildConf mapBuildConf + +type cfg struct { + Type int8 `json:"type"` + Name string `json:"name"` + Level int8 `json:"level"` + Grain int `json:"grain"` + Wood int `json:"wood"` + Iron int `json:"iron"` + Stone int `json:"stone"` + Durable int `json:"durable"` + Defender int `json:"defender"` +} + +type mapBuildConf struct { + Title string `json:"title"` + Cfg []cfg `json:"cfg"` + cfgMap map[int8][]cfg +} + +func (this *mapBuildConf) Load() { + jsonDir := config.GetPath("logic.json_data", "data/conf/json/") + fileName := path.Join(jsonDir, "map_build.json") + jdata, err := os.ReadFile(fileName) + if err != nil { + slog.Error("mapBuildConf load file error", "error", err, "file", fileName) + os.Exit(0) + } + + json.Unmarshal(jdata, this) + + this.cfgMap = make(map[int8][]cfg) + for _, v := range this.Cfg { + if _, ok := this.cfgMap[v.Type]; ok == false { + this.cfgMap[v.Type] = make([]cfg, 0) + } + this.cfgMap[v.Type] = append(this.cfgMap[v.Type], v) + } + + slog.Debug("map build config loaded", "types", len(this.cfgMap)) +} + +func (this *mapBuildConf) BuildConfig(cfgType int8, level int8) (*cfg, bool) { + if c, ok := this.cfgMap[cfgType]; ok { + for _, v := range c { + if v.Level == level { + return &v, true + } + } + } + + return nil, false +} diff --git a/server/slgserver/static_conf/map_build_custom.go b/server/slgserver/static_conf/map_build_custom.go new file mode 100644 index 0000000..768d820 --- /dev/null +++ b/server/slgserver/static_conf/map_build_custom.go @@ -0,0 +1,94 @@ +package static_conf + +import ( + "encoding/json" + "log/slog" + "os" + "path" + "slgserver/config" + "slgserver/server/slgserver/static_conf/facility" +) + +// 地图资源配置 +var MapBCConf mapBuildCustomConf + +type level struct { + Level int8 `json:"level"` + Time int `json:"time"` //升级需要的时间 + Durable int `json:"durable"` + Defender int `json:"defender"` + Need facility.NeedRes `json:"need"` + Result result `json:"result"` +} + +type customConf struct { + Type int8 `json:"type"` + Name string `json:"name"` + Levels []level `json:"levels"` +} + +type result struct { + ArmyCnt int `json:"army_cnt"` +} + +type BCLevelCfg struct { + level + Type int8 `json:"type"` + Name string `json:"name"` +} + +type mapBuildCustomConf struct { + Title string `json:"title"` + Cfg []customConf `json:"cfg"` + cfgMap map[int8]customConf +} + +func (this *mapBuildCustomConf) Load() { + jsonDir := config.GetPath("logic.json_data", "data/conf/json/") + fileName := path.Join(jsonDir, "map_build_custom.json") + jdata, err := os.ReadFile(fileName) + if err != nil { + slog.Error("mapBuildCustomConf load file error", + "error", err, + "file", fileName) + os.Exit(0) + } + + json.Unmarshal(jdata, this) + + this.cfgMap = make(map[int8]customConf) + for _, v := range this.Cfg { + this.cfgMap[v.Type] = v + } + + slog.Debug("map build custom config loaded", "types", len(this.cfgMap)) +} + +func (this *mapBuildCustomConf) BuildConfig(cfgType int8, level int8) (*BCLevelCfg, bool) { + if c, ok := this.cfgMap[cfgType]; ok { + if len(c.Levels) < int(level) { + return nil, false + } + + lc := c.Levels[level-1] + cfg := BCLevelCfg{Type: cfgType, Name: c.Name} + cfg.Level = level + cfg.Need = lc.Need + cfg.Result = lc.Result + cfg.Durable = lc.Durable + cfg.Time = lc.Time + cfg.Result = lc.Result + + return &cfg, true + } + return nil, false +} + +// 可容纳队伍数量 +func (this *mapBuildCustomConf) GetHoldArmyCnt(cfgType int8, level int8) int { + cfg, ok := this.BuildConfig(cfgType, level) + if ok == false { + return 0 + } + return cfg.Result.ArmyCnt +} diff --git a/server/slgserver/static_conf/skill/skill.go b/server/slgserver/static_conf/skill/skill.go new file mode 100644 index 0000000..1a65e1d --- /dev/null +++ b/server/slgserver/static_conf/skill/skill.go @@ -0,0 +1,73 @@ +package skill + +import ( + "encoding/json" + "log/slog" + "os" + "path" + "slgserver/config" +) + +var Skill skill + +type skill struct { + skills []Conf + skillConfMap map[int]Conf + outline outline +} + +func (this *skill) Load() { + this.skills = make([]Conf, 0) + this.skillConfMap = make(map[int]Conf) + + jsonDir := config.GetPath("logic.json_data", "data/conf/json/") + fileName := path.Join(jsonDir, "skill", "skill_outline.json") + jdata, err := os.ReadFile(fileName) + if err != nil { + slog.Error("skill load file error", "error", err, "file", fileName) + os.Exit(0) + } + + json.Unmarshal(jdata, &this.outline) + + rd, err := os.ReadDir(path.Join(jsonDir, "skill")) + if err != nil { + slog.Error("skill readdir error", "error", err) + os.Exit(0) + } + + for _, r := range rd { + if r.IsDir() { + this.readSkill(path.Join(jsonDir, "skill", r.Name())) + } + } + + slog.Debug("skill configs loaded", "count", len(this.skills)) +} + +func (this *skill) readSkill(dir string) { + rd, err := os.ReadDir(dir) + if err == nil { + for _, r := range rd { + if r.IsDir() == false { + jdata, err := os.ReadFile(path.Join(dir, r.Name())) + if err == nil { + conf := Conf{} + if err := json.Unmarshal(jdata, &conf); err == nil { + this.skills = append(this.skills, conf) + this.skillConfMap[conf.CfgId] = conf + } else { + slog.Warn("Unmarshal skill error", "error", err, + "file", path.Join(dir, r.Name())) + } + } + } + } + } + +} + +func (this *skill) GetCfg(cfgId int) (Conf, bool) { + cfg, ok := this.skillConfMap[cfgId] + return cfg, ok +} diff --git a/server/slgserver/static_conf/skill/skill_conf.go b/server/slgserver/static_conf/skill/skill_conf.go new file mode 100644 index 0000000..acd75df --- /dev/null +++ b/server/slgserver/static_conf/skill/skill_conf.go @@ -0,0 +1,19 @@ +package skill + +type level struct { + Probability int `json:"probability"` //发动概率 + EffectValue []int `json:"effect_value"` //效果值 + EffectRound []int `json:"effect_round"` //效果持续回合数 +} + +type Conf struct { + CfgId int `json:"cfgId"` + Name string `json:"name"` + Trigger int `json:"trigger"` //发起类型 + Target int `json:"target"` //目标类型 + Des string `json:"des"` + Limit int `json:"limit"` //可以被武将装备上限 + Arms []int `json:"arms"` //可以装备的兵种 + IncludeEffect []int `json:"include_effect"` //技能包括的效果 + Levels []level `json:"levels"` +} diff --git a/server/slgserver/static_conf/skill/skill_outline.go b/server/slgserver/static_conf/skill/skill_outline.go new file mode 100644 index 0000000..d3e6049 --- /dev/null +++ b/server/slgserver/static_conf/skill/skill_outline.go @@ -0,0 +1,39 @@ +package skill + +type trigger struct { + Type int `json:"type"` + Des string `json:"des"` +} + +type triggerType struct { + Des string `json:"des"` + List [] trigger `json:"list"` +} + +type effect struct { + Type int `json:"type"` + Des string `json:"des"` + IsRate bool `json:"isRate"` +} + +type effectType struct { + Des string `json:"des"` + List [] effect `json:"list"` +} + +type target struct { + Type int `json:"type"` + Des string `json:"des"` +} + +type targetType struct { + Des string `json:"des"` + List [] target `json:"list"` +} + + +type outline struct { + TriggerType triggerType `json:"trigger_type"` //触发类型 + EffectType effectType `json:"effect_type"` //效果类型 + TargetType targetType `json:"target_type"` //目标类型 +} diff --git a/shell/build.bat b/shell/build.bat new file mode 100644 index 0000000..f410654 --- /dev/null +++ b/shell/build.bat @@ -0,0 +1,10 @@ +set CGO_ENABLED=0 +set GO111MODULE=on +set GOOS=linux +set GIN_MODE=release + +go build -o ../bin/chatserver ../main/chatserver.go +go build -o ../bin/gateserver ../main/gateserver.go +go build -o ../bin/httpserver ../main/httpserver.go +go build -o ../bin/loginserver ../main/loginserver.go +go build -o ../bin/slgserver ../main/slgserver.go diff --git a/shell/copydata.bat b/shell/copydata.bat new file mode 100644 index 0000000..09fc1be --- /dev/null +++ b/shell/copydata.bat @@ -0,0 +1 @@ +xcopy ..\data ..\bin /e /i /y \ No newline at end of file diff --git a/util/crypto.go b/util/crypto.go new file mode 100644 index 0000000..c2b94fa --- /dev/null +++ b/util/crypto.go @@ -0,0 +1,71 @@ +package util + +import ( + "bytes" + "compress/gzip" + "crypto/md5" + "encoding/binary" + "encoding/hex" + "fmt" + "github.com/go-think/openssl" + "io" +) + +func AesCBCEncrypt(src, key, iv []byte, padding string) ([]byte, error) { + data, err := openssl.AesCBCEncrypt(src, key, iv, padding) + if err != nil { + return nil, err + } + return []byte(hex.EncodeToString(data)), nil +} + +func AesCBCDecrypt(src, key, iv []byte, padding string) ([]byte, error) { + data, err := hex.DecodeString(string(src)) + if err != nil { + return nil, err + } + return openssl.AesCBCDecrypt(data, key, iv, padding) + +} +func Md5(text string) string { + hashMd5 := md5.New() + io.WriteString(hashMd5, text) + return fmt.Sprintf("%x", hashMd5.Sum(nil)) +} + +func Zip(data []byte) ([]byte, error) { + + var b bytes.Buffer + gz, _ := gzip.NewWriterLevel(&b, 9) + if _, err := gz.Write([]byte(data)); err != nil { + return nil, err + } + if err := gz.Flush(); err != nil { + return nil, err + } + if err := gz.Close(); err != nil { + return nil, err + } + return b.Bytes(), nil +} + +func UnZip(data []byte) ([]byte, error) { + b := new(bytes.Buffer) + binary.Write(b, binary.LittleEndian, data) + r, err := gzip.NewReader(b) + if err != nil { + return nil, err + } + defer r.Close() + + unzipData, err := io.ReadAll(r) + if err != nil { + return nil, err + } + + return unzipData, nil +} + +func Password(pwd string, pwdCode string) string { + return Md5(pwd + pwdCode) +} diff --git a/util/math.go b/util/math.go new file mode 100644 index 0000000..4ccbe09 --- /dev/null +++ b/util/math.go @@ -0,0 +1,24 @@ +package util + +func MinInt(x, y int) int{ + if x>y { + return y + } + return x +} + +func MaxInt(x, y int) int{ + if x 0{ + return x + }else { + return -x + } +} + diff --git a/util/msgpack.go b/util/msgpack.go new file mode 100644 index 0000000..8f7bc48 --- /dev/null +++ b/util/msgpack.go @@ -0,0 +1,21 @@ +package util + +import ( + "encoding/json" +) + +func Unmarshal(data []byte, v interface{}) error { + //dec := msgpack.NewDecoder(bytes.NewReader(data)) + //dec.UseJSONTag(true) + //return dec.Decode(v) + return json.Unmarshal(data, v) +} + +func Marshal(v interface{}) ([]byte, error) { + //var buf bytes.Buffer + //enc := msgpack.NewEncoder(&buf) + //enc.UseJSONTag(true) + //err := enc.Encode(v) + //return buf.Bytes(), err + return json.Marshal(v) +} diff --git a/util/random.go b/util/random.go new file mode 100644 index 0000000..a2a308e --- /dev/null +++ b/util/random.go @@ -0,0 +1,13 @@ +package util + +import "math/rand" + +var letters = []rune("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func RandSeq(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} diff --git a/util/session.go b/util/session.go new file mode 100644 index 0000000..bc0211c --- /dev/null +++ b/util/session.go @@ -0,0 +1,65 @@ +package util + +import ( + "encoding/base64" + "errors" + "fmt" + "github.com/go-think/openssl" + "strconv" + "strings" + "time" +) + +//有效时间30天 +const validTime = 30*24*time.Hour +const key = ("1234567890123456") + +type Session struct { + MTime time.Time + Id int +} + +func NewSession(id int, time time.Time) *Session { + return &Session{Id: id, MTime: time} +} + +func ParseSession(session string) (*Session, error) { + if session == ""{ + return nil, errors.New("session is empty") + } + decode, err := base64.StdEncoding.DecodeString(session) + if err != nil{ + return nil, err + } + + data, _ := AesCBCDecrypt(decode, []byte(key), []byte(key),openssl.ZEROS_PADDING) + arr := strings.Split(string(data), "|") + if len(arr) != 2 { + return nil, errors.New("session format error") + } + + int, err := strconv.Atoi(arr[0]) + if err != nil{ + return nil, err + } + + time, err :=time.Parse("2006-01-02 15:04:05", arr[1]) + if err != nil{ + return nil, err + } + + return &Session{Id: int, MTime: time}, nil +} + +func (self *Session) String() string { + timeStr := self.MTime.Format("2006-01-02 15:04:05") + str := fmt.Sprintf("%d|%s", self.Id, timeStr) + data, _ := AesCBCEncrypt([]byte(str), []byte(key), []byte(key),openssl.ZEROS_PADDING) + encode := base64.StdEncoding.EncodeToString(data) + return encode +} + +func (self *Session) IsValid() bool { + diff := time.Now().Sub(self.MTime) + return diff - time.Duration(validTime) < 0 +}