├── .DS_Store ├── .gitignore ├── .idea ├── TFT.iml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── LICENSE ├── README.md ├── config └── app.yaml ├── data ├── .DS_Store ├── avatar │ ├── 00Varus.png │ ├── 01Elise.png │ ├── 02Morgana.png │ ├── 03Evelynn.png │ ├── 04Aatrox.png │ ├── 05Brand.png │ ├── 06Swain.png │ ├── 07Shyvana.png │ ├── 08Aurelion Sol.png │ ├── 09Pantheon.png │ ├── 10Yasuo.png │ ├── 11Braum.png │ ├── 12Lissandra.png │ ├── 13Ashe.png │ ├── 14Volibear.png │ ├── 15Sejuani.png │ ├── 16Anivia.png │ ├── 17Blitzcrank.png │ ├── 18Darius.png │ ├── 19Katarina.png │ ├── 20Draven.png │ ├── 21Fiora.png │ ├── 22Garen.png │ ├── 23Vayne.png │ ├── 24Lucian.png │ ├── 25Leona.png │ ├── 26Kayle.png │ ├── 27Shen.png │ ├── 28Zed.png │ ├── 29Kennen.png │ ├── 30Akali.png │ ├── 31Graves.png │ ├── 32Pyke.png │ ├── 33Twist Fate.png │ ├── 34Gangplank.png │ ├── 35Miss Fortune.png │ ├── 36Mordekaiser.png │ ├── 37Kindred.png │ ├── 38Karthus.png │ ├── 39Warwick.png │ ├── 40Nidalee.png │ ├── 41Ahri.png │ ├── 42Rengar.png │ ├── 43Gnar.png │ ├── 44Kha'Zix.png │ ├── 45Kassadin.png │ ├── 46Rek'Sai.png │ ├── 47Cho'Gath.png │ ├── 48Kaisa.png │ ├── 49Tristana.png │ ├── 50Lulu.png │ ├── 51Poppy.png │ ├── 52Veigar.png │ ├── 53Camille.png │ ├── 54jayce.png │ ├── 55VI.png │ └── 56Jinx.png ├── champions.json ├── champions_graph.json ├── final_result │ ├── total_strength │ │ ├── final_result6.json │ │ ├── final_result7.json │ │ ├── final_result8.json │ │ └── final_result9.json │ └── trait_num │ │ ├── final_result6.json │ │ ├── final_result7.json │ │ ├── final_result8.json │ │ └── final_result9.json ├── language.json ├── output │ ├── total_strength │ │ ├── champions_comb10.json │ │ ├── champions_comb3.json │ │ ├── champions_comb4.json │ │ ├── champions_comb5.json │ │ ├── champions_comb6.json │ │ ├── champions_comb7.json │ │ ├── champions_comb8.json │ │ └── champions_comb9.json │ └── trait_num │ │ ├── champions_comb10.json │ │ ├── champions_comb6.json │ │ ├── champions_comb7.json │ │ ├── champions_comb8.json │ │ └── champions_comb9.json ├── trait_graph.png ├── trait_icons │ ├── Assassin.png │ ├── Blademaster.png │ ├── Brawler.png │ ├── Demon.png │ ├── Dragon.png │ ├── Elementalist.png │ ├── Exile.png │ ├── Glacial.png │ ├── Guardian.png │ ├── Gunslinger.png │ ├── Hextech.png │ ├── Imperial.png │ ├── Knight.png │ ├── Ninja.png │ ├── Noble.png │ ├── Phantom.png │ ├── Pirate.png │ ├── Ranger.png │ ├── Robot.png │ ├── Shapeshifter.png │ ├── Sorcerer.png │ ├── Void.png │ ├── Wild.png │ └── Yordle.png └── traits.json ├── evaluate └── evaluation.go ├── globals └── global.go ├── main.go ├── models ├── champions.go ├── metrics.go └── traits.go ├── python_scripts ├── deduplicate.py ├── download.py ├── graph_visualisation.py ├── scrape.py ├── scrape_icon.py ├── traits.py ├── translate.py ├── visualise_champions.py └── visualise_trait_graph.py ├── search ├── graph.go ├── search.go └── traverse.go ├── utils ├── extend.go ├── math.go └── translate.go └── visualisation ├── champion_graph.html └── graph.json /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | -------------------------------------------------------------------------------- /.idea/TFT.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 102 | 103 | 104 | 123 | 124 | 125 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 157 | 158 | 169 | 170 | 171 | https://goproxy.cn,direct 172 | 173 | 174 | 175 | 176 | 177 | 178 | 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 韦子扬 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > 本文希望读者玩过云顶之弈,不懂编程的可以直接拉到最下面去看结论,懂编程的希望你了解递归、分治、图、堆这些基本概念,并掌握Python或者Go语言。 2 | 代码已公开在github上:[https://github.com/weiziyoung/TFT](https://github.com/weiziyoung/TFT) ,转载请注明来源。 3 | 4 | 今天是11月11日,首先恭喜FPX一顿摧枯拉朽横扫G2, 拿下S赛冠军!证明了LPL是世界第一赛区,也让电竞作为一种赛事在这代人心中铭记。本届S赛结束,也就意味着,S8告一段落,S9即将上线。而云顶之弈作为今年刚出的新模式,在上周11月6日也发布了S2元素崛起版本,一时间各种打法也是层出不穷,小编我也是一名忠实的云顶之弈玩家,但目前还没有玩过S2版本,主要想把这篇文章先写好分享给想读的人。 5 | 6 | 其实早在今年暑假刚出这个新模式,大家都还不会玩,还在摸索各种阵容的时候,我就在思考一件事——如何通过编程的手段搜索到6人口、7人口、8人口甚至9人口时凑到的最多的羁绊?这种想法来源于一个惨痛的经历,就是我第一次玩的时候,大概只凑出来了一个3贵族2骑士羁绊,就草草第七名带走了...当时就觉得这个游戏太难了,这么多卡片怎么能全记住?除了英雄之外,还有装备合成也跟英雄联盟差的很远,但玩个两三局,大概就明白: 7 | 8 | 这个游戏想吃鸡有三个核心——**羁绊**、**英雄等级**、**装备**, 三个核心有两个占优势,基本可以达到前四,三个都占优势,就稳定吃鸡了。这里我们主要讨论的就是去搜索**羁绊**,从而在这个维度上不吃亏。而装备这块比较靠脸,所以不做讨论,英雄等级这块其实可以根据每张卡在每个阶段出现的概率来估算出来这个阵容成型的难易程度,但是在本片博客里不做讨论,这里只讨论一个问题,就是**羁绊**。 9 | 10 | # 文章大纲 11 | - 云顶之弈游戏简介 12 | - 基本算法思路 13 | - 准备实验数据 14 | - 排列组合的原理和实现 15 | - 用图降低搜索复杂度 16 | - 评估函数的设计和实现 17 | - 最小堆维护Top 100阵容 18 | - 结果展示 19 | - 分析与总结 20 | 21 | # 云顶之弈游戏简介 22 | 一般读到这里的读者应该都玩过云顶之弈,但为了照顾有些只打匹配排位从不下棋的同学,这里还是简单介绍一下这个游戏机制。 23 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37e60f05a6fa8aimage.png) 24 | 25 | - 方框`1`所在的是小小英雄,就是召唤师啦,好看用的。 26 | - 方框`2`是你目前的队伍,这个队伍可以由不同英雄组成,但是队伍规模取决于你等级的高低。 27 | - 方框`3`是你候选区的英雄,放一些你暂时不想上场的英雄,当然这个区域大多数是用来合成英雄的,3个相同1星英雄可以合成成2星,3个相同2星英雄可以合成为3星。当然我们这里不讨论如何优化英雄等级的话题。 28 | - 方框`4`是发牌员给你发的牌,还有你目前有多少钱,每回合发牌员会给你发5张牌,你需要用金币去购买,这里只需要记住一点,星级越高的英雄越难抽到,并且也越强。 29 | - 方框`5`就是我们的核心——羁绊了,它是根据场上的英雄的种族和职业所确定的,比如目前场上小炮和男枪可以组成一个枪手的buff,这个Buff可以使得枪手在攻击时造成2个目标伤害,而劫的话自己是个忍者,所以可以组成一个忍者buff,它可以提升自己暴击几率和攻击速度。每个羁绊都有自己的效果,同时,羁绊也有自己的等级,比如当你只有2个枪手的时候,你的枪手能够同时造成2个敌人的伤害,而4个枪手的时候,你可以再攻击时同时造成3个目标的伤害;同时羁绊也有范围,有的羁绊只对单个人有效,比如双帝国、三贵族、单忍者,大多数羁绊对同种族的有效,比如狂野、枪手、剑士,少数羁绊对队伍里所有英雄都有效,比如骑士、法师。 30 | 31 | 具体的S1版本英雄羁绊图如下(有一些后期英雄没加上去,比如潘森、卡萨、海克斯): 32 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37e611184d2ee6image.png) 33 | 34 | 总共是56只英雄,大多英雄拥有一个种族,一个职业,船长的职业既是剑士也是枪手,纳尔的种族既是约德尔人也是狂野。一般来说,这个游戏在七人口时阵容成型,这个阶段基本能看出谁胜谁负,所以我们的目的就是选7个英雄,组成羁绊上最强的阵容。 35 | 36 | # 基本算法思路 37 | 38 | 就像之前所说的,我们的目的是在56个英雄里选n个英雄,然后从里面选出羁绊最强的前K个。这句话可以拆分为这三个问题: 39 | 1. 首先,如何让计算机去自动把所有组合的可能性一个不拉地遍历出来?不重复也不漏检? 40 | 2. 其次,给定一个阵容,如何去评判羁绊的强度? 41 | 3. 第三,怎么去保存前K个羁绊最强的结果? 42 | 43 | 对于第一个问题来说,很多编程语言都有combination的拓展库,方便程序员求出一个列表的元素所有的组合可能性。但是这个是个好的方案嘛?真的可行嘛?如果不可行,怎么去优化? 44 | 45 | 对于第二个问题来说,我们在评估一个东西,或者说量化一个东西的时候,应该采用哪些指标?羁绊多是不是意味着羁绊就强?如果不是的话,是否需要引入主观性的一些指标,比如单个羁绊对英雄的增益程度?另外这个羁绊好成型嘛?是不是容易在组建的半路上暴毙?这些都是需要注意的问题。 46 | 47 | 对于第三个问题来说,看起来很容易,但排序真的可行吗?由于我们搜索的结果多达几百万个的阵容组合,全部排序后再取前K个现实嘛? 48 | 49 | # 准备实验数据 50 | 本次主要使用语言为Go,并且用Python做一些脚本辅助我们做一些分析,之所以采用Go来写核心代码,是因为这种上百万轮次的搜索,Go往往比Python能快出一个数量级,同时Go工程化之类的也做的更好一些,语法也不至于像C++和Java那样繁琐。 51 | 52 | 程序 = 算法 + 数据。数据是一切的基石,要实现我们这次的目标,我们至少需要拥有两个数据:英雄数据、羁绊数据。在国外英雄联盟官网上,我们可以找到这个页面:[TFT GAMEPLAY GUIDE](https://na.leagueoflegends.com/en/news/game-updates/gameplay/teamfight-tactics-gameplay-guide?utm_source=web&utm_medium=web&utm_campaign=tft-microsite-2019),接下来只要用Python 的BeautifulSoup包吧页面解析出来就可以了,大概20行代码就可以搞定了,由于思路比较简单,这里就不放代码了,给个链接自己看:[python_scripts/scrape.py](https://github.com/weiziyoung/TFT/blob/master/python_scripts/scrape.py)。 53 | 54 | 如下所示,这里我们需要记录英雄的元数据包括:名字、头像、费用、种族和职业,总共56个英雄,这里不展示了。需要的自己去取:[data/champions.json](https://github.com/weiziyoung/TFT/blob/master/data/champions.json) 55 | ```json 56 | { 57 | "name": "Varus", 58 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Varus.png&resize=64:", 59 | "price": 2, 60 | "origin": ["demon"], 61 | "class": ["ranger"] 62 | }, 63 | ``` 64 | 65 | 另外是羁绊数据,这个数据可以从英雄数据里面整理出来,同时也要我们自己手填一些数据,以**恶魔**为例: 66 | ```json 67 | { 68 | "name": "demon", 69 | "bonus_num": [2,4,6], 70 | "scope": [2,2,2], 71 | "champions": [ 72 | "Varus","Elise","Morgana","Evelynn", 73 | "Aatrox","Brand","Swain"] 74 | }, 75 | ``` 76 | 恶魔羁绊需要在2只时触发,且在4,6时羁绊进阶,那`bonus_num`就是`[2,4,6]`,而恶魔羁绊无论多少级,都是只有同种族的受益,所以范围序号是`2`,具体范围序号含义我们定义如下 77 | 1. `1`代表只有一个英雄能吃到这个羁绊buff的效果,典型的比如3贵族、2帝国。 78 | 2. `2`代表持有该羁绊的能够吃到这个buff效果,大多数羁绊都属于这个效果,比如恶魔、冰川、狂野、变形者、刺客、枪手、剑士、4帝国等等。 79 | 3. `3`代表队伍全部都可以吃到这个buff,比如6贵族、骑士、法师这些。 80 | 4. `4`代表一个特殊的羁绊范围,就是护卫了,护卫是除了护卫本身,其周围的人都能吃到buff。 81 | 82 | `champions`就是持有这个羁绊的所有英雄了,全部羁绊数据在这里:[data/traits.json](https://github.com/weiziyoung/TFT/blob/master/data/traits.json)。这就是我们现在所能拿到的所有客观数据,不掺杂任何拍脑袋给的主观权重。实际上在评估时,这种数据越多越好,主观性太强的指标例如英雄强度、羁绊强度这种,公说公有理,婆说婆有理,很难有客观的结论,尽量少引入到评价体系中。 83 | 84 | # 排列组合的原理和实现 85 | 现在我们有所有英雄了,作为召唤师,我觉得很有必要把它们一字排开欣赏欣赏...毕竟S2就看不到他们的绝大多数了。 86 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37e6ce133434acimage.png) 87 | 所以我们的任务就是从55个英雄里面挑出8个英雄,让他们的羁绊数量最多。所以这是一个排列组合里的组合问题,可以根据公式求出组合数量: 88 | $$ C_{n}^{m}=\frac{n!}{m!(n-m)!} $$ 89 | 其中`n`等于55,`m`等于8,也就是八人口时,需要搜索`231917400`个不重复的可能性。 90 | ## 如何实现组合呢 91 | 最经典的思路就是分治了,看个简单的问题,比如对`[a,b,c,d,e]`求个数为3的所有组合。那么,我们首先会先把`a`取出来,问题简化成了对`[b,c,d,e]`求个数为2的所有组合。其次,我们把`b`取出来,问题简化成了对`[c,d,e]`求个数为1的所有组合,这时候问题就简单了.示意图如下: 92 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37e6d4b7680260image.png) 93 | 红框表示你现在已经选择的字母,红框下面的数字代表需要继续进行组合的元素,到三层结束。 94 | Python实现代码,非常短小精干,需要仔细品味和研读,理解递归、分治的优雅: 95 | ```Python 96 | def combine(data, step, selected_data, target_num): 97 | if len(selected_data) == target_num: # 递归的结束条件:已选择的元素数量等于目标数量 98 | print(selected_data) 99 | return 100 | if step == len(data): # 游标到头了还没找出来,就结束吧 101 | return 102 | selected_data.append(data[step]) # 选择当前元素把她加到已选择的队伍里 103 | combine(data, step + 1, selected_data, target_num) # 将游标推进,进入递归去找下一层 104 | selected_data.pop() # 把选择过的元素踢出去 105 | combine(data, step + 1, selected_data, target_num) #在不选择刚才被踢出去的元素情况下继续递归 106 | if __name__ == '__main__': 107 | data = ['a','b','c','d', 'e'] 108 | combine(data, 0, [], 3) 109 | ``` 110 | 理解了上面这个代码,换个变量名,加入evaluate函数,就可以用于搜索我们的全羁绊了。 111 | ```Python 112 | def combine(champions, step ,combo, max_num): 113 | if len(combo) == max_num: # 如果队伍到了最大的人口,就进行评估 114 | evaluate(combo) 115 | return 116 | if step == len(combo): 117 | return 118 | combo.append(champions[step]) # 把游标所指定的英雄加到队伍里面去 119 | combine(champions, step + 1, combo, max_num) # 游标往前进,继续抓壮丁 120 | combo.pop() # 把刚才指定的英雄踢出去 121 | combine(champions, step+1, combo, max_num) # 再继续往前进抓壮丁 122 | 123 | def evaluate(combo): 124 | # 这里写给定一个阵容,怎么去评估它的强度,应该返回一个数值,或者是多个维度的评分结构体。 125 | # 往后再议 126 | pass 127 | 128 | def init_champions(): 129 | # 这里从json里读数据,代码略 130 | pass 131 | 132 | if __name__ == "__main__": 133 | champions = init_champions() # 把英雄数据导入进去,每个英雄应该是个结构体,或者是个字典。 134 | combine(champions, 0, [], 7) 135 | ``` 136 | 跑了一下,自行感受一下Python🐌蜗牛一般的速度吧: 137 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37e77878ffd19cimage.png) 138 | 平均每秒遍历`36979`个结点,搜索6人口的最优羁绊竟然要花14分钟,作为一个堆效率有追求的程序员,怎么能够容忍这种事情出现??我只想对这个结果说: 139 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37e779287edda3image.png) 140 | 所以接下来就没有Python代码了,同样的算法用Go跑的话,速度是每秒大约20w个结点, 大概是Python的7倍左右,如果用C++来写会更快,但如果让我用C++来写可能要明年你们才能看到我这篇文章了,所以程序员要在开发效率和运行速度中取得一个平衡: 141 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37e77b30a5a8ffimage.png) 142 | 143 | # 用图降低搜索复杂度 144 | ## 穷举法的弊端 145 | 由之前的公式: 146 | 147 | $$ C_{n}^{m}=\frac{n!}{m!(n-m)!} $$ 148 | 149 | 我们可以算出,八人口需要搜索`231917400`个结点,用Python搜索大概需要1.7个小时左右,用Golang搜索大概需要20分钟,速度还是很不够看,从语言上已经优化不了了,那就从算法上进行优化。 150 | 151 | 结合这个游戏,仔细思考一下我们是否真的需要对56个英雄都组合一遍呢?这么看不够直观,我举个非常简单的栗子 152 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37e78fc64dcd0aimage.png) 153 | 给定图上的五只英雄:蜘蛛、盖伦、浪人、维鲁斯、豹女、寒冰,选出三个英雄,目标是让他们组成的羁绊数量最大,用大脑去看,那结果一定是“蜘蛛、维鲁斯、寒冰”,但是,我们模拟之前穷举法的过程,首先选出蜘蛛,其次选择第二位的盖伦,如果真的有人会在拿到蜘蛛的情况下去第二位去选择盖伦凑羁绊,大概会让人觉得: 154 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37e790c69b29a5image.png) 155 | ## 基于羁绊的思路 156 | 正常的人拿完蜘蛛,下一步一定是拿维鲁斯或者豹女,拿维鲁斯因为刚好可以凑一个恶魔,维鲁斯又是一个比较强的打工二费卡,何乐而不为?拿豹女是因为后面可能可以凑3换型,能凑出3换型,前期坦度是妥妥的,所以我们在拿到蜘蛛的情况下,不可能去考虑下一步拿盖伦和狼人,在下一步拿到维鲁斯的情况下,去考虑豹女和寒冰,(思考一下为什么要考虑豹女?),这样我们就达到了最多羁绊:双恶魔加双寒冰。综上,我们简化搜索的主要逻辑就是**每次只选择与他能产生羁绊的对象**,基于这个想法,我们的搜索就变成: 157 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x597283d640b96image.png) 158 | 159 | 而图就是用来描述每个对象之间关系的一种数据结构,在这里,图用来描述英雄之间的羁绊关系,而图的表示方法有两种:邻接矩阵法和邻接表法,两者的取舍取决于图的稀疏程度。将上面官方给的羁绊-英雄图转个方式就得到了英雄-羁绊邻接矩阵图(57*57的矩阵,有相同羁绊则输出1, 没有则输出0)由图中可以看出,该矩阵为稀疏矩阵,所以我们后面用邻接表法来表示该矩阵): 160 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37eb7e5e8dd158image.png) 161 | 另外,所有的英雄都和机器人、浪人、忍者有羁绊,因为队伍里只要添上它们任何中的一个,都可以为羁绊数+1,符合我们的优化预期。亚索在这里不是孤儿了。 162 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37eb85fea153ddimage.png) 163 | 164 | 那么怎么利用这个信息去优化我们的算法呢?这需要进一步地去理解“组合”搜索究竟做了什么?是否可以用图的方式来进行组合搜索?答案是肯定的,以刚才组合`a,b,c,d,e`选出3个进行组合为例,换个思路来想这个事,实际上他们彼此之间也可以用有向图来表示: 165 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37eb83b1ecd59aimage.png) 166 | 所以之前那个组合示意图,也可以这么理解: 167 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37eb8407a5c20aimage.png) 168 | 综上所述,对于组合而言,我们只要把每个结点指向起后面的所有结点,然后用普通的图搜索,就可以得到组合的结果。 169 | 而利用羁绊图,我们可以不用把每个结点指向后面的所有结点,相反,我们只要把每个结点指向后面所有能跟当前组合产生羁绊的结点就可以了,注意!不能只考虑和当前结点产生羁绊,而要考虑队伍里所有英雄所拥有的所有结点,否则会漏搜索!我们优化的初衷是,保证搜索结果不变的情况下,减少不必要的搜索,而不能漏搜索。 170 | 因此核心搜索代码如下: 171 | ```go 172 | type Graph map[int][]int 173 | 174 | // GenerateGraph 生成羁绊图 175 | func GenerateGraph(championList models.ChampionList) Graph{ 176 | graph := make(Graph) 177 | positionMap := make(map[string]int) 178 | for index, champion := range championList { 179 | positionMap[champion.Name] = index 180 | } 181 | for no, champion := range championList { 182 | // children 排序 183 | children := make([]int, 0, 30) 184 | // 加入相同职业的英雄 185 | classes := champion.Class 186 | for _, class := range classes { 187 | sameClassChampions := globals.TraitDict[class].Champions 188 | for _, champion := range sameClassChampions { 189 | index := positionMap[champion] 190 | if index > no{ 191 | children = append(children, index) 192 | } 193 | } 194 | } 195 | // 加入相同种族的英雄 196 | origins := champion.Origin 197 | for _, origin := range origins { 198 | sameOriginChampions := globals.TraitDict[origin].Champions 199 | for _, champion := range sameOriginChampions { 200 | index := positionMap[champion] 201 | if index > no { 202 | children = append(children, index) 203 | } 204 | } 205 | } 206 | // 加入1羁绊的英雄 207 | for _, championName := range globals.OneTraitChampionNameList { 208 | index := positionMap[championName] 209 | if index > no { 210 | children = append(children, index) 211 | } 212 | } 213 | // 对index从小到大排序 214 | sort.Ints(children) 215 | children = utils.Deduplicate(children) 216 | graph[no] = children 217 | } 218 | return graph 219 | } 220 | 221 | 222 | // Traverse 图遍历, 223 | // championList, 英雄列表,固定不变。 graph 羁绊图,也是固定不变。node 为当前的结点, selected 为已选择的英雄, oldChildren是父节点的children 224 | func Traverse(championList models.ChampionList, graph Graph, node int, selected []int, oldChildren []int) { 225 | selected = append(selected, node) 226 | if len(selected) == lim { 227 | combo := make(models.ChampionList, lim) 228 | for index, no := range selected { 229 | unit := championList[no] 230 | combo[index] = unit 231 | } 232 | metric := evaluate.Evaluate(combo) 233 | heap.Push(&Result, metric) 234 | 235 | // 超过最大就pop 236 | if len(Result) == globals.Global.MaximumHeap { 237 | heap.Remove(&Result, 0) 238 | } 239 | return 240 | } 241 | newChildren := graph[node] 242 | children := append(oldChildren, newChildren...) 243 | sort.Ints(children) 244 | children = utils.DeduplicateAndFilter(children, node) 245 | copyChildren := make([]int, len(children), 50) 246 | copy(copyChildren, children) 247 | for _, child := range children { 248 | copySelected := make([]int, len(selected), lim) 249 | copy(copySelected, selected) 250 | Traverse(championList, graph, child, copySelected, copyChildren) 251 | } 252 | } 253 | // TraitBasedGraphSearch 基于羁绊图的图搜索 254 | func TraitBasedGraphSearch(championList models.ChampionList, teamSize int) models.ComboMetricHeap { 255 | graph := GenerateGraph(championList) 256 | lim = teamSize 257 | 258 | heap.Init(&Result) 259 | startPoints := getSlice(0, len(championList)-teamSize + 1) 260 | for _,startNode := range startPoints{ 261 | Traverse(championList, graph, startNode, make([]int, 0, teamSize), make([]int, 0, 57)) 262 | } 263 | return Result 264 | } 265 | ``` 266 | 用这种方法所产生的有向图如下图所示(这里顺手安利一个网络图可视化的js库[antv-G6](https://www.yuque.com/antv/g6/ie7zi7)),大幅度简化了初始的搜索图(自行想象一下所有结点连接所有后续结点密密麻麻的效果图)。 267 | 268 | ![image10.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images/screencapture-localhost-63342-TFT-visualisation-champion-graph-html-2019-11-10-16_16_59-Recovered.jpg) 269 | 实际上,我认为这种启发式搜索,有点A star搜索的意思在里面,核心思想就是讲后续children进行排序,将预期离目标结果近的放在前面。这里做的极端了一些,我们把没有产生羁绊的后续结点全部咔嚓了,但实际上这并不会造成漏检(读者可以自己实验一下) 270 | 271 | 最后,比较一下基于羁绊图的结点搜索数量和不基于羁绊图的结点搜索数量,横坐标是人口,纵坐标是结点数量,注意一下纵坐标的跨度,是指数级别的。 272 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37eb8c389e91dbimage.png) 273 | 所以到这里,这篇博客的核心部分就讲完了,基本思想就是利用现有的知识(英雄之间产生的羁绊)来大幅度简化搜索。 274 | 275 | # 评估函数的设计与实现 276 | 之前我们一直都没有实现评估函数,其实这个评估函数的设计是非常灵活的,也是玩家可以加入自己玩游戏的经验的一部分。这里我们用4个指标来描述阵容强度: 277 | ```go 278 | type ComboMetric struct { 279 | // 英雄组合 280 | Combo []string `json:"combo"` 281 | // 队伍总羁绊数量 = sigma{羁绊} * 羁绊等级 282 | TraitNum int `json:"trait_num"` 283 | // 具体羁绊 284 | TraitDetail map[string]int `json:"trait_detail"` 285 | // 总英雄收益羁绊数量 = sigma{羁绊} 羁绊范围 * 羁绊等级 286 | TotalTraitNum int `json:"total_trait_num"` 287 | // 当前阵容羁绊强度 = sigma{羁绊} 羁绊范围 * 羁绊强度 288 | TotalTraitStrength float32 `json:"total_trait_strength"` 289 | // 当前阵容强度 = sigma{英雄} 英雄强度 * 羁绊强度 290 | TotalStrength float64 `json:"total_strength"` 291 | } 292 | ``` 293 | 294 | - 队伍总羁绊数量: 这个是最好理解的,你可以理解为你左侧边栏有多少个羁绊,也就是这个部分,谁不喜欢亮刷刷的一排羁绊呢?看的就很舒服。注意,像6恶魔这种算3个羁绊,而不能只算1个羁绊,6贵族算2个羁绊。这也是我们最开始的motivation,就是寻找怎么能让左边的羁绊灯亮的最多。 295 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37eb8df9467873image.png) 296 | 297 | - 英雄总收益羁绊数量: 这个也是好理解的,灯亮的多并不代表强,我的经验告诉我,往往吃鸡的阵容,灯亮的往往并不多,有时候甚至就三四个,因此需要引入其他衡量标准。因为不同羁绊有不同的收益范围,所以这个指标就是计算的就是每个羁绊羁绊收益范围乘以它等级的总和。6贵族羁绊之所以挺强,强的不在于它单个属性有多强,而在于它产生了单个buff到群体buff的一个质变,骑士Buff好用也是这个道理,为什么大家都喜欢用骑士过渡,甚至到后面主流吃鸡阵容就包括骑士+枪呢?本质上就是因为骑士能够提供全队伍的收益,而不是只针对本种族的收益。 298 | 299 | - 当前阵容羁绊强度: 这个指标开始就加入人为指标了,也就是其输出取决于玩家对羁绊的理解,这个指标引入了羁绊强度这个概念,这个参数是指:当英雄拥有该羁绊时,能够比不拥有羁绊时强多少倍,比如在这里我设置贵族buff可以让英雄强1.8倍,双恶魔buff能让英雄强1.3倍,龙buff能够直接增强2倍...具体可以看我[data/traits.json](https://github.com/weiziyoung/TFT/blob/master/data/traits.json)文件。 300 | 301 | - 当前阵容整体强度: 这个跟上一版差别就在于考虑了英雄的等级,比如同样是双骑士,你拿个盖伦加诺手,肯定比不上你拿个波比加猪妹。这里为了简化情景,所以设定,2星英雄比1星英雄强1.25倍,3星又比2星强1.25倍...以此类推,最后5星英雄大约比1星英雄强2.5倍,如果你觉得这个数值低了,可以自己在配置文件里面调整。 302 | 303 | 最后我们的evaluate评估函数如下,注意一个问题,就是忍者buff的奇异设定,游戏规定,忍者Buff只在1和4的时触发,在2,3时会熄灭,这不同于其他任何一个羁绊规则,所以要拎出来单独处理一下: 304 | ```go 305 | // Evaluate 评估当前组合的羁绊数量、单位收益羁绊总数、羁绊强度 306 | func Evaluate(combo []models.ChampionDict) models.ComboMetric { 307 | var traitDetail = make(map[string]int) 308 | 309 | comboName := make([]string, 0, len(combo)) 310 | traitNum := 0 311 | totalTraitNum := 0 312 | totalTraitStrength := float32(0.0) 313 | 314 | // 初始化英雄强度向量 315 | unitsStrength := make([]float64, len(combo), len(combo)) 316 | traitChampionsDict := make(map[string][]int) 317 | for index, unit := range combo { 318 | comboName = append(comboName, unit.Name) 319 | unitStrength := math.Pow(globals.Global.GainLevel, float64(unit.Price-1)) 320 | unitsStrength[index] = unitStrength 321 | for _, origin := range unit.Origin { 322 | traitChampionsDict[origin] = append(traitChampionsDict[origin], index) 323 | } 324 | for _, class := range unit.Class { 325 | traitChampionsDict[class] = append(traitChampionsDict[class], index) 326 | } 327 | } 328 | 329 | for trait, champions := range traitChampionsDict { 330 | num := len(champions) 331 | bonusRequirement := globals.TraitDict[trait].BonusNum 332 | var bonusLevel = len(bonusRequirement) 333 | for index, requirement := range bonusRequirement { 334 | if requirement > num { 335 | bonusLevel = index 336 | break 337 | } 338 | } 339 | 340 | // 忍者只有在1只和4只时触发,其他不触发 341 | if trait == "ninja" && 1 < num && num < 4 { 342 | bonusLevel = 0 343 | } 344 | if bonusLevel > 0 { 345 | traitDetail[trait] = bonusRequirement[bonusLevel-1] 346 | bonusScope := globals.TraitDict[trait].Scope[bonusLevel-1] 347 | traitNum += bonusLevel 348 | bonusStrength := globals.TraitDict[trait].Strength[bonusLevel-1] 349 | benefitedNum := 0 350 | switch bonusScope { 351 | case 1: 352 | { 353 | benefitedNum = 1 // 单体Buff,例如 机器人、浪人、三贵族、双帝国 354 | for _, champion := range champions { 355 | unitsStrength[champion] *= float64(bonusStrength) 356 | } 357 | } 358 | case 2: 359 | { 360 | benefitedNum = num // 对同一种族的Buff,大多数羁绊都是这种 361 | for _, champion := range champions { 362 | unitsStrength[champion] *= float64(bonusStrength) 363 | } 364 | } 365 | case 3: 366 | { 367 | benefitedNum = len(combo) // 群体Buff,如骑士、六贵族、四帝国 368 | for index, _ := range unitsStrength { 369 | unitsStrength[index] *= float64(bonusStrength) 370 | } 371 | } 372 | case 4: 373 | { 374 | benefitedNum = len(combo) - 2 // 护卫Buff,比较特殊,除护卫本身外,其他均能吃到buff 375 | for index, _ := range unitsStrength { 376 | isGuard := false 377 | for _, champion := range champions { 378 | if index == champion { 379 | isGuard = true 380 | break 381 | } 382 | } 383 | if !isGuard { 384 | unitsStrength[index] *= float64(bonusStrength) 385 | } 386 | } 387 | } 388 | } 389 | totalTraitNum += bonusLevel * benefitedNum 390 | totalTraitStrength += float32(benefitedNum) * bonusStrength 391 | } 392 | } 393 | metric := models.ComboMetric{ 394 | Combo: comboName, 395 | TraitNum: traitNum, 396 | TotalTraitNum: totalTraitNum, 397 | TraitDetail: traitDetail, 398 | TotalTraitStrength: totalTraitStrength, 399 | TotalStrength: utils.Sum(unitsStrength), 400 | } 401 | return metric 402 | } 403 | 404 | ``` 405 | 406 | # 最小堆维护Top 100阵容 407 | 之前也提到了,我们每次搜索都是对上千万乃至上亿的叶子结点进行评估,那么如何取出评估结点的前100名呢?我们会想到把结果存起来,然后排序,但这么做可行嘛? 408 | 409 | 想一下我们十人口进行搜索,总共搜索了25844630个结点,假设每存一个metric需要消耗1kb,那最后把它们全部存下来,大约需要24G,记住这是存在内存里的哦,而不是在硬盘上的噢,正常PC的内存条能有16G很不错了吧,更何况还要跑个操作系统在上面,所以这个方案一定是不行的,那有什么更好的方案呢? 410 | 411 | 这就需要联系我上个月写的博客,[详解数据结构——堆](https://zhuanlan.zhihu.com/p/85518062),这篇博文里我们讲到利用堆,我们只需要在内存里开辟堆长度大小的空间即可,比如我们想保留前100个结果,那我们只要开辟100k的内存即可,而每次插入删除,都是`log n`的复杂度,非常快。 412 | 413 | 而保留前K个结果,需要使用的是最小堆,golang里集成了堆的数据结构,只需要重写它的一些接口就可以用了,所以我们的ComboMetric完整版实现就是这样,具体用起来就是每次都push,满了就把堆顶pop出来即可,最后剩下来的就是前K个结果,把它们最后排个序即可: 414 | ```go 415 | package models 416 | 417 | type ComboMetric struct { 418 | // 英雄组合 419 | Combo []string `json:"combo"` 420 | // 队伍总羁绊数量 = sigma{羁绊} * 羁绊等级 421 | TraitNum int `json:"trait_num"` 422 | // 具体羁绊 423 | TraitDetail map[string]int `json:"trait_detail"` 424 | // 总英雄收益羁绊数量 = sigma{羁绊} 羁绊范围 * 羁绊等级 425 | TotalTraitNum int `json:"total_trait_num"` 426 | // 当前阵容羁绊强度 = sigma{羁绊} 羁绊范围 * 羁绊强度 427 | TotalTraitStrength float32 `json:"total_trait_strength"` 428 | // 当前阵容强度 = sigma{英雄} 英雄强度 * 羁绊强度 429 | TotalStrength float64 `json:"total_strength"` 430 | } 431 | 432 | // 定义一个最小堆,保留前K个羁绊 433 | type ComboMetricHeap []ComboMetric 434 | 435 | func (h ComboMetricHeap) Len() int { 436 | return len(h) 437 | } 438 | 439 | func (h ComboMetricHeap) Less(i,j int) bool { 440 | return h[i].TotalStrength < h[j].TotalStrength 441 | } 442 | 443 | func (h ComboMetricHeap) Swap(i, j int) { 444 | h[i], h[j] = h[j], h[i] 445 | } 446 | 447 | func (h *ComboMetricHeap) Push(x interface{}) { 448 | *h = append(*h, x.(ComboMetric)) 449 | } 450 | 451 | func (h *ComboMetricHeap) Pop() interface{} { 452 | old := *h 453 | n := len(old) 454 | x := old[n-1] 455 | *h = old[0 : n-1] 456 | return x 457 | } 458 | 459 | ``` 460 | 461 | # 结果展示 462 | 这篇博客最最重要的环节要来了,我们需要检验,计算机搜索出来的最强阵容,是否和S1版本的吃鸡阵容是相符的。全部结果文件在[result](https://github.com/weiziyoung/TFT/tree/master/data/final_result)里,读者也可以自己把代码下下来编译跑一下。 463 | 464 | 另外因为很多阵容之间的区别仅仅是换了一个相同羁绊的英雄,或者改了一个小羁绊,所以我们这里对搜索结果做了一个很简单的去重融合,当两个阵容羁绊相似度过高时进行合并,相似度可以用[Jaccard similarity coefficient](https://en.wikipedia.org/wiki/Jaccard_index) 来计算集合之间的相似度,如果相似度大于0.7,则认为属于同一套阵容: 465 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37ebee8b58e0a2image.png) 466 | 467 | ## 羁绊数最多的阵容 468 | 首先我们看不可能有错的一个指标——羁绊数。直观来说,就是搜索出让左边的羁绊灯亮最多的阵容(这种阵容不一定强) 469 | - 六人口 470 | ```json 471 | { 472 | "combo": ["艾希","狗熊","机器人","劫","螳螂","卡萨"], 473 | "trait_num": 7, 474 | "trait_detail": { 475 | "冰川": 2, 476 | "刺客": 3, 477 | "忍者": 1, 478 | "斗士": 2, 479 | "机器人": 1, 480 | "游侠": 2, 481 | "虚空": 2 482 | }, 483 | "total_trait_num": 12, 484 | "total_trait_strength": 16.4, 485 | "total_strength": 19.052499984405003 486 | }, 487 | ``` 488 | 总羁绊数达到了7个羁绊,注意这是6人口,正常咱们玩自走棋,6人口大约是4个羁绊数左右,毕竟阵容还没成型,但是实际上6人口在不用铲子的情况下最多可以有7个羁绊。 489 | 490 | - 七人口 491 | ```json 492 | { 493 | "combo": [ 494 | "狗熊","猪妹","机器人","慎","船长","卡密尔","金克斯" 495 | ], 496 | "trait_num": 7, 497 | "trait_detail": { 498 | "冰川": 2, 499 | "剑士": 3, 500 | "忍者": 1, 501 | "斗士": 2, 502 | "机器人": 1, 503 | "枪手": 2, 504 | "海克斯": 2 505 | }, 506 | "total_trait_num": 17, 507 | "total_trait_strength": 22.6, 508 | "total_strength": 21.726248967722068 509 | }, 510 | ``` 511 | 七人口最大羁绊数竟然还是7。不过不同于6人口只有一种组合能达到7羁绊,七人口前100个中基本都达到了7羁绊。 512 | 513 | - 八人口 514 | ```json 515 | { 516 | "combo": [ 517 | "艾希", "狗熊","机器人","劫","螳螂","挖掘机", 518 | "大虫子","卡萨" 519 | ], 520 | "trait_num": 9, 521 | "trait_detail": { 522 | "冰川": 2, 523 | "刺客": 3, 524 | "忍者": 1, 525 | "斗士": 4, 526 | "机器人": 1, 527 | "游侠": 2, 528 | "虚空": 4 529 | }, 530 | "total_trait_num": 25, 531 | "total_trait_strength": 24.4, 532 | "total_strength": 27.058749668872913 533 | } 534 | ``` 535 | 总共是9个羁绊,看着阵容好像是虚空斗刺哈哈哈,但虚空斗刺没有艾希。这套阵容强度看上去还是可以的。 536 | 537 | - 九人口 538 | ```json 539 | { 540 | "combo": [ 541 | "狗熊","猪妹","机器人","盖伦","薇恩","天使","劫","螳螂","卡萨" 542 | ], 543 | "trait_num": 9, 544 | "trait_detail": { 545 | "冰川": 2, 546 | "刺客": 3, 547 | "忍者": 1, 548 | "斗士": 2, 549 | "机器人": 1, 550 | "游侠": 2, 551 | "虚空": 2, 552 | "贵族": 3, 553 | "骑士": 2 554 | }, 555 | "total_trait_num": 22, 556 | "total_trait_strength": 28.55, 557 | "total_strength": 31.621585006726214 558 | } 559 | ``` 560 | 总之我没看过亮9栈灯的阵容,看样子挺花哨的,但这个阵容其实不妥的。羁绊只是吃鸡的一小部分,实际上更多的需要依靠英雄等级、装备、输出和坦克的组合。 561 | 562 | - 十人口 563 | ```json 564 | { 565 | "combo": [ 566 | "维鲁斯","乌鸦","亚索","机器人","诺手","天使", 567 | "阿卡丽","螳螂","挖掘机","卡萨" 568 | ], 569 | "trait_num": 10, 570 | "trait_detail": { 571 | "刺客": 3,"帝国": 2,"忍者": 1,"恶魔": 2, 572 | "斗士": 2,"机器人": 1,"浪人": 1,"游侠": 2, 573 | "虚空": 2,"骑士": 2 574 | }, 575 | "total_trait_num": 24, 576 | "total_trait_strength": 31, 577 | "total_strength": 37.67076561712962 578 | } 579 | ``` 580 | 亮了10栈灯,这种阵容基本看看就好,不可能成型并且吃鸡的,因为这是个有5个5费卡的阵容。 581 | 582 | ## 强度最高的阵容 583 | 正如之前说的,羁绊多阵容并不一定强,所以一定要结合英雄等级、羁绊强度、羁绊范围这些来算,这里英雄等级的增益和羁绊强度都是具有主观判断在里面的,而且算上这些指标实际上也是不够的,看下计算出的阵容就知道了: 584 | 585 | - 六人口 586 | ```json 587 | { 588 | "combo": [ 589 | "潘森","布隆","丽桑卓","狗熊","冰鸟","凯南" 590 | ], 591 | "trait_num": 5, 592 | "trait_detail": { 593 | "元素师": 3, 594 | "冰川": 4, 595 | "忍者": 1, 596 | "护卫": 2 597 | }, 598 | "total_trait_num": 14, 599 | "total_trait_strength": 15.2, 600 | "total_strength": 30.272461525164545 601 | }, 602 | ``` 603 | 这看上去是一个冰川元素阵容,游戏刚出的时候,这套阵容还是很容易吃鸡的,主要就是利用丽桑卓和冰鸟都是冰川+元素,导致这套阵容又有控制又有坦度,在以前谁都不会玩这个游戏的年代很容易吃鸡,小编我第一次吃鸡用的就是冰川元素流。但冰川元素逐渐没落了,原因就是后来大家都会玩这个游戏了,导致游戏节奏加快,而这个阵容一个最大的缺点就是成型有点困难,猪妹和冰鸟都不是那么容易抽到的,前期靠布隆一个坦度点是肯定不够的。 604 | 605 | - 七人口 606 | ```json 607 | { 608 | "combo": [ 609 | "莫甘娜","龙王","潘森","日女","天使","铁男","死歌" 610 | ], 611 | "trait_num": 5, 612 | "trait_detail": { 613 | "幽灵": 2,"护卫": 2,"法师": 3,"骑士": 2,"龙": 2 614 | }, 615 | "total_trait_num": 22, 616 | "total_trait_strength": 29.9, 617 | "total_strength": 40.17980836913922 618 | }, 619 | ``` 620 | 这个看上去是护卫龙,但又不太像,因为护卫龙好像没有人配法师的,但这不是最重要的,最重要的是,这套阵容太不容易成型了!!因为我们的评价指标里没有考虑羁绊的成型难易度,导致它更偏好等级高的英雄,强度看上去还可以,有输出有坦克,但有谁7人口能凑出来3个五星,2个四星呢? 621 | 622 | - 八人口 623 | ```json 624 | { 625 | "combo": [ 626 | "龙王","潘森","布隆","丽桑卓","冰鸟", 627 | "凯南","露露","小法" 628 | ], 629 | "trait_num": 7, 630 | "trait_detail": { 631 | "元素师": 3,"冰川": 2,"忍者": 1, 632 | "护卫": 2,"法师": 3,"约德尔": 3, 633 | "龙": 2 634 | }, 635 | "total_trait_num": 24, 636 | "total_trait_strength": 34.100002, 637 | "total_strength": 50.979002334643155 638 | } 639 | ``` 640 | 跟上面有点像(其实我不太清楚为什么七八人口都是护卫龙),这套阵容其实是缺乏坦度的hhh还不容易成型。所以我们的评估指标还是有问题哈哈哈,看到这套阵容人傻了。 641 | 642 | - 九人口 643 | ```json 644 | { 645 | "combo": [ 646 | "潘森","亚索","剑姬","盖伦", 647 | "薇恩","卢锡安","日女","天使","船长" 648 | ], 649 | "trait_num": 7, 650 | "trait_detail": { 651 | "剑士": 3,"护卫": 2,"枪手": 2, 652 | "浪人": 1,"贵族": 6,"骑士": 2 653 | }, 654 | "total_trait_num": 47, 655 | "total_trait_strength": 54.249996, 656 | "total_strength": 61.73055001568699 657 | } 658 | ``` 659 | 这套阵容我还是用过的,能不能吃鸡要看装备,亚索能2星并且吃到装备基本能吃鸡,吃不到装备就很缺乏输出,据说也可以把装备给船长养船长这个点,不过没试过。九人口贵族崛起大概是因为贵族的全范围buff比较给力。 660 | 661 | # 分析与总结 662 | 663 | ## 贡献 664 | 直到云顶之弈S1结束,网上并没有一篇用图搜索来组建羁绊阵容的文章,这篇文章就当是弥补这一块的空白吧,它从另一个角度去为我们推荐了阵容。核心思想就是利用英雄之间的相互羁绊来简化暴力搜索。 665 | 666 | ## 缺陷 667 | 668 | 实际上我觉得在评估阵容强度的时候,模型还是过于粗糙的,具体表现如下: 669 | 670 | 1. **首先忽视了坦度和输出的配合这个维度**。导致有些推荐阵容全是坦克没有输出,有些阵容只有输出没有坦克。 671 | 672 | 673 | 2. **其次忽视了羁绊之间的克制关系**。可以看到七八人口的时候,计算出来的都是以护卫龙为核心的阵容,因为护卫羁绊提供的收益范围很大,但前提条件是你把英雄都集中放护卫周围,但这种方法实际上是被海克斯完克的,所以在实际时间上,护卫buff的收益并没有这里计算中的那么大。 674 | 675 | 3. **忽略了阵过渡的平滑程度**。这是这里存在的最大问题,由于我们在评价阵容的时候,给高等级英雄倾向了一些权重,导致阵容中会有数量较多的高费英雄,实际上不考虑阵容成型难易程度的推荐就是在耍流氓。比如潘森刚出来的时候,很多人推荐贵族护卫龙,实际应用上效果并不好。 676 | 677 | 4. **没有考虑英雄升星的难易程度**。这个实际上跟上面是一种问题,我在搜索结果里找赌刺的阵容,直接被排名拍到了40多名,但赌刺绝对是6人口的T1阵容,这里面的原因就是刺客的卡费普遍是低的,导致在这套算法里赚不到便宜,但其实低费卡更容易到三星,而三星低费卡的强度是高于高费卡的,尤其是像三星劫这样的英雄。 678 | ![image.png](https://wzy-zone.oss-cn-shanghai.aliyuncs.com/article_images%2F0x37ebf0f7478498image.png) 679 | 680 | 5. **没有考虑金铲铲**。因为简化问题,这里没有考虑金铲铲,如果考虑金铲铲的话,搜索空间将会变得极其庞大,相当于为每个英雄都给配剑士、刺客、骑士、冰川、约德尔、恶魔这些羁绊。这些加上去以后,复杂度也就跟全搜索差不多了。 681 | 682 | ## 踩坑记录 683 | 684 | 1. Golang append函数,函数原型如下: 685 | ```go 686 | func append(slice []Type, elems ...Type) []Type 687 | ``` 688 | 从原型上看是传入一个切片,和若干需要加入的元素,返回一个切片。但实际上传入的slice切片在运行的过程中会被修改,返回的那个切片实际上就是你传入的slice切片。所以在使用golang里面的append函数的时候,记得把接受变量设置成你传入的第一个slice变量,或者使用前对slice进行copy。 689 | 690 | 2. 保留前K大个数实际上要用小顶堆,而不是想当然地使用大顶堆。 691 | 692 | 3. 在考虑当前英雄的后续结点的时候,不能只考虑当前英雄的羁绊,而要考虑队伍里所有英雄的羁绊,否则会漏检。 -------------------------------------------------------------------------------- /config/app.yaml: -------------------------------------------------------------------------------- 1 | maximum_heap : 256 2 | gain_level : 1.25 3 | evaluation: "trait_num" 4 | trait_path: "data/traits.json" 5 | champion_path: "data/champions.json" 6 | language_path: "data/language.json" 7 | output_path: "data/output/trait_num/" -------------------------------------------------------------------------------- /data/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/.DS_Store -------------------------------------------------------------------------------- /data/avatar/00Varus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/00Varus.png -------------------------------------------------------------------------------- /data/avatar/01Elise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/01Elise.png -------------------------------------------------------------------------------- /data/avatar/02Morgana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/02Morgana.png -------------------------------------------------------------------------------- /data/avatar/03Evelynn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/03Evelynn.png -------------------------------------------------------------------------------- /data/avatar/04Aatrox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/04Aatrox.png -------------------------------------------------------------------------------- /data/avatar/05Brand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/05Brand.png -------------------------------------------------------------------------------- /data/avatar/06Swain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/06Swain.png -------------------------------------------------------------------------------- /data/avatar/07Shyvana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/07Shyvana.png -------------------------------------------------------------------------------- /data/avatar/08Aurelion Sol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/08Aurelion Sol.png -------------------------------------------------------------------------------- /data/avatar/09Pantheon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/09Pantheon.png -------------------------------------------------------------------------------- /data/avatar/10Yasuo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/10Yasuo.png -------------------------------------------------------------------------------- /data/avatar/11Braum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/11Braum.png -------------------------------------------------------------------------------- /data/avatar/12Lissandra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/12Lissandra.png -------------------------------------------------------------------------------- /data/avatar/13Ashe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/13Ashe.png -------------------------------------------------------------------------------- /data/avatar/14Volibear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/14Volibear.png -------------------------------------------------------------------------------- /data/avatar/15Sejuani.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/15Sejuani.png -------------------------------------------------------------------------------- /data/avatar/16Anivia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/16Anivia.png -------------------------------------------------------------------------------- /data/avatar/17Blitzcrank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/17Blitzcrank.png -------------------------------------------------------------------------------- /data/avatar/18Darius.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/18Darius.png -------------------------------------------------------------------------------- /data/avatar/19Katarina.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/19Katarina.png -------------------------------------------------------------------------------- /data/avatar/20Draven.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/20Draven.png -------------------------------------------------------------------------------- /data/avatar/21Fiora.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/21Fiora.png -------------------------------------------------------------------------------- /data/avatar/22Garen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/22Garen.png -------------------------------------------------------------------------------- /data/avatar/23Vayne.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/23Vayne.png -------------------------------------------------------------------------------- /data/avatar/24Lucian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/24Lucian.png -------------------------------------------------------------------------------- /data/avatar/25Leona.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/25Leona.png -------------------------------------------------------------------------------- /data/avatar/26Kayle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/26Kayle.png -------------------------------------------------------------------------------- /data/avatar/27Shen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/27Shen.png -------------------------------------------------------------------------------- /data/avatar/28Zed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/28Zed.png -------------------------------------------------------------------------------- /data/avatar/29Kennen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/29Kennen.png -------------------------------------------------------------------------------- /data/avatar/30Akali.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/30Akali.png -------------------------------------------------------------------------------- /data/avatar/31Graves.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/31Graves.png -------------------------------------------------------------------------------- /data/avatar/32Pyke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/32Pyke.png -------------------------------------------------------------------------------- /data/avatar/33Twist Fate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/33Twist Fate.png -------------------------------------------------------------------------------- /data/avatar/34Gangplank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/34Gangplank.png -------------------------------------------------------------------------------- /data/avatar/35Miss Fortune.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/35Miss Fortune.png -------------------------------------------------------------------------------- /data/avatar/36Mordekaiser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/36Mordekaiser.png -------------------------------------------------------------------------------- /data/avatar/37Kindred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/37Kindred.png -------------------------------------------------------------------------------- /data/avatar/38Karthus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/38Karthus.png -------------------------------------------------------------------------------- /data/avatar/39Warwick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/39Warwick.png -------------------------------------------------------------------------------- /data/avatar/40Nidalee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/40Nidalee.png -------------------------------------------------------------------------------- /data/avatar/41Ahri.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/41Ahri.png -------------------------------------------------------------------------------- /data/avatar/42Rengar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/42Rengar.png -------------------------------------------------------------------------------- /data/avatar/43Gnar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/43Gnar.png -------------------------------------------------------------------------------- /data/avatar/44Kha'Zix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/44Kha'Zix.png -------------------------------------------------------------------------------- /data/avatar/45Kassadin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/45Kassadin.png -------------------------------------------------------------------------------- /data/avatar/46Rek'Sai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/46Rek'Sai.png -------------------------------------------------------------------------------- /data/avatar/47Cho'Gath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/47Cho'Gath.png -------------------------------------------------------------------------------- /data/avatar/48Kaisa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/48Kaisa.png -------------------------------------------------------------------------------- /data/avatar/49Tristana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/49Tristana.png -------------------------------------------------------------------------------- /data/avatar/50Lulu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/50Lulu.png -------------------------------------------------------------------------------- /data/avatar/51Poppy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/51Poppy.png -------------------------------------------------------------------------------- /data/avatar/52Veigar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/52Veigar.png -------------------------------------------------------------------------------- /data/avatar/53Camille.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/53Camille.png -------------------------------------------------------------------------------- /data/avatar/54jayce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/54jayce.png -------------------------------------------------------------------------------- /data/avatar/55VI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/55VI.png -------------------------------------------------------------------------------- /data/avatar/56Jinx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/avatar/56Jinx.png -------------------------------------------------------------------------------- /data/champions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Varus", 4 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Varus.png&resize=64:", 5 | "price": 2, 6 | "origin": [ 7 | "demon" 8 | ], 9 | "class": [ 10 | "ranger" 11 | ] 12 | }, 13 | { 14 | "name": "Elise", 15 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Elise.png&resize=64:", 16 | "price": 1, 17 | "origin": [ 18 | "demon" 19 | ], 20 | "class": [ 21 | "shapeshifter" 22 | ] 23 | }, 24 | { 25 | "name": "Morgana", 26 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Morgana.png&resize=64:", 27 | "price": 3, 28 | "origin": [ 29 | "demon" 30 | ], 31 | "class": [ 32 | "sorcerer" 33 | ] 34 | }, 35 | { 36 | "name": "Evelynn", 37 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Evelynn.png&resize=64:", 38 | "price": 3, 39 | "origin": [ 40 | "demon" 41 | ], 42 | "class": [ 43 | "assassin" 44 | ] 45 | }, 46 | { 47 | "name": "Aatrox", 48 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Aatrox.png&resize=64:", 49 | "price": 3, 50 | "origin": [ 51 | "demon" 52 | ], 53 | "class": [ 54 | "blademaster" 55 | ] 56 | }, 57 | { 58 | "name": "Brand", 59 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Brand.png&resize=64:", 60 | "price": 4, 61 | "origin": [ 62 | "demon" 63 | ], 64 | "class": [ 65 | "elementalist" 66 | ] 67 | }, 68 | { 69 | "name": "Swain", 70 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Swain.png&resize=64:", 71 | "price": 5, 72 | "origin": [ 73 | "demon", 74 | "imperial" 75 | ], 76 | "class": [ 77 | "shapeshifter" 78 | ] 79 | }, 80 | { 81 | "name": "Shyvana", 82 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Shyvana.png&resize=64:", 83 | "price": 3, 84 | "origin": [ 85 | "dragon" 86 | ], 87 | "class": [ 88 | "shapeshifter" 89 | ] 90 | }, 91 | { 92 | "name": "Aurelion Sol", 93 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/AurelionSol.png&resize=64:", 94 | "price": 4, 95 | "origin": [ 96 | "dragon" 97 | ], 98 | "class": [ 99 | "sorcerer" 100 | ] 101 | }, 102 | { 103 | "name": "Pantheon", 104 | "avatar": "http://game.gtimg.cn/images/lol/tft/cham-icons/80.png", 105 | "price": 5, 106 | "origin": [ 107 | "dragon" 108 | ], 109 | "class": [ 110 | "guardian" 111 | ] 112 | }, 113 | { 114 | "name": "Yasuo", 115 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Yasuo.png&resize=64:", 116 | "price": 5, 117 | "origin": [ 118 | "exile" 119 | ], 120 | "class": [ 121 | "blademaster" 122 | ] 123 | }, 124 | { 125 | "name": "Braum", 126 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Braum.png&resize=64:", 127 | "price": 2, 128 | "origin": [ 129 | "glacial" 130 | ], 131 | "class": [ 132 | "guardian" 133 | ] 134 | }, 135 | { 136 | "name": "Lissandra", 137 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Lissandra.png&resize=64:", 138 | "price": 2, 139 | "origin": [ 140 | "glacial" 141 | ], 142 | "class": [ 143 | "elementalist" 144 | ] 145 | }, 146 | { 147 | "name": "Ashe", 148 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Ashe.png&resize=64:", 149 | "price": 3, 150 | "origin": [ 151 | "glacial" 152 | ], 153 | "class": [ 154 | "ranger" 155 | ] 156 | }, 157 | { 158 | "name": "Volibear", 159 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Volibear.png&resize=64:", 160 | "price": 3, 161 | "origin": [ 162 | "glacial" 163 | ], 164 | "class": [ 165 | "brawler" 166 | ] 167 | }, 168 | { 169 | "name": "Sejuani", 170 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Sejuani.png&resize=64:", 171 | "price": 4, 172 | "origin": [ 173 | "glacial" 174 | ], 175 | "class": [ 176 | "knight" 177 | ] 178 | }, 179 | { 180 | "name": "Anivia", 181 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Anivia.png&resize=64:", 182 | "price": 5, 183 | "origin": [ 184 | "glacial" 185 | ], 186 | "class": [ 187 | "elementalist" 188 | ] 189 | }, 190 | { 191 | "name": "Blitzcrank", 192 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Blitzcrank.png&resize=64:", 193 | "price": 2, 194 | "origin": [ 195 | "robot" 196 | ], 197 | "class": [ 198 | "brawler" 199 | ] 200 | }, 201 | { 202 | "name": "Darius", 203 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Darius.png&resize=64:", 204 | "price": 1, 205 | "origin": [ 206 | "imperial" 207 | ], 208 | "class": [ 209 | "knight" 210 | ] 211 | }, 212 | { 213 | "name": "Katarina", 214 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Katarina.png&resize=64:", 215 | "price": 3, 216 | "origin": [ 217 | "imperial" 218 | ], 219 | "class": [ 220 | "assassin" 221 | ] 222 | }, 223 | { 224 | "name": "Draven", 225 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Draven.png&resize=64:", 226 | "price": 4, 227 | "origin": [ 228 | "imperial" 229 | ], 230 | "class": [ 231 | "blademaster" 232 | ] 233 | }, 234 | { 235 | "name": "Fiora", 236 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Fiora.png&resize=64:", 237 | "price": 1, 238 | "origin": [ 239 | "noble" 240 | ], 241 | "class": [ 242 | "blademaster" 243 | ] 244 | }, 245 | { 246 | "name": "Garen", 247 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Garen.png&resize=64:", 248 | "price": 1, 249 | "origin": [ 250 | "noble" 251 | ], 252 | "class": [ 253 | "knight" 254 | ] 255 | }, 256 | { 257 | "name": "Vayne", 258 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Vayne.png&resize=64:", 259 | "price": 1, 260 | "origin": [ 261 | "noble" 262 | ], 263 | "class": [ 264 | "ranger" 265 | ] 266 | }, 267 | { 268 | "name": "Lucian", 269 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Lucian.png&resize=64:", 270 | "price": 2, 271 | "origin": [ 272 | "noble" 273 | ], 274 | "class": [ 275 | "gunslinger" 276 | ] 277 | }, 278 | { 279 | "name": "Leona", 280 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Leona.png&resize=64:", 281 | "price": 4, 282 | "origin": [ 283 | "noble" 284 | ], 285 | "class": [ 286 | "guardian" 287 | ] 288 | }, 289 | { 290 | "name": "Kayle", 291 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Kayle.png&resize=64:", 292 | "price": 5, 293 | "origin": [ 294 | "noble" 295 | ], 296 | "class": [ 297 | "knight" 298 | ] 299 | }, 300 | { 301 | "name": "Shen", 302 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Shen.png&resize=64:", 303 | "price": 2, 304 | "origin": [ 305 | "ninja" 306 | ], 307 | "class": [ 308 | "blademaster" 309 | ] 310 | }, 311 | { 312 | "name": "Zed", 313 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Zed.png&resize=64:", 314 | "price": 2, 315 | "origin": [ 316 | "ninja" 317 | ], 318 | "class": [ 319 | "assassin" 320 | ] 321 | }, 322 | { 323 | "name": "Kennen", 324 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Kennen.png&resize=64:", 325 | "price": 3, 326 | "origin": [ 327 | "ninja", 328 | "yordle" 329 | ], 330 | "class": [ 331 | "elementalist" 332 | ] 333 | }, 334 | { 335 | "name": "Akali", 336 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Akali.png&resize=64:", 337 | "price": 4, 338 | "origin": [ 339 | "ninja" 340 | ], 341 | "class": [ 342 | "assassin" 343 | ] 344 | }, 345 | { 346 | "name": "Graves", 347 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Graves.png&resize=64:", 348 | "price": 1, 349 | "origin": [ 350 | "pirate" 351 | ], 352 | "class": [ 353 | "gunslinger" 354 | ] 355 | }, 356 | { 357 | "name": "Pyke", 358 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Pyke.png&resize=64:", 359 | "price": 2, 360 | "origin": [ 361 | "pirate" 362 | ], 363 | "class": [ 364 | "assassin" 365 | ] 366 | }, 367 | { 368 | "name": "Twist Fate", 369 | "avatar": "http://game.gtimg.cn/images/lol/tft/cham-icons/4.png", 370 | "price": 2, 371 | "origin": [ 372 | "pirate" 373 | ], 374 | "class": [ 375 | "sorcerer" 376 | ] 377 | }, 378 | { 379 | "name": "Gangplank", 380 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Gangplank.png&resize=64:", 381 | "price": 3, 382 | "origin": [ 383 | "pirate" 384 | ], 385 | "class": [ 386 | "blademaster", 387 | "gunslinger" 388 | ] 389 | }, 390 | { 391 | "name": "Miss Fortune", 392 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/MissFortune.png&resize=64:", 393 | "price": 5, 394 | "origin": [ 395 | "pirate" 396 | ], 397 | "class": [ 398 | "gunslinger" 399 | ] 400 | }, 401 | { 402 | "name": "Mordekaiser", 403 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Mordekaiser.png&resize=64:", 404 | "price": 1, 405 | "origin": [ 406 | "phantom" 407 | ], 408 | "class": [ 409 | "knight" 410 | ] 411 | }, 412 | { 413 | "name": "Kindred", 414 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Kindred.png&resize=64:", 415 | "price": 4, 416 | "origin": [ 417 | "phantom" 418 | ], 419 | "class": [ 420 | "ranger" 421 | ] 422 | }, 423 | { 424 | "name": "Karthus", 425 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Karthus.png&resize=64:", 426 | "price": 5, 427 | "origin": [ 428 | "phantom" 429 | ], 430 | "class": [ 431 | "sorcerer" 432 | ] 433 | }, 434 | { 435 | "name": "Warwick", 436 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Warwick.png&resize=64:", 437 | "price": 1, 438 | "origin": [ 439 | "wild" 440 | ], 441 | "class": [ 442 | "brawler" 443 | ] 444 | }, 445 | { 446 | "name": "Nidalee", 447 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Nidalee.png&resize=64:", 448 | "price": 1, 449 | "origin": [ 450 | "wild" 451 | ], 452 | "class": [ 453 | "shapeshifter" 454 | ] 455 | }, 456 | { 457 | "name": "Ahri", 458 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Ahri.png&resize=64:", 459 | "price": 2, 460 | "origin": [ 461 | "wild" 462 | ], 463 | "class": [ 464 | "sorcerer" 465 | ] 466 | }, 467 | { 468 | "name": "Rengar", 469 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Rengar.png&resize=64:", 470 | "price": 3, 471 | "origin": [ 472 | "wild" 473 | ], 474 | "class": [ 475 | "assassin" 476 | ] 477 | }, 478 | { 479 | "name": "Gnar", 480 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Gnar.png&resize=64:", 481 | "price": 4, 482 | "origin": [ 483 | "wild", 484 | "yordle" 485 | ], 486 | "class": [ 487 | "shapeshifter" 488 | ] 489 | }, 490 | { 491 | "name": "Kha'Zix", 492 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Khazix.png&resize=64:", 493 | "price": 1, 494 | "origin": [ 495 | "void" 496 | ], 497 | "class": [ 498 | "assassin" 499 | ] 500 | }, 501 | { 502 | "name": "Kassadin", 503 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Kassadin.png&resize=64:", 504 | "price": 1, 505 | "origin": [ 506 | "void" 507 | ], 508 | "class": [ 509 | "sorcerer" 510 | ] 511 | }, 512 | { 513 | "name": "Rek'Sai", 514 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/RekSai.png&resize=64:", 515 | "price": 2, 516 | "origin": [ 517 | "void" 518 | ], 519 | "class": [ 520 | "brawler" 521 | ] 522 | }, 523 | { 524 | "name": "Cho'Gath", 525 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Chogath.png&resize=64:", 526 | "price": 4, 527 | "origin": [ 528 | "void" 529 | ], 530 | "class": [ 531 | "brawler" 532 | ] 533 | }, 534 | { 535 | "name": "Kaisa", 536 | "avatar": "http://game.gtimg.cn/images/lol/tft/cham-icons/145.png", 537 | "price": 5, 538 | "origin": [ 539 | "void" 540 | ], 541 | "class": [ 542 | "assassin", 543 | "ranger" 544 | ] 545 | }, 546 | { 547 | "name": "Tristana", 548 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Tristana.png&resize=64:", 549 | "price": 1, 550 | "origin": [ 551 | "yordle" 552 | ], 553 | "class": [ 554 | "gunslinger" 555 | ] 556 | }, 557 | { 558 | "name": "Lulu", 559 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Lulu.png&resize=64:", 560 | "price": 2, 561 | "origin": [ 562 | "yordle" 563 | ], 564 | "class": [ 565 | "sorcerer" 566 | ] 567 | }, 568 | { 569 | "name": "Poppy", 570 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Poppy.png&resize=64:", 571 | "price": 3, 572 | "origin": [ 573 | "yordle" 574 | ], 575 | "class": [ 576 | "knight" 577 | ] 578 | }, 579 | { 580 | "name": "Veigar", 581 | "avatar": "https://am-a.akamaihd.net/image?f=https://news-a.akamaihd.net/public/images/articles/2019/june/tftcompendium/Champions/Veigar.png&resize=64:", 582 | "price": 3, 583 | "origin": [ 584 | "yordle" 585 | ], 586 | "class": [ 587 | "sorcerer" 588 | ] 589 | }, 590 | { 591 | "name": "Camille", 592 | "avatar": "http://game.gtimg.cn/images/lol/tft/cham-icons/164.png", 593 | "price": 1, 594 | "origin": [ 595 | "Hextech" 596 | ], 597 | "class": [ 598 | "blademaster" 599 | ] 600 | }, 601 | { 602 | "name": "Jayce", 603 | "avatar": "http://game.gtimg.cn/images/lol/tft/cham-icons/126.png", 604 | "price": 2, 605 | "origin": [ 606 | "Hextech" 607 | ], 608 | "class": [ 609 | "shapeshifter" 610 | ] 611 | }, 612 | { 613 | "name": "VI", 614 | "avatar": "http://game.gtimg.cn/images/lol/tft/cham-icons/254.png", 615 | "price": 3, 616 | "origin": [ 617 | "Hextech" 618 | ], 619 | "class": [ 620 | "brawler" 621 | ] 622 | }, 623 | { 624 | "name": "Jinx", 625 | "avatar": "http://game.gtimg.cn/images/lol/tft/cham-icons/222.png", 626 | "price": 4, 627 | "origin": [ 628 | "Hextech" 629 | ], 630 | "class": [ 631 | "gunslinger" 632 | ] 633 | } 634 | ] -------------------------------------------------------------------------------- /data/champions_graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "0": [ 3 | 1, 4 | 2, 5 | 3, 6 | 4, 7 | 5, 8 | 6, 9 | 10, 10 | 13, 11 | 17, 12 | 23, 13 | 27, 14 | 28, 15 | 29, 16 | 30, 17 | 37, 18 | 48 19 | ], 20 | "1": [ 21 | 2, 22 | 3, 23 | 4, 24 | 5, 25 | 6, 26 | 7, 27 | 10, 28 | 17, 29 | 27, 30 | 28, 31 | 29, 32 | 30, 33 | 40, 34 | 43 35 | ], 36 | "10": [ 37 | 17, 38 | 20, 39 | 21, 40 | 27, 41 | 28, 42 | 29, 43 | 30, 44 | 34, 45 | 53 46 | ], 47 | "11": [ 48 | 12, 49 | 13, 50 | 14, 51 | 15, 52 | 16, 53 | 17, 54 | 25, 55 | 27, 56 | 28, 57 | 29, 58 | 30 59 | ], 60 | "12": [ 61 | 13, 62 | 14, 63 | 15, 64 | 16, 65 | 17, 66 | 27, 67 | 28, 68 | 29, 69 | 30 70 | ], 71 | "13": [ 72 | 14, 73 | 15, 74 | 16, 75 | 17, 76 | 23, 77 | 27, 78 | 28, 79 | 29, 80 | 30, 81 | 37, 82 | 48 83 | ], 84 | "14": [ 85 | 15, 86 | 16, 87 | 17, 88 | 27, 89 | 28, 90 | 29, 91 | 30, 92 | 39, 93 | 46, 94 | 47, 95 | 54 96 | ], 97 | "15": [ 98 | 16, 99 | 17, 100 | 18, 101 | 22, 102 | 26, 103 | 27, 104 | 28, 105 | 29, 106 | 30, 107 | 36, 108 | 51 109 | ], 110 | "16": [ 111 | 17, 112 | 27, 113 | 28, 114 | 29, 115 | 30 116 | ], 117 | "17": [ 118 | 27, 119 | 28, 120 | 29, 121 | 30, 122 | 39, 123 | 46, 124 | 47, 125 | 54 126 | ], 127 | "18": [ 128 | 19, 129 | 20, 130 | 22, 131 | 26, 132 | 27, 133 | 28, 134 | 29, 135 | 30, 136 | 36, 137 | 51 138 | ], 139 | "19": [ 140 | 20, 141 | 27, 142 | 28, 143 | 29, 144 | 30, 145 | 32, 146 | 42, 147 | 44, 148 | 48 149 | ], 150 | "2": [ 151 | 3, 152 | 4, 153 | 5, 154 | 6, 155 | 8, 156 | 10, 157 | 17, 158 | 27, 159 | 28, 160 | 29, 161 | 30, 162 | 33, 163 | 38, 164 | 41, 165 | 45, 166 | 50, 167 | 52 168 | ], 169 | "20": [ 170 | 21, 171 | 27, 172 | 28, 173 | 29, 174 | 30, 175 | 34, 176 | 53 177 | ], 178 | "21": [ 179 | 22, 180 | 23, 181 | 24, 182 | 25, 183 | 26, 184 | 27, 185 | 28, 186 | 29, 187 | 30, 188 | 34, 189 | 53 190 | ], 191 | "22": [ 192 | 23, 193 | 24, 194 | 25, 195 | 26, 196 | 27, 197 | 28, 198 | 29, 199 | 30, 200 | 36, 201 | 51 202 | ], 203 | "23": [ 204 | 24, 205 | 25, 206 | 26, 207 | 27, 208 | 28, 209 | 29, 210 | 30, 211 | 37, 212 | 48 213 | ], 214 | "24": [ 215 | 25, 216 | 26, 217 | 27, 218 | 28, 219 | 29, 220 | 30, 221 | 36, 222 | 51 223 | ], 224 | "25": [ 225 | 26, 226 | 27, 227 | 28, 228 | 29, 229 | 30 230 | ], 231 | "26": [ 232 | 27, 233 | 28, 234 | 29, 235 | 30, 236 | 36, 237 | 51 238 | ], 239 | "27": [ 240 | 28, 241 | 29, 242 | 30, 243 | 34, 244 | 53 245 | ], 246 | "28": [ 247 | 29, 248 | 30, 249 | 32, 250 | 42, 251 | 44, 252 | 48 253 | ], 254 | "29": [ 255 | 30, 256 | 43, 257 | 49, 258 | 50, 259 | 51, 260 | 52 261 | ], 262 | "3": [ 263 | 4, 264 | 5, 265 | 6, 266 | 10, 267 | 17, 268 | 19, 269 | 27, 270 | 28, 271 | 29, 272 | 30, 273 | 32, 274 | 42, 275 | 44, 276 | 48 277 | ], 278 | "30": [ 279 | 32, 280 | 42, 281 | 44, 282 | 48 283 | ], 284 | "31": [ 285 | 32, 286 | 33, 287 | 34, 288 | 35, 289 | 36, 290 | 51 291 | ], 292 | "32": [ 293 | 33, 294 | 34, 295 | 35, 296 | 42, 297 | 44, 298 | 48 299 | ], 300 | "33": [ 301 | 34, 302 | 35, 303 | 38, 304 | 41, 305 | 45, 306 | 50, 307 | 52 308 | ], 309 | "34": [ 310 | 35, 311 | 36, 312 | 51, 313 | 53 314 | ], 315 | "35": [ 316 | 36, 317 | 51 318 | ], 319 | "36": [ 320 | 37, 321 | 38, 322 | 51 323 | ], 324 | "37": [ 325 | 38, 326 | 48 327 | ], 328 | "38": [ 329 | 41, 330 | 45, 331 | 50, 332 | 52 333 | ], 334 | "39": [ 335 | 40, 336 | 41, 337 | 42, 338 | 43, 339 | 46, 340 | 47, 341 | 54 342 | ], 343 | "4": [ 344 | 5, 345 | 6, 346 | 10, 347 | 17, 348 | 20, 349 | 21, 350 | 27, 351 | 28, 352 | 29, 353 | 30, 354 | 34, 355 | 53 356 | ], 357 | "40": [ 358 | 41, 359 | 42, 360 | 43 361 | ], 362 | "41": [ 363 | 42, 364 | 43, 365 | 45, 366 | 50, 367 | 52 368 | ], 369 | "42": [ 370 | 43, 371 | 44, 372 | 48 373 | ], 374 | "43": [ 375 | 49, 376 | 50, 377 | 51, 378 | 52 379 | ], 380 | "44": [ 381 | 45, 382 | 46, 383 | 47, 384 | 48 385 | ], 386 | "45": [ 387 | 46, 388 | 47, 389 | 48, 390 | 50, 391 | 52 392 | ], 393 | "46": [ 394 | 47, 395 | 48, 396 | 54 397 | ], 398 | "47": [ 399 | 48, 400 | 54 401 | ], 402 | "48": null, 403 | "49": [ 404 | 50, 405 | 51, 406 | 52 407 | ], 408 | "5": [ 409 | 6, 410 | 10, 411 | 12, 412 | 16, 413 | 17, 414 | 27, 415 | 28, 416 | 29, 417 | 30 418 | ], 419 | "50": [ 420 | 51, 421 | 52 422 | ], 423 | "51": [ 424 | 52 425 | ], 426 | "52": null, 427 | "53": [ 428 | 54, 429 | 55 430 | ], 431 | "54": [ 432 | 55 433 | ], 434 | "55": null, 435 | "6": [ 436 | 7, 437 | 10, 438 | 17, 439 | 18, 440 | 19, 441 | 20, 442 | 27, 443 | 28, 444 | 29, 445 | 30, 446 | 40, 447 | 43 448 | ], 449 | "7": [ 450 | 8, 451 | 9, 452 | 10, 453 | 17, 454 | 27, 455 | 28, 456 | 29, 457 | 30, 458 | 40, 459 | 43 460 | ], 461 | "8": [ 462 | 9, 463 | 10, 464 | 17, 465 | 27, 466 | 28, 467 | 29, 468 | 30, 469 | 33, 470 | 38, 471 | 41, 472 | 45, 473 | 50, 474 | 52 475 | ], 476 | "9": [ 477 | 10, 478 | 11, 479 | 17, 480 | 25, 481 | 27, 482 | 28, 483 | 29, 484 | 30 485 | ] 486 | } -------------------------------------------------------------------------------- /data/final_result/total_strength/final_result6.json: -------------------------------------------------------------------------------- 1 | [ 2 | "[('元素师', 3), ('冰川', 2), ('龙', 2), ('护卫', 2), ('忍者', 1)]", 3 | "[('忍者', 1), ('元素师', 3), ('护卫', 2), ('冰川', 4)]", 4 | "[('元素师', 3), ('冰川', 2), ('浪人', 1), ('护卫', 2), ('忍者', 1)]", 5 | "[('游侠', 2), ('冰川', 2), ('龙', 2), ('幽灵', 2), ('护卫', 2)]", 6 | "[('浪人', 1), ('枪手', 2), ('龙', 2), ('护卫', 2)]", 7 | "[('变形者', 3), ('帝国', 2), ('恶魔', 2), ('龙', 2), ('护卫', 2)]", 8 | "[('幽灵', 2), ('骑士', 2), ('龙', 2), ('护卫', 2)]", 9 | "[('虚空', 2), ('龙', 2), ('刺客', 3), ('护卫', 2), ('忍者', 1)]", 10 | "[('枪手', 2), ('剑士', 3), ('浪人', 1), ('护卫', 2), ('忍者', 1)]", 11 | "[('法师', 3), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 12 | "[('游侠', 2), ('冰川', 2), ('浪人', 1), ('幽灵', 2), ('护卫', 2)]", 13 | "[('浪人', 1), ('贵族', 3), ('龙', 2), ('护卫', 2)]", 14 | "[('骑士', 2), ('冰川', 2), ('龙', 2), ('浪人', 1), ('护卫', 2)]", 15 | "[('元素师', 3), ('冰川', 2), ('机器人', 1), ('护卫', 2), ('忍者', 1)]", 16 | "[('枪手', 2), ('剑士', 3), ('浪人', 1), ('护卫', 2), ('海克斯', 2)]", 17 | "[('浪人', 1), ('幽灵', 2), ('骑士', 2), ('护卫', 2)]", 18 | "[('贵族', 3), ('骑士', 4), ('冰川', 2), ('护卫', 2)]", 19 | "[('枪手', 2), ('帝国', 2), ('剑士', 3), ('恶魔', 2), ('浪人', 1)]", 20 | "[('骑士', 2), ('幽灵', 2), ('冰川', 2), ('护卫', 2)]", 21 | "[('约德尔', 3), ('龙', 2), ('法师', 3), ('护卫', 2), ('忍者', 1)]", 22 | "[('虚空', 2), ('刺客', 3), ('浪人', 1), ('护卫', 2), ('忍者', 1)]", 23 | "[('浪人', 1), ('剑士', 3), ('贵族', 3), ('护卫', 2)]", 24 | "[('浪人', 1), ('骑士', 2), ('贵族', 3), ('护卫', 2)]", 25 | "[('游侠', 2), ('虚空', 2), ('冰川', 2), ('刺客', 3), ('护卫', 2), ('忍者', 1)]", 26 | "[('元素师', 3), ('骑士', 2), ('帝国', 2), ('恶魔', 2), ('冰川', 2)]", 27 | "[('浪人', 1), ('帝国', 2), ('龙', 2), ('护卫', 2)]", 28 | "[('约德尔', 3), ('元素师', 3), ('恶魔', 2), ('法师', 3), ('忍者', 1)]", 29 | "[('变形者', 3), ('恶魔', 2), ('龙', 2), ('浪人', 1), ('护卫', 2)]", 30 | "[('约德尔', 3), ('元素师', 3), ('骑士', 2), ('冰川', 2), ('忍者', 1)]", 31 | "[('枪手', 2), ('帝国', 2), ('剑士', 3), ('浪人', 1), ('海克斯', 2)]", 32 | "[('剑士', 3), ('龙', 2), ('浪人', 1), ('护卫', 2), ('忍者', 1)]", 33 | "[('贵族', 3), ('骑士', 2), ('冰川', 2), ('护卫', 2)]", 34 | "[('斗士', 2), ('虚空', 2), ('冰川', 2), ('龙', 2), ('护卫', 2)]", 35 | "[('游侠', 2), ('幽灵', 2), ('骑士', 2), ('护卫', 2)]", 36 | "[('枪手', 2), ('帝国', 2), ('剑士', 3), ('浪人', 1), ('忍者', 1)]", 37 | "[('幽灵', 2), ('骑士', 2), ('元素师', 3), ('冰川', 2)]", 38 | "[('骑士', 2), ('贵族', 3), ('龙', 2), ('护卫', 2)]", 39 | "[('忍者', 1), ('枪手', 2), ('龙', 2), ('护卫', 2)]", 40 | "[('骑士', 2), ('冰川', 2), ('龙', 2), ('护卫', 2), ('忍者', 1)]", 41 | "[('骑士', 2), ('帝国', 2), ('冰川', 2), ('龙', 2), ('护卫', 2)]", 42 | "[('斗士', 2), ('虚空', 2), ('龙', 2), ('机器人', 1), ('护卫', 2)]", 43 | "[('枪手', 2), ('帝国', 2), ('剑士', 3), ('机器人', 1), ('浪人', 1)]", 44 | "[('元素师', 3), ('帝国', 2), ('恶魔', 2), ('浪人', 1), ('忍者', 1)]", 45 | "[('元素师', 3), ('冰川', 2), ('护卫', 2)]", 46 | "[('冰川', 2), ('龙', 2), ('浪人', 1), ('护卫', 2), ('忍者', 1)]", 47 | "[('忍者', 1), ('元素师', 3), ('骑士', 2), ('冰川', 4)]", 48 | "[('浪人', 1), ('枪手', 2), ('剑士', 3), ('龙', 2)]", 49 | "[('忍者', 1), ('虚空', 2), ('刺客', 6)]", 50 | "[('游侠', 2), ('法师', 3), ('幽灵', 2), ('虚空', 2)]", 51 | "[('骑士', 2), ('浪人', 1), ('元素师', 3), ('冰川', 2)]", 52 | "[('机器人', 1), ('贵族', 3), ('龙', 2), ('护卫', 2)]", 53 | "[('游侠', 2), ('冰川', 2), ('龙', 2), ('浪人', 1), ('护卫', 2)]", 54 | "[('元素师', 3), ('恶魔', 2), ('冰川', 2), ('浪人', 1), ('忍者', 1)]", 55 | "[('骑士', 2), ('贵族', 3), ('帝国', 2), ('剑士', 3), ('浪人', 1)]", 56 | "[('法师', 3), ('枪手', 2), ('海盗', 3), ('龙', 2)]", 57 | "[('变形者', 3), ('恶魔', 2), ('冰川', 2), ('龙', 2), ('护卫', 2)]", 58 | "[('骑士', 2), ('冰川', 2), ('龙', 2), ('机器人', 1), ('护卫', 2)]", 59 | "[('游侠', 2), ('骑士', 2), ('幽灵', 2), ('贵族', 3)]", 60 | "[('忍者', 1), ('浪人', 1), ('贵族', 3), ('护卫', 2)]", 61 | "[('贵族', 3), ('骑士', 2), ('斗士', 2), ('冰川', 2), ('机器人', 1), ('护卫', 2)]", 62 | "[('忍者', 1), ('帝国', 2), ('龙', 2), ('护卫', 2)]", 63 | "[('约德尔', 3), ('枪手', 2), ('骑士', 2), ('贵族', 3), ('忍者', 1)]", 64 | "[('冰川', 2), ('龙', 2), ('机器人', 1), ('浪人', 1), ('护卫', 2)]", 65 | "[('斗士', 2), ('虚空', 2), ('冰川', 2), ('浪人', 1), ('护卫', 2)]", 66 | "[('元素师', 3), ('虚空', 2), ('冰川', 2), ('刺客', 3), ('忍者', 1)]", 67 | "[('幽灵', 2), ('贵族', 3), ('骑士', 4)]", 68 | "[('虚空', 2), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 69 | "[('忍者', 1), ('枪手', 2), ('元素师', 3), ('冰川', 2)]", 70 | "[('变形者', 3), ('恶魔', 2), ('龙', 2), ('护卫', 2), ('忍者', 1)]", 71 | "[('骑士', 2), ('帝国', 2), ('恶魔', 2), ('法师', 3), ('幽灵', 2)]" 72 | ] -------------------------------------------------------------------------------- /data/final_result/total_strength/final_result7.json: -------------------------------------------------------------------------------- 1 | [ 2 | "[('法师', 3), ('骑士', 2), ('龙', 2), ('护卫', 2), ('幽灵', 2)]", 3 | "[('冰川', 2), ('法师', 3), ('游侠', 2), ('龙', 2), ('护卫', 2), ('幽灵', 2)]", 4 | "[('骑士', 2), ('元素师', 3), ('忍者', 1), ('冰川', 4), ('护卫', 2)]", 5 | "[('冰川', 2), ('贵族', 3), ('骑士', 4), ('护卫', 2), ('幽灵', 2)]", 6 | "[('元素师', 3), ('忍者', 1), ('冰川', 4), ('龙', 2), ('护卫', 2)]", 7 | "[('枪手', 2), ('忍者', 1), ('剑士', 3), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 8 | "[('冰川', 2), ('元素师', 3), ('忍者', 1), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 9 | "[('元素师', 3), ('忍者', 1), ('冰川', 4), ('浪人', 1), ('护卫', 2)]", 10 | "[('骑士', 2), ('浪人', 1), ('龙', 2), ('护卫', 2), ('幽灵', 2)]", 11 | "[('骑士', 2), ('贵族', 3), ('浪人', 1), ('护卫', 2), ('幽灵', 2)]", 12 | "[('冰川', 2), ('元素师', 3), ('恶魔', 2), ('龙', 2), ('护卫', 2)]", 13 | "[('冰川', 2), ('骑士', 2), ('龙', 2), ('护卫', 2), ('幽灵', 2)]", 14 | "[('冰川', 2), ('帝国', 2), ('变形者', 3), ('骑士', 2), ('恶魔', 2), ('龙', 2), ('护卫', 2)]", 15 | "[('法师', 3), ('虚空', 2), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 16 | "[('骑士', 2), ('贵族', 3), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 17 | "[('帝国', 2), ('变形者', 3), ('恶魔', 2), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 18 | "[('帝国', 2), ('龙', 2), ('护卫', 2), ('枪手', 2)]", 19 | "[('龙', 2), ('护卫', 2), ('枪手', 2), ('浪人', 1)]", 20 | "[('冰川', 2), ('约德尔', 3), ('元素师', 3), ('忍者', 1), ('护卫', 2)]", 21 | "[('法师', 3), ('约德尔', 3), ('忍者', 1), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 22 | "[('游侠', 2), ('护卫', 2), ('幽灵', 2), ('骑士', 2)]", 23 | "[('冰川', 2), ('帝国', 2), ('贵族', 3), ('骑士', 4), ('护卫', 2)]", 24 | "[('忍者', 1), ('刺客', 3), ('虚空', 2), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 25 | "[('元素师', 3), ('忍者', 1), ('冰川', 4), ('斗士', 2), ('护卫', 2), ('机器人', 1)]", 26 | "[('帝国', 2), ('骑士', 2), ('贵族', 3), ('龙', 2), ('护卫', 2)]", 27 | "[('骑士', 2), ('贵族', 3), ('剑士', 3), ('浪人', 1), ('护卫', 2)]", 28 | "[('贵族', 3), ('剑士', 3), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 29 | "[('冰川', 2), ('护卫', 2), ('游侠', 4), ('幽灵', 2)]", 30 | "[('法师', 3), ('恶魔', 2), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 31 | "[('冰川', 2), ('游侠', 2), ('忍者', 1), ('刺客', 3), ('虚空', 2), ('龙', 2), ('护卫', 2)]", 32 | "[('冰川', 2), ('骑士', 2), ('浪人', 1), ('护卫', 2), ('幽灵', 2)]", 33 | "[('冰川', 2), ('骑士', 2), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 34 | "[('帝国', 2), ('刺客', 6), ('忍者', 1), ('恶魔', 2), ('虚空', 2)]", 35 | "[('护卫', 2), ('幽灵', 2), ('枪手', 2), ('浪人', 1)]", 36 | "[('冰川', 2), ('游侠', 2), ('骑士', 2), ('贵族', 3), ('护卫', 2), ('幽灵', 2)]", 37 | "[('帝国', 2), ('法师', 3), ('骑士', 2), ('恶魔', 2), ('龙', 2), ('幽灵', 2)]", 38 | "[('游侠', 2), ('骑士', 2), ('贵族', 3), ('冰川', 4), ('护卫', 2)]", 39 | "[('帝国', 2), ('骑士', 2), ('龙', 2), ('护卫', 2), ('幽灵', 2)]", 40 | "[('帝国', 2), ('刺客', 3), ('虚空', 2), ('龙', 2), ('护卫', 2)]", 41 | "[('帝国', 2), ('剑士', 3), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 42 | "[('帝国', 2), ('骑士', 2), ('浪人', 1), ('龙', 2), ('护卫', 2)]", 43 | "[('冰川', 2), ('骑士', 2), ('忍者', 1), ('刺客', 3), ('虚空', 2), ('护卫', 2)]", 44 | "[('海克斯', 2), ('枪手', 2), ('剑士', 3), ('浪人', 1), ('护卫', 2)]", 45 | "[('骑士', 2), ('龙', 2), ('护卫', 2), ('机器人', 1), ('幽灵', 2)]", 46 | "[('游侠', 2), ('元素师', 3), ('忍者', 1), ('冰川', 4), ('护卫', 2)]", 47 | "[('冰川', 2), ('游侠', 2), ('浪人', 1), ('护卫', 2), ('幽灵', 2)]", 48 | "[('冰川', 2), ('枪手', 2), ('元素师', 3), ('忍者', 1), ('剑士', 3), ('浪人', 1)]", 49 | "[('法师', 3), ('幽灵', 2), ('恶魔', 2), ('虚空', 2), ('游侠', 4)]", 50 | "[('冰川', 2), ('枪手', 2), ('剑士', 3), ('浪人', 1), ('护卫', 2)]", 51 | "[('帝国', 2), ('枪手', 2), ('剑士', 3), ('浪人', 1), ('龙', 2)]", 52 | "[('冰川', 2), ('法师', 3), ('约德尔', 3), ('元素师', 3), ('忍者', 1), ('恶魔', 2)]" 53 | ] -------------------------------------------------------------------------------- /data/final_result/total_strength/final_result8.json: -------------------------------------------------------------------------------- 1 | [ 2 | "[('忍者', 1), ('护卫', 2), ('冰川', 2), ('龙', 2), ('约德尔', 3), ('法师', 3), ('元素师', 3)]", 3 | "[('护卫', 2), ('冰川', 2), ('虚空', 2), ('龙', 2), ('游侠', 2), ('法师', 3), ('幽灵', 2)]", 4 | "[('骑士', 2), ('护卫', 2), ('龙', 2), ('帝国', 2), ('法师', 3), ('恶魔', 2), ('幽灵', 2)]", 5 | "[('骑士', 2), ('护卫', 2), ('虚空', 2), ('龙', 2), ('法师', 3), ('幽灵', 2)]", 6 | "[('骑士', 2), ('护卫', 2), ('冰川', 2), ('浪人', 1), ('龙', 2), ('法师', 3), ('幽灵', 2)]", 7 | "[('骑士', 2), ('忍者', 1), ('护卫', 2), ('龙', 2), ('冰川', 4), ('元素师', 3)]", 8 | "[('护卫', 2), ('浪人', 1), ('龙', 2), ('剑士', 3), ('枪手', 2), ('帝国', 2)]", 9 | "[('骑士', 2), ('护卫', 2), ('冰川', 2), ('浪人', 1), ('剑士', 3), ('枪手', 2), ('帝国', 2)]", 10 | "[('护卫', 2), ('冰川', 2), ('骑士', 4), ('幽灵', 2), ('贵族', 3)]", 11 | "[('护卫', 2), ('龙', 2), ('变形者', 3), ('枪手', 2), ('帝国', 2), ('恶魔', 2)]", 12 | "[('护卫', 2), ('浪人', 1), ('龙', 2), ('海盗', 3), ('枪手', 2), ('法师', 3)]", 13 | "[('骑士', 2), ('护卫', 2), ('冰川', 2), ('游侠', 4), ('幽灵', 2), ('贵族', 3)]", 14 | "[('忍者', 1), ('护卫', 2), ('冰川', 2), ('龙', 2), ('变形者', 3), ('恶魔', 2), ('元素师', 3)]", 15 | "[('骑士', 2), ('护卫', 2), ('浪人', 1), ('龙', 2), ('幽灵', 2), ('贵族', 3)]", 16 | "[('骑士', 2), ('护卫', 2), ('龙', 2), ('变形者', 3), ('帝国', 2), ('恶魔', 2), ('贵族', 3)]", 17 | "[('忍者', 1), ('护卫', 2), ('浪人', 1), ('龙', 2), ('剑士', 3), ('枪手', 2), ('贵族', 3)]", 18 | "[('护卫', 2), ('龙', 2), ('骑士', 4), ('帝国', 2), ('贵族', 3)]", 19 | "[('贵族', 3), ('护卫', 2), ('骑士', 6), ('冰川', 2)]", 20 | "[('骑士', 2), ('浪人', 1), ('贵族', 6), ('剑士', 3), ('枪手', 2)]", 21 | "[('骑士', 2), ('护卫', 2), ('龙', 2), ('游侠', 2), ('幽灵', 2)]", 22 | "[('护卫', 2), ('浪人', 1), ('龙', 2), ('枪手', 2), ('幽灵', 2)]", 23 | "[('骑士', 2), ('忍者', 1), ('护卫', 2), ('浪人', 1), ('剑士', 3), ('幽灵', 2), ('贵族', 3)]", 24 | "[('骑士', 2), ('护卫', 2), ('冰川', 2), ('龙', 2), ('枪手', 2), ('帝国', 2)]", 25 | "[('骑士', 2), ('护卫', 2), ('冰川', 2), ('浪人', 1), ('龙', 2), ('变形者', 3), ('帝国', 2), ('恶魔', 2)]", 26 | "[('忍者', 1), ('护卫', 2), ('龙', 2), ('法师', 3), ('恶魔', 2), ('元素师', 3)]" 27 | ] -------------------------------------------------------------------------------- /data/final_result/total_strength/final_result9.json: -------------------------------------------------------------------------------- 1 | [ 2 | "[('骑士', 2), ('剑士', 3), ('浪人', 1), ('枪手', 2), ('贵族', 6), ('护卫', 2)]", 3 | "[('骑士', 2), ('贵族', 3), ('冰川', 4), ('枪手', 2), ('忍者', 1), ('元素师', 3), ('护卫', 2)]", 4 | "[('骑士', 2), ('龙', 2), ('法师', 3), ('游侠', 2), ('虚空', 2), ('护卫', 2), ('冰川', 2), ('幽灵', 2)]", 5 | "[('贵族', 3), ('冰川', 4), ('忍者', 1), ('元素师', 3), ('护卫', 2), ('骑士', 4)]", 6 | "[('龙', 2), ('法师', 3), ('虚空', 2), ('冰川', 2), ('护卫', 2), ('游侠', 4), ('幽灵', 2)]", 7 | "[('龙', 2), ('约德尔', 3), ('法师', 3), ('冰川', 4), ('忍者', 1), ('元素师', 3), ('护卫', 2)]", 8 | "[('恶魔', 2), ('龙', 2), ('约德尔', 3), ('法师', 3), ('忍者', 1), ('元素师', 3), ('护卫', 2), ('冰川', 2)]", 9 | "[('贵族', 3), ('骑士', 6), ('护卫', 2), ('冰川', 2), ('幽灵', 2)]", 10 | "[('骑士', 2), ('龙', 2), ('贵族', 3), ('浪人', 1), ('法师', 3), ('护卫', 2), ('幽灵', 2)]", 11 | "[('龙', 2), ('剑士', 3), ('变形者', 3), ('浪人', 1), ('帝国', 2), ('枪手', 2), ('护卫', 2), ('恶魔', 2)]", 12 | "[('骑士', 2), ('龙', 2), ('法师', 3), ('帝国', 2), ('护卫', 2), ('恶魔', 2), ('幽灵', 2)]", 13 | "[('骑士', 2), ('龙', 2), ('剑士', 3), ('浪人', 1), ('帝国', 2), ('枪手', 2), ('护卫', 2), ('冰川', 2)]", 14 | "[('约德尔', 3), ('贵族', 3), ('枪手', 2), ('忍者', 1), ('护卫', 2), ('骑士', 4), ('冰川', 2)]", 15 | "[('骑士', 2), ('龙', 2), ('浪人', 1), ('贵族', 6), ('护卫', 2)]", 16 | "[('龙', 2), ('浪人', 1), ('法师', 3), ('枪手', 2), ('护卫', 2), ('幽灵', 2)]", 17 | "[('龙', 2), ('法师', 3), ('护卫', 2), ('骑士', 4), ('冰川', 2), ('幽灵', 2)]", 18 | "[('贵族', 3), ('帝国', 2), ('骑士', 6), ('护卫', 2), ('冰川', 2)]", 19 | "[('龙', 2), ('贵族', 3), ('变形者', 3), ('帝国', 2), ('护卫', 2), ('骑士', 4), ('恶魔', 2)]", 20 | "[('骑士', 2), ('贵族', 3), ('剑士', 3), ('浪人', 1), ('枪手', 2), ('忍者', 1), ('护卫', 2)]", 21 | "[('骑士', 2), ('龙', 2), ('冰川', 4), ('帝国', 2), ('元素师', 3), ('护卫', 2), ('恶魔', 2)]", 22 | "[('龙', 2), ('贵族', 3), ('帝国', 2), ('护卫', 2), ('骑士', 4), ('幽灵', 2)]", 23 | "[('骑士', 2), ('龙', 2), ('浪人', 1), ('法师', 3), ('冰川', 2), ('护卫', 2), ('恶魔', 2), ('幽灵', 2)]", 24 | "[('骑士', 2), ('龙', 2), ('浪人', 1), ('冰川', 4), ('忍者', 1), ('元素师', 3), ('护卫', 2)]", 25 | "[('骑士', 2), ('贵族', 3), ('冰川', 2), ('护卫', 2), ('游侠', 4), ('幽灵', 2)]", 26 | "[('贵族', 3), ('游侠', 2), ('护卫', 2), ('骑士', 4), ('冰川', 2), ('幽灵', 2)]", 27 | "[('龙', 2), ('剑士', 3), ('浪人', 1), ('法师', 3), ('海盗', 3), ('枪手', 2), ('护卫', 2), ('恶魔', 2)]", 28 | "[('龙', 2), ('剑士', 3), ('浪人', 1), ('法师', 3), ('海克斯', 2), ('枪手', 2), ('护卫', 2)]", 29 | "[('骑士', 2), ('斗士', 2), ('龙', 2), ('法师', 3), ('虚空', 2), ('机器人', 1), ('护卫', 2), ('幽灵', 2)]", 30 | "[('恶魔', 2), ('骑士', 2), ('龙', 2), ('帝国', 2), ('忍者', 1), ('元素师', 3), ('护卫', 2), ('冰川', 2)]", 31 | "[('龙', 2), ('浪人', 1), ('法师', 3), ('忍者', 1), ('元素师', 3), ('护卫', 2), ('恶魔', 2)]", 32 | "[('骑士', 2), ('剑士', 3), ('浪人', 1), ('枪手', 2), ('忍者', 1), ('护卫', 2), ('冰川', 2), ('幽灵', 2)]", 33 | "[('骑士', 2), ('龙', 2), ('法师', 3), ('狂野', 2), ('护卫', 2), ('冰川', 2), ('幽灵', 2)]", 34 | "[('骑士', 2), ('冰川', 6), ('忍者', 1), ('元素师', 3), ('护卫', 2)]", 35 | "[('骑士', 2), ('龙', 2), ('法师', 3), ('冰川', 4), ('护卫', 2), ('幽灵', 2)]", 36 | "[('龙', 2), ('浪人', 1), ('海盗', 3), ('法师', 3), ('虚空', 2), ('枪手', 2), ('护卫', 2)]", 37 | "[('骑士', 2), ('剑士', 3), ('帝国', 2), ('枪手', 2), ('贵族', 6)]", 38 | "[('骑士', 2), ('斗士', 2), ('贵族', 3), ('冰川', 4), ('忍者', 1), ('机器人', 1), ('元素师', 3), ('护卫', 2)]", 39 | "[('骑士', 2), ('龙', 2), ('贵族', 6), ('机器人', 1), ('护卫', 2)]", 40 | "[('骑士', 2), ('龙', 2), ('法师', 3), ('虚空', 2), ('忍者', 1), ('护卫', 2), ('幽灵', 2)]", 41 | "[('龙', 2), ('浪人', 1), ('法师', 3), ('游侠', 2), ('护卫', 2), ('冰川', 2), ('幽灵', 2)]", 42 | "[('骑士', 2), ('浪人', 1), ('游侠', 2), ('贵族', 6), ('护卫', 2)]", 43 | "[('龙', 2), ('剑士', 3), ('浪人', 1), ('帝国', 2), ('枪手', 2), ('忍者', 1), ('护卫', 2)]", 44 | "[('骑士', 2), ('约德尔', 3), ('冰川', 4), ('忍者', 1), ('元素师', 3), ('护卫', 2)]", 45 | "[('骑士', 2), ('龙', 2), ('贵族', 3), ('剑士', 3), ('浪人', 1), ('帝国', 2), ('护卫', 2)]", 46 | "[('龙', 2), ('变形者', 3), ('恶魔', 4), ('忍者', 1), ('元素师', 3), ('护卫', 2), ('冰川', 2)]", 47 | "[('贵族', 3), ('冰川', 4), ('护卫', 2), ('骑士', 4), ('幽灵', 2)]", 48 | "[('骑士', 2), ('龙', 2), ('约德尔', 3), ('贵族', 3), ('枪手', 2), ('忍者', 1), ('护卫', 2)]", 49 | "[('骑士', 2), ('龙', 2), ('贵族', 3), ('剑士', 3), ('浪人', 1), ('忍者', 1), ('护卫', 2), ('幽灵', 2)]", 50 | "[('龙', 2), ('法师', 3), ('刺客', 3), ('虚空', 2), ('帝国', 2), ('护卫', 2), ('恶魔', 2)]", 51 | "[('骑士', 2), ('龙', 2), ('贵族', 3), ('变形者', 3), ('浪人', 1), ('帝国', 2), ('护卫', 2), ('恶魔', 2)]", 52 | "[('贵族', 3), ('骑士', 6), ('机器人', 1), ('护卫', 2), ('冰川', 2)]", 53 | "[('骑士', 2), ('龙', 2), ('枪手', 2), ('忍者', 1), ('护卫', 2), ('冰川', 2), ('幽灵', 2)]", 54 | "[('贵族', 3), ('剑士', 3), ('浪人', 1), ('帝国', 2), ('护卫', 2), ('骑士', 4), ('冰川', 2)]", 55 | "[('龙', 2), ('贵族', 3), ('剑士', 3), ('浪人', 1), ('海克斯', 2), ('枪手', 2), ('忍者', 1), ('护卫', 2)]", 56 | "[('龙', 2), ('剑士', 3), ('变形者', 3), ('浪人', 1), ('恶魔', 4), ('帝国', 2), ('护卫', 2)]", 57 | "[('龙', 2), ('法师', 3), ('忍者', 1), ('机器人', 1), ('元素师', 3), ('护卫', 2), ('冰川', 2)]", 58 | "[('贵族', 3), ('刺客', 3), ('帝国', 2), ('忍者', 1), ('护卫', 2), ('骑士', 4), ('冰川', 2)]", 59 | "[('贵族', 3), ('浪人', 1), ('枪手', 2), ('忍者', 1), ('护卫', 2), ('剑士', 6)]", 60 | "[('骑士', 2), ('浪人', 1), ('忍者', 1), ('贵族', 6), ('护卫', 2)]", 61 | "[('骑士', 2), ('龙', 2), ('约德尔', 3), ('法师', 3), ('帝国', 2), ('忍者', 1), ('护卫', 2), ('恶魔', 2)]", 62 | "[('龙', 2), ('变形者', 3), ('帝国', 2), ('枪手', 2), ('冰川', 2), ('护卫', 2), ('恶魔', 2)]", 63 | "[('骑士', 2), ('浪人', 1), ('枪手', 2), ('护卫', 2), ('幽灵', 2)]", 64 | "[('恶魔', 2), ('龙', 2), ('变形者', 3), ('浪人', 1), ('忍者', 1), ('元素师', 3), ('护卫', 2), ('冰川', 2)]", 65 | "[('骑士', 2), ('龙', 2), ('约德尔', 3), ('浪人', 1), ('法师', 3), ('忍者', 1), ('护卫', 2), ('冰川', 2)]", 66 | "[('龙', 2), ('约德尔', 3), ('变形者', 3), ('法师', 3), ('忍者', 1), ('护卫', 2), ('恶魔', 2)]", 67 | "[('枪手', 2), ('护卫', 2), ('贵族', 6), ('骑士', 2)]", 68 | "[('骑士', 2), ('约德尔', 3), ('贵族', 3), ('游侠', 2), ('枪手', 2), ('忍者', 1), ('护卫', 2), ('冰川', 2)]" 69 | ] -------------------------------------------------------------------------------- /data/final_result/trait_num/final_result6.json: -------------------------------------------------------------------------------- 1 | [ 2 | "[('忍者', 1), ('冰川', 2), ('刺客', 3), ('游侠', 2), ('机器人', 1), ('虚空', 2), ('斗士', 2)]", 3 | "[('虚空', 4), ('忍者', 1), ('刺客', 3), ('机器人', 1), ('斗士', 2)]", 4 | "[('恶魔', 2), ('忍者', 1), ('刺客', 3), ('机器人', 1), ('虚空', 2), ('斗士', 2)]", 5 | "[('忍者', 1), ('冰川', 2), ('刺客', 3), ('游侠', 2), ('虚空', 2), ('护卫', 2)]", 6 | "[('忍者', 1), ('贵族', 3), ('刺客', 3), ('游侠', 2), ('骑士', 2), ('虚空', 2)]", 7 | "[('恶魔', 2), ('帝国', 2), ('忍者', 1), ('刺客', 3), ('游侠', 2), ('机器人', 1)]", 8 | "[('恶魔', 2), ('元素师', 3), ('忍者', 1), ('冰川', 2), ('机器人', 1), ('斗士', 2)]", 9 | "[('冰川', 2), ('游侠', 2), ('机器人', 1), ('虚空', 2), ('斗士', 2), ('护卫', 2)]", 10 | "[('贵族', 3), ('冰川', 2), ('骑士', 2), ('机器人', 1), ('斗士', 2), ('护卫', 2)]", 11 | "[('恶魔', 2), ('游侠', 2), ('浪人', 1), ('机器人', 1), ('虚空', 2), ('斗士', 2)]", 12 | "[('忍者', 1), ('刺客', 3), ('游侠', 2), ('浪人', 1), ('机器人', 1), ('虚空', 2)]", 13 | "[('恶魔', 2), ('帝国', 2), ('剑士', 3), ('忍者', 1), ('浪人', 1), ('机器人', 1)]", 14 | "[('忍者', 1), ('冰川', 2), ('龙', 2), ('机器人', 1), ('斗士', 2), ('护卫', 2)]", 15 | "[('恶魔', 2), ('剑士', 3), ('忍者', 1), ('冰川', 2), ('游侠', 2), ('浪人', 1)]", 16 | "[('恶魔', 2), ('帝国', 2), ('骑士', 2), ('游侠', 2), ('浪人', 1), ('幽灵', 2)]", 17 | "[('剑士', 3), ('忍者', 1), ('海克斯', 2), ('浪人', 1), ('机器人', 1), ('斗士', 2)]", 18 | "[('狂野', 2), ('刺客', 3), ('游侠', 2), ('机器人', 1), ('虚空', 2), ('斗士', 2)]", 19 | "[('变形者', 3), ('恶魔', 2), ('狂野', 2), ('浪人', 1), ('机器人', 1), ('斗士', 2)]", 20 | "[('冰川', 2), ('斗士', 4), ('游侠', 2), ('机器人', 1), ('虚空', 2)]", 21 | "[('虚空', 4), ('忍者', 1), ('刺客', 3), ('游侠', 2), ('斗士', 2)]", 22 | "[('恶魔', 2), ('虚空', 4), ('刺客', 3), ('游侠', 2), ('斗士', 2)]", 23 | "[('恶魔', 2), ('帝国', 2), ('刺客', 3), ('游侠', 2), ('浪人', 1), ('虚空', 2)]", 24 | "[('变形者', 3), ('恶魔', 2), ('帝国', 2), ('狂野', 2), ('忍者', 1), ('刺客', 3)]", 25 | "[('斗士', 4), ('海克斯', 2), ('浪人', 1), ('机器人', 1), ('虚空', 2)]", 26 | "[('元素师', 3), ('冰川', 4), ('忍者', 1), ('机器人', 1), ('斗士', 2)]", 27 | "[('冰川', 2), ('骑士', 2), ('游侠', 2), ('机器人', 1), ('幽灵', 2), ('斗士', 2)]", 28 | "[('变形者', 3), ('恶魔', 2), ('帝国', 2), ('约德尔', 3), ('忍者', 1), ('骑士', 2)]", 29 | "[('恶魔', 2), ('帝国', 2), ('元素师', 3), ('忍者', 1), ('冰川', 2), ('骑士', 2)]", 30 | "[('冰川', 2), ('斗士', 4), ('机器人', 1), ('虚空', 2), ('护卫', 2)]", 31 | "[('剑士', 3), ('忍者', 1), ('贵族', 3), ('骑士', 2), ('浪人', 1), ('机器人', 1)]", 32 | "[('狂野', 2), ('斗士', 4), ('浪人', 1), ('机器人', 1), ('虚空', 2)]", 33 | "[('虚空', 4), ('忍者', 1), ('刺客', 3), ('浪人', 1), ('斗士', 2)]", 34 | "[('帝国', 2), ('忍者', 1), ('冰川', 2), ('刺客', 3), ('游侠', 2), ('骑士', 2)]" 35 | ] -------------------------------------------------------------------------------- /data/final_result/trait_num/final_result7.json: -------------------------------------------------------------------------------- 1 | [ 2 | "[('忍者', 1), ('冰川', 2), ('剑士', 3), ('海克斯', 2), ('枪手', 2), ('机器人', 1), ('斗士', 2)]", 3 | "[('骑士', 2), ('忍者', 1), ('冰川', 2), ('虚空', 2), ('刺客', 3), ('机器人', 1), ('斗士', 2)]", 4 | "[('忍者', 1), ('浪人', 1), ('冰川', 2), ('虚空', 2), ('护卫', 2), ('刺客', 3), ('游侠', 2)]", 5 | "[('斗士', 4), ('狂野', 2), ('虚空', 4), ('刺客', 3), ('机器人', 1)]", 6 | "[('游侠', 2), ('忍者', 1), ('虚空', 2), ('狂野', 2), ('刺客', 3), ('机器人', 1), ('斗士', 2)]", 7 | "[('恶魔', 2), ('忍者', 1), ('浪人', 1), ('虚空', 2), ('刺客', 3), ('机器人', 1), ('斗士', 2)]", 8 | "[('骑士', 2), ('忍者', 1), ('剑士', 3), ('帝国', 2), ('海克斯', 2), ('机器人', 1), ('斗士', 2)]", 9 | "[('恶魔', 2), ('忍者', 1), ('冰川', 2), ('帝国', 2), ('元素师', 3), ('机器人', 1), ('斗士', 2)]", 10 | "[('游侠', 2), ('浪人', 1), ('冰川', 2), ('虚空', 2), ('护卫', 2), ('机器人', 1), ('斗士', 2)]", 11 | "[('忍者', 1), ('斗士', 4), ('虚空', 4), ('刺客', 3), ('机器人', 1)]", 12 | "[('恶魔', 2), ('游侠', 2), ('浪人', 1), ('虚空', 2), ('帝国', 2), ('机器人', 1), ('斗士', 2)]", 13 | "[('恶魔', 2), ('忍者', 1), ('虚空', 2), ('帝国', 2), ('刺客', 3), ('机器人', 1), ('游侠', 2)]", 14 | "[('恶魔', 2), ('变形者', 3), ('忍者', 1), ('浪人', 1), ('龙', 2), ('剑士', 3), ('帝国', 2)]", 15 | "[('恶魔', 2), ('浪人', 1), ('剑士', 3), ('帝国', 2), ('海克斯', 2), ('机器人', 1), ('斗士', 2)]", 16 | "[('游侠', 2), ('忍者', 1), ('虚空', 4), ('刺客', 3), ('机器人', 1), ('斗士', 2)]", 17 | "[('恶魔', 2), ('变形者', 3), ('忍者', 1), ('狂野', 2), ('帝国', 2), ('刺客', 3), ('机器人', 1)]", 18 | "[('恶魔', 2), ('忍者', 1), ('浪人', 1), ('虚空', 2), ('剑士', 3), ('帝国', 2), ('刺客', 3)]", 19 | "[('忍者', 1), ('浪人', 1), ('龙', 2), ('剑士', 3), ('海克斯', 2), ('机器人', 1), ('斗士', 2)]", 20 | "[('忍者', 1), ('浪人', 1), ('冰川', 2), ('龙', 2), ('护卫', 2), ('机器人', 1), ('斗士', 2)]", 21 | "[('冰川', 2), ('虚空', 2), ('斗士', 4), ('护卫', 2), ('龙', 2), ('机器人', 1)]", 22 | "[('恶魔', 2), ('忍者', 1), ('浪人', 1), ('冰川', 2), ('剑士', 3), ('机器人', 1), ('斗士', 2)]", 23 | "[('恶魔', 2), ('游侠', 2), ('冰川', 2), ('虚空', 2), ('元素师', 3), ('机器人', 1), ('斗士', 2)]", 24 | "[('骑士', 2), ('恶魔', 2), ('浪人', 1), ('帝国', 2), ('机器人', 1), ('游侠', 2), ('幽灵', 2)]", 25 | "[('骑士', 2), ('恶魔', 2), ('变形者', 3), ('冰川', 2), ('龙', 2), ('护卫', 2), ('帝国', 2)]", 26 | "[('恶魔', 2), ('变形者', 3), ('浪人', 1), ('狂野', 2), ('帝国', 2), ('机器人', 1), ('斗士', 2)]", 27 | "[('恶魔', 2), ('海盗', 3), ('忍者', 1), ('浪人', 1), ('剑士', 3), ('枪手', 2), ('刺客', 3)]", 28 | "[('骑士', 2), ('恶魔', 2), ('忍者', 1), ('浪人', 1), ('剑士', 3), ('帝国', 2), ('机器人', 1)]", 29 | "[('恶魔', 2), ('冰川', 2), ('虚空', 2), ('斗士', 4), ('机器人', 1), ('游侠', 2)]", 30 | "[('恶魔', 2), ('法师', 3), ('虚空', 2), ('斗士', 2), ('狂野', 2), ('机器人', 1), ('游侠', 2)]", 31 | "[('恶魔', 2), ('忍者', 1), ('浪人', 1), ('冰川', 2), ('元素师', 3), ('机器人', 1), ('游侠', 2)]", 32 | "[('恶魔', 2), ('忍者', 1), ('冰川', 2), ('虚空', 2), ('刺客', 3), ('元素师', 3), ('游侠', 2)]", 33 | "[('恶魔', 2), ('游侠', 2), ('帝国', 2), ('虚空', 4), ('刺客', 3), ('斗士', 2)]", 34 | "[('恶魔', 2), ('变形者', 3), ('冰川', 2), ('龙', 2), ('护卫', 2), ('机器人', 1), ('斗士', 2)]", 35 | "[('骑士', 2), ('恶魔', 2), ('变形者', 3), ('忍者', 1), ('浪人', 1), ('帝国', 2), ('约德尔', 3)]", 36 | "[('恶魔', 2), ('变形者', 3), ('虚空', 2), ('斗士', 4), ('狂野', 2), ('机器人', 1)]", 37 | "[('骑士', 2), ('恶魔', 2), ('忍者', 1), ('浪人', 1), ('冰川', 2), ('帝国', 2), ('元素师', 3)]" 38 | ] -------------------------------------------------------------------------------- /data/final_result/trait_num/final_result8.json: -------------------------------------------------------------------------------- 1 | [ 2 | "[('斗士', 4), ('刺客', 3), ('忍者', 1), ('机器人', 1), ('冰川', 2), ('游侠', 2), ('虚空', 4)]", 3 | "[('刺客', 3), ('虚空', 2), ('忍者', 1), ('骑士', 2), ('帝国', 2), ('冰川', 2), ('机器人', 1), ('斗士', 2)]", 4 | "[('狂野', 2), ('斗士', 4), ('刺客', 3), ('忍者', 1), ('机器人', 1), ('虚空', 4)]", 5 | "[('刺客', 3), ('浪人', 1), ('忍者', 1), ('机器人', 1), ('虚空', 2), ('游侠', 2), ('恶魔', 2), ('斗士', 2)]", 6 | "[('变形者', 3), ('狂野', 2), ('剑士', 3), ('浪人', 1), ('忍者', 1), ('机器人', 1), ('恶魔', 2), ('斗士', 2)]", 7 | "[('冰川', 4), ('元素师', 3), ('忍者', 1), ('机器人', 1), ('游侠', 2), ('恶魔', 2), ('斗士', 2)]", 8 | "[('刺客', 3), ('机器人', 1), ('帝国', 2), ('游侠', 2), ('虚空', 4), ('恶魔', 2), ('斗士', 2)]", 9 | "[('刺客', 3), ('浪人', 1), ('忍者', 1), ('游侠', 2), ('虚空', 4), ('恶魔', 2), ('斗士', 2)]", 10 | "[('幽灵', 2), ('剑士', 3), ('浪人', 1), ('骑士', 2), ('忍者', 1), ('帝国', 2), ('游侠', 2), ('恶魔', 2)]", 11 | "[('变形者', 3), ('护卫', 2), ('骑士', 2), ('忍者', 1), ('龙', 2), ('帝国', 2), ('冰川', 2), ('恶魔', 2)]", 12 | "[('剑士', 3), ('浪人', 1), ('忍者', 1), ('帝国', 2), ('冰川', 2), ('机器人', 1), ('恶魔', 2), ('斗士', 2)]", 13 | "[('刺客', 3), ('贵族', 3), ('骑士', 2), ('忍者', 1), ('游侠', 2), ('虚空', 4), ('斗士', 2)]", 14 | "[('忍者', 1), ('法师', 3), ('机器人', 1), ('冰川', 2), ('约德尔', 3), ('游侠', 2), ('恶魔', 2), ('斗士', 2)]", 15 | "[('刺客', 3), ('元素师', 3), ('浪人', 1), ('忍者', 1), ('冰川', 2), ('虚空', 2), ('游侠', 2), ('恶魔', 2)]", 16 | "[('元素师', 3), ('虚空', 2), ('忍者', 1), ('冰川', 2), ('机器人', 1), ('游侠', 2), ('恶魔', 2), ('斗士', 2)]", 17 | "[('刺客', 3), ('浪人', 1), ('骑士', 2), ('忍者', 1), ('帝国', 2), ('虚空', 2), ('游侠', 2), ('恶魔', 2)]", 18 | "[('变形者', 3), ('护卫', 2), ('忍者', 1), ('龙', 2), ('冰川', 2), ('机器人', 1), ('恶魔', 2), ('斗士', 2)]", 19 | "[('变形者', 3), ('狂野', 2), ('刺客', 3), ('浪人', 1), ('忍者', 1), ('帝国', 2), ('机器人', 1), ('恶魔', 2)]", 20 | "[('变形者', 3), ('狂野', 2), ('刺客', 3), ('虚空', 2), ('帝国', 2), ('机器人', 1), ('恶魔', 2), ('斗士', 2)]", 21 | "[('枪手', 2), ('刺客', 3), ('剑士', 3), ('浪人', 1), ('忍者', 1), ('海盗', 3), ('机器人', 1), ('恶魔', 2)]", 22 | "[('刺客', 3), ('游侠', 4), ('虚空', 2), ('忍者', 1), ('机器人', 1), ('冰川', 2), ('斗士', 2)]", 23 | "[('变形者', 3), ('狂野', 2), ('斗士', 4), ('虚空', 2), ('机器人', 1), ('帝国', 2), ('恶魔', 2)]", 24 | "[('变形者', 3), ('狂野', 2), ('骑士', 2), ('机器人', 1), ('帝国', 2), ('约德尔', 3), ('恶魔', 2), ('斗士', 2)]", 25 | "[('剑士', 3), ('海克斯', 2), ('骑士', 2), ('忍者', 1), ('帝国', 2), ('冰川', 2), ('机器人', 1), ('斗士', 2)]", 26 | "[('狂野', 2), ('浪人', 1), ('法师', 3), ('机器人', 1), ('虚空', 2), ('游侠', 2), ('恶魔', 2), ('斗士', 2)]", 27 | "[('刺客', 3), ('剑士', 3), ('浪人', 1), ('恶魔', 4), ('忍者', 1), ('帝国', 2), ('游侠', 2)]", 28 | "[('枪手', 2), ('剑士', 3), ('海克斯', 2), ('忍者', 1), ('机器人', 1), ('冰川', 2), ('游侠', 2), ('斗士', 2)]", 29 | "[('变形者', 3), ('剑士', 3), ('浪人', 1), ('忍者', 1), ('龙', 2), ('帝国', 2), ('机器人', 1), ('恶魔', 2)]", 30 | "[('变形者', 3), ('剑士', 3), ('浪人', 1), ('海克斯', 2), ('帝国', 2), ('机器人', 1), ('恶魔', 2), ('斗士', 2)]", 31 | "[('变形者', 3), ('浪人', 1), ('骑士', 2), ('忍者', 1), ('机器人', 1), ('帝国', 2), ('约德尔', 3), ('恶魔', 2)]", 32 | "[('刺客', 3), ('剑士', 3), ('浪人', 1), ('虚空', 2), ('帝国', 2), ('机器人', 1), ('恶魔', 2), ('斗士', 2)]" 33 | ] -------------------------------------------------------------------------------- /data/final_result/trait_num/final_result9.json: -------------------------------------------------------------------------------- 1 | [ 2 | "[('剑士', 3), ('贵族', 3), ('斗士', 2), ('机器人', 1), ('忍者', 1), ('骑士', 4), ('帝国', 2), ('冰川', 2)]", 3 | "[('斗士', 4), ('骑士', 2), ('机器人', 1), ('忍者', 1), ('虚空', 4), ('刺客', 3), ('冰川', 2)]", 4 | "[('斗士', 4), ('海克斯', 2), ('机器人', 1), ('忍者', 1), ('游侠', 2), ('虚空', 4), ('刺客', 3)]", 5 | "[('恶魔', 2), ('斗士', 2), ('元素师', 3), ('机器人', 1), ('浪人', 1), ('忍者', 1), ('冰川', 4), ('游侠', 2)]", 6 | "[('恶魔', 2), ('刺客', 3), ('虚空', 2), ('斗士', 2), ('机器人', 1), ('浪人', 1), ('忍者', 1), ('游侠', 2), ('帝国', 2)]", 7 | "[('贵族', 3), ('斗士', 2), ('机器人', 1), ('枪手', 2), ('忍者', 1), ('骑士', 4), ('约德尔', 3), ('冰川', 2)]", 8 | "[('斗士', 4), ('法师', 3), ('恶魔', 2), ('虚空', 2), ('狂野', 2), ('机器人', 1), ('游侠', 2), ('冰川', 2)]", 9 | "[('恶魔', 2), ('元素师', 3), ('斗士', 2), ('忍者', 1), ('游侠', 2), ('虚空', 4), ('刺客', 3), ('冰川', 2)]", 10 | "[('剑士', 3), ('恶魔', 2), ('骑士', 2), ('机器人', 1), ('浪人', 1), ('忍者', 1), ('幽灵', 2), ('游侠', 2), ('帝国', 2)]", 11 | "[('剑士', 3), ('骑士', 2), ('海克斯', 2), ('斗士', 2), ('机器人', 1), ('忍者', 1), ('游侠', 2), ('帝国', 2), ('冰川', 2)]", 12 | "[('骑士', 2), ('贵族', 3), ('虚空', 2), ('斗士', 2), ('机器人', 1), ('忍者', 1), ('游侠', 2), ('刺客', 3), ('冰川', 2)]", 13 | "[('斗士', 4), ('恶魔', 2), ('狂野', 2), ('机器人', 1), ('游侠', 2), ('虚空', 4), ('刺客', 3)]", 14 | "[('法师', 3), ('恶魔', 2), ('狂野', 2), ('机器人', 1), ('斗士', 2), ('游侠', 2), ('护卫', 2), ('龙', 2), ('冰川', 2)]", 15 | "[('斗士', 4), ('骑士', 2), ('刺客', 3), ('虚空', 2), ('机器人', 1), ('忍者', 1), ('帝国', 2), ('冰川', 2)]", 16 | "[('剑士', 3), ('刺客', 3), ('虚空', 2), ('浪人', 1), ('忍者', 1), ('游侠', 2), ('帝国', 2), ('恶魔', 4)]", 17 | "[('恶魔', 2), ('虚空', 2), ('机器人', 1), ('斗士', 2), ('变形者', 3), ('狂野', 4), ('游侠', 2), ('刺客', 3)]", 18 | "[('剑士', 3), ('斗士', 2), ('机器人', 1), ('浪人', 1), ('游侠', 2), ('帝国', 2), ('冰川', 2), ('恶魔', 4)]", 19 | "[('剑士', 3), ('恶魔', 2), ('海克斯', 2), ('斗士', 2), ('机器人', 1), ('枪手', 2), ('忍者', 1), ('游侠', 2), ('冰川', 2)]", 20 | "[('恶魔', 2), ('斗士', 2), ('机器人', 1), ('忍者', 1), ('游侠', 2), ('护卫', 2), ('刺客', 3), ('冰川', 2), ('龙', 2)]", 21 | "[('剑士', 3), ('恶魔', 2), ('斗士', 2), ('浪人', 1), ('忍者', 1), ('游侠', 2), ('虚空', 4), ('刺客', 3)]", 22 | "[('剑士', 3), ('恶魔', 2), ('海克斯', 2), ('元素师', 3), ('斗士', 2), ('机器人', 1), ('浪人', 1), ('忍者', 1), ('冰川', 2)]", 23 | "[('恶魔', 2), ('虚空', 2), ('狂野', 2), ('斗士', 2), ('元素师', 3), ('机器人', 1), ('游侠', 2), ('刺客', 3), ('冰川', 2)]", 24 | "[('剑士', 3), ('虚空', 2), ('斗士', 2), ('机器人', 1), ('浪人', 1), ('忍者', 1), ('游侠', 2), ('恶魔', 4)]", 25 | "[('剑士', 3), ('狂野', 2), ('斗士', 2), ('变形者', 3), ('机器人', 1), ('浪人', 1), ('忍者', 1), ('恶魔', 4)]", 26 | "[('恶魔', 2), ('虚空', 2), ('斗士', 2), ('机器人', 1), ('游侠', 4), ('忍者', 1), ('刺客', 3), ('冰川', 2)]", 27 | "[('法师', 3), ('恶魔', 2), ('斗士', 2), ('机器人', 1), ('忍者', 1), ('游侠', 2), ('虚空', 4), ('刺客', 3)]", 28 | "[('剑士', 3), ('恶魔', 2), ('虚空', 2), ('狂野', 2), ('机器人', 1), ('斗士', 2), ('浪人', 1), ('游侠', 2), ('刺客', 3)]", 29 | "[('骑士', 2), ('恶魔', 2), ('斗士', 2), ('元素师', 3), ('机器人', 1), ('冰川', 4), ('幽灵', 2), ('游侠', 2)]", 30 | "[('剑士', 3), ('恶魔', 2), ('骑士', 2), ('贵族', 3), ('枪手', 2), ('浪人', 1), ('忍者', 1), ('游侠', 2), ('帝国', 2)]", 31 | "[('骑士', 2), ('恶魔', 2), ('刺客', 3), ('斗士', 2), ('忍者', 1), ('游侠', 2), ('虚空', 4), ('帝国', 2)]", 32 | "[('剑士', 3), ('骑士', 2), ('浪人', 1), ('忍者', 1), ('游侠', 2), ('帝国', 2), ('冰川', 2), ('恶魔', 4)]", 33 | "[('剑士', 3), ('恶魔', 2), ('骑士', 2), ('贵族', 3), ('虚空', 2), ('浪人', 1), ('忍者', 1), ('游侠', 2), ('刺客', 3)]", 34 | "[('恶魔', 2), ('虚空', 2), ('元素师', 3), ('机器人', 1), ('浪人', 1), ('忍者', 1), ('游侠', 2), ('刺客', 3), ('冰川', 2)]", 35 | "[('斗士', 4), ('恶魔', 2), ('虚空', 2), ('机器人', 1), ('元素师', 3), ('冰川', 4), ('游侠', 2)]", 36 | "[('骑士', 2), ('恶魔', 2), ('贵族', 3), ('斗士', 2), ('元素师', 3), ('机器人', 1), ('忍者', 1), ('游侠', 2), ('冰川', 2)]", 37 | "[('剑士', 3), ('恶魔', 2), ('浪人', 1), ('忍者', 1), ('游侠', 2), ('护卫', 2), ('帝国', 2), ('冰川', 2), ('龙', 2)]", 38 | "[('剑士', 3), ('恶魔', 2), ('骑士', 2), ('海克斯', 2), ('斗士', 2), ('机器人', 1), ('浪人', 1), ('忍者', 1), ('帝国', 2)]" 39 | ] -------------------------------------------------------------------------------- /data/language.json: -------------------------------------------------------------------------------- 1 | { 2 | "demon": "恶魔", 3 | "imperial": "帝国", 4 | "dragon": "龙", 5 | "exile": "浪人", 6 | "glacial": "冰川", 7 | "robot": "机器人", 8 | "noble": "贵族", 9 | "ninja": "忍者", 10 | "yordle": "约德尔", 11 | "pirate": "海盗", 12 | "phantom": "幽灵", 13 | "wild": "狂野", 14 | "void": "虚空", 15 | "Hextech": "海克斯", 16 | "ranger": "游侠", 17 | "shapeshifter": "变形者", 18 | "sorcerer": "法师", 19 | "assassin": "刺客", 20 | "blademaster": "剑士", 21 | "elementalist": "元素师", 22 | "guardian": "护卫", 23 | "brawler": "斗士", 24 | "knight": "骑士", 25 | "gunslinger": "枪手", 26 | "Varus": "维鲁斯", 27 | "Elise": "蜘蛛", 28 | "Morgana": "莫甘娜", 29 | "Evelynn": "寡妇", 30 | "Aatrox": "剑魔", 31 | "Brand": "火男", 32 | "Swain": "乌鸦", 33 | "Shyvana": "龙女", 34 | "Aurelion Sol": "龙王", 35 | "Pantheon": "潘森", 36 | "Yasuo": "亚索", 37 | "Braum": "布隆", 38 | "Lissandra": "丽桑卓", 39 | "Ashe": "艾希", 40 | "Volibear": "狗熊", 41 | "Sejuani": "猪妹", 42 | "Anivia": "冰鸟", 43 | "Blitzcrank": "机器人", 44 | "Darius": "诺手", 45 | "Katarina": "卡特", 46 | "Draven": "德莱文", 47 | "Fiora": "剑姬", 48 | "Garen": "盖伦", 49 | "Vayne": "薇恩", 50 | "Lucian": "卢锡安", 51 | "Leona": "日女", 52 | "Kayle": "天使", 53 | "Shen": "慎", 54 | "Zed": "劫", 55 | "Kennen": "凯南", 56 | "Akali": "阿卡丽", 57 | "Graves": "男枪", 58 | "Pyke": "派克", 59 | "Twist Fate": "卡牌", 60 | "Gangplank": "船长", 61 | "Miss Fortune": "好运姐", 62 | "Mordekaiser": "铁男", 63 | "Kindred": "千珏", 64 | "Karthus": "死歌", 65 | "Warwick": "狼人", 66 | "Nidalee": "豹女", 67 | "Ahri": "狐狸", 68 | "Rengar": "狮子狗", 69 | "Gnar": "纳尔", 70 | "Kha'Zix": "螳螂", 71 | "Kassadin": "卡萨丁", 72 | "Rek'Sai": "挖掘机", 73 | "Cho'Gath": "大虫子", 74 | "Kaisa": "卡萨", 75 | "Tristana": "小炮", 76 | "Lulu": "露露", 77 | "Poppy": "波比", 78 | "Veigar": "小法", 79 | "Camille": "卡密尔", 80 | "jayce": "杰斯", 81 | "VI": "蔚", 82 | "Jinx": "金克斯" 83 | } -------------------------------------------------------------------------------- /data/trait_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_graph.png -------------------------------------------------------------------------------- /data/trait_icons/Assassin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Assassin.png -------------------------------------------------------------------------------- /data/trait_icons/Blademaster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Blademaster.png -------------------------------------------------------------------------------- /data/trait_icons/Brawler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Brawler.png -------------------------------------------------------------------------------- /data/trait_icons/Demon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Demon.png -------------------------------------------------------------------------------- /data/trait_icons/Dragon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Dragon.png -------------------------------------------------------------------------------- /data/trait_icons/Elementalist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Elementalist.png -------------------------------------------------------------------------------- /data/trait_icons/Exile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Exile.png -------------------------------------------------------------------------------- /data/trait_icons/Glacial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Glacial.png -------------------------------------------------------------------------------- /data/trait_icons/Guardian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Guardian.png -------------------------------------------------------------------------------- /data/trait_icons/Gunslinger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Gunslinger.png -------------------------------------------------------------------------------- /data/trait_icons/Hextech.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Hextech.png -------------------------------------------------------------------------------- /data/trait_icons/Imperial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Imperial.png -------------------------------------------------------------------------------- /data/trait_icons/Knight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Knight.png -------------------------------------------------------------------------------- /data/trait_icons/Ninja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Ninja.png -------------------------------------------------------------------------------- /data/trait_icons/Noble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Noble.png -------------------------------------------------------------------------------- /data/trait_icons/Phantom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Phantom.png -------------------------------------------------------------------------------- /data/trait_icons/Pirate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Pirate.png -------------------------------------------------------------------------------- /data/trait_icons/Ranger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Ranger.png -------------------------------------------------------------------------------- /data/trait_icons/Robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Robot.png -------------------------------------------------------------------------------- /data/trait_icons/Shapeshifter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Shapeshifter.png -------------------------------------------------------------------------------- /data/trait_icons/Sorcerer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Sorcerer.png -------------------------------------------------------------------------------- /data/trait_icons/Void.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Void.png -------------------------------------------------------------------------------- /data/trait_icons/Wild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Wild.png -------------------------------------------------------------------------------- /data/trait_icons/Yordle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiziyoung/TFT/5f4448dccc2afcd75c52de39e603ef066c7c4166/data/trait_icons/Yordle.png -------------------------------------------------------------------------------- /data/traits.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "demon", 4 | "bonus_num": [ 5 | 2, 6 | 4, 7 | 6 8 | ], 9 | "scope": [ 10 | 2, 11 | 2, 12 | 2 13 | ], 14 | "strength": [ 15 | 1.2, 16 | 1.52, 17 | 1.66 18 | ], 19 | "champions": [ 20 | "Varus", 21 | "Elise", 22 | "Morgana", 23 | "Evelynn", 24 | "Aatrox", 25 | "Brand", 26 | "Swain" 27 | ] 28 | }, 29 | { 30 | "name": "imperial", 31 | "bonus_num": [ 32 | 2, 33 | 4 34 | ], 35 | "scope": [ 36 | 1, 37 | 2 38 | ], 39 | "strength": [ 40 | 1.7, 41 | 1.7 42 | ], 43 | "champions": [ 44 | "Swain", 45 | "Darius", 46 | "Katarina", 47 | "Draven" 48 | ] 49 | }, 50 | { 51 | "name": "dragon", 52 | "bonus_num": [ 53 | 2 54 | ], 55 | "scope": [ 56 | 2 57 | ], 58 | "strength": [ 59 | 1.8 60 | ], 61 | "champions": [ 62 | "Shyvana", 63 | "Aurelion Sol", 64 | "Pantheon" 65 | ] 66 | }, 67 | { 68 | "name": "exile", 69 | "bonus_num": [ 70 | 1 71 | ], 72 | "scope": [ 73 | 1 74 | ], 75 | "strength": [ 76 | 1.6 77 | ], 78 | "champions": [ 79 | "Yasuo" 80 | ] 81 | }, 82 | { 83 | "name": "glacial", 84 | "bonus_num": [ 85 | 2, 86 | 4, 87 | 6 88 | ], 89 | "scope": [ 90 | 2, 91 | 2, 92 | 2 93 | ], 94 | "strength": [ 95 | 1.3, 96 | 1.45, 97 | 1.67 98 | ], 99 | "champions": [ 100 | "Braum", 101 | "Lissandra", 102 | "Ashe", 103 | "Volibear", 104 | "Sejuani", 105 | "Anivia" 106 | ] 107 | }, 108 | { 109 | "name": "robot", 110 | "bonus_num": [ 111 | 1 112 | ], 113 | "scope": [ 114 | 1 115 | ], 116 | "strength": [ 117 | 1.7 118 | ], 119 | "champions": [ 120 | "Blitzcrank" 121 | ] 122 | }, 123 | { 124 | "name": "noble", 125 | "bonus_num": [ 126 | 3, 127 | 6 128 | ], 129 | "scope": [ 130 | 1, 131 | 3 132 | ], 133 | "strength": [ 134 | 1.8, 135 | 1.8 136 | ], 137 | "champions": [ 138 | "Fiora", 139 | "Garen", 140 | "Vayne", 141 | "Lucian", 142 | "Leona", 143 | "Kayle" 144 | ] 145 | }, 146 | { 147 | "name": "ninja", 148 | "bonus_num": [ 149 | 1, 150 | 4 151 | ], 152 | "scope": [ 153 | 1, 154 | 2 155 | ], 156 | "strength": [ 157 | 1.4, 158 | 1.75 159 | ], 160 | "champions": [ 161 | "Shen", 162 | "Zed", 163 | "Kennen", 164 | "Akali" 165 | ] 166 | }, 167 | { 168 | "name": "yordle", 169 | "bonus_num": [ 170 | 3, 171 | 6, 172 | 9 173 | ], 174 | "scope": [ 175 | 2, 176 | 2, 177 | 2 178 | ], 179 | "strength": [ 180 | 1.4, 181 | 1.86, 182 | 2.5 183 | ], 184 | "champions": [ 185 | "Kennen", 186 | "Gnar", 187 | "Tristana", 188 | "Lulu", 189 | "Poppy", 190 | "Veigar" 191 | ] 192 | }, 193 | { 194 | "name": "pirate", 195 | "bonus_num": [ 196 | 3 197 | ], 198 | "scope": [ 199 | 1 200 | ], 201 | "strength": [ 202 | 1 203 | ], 204 | "champions": [ 205 | "Graves", 206 | "Pyke", 207 | "Twist Fate", 208 | "Gangplank", 209 | "Miss Fortune" 210 | ] 211 | }, 212 | { 213 | "name": "phantom", 214 | "bonus_num": [ 215 | 2 216 | ], 217 | "scope": [ 218 | 1 219 | ], 220 | "strength": [ 221 | 2 222 | ], 223 | "champions": [ 224 | "Mordekaiser", 225 | "Kindred", 226 | "Karthus" 227 | ] 228 | }, 229 | { 230 | "name": "wild", 231 | "bonus_num": [ 232 | 2, 233 | 4 234 | ], 235 | "scope": [ 236 | 2, 237 | 3 238 | ], 239 | "strength": [ 240 | 1.2, 241 | 1.2 242 | ], 243 | "champions": [ 244 | "Warwick", 245 | "Nidalee", 246 | "Ahri", 247 | "Rengar", 248 | "Gnar" 249 | ] 250 | }, 251 | { 252 | "name": "void", 253 | "bonus_num": [ 254 | 2, 255 | 4 256 | ], 257 | "scope": [ 258 | 1, 259 | 2 260 | ], 261 | "strength": [ 262 | 1.6, 263 | 1.6 264 | ], 265 | "champions": [ 266 | "Kha'Zix", 267 | "Kassadin", 268 | "Rek'Sai", 269 | "Cho'Gath", 270 | "Kaisa" 271 | ] 272 | }, 273 | { 274 | "name": "Hextech", 275 | "bonus_num": [ 276 | 2, 277 | 4 278 | ], 279 | "scope": [ 280 | 1, 281 | 2 282 | ], 283 | "strength": [ 284 | 1.5, 285 | 1.5 286 | ], 287 | "champions": [ 288 | "Camille", 289 | "VI", 290 | "Jinx" 291 | ] 292 | }, 293 | { 294 | "name": "ranger", 295 | "bonus_num": [ 296 | 2, 297 | 4 298 | ], 299 | "scope": [ 300 | 2, 301 | 2 302 | ], 303 | "strength": [ 304 | 1.25, 305 | 1.65 306 | ], 307 | "champions": [ 308 | "Varus", 309 | "Ashe", 310 | "Vayne", 311 | "Kindred", 312 | "Kaisa" 313 | ] 314 | }, 315 | { 316 | "name": "shapeshifter", 317 | "bonus_num": [ 318 | 3, 319 | 6 320 | ], 321 | "scope": [ 322 | 2, 323 | 2 324 | ], 325 | "strength": [ 326 | 1.4, 327 | 1.8 328 | ], 329 | "champions": [ 330 | "Elise", 331 | "Swain", 332 | "Shyvana", 333 | "Nidalee", 334 | "Gnar" 335 | ] 336 | }, 337 | { 338 | "name": "sorcerer", 339 | "bonus_num": [ 340 | 3, 341 | 6, 342 | 9 343 | ], 344 | "scope": [ 345 | 3, 346 | 3, 347 | 3 348 | ], 349 | "strength": [ 350 | 1.25, 351 | 1.61, 352 | 2.1 353 | ], 354 | "champions": [ 355 | "Morgana", 356 | "Aurelion Sol", 357 | "Twist Fate", 358 | "Karthus", 359 | "Ahri", 360 | "Kassadin", 361 | "Lulu", 362 | "Veigar" 363 | ] 364 | }, 365 | { 366 | "name": "assassin", 367 | "bonus_num": [ 368 | 3, 369 | 6, 370 | 9 371 | ], 372 | "scope": [ 373 | 2, 374 | 2, 375 | 2 376 | ], 377 | "strength": [ 378 | 1.4, 379 | 2, 380 | 2.2 381 | ], 382 | "champions": [ 383 | "Evelynn", 384 | "Katarina", 385 | "Zed", 386 | "Akali", 387 | "Pyke", 388 | "Rengar", 389 | "Kha'Zix", 390 | "Kaisa" 391 | ] 392 | }, 393 | { 394 | "name": "blademaster", 395 | "bonus_num": [ 396 | 3, 397 | 6, 398 | 9 399 | ], 400 | "scope": [ 401 | 2, 402 | 2, 403 | 2 404 | ], 405 | "strength": [ 406 | 1.3, 407 | 1.6, 408 | 2.2 409 | ], 410 | "champions": [ 411 | "Aatrox", 412 | "Yasuo", 413 | "Draven", 414 | "Fiora", 415 | "Shen", 416 | "Gangplank", 417 | "Camille" 418 | ] 419 | }, 420 | { 421 | "name": "elementalist", 422 | "bonus_num": [ 423 | 3 424 | ], 425 | "scope": [ 426 | 1 427 | ], 428 | "strength": [ 429 | 2 430 | ], 431 | "champions": [ 432 | "Brand", 433 | "Lissandra", 434 | "Anivia", 435 | "Kennen" 436 | ] 437 | }, 438 | { 439 | "name": "guardian", 440 | "bonus_num": [ 441 | 2 442 | ], 443 | "scope": [ 444 | 4 445 | ], 446 | "strength": [ 447 | 1.5 448 | ], 449 | "champions": [ 450 | "Pantheon", 451 | "Braum", 452 | "Leona" 453 | ] 454 | }, 455 | { 456 | "name": "brawler", 457 | "bonus_num": [ 458 | 2, 459 | 4, 460 | 6 461 | ], 462 | "scope": [ 463 | 2, 464 | 2, 465 | 2 466 | ], 467 | "strength": [ 468 | 1.2, 469 | 1.4, 470 | 1.7 471 | ], 472 | "champions": [ 473 | "Volibear", 474 | "Blitzcrank", 475 | "Warwick", 476 | "Rek'Sai", 477 | "Cho'Gath", 478 | "VI" 479 | ] 480 | }, 481 | { 482 | "name": "knight", 483 | "bonus_num": [ 484 | 2, 485 | 4, 486 | 6 487 | ], 488 | "scope": [ 489 | 3, 490 | 3, 491 | 3 492 | ], 493 | "strength": [ 494 | 1.15, 495 | 1.35, 496 | 1.85 497 | ], 498 | "champions": [ 499 | "Sejuani", 500 | "Darius", 501 | "Garen", 502 | "Kayle", 503 | "Mordekaiser", 504 | "Poppy" 505 | ] 506 | }, 507 | { 508 | "name": "gunslinger", 509 | "bonus_num": [ 510 | 2, 511 | 4, 512 | 6 513 | ], 514 | "scope": [ 515 | 3, 516 | 3, 517 | 3 518 | ], 519 | "strength": [ 520 | 1.3, 521 | 1.6, 522 | 1.9 523 | ], 524 | "champions": [ 525 | "Sejuani", 526 | "Darius", 527 | "Garen", 528 | "Kayle", 529 | "Mordekaiser", 530 | "Poppy" 531 | ] 532 | } 533 | ] -------------------------------------------------------------------------------- /evaluate/evaluation.go: -------------------------------------------------------------------------------- 1 | package evaluate 2 | 3 | import ( 4 | "TFT/globals" 5 | "TFT/models" 6 | "TFT/utils" 7 | "math" 8 | ) 9 | 10 | // Evaluate 评估当前组合的羁绊数量、单位收益羁绊总数、羁绊强度 11 | func Evaluate(combo []models.ChampionDict) models.ComboMetric { 12 | var traitDetail = make(map[string]int) 13 | 14 | comboName := make([]string, 0, len(combo)) 15 | traitNum := 0 16 | totalTraitNum := 0 17 | totalTraitStrength := float32(0.0) 18 | 19 | // 初始化英雄强度向量 20 | unitsStrength := make([]float64, len(combo), len(combo)) 21 | traitChampionsDict := make(map[string][]int) 22 | for index, unit := range combo { 23 | comboName = append(comboName, unit.Name) 24 | unitStrength := math.Pow(globals.Global.GainLevel, float64(unit.Price-1)) 25 | unitsStrength[index] = unitStrength 26 | for _, origin := range unit.Origin { 27 | traitChampionsDict[origin] = append(traitChampionsDict[origin], index) 28 | } 29 | for _, class := range unit.Class { 30 | traitChampionsDict[class] = append(traitChampionsDict[class], index) 31 | } 32 | } 33 | 34 | for trait, champions := range traitChampionsDict { 35 | num := len(champions) 36 | bonusRequirement := globals.TraitDict[trait].BonusNum 37 | var bonusLevel = len(bonusRequirement) 38 | for index, requirement := range bonusRequirement { 39 | if requirement > num { 40 | bonusLevel = index 41 | break 42 | } 43 | } 44 | 45 | // 忍者只有在1只和4只时触发,其他不触发 46 | if trait == "ninja" && 1 < num && num < 4 { 47 | bonusLevel = 0 48 | } 49 | if bonusLevel > 0 { 50 | traitDetail[trait] = bonusRequirement[bonusLevel-1] 51 | bonusScope := globals.TraitDict[trait].Scope[bonusLevel-1] 52 | traitNum += bonusLevel 53 | bonusStrength := globals.TraitDict[trait].Strength[bonusLevel-1] 54 | benefitedNum := 0 55 | switch bonusScope { 56 | case 1: 57 | { 58 | benefitedNum = 1 // 单体Buff,例如 机器人、浪人、三贵族、双帝国 59 | for _, champion := range champions { 60 | unitsStrength[champion] *= float64(bonusStrength) 61 | } 62 | } 63 | case 2: 64 | { 65 | benefitedNum = num // 对同一种族的Buff,大多数羁绊都是这种 66 | for _, champion := range champions { 67 | unitsStrength[champion] *= float64(bonusStrength) 68 | } 69 | } 70 | case 3: 71 | { 72 | benefitedNum = len(combo) // 群体Buff,如骑士、六贵族、四帝国 73 | for index, _ := range unitsStrength { 74 | unitsStrength[index] *= float64(bonusStrength) 75 | } 76 | } 77 | case 4: 78 | { 79 | benefitedNum = len(combo) - 2 // 护卫Buff,比较特殊,除护卫本身外,其他均能吃到buff 80 | for index, _ := range unitsStrength { 81 | isGuard := false 82 | for _, champion := range champions { 83 | if index == champion { 84 | isGuard = true 85 | break 86 | } 87 | } 88 | if !isGuard { 89 | unitsStrength[index] *= float64(bonusStrength) 90 | } 91 | } 92 | } 93 | } 94 | totalTraitNum += bonusLevel * benefitedNum 95 | totalTraitStrength += float32(benefitedNum) * bonusStrength 96 | } 97 | } 98 | metric := models.ComboMetric{ 99 | Combo: comboName, 100 | TraitNum: traitNum, 101 | TotalTraitNum: totalTraitNum, 102 | TraitDetail: traitDetail, 103 | TotalTraitStrength: totalTraitStrength, 104 | TotalStrength: utils.Sum(unitsStrength), 105 | } 106 | return metric 107 | } 108 | -------------------------------------------------------------------------------- /globals/global.go: -------------------------------------------------------------------------------- 1 | package globals 2 | 3 | import ( 4 | "TFT/models" 5 | "encoding/json" 6 | "github.com/go-yaml/yaml" 7 | "github.com/schollz/progressbar" 8 | "io/ioutil" 9 | "os" 10 | ) 11 | 12 | var ( 13 | traitList models.TraitList 14 | ChampionList models.ChampionList 15 | OneTraitChampionNameList []string 16 | TraitDict map[string]models.Trait 17 | ChampionDict map[string]models.Champion 18 | TranslateDict map[string]string 19 | Bar *progressbar.ProgressBar 20 | Counter int64 21 | Global GlobalStruct 22 | ) 23 | 24 | type GlobalStruct struct { 25 | TraitPath string `yaml:"trait_path"` 26 | ChampionPath string `yaml:"champion_path"` 27 | LanguagePath string `yaml:"language_path"` 28 | OutPutPath string `yaml:"output_path"` 29 | GainLevel float64 `yaml:"gain_level"` 30 | MaximumHeap int `yaml:"maximum_heap"` 31 | Evaluation string `yaml:"evaluation"` 32 | } 33 | 34 | func init() { 35 | // 读取配置文件 36 | content, _ := ioutil.ReadFile("config/app.yaml") 37 | err := yaml.Unmarshal(content, &Global) 38 | // Init traits file 39 | traitsFile, err := os.Open(Global.TraitPath) 40 | if err != nil { 41 | panic("Open traits file fail!") 42 | } 43 | Counter = 0 44 | jsonParser := json.NewDecoder(traitsFile) 45 | if err = jsonParser.Decode(&traitList); err != nil { 46 | panic(err.Error()) 47 | } 48 | TraitDict = make(map[string]models.Trait) 49 | for _, trait := range traitList { 50 | TraitDict[trait.Name] = models.Trait{ 51 | BonusNum: trait.BonusNum, 52 | Scope: trait.Scope, 53 | Champions: trait.Champions, 54 | Strength: trait.Strength, 55 | } 56 | } 57 | // Init champion file 58 | championFile, err := os.Open(Global.ChampionPath) 59 | if err != nil { 60 | panic("Open champion file fail!") 61 | } 62 | jsonParser = json.NewDecoder(championFile) 63 | if err = jsonParser.Decode(&ChampionList); err != nil { 64 | panic(err.Error()) 65 | } 66 | 67 | translateFile, err := os.Open(Global.LanguagePath) 68 | if err != nil { 69 | panic("Open language file fail") 70 | } 71 | jsonParser = json.NewDecoder(translateFile) 72 | if err = jsonParser.Decode(&TranslateDict); err != nil { 73 | panic(err.Error()) 74 | } 75 | ChampionDict = make(map[string]models.Champion) 76 | for _, champion := range ChampionList { 77 | ChampionDict[champion.Name] = models.Champion{ 78 | Avatar: champion.Avatar, 79 | Price: champion.Price, 80 | Origin: champion.Origin, 81 | Class: champion.Class, 82 | } 83 | } 84 | for _, trait := range traitList { 85 | if trait.BonusNum[0] == 1 { 86 | OneTraitChampionNameList = append(OneTraitChampionNameList, trait.Champions...) 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "TFT/globals" 5 | "TFT/search" 6 | "TFT/utils" 7 | "encoding/json" 8 | "fmt" 9 | "os" 10 | "sort" 11 | "strconv" 12 | "time" 13 | ) 14 | 15 | func start(teamSize int){ 16 | start := time.Now() 17 | result := search.TraitBasedGraphSearch(globals.ChampionList, int(teamSize)) 18 | elapsed := time.Since(start) 19 | fmt.Println("人口:",teamSize, 20 | "共耗时:", elapsed.Seconds(), "s", 21 | "平均每秒遍历组合数:", float64(globals.Counter)/elapsed.Seconds(), 22 | "共搜索结点个数:", globals.Counter) 23 | 24 | // 排序 25 | sort.Slice(result, func(i, j int)bool{ 26 | return result[i].TotalStrength > result[j].TotalStrength 27 | }) 28 | utils.Translate(&result) 29 | jsonString, err := json.MarshalIndent(&result, "", " ") 30 | if err != nil { 31 | fmt.Println(err.Error()) 32 | } 33 | dstFile, err := os.Create(globals.Global.OutPutPath+"champions_comb"+strconv.Itoa(teamSize)+".json") 34 | if err != nil { 35 | panic("打开文件句柄失败") 36 | } 37 | _, err = dstFile.WriteString(string(jsonString)) 38 | if err != nil { 39 | panic("写入文件失败") 40 | } 41 | } 42 | 43 | func main() { 44 | start(7) 45 | } -------------------------------------------------------------------------------- /models/champions.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type Champion struct { 4 | Avatar string `json:"avatar"` 5 | Price int `json:"price"` 6 | Origin []string `json:"origin"` 7 | Class []string `json:"class"` 8 | } 9 | 10 | type ChampionDict struct { 11 | Name string `json:"name"` 12 | *Champion 13 | } 14 | 15 | type ChampionList []ChampionDict 16 | -------------------------------------------------------------------------------- /models/metrics.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type ComboMetric struct { 4 | // 英雄组合 5 | Combo []string `json:"combo"` 6 | // 队伍总羁绊数量 = sigma{羁绊} * 羁绊等级 7 | TraitNum int `json:"trait_num"` 8 | // 具体羁绊 9 | TraitDetail map[string]int `json:"trait_detail"` 10 | // 总英雄收益羁绊数量 = sigma{羁绊} 羁绊范围 * 羁绊等级 11 | TotalTraitNum int `json:"total_trait_num"` 12 | // 当前阵容羁绊强度 = sigma{羁绊} 羁绊范围 * 羁绊强度 13 | TotalTraitStrength float32 `json:"total_trait_strength"` 14 | // 当前阵容强度 = sigma{英雄} 英雄强度 * 羁绊强度 15 | TotalStrength float64 `json:"total_strength"` 16 | } 17 | 18 | // 定义一个最小堆,保留前K个羁绊 19 | type ComboMetricHeap []ComboMetric 20 | 21 | func (h ComboMetricHeap) Len() int { 22 | return len(h) 23 | } 24 | 25 | func (h ComboMetricHeap) Less(i,j int) bool { 26 | return h[i].TotalStrength < h[j].TotalStrength 27 | } 28 | 29 | func (h ComboMetricHeap) Swap(i, j int) { 30 | h[i], h[j] = h[j], h[i] 31 | } 32 | 33 | func (h *ComboMetricHeap) Push(x interface{}) { 34 | *h = append(*h, x.(ComboMetric)) 35 | } 36 | 37 | func (h *ComboMetricHeap) Pop() interface{} { 38 | old := *h 39 | n := len(old) 40 | x := old[n-1] 41 | *h = old[0 : n-1] 42 | return x 43 | } 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /models/traits.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type Trait struct{ 4 | BonusNum []int `json:"bonus_num"` 5 | Scope []int `json:"scope"` 6 | Champions []string `json:"champions"` 7 | Strength []float32 `json:"strength"` 8 | } 9 | 10 | type TraitDict struct { 11 | Name string `json:"name"` 12 | *Trait 13 | } 14 | 15 | type TraitList []TraitDict -------------------------------------------------------------------------------- /python_scripts/deduplicate.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | # jaccard 相似度 5 | def diff_set(set1 :set, set2 :set) -> float: 6 | return len(set1 & set2) / len(set1 | set2) 7 | 8 | 9 | def setify(combo:dict) -> set: 10 | trait_detail = combo['trait_detail'] 11 | result_set = set() 12 | for trait, num in trait_detail.items(): 13 | result_set.add((trait, num,)) 14 | return result_set 15 | 16 | 17 | if __name__ == "__main__": 18 | num = 9 19 | with open(f'../data/output/total_strength/champions_comb{num}.json', 'r') as f: 20 | combos = json.load(f) 21 | 22 | trait_list = [setify(combos[0])] 23 | for combo in combos[1:]: 24 | combo_set = setify(combo) 25 | for trait_set in trait_list: 26 | # 如果相似度大于80%就是相同体系羁绊 27 | sim = diff_set(trait_set, combo_set) 28 | if sim >= 0.7: 29 | break 30 | else: 31 | trait_list.append(combo_set) 32 | result = [str(list(each)) for each in trait_list] 33 | with open(f"../data/final_result/total_strength/final_result{num}.json", 'w') as f: 34 | json.dump(result, f, indent='\t', ensure_ascii=False) 35 | -------------------------------------------------------------------------------- /python_scripts/download.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import os 3 | import json 4 | import cv2 5 | 6 | os.chdir('../data') 7 | if __name__ == "__main__": 8 | with open('champions.json', 'r') as f: 9 | champions = json.load(f) 10 | for n, each in enumerate(champions): 11 | filename = 'avatar/'+each['name']+'.png' 12 | if not os.path.exists(filename): 13 | url = each['avatar'] 14 | url = url.replace('resize=64', 'resize=120') 15 | response = requests.get(url) 16 | with open(filename, 'wb') as fp: 17 | fp.write(response.content) 18 | image = cv2.imread(filename) 19 | image = cv2.resize(image, (60, 60)) 20 | cv2.imwrite('avatar/'+str(n).zfill(2)+each['name']+'.png', image) 21 | -------------------------------------------------------------------------------- /python_scripts/graph_visualisation.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | os.chdir("../data") 5 | 6 | if __name__ == "__main__": 7 | with open("language.json", "r") as f: 8 | translate_dict = json.load(f) 9 | with open("champions_graph.json", "r") as f: 10 | champions_graph = json.load(f) 11 | with open("champions.json", "r") as f: 12 | champions_list = json.load(f) 13 | 14 | # Generate nodes 15 | node_list = [] 16 | for n, champion in enumerate(champions_list): 17 | node = dict() 18 | node['id'] = str(n) 19 | node["name"] = translate_dict[str(champion['name'])] 20 | node["cluster"] = translate_dict[champion["origin"][0]] 21 | node["value"] = champion["price"]*5 22 | node_list.append(node) 23 | 24 | # Generate edges 25 | edge_list = [] 26 | for from_node, to_nodes in champions_graph.items(): 27 | if to_nodes: 28 | for to_node in to_nodes: 29 | edge = dict() 30 | edge['source'] = str(from_node) 31 | edge['target'] = str(to_node) 32 | edge['sourceWeight'] = 10 33 | edge['targetWeight'] = 0 34 | edge_list.append(edge) 35 | 36 | total_dict = { 37 | "nodes": node_list, 38 | "edges": edge_list 39 | } 40 | with open("graph.json", 'w') as f: 41 | json.dump(total_dict, f, indent="\t", ensure_ascii=False) -------------------------------------------------------------------------------- /python_scripts/scrape.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2019/10/29 11:19 PM 3 | # @Author : weiziyang 4 | # @FileName: scrape.py 5 | # @Software: PyCharm 6 | import os 7 | import json 8 | import time 9 | import requests 10 | from bs4 import BeautifulSoup 11 | 12 | response = requests.get('https://na.leagueoflegends.com/en/news/game-updates/gameplay/teamfight-tactics-gameplay-guide?utm_source=web&utm_medium=web&utm_campaign=tft-microsite-2019#patch-champion-compendium') 13 | soup = BeautifulSoup(response.text, 'lxml') 14 | block = soup.find('div', attrs={'id': 'champion-compendium-slideshow'}) 15 | boxes = block.findAll('div', attrs={'class': 'content-border'}) 16 | 17 | champion_list = list() 18 | 19 | for box in boxes: 20 | avatar_url = box.find('a', attrs={'class': 'reference-link'}).find('img')['src'] 21 | name = box.find('h4', attrs={'class': 'change-title'}).getText() 22 | price = box.find('p', attrs={'class': 'summary price'}).getText().replace('gold', '') 23 | h4 = box.findAll('h4', attrs={'class': 'ability-title'}) 24 | origin = [] 25 | Class = [] 26 | for each in h4[1:]: 27 | text = each.getText() 28 | if 'Origin' in text: 29 | origin.append(text.replace('Origin', '').strip().lower()) 30 | elif 'Class' in text: 31 | Class.append(text.replace('Class', '').strip().lower()) 32 | champion = { 33 | 'name': name.strip(), 34 | 'avatar': avatar_url, 35 | 'price': int(price.strip()), 36 | 'origin': origin, 37 | 'class': Class 38 | } 39 | champion_list.append(champion) 40 | 41 | with open('data.json', 'w') as f: 42 | json.dump(champion_list, f, indent='\t') 43 | 44 | -------------------------------------------------------------------------------- /python_scripts/scrape_icon.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import requests 4 | from bs4 import BeautifulSoup 5 | 6 | response = requests.get('https://na.leagueoflegends.com/en/news/game-updates/gameplay/teamfight-tactics-gameplay-guide?utm_source=web&utm_medium=web&utm_campaign=tft-microsite-2019#patch-champion-compendium') 7 | soup = BeautifulSoup(response.text, 'lxml') 8 | 9 | icons = soup.find_all('div', attrs={'class': "tft-icon-container"}) 10 | result = {} 11 | for icon in icons: 12 | url = icon.find("img")['src'] 13 | trait = icon.find('h4').getText() 14 | result[trait] = url 15 | result['Hextech'] = "http://game.gtimg.cn/images/lol/act/a20190702loltftwf/icon-hks.png" 16 | 17 | os.chdir('../data/trait_icons') 18 | for name, url in result.items(): 19 | response = requests.get(url) 20 | with open(name+'.png', 'wb') as f: 21 | f.write(response.content) 22 | -------------------------------------------------------------------------------- /python_scripts/traits.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2019/10/31 12:58 AM 3 | # @Author : weiziyang 4 | # @FileName: traits.py 5 | # @Software: PyCharm 6 | import json 7 | 8 | ONLY_ONE = 1 9 | SAME_ORIGIN = 2 10 | ALL = 3 11 | NINJIA = 12 12 | BOOST = 23 13 | SUPERBOOST = 13 14 | GUARD = 4 15 | 16 | 17 | if __name__ == "__main__": 18 | with open('champions_data.json', 'r') as f: 19 | champion_list = json.load(f) 20 | origin_dict = dict() 21 | class_dict = dict() 22 | for champion in champion_list: 23 | origins = champion['origin'] 24 | for origin in origins: 25 | if origin_dict.get(origin): 26 | origin_dict[origin]['champions'].append(champion['name']) 27 | else: 28 | origin_dict[origin] = { 29 | 'bonus_num': [], 30 | 'scope': 2, 31 | 'strength': 1, 32 | 'champions': [champion['name']] 33 | } 34 | classes = champion['class'] 35 | for _class in classes: 36 | if class_dict.get(_class): 37 | class_dict[_class]['champions'].append(champion['name']) 38 | else: 39 | class_dict[_class] = { 40 | 'bonus_num': [], 41 | 'scope': 2, 42 | 'strength': 1, 43 | 'champions': [champion['name']] 44 | } 45 | 46 | trait_dict = {} 47 | trait_dict.update(origin_dict) 48 | trait_dict.update(class_dict) 49 | 50 | with open('traits_data.json', 'w') as f: 51 | json.dump(trait_dict, f, indent='\t') 52 | -------------------------------------------------------------------------------- /python_scripts/translate.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | # with open('../data/traits.json', 'r') as f: 4 | # champion_list = json.load(f) 5 | # 6 | # name_list = [] 7 | # for each in champion_list: 8 | # name_list.append({each['name']: ""}) 9 | # 10 | # with open('../data/language.json', 'w') as f: 11 | # json.dump(name_list, f, indent='\t', ensure_ascii=False) 12 | dic = {} 13 | 14 | with open("../data/language.json", 'r') as f: 15 | l = json.load(f) 16 | 17 | for each in l: 18 | key = list(each.keys())[0] 19 | value = list(each.values())[0] 20 | dic[key] = value 21 | 22 | with open("../data/language_copy.json", "w") as f: 23 | json.dump(dic, f, indent='\t', ensure_ascii=False) -------------------------------------------------------------------------------- /python_scripts/visualise_champions.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import os 3 | import numpy as np 4 | 5 | os.chdir('../data') 6 | width = 60*56 7 | height = 60 8 | avatars = [each for each in sorted(os.listdir('avatar'), key=lambda a:int(a[:2]))if not each.startswith('.')] 9 | canvas = np.zeros((height, width, 3)) 10 | 11 | for n, avatar in enumerate(avatars): 12 | path = os.path.join('avatar', avatar) 13 | img = plt.imread(path) 14 | canvas[:, 60*n:60*(n+1), :] = img 15 | 16 | plt.imsave('canvas.png', canvas) -------------------------------------------------------------------------------- /python_scripts/visualise_trait_graph.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import numpy as np 4 | import cv2 5 | import matplotlib.pyplot as plt 6 | 7 | os.chdir('..') 8 | with open('data/champions.json') as f: 9 | champions = json.load(f) 10 | trait_graph = [["" for _ in range(len(champions))] for each in range(len(champions))] 11 | 12 | prior_trait = {'ninja', 'exile', 'robot'} 13 | for y, champion_a in enumerate(champions): 14 | origins = champion_a['origin'] 15 | classes = champion_a['class'] 16 | champion_a_traits = set(origins + classes) 17 | for x, champion_b in enumerate(champions): 18 | if x == y: 19 | trait_graph[y][x] = "same" 20 | continue 21 | origins = champion_b['origin'] 22 | classes = champion_b['class'] 23 | champion_b_traits = set(origins + classes) 24 | # 两个英雄共同的羁绊 25 | common_traits = (champion_a_traits & champion_b_traits) 26 | # 是否存在忍者、浪人、机器人 27 | if common_traits: 28 | extra_traits = set() 29 | else: 30 | extra_traits = (champion_b_traits | champion_a_traits) & prior_trait 31 | all_traits = common_traits | extra_traits 32 | if all_traits: 33 | trait_graph[y][x] = str(','.join(list(all_traits))) 34 | 35 | champions_num = len(champions) 36 | size = 40 37 | width = size + champions_num * size * 2 + size 38 | height = size + champions_num * size + size 39 | canvas = np.zeros((height, width, 3))*255 40 | start_point = (size, size) 41 | 42 | # 首先画英雄 43 | file_names = sorted([each for each in os.listdir('data/avatar') if not each.startswith('.')], key=lambda a: int(a[:2])) 44 | file_names = [os.path.join('data', 'avatar', each) for each in file_names] 45 | for n, file_name in enumerate(file_names): 46 | img = cv2.cvtColor(cv2.imread(file_name), cv2.COLOR_BGR2RGB) 47 | resized_img = cv2.resize(img, (size, size)) 48 | # 先画横向的 49 | y = 0 50 | x = size + size * 2 * n 51 | canvas[y:y+size, x:x+size, :] = resized_img 52 | canvas[:, x+size:x+size+1, :] = np.ones((height, 1, 3))*255 53 | # 再画纵向的 54 | x = 0 55 | y = size + size * n 56 | canvas[y:y+size, x:x+size, :] = resized_img 57 | canvas[y+size:y+size+1, :, :] = np.ones((1, width, 3))*255 58 | 59 | # 载入羁绊 60 | trait_file_names = [each for each in os.listdir('data/trait_icons') if not each.startswith('.')] 61 | name = [each.split('.')[0].lower() for each in trait_file_names] 62 | trait_icon_dict = {} 63 | for n, trait_file in enumerate(trait_file_names): 64 | img = cv2.cvtColor(cv2.imread(os.path.join('data', 'trait_icons', trait_file)), cv2.COLOR_BGR2RGB) 65 | resized_img = cv2.resize(img, (size, size)) 66 | trait_icon_dict[name[n]] = resized_img 67 | trait_icon_dict['Hextech'] = trait_icon_dict['hextech'] 68 | # 再画羁绊 69 | for row in range(len(trait_graph)): 70 | for col in range((len(trait_graph))): 71 | content = trait_graph[row][col] 72 | if content and content != 'same': 73 | traits = content.split(',') 74 | for index, trait in enumerate(traits): 75 | icon = trait_icon_dict[trait] 76 | y = size + row * size 77 | if index == 0: 78 | x = size + 2 * col * size 79 | if index == 1: 80 | x = size + 2 * col * size + size 81 | canvas[y:y+size, x:x+size] = trait_icon_dict[trait] 82 | 83 | cv2.imwrite("data/trait_graph.png", canvas) -------------------------------------------------------------------------------- /search/graph.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import ( 4 | "TFT/globals" 5 | "TFT/models" 6 | "TFT/utils" 7 | "sort" 8 | ) 9 | 10 | type Graph map[int][]int 11 | 12 | // GenerateGraph 生成羁绊图 13 | func GenerateGraph(championList models.ChampionList) Graph{ 14 | graph := make(Graph) 15 | positionMap := make(map[string]int) 16 | for index, champion := range championList { 17 | positionMap[champion.Name] = index 18 | } 19 | for no, champion := range championList { 20 | // children 排序 21 | children := make([]int, 0, 30) 22 | // 加入相同职业的英雄 23 | classes := champion.Class 24 | for _, class := range classes { 25 | sameClassChampions := globals.TraitDict[class].Champions 26 | for _, champion := range sameClassChampions { 27 | index := positionMap[champion] 28 | if index > no{ 29 | children = append(children, index) 30 | } 31 | } 32 | } 33 | // 加入相同种族的英雄 34 | origins := champion.Origin 35 | for _, origin := range origins { 36 | sameOriginChampions := globals.TraitDict[origin].Champions 37 | for _, champion := range sameOriginChampions { 38 | index := positionMap[champion] 39 | if index > no { 40 | children = append(children, index) 41 | } 42 | } 43 | } 44 | // 加入1羁绊的英雄 45 | for _, championName := range globals.OneTraitChampionNameList { 46 | index := positionMap[championName] 47 | if index > no { 48 | children = append(children, index) 49 | } 50 | } 51 | // 对index从小到大排序 52 | sort.Ints(children) 53 | children = utils.Deduplicate(children) 54 | graph[no] = children 55 | } 56 | return graph 57 | } -------------------------------------------------------------------------------- /search/search.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import ( 4 | "TFT/globals" 5 | "TFT/models" 6 | "container/heap" 7 | ) 8 | 9 | var lim int 10 | var Result = make(models.ComboMetricHeap, 0, globals.Global.MaximumHeap) 11 | 12 | // getSlice 与python range(x,y)相同效果 13 | func getSlice(start int, end int) []int { 14 | rangeList := make([]int, end-start) 15 | for i := start; i < end; i++ { 16 | rangeList[i-start] = i 17 | } 18 | return rangeList 19 | } 20 | 21 | 22 | // TraitBasedGraphSearch 基于羁绊图的图搜索 23 | func TraitBasedGraphSearch(championList models.ChampionList, teamSize int) models.ComboMetricHeap { 24 | graph := GenerateGraph(championList) 25 | lim = teamSize 26 | 27 | heap.Init(&Result) 28 | startPoints := getSlice(0, len(championList)-teamSize + 1) 29 | for _,startNode := range startPoints{ 30 | Traverse(championList, graph, startNode, make([]int, 0, teamSize), make([]int, 0, 57)) 31 | } 32 | 33 | return Result 34 | } 35 | 36 | -------------------------------------------------------------------------------- /search/traverse.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import ( 4 | "TFT/evaluate" 5 | "TFT/globals" 6 | "TFT/models" 7 | "TFT/utils" 8 | "container/heap" 9 | "fmt" 10 | "sort" 11 | ) 12 | 13 | // Traverse 图遍历, 14 | // championList, 英雄列表,固定不变。 graph 羁绊图,也是固定不变。node 为当前的结点, selected 为已选择的英雄, oldChildren是父节点的children 15 | func Traverse(championList models.ChampionList, graph Graph, node int, selected []int, oldChildren []int) { 16 | selected = append(selected, node) 17 | if len(selected) == lim { 18 | combo := make(models.ChampionList, lim) 19 | for index, no := range selected { 20 | unit := championList[no] 21 | combo[index] = unit 22 | } 23 | globals.Counter += 1 24 | if globals.Counter%100000 == 0 { 25 | fmt.Println(globals.Counter) 26 | } 27 | metric := evaluate.Evaluate(combo) 28 | heap.Push(&Result, metric) 29 | 30 | // 超过最大就pop 31 | if len(Result) == globals.Global.MaximumHeap { 32 | heap.Remove(&Result, 0) 33 | } 34 | return 35 | } 36 | newChildren := graph[node] 37 | children := append(oldChildren, newChildren...) 38 | sort.Ints(children) 39 | children = utils.DeduplicateAndFilter(children, node) 40 | // 注意这里children在后面会因为append方法原地操作其内部元素,因此需要拷贝一下 41 | copyChildren := make([]int, len(children), 50) 42 | copy(copyChildren, children) 43 | for _, child := range children { 44 | // selected 也是同理 45 | copySelected := make([]int, len(selected), lim) 46 | copy(copySelected, selected) 47 | Traverse(championList, graph, child, copySelected, copyChildren) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /utils/extend.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | // Contain 相当于 python 的 in 4 | func Contain(container []int, object int) bool{ 5 | for _,candidate:=range container{ 6 | if candidate == object{ 7 | return true 8 | } 9 | } 10 | return false 11 | } 12 | 13 | // DeduplicateAndFilter 去重并且过滤比当前英雄位置先的英雄 14 | func DeduplicateAndFilter(list []int, node int)[]int{ 15 | var lastOne int 16 | var resultList []int 17 | lastOne = 65535 18 | for _, item:=range list{ 19 | if item > node && item != lastOne{ 20 | resultList = append(resultList, item) 21 | lastOne = item 22 | } 23 | } 24 | return resultList 25 | } 26 | 27 | // Deduplicate 去重 28 | func Deduplicate(list []int) []int{ 29 | var lastOne int 30 | var resultList []int 31 | lastOne = 65535 32 | for _, item:=range list{ 33 | if item != lastOne{ 34 | resultList = append(resultList, item) 35 | lastOne = item 36 | } 37 | } 38 | return resultList 39 | } 40 | 41 | // IsEqual 判断两个切片是否相等 42 | func IsEqual(list1 []int, list2 []int) bool{ 43 | if len(list1)!=len(list2){ 44 | return false 45 | } 46 | for i:=0;i 2 | 3 | 4 | 5 | Arc Diagram 弧线图 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 24 | 150 | 151 | -------------------------------------------------------------------------------- /visualisation/graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": [ 3 | { 4 | "id": "0", 5 | "name": "维鲁斯", 6 | "cluster": "恶魔", 7 | "value": 10 8 | }, 9 | { 10 | "id": "1", 11 | "name": "蜘蛛", 12 | "cluster": "恶魔", 13 | "value": 5 14 | }, 15 | { 16 | "id": "2", 17 | "name": "莫甘娜", 18 | "cluster": "恶魔", 19 | "value": 15 20 | }, 21 | { 22 | "id": "3", 23 | "name": "寡妇", 24 | "cluster": "恶魔", 25 | "value": 15 26 | }, 27 | { 28 | "id": "4", 29 | "name": "剑魔", 30 | "cluster": "恶魔", 31 | "value": 15 32 | }, 33 | { 34 | "id": "5", 35 | "name": "火男", 36 | "cluster": "恶魔", 37 | "value": 20 38 | }, 39 | { 40 | "id": "6", 41 | "name": "乌鸦", 42 | "cluster": "恶魔", 43 | "value": 25 44 | }, 45 | { 46 | "id": "7", 47 | "name": "龙女", 48 | "cluster": "龙", 49 | "value": 15 50 | }, 51 | { 52 | "id": "8", 53 | "name": "龙王", 54 | "cluster": "龙", 55 | "value": 20 56 | }, 57 | { 58 | "id": "9", 59 | "name": "潘森", 60 | "cluster": "龙", 61 | "value": 25 62 | }, 63 | { 64 | "id": "10", 65 | "name": "亚索", 66 | "cluster": "浪人", 67 | "value": 25 68 | }, 69 | { 70 | "id": "11", 71 | "name": "布隆", 72 | "cluster": "冰川", 73 | "value": 10 74 | }, 75 | { 76 | "id": "12", 77 | "name": "丽桑卓", 78 | "cluster": "冰川", 79 | "value": 10 80 | }, 81 | { 82 | "id": "13", 83 | "name": "艾希", 84 | "cluster": "冰川", 85 | "value": 15 86 | }, 87 | { 88 | "id": "14", 89 | "name": "狗熊", 90 | "cluster": "冰川", 91 | "value": 15 92 | }, 93 | { 94 | "id": "15", 95 | "name": "猪妹", 96 | "cluster": "冰川", 97 | "value": 20 98 | }, 99 | { 100 | "id": "16", 101 | "name": "冰鸟", 102 | "cluster": "冰川", 103 | "value": 25 104 | }, 105 | { 106 | "id": "17", 107 | "name": "机器人", 108 | "cluster": "机器人", 109 | "value": 10 110 | }, 111 | { 112 | "id": "18", 113 | "name": "诺手", 114 | "cluster": "帝国", 115 | "value": 5 116 | }, 117 | { 118 | "id": "19", 119 | "name": "卡特", 120 | "cluster": "帝国", 121 | "value": 15 122 | }, 123 | { 124 | "id": "20", 125 | "name": "德莱文", 126 | "cluster": "帝国", 127 | "value": 20 128 | }, 129 | { 130 | "id": "21", 131 | "name": "剑姬", 132 | "cluster": "贵族", 133 | "value": 5 134 | }, 135 | { 136 | "id": "22", 137 | "name": "盖伦", 138 | "cluster": "贵族", 139 | "value": 5 140 | }, 141 | { 142 | "id": "23", 143 | "name": "薇恩", 144 | "cluster": "贵族", 145 | "value": 5 146 | }, 147 | { 148 | "id": "24", 149 | "name": "卢锡安", 150 | "cluster": "贵族", 151 | "value": 10 152 | }, 153 | { 154 | "id": "25", 155 | "name": "日女", 156 | "cluster": "贵族", 157 | "value": 20 158 | }, 159 | { 160 | "id": "26", 161 | "name": "天使", 162 | "cluster": "贵族", 163 | "value": 25 164 | }, 165 | { 166 | "id": "27", 167 | "name": "慎", 168 | "cluster": "忍者", 169 | "value": 10 170 | }, 171 | { 172 | "id": "28", 173 | "name": "劫", 174 | "cluster": "忍者", 175 | "value": 10 176 | }, 177 | { 178 | "id": "29", 179 | "name": "凯南", 180 | "cluster": "忍者", 181 | "value": 15 182 | }, 183 | { 184 | "id": "30", 185 | "name": "阿卡丽", 186 | "cluster": "忍者", 187 | "value": 20 188 | }, 189 | { 190 | "id": "31", 191 | "name": "男枪", 192 | "cluster": "海盗", 193 | "value": 5 194 | }, 195 | { 196 | "id": "32", 197 | "name": "派克", 198 | "cluster": "海盗", 199 | "value": 10 200 | }, 201 | { 202 | "id": "33", 203 | "name": "卡牌", 204 | "cluster": "海盗", 205 | "value": 10 206 | }, 207 | { 208 | "id": "34", 209 | "name": "船长", 210 | "cluster": "海盗", 211 | "value": 15 212 | }, 213 | { 214 | "id": "35", 215 | "name": "好运姐", 216 | "cluster": "海盗", 217 | "value": 25 218 | }, 219 | { 220 | "id": "36", 221 | "name": "铁男", 222 | "cluster": "幽灵", 223 | "value": 5 224 | }, 225 | { 226 | "id": "37", 227 | "name": "千珏", 228 | "cluster": "幽灵", 229 | "value": 20 230 | }, 231 | { 232 | "id": "38", 233 | "name": "死歌", 234 | "cluster": "幽灵", 235 | "value": 25 236 | }, 237 | { 238 | "id": "39", 239 | "name": "狼人", 240 | "cluster": "狂野", 241 | "value": 5 242 | }, 243 | { 244 | "id": "40", 245 | "name": "豹女", 246 | "cluster": "狂野", 247 | "value": 5 248 | }, 249 | { 250 | "id": "41", 251 | "name": "狐狸", 252 | "cluster": "狂野", 253 | "value": 10 254 | }, 255 | { 256 | "id": "42", 257 | "name": "狮子狗", 258 | "cluster": "狂野", 259 | "value": 15 260 | }, 261 | { 262 | "id": "43", 263 | "name": "纳尔", 264 | "cluster": "狂野", 265 | "value": 20 266 | }, 267 | { 268 | "id": "44", 269 | "name": "螳螂", 270 | "cluster": "虚空", 271 | "value": 5 272 | }, 273 | { 274 | "id": "45", 275 | "name": "卡萨丁", 276 | "cluster": "虚空", 277 | "value": 5 278 | }, 279 | { 280 | "id": "46", 281 | "name": "挖掘机", 282 | "cluster": "虚空", 283 | "value": 10 284 | }, 285 | { 286 | "id": "47", 287 | "name": "大虫子", 288 | "cluster": "虚空", 289 | "value": 20 290 | }, 291 | { 292 | "id": "48", 293 | "name": "卡萨", 294 | "cluster": "虚空", 295 | "value": 25 296 | }, 297 | { 298 | "id": "49", 299 | "name": "小炮", 300 | "cluster": "约德尔", 301 | "value": 5 302 | }, 303 | { 304 | "id": "50", 305 | "name": "露露", 306 | "cluster": "约德尔", 307 | "value": 10 308 | }, 309 | { 310 | "id": "51", 311 | "name": "波比", 312 | "cluster": "约德尔", 313 | "value": 15 314 | }, 315 | { 316 | "id": "52", 317 | "name": "小法", 318 | "cluster": "约德尔", 319 | "value": 15 320 | }, 321 | { 322 | "id": "53", 323 | "name": "卡密尔", 324 | "cluster": "海克斯", 325 | "value": 5 326 | }, 327 | { 328 | "id": "54", 329 | "name": "蔚", 330 | "cluster": "海克斯", 331 | "value": 15 332 | }, 333 | { 334 | "id": "55", 335 | "name": "金克斯", 336 | "cluster": "海克斯", 337 | "value": 20 338 | } 339 | ], 340 | "edges": [ 341 | { 342 | "source": "0", 343 | "target": "1", 344 | "sourceWeight": 10, 345 | "targetWeight": 0 346 | }, 347 | { 348 | "source": "0", 349 | "target": "2", 350 | "sourceWeight": 10, 351 | "targetWeight": 0 352 | }, 353 | { 354 | "source": "0", 355 | "target": "3", 356 | "sourceWeight": 10, 357 | "targetWeight": 0 358 | }, 359 | { 360 | "source": "0", 361 | "target": "4", 362 | "sourceWeight": 10, 363 | "targetWeight": 0 364 | }, 365 | { 366 | "source": "0", 367 | "target": "5", 368 | "sourceWeight": 10, 369 | "targetWeight": 0 370 | }, 371 | { 372 | "source": "0", 373 | "target": "6", 374 | "sourceWeight": 10, 375 | "targetWeight": 0 376 | }, 377 | { 378 | "source": "0", 379 | "target": "10", 380 | "sourceWeight": 10, 381 | "targetWeight": 0 382 | }, 383 | { 384 | "source": "0", 385 | "target": "13", 386 | "sourceWeight": 10, 387 | "targetWeight": 0 388 | }, 389 | { 390 | "source": "0", 391 | "target": "17", 392 | "sourceWeight": 10, 393 | "targetWeight": 0 394 | }, 395 | { 396 | "source": "0", 397 | "target": "23", 398 | "sourceWeight": 10, 399 | "targetWeight": 0 400 | }, 401 | { 402 | "source": "0", 403 | "target": "27", 404 | "sourceWeight": 10, 405 | "targetWeight": 0 406 | }, 407 | { 408 | "source": "0", 409 | "target": "28", 410 | "sourceWeight": 10, 411 | "targetWeight": 0 412 | }, 413 | { 414 | "source": "0", 415 | "target": "29", 416 | "sourceWeight": 10, 417 | "targetWeight": 0 418 | }, 419 | { 420 | "source": "0", 421 | "target": "30", 422 | "sourceWeight": 10, 423 | "targetWeight": 0 424 | }, 425 | { 426 | "source": "0", 427 | "target": "37", 428 | "sourceWeight": 10, 429 | "targetWeight": 0 430 | }, 431 | { 432 | "source": "0", 433 | "target": "48", 434 | "sourceWeight": 10, 435 | "targetWeight": 0 436 | }, 437 | { 438 | "source": "1", 439 | "target": "2", 440 | "sourceWeight": 10, 441 | "targetWeight": 0 442 | }, 443 | { 444 | "source": "1", 445 | "target": "3", 446 | "sourceWeight": 10, 447 | "targetWeight": 0 448 | }, 449 | { 450 | "source": "1", 451 | "target": "4", 452 | "sourceWeight": 10, 453 | "targetWeight": 0 454 | }, 455 | { 456 | "source": "1", 457 | "target": "5", 458 | "sourceWeight": 10, 459 | "targetWeight": 0 460 | }, 461 | { 462 | "source": "1", 463 | "target": "6", 464 | "sourceWeight": 10, 465 | "targetWeight": 0 466 | }, 467 | { 468 | "source": "1", 469 | "target": "7", 470 | "sourceWeight": 10, 471 | "targetWeight": 0 472 | }, 473 | { 474 | "source": "1", 475 | "target": "10", 476 | "sourceWeight": 10, 477 | "targetWeight": 0 478 | }, 479 | { 480 | "source": "1", 481 | "target": "17", 482 | "sourceWeight": 10, 483 | "targetWeight": 0 484 | }, 485 | { 486 | "source": "1", 487 | "target": "27", 488 | "sourceWeight": 10, 489 | "targetWeight": 0 490 | }, 491 | { 492 | "source": "1", 493 | "target": "28", 494 | "sourceWeight": 10, 495 | "targetWeight": 0 496 | }, 497 | { 498 | "source": "1", 499 | "target": "29", 500 | "sourceWeight": 10, 501 | "targetWeight": 0 502 | }, 503 | { 504 | "source": "1", 505 | "target": "30", 506 | "sourceWeight": 10, 507 | "targetWeight": 0 508 | }, 509 | { 510 | "source": "1", 511 | "target": "40", 512 | "sourceWeight": 10, 513 | "targetWeight": 0 514 | }, 515 | { 516 | "source": "1", 517 | "target": "43", 518 | "sourceWeight": 10, 519 | "targetWeight": 0 520 | }, 521 | { 522 | "source": "10", 523 | "target": "17", 524 | "sourceWeight": 10, 525 | "targetWeight": 0 526 | }, 527 | { 528 | "source": "10", 529 | "target": "20", 530 | "sourceWeight": 10, 531 | "targetWeight": 0 532 | }, 533 | { 534 | "source": "10", 535 | "target": "21", 536 | "sourceWeight": 10, 537 | "targetWeight": 0 538 | }, 539 | { 540 | "source": "10", 541 | "target": "27", 542 | "sourceWeight": 10, 543 | "targetWeight": 0 544 | }, 545 | { 546 | "source": "10", 547 | "target": "28", 548 | "sourceWeight": 10, 549 | "targetWeight": 0 550 | }, 551 | { 552 | "source": "10", 553 | "target": "29", 554 | "sourceWeight": 10, 555 | "targetWeight": 0 556 | }, 557 | { 558 | "source": "10", 559 | "target": "30", 560 | "sourceWeight": 10, 561 | "targetWeight": 0 562 | }, 563 | { 564 | "source": "10", 565 | "target": "34", 566 | "sourceWeight": 10, 567 | "targetWeight": 0 568 | }, 569 | { 570 | "source": "10", 571 | "target": "53", 572 | "sourceWeight": 10, 573 | "targetWeight": 0 574 | }, 575 | { 576 | "source": "11", 577 | "target": "12", 578 | "sourceWeight": 10, 579 | "targetWeight": 0 580 | }, 581 | { 582 | "source": "11", 583 | "target": "13", 584 | "sourceWeight": 10, 585 | "targetWeight": 0 586 | }, 587 | { 588 | "source": "11", 589 | "target": "14", 590 | "sourceWeight": 10, 591 | "targetWeight": 0 592 | }, 593 | { 594 | "source": "11", 595 | "target": "15", 596 | "sourceWeight": 10, 597 | "targetWeight": 0 598 | }, 599 | { 600 | "source": "11", 601 | "target": "16", 602 | "sourceWeight": 10, 603 | "targetWeight": 0 604 | }, 605 | { 606 | "source": "11", 607 | "target": "17", 608 | "sourceWeight": 10, 609 | "targetWeight": 0 610 | }, 611 | { 612 | "source": "11", 613 | "target": "25", 614 | "sourceWeight": 10, 615 | "targetWeight": 0 616 | }, 617 | { 618 | "source": "11", 619 | "target": "27", 620 | "sourceWeight": 10, 621 | "targetWeight": 0 622 | }, 623 | { 624 | "source": "11", 625 | "target": "28", 626 | "sourceWeight": 10, 627 | "targetWeight": 0 628 | }, 629 | { 630 | "source": "11", 631 | "target": "29", 632 | "sourceWeight": 10, 633 | "targetWeight": 0 634 | }, 635 | { 636 | "source": "11", 637 | "target": "30", 638 | "sourceWeight": 10, 639 | "targetWeight": 0 640 | }, 641 | { 642 | "source": "12", 643 | "target": "13", 644 | "sourceWeight": 10, 645 | "targetWeight": 0 646 | }, 647 | { 648 | "source": "12", 649 | "target": "14", 650 | "sourceWeight": 10, 651 | "targetWeight": 0 652 | }, 653 | { 654 | "source": "12", 655 | "target": "15", 656 | "sourceWeight": 10, 657 | "targetWeight": 0 658 | }, 659 | { 660 | "source": "12", 661 | "target": "16", 662 | "sourceWeight": 10, 663 | "targetWeight": 0 664 | }, 665 | { 666 | "source": "12", 667 | "target": "17", 668 | "sourceWeight": 10, 669 | "targetWeight": 0 670 | }, 671 | { 672 | "source": "12", 673 | "target": "27", 674 | "sourceWeight": 10, 675 | "targetWeight": 0 676 | }, 677 | { 678 | "source": "12", 679 | "target": "28", 680 | "sourceWeight": 10, 681 | "targetWeight": 0 682 | }, 683 | { 684 | "source": "12", 685 | "target": "29", 686 | "sourceWeight": 10, 687 | "targetWeight": 0 688 | }, 689 | { 690 | "source": "12", 691 | "target": "30", 692 | "sourceWeight": 10, 693 | "targetWeight": 0 694 | }, 695 | { 696 | "source": "13", 697 | "target": "14", 698 | "sourceWeight": 10, 699 | "targetWeight": 0 700 | }, 701 | { 702 | "source": "13", 703 | "target": "15", 704 | "sourceWeight": 10, 705 | "targetWeight": 0 706 | }, 707 | { 708 | "source": "13", 709 | "target": "16", 710 | "sourceWeight": 10, 711 | "targetWeight": 0 712 | }, 713 | { 714 | "source": "13", 715 | "target": "17", 716 | "sourceWeight": 10, 717 | "targetWeight": 0 718 | }, 719 | { 720 | "source": "13", 721 | "target": "23", 722 | "sourceWeight": 10, 723 | "targetWeight": 0 724 | }, 725 | { 726 | "source": "13", 727 | "target": "27", 728 | "sourceWeight": 10, 729 | "targetWeight": 0 730 | }, 731 | { 732 | "source": "13", 733 | "target": "28", 734 | "sourceWeight": 10, 735 | "targetWeight": 0 736 | }, 737 | { 738 | "source": "13", 739 | "target": "29", 740 | "sourceWeight": 10, 741 | "targetWeight": 0 742 | }, 743 | { 744 | "source": "13", 745 | "target": "30", 746 | "sourceWeight": 10, 747 | "targetWeight": 0 748 | }, 749 | { 750 | "source": "13", 751 | "target": "37", 752 | "sourceWeight": 10, 753 | "targetWeight": 0 754 | }, 755 | { 756 | "source": "13", 757 | "target": "48", 758 | "sourceWeight": 10, 759 | "targetWeight": 0 760 | }, 761 | { 762 | "source": "14", 763 | "target": "15", 764 | "sourceWeight": 10, 765 | "targetWeight": 0 766 | }, 767 | { 768 | "source": "14", 769 | "target": "16", 770 | "sourceWeight": 10, 771 | "targetWeight": 0 772 | }, 773 | { 774 | "source": "14", 775 | "target": "17", 776 | "sourceWeight": 10, 777 | "targetWeight": 0 778 | }, 779 | { 780 | "source": "14", 781 | "target": "27", 782 | "sourceWeight": 10, 783 | "targetWeight": 0 784 | }, 785 | { 786 | "source": "14", 787 | "target": "28", 788 | "sourceWeight": 10, 789 | "targetWeight": 0 790 | }, 791 | { 792 | "source": "14", 793 | "target": "29", 794 | "sourceWeight": 10, 795 | "targetWeight": 0 796 | }, 797 | { 798 | "source": "14", 799 | "target": "30", 800 | "sourceWeight": 10, 801 | "targetWeight": 0 802 | }, 803 | { 804 | "source": "14", 805 | "target": "39", 806 | "sourceWeight": 10, 807 | "targetWeight": 0 808 | }, 809 | { 810 | "source": "14", 811 | "target": "46", 812 | "sourceWeight": 10, 813 | "targetWeight": 0 814 | }, 815 | { 816 | "source": "14", 817 | "target": "47", 818 | "sourceWeight": 10, 819 | "targetWeight": 0 820 | }, 821 | { 822 | "source": "14", 823 | "target": "54", 824 | "sourceWeight": 10, 825 | "targetWeight": 0 826 | }, 827 | { 828 | "source": "15", 829 | "target": "16", 830 | "sourceWeight": 10, 831 | "targetWeight": 0 832 | }, 833 | { 834 | "source": "15", 835 | "target": "17", 836 | "sourceWeight": 10, 837 | "targetWeight": 0 838 | }, 839 | { 840 | "source": "15", 841 | "target": "18", 842 | "sourceWeight": 10, 843 | "targetWeight": 0 844 | }, 845 | { 846 | "source": "15", 847 | "target": "22", 848 | "sourceWeight": 10, 849 | "targetWeight": 0 850 | }, 851 | { 852 | "source": "15", 853 | "target": "26", 854 | "sourceWeight": 10, 855 | "targetWeight": 0 856 | }, 857 | { 858 | "source": "15", 859 | "target": "27", 860 | "sourceWeight": 10, 861 | "targetWeight": 0 862 | }, 863 | { 864 | "source": "15", 865 | "target": "28", 866 | "sourceWeight": 10, 867 | "targetWeight": 0 868 | }, 869 | { 870 | "source": "15", 871 | "target": "29", 872 | "sourceWeight": 10, 873 | "targetWeight": 0 874 | }, 875 | { 876 | "source": "15", 877 | "target": "30", 878 | "sourceWeight": 10, 879 | "targetWeight": 0 880 | }, 881 | { 882 | "source": "15", 883 | "target": "36", 884 | "sourceWeight": 10, 885 | "targetWeight": 0 886 | }, 887 | { 888 | "source": "15", 889 | "target": "51", 890 | "sourceWeight": 10, 891 | "targetWeight": 0 892 | }, 893 | { 894 | "source": "16", 895 | "target": "17", 896 | "sourceWeight": 10, 897 | "targetWeight": 0 898 | }, 899 | { 900 | "source": "16", 901 | "target": "27", 902 | "sourceWeight": 10, 903 | "targetWeight": 0 904 | }, 905 | { 906 | "source": "16", 907 | "target": "28", 908 | "sourceWeight": 10, 909 | "targetWeight": 0 910 | }, 911 | { 912 | "source": "16", 913 | "target": "29", 914 | "sourceWeight": 10, 915 | "targetWeight": 0 916 | }, 917 | { 918 | "source": "16", 919 | "target": "30", 920 | "sourceWeight": 10, 921 | "targetWeight": 0 922 | }, 923 | { 924 | "source": "17", 925 | "target": "27", 926 | "sourceWeight": 10, 927 | "targetWeight": 0 928 | }, 929 | { 930 | "source": "17", 931 | "target": "28", 932 | "sourceWeight": 10, 933 | "targetWeight": 0 934 | }, 935 | { 936 | "source": "17", 937 | "target": "29", 938 | "sourceWeight": 10, 939 | "targetWeight": 0 940 | }, 941 | { 942 | "source": "17", 943 | "target": "30", 944 | "sourceWeight": 10, 945 | "targetWeight": 0 946 | }, 947 | { 948 | "source": "17", 949 | "target": "39", 950 | "sourceWeight": 10, 951 | "targetWeight": 0 952 | }, 953 | { 954 | "source": "17", 955 | "target": "46", 956 | "sourceWeight": 10, 957 | "targetWeight": 0 958 | }, 959 | { 960 | "source": "17", 961 | "target": "47", 962 | "sourceWeight": 10, 963 | "targetWeight": 0 964 | }, 965 | { 966 | "source": "17", 967 | "target": "54", 968 | "sourceWeight": 10, 969 | "targetWeight": 0 970 | }, 971 | { 972 | "source": "18", 973 | "target": "19", 974 | "sourceWeight": 10, 975 | "targetWeight": 0 976 | }, 977 | { 978 | "source": "18", 979 | "target": "20", 980 | "sourceWeight": 10, 981 | "targetWeight": 0 982 | }, 983 | { 984 | "source": "18", 985 | "target": "22", 986 | "sourceWeight": 10, 987 | "targetWeight": 0 988 | }, 989 | { 990 | "source": "18", 991 | "target": "26", 992 | "sourceWeight": 10, 993 | "targetWeight": 0 994 | }, 995 | { 996 | "source": "18", 997 | "target": "27", 998 | "sourceWeight": 10, 999 | "targetWeight": 0 1000 | }, 1001 | { 1002 | "source": "18", 1003 | "target": "28", 1004 | "sourceWeight": 10, 1005 | "targetWeight": 0 1006 | }, 1007 | { 1008 | "source": "18", 1009 | "target": "29", 1010 | "sourceWeight": 10, 1011 | "targetWeight": 0 1012 | }, 1013 | { 1014 | "source": "18", 1015 | "target": "30", 1016 | "sourceWeight": 10, 1017 | "targetWeight": 0 1018 | }, 1019 | { 1020 | "source": "18", 1021 | "target": "36", 1022 | "sourceWeight": 10, 1023 | "targetWeight": 0 1024 | }, 1025 | { 1026 | "source": "18", 1027 | "target": "51", 1028 | "sourceWeight": 10, 1029 | "targetWeight": 0 1030 | }, 1031 | { 1032 | "source": "19", 1033 | "target": "20", 1034 | "sourceWeight": 10, 1035 | "targetWeight": 0 1036 | }, 1037 | { 1038 | "source": "19", 1039 | "target": "27", 1040 | "sourceWeight": 10, 1041 | "targetWeight": 0 1042 | }, 1043 | { 1044 | "source": "19", 1045 | "target": "28", 1046 | "sourceWeight": 10, 1047 | "targetWeight": 0 1048 | }, 1049 | { 1050 | "source": "19", 1051 | "target": "29", 1052 | "sourceWeight": 10, 1053 | "targetWeight": 0 1054 | }, 1055 | { 1056 | "source": "19", 1057 | "target": "30", 1058 | "sourceWeight": 10, 1059 | "targetWeight": 0 1060 | }, 1061 | { 1062 | "source": "19", 1063 | "target": "32", 1064 | "sourceWeight": 10, 1065 | "targetWeight": 0 1066 | }, 1067 | { 1068 | "source": "19", 1069 | "target": "42", 1070 | "sourceWeight": 10, 1071 | "targetWeight": 0 1072 | }, 1073 | { 1074 | "source": "19", 1075 | "target": "44", 1076 | "sourceWeight": 10, 1077 | "targetWeight": 0 1078 | }, 1079 | { 1080 | "source": "19", 1081 | "target": "48", 1082 | "sourceWeight": 10, 1083 | "targetWeight": 0 1084 | }, 1085 | { 1086 | "source": "2", 1087 | "target": "3", 1088 | "sourceWeight": 10, 1089 | "targetWeight": 0 1090 | }, 1091 | { 1092 | "source": "2", 1093 | "target": "4", 1094 | "sourceWeight": 10, 1095 | "targetWeight": 0 1096 | }, 1097 | { 1098 | "source": "2", 1099 | "target": "5", 1100 | "sourceWeight": 10, 1101 | "targetWeight": 0 1102 | }, 1103 | { 1104 | "source": "2", 1105 | "target": "6", 1106 | "sourceWeight": 10, 1107 | "targetWeight": 0 1108 | }, 1109 | { 1110 | "source": "2", 1111 | "target": "8", 1112 | "sourceWeight": 10, 1113 | "targetWeight": 0 1114 | }, 1115 | { 1116 | "source": "2", 1117 | "target": "10", 1118 | "sourceWeight": 10, 1119 | "targetWeight": 0 1120 | }, 1121 | { 1122 | "source": "2", 1123 | "target": "17", 1124 | "sourceWeight": 10, 1125 | "targetWeight": 0 1126 | }, 1127 | { 1128 | "source": "2", 1129 | "target": "27", 1130 | "sourceWeight": 10, 1131 | "targetWeight": 0 1132 | }, 1133 | { 1134 | "source": "2", 1135 | "target": "28", 1136 | "sourceWeight": 10, 1137 | "targetWeight": 0 1138 | }, 1139 | { 1140 | "source": "2", 1141 | "target": "29", 1142 | "sourceWeight": 10, 1143 | "targetWeight": 0 1144 | }, 1145 | { 1146 | "source": "2", 1147 | "target": "30", 1148 | "sourceWeight": 10, 1149 | "targetWeight": 0 1150 | }, 1151 | { 1152 | "source": "2", 1153 | "target": "33", 1154 | "sourceWeight": 10, 1155 | "targetWeight": 0 1156 | }, 1157 | { 1158 | "source": "2", 1159 | "target": "38", 1160 | "sourceWeight": 10, 1161 | "targetWeight": 0 1162 | }, 1163 | { 1164 | "source": "2", 1165 | "target": "41", 1166 | "sourceWeight": 10, 1167 | "targetWeight": 0 1168 | }, 1169 | { 1170 | "source": "2", 1171 | "target": "45", 1172 | "sourceWeight": 10, 1173 | "targetWeight": 0 1174 | }, 1175 | { 1176 | "source": "2", 1177 | "target": "50", 1178 | "sourceWeight": 10, 1179 | "targetWeight": 0 1180 | }, 1181 | { 1182 | "source": "2", 1183 | "target": "52", 1184 | "sourceWeight": 10, 1185 | "targetWeight": 0 1186 | }, 1187 | { 1188 | "source": "20", 1189 | "target": "21", 1190 | "sourceWeight": 10, 1191 | "targetWeight": 0 1192 | }, 1193 | { 1194 | "source": "20", 1195 | "target": "27", 1196 | "sourceWeight": 10, 1197 | "targetWeight": 0 1198 | }, 1199 | { 1200 | "source": "20", 1201 | "target": "28", 1202 | "sourceWeight": 10, 1203 | "targetWeight": 0 1204 | }, 1205 | { 1206 | "source": "20", 1207 | "target": "29", 1208 | "sourceWeight": 10, 1209 | "targetWeight": 0 1210 | }, 1211 | { 1212 | "source": "20", 1213 | "target": "30", 1214 | "sourceWeight": 10, 1215 | "targetWeight": 0 1216 | }, 1217 | { 1218 | "source": "20", 1219 | "target": "34", 1220 | "sourceWeight": 10, 1221 | "targetWeight": 0 1222 | }, 1223 | { 1224 | "source": "20", 1225 | "target": "53", 1226 | "sourceWeight": 10, 1227 | "targetWeight": 0 1228 | }, 1229 | { 1230 | "source": "21", 1231 | "target": "22", 1232 | "sourceWeight": 10, 1233 | "targetWeight": 0 1234 | }, 1235 | { 1236 | "source": "21", 1237 | "target": "23", 1238 | "sourceWeight": 10, 1239 | "targetWeight": 0 1240 | }, 1241 | { 1242 | "source": "21", 1243 | "target": "24", 1244 | "sourceWeight": 10, 1245 | "targetWeight": 0 1246 | }, 1247 | { 1248 | "source": "21", 1249 | "target": "25", 1250 | "sourceWeight": 10, 1251 | "targetWeight": 0 1252 | }, 1253 | { 1254 | "source": "21", 1255 | "target": "26", 1256 | "sourceWeight": 10, 1257 | "targetWeight": 0 1258 | }, 1259 | { 1260 | "source": "21", 1261 | "target": "27", 1262 | "sourceWeight": 10, 1263 | "targetWeight": 0 1264 | }, 1265 | { 1266 | "source": "21", 1267 | "target": "28", 1268 | "sourceWeight": 10, 1269 | "targetWeight": 0 1270 | }, 1271 | { 1272 | "source": "21", 1273 | "target": "29", 1274 | "sourceWeight": 10, 1275 | "targetWeight": 0 1276 | }, 1277 | { 1278 | "source": "21", 1279 | "target": "30", 1280 | "sourceWeight": 10, 1281 | "targetWeight": 0 1282 | }, 1283 | { 1284 | "source": "21", 1285 | "target": "34", 1286 | "sourceWeight": 10, 1287 | "targetWeight": 0 1288 | }, 1289 | { 1290 | "source": "21", 1291 | "target": "53", 1292 | "sourceWeight": 10, 1293 | "targetWeight": 0 1294 | }, 1295 | { 1296 | "source": "22", 1297 | "target": "23", 1298 | "sourceWeight": 10, 1299 | "targetWeight": 0 1300 | }, 1301 | { 1302 | "source": "22", 1303 | "target": "24", 1304 | "sourceWeight": 10, 1305 | "targetWeight": 0 1306 | }, 1307 | { 1308 | "source": "22", 1309 | "target": "25", 1310 | "sourceWeight": 10, 1311 | "targetWeight": 0 1312 | }, 1313 | { 1314 | "source": "22", 1315 | "target": "26", 1316 | "sourceWeight": 10, 1317 | "targetWeight": 0 1318 | }, 1319 | { 1320 | "source": "22", 1321 | "target": "27", 1322 | "sourceWeight": 10, 1323 | "targetWeight": 0 1324 | }, 1325 | { 1326 | "source": "22", 1327 | "target": "28", 1328 | "sourceWeight": 10, 1329 | "targetWeight": 0 1330 | }, 1331 | { 1332 | "source": "22", 1333 | "target": "29", 1334 | "sourceWeight": 10, 1335 | "targetWeight": 0 1336 | }, 1337 | { 1338 | "source": "22", 1339 | "target": "30", 1340 | "sourceWeight": 10, 1341 | "targetWeight": 0 1342 | }, 1343 | { 1344 | "source": "22", 1345 | "target": "36", 1346 | "sourceWeight": 10, 1347 | "targetWeight": 0 1348 | }, 1349 | { 1350 | "source": "22", 1351 | "target": "51", 1352 | "sourceWeight": 10, 1353 | "targetWeight": 0 1354 | }, 1355 | { 1356 | "source": "23", 1357 | "target": "24", 1358 | "sourceWeight": 10, 1359 | "targetWeight": 0 1360 | }, 1361 | { 1362 | "source": "23", 1363 | "target": "25", 1364 | "sourceWeight": 10, 1365 | "targetWeight": 0 1366 | }, 1367 | { 1368 | "source": "23", 1369 | "target": "26", 1370 | "sourceWeight": 10, 1371 | "targetWeight": 0 1372 | }, 1373 | { 1374 | "source": "23", 1375 | "target": "27", 1376 | "sourceWeight": 10, 1377 | "targetWeight": 0 1378 | }, 1379 | { 1380 | "source": "23", 1381 | "target": "28", 1382 | "sourceWeight": 10, 1383 | "targetWeight": 0 1384 | }, 1385 | { 1386 | "source": "23", 1387 | "target": "29", 1388 | "sourceWeight": 10, 1389 | "targetWeight": 0 1390 | }, 1391 | { 1392 | "source": "23", 1393 | "target": "30", 1394 | "sourceWeight": 10, 1395 | "targetWeight": 0 1396 | }, 1397 | { 1398 | "source": "23", 1399 | "target": "37", 1400 | "sourceWeight": 10, 1401 | "targetWeight": 0 1402 | }, 1403 | { 1404 | "source": "23", 1405 | "target": "48", 1406 | "sourceWeight": 10, 1407 | "targetWeight": 0 1408 | }, 1409 | { 1410 | "source": "24", 1411 | "target": "25", 1412 | "sourceWeight": 10, 1413 | "targetWeight": 0 1414 | }, 1415 | { 1416 | "source": "24", 1417 | "target": "26", 1418 | "sourceWeight": 10, 1419 | "targetWeight": 0 1420 | }, 1421 | { 1422 | "source": "24", 1423 | "target": "27", 1424 | "sourceWeight": 10, 1425 | "targetWeight": 0 1426 | }, 1427 | { 1428 | "source": "24", 1429 | "target": "28", 1430 | "sourceWeight": 10, 1431 | "targetWeight": 0 1432 | }, 1433 | { 1434 | "source": "24", 1435 | "target": "29", 1436 | "sourceWeight": 10, 1437 | "targetWeight": 0 1438 | }, 1439 | { 1440 | "source": "24", 1441 | "target": "30", 1442 | "sourceWeight": 10, 1443 | "targetWeight": 0 1444 | }, 1445 | { 1446 | "source": "24", 1447 | "target": "36", 1448 | "sourceWeight": 10, 1449 | "targetWeight": 0 1450 | }, 1451 | { 1452 | "source": "24", 1453 | "target": "51", 1454 | "sourceWeight": 10, 1455 | "targetWeight": 0 1456 | }, 1457 | { 1458 | "source": "25", 1459 | "target": "26", 1460 | "sourceWeight": 10, 1461 | "targetWeight": 0 1462 | }, 1463 | { 1464 | "source": "25", 1465 | "target": "27", 1466 | "sourceWeight": 10, 1467 | "targetWeight": 0 1468 | }, 1469 | { 1470 | "source": "25", 1471 | "target": "28", 1472 | "sourceWeight": 10, 1473 | "targetWeight": 0 1474 | }, 1475 | { 1476 | "source": "25", 1477 | "target": "29", 1478 | "sourceWeight": 10, 1479 | "targetWeight": 0 1480 | }, 1481 | { 1482 | "source": "25", 1483 | "target": "30", 1484 | "sourceWeight": 10, 1485 | "targetWeight": 0 1486 | }, 1487 | { 1488 | "source": "26", 1489 | "target": "27", 1490 | "sourceWeight": 10, 1491 | "targetWeight": 0 1492 | }, 1493 | { 1494 | "source": "26", 1495 | "target": "28", 1496 | "sourceWeight": 10, 1497 | "targetWeight": 0 1498 | }, 1499 | { 1500 | "source": "26", 1501 | "target": "29", 1502 | "sourceWeight": 10, 1503 | "targetWeight": 0 1504 | }, 1505 | { 1506 | "source": "26", 1507 | "target": "30", 1508 | "sourceWeight": 10, 1509 | "targetWeight": 0 1510 | }, 1511 | { 1512 | "source": "26", 1513 | "target": "36", 1514 | "sourceWeight": 10, 1515 | "targetWeight": 0 1516 | }, 1517 | { 1518 | "source": "26", 1519 | "target": "51", 1520 | "sourceWeight": 10, 1521 | "targetWeight": 0 1522 | }, 1523 | { 1524 | "source": "27", 1525 | "target": "28", 1526 | "sourceWeight": 10, 1527 | "targetWeight": 0 1528 | }, 1529 | { 1530 | "source": "27", 1531 | "target": "29", 1532 | "sourceWeight": 10, 1533 | "targetWeight": 0 1534 | }, 1535 | { 1536 | "source": "27", 1537 | "target": "30", 1538 | "sourceWeight": 10, 1539 | "targetWeight": 0 1540 | }, 1541 | { 1542 | "source": "27", 1543 | "target": "34", 1544 | "sourceWeight": 10, 1545 | "targetWeight": 0 1546 | }, 1547 | { 1548 | "source": "27", 1549 | "target": "53", 1550 | "sourceWeight": 10, 1551 | "targetWeight": 0 1552 | }, 1553 | { 1554 | "source": "28", 1555 | "target": "29", 1556 | "sourceWeight": 10, 1557 | "targetWeight": 0 1558 | }, 1559 | { 1560 | "source": "28", 1561 | "target": "30", 1562 | "sourceWeight": 10, 1563 | "targetWeight": 0 1564 | }, 1565 | { 1566 | "source": "28", 1567 | "target": "32", 1568 | "sourceWeight": 10, 1569 | "targetWeight": 0 1570 | }, 1571 | { 1572 | "source": "28", 1573 | "target": "42", 1574 | "sourceWeight": 10, 1575 | "targetWeight": 0 1576 | }, 1577 | { 1578 | "source": "28", 1579 | "target": "44", 1580 | "sourceWeight": 10, 1581 | "targetWeight": 0 1582 | }, 1583 | { 1584 | "source": "28", 1585 | "target": "48", 1586 | "sourceWeight": 10, 1587 | "targetWeight": 0 1588 | }, 1589 | { 1590 | "source": "29", 1591 | "target": "30", 1592 | "sourceWeight": 10, 1593 | "targetWeight": 0 1594 | }, 1595 | { 1596 | "source": "29", 1597 | "target": "43", 1598 | "sourceWeight": 10, 1599 | "targetWeight": 0 1600 | }, 1601 | { 1602 | "source": "29", 1603 | "target": "49", 1604 | "sourceWeight": 10, 1605 | "targetWeight": 0 1606 | }, 1607 | { 1608 | "source": "29", 1609 | "target": "50", 1610 | "sourceWeight": 10, 1611 | "targetWeight": 0 1612 | }, 1613 | { 1614 | "source": "29", 1615 | "target": "51", 1616 | "sourceWeight": 10, 1617 | "targetWeight": 0 1618 | }, 1619 | { 1620 | "source": "29", 1621 | "target": "52", 1622 | "sourceWeight": 10, 1623 | "targetWeight": 0 1624 | }, 1625 | { 1626 | "source": "3", 1627 | "target": "4", 1628 | "sourceWeight": 10, 1629 | "targetWeight": 0 1630 | }, 1631 | { 1632 | "source": "3", 1633 | "target": "5", 1634 | "sourceWeight": 10, 1635 | "targetWeight": 0 1636 | }, 1637 | { 1638 | "source": "3", 1639 | "target": "6", 1640 | "sourceWeight": 10, 1641 | "targetWeight": 0 1642 | }, 1643 | { 1644 | "source": "3", 1645 | "target": "10", 1646 | "sourceWeight": 10, 1647 | "targetWeight": 0 1648 | }, 1649 | { 1650 | "source": "3", 1651 | "target": "17", 1652 | "sourceWeight": 10, 1653 | "targetWeight": 0 1654 | }, 1655 | { 1656 | "source": "3", 1657 | "target": "19", 1658 | "sourceWeight": 10, 1659 | "targetWeight": 0 1660 | }, 1661 | { 1662 | "source": "3", 1663 | "target": "27", 1664 | "sourceWeight": 10, 1665 | "targetWeight": 0 1666 | }, 1667 | { 1668 | "source": "3", 1669 | "target": "28", 1670 | "sourceWeight": 10, 1671 | "targetWeight": 0 1672 | }, 1673 | { 1674 | "source": "3", 1675 | "target": "29", 1676 | "sourceWeight": 10, 1677 | "targetWeight": 0 1678 | }, 1679 | { 1680 | "source": "3", 1681 | "target": "30", 1682 | "sourceWeight": 10, 1683 | "targetWeight": 0 1684 | }, 1685 | { 1686 | "source": "3", 1687 | "target": "32", 1688 | "sourceWeight": 10, 1689 | "targetWeight": 0 1690 | }, 1691 | { 1692 | "source": "3", 1693 | "target": "42", 1694 | "sourceWeight": 10, 1695 | "targetWeight": 0 1696 | }, 1697 | { 1698 | "source": "3", 1699 | "target": "44", 1700 | "sourceWeight": 10, 1701 | "targetWeight": 0 1702 | }, 1703 | { 1704 | "source": "3", 1705 | "target": "48", 1706 | "sourceWeight": 10, 1707 | "targetWeight": 0 1708 | }, 1709 | { 1710 | "source": "30", 1711 | "target": "32", 1712 | "sourceWeight": 10, 1713 | "targetWeight": 0 1714 | }, 1715 | { 1716 | "source": "30", 1717 | "target": "42", 1718 | "sourceWeight": 10, 1719 | "targetWeight": 0 1720 | }, 1721 | { 1722 | "source": "30", 1723 | "target": "44", 1724 | "sourceWeight": 10, 1725 | "targetWeight": 0 1726 | }, 1727 | { 1728 | "source": "30", 1729 | "target": "48", 1730 | "sourceWeight": 10, 1731 | "targetWeight": 0 1732 | }, 1733 | { 1734 | "source": "31", 1735 | "target": "32", 1736 | "sourceWeight": 10, 1737 | "targetWeight": 0 1738 | }, 1739 | { 1740 | "source": "31", 1741 | "target": "33", 1742 | "sourceWeight": 10, 1743 | "targetWeight": 0 1744 | }, 1745 | { 1746 | "source": "31", 1747 | "target": "34", 1748 | "sourceWeight": 10, 1749 | "targetWeight": 0 1750 | }, 1751 | { 1752 | "source": "31", 1753 | "target": "35", 1754 | "sourceWeight": 10, 1755 | "targetWeight": 0 1756 | }, 1757 | { 1758 | "source": "31", 1759 | "target": "36", 1760 | "sourceWeight": 10, 1761 | "targetWeight": 0 1762 | }, 1763 | { 1764 | "source": "31", 1765 | "target": "51", 1766 | "sourceWeight": 10, 1767 | "targetWeight": 0 1768 | }, 1769 | { 1770 | "source": "32", 1771 | "target": "33", 1772 | "sourceWeight": 10, 1773 | "targetWeight": 0 1774 | }, 1775 | { 1776 | "source": "32", 1777 | "target": "34", 1778 | "sourceWeight": 10, 1779 | "targetWeight": 0 1780 | }, 1781 | { 1782 | "source": "32", 1783 | "target": "35", 1784 | "sourceWeight": 10, 1785 | "targetWeight": 0 1786 | }, 1787 | { 1788 | "source": "32", 1789 | "target": "42", 1790 | "sourceWeight": 10, 1791 | "targetWeight": 0 1792 | }, 1793 | { 1794 | "source": "32", 1795 | "target": "44", 1796 | "sourceWeight": 10, 1797 | "targetWeight": 0 1798 | }, 1799 | { 1800 | "source": "32", 1801 | "target": "48", 1802 | "sourceWeight": 10, 1803 | "targetWeight": 0 1804 | }, 1805 | { 1806 | "source": "33", 1807 | "target": "34", 1808 | "sourceWeight": 10, 1809 | "targetWeight": 0 1810 | }, 1811 | { 1812 | "source": "33", 1813 | "target": "35", 1814 | "sourceWeight": 10, 1815 | "targetWeight": 0 1816 | }, 1817 | { 1818 | "source": "33", 1819 | "target": "38", 1820 | "sourceWeight": 10, 1821 | "targetWeight": 0 1822 | }, 1823 | { 1824 | "source": "33", 1825 | "target": "41", 1826 | "sourceWeight": 10, 1827 | "targetWeight": 0 1828 | }, 1829 | { 1830 | "source": "33", 1831 | "target": "45", 1832 | "sourceWeight": 10, 1833 | "targetWeight": 0 1834 | }, 1835 | { 1836 | "source": "33", 1837 | "target": "50", 1838 | "sourceWeight": 10, 1839 | "targetWeight": 0 1840 | }, 1841 | { 1842 | "source": "33", 1843 | "target": "52", 1844 | "sourceWeight": 10, 1845 | "targetWeight": 0 1846 | }, 1847 | { 1848 | "source": "34", 1849 | "target": "35", 1850 | "sourceWeight": 10, 1851 | "targetWeight": 0 1852 | }, 1853 | { 1854 | "source": "34", 1855 | "target": "36", 1856 | "sourceWeight": 10, 1857 | "targetWeight": 0 1858 | }, 1859 | { 1860 | "source": "34", 1861 | "target": "51", 1862 | "sourceWeight": 10, 1863 | "targetWeight": 0 1864 | }, 1865 | { 1866 | "source": "34", 1867 | "target": "53", 1868 | "sourceWeight": 10, 1869 | "targetWeight": 0 1870 | }, 1871 | { 1872 | "source": "35", 1873 | "target": "36", 1874 | "sourceWeight": 10, 1875 | "targetWeight": 0 1876 | }, 1877 | { 1878 | "source": "35", 1879 | "target": "51", 1880 | "sourceWeight": 10, 1881 | "targetWeight": 0 1882 | }, 1883 | { 1884 | "source": "36", 1885 | "target": "37", 1886 | "sourceWeight": 10, 1887 | "targetWeight": 0 1888 | }, 1889 | { 1890 | "source": "36", 1891 | "target": "38", 1892 | "sourceWeight": 10, 1893 | "targetWeight": 0 1894 | }, 1895 | { 1896 | "source": "36", 1897 | "target": "51", 1898 | "sourceWeight": 10, 1899 | "targetWeight": 0 1900 | }, 1901 | { 1902 | "source": "37", 1903 | "target": "38", 1904 | "sourceWeight": 10, 1905 | "targetWeight": 0 1906 | }, 1907 | { 1908 | "source": "37", 1909 | "target": "48", 1910 | "sourceWeight": 10, 1911 | "targetWeight": 0 1912 | }, 1913 | { 1914 | "source": "38", 1915 | "target": "41", 1916 | "sourceWeight": 10, 1917 | "targetWeight": 0 1918 | }, 1919 | { 1920 | "source": "38", 1921 | "target": "45", 1922 | "sourceWeight": 10, 1923 | "targetWeight": 0 1924 | }, 1925 | { 1926 | "source": "38", 1927 | "target": "50", 1928 | "sourceWeight": 10, 1929 | "targetWeight": 0 1930 | }, 1931 | { 1932 | "source": "38", 1933 | "target": "52", 1934 | "sourceWeight": 10, 1935 | "targetWeight": 0 1936 | }, 1937 | { 1938 | "source": "39", 1939 | "target": "40", 1940 | "sourceWeight": 10, 1941 | "targetWeight": 0 1942 | }, 1943 | { 1944 | "source": "39", 1945 | "target": "41", 1946 | "sourceWeight": 10, 1947 | "targetWeight": 0 1948 | }, 1949 | { 1950 | "source": "39", 1951 | "target": "42", 1952 | "sourceWeight": 10, 1953 | "targetWeight": 0 1954 | }, 1955 | { 1956 | "source": "39", 1957 | "target": "43", 1958 | "sourceWeight": 10, 1959 | "targetWeight": 0 1960 | }, 1961 | { 1962 | "source": "39", 1963 | "target": "46", 1964 | "sourceWeight": 10, 1965 | "targetWeight": 0 1966 | }, 1967 | { 1968 | "source": "39", 1969 | "target": "47", 1970 | "sourceWeight": 10, 1971 | "targetWeight": 0 1972 | }, 1973 | { 1974 | "source": "39", 1975 | "target": "54", 1976 | "sourceWeight": 10, 1977 | "targetWeight": 0 1978 | }, 1979 | { 1980 | "source": "4", 1981 | "target": "5", 1982 | "sourceWeight": 10, 1983 | "targetWeight": 0 1984 | }, 1985 | { 1986 | "source": "4", 1987 | "target": "6", 1988 | "sourceWeight": 10, 1989 | "targetWeight": 0 1990 | }, 1991 | { 1992 | "source": "4", 1993 | "target": "10", 1994 | "sourceWeight": 10, 1995 | "targetWeight": 0 1996 | }, 1997 | { 1998 | "source": "4", 1999 | "target": "17", 2000 | "sourceWeight": 10, 2001 | "targetWeight": 0 2002 | }, 2003 | { 2004 | "source": "4", 2005 | "target": "20", 2006 | "sourceWeight": 10, 2007 | "targetWeight": 0 2008 | }, 2009 | { 2010 | "source": "4", 2011 | "target": "21", 2012 | "sourceWeight": 10, 2013 | "targetWeight": 0 2014 | }, 2015 | { 2016 | "source": "4", 2017 | "target": "27", 2018 | "sourceWeight": 10, 2019 | "targetWeight": 0 2020 | }, 2021 | { 2022 | "source": "4", 2023 | "target": "28", 2024 | "sourceWeight": 10, 2025 | "targetWeight": 0 2026 | }, 2027 | { 2028 | "source": "4", 2029 | "target": "29", 2030 | "sourceWeight": 10, 2031 | "targetWeight": 0 2032 | }, 2033 | { 2034 | "source": "4", 2035 | "target": "30", 2036 | "sourceWeight": 10, 2037 | "targetWeight": 0 2038 | }, 2039 | { 2040 | "source": "4", 2041 | "target": "34", 2042 | "sourceWeight": 10, 2043 | "targetWeight": 0 2044 | }, 2045 | { 2046 | "source": "4", 2047 | "target": "53", 2048 | "sourceWeight": 10, 2049 | "targetWeight": 0 2050 | }, 2051 | { 2052 | "source": "40", 2053 | "target": "41", 2054 | "sourceWeight": 10, 2055 | "targetWeight": 0 2056 | }, 2057 | { 2058 | "source": "40", 2059 | "target": "42", 2060 | "sourceWeight": 10, 2061 | "targetWeight": 0 2062 | }, 2063 | { 2064 | "source": "40", 2065 | "target": "43", 2066 | "sourceWeight": 10, 2067 | "targetWeight": 0 2068 | }, 2069 | { 2070 | "source": "41", 2071 | "target": "42", 2072 | "sourceWeight": 10, 2073 | "targetWeight": 0 2074 | }, 2075 | { 2076 | "source": "41", 2077 | "target": "43", 2078 | "sourceWeight": 10, 2079 | "targetWeight": 0 2080 | }, 2081 | { 2082 | "source": "41", 2083 | "target": "45", 2084 | "sourceWeight": 10, 2085 | "targetWeight": 0 2086 | }, 2087 | { 2088 | "source": "41", 2089 | "target": "50", 2090 | "sourceWeight": 10, 2091 | "targetWeight": 0 2092 | }, 2093 | { 2094 | "source": "41", 2095 | "target": "52", 2096 | "sourceWeight": 10, 2097 | "targetWeight": 0 2098 | }, 2099 | { 2100 | "source": "42", 2101 | "target": "43", 2102 | "sourceWeight": 10, 2103 | "targetWeight": 0 2104 | }, 2105 | { 2106 | "source": "42", 2107 | "target": "44", 2108 | "sourceWeight": 10, 2109 | "targetWeight": 0 2110 | }, 2111 | { 2112 | "source": "42", 2113 | "target": "48", 2114 | "sourceWeight": 10, 2115 | "targetWeight": 0 2116 | }, 2117 | { 2118 | "source": "43", 2119 | "target": "49", 2120 | "sourceWeight": 10, 2121 | "targetWeight": 0 2122 | }, 2123 | { 2124 | "source": "43", 2125 | "target": "50", 2126 | "sourceWeight": 10, 2127 | "targetWeight": 0 2128 | }, 2129 | { 2130 | "source": "43", 2131 | "target": "51", 2132 | "sourceWeight": 10, 2133 | "targetWeight": 0 2134 | }, 2135 | { 2136 | "source": "43", 2137 | "target": "52", 2138 | "sourceWeight": 10, 2139 | "targetWeight": 0 2140 | }, 2141 | { 2142 | "source": "44", 2143 | "target": "45", 2144 | "sourceWeight": 10, 2145 | "targetWeight": 0 2146 | }, 2147 | { 2148 | "source": "44", 2149 | "target": "46", 2150 | "sourceWeight": 10, 2151 | "targetWeight": 0 2152 | }, 2153 | { 2154 | "source": "44", 2155 | "target": "47", 2156 | "sourceWeight": 10, 2157 | "targetWeight": 0 2158 | }, 2159 | { 2160 | "source": "44", 2161 | "target": "48", 2162 | "sourceWeight": 10, 2163 | "targetWeight": 0 2164 | }, 2165 | { 2166 | "source": "45", 2167 | "target": "46", 2168 | "sourceWeight": 10, 2169 | "targetWeight": 0 2170 | }, 2171 | { 2172 | "source": "45", 2173 | "target": "47", 2174 | "sourceWeight": 10, 2175 | "targetWeight": 0 2176 | }, 2177 | { 2178 | "source": "45", 2179 | "target": "48", 2180 | "sourceWeight": 10, 2181 | "targetWeight": 0 2182 | }, 2183 | { 2184 | "source": "45", 2185 | "target": "50", 2186 | "sourceWeight": 10, 2187 | "targetWeight": 0 2188 | }, 2189 | { 2190 | "source": "45", 2191 | "target": "52", 2192 | "sourceWeight": 10, 2193 | "targetWeight": 0 2194 | }, 2195 | { 2196 | "source": "46", 2197 | "target": "47", 2198 | "sourceWeight": 10, 2199 | "targetWeight": 0 2200 | }, 2201 | { 2202 | "source": "46", 2203 | "target": "48", 2204 | "sourceWeight": 10, 2205 | "targetWeight": 0 2206 | }, 2207 | { 2208 | "source": "46", 2209 | "target": "54", 2210 | "sourceWeight": 10, 2211 | "targetWeight": 0 2212 | }, 2213 | { 2214 | "source": "47", 2215 | "target": "48", 2216 | "sourceWeight": 10, 2217 | "targetWeight": 0 2218 | }, 2219 | { 2220 | "source": "47", 2221 | "target": "54", 2222 | "sourceWeight": 10, 2223 | "targetWeight": 0 2224 | }, 2225 | { 2226 | "source": "49", 2227 | "target": "50", 2228 | "sourceWeight": 10, 2229 | "targetWeight": 0 2230 | }, 2231 | { 2232 | "source": "49", 2233 | "target": "51", 2234 | "sourceWeight": 10, 2235 | "targetWeight": 0 2236 | }, 2237 | { 2238 | "source": "49", 2239 | "target": "52", 2240 | "sourceWeight": 10, 2241 | "targetWeight": 0 2242 | }, 2243 | { 2244 | "source": "5", 2245 | "target": "6", 2246 | "sourceWeight": 10, 2247 | "targetWeight": 0 2248 | }, 2249 | { 2250 | "source": "5", 2251 | "target": "10", 2252 | "sourceWeight": 10, 2253 | "targetWeight": 0 2254 | }, 2255 | { 2256 | "source": "5", 2257 | "target": "12", 2258 | "sourceWeight": 10, 2259 | "targetWeight": 0 2260 | }, 2261 | { 2262 | "source": "5", 2263 | "target": "16", 2264 | "sourceWeight": 10, 2265 | "targetWeight": 0 2266 | }, 2267 | { 2268 | "source": "5", 2269 | "target": "17", 2270 | "sourceWeight": 10, 2271 | "targetWeight": 0 2272 | }, 2273 | { 2274 | "source": "5", 2275 | "target": "27", 2276 | "sourceWeight": 10, 2277 | "targetWeight": 0 2278 | }, 2279 | { 2280 | "source": "5", 2281 | "target": "28", 2282 | "sourceWeight": 10, 2283 | "targetWeight": 0 2284 | }, 2285 | { 2286 | "source": "5", 2287 | "target": "29", 2288 | "sourceWeight": 10, 2289 | "targetWeight": 0 2290 | }, 2291 | { 2292 | "source": "5", 2293 | "target": "30", 2294 | "sourceWeight": 10, 2295 | "targetWeight": 0 2296 | }, 2297 | { 2298 | "source": "50", 2299 | "target": "51", 2300 | "sourceWeight": 10, 2301 | "targetWeight": 0 2302 | }, 2303 | { 2304 | "source": "50", 2305 | "target": "52", 2306 | "sourceWeight": 10, 2307 | "targetWeight": 0 2308 | }, 2309 | { 2310 | "source": "51", 2311 | "target": "52", 2312 | "sourceWeight": 10, 2313 | "targetWeight": 0 2314 | }, 2315 | { 2316 | "source": "53", 2317 | "target": "54", 2318 | "sourceWeight": 10, 2319 | "targetWeight": 0 2320 | }, 2321 | { 2322 | "source": "53", 2323 | "target": "55", 2324 | "sourceWeight": 10, 2325 | "targetWeight": 0 2326 | }, 2327 | { 2328 | "source": "54", 2329 | "target": "55", 2330 | "sourceWeight": 10, 2331 | "targetWeight": 0 2332 | }, 2333 | { 2334 | "source": "6", 2335 | "target": "7", 2336 | "sourceWeight": 10, 2337 | "targetWeight": 0 2338 | }, 2339 | { 2340 | "source": "6", 2341 | "target": "10", 2342 | "sourceWeight": 10, 2343 | "targetWeight": 0 2344 | }, 2345 | { 2346 | "source": "6", 2347 | "target": "17", 2348 | "sourceWeight": 10, 2349 | "targetWeight": 0 2350 | }, 2351 | { 2352 | "source": "6", 2353 | "target": "18", 2354 | "sourceWeight": 10, 2355 | "targetWeight": 0 2356 | }, 2357 | { 2358 | "source": "6", 2359 | "target": "19", 2360 | "sourceWeight": 10, 2361 | "targetWeight": 0 2362 | }, 2363 | { 2364 | "source": "6", 2365 | "target": "20", 2366 | "sourceWeight": 10, 2367 | "targetWeight": 0 2368 | }, 2369 | { 2370 | "source": "6", 2371 | "target": "27", 2372 | "sourceWeight": 10, 2373 | "targetWeight": 0 2374 | }, 2375 | { 2376 | "source": "6", 2377 | "target": "28", 2378 | "sourceWeight": 10, 2379 | "targetWeight": 0 2380 | }, 2381 | { 2382 | "source": "6", 2383 | "target": "29", 2384 | "sourceWeight": 10, 2385 | "targetWeight": 0 2386 | }, 2387 | { 2388 | "source": "6", 2389 | "target": "30", 2390 | "sourceWeight": 10, 2391 | "targetWeight": 0 2392 | }, 2393 | { 2394 | "source": "6", 2395 | "target": "40", 2396 | "sourceWeight": 10, 2397 | "targetWeight": 0 2398 | }, 2399 | { 2400 | "source": "6", 2401 | "target": "43", 2402 | "sourceWeight": 10, 2403 | "targetWeight": 0 2404 | }, 2405 | { 2406 | "source": "7", 2407 | "target": "8", 2408 | "sourceWeight": 10, 2409 | "targetWeight": 0 2410 | }, 2411 | { 2412 | "source": "7", 2413 | "target": "9", 2414 | "sourceWeight": 10, 2415 | "targetWeight": 0 2416 | }, 2417 | { 2418 | "source": "7", 2419 | "target": "10", 2420 | "sourceWeight": 10, 2421 | "targetWeight": 0 2422 | }, 2423 | { 2424 | "source": "7", 2425 | "target": "17", 2426 | "sourceWeight": 10, 2427 | "targetWeight": 0 2428 | }, 2429 | { 2430 | "source": "7", 2431 | "target": "27", 2432 | "sourceWeight": 10, 2433 | "targetWeight": 0 2434 | }, 2435 | { 2436 | "source": "7", 2437 | "target": "28", 2438 | "sourceWeight": 10, 2439 | "targetWeight": 0 2440 | }, 2441 | { 2442 | "source": "7", 2443 | "target": "29", 2444 | "sourceWeight": 10, 2445 | "targetWeight": 0 2446 | }, 2447 | { 2448 | "source": "7", 2449 | "target": "30", 2450 | "sourceWeight": 10, 2451 | "targetWeight": 0 2452 | }, 2453 | { 2454 | "source": "7", 2455 | "target": "40", 2456 | "sourceWeight": 10, 2457 | "targetWeight": 0 2458 | }, 2459 | { 2460 | "source": "7", 2461 | "target": "43", 2462 | "sourceWeight": 10, 2463 | "targetWeight": 0 2464 | }, 2465 | { 2466 | "source": "8", 2467 | "target": "9", 2468 | "sourceWeight": 10, 2469 | "targetWeight": 0 2470 | }, 2471 | { 2472 | "source": "8", 2473 | "target": "10", 2474 | "sourceWeight": 10, 2475 | "targetWeight": 0 2476 | }, 2477 | { 2478 | "source": "8", 2479 | "target": "17", 2480 | "sourceWeight": 10, 2481 | "targetWeight": 0 2482 | }, 2483 | { 2484 | "source": "8", 2485 | "target": "27", 2486 | "sourceWeight": 10, 2487 | "targetWeight": 0 2488 | }, 2489 | { 2490 | "source": "8", 2491 | "target": "28", 2492 | "sourceWeight": 10, 2493 | "targetWeight": 0 2494 | }, 2495 | { 2496 | "source": "8", 2497 | "target": "29", 2498 | "sourceWeight": 10, 2499 | "targetWeight": 0 2500 | }, 2501 | { 2502 | "source": "8", 2503 | "target": "30", 2504 | "sourceWeight": 10, 2505 | "targetWeight": 0 2506 | }, 2507 | { 2508 | "source": "8", 2509 | "target": "33", 2510 | "sourceWeight": 10, 2511 | "targetWeight": 0 2512 | }, 2513 | { 2514 | "source": "8", 2515 | "target": "38", 2516 | "sourceWeight": 10, 2517 | "targetWeight": 0 2518 | }, 2519 | { 2520 | "source": "8", 2521 | "target": "41", 2522 | "sourceWeight": 10, 2523 | "targetWeight": 0 2524 | }, 2525 | { 2526 | "source": "8", 2527 | "target": "45", 2528 | "sourceWeight": 10, 2529 | "targetWeight": 0 2530 | }, 2531 | { 2532 | "source": "8", 2533 | "target": "50", 2534 | "sourceWeight": 10, 2535 | "targetWeight": 0 2536 | }, 2537 | { 2538 | "source": "8", 2539 | "target": "52", 2540 | "sourceWeight": 10, 2541 | "targetWeight": 0 2542 | }, 2543 | { 2544 | "source": "9", 2545 | "target": "10", 2546 | "sourceWeight": 10, 2547 | "targetWeight": 0 2548 | }, 2549 | { 2550 | "source": "9", 2551 | "target": "11", 2552 | "sourceWeight": 10, 2553 | "targetWeight": 0 2554 | }, 2555 | { 2556 | "source": "9", 2557 | "target": "17", 2558 | "sourceWeight": 10, 2559 | "targetWeight": 0 2560 | }, 2561 | { 2562 | "source": "9", 2563 | "target": "25", 2564 | "sourceWeight": 10, 2565 | "targetWeight": 0 2566 | }, 2567 | { 2568 | "source": "9", 2569 | "target": "27", 2570 | "sourceWeight": 10, 2571 | "targetWeight": 0 2572 | }, 2573 | { 2574 | "source": "9", 2575 | "target": "28", 2576 | "sourceWeight": 10, 2577 | "targetWeight": 0 2578 | }, 2579 | { 2580 | "source": "9", 2581 | "target": "29", 2582 | "sourceWeight": 10, 2583 | "targetWeight": 0 2584 | }, 2585 | { 2586 | "source": "9", 2587 | "target": "30", 2588 | "sourceWeight": 10, 2589 | "targetWeight": 0 2590 | } 2591 | ] 2592 | } --------------------------------------------------------------------------------